-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsw.js
More file actions
153 lines (134 loc) · 6.47 KB
/
sw.js
File metadata and controls
153 lines (134 loc) · 6.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/* ═══════════════════════════════════════════════════════════════════════
BACKSTAX v4.2 — SERVICE WORKER
═══════════════════════════════════════════════════════════════════════
Provides offline capability and caches static assets for PWA support.
═══════════════════════════════════════════════════════════════════════ */
const CACHE_NAME = 'backstax-v4.2.0';
const CACHE_DURATION = 24 * 60 * 60 * 1000; // 24 hours
// Assets to cache on install (static resources)
const STATIC_ASSETS = [
'./',
'./index.html',
'./ui-controller.js',
'./map-renderer.js'
];
// External resources to cache on first request
const EXTERNAL_PATTERNS = [
/fonts\.googleapis\.com/,
/fonts\.gstatic\.com/,
/unpkg\.com\/leaflet/
];
/* ─── INSTALL EVENT ───────────────────────────────────────────────────────
Pre-cache static assets when the service worker is installed.
─────────────────────────────────────────────────────────────────────────── */
self.addEventListener('install', (event) => {
event.waitUntil(
(async () => {
const cache = await caches.open(CACHE_NAME);
console.log('[BACKSTAX SW] Caching static assets');
const results = await Promise.allSettled(
STATIC_ASSETS.map(async (url) => {
try {
const fullUrl = new URL(url, self.location.origin + BASE_PATH).href;
await cache.add(fullUrl);
console.log('[BACKSTAX SW] Cached:', fullUrl);
} catch (err) {
console.warn('[BACKSTAX SW] Failed to cache:', url, err.message);
}
})
);
const successCount = results.filter(r => r.status === 'fulfilled').length;
console.log(`[BACKSTAX SW] Cached ${successCount}/${STATIC_ASSETS.length} assets`);
await self.skipWaiting();
console.log('[BACKSTAX SW] Install complete');
})()
);
});
/* ─── ACTIVATE EVENT ──────────────────────────────────────────────────────
Clean up old caches when a new service worker activates.
─────────────────────────────────────────────────────────────────────────── */
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys()
.then((cacheNames) => {
return Promise.all(
cacheNames
.filter(name => name !== CACHE_NAME)
.map(name => {
console.log('[BACKSTAX SW] Removing old cache:', name);
return caches.delete(name);
})
);
})
.then(() => {
console.log('[BACKSTAX SW] Activate complete');
return self.clients.claim();
})
);
});
/* ─── FETCH EVENT ─────────────────────────────────────────────────────────
Serve from cache, fallback to network, cache external resources.
─────────────────────────────────────────────────────────────────────────── */
self.addEventListener('fetch', (event) => {
const { request } = event;
const url = new URL(request.url);
// Skip non-GET requests
if (request.method !== 'GET') {
return;
}
// Skip chrome-extension and other non-http(s) requests
if (!url.protocol.startsWith('http')) {
return;
}
event.respondWith(
caches.open(CACHE_NAME)
.then((cache) => {
return cache.match(request)
.then((cachedResponse) => {
// Return cached response if available and fresh
if (cachedResponse) {
// Check if cache is stale (for API calls, always fetch fresh)
const isApiRequest = url.pathname.includes('/api/') ||
url.hostname.includes('api.');
if (!isApiRequest) {
return cachedResponse;
}
}
// Fetch from network
return fetch(request)
.then((networkResponse) => {
// Cache successful responses
if (networkResponse && networkResponse.status === 200) {
const shouldCache = EXTERNAL_PATTERNS.some(pattern =>
pattern.test(url.hostname)
);
if (shouldCache) {
cache.put(request, networkResponse.clone());
}
}
return networkResponse;
})
.catch((error) => {
// Network failed, return cached version if available
if (cachedResponse) {
return cachedResponse;
}
// Return offline fallback for navigation requests
if (request.mode === 'navigate') {
return caches.match('/index.html');
}
throw error;
});
});
})
);
});
/* ─── MESSAGE EVENT ───────────────────────────────────────────────────────
Handle messages from the main application.
─────────────────────────────────────────────────────────────────────────── */
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'SKIP_WAITING') {
self.skipWaiting();
}
});
console.log('[BACKSTAX SW] Service Worker loaded v4.2.0');