add more servce worker boot controls

disable scarf by default
handle redirect with query
This commit is contained in:
Stewart Allen 2025-10-13 11:45:14 -04:00
commit 3bc0f0cfc2
4 changed files with 62 additions and 37 deletions

8
app.js
View file

@ -526,7 +526,13 @@ function fixedmap(prefix, map) {
// HTTP 307 redirect
function redir(path, type) {
return (req, res, next) => {
http.redirect(res, path, type);
let query = req.url.split('?')[1];
let rpath = path;
if (query && path.indexOf('?') < 0) {
rpath += `?${query}`;
}
// console.log({ redir: req.url, to: path, query, new_path: rpath });
http.redirect(res, rpath, type);
}
}

View file

@ -302,7 +302,7 @@ export const conf = {
outputRetractDwell: 20,
outputRetractSpeed: 40,
outputRetractWipe: 0,
outputScarfLength: 5,
outputScarfLength: 0,
outputSeekrate: 80,
outputShellMult: 1.25,
outputShortPoly: 0.0,

View file

@ -22,7 +22,6 @@
<script type="module">
import { version } from '/lib/moto/license.js';
(async () => {
const ver = location.search.slice(1);
const reg = await navigator.serviceWorker.register('/boot/service.js', { scope: '/' });
await reg.update();
await navigator.serviceWorker.ready;
@ -33,19 +32,31 @@
return;
}
// turn url params into key/value map
const map = Object.fromEntries(
(location.search || location.hash).slice(1).split('&')
.map(v => v.split('='))
.map(([k, v = true]) => [k, v])
);
if (map.debug) {
console.log({ map });
}
navigator.serviceWorker.controller.postMessage({
mode: 'cached',
version: ver || version
clear: map.clear,
disable: map.disable,
version: map.version || version
});
navigator.serviceWorker.addEventListener('message', e => {
if (e.data === 'preload-complete') {
console.log('preload complete');
location.replace('/kiri/index.html');
} else if (e.data === 'preload-cached') {
console.log('preload cached');
location.replace('/kiri/index.html');
}
console.log('[SM]', e.data);
setTimeout(() => {
if (map.mesh) {
location.replace('/mesh/index.html');
} else {
location.replace('/kiri/index.html');
}
}, map.delay || 10);
});
})();
</script>

View file

@ -1,8 +1,9 @@
// --- configurable ---
const CACHE_VERSION = 'boot-v001';
const CACHE_VERSION = 'boot-001';
const BUNDLE_URL = '/boot/bundle.bin';
const VERSION_KEY = '/__version__';
let loaded = 0;
let mode = 'cached';
let currentVersion = null;
@ -18,14 +19,33 @@ self.addEventListener('activate', e => e.waitUntil(clients.claim()));
// --- mode control ---
self.addEventListener('message', e => {
log({ message: e.data });
const data = e.data || {};
if (data.mode) mode = data.mode;
if (data.mode === 'cached' && data.version !== undefined) {
ensureVersion(data.version);
const { clear, disable, version } = data;
if (clear) {
clearCache();
}
if (disable) {
mode = 'transparent';
broadcast('transparent mode');
unregister();
} else if (version !== undefined) {
mode = 'cached';
log('version', version);
ensureVersion(version);
}
});
// --- unregister current service worker ---
async function unregister() {
await self.registration.unregister();
}
// --- erase existing cache ---
async function clearCache() {
log('clearing cache');
await caches.delete(CACHE_VERSION);
}
// --- version check and preload ---
async function ensureVersion(incomingVersion) {
const cache = await caches.open(CACHE_VERSION);
@ -38,10 +58,8 @@ async function ensureVersion(incomingVersion) {
} else {
const stored = await existing.text();
if (stored !== incomingVersion) {
log(`version mismatch ${stored}${incomingVersion} → preload`);
log(`mismatch ${stored}${incomingVersion} → preload`);
needPreload = true;
} else {
log(`version OK (${stored})`);
}
}
@ -51,9 +69,9 @@ async function ensureVersion(incomingVersion) {
VERSION_KEY,
new Response(String(incomingVersion), { headers: { 'Content-Type': 'text/plain' } })
);
broadcast('preload-complete');
broadcast(`preload added ${loaded} files`);
} else {
broadcast('preload-cached');
broadcast('preload cached');
}
}
@ -80,7 +98,7 @@ self.addEventListener('fetch', e => {
if (request.method !== 'GET') return;
if (mode === 'transparent') {
if (mode == 'transparent') {
e.respondWith(fetch_safe(e.request));
return;
}
@ -93,23 +111,15 @@ async function fromCacheOrNetwork(req) {
const cache = await caches.open(CACHE_VERSION);
const hit = await cache.match(req);
if (hit) {
// log({ hit: hit.url || req.url });
// log(`hit: ${req.url}`);
return hit;
}
const net = await fetch_safe(req);
cache.put(req, net.clone());
log({ put: net.url });
log(`put: ${net.url}`);
return net;
}
async function serveIndex() {
const cache = await caches.open(CACHE_VERSION);
const hit = await cache.match('/kiri/index.html');
log({ serve_index: hit, cache });
if (hit) return hit;
return fetch_safe('/kiri/index.html');
}
async function broadcast(message) {
const clientsList = await clients.matchAll({ type: 'window' });
for (const client of clientsList) {
@ -124,12 +134,11 @@ const sec_headers = {
// --- preload & unpack bundle ---
async function preloadBundle() {
// return;
loaded = 0;
const cache = await caches.open(CACHE_VERSION);
const res = await fetch(BUNDLE_URL, { cache: 'no-store' });
const buf = await res.arrayBuffer();
const files = await unpackBundle(buf);
log({ files });
await Promise.all(
Object.entries(files).map(([path, blob]) => {
const ext = path.split('.').pop();
@ -142,8 +151,8 @@ async function preloadBundle() {
ext === 'svg' ? 'image/svg+xml' :
'application/octet-stream';
const headers = { 'Content-Type': type, ...sec_headers };
// Object.assign(headers, sec_headers);
const resp = new Response(blob, { headers });
loaded++;
return cache.put('/' + path, resp);
})
);
@ -166,7 +175,6 @@ async function unpackBundle(buf) {
const len = view.getUint32(pos, true); pos += 4;
table.push({ name, offset, len });
}
log({ table });
const files = {};
for (const { name, offset, len } of table)