Files
simple/frontend/sw.js
T
catarrh 666fc2cf6c fix: per-AID version queries - module->applet mapping + chained GET RESPONSE (v3.7.1)
Two bugs in the v3.7.0 per-AID fallback, both visible in the live log
(2026-09-30 11:21):

- the candidate applet was searched by the AID prefix, but the applet
  instance AIDs are the package's module AIDs (package A113...0200 has
  modules ...0208 / ...494D4508, both present as applet instances - they
  differ from the package AID in the last byte), so that package produced no
  query at all.  ramElfAppletCandidate (pure) prefers the module AIDs and
  keeps the shared-prefix rule as a fallback;
- the single-AID expanded query answered 6134 (the card holds the data) and
  the empty response was read, so no version was derived.  The query is now
  retried with the GET RESPONSE chained into the compact command string
  (ramChainGetResponse) exactly like the ladder - a standalone GET RESPONSE
  answers 6700 on this card.

Tests: the module->applet mapping with the live AIDs (incl. the versioned
applet being skipped and the prefix fallback), plus the source guards for the
chained retry.

sw cache simple-v333; tests: 557 Python / 717 Node.
2026-09-30 11:30:40 +03:00

78 lines
2.1 KiB
JavaScript

const CACHE = 'simple-v333';
const URLS = [
'index.html',
'help.html',
'help-ru.html',
'style.css',
'sim.png',
'favicon.svg',
'icon-192.png',
'icon-512.png',
'manifest.json',
'des-bundle.js',
'aes-bundle.js',
'sim.svg',
'sim_anim.svg',
'nosim.svg',
'uicc_files.json',
];
self.addEventListener('install', e => {
// Fetch the shell with `cache: 'reload'`: a plain addAll() would re-use
// HTTP-cached copies, so a new SW version could precache a stale
// style.css/index.html (the stale-style trap, v3.6.31).
e.waitUntil(
caches.open(CACHE).then(c =>
Promise.all(URLS.map(u => fetch(u, { cache: 'reload' }).then(r => {
if (r && r.ok) return c.put(u, r);
})))
)
);
self.skipWaiting();
});
self.addEventListener('activate', e => {
e.waitUntil(
caches.keys().then(keys =>
Promise.all(keys.filter(k => k !== CACHE).map(k => caches.delete(k)))
).then(() => clients.claim())
);
});
const OFFLINE_RESPONSE = new Response('Offline: page not cached', {
status: 503,
statusText: 'Offline',
headers: { 'Content-Type': 'text/plain' },
});
self.addEventListener('fetch', e => {
if (!e.request.url.startsWith('http')) return;
const path = new URL(e.request.url).pathname;
if (path.startsWith('/api/')) return; // live data, never cache
if (e.request.method !== 'GET') return;
const isNavigate = e.request.mode === 'navigate';
const isSwScript = path.endsWith('/sw.js');
if (isNavigate) {
e.respondWith(
fetch(e.request).then(res => {
const clone = res.clone();
caches.open(CACHE).then(c => c.put(e.request, clone));
return res;
}).catch(() =>
caches.match(e.request)
.then(r => r || caches.match('index.html'))
.then(r => r || OFFLINE_RESPONSE)
)
);
} else if (isSwScript) {
e.respondWith(fetch(e.request).catch(() => OFFLINE_RESPONSE));
} else {
e.respondWith(
caches.match(e.request).then(r => r || fetch(e.request).then(res => {
const clone = res.clone();
caches.open(CACHE).then(c => c.put(e.request, clone));
return res;
}))
);
}
});