9cbf301f09
The Push commands pill now has three sub-pills: Trigger (Push SMS), Store (SD admin params) and Channel / link trigger, which builds all three TS 102 226 §9 establishment requests - 01 BIP channel opening (OPEN CHANNEL), 02 CAT_TP link, 03 TCP connection - with one shared destination-port field and per-request field visibility. The TCP parameters are the OPEN CHANNEL TCP set (BIP, or a direct IP connection per TS 102 483 where supported), so 03 belongs with the other channel/link requests. The identification packet (04) is not a trigger: it presupposes an already open TCP channel and only makes sense as a follow-up in the same message, so it is no longer a standalone request. The TCP request carries an "Also send the identification packet (04) in the same message" checkbox (optional data, ICCID when empty): the preview then shows both commands (a command string sent in one secured packet) and → Expanded Script appends one 22 Command TLV per command. pushSectionApdus() returns the APDU list; 04 stays available in the RAM/GP chain's PUSH row for script sequences. Help 2.7 EN/RU, READMEs and AGENTS describe the three sub-pills and the BIP vs direct-IP nuance; sw cache -> simple-v249; version stays 3.5.0. html.test.js also asserts that the document is complete (ends with </html>, every <script> closed, the inline script parses and defines cApduSwitchSubtab): a truncated index.html made the browser fail to parse the inline script, so every onclick handler reported "function is not defined" while the Node tests still passed.
71 lines
1.8 KiB
JavaScript
71 lines
1.8 KiB
JavaScript
const CACHE = 'simple-v249';
|
|
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 => {
|
|
e.waitUntil(
|
|
caches.open(CACHE).then(c => c.addAll(URLS))
|
|
);
|
|
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;
|
|
}))
|
|
);
|
|
}
|
|
}); |