-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsw.js
More file actions
311 lines (269 loc) · 8.82 KB
/
Copy pathsw.js
File metadata and controls
311 lines (269 loc) · 8.82 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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
// ===== SERVICE WORKER FOR OVERFLUX PWA =====
const CACHE_NAME = 'overflux-v1.0.0';
const STATIC_CACHE_NAME = 'overflux-static-v1.0.0';
const DYNAMIC_CACHE_NAME = 'overflux-dynamic-v1.0.0';
// Files to cache immediately
const STATIC_FILES = [
'/',
'/index.html',
'/styles/styles.css',
'/scripts/scripts.js',
'/manifest.json',
'/materials/overflux_logo_lowres.png',
'/materials/favicon.ico',
// Add Google Fonts
'https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Space+Grotesk:wght@400;500;600;700&display=swap'
];
// Files to cache dynamically
const DYNAMIC_FILES = [
'/images/selfie_founder.jpg',
'/images/selfie_ceo.png',
'/images/selfie_cto.jpg',
'/images/selfie_tester.png',
'/images/highres_bg_image.jpg'
];
// Maximum number of dynamic cache entries
const MAX_DYNAMIC_CACHE_SIZE = 50;
// ===== UTILITY FUNCTIONS =====
// Clean old caches
const cleanupCaches = async () => {
const cacheNames = await caches.keys();
const oldCaches = cacheNames.filter(name =>
name !== STATIC_CACHE_NAME &&
name !== DYNAMIC_CACHE_NAME &&
name.startsWith('overflux-')
);
return Promise.all(
oldCaches.map(cacheName => caches.delete(cacheName))
);
};
// Limit cache size
const limitCacheSize = async (cacheName, maxSize) => {
const cache = await caches.open(cacheName);
const keys = await cache.keys();
if (keys.length > maxSize) {
const keysToDelete = keys.slice(0, keys.length - maxSize);
await Promise.all(
keysToDelete.map(key => cache.delete(key))
);
}
};
// Check if request is for static content
const isStaticContent = (url) => {
return STATIC_FILES.some(file => url.includes(file)) ||
url.includes('.css') ||
url.includes('.js') ||
url.includes('.html') ||
url.includes('fonts.googleapis.com') ||
url.includes('fonts.gstatic.com');
};
// Check if request is for images
const isImageContent = (url) => {
return url.includes('.jpg') ||
url.includes('.jpeg') ||
url.includes('.png') ||
url.includes('.gif') ||
url.includes('.webp') ||
url.includes('.svg');
};
// ===== SERVICE WORKER EVENTS =====
// Install event - cache static assets
self.addEventListener('install', event => {
console.log('OverFlux SW: Installing service worker...');
event.waitUntil(
(async () => {
try {
const staticCache = await caches.open(STATIC_CACHE_NAME);
console.log('OverFlux SW: Caching static files...');
await staticCache.addAll(STATIC_FILES);
console.log('OverFlux SW: Static files cached successfully');
// Skip waiting to activate immediately
await self.skipWaiting();
} catch (error) {
console.error('OverFlux SW: Error during installation:', error);
}
})()
);
});
// Activate event - clean up old caches
self.addEventListener('activate', event => {
console.log('OverFlux SW: Activating service worker...');
event.waitUntil(
(async () => {
try {
await cleanupCaches();
console.log('OverFlux SW: Old caches cleaned up');
// Take control of all clients immediately
await self.clients.claim();
console.log('OverFlux SW: Service worker activated and took control');
} catch (error) {
console.error('OverFlux SW: Error during activation:', error);
}
})()
);
});
// Fetch event - handle network requests
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(
(async () => {
try {
// Strategy 1: Cache First for static content
if (isStaticContent(url.href)) {
const cachedResponse = await caches.match(request);
if (cachedResponse) {
return cachedResponse;
}
// If not in cache, fetch and cache
const networkResponse = await fetch(request);
if (networkResponse.ok) {
const cache = await caches.open(STATIC_CACHE_NAME);
cache.put(request, networkResponse.clone());
}
return networkResponse;
}
// Strategy 2: Network First with fallback for images
if (isImageContent(url.href)) {
try {
const networkResponse = await fetch(request);
if (networkResponse.ok) {
const cache = await caches.open(DYNAMIC_CACHE_NAME);
cache.put(request, networkResponse.clone());
// Limit dynamic cache size
limitCacheSize(DYNAMIC_CACHE_NAME, MAX_DYNAMIC_CACHE_SIZE);
}
return networkResponse;
} catch (error) {
// Network failed, try cache
const cachedResponse = await caches.match(request);
if (cachedResponse) {
return cachedResponse;
}
// Return placeholder image for failed image requests
return new Response(
'<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"400\" height=\"300\" viewBox=\"0 0 400 300\"><rect width=\"400\" height=\"300\" fill=\"#f3f4f6\"/><text x=\"200\" y=\"150\" text-anchor=\"middle\" fill=\"#9ca3af\" font-family=\"Arial\">Image unavailable</text></svg>',
{
headers: {
'Content-Type': 'image/svg+xml',
'Cache-Control': 'no-cache'
}
}
);
}
}
// Strategy 3: Network Only for API calls and other dynamic content
return fetch(request);
} catch (error) {
console.error('OverFlux SW: Fetch error:', error);
// For navigation requests, return cached index.html as fallback
if (request.mode === 'navigate') {
const cachedResponse = await caches.match('/index.html');
if (cachedResponse) {
return cachedResponse;
}
}
// Return generic error response
return new Response(
JSON.stringify({
error: 'Network error',
message: 'Please check your internet connection'
}),
{
status: 503,
statusText: 'Service Unavailable',
headers: {
'Content-Type': 'application/json'
}
}
);
}
})()
);
});
// Background sync event (for future use)
self.addEventListener('sync', event => {
console.log('OverFlux SW: Background sync triggered:', event.tag);
if (event.tag === 'background-sync') {
event.waitUntil(
// Add background sync logic here
Promise.resolve()
);
}
});
// Push event (for future notifications)
self.addEventListener('push', event => {
console.log('OverFlux SW: Push event received');
const options = {
body: event.data ? event.data.text() : 'New update available!',
icon: '/materials/overflux_logo_lowres.png',
badge: '/materials/overflux_logo_lowres.png',
tag: 'overflux-notification',
renotify: true,
requireInteraction: true,
actions: [
{
action: 'view',
title: 'View',
icon: '/materials/overflux_logo_lowres.png'
},
{
action: 'dismiss',
title: 'Dismiss'
}
]
};
event.waitUntil(
self.registration.showNotification('OverFlux', options)
);
});
// Notification click event
self.addEventListener('notificationclick', event => {
console.log('OverFlux SW: Notification clicked:', event.action);
event.notification.close();
if (event.action === 'view') {
event.waitUntil(
clients.openWindow('/')
);
}
});
// Message event for communication with main thread
self.addEventListener('message', event => {
console.log('OverFlux SW: Message received:', event.data);
if (event.data && event.data.type) {
switch (event.data.type) {
case 'SKIP_WAITING':
self.skipWaiting();
break;
case 'GET_VERSION':
event.ports[0].postMessage({ version: CACHE_NAME });
break;
case 'CLEAR_CACHE':
event.waitUntil(
(async () => {
const cacheNames = await caches.keys();
await Promise.all(
cacheNames.map(cacheName => caches.delete(cacheName))
);
event.ports[0].postMessage({ success: true });
})()
);
break;
default:
console.log('OverFlux SW: Unknown message type:', event.data.type);
}
}
});
// Error event
self.addEventListener('error', event => {
console.error('OverFlux SW: Service worker error:', event.error);
});
console.log('OverFlux SW: Service worker script loaded');