fix: resume queued delivery after sign-in (#266)
CI / lint (pull_request) Successful in 24s
CI / build-frontend (pull_request) Successful in 4s

This commit is contained in:
timmy committed 2026-08-08 05:32:29 +00:00
1 parent 65d1f9f194
commit acd2d82d10
7 files changed
+93 -6

No files matched your search

+4
View File
@@ -224,6 +224,10 @@ function createBackgroundIssueSync({ store, fetchJson, base = '' }) {
return item.kind ? { message: delivered, receipt } : { issue: delivered, receipt };
} catch (error) {
const status = Number(error?.status || 0);
if (status === 401) {
await store.release(item.id);
throw error;
}
if (status >= 400 && status < 500) {
await store.fail(item.id, String(error?.message || 'Issue needs attention').slice(0, 240));
return { attention: true, error, receipt: receiptFor(item, 'attention') };
+5 -1
View File
@@ -1,6 +1,6 @@
const BASE = new URL('./', self.location.href).pathname;
importScripts(BASE + 'static/background-issue-sync.js');
const CACHE = 'stackchain-dashboard-shell-v17';
const CACHE = 'stackchain-dashboard-shell-v18';
const OUTAGE_STATUSES = new Set([500, 502, 503, 504]);
const SHELL = [
BASE,
@@ -96,6 +96,10 @@ self.addEventListener('sync', event => {
if (event.tag === 'stackchain-issue-outbox-v1') event.waitUntil(flushAndNotify());
});
self.addEventListener('message', event => {
if (event.data?.type === 'stackchain-resume-outbox') event.waitUntil(flushAndNotify());
});
self.addEventListener('notificationclick', event => {
event.notification.close();
const route = String(event.notification.data?.route || '');
+11 -2
View File
@@ -12,6 +12,7 @@
sessionStorage: root.sessionStorage,
indexedDB: root.indexedDB,
caches: root.caches,
serviceWorker: root.navigator?.serviceWorker,
location: root.location,
onExpired: () => root.dispatchEvent(new CustomEvent('stackchain:session-expired')),
});
@@ -19,13 +20,14 @@
const attach = () => {
const button = root.document.getElementById('sign-out');
if (button) button.addEventListener('click', () => boundary.signOut());
boundary.resumeQueuedWork();
};
if (root.document.readyState === 'loading') root.document.addEventListener('DOMContentLoaded', attach);
else attach();
root.stackchainSession = boundary;
}
})(typeof window !== 'undefined' ? window : this, function createSessionBoundary({
cookie, origin, base, fetchImpl, localStorage, sessionStorage, indexedDB, caches, location,
cookie, origin, base, fetchImpl, localStorage, sessionStorage, indexedDB, caches, serviceWorker, location,
onExpired = () => {},
}) {
const SAFE_METHODS = new Set(['GET', 'HEAD', 'OPTIONS']);
@@ -88,5 +90,12 @@
}
}
return { fetch: sessionFetch, signOut, clearPrivateDeviceData };
async function resumeQueuedWork() {
try {
const registration = await serviceWorker?.ready;
registration?.active?.postMessage({ type: 'stackchain-resume-outbox' });
} catch (_error) { /* Background Sync is optional; foreground delivery remains available. */ }
}
return { fetch: sessionFetch, signOut, clearPrivateDeviceData, resumeQueuedWork };
});