pub const SERVICE_WORKER: &str = "// The service worker: the shell, so that a cold start with no network is a page rather than an\n// error.\n//\n// `docs/94` \u{a7}94.13 is why this exists. A Mode B client keeps its state in the browser and queues\n// what it cannot send, so it survives a *reconnect* \u{2014} but a **reload** with nothing listening never\n// gets that far, because the document, the scripts and the kernel all come from the server. The\n// local copy is fine and unreachable. A worker is the only thing a browser will run before the\n// network is consulted, so it is the only place that can answer.\n//\n// Network first, cache second. A live server always wins, which is what keeps a deploy from being\n// hostage to a cache: the only requests answered from the cache are the ones that *failed*.\n//\n// `%WIRE%` is substituted by the server from the program\'s content-derived wire id (\u{a7}4.3), so a\n// deployment that changes the command channel\'s types gets a new cache and the old one is deleted\n// on activate. That is the same key `beck-mode-b.js` stores its local copy under, and for the same\n// reason: two programs must not share one browser\'s idea of either.\nconst CACHE = \"beck-shell-%WIRE%\";\n\n// Everything a Mode B tab needs before it can render anything at all. The document is `/` \u{2014} and it\n// is the document for **every** route, not only that one: a Mode B client renders from the state it\n// holds and reads its route off `location`, so the shell it hydrates into is the same shell\n// whatever the address bar says (`docs/94` \u{a7}94.3). Caching one document per route would be caching\n// the same file under different names, and would still miss the route nobody had visited.\n// The bundle and the kernel are the component and its backend.\nconst SHELL = [\n \"/\",\n \"/beck.css\",\n \"/beck-patch.js\",\n \"/beck-mode-b.js\",\n \"/beck-bundle.bpk\",\n \"/beck-kernel.wasm\",\n];\n\nself.addEventListener(\"install\", (event) => {\n // `skipWaiting` so a tab that reloads onto a new deployment gets the new worker rather than the\n // one the previous page installed. The cache name changed with the wire id, so there is nothing\n // of the old program left to serve.\n event.waitUntil(\n caches.open(CACHE).then((c) => c.addAll(SHELL)).then(() => self.skipWaiting()),\n );\n});\n\nself.addEventListener(\"activate\", (event) => {\n event.waitUntil(\n caches\n .keys()\n .then((names) =>\n Promise.all(\n names.filter((n) => n.startsWith(\"beck-shell-\") && n !== CACHE).map((n) => caches.delete(n)),\n ),\n )\n .then(() => self.clients.claim()),\n );\n});\n\nself.addEventListener(\"fetch\", (event) => {\n const url = new URL(event.request.url);\n // Only this origin, only GETs, and never the socket: a command must reach the server or be\n // queued by the client, and a cached answer to one would be a lie about the log.\n if (url.origin !== self.location.origin) return;\n if (event.request.method !== \"GET\") return;\n if (url.pathname === \"/socket\") return;\n\n event.respondWith(\n fetch(event.request)\n .then((response) => {\n // Keep the shell current. A copy is taken because a Response body is read once.\n if (response.ok && SHELL.includes(url.pathname)) {\n const copy = response.clone();\n caches.open(CACHE).then((c) => c.put(event.request, copy));\n }\n return response;\n })\n .catch(async () => {\n const hit = await caches.match(event.request);\n if (hit) return hit;\n // A route this tab has never asked for while offline. The shell answers for it, because in\n // Mode B the route is the *client\'s* to render \u{2014} it reads `location` and renders from the\n // state it holds \u{2014} so one cached document serves every route. Without this, a tab that had\n // navigated and then reloaded with no network got an error page for a route it could have\n // rendered (`docs/94` \u{a7}94.3).\n if (event.request.mode === \"navigate\") {\n const shell = await caches.match(\"/\", { ignoreSearch: true });\n if (shell) return shell;\n }\n // Nothing cached at all: say so as a page rather than as a browser error, because \"the\n // server is unreachable and this tab has never been here before\" is a different thing from\n // \"this site is broken\".\n return new Response(\"this application has not been loaded on this device before\", {\n status: 503,\n headers: { \"content-type\": \"text/plain\" },\n });\n }),\n );\n});\n";Expand description
Mode B’s service worker: the shell, cached, so a cold start with no network is a page.
Served with the program’s wire id substituted for %WIRE%, which is what keys the cache to the
program and what deletes the previous one on a deploy.