78 lines
2.6 KiB
Markdown
78 lines
2.6 KiB
Markdown
---
|
|
phase: quick-260611-tfc
|
|
plan: "01"
|
|
subsystem: pwa-sw
|
|
tags: [service-worker, push-notifications, bug-fix, wr-01]
|
|
dependency_graph:
|
|
requires: []
|
|
provides: [reachable-openWindow-fallback-notificationclick]
|
|
affects: [apps/pwa/src/sw.ts]
|
|
tech_stack:
|
|
added: []
|
|
patterns: [promise-chain-catch-fallback]
|
|
key_files:
|
|
created: []
|
|
modified:
|
|
- apps/pwa/src/sw.ts
|
|
decisions:
|
|
- "Canonical fix shape: .then(navigated => openWindow if null) + .catch(() => openWindow) on the focus/navigate chain — keeps the returned promise intact for no-floating-promises"
|
|
metrics:
|
|
duration: ~6 min
|
|
completed: "2026-06-12"
|
|
---
|
|
|
|
# Quick Task 260611-tfc: Fix WR-01 sw.ts notificationclick openWindow Fallback
|
|
|
|
**One-liner:** notificationclick handler extended with `.then(navigated===null → openWindow)` + `.catch(→ openWindow)` so the new-window fallback is reachable on both focus rejection and null navigate.
|
|
|
|
## What Was Done
|
|
|
|
Fixed WR-01 from `.planning/phases/13-real-lint-gate-eslint/13-REVIEW.md`.
|
|
|
|
The focusable-client `return` inside the `for (const client of clientList)` loop was:
|
|
|
|
```ts
|
|
return client.focus().then(() => client.navigate(url));
|
|
```
|
|
|
|
Two failure modes made the `openWindow` fallback unreachable:
|
|
1. `navigate()` resolving `null` (browser rejected the navigation) — the chain resolved successfully, so the post-loop fallback was never reached.
|
|
2. `focus()` or `navigate()` rejecting (window closed between `matchAll` and `focus`) — the rejection propagated into `event.waitUntil`, marking the click as handled without opening a new window.
|
|
|
|
Applied the canonical replacement per the review:
|
|
|
|
```ts
|
|
return client
|
|
.focus()
|
|
.then(() => client.navigate(url))
|
|
.then((navigated) => {
|
|
if (navigated === null && self.clients.openWindow)
|
|
return self.clients.openWindow(url);
|
|
})
|
|
.catch(() => {
|
|
if (self.clients.openWindow) return self.clients.openWindow(url);
|
|
});
|
|
```
|
|
|
|
All surrounding behaviour preserved: `event.notification.close()`, `url` extraction + eslint-disable comments, `matchAll` options, and the post-loop no-focusable-client fallback.
|
|
|
|
## Verification — Exit Codes
|
|
|
|
| Command | Exit |
|
|
|---------|------|
|
|
| `pnpm lint` | 0 |
|
|
| `pnpm typecheck` | 0 |
|
|
| `pnpm --filter @familysync/pwa test` | 0 (191/191 pass) |
|
|
| `pnpm --filter @familysync/pwa build` | 0 (dist/sw.js emitted) |
|
|
|
|
## Deviations from Plan
|
|
|
|
None — plan executed exactly as written.
|
|
|
|
## Self-Check: PASSED
|
|
|
|
- `apps/pwa/src/sw.ts` modified: confirmed
|
|
- Commit `af78ccc` exists: confirmed
|
|
- `git diff --diff-filter=D HEAD~1 HEAD`: no deletions
|
|
- Only `apps/pwa/src/sw.ts` changed (`git diff --stat` = 1 file, 10 insertions, 1 deletion)
|