updated directory structure to fix root Service Worker issues and performance improvements

This commit is contained in:
Keep Creating Online
2025-02-05 16:54:40 -05:00
parent 03c28dacab
commit b6b61e4e15
94 changed files with 2265 additions and 79 deletions

171
sw.min.js vendored Normal file
View File

@@ -0,0 +1,171 @@
(() => {
"use strict";
let cancelled = false;
// Handle messages from clients
self.addEventListener("message", (event) => {
if (event.data && event.data.type === "SKIP_WAITING") {
self.skipWaiting();
}
if (event.data && event.data.type === "CLEAR_CACHES") {
caches
.keys()
.then((cacheNames) =>
Promise.all(cacheNames.map((cacheName) => caches.delete(cacheName)))
);
}
});
// Immediately install and skip waiting
self.addEventListener("install", (event) => {
self.skipWaiting();
});
// Claim clients on activation and clear caches
self.addEventListener("activate", (event) => {
event.waitUntil(
Promise.all([
clients.claim(),
self.skipWaiting(),
caches
.keys()
.then((cacheNames) =>
Promise.all(cacheNames.map((cacheName) => caches.delete(cacheName)))
),
])
);
});
// Handle fetch events
self.addEventListener("fetch", (event) => {
const requestURL = event.request.url;
// Only handle WebTorrent streaming requests
if (!requestURL.includes("/webtorrent/")) {
return;
}
// Create a promise to handle the request
const responsePromise = (async () => {
// 1) Keepalive check
if (requestURL.includes("/webtorrent/keepalive/")) {
return new Response();
}
// 2) Cancel check
if (requestURL.includes("/webtorrent/cancel/")) {
return new Response(
new ReadableStream({
cancel() {
cancelled = true;
},
})
);
}
// 3) Streaming requests
// We define an async function and immediately invoke it with `event`
return (async function ({ request }) {
const { url, method, headers, destination } = request;
// 3a) Find open window clients
const windowClients = await clients.matchAll({
type: "window",
includeUncontrolled: true,
});
// 3b) We send a message to each client with a MessageChannel
const [clientResponse, port] = await new Promise((resolve) => {
for (const client of windowClients) {
const channel = new MessageChannel();
channel.port1.onmessage = ({ data }) => {
resolve([data, channel.port1]);
};
client.postMessage(
{
url,
method,
headers: Object.fromEntries(headers.entries()),
scope: self.registration.scope,
destination,
type: "webtorrent",
},
[channel.port2]
);
}
});
// 3c) Setup a small helper to close the port
let timeoutId = null;
const closeChannel = () => {
port.postMessage(false);
clearTimeout(timeoutId);
port.onmessage = null;
};
// 3d) Build a Headers object that prevents caching
const responseHeaders = new Headers(clientResponse.headers);
responseHeaders.set(
"Cache-Control",
"no-cache, no-store, must-revalidate, max-age=0"
);
responseHeaders.set("Pragma", "no-cache");
responseHeaders.set("Expires", "0");
// 3e) If the response is not a streaming request, return it directly
if (clientResponse.body !== "STREAM") {
closeChannel();
return new Response(clientResponse.body, {
status: clientResponse.status,
statusText: clientResponse.statusText,
headers: responseHeaders,
});
}
// 3f) Otherwise, create a streaming response
return new Response(
new ReadableStream({
pull(controller) {
return new Promise((resolvePull) => {
port.onmessage = ({ data }) => {
if (data) {
controller.enqueue(data);
} else {
closeChannel();
controller.close();
}
resolvePull();
};
// If not cancelled, autoclose after 5s of no data
// *** Increase the timeout to avoid frequent CPU wake-ups ***
if (!cancelled && destination !== "document") {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
closeChannel();
resolvePull();
}, 30000); // 30 seconds
}
// Request next chunk from client
port.postMessage(true);
});
},
cancel() {
closeChannel();
},
}),
{
status: clientResponse.status,
statusText: clientResponse.statusText,
headers: responseHeaders,
}
);
})(event);
})();
// respondWith the promise if it exists
event.respondWith(responsePromise);
});
})();