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 // HTTP 307 redirect
function redir(path, type) { function redir(path, type) {
return (req, res, next) => { 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, outputRetractDwell: 20,
outputRetractSpeed: 40, outputRetractSpeed: 40,
outputRetractWipe: 0, outputRetractWipe: 0,
outputScarfLength: 5, outputScarfLength: 0,
outputSeekrate: 80, outputSeekrate: 80,
outputShellMult: 1.25, outputShellMult: 1.25,
outputShortPoly: 0.0, outputShortPoly: 0.0,

View file

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

View file

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