// Enregistrement du service worker et bandeau de mise à jour. // // Pourquoi ce fichier existe (et pourquoi il n'est pas qu'une ligne `register(...)`) : // // 1. Les empreintes des assets WASM sont DÉSACTIVÉES (voir CLAUDE.md). `blazor.webassembly.js` // et `dotnet.js` portent donc des noms stables, et c'est le service worker — lui seul — qui // empêche de servir éternellement une version périmée. Le mécanisme de Blazor fonctionne, // mais il est silencieux et différé : le nouveau worker attend que TOUS les onglets de // l'application soient fermés. Sur mobile, un onglet oublié fige la mise à jour sans que // personne comprenne pourquoi. D'où un bandeau explicite, avec un bouton qui l'applique. // // 2. `navigator.serviceWorker` n'existe pas en contexte non sécurisé (http sur une IP locale). // L'appeler sans vérification lève une TypeError qui casse le script — et fait croire à un // défaut de la PWA alors que c'est le contexte qui n'est pas éligible. (function () { 'use strict'; if (!('serviceWorker' in navigator)) { // Cas normal en http sur une IP de réseau local : rien à signaler à l'utilisateur, // l'application fonctionne, elle n'est simplement pas installable ni hors-ligne. console.info('Service worker indisponible (contexte non sécurisé ou navigateur sans support).'); return; } // Le rechargement n'a lieu que si l'utilisateur a cliqué : un changement de contrôleur // survient aussi à la toute première installation, et recharger la page à ce moment-là // serait un clignotement inexplicable. let demandee = false; function proposerLaMiseAJour(enAttente) { if (document.getElementById('mb-maj')) return; const barre = document.createElement('div'); barre.id = 'mb-maj'; barre.setAttribute('role', 'status'); barre.textContent = 'Une nouvelle version de MaBibli est disponible. '; const bouton = document.createElement('button'); bouton.type = 'button'; bouton.textContent = 'Mettre à jour'; bouton.addEventListener('click', function () { bouton.disabled = true; demandee = true; // Le worker en attente prend la main sans qu'on ait à fermer tous les onglets. enAttente.postMessage({ type: 'SKIP_WAITING' }); }); barre.appendChild(bouton); document.body.appendChild(barre); } navigator.serviceWorker.register('service-worker.js', { updateViaCache: 'none' }) .then(function (enregistrement) { // Un worker déjà installé attendait peut-être depuis la visite précédente. if (enregistrement.waiting && navigator.serviceWorker.controller) { proposerLaMiseAJour(enregistrement.waiting); } enregistrement.addEventListener('updatefound', function () { const nouveau = enregistrement.installing; if (!nouveau) return; nouveau.addEventListener('statechange', function () { // `controller` non nul = ce n'est pas la première installation, donc il y a // bien une version précédente à remplacer. if (nouveau.state === 'installed' && navigator.serviceWorker.controller) { proposerLaMiseAJour(nouveau); } }); }); // Vérification explicite à chaque chargement : ne pas dépendre du seul rythme // interne du navigateur pour découvrir une version plus récente. enregistrement.update().catch(function () { /* hors-ligne : sans objet */ }); }) .catch(function (erreur) { // Ne jamais laisser cet échec passer inaperçu : sans service worker, l'application // ne démarre pas hors-ligne, et le cache IndexedDB ne sert alors à rien. console.error("Échec de l'enregistrement du service worker :", erreur); }); let recharge = false; navigator.serviceWorker.addEventListener('controllerchange', function () { if (!demandee || recharge) return; recharge = true; window.location.reload(); }); })();