diff options
Diffstat (limited to 'src/sw-nwc.js')
| -rw-r--r-- | src/sw-nwc.js | 32 |
1 files changed, 28 insertions, 4 deletions
diff --git a/src/sw-nwc.js b/src/sw-nwc.js index 0b65268..211c4f9 100644 --- a/src/sw-nwc.js +++ b/src/sw-nwc.js @@ -29,7 +29,7 @@ async function applePush() { } catch (_) { return false; } } async function standIn(visible) { - if (!(await applePush())) return; + if (!(await applePush())) return false; await self.registration.showNotification('Coinos', { body: 'Your wallet checked in.', icon: 'icon-192.png', badge: 'badge-96.png', tag: 'coinos-bg', renotify: false, silent: true, data: { url: './' }, @@ -38,6 +38,7 @@ async function standIn(visible) { const open = await self.registration.getNotifications({ tag: 'coinos-bg' }).catch(() => []); for (const n of open) n.close(); } + return true; } self.addEventListener('push', (e) => { @@ -45,7 +46,17 @@ self.addEventListener('push', (e) => { try { data = e.data ? e.data.json() : {}; } catch (_) {} // every path below ends in a notification or, failing that, the stand-in let showed = false; - const show = (title, opts) => { showed = true; return self.registration.showNotification(title, opts); }; + // A notification the platform refuses must not count as shown: the old + // code flagged it before the call, so a refusal left the push with no line + // at all — a silent push, on iOS a strike towards losing the subscription. + // (PullCap's night of 2026-10-22: paid four times, no "Payment sent" seen.) + // Try the full options; refused, try again with the plainest ones. + const show = async (title, opts) => { + try { await self.registration.showNotification(title, opts); showed = true; return; } + catch (e) { console.warn('[sw] notification refused:', e && e.message); } + try { await self.registration.showNotification(title, { body: opts && opts.body, tag: opts && opts.tag, data: opts && opts.data }); showed = true; } + catch (e) { console.warn('[sw] plain notification refused too:', e && e.message); } + }; // the stand-in, as soon as a path knows it has nothing to say (a long tail // of work after it mustn't keep the push waiting for its notification) const quiet = async () => { @@ -155,14 +166,25 @@ self.addEventListener('push', (e) => { if (data.type !== 'nwc') { settle(async () => {}); return; } const startedAt = Date.now(); settle(async () => { + // WebKit's silent-push quota counts a push whose notification comes + // late: a payment can take most of the push budget, and a worker stopped + // before its last line never shows one (PullCap's night of 2026-10-22: + // four payments, no line for the fourth, then no more wakes). On an + // Apple endpoint the stand-in goes up FIRST; the outcome replaces it. + const apple = await applePush(); + const dropStandIn = async () => { + const open = await self.registration.getNotifications({ tag: 'coinos-bg' }).catch(() => []); + for (const n of open) n.close(); + }; + if (apple && await standIn(false).catch(() => false)) showed = true; // An open window handles requests itself with full wallet state — nudge // it and stay out of the way. On iOS only one on screen counts: a // backgrounded app is suspended, so a nudge to it went unanswered. const all = await self.clients.matchAll({ type: 'window', includeUncontrolled: true }); - const apple = await applePush(); const clients = all.filter((c) => !apple || c.visibilityState === 'visible'); if (clients.length) { for (const c of clients) c.postMessage({ type: 'nwc-wake', servicePubkey: data.servicePubkey }); + if (apple) await dropStandIn(); // the window on screen shows it live return; } // A wake is the only moment a closed wallet gets to look after its coins: @@ -186,9 +208,10 @@ self.addEventListener('push', (e) => { await show(handled.notify.title, { body: handled.notify.body, icon: 'icon-192.png', badge: 'badge-96.png', - tag: handled.notify.tag || 'nwc-incoming', renotify: true, + tag: handled.notify.tag || 'nwc-incoming', renotify: !apple, data: { url: './' }, }); + if (apple) await dropStandIn(); await tend(); return; } @@ -204,6 +227,7 @@ self.addEventListener('push', (e) => { tag: 'nwc-' + (data.servicePubkey || 'req'), renotify: false, data: { url: './' }, }); + if (apple) await dropStandIn(); }); }); |
