[FEAT] Sessione + release: refresh token silenzioso + avviso "nuova versione"
Evita la "sessione scaduta" e i deploy che restano invisibili all'utente. - api.js: refresh PROATTIVO dell'access token ~2 min prima della scadenza (scheduleTokenRefresh su exp del JWT, riprogrammato ad ogni setTokens) + ensureFreshToken() per rinnovo immediato al ritorno sulla scheda. Con refresh a 7gg l'utente resta loggato senza mai vedere il login. - common.js: watch versione (poll version.json ogni 5 min + su visibilitychange) → banner "È disponibile una nuova versione — Aggiorna" (reload) quando cambia; nudge service worker (registration.update); su visibilitychange chiama anche api.ensureFreshToken(). Nessun hard-refresh manuale. - Cache-buster api/common ?v=20260729b. version 1.25.12. Solo frontend. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
faadb62da6
commit
cf224480cc
@@ -10,6 +10,42 @@ class NIS2API {
|
||||
this.token = localStorage.getItem('nis2_access_token');
|
||||
this.refreshToken = localStorage.getItem('nis2_refresh_token');
|
||||
this.orgId = localStorage.getItem('nis2_org_id');
|
||||
this._refreshTimer = null;
|
||||
if (this.token) this.scheduleTokenRefresh();
|
||||
}
|
||||
|
||||
// ── Refresh proattivo/silenzioso ────────────────────────────────────
|
||||
// Rinnova l'access token PRIMA che scada, così l'utente non incontra 401 né deve
|
||||
// rifare il login (il refresh token dura 7 giorni). Evita la "sessione scaduta".
|
||||
_tokenExp(token) {
|
||||
try {
|
||||
const raw = (token || this.token || '').split('.')[1];
|
||||
const p = JSON.parse(atob(raw.replace(/-/g, '+').replace(/_/g, '/')));
|
||||
return (typeof p.exp === 'number') ? p.exp : 0;
|
||||
} catch (e) { return 0; }
|
||||
}
|
||||
|
||||
scheduleTokenRefresh() {
|
||||
if (this._refreshTimer) { clearTimeout(this._refreshTimer); this._refreshTimer = null; }
|
||||
if (!this.token || !this.refreshToken) return;
|
||||
const exp = this._tokenExp(this.token);
|
||||
if (!exp) return;
|
||||
let delay = exp * 1000 - Date.now() - 120000; // rinnova ~2 min prima della scadenza
|
||||
if (delay < 1000) delay = 1000;
|
||||
if (delay > 2000000000) delay = 2000000000; // cap (limite setTimeout a 32 bit)
|
||||
this._refreshTimer = setTimeout(() => {
|
||||
if (this.isAuthenticated() && this.refreshToken) this.doRefreshToken().catch(() => {});
|
||||
}, delay);
|
||||
}
|
||||
|
||||
// Rinnova SUBITO se l'access è scaduto o entro 5 min (usato al ritorno sulla scheda
|
||||
// dopo sospensione/inattività, quando i timer possono non essere scattati).
|
||||
async ensureFreshToken() {
|
||||
if (!this.token || !this.refreshToken) return;
|
||||
const exp = this._tokenExp(this.token);
|
||||
if (exp && exp * 1000 - Date.now() < 300000) {
|
||||
await this.doRefreshToken().catch(() => {});
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
@@ -133,6 +169,7 @@ class NIS2API {
|
||||
this.refreshToken = refresh;
|
||||
localStorage.setItem('nis2_access_token', access);
|
||||
localStorage.setItem('nis2_refresh_token', refresh);
|
||||
this.scheduleTokenRefresh(); // riprogramma il refresh silenzioso sul nuovo exp
|
||||
}
|
||||
|
||||
clearTokens() {
|
||||
|
||||
Reference in New Issue
Block a user