Commit the previously-untracked standard directories and catalog them in the
root README alongside proof:
- aac/ — communication cargo class: portable boards + a ten-level
offline-first cascade (Apache-2.0 code / CC-BY-4.0 spec).
- map/ — geospatial cargo class: range-requestable signed tilesets +
an F0–F4 fidelity cascade (Apache-2.0 code / CC-BY-4.0 spec).
- sandbox/— isolated, metered, attested execution across the heterogeneous
compute fabric (Apache-2.0 code / CC-BY-4.0 spec).
- jouleclaw-otel-authz, jouleclaw-trust — new jouleclaw reference crates.
Root README now lists aac, map, sandbox, and proof in the catalog, the tree,
and the contribution guide.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
92 lines
2.7 KiB
JavaScript
92 lines
2.7 KiB
JavaScript
// Service Worker for aac.transaction.science — offline-first AAC.
|
|
//
|
|
// AAC must NEVER fail because of network. This service worker
|
|
// caches everything needed for full offline communication.
|
|
// Only AI prediction (L3+) requires network, and it's optional.
|
|
|
|
const CACHE_NAME = 'aac-v1';
|
|
const OFFLINE_URL = '/';
|
|
|
|
// Core assets that must be cached for offline AAC to work.
|
|
// Names match the cargo-leptos output (output-name = "aac-web").
|
|
const CORE_ASSETS = [
|
|
'/',
|
|
'/manifest.json',
|
|
'/pkg/aac-web.js',
|
|
'/pkg/aac-web.wasm',
|
|
'/pkg/aac-web.css',
|
|
];
|
|
|
|
// Install: cache core assets
|
|
self.addEventListener('install', (event) => {
|
|
event.waitUntil(
|
|
caches.open(CACHE_NAME)
|
|
.then((cache) => cache.addAll(CORE_ASSETS))
|
|
.then(() => self.skipWaiting())
|
|
);
|
|
});
|
|
|
|
// Activate: clean old caches
|
|
self.addEventListener('activate', (event) => {
|
|
event.waitUntil(
|
|
caches.keys()
|
|
.then((keys) => Promise.all(
|
|
keys
|
|
.filter((key) => key !== CACHE_NAME)
|
|
.map((key) => caches.delete(key))
|
|
))
|
|
.then(() => self.clients.claim())
|
|
);
|
|
});
|
|
|
|
// Fetch: cache-first for assets, network-first for API
|
|
self.addEventListener('fetch', (event) => {
|
|
const url = new URL(event.request.url);
|
|
|
|
// API calls (prediction, sync) — network first, fall back to cache
|
|
if (url.pathname.startsWith('/api/')) {
|
|
event.respondWith(
|
|
fetch(event.request)
|
|
.then((response) => {
|
|
const clone = response.clone();
|
|
caches.open(CACHE_NAME).then((cache) => cache.put(event.request, clone));
|
|
return response;
|
|
})
|
|
.catch(() => caches.match(event.request))
|
|
);
|
|
return;
|
|
}
|
|
|
|
// Everything else — cache first (core AAC functionality)
|
|
event.respondWith(
|
|
caches.match(event.request)
|
|
.then((cached) => {
|
|
if (cached) {
|
|
// Return cache, update in background
|
|
fetch(event.request)
|
|
.then((response) => {
|
|
caches.open(CACHE_NAME).then((cache) => cache.put(event.request, response));
|
|
})
|
|
.catch(() => {});
|
|
return cached;
|
|
}
|
|
|
|
// Not cached — fetch and cache
|
|
return fetch(event.request)
|
|
.then((response) => {
|
|
if (response.status === 200) {
|
|
const clone = response.clone();
|
|
caches.open(CACHE_NAME).then((cache) => cache.put(event.request, clone));
|
|
}
|
|
return response;
|
|
})
|
|
.catch(() => {
|
|
// Offline and not cached — return the app shell
|
|
if (event.request.mode === 'navigate') {
|
|
return caches.match(OFFLINE_URL);
|
|
}
|
|
return new Response('Offline', { status: 503 });
|
|
});
|
|
})
|
|
);
|
|
});
|