Spaces:
Running
Running
File size: 5,099 Bytes
ba1e29d | 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 | // JAYNES MAX β Service Worker
// Hifadhi "app shell" + maktaba za Shaka/hls ili app ifunguke hata bila mtandao.
// API, video na streams HAZIHIFADHIWI (zinahitaji mtandao). Movie zilizopakuliwa ziko OPFS ndani ya app.
const VERSION = 'jm-v9';
const RUNTIME = 'jm-cdn-v1';
const SHELL = ['./', './index.html', './manifest.webmanifest', './config.js', './icon-192.png', './icon-512.png', './icon-maskable-512.png', './apple-touch-icon.png'];
const CDN_HOST = 'cdnjs.cloudflare.com';
const CDN = [
'https://cdnjs.cloudflare.com/ajax/libs/hls.js/1.5.13/hls.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/shaka-player/4.10.0/shaka-player.compiled.js',
];
self.addEventListener('install', (e) => {
e.waitUntil((async () => {
// Kila faili peke yake: faili moja likikosekana, install HAIFEI (addAll ingefeli yote)
const shell = await caches.open(VERSION);
await Promise.all(SHELL.map((u) => shell.add(u).catch(() => {})));
const rt = await caches.open(RUNTIME);
await Promise.all(CDN.map((u) => fetch(u, { mode: 'no-cors' }).then((r) => rt.put(u, r)).catch(() => {})));
await self.skipWaiting();
})());
});
self.addEventListener('activate', (e) => {
e.waitUntil(
caches.keys().then((keys) => Promise.all(keys.filter((k) => k !== VERSION && k !== RUNTIME).map((k) => caches.delete(k))))
.then(() => self.clients.claim())
);
});
function shellFallback() {
return caches.match('./index.html', { ignoreSearch: true })
.then((r) => r || caches.match('./', { ignoreSearch: true }));
}
self.addEventListener('fetch', (e) => {
const req = e.request;
if (req.method !== 'GET') return;
const url = new URL(req.url);
// Maktaba za CDN (hls/shaka): cache-first ili zipatikane offline na zipakie haraka
if (url.hostname === CDN_HOST) {
e.respondWith(
caches.match(req).then((hit) => hit || fetch(req).then((res) => {
if (res && (res.ok || res.type === 'opaque')) { const copy = res.clone(); caches.open(RUNTIME).then((c) => c.put(req, copy)); }
return res;
}))
);
return;
}
// Usiguse chochote kingine nje ya asili yetu (Supabase API, video, picha za CDN n.k.)
if (url.origin !== self.location.origin) return;
// Range requests (video/sauti) β acha mtandao ushughulikie
if (req.headers.has('range')) return;
// Ukurasa mkuu: network-first, lakini mtandao ukichelewa (>3.5s) au ukikosekana β cache.
// Hii inazuia app "kuning'inia" ukiwa na mtandao dhaifu / bila bando.
if (req.mode === 'navigate') {
e.respondWith(new Promise((resolve) => {
let settled = false;
const settle = (r) => { if (!settled && r) { settled = true; resolve(r); } };
const timer = setTimeout(() => { shellFallback().then(settle); }, 3500);
fetch(req).then((res) => {
clearTimeout(timer);
if (res && res.ok) { const copy = res.clone(); caches.open(VERSION).then((c) => c.put('./index.html', copy)); }
settle(res);
}).catch(() => {
clearTimeout(timer);
shellFallback().then((r) => { if (!settled) { settled = true; resolve(r || Response.error()); } });
});
}));
return;
}
// config.js: network-first (funguo/URL zikibadilishwa zifike mara moja), cache ikiwa offline
if (url.pathname.endsWith('/config.js')) {
e.respondWith(
fetch(req).then((res) => { if (res.ok) { const copy = res.clone(); caches.open(VERSION).then((c) => c.put(req, copy)); } return res; })
.catch(() => caches.match(req, { ignoreSearch: true }))
);
return;
}
// Faili tuli (icons, manifest): cache-first
e.respondWith(
caches.match(req).then((hit) => hit || fetch(req).then((res) => {
if (res.ok) { const copy = res.clone(); caches.open(VERSION).then((c) => c.put(req, copy)); }
return res;
}))
);
});
// ββ Web Push (inatoka Supabase Edge Function 'send-push') ββ
self.addEventListener('push', (e) => {
let d = {};
try { d = e.data ? e.data.json() : {}; } catch (_) { d = { body: e.data && e.data.text() }; }
const opts = {
body: d.body || '',
icon: './icon-192.png',
badge: './icon-192.png',
tag: d.id ? 'jm-ann-' + d.id : undefined,
data: { url: d.url || './' },
};
if (d.image) opts.image = d.image; // picha kubwa (Android/Chrome)
e.waitUntil(self.registration.showNotification(d.title || 'JAYNES MAX', opts));
});
// Kubonyeza notification: fungua app moja kwa moja kwenye ukurasa ulioainishwa (#/title/ID, #/live, ...)
self.addEventListener('notificationclick', (e) => {
e.notification.close();
const raw = (e.notification.data && e.notification.data.url) || './';
const target = new URL(raw, self.registration.scope).href;
e.waitUntil((async () => {
const all = await self.clients.matchAll({ type: 'window', includeUncontrolled: true });
for (const c of all) {
if (c.url.startsWith(self.registration.scope)) {
try { c.postMessage({ type: 'jm-open', url: target }); } catch (_) {}
if ('focus' in c) await c.focus();
return;
}
}
await self.clients.openWindow(target);
})());
});
|