sign.js :
- aria-label sur les 4 Fab (Se déconnecter, dashboard, Se connecter, S'enregistrer)
- Correction des guillemets typographiques U+2018/U+2019 en ASCII (empêchaient le parsing JSX)
- Suppression de useMemo inutilisé
- IIFE async ;() → startSubscription() nommée + .catch() explicite (semi-style + no-void)
auth-form/index.js :
- aria-label des IconButton visibility traduits en français avec état dynamique :
'Afficher/Masquer le mot de passe' et 'Afficher/Masquer la vérification'
version-timeline.js :
- aria-label='Comparer les versions' sur IconButton Comparer
- aria-label dynamique + aria-expanded sur le bouton expand/collapse
- Correction object-curly-newline et jsx-closing-bracket-location (pré-existants)
version-search.js :
- inputProps aria-label='Rechercher dans les versions' (placeholder seul insuffisant)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
La page d'accueil appelle auth() (cookies → dynamique) donc export const revalidate
ne s'applique pas au rendu. On cache à la place les appels Directus :
- fetchConstitution() → wrappée avec nextCache (unstable_cache)
- revalidate: 300 (5 min) — la constitution évolue peu
- tag 'constitution' — permet revalidateTag('constitution') depuis une API route
pour invalider le cache à la demande lors d'un changement Directus
Les appels API Directus (titres + articles) ne sont plus refaits à chaque requête.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sans ce correctif, l'access token Directus (~15 min) expirait silencieusement,
rendant toutes les requêtes API 401 sans déconnecter l'utilisateur.
- Ajout de refreshDirectusToken() : POST /auth/refresh avec rotation du refresh_token
- accessTokenExpires stocké dès la connexion (expires Directus - marge 60s)
- jwt callback : token valide → pass-through, token expiré → refresh, échec → error flag
- session callback : propagation de session.error = 'RefreshAccessTokenError'
(permet au client de forcer un signOut si le refresh_token est lui-même expiré)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
export-pdf-button et print-button injectaient marked(content) directement
dans innerHTML / document.write. Un lien Markdown javascript: passait le
filtre hasRestrictedChar et pouvait s'exécuter.
Ajout de DOMPurify.sanitize() via import dynamique (déjà présent en dep
transitive de jspdf) sur les deux composants, avec whitelist de tags
et d'attributs stricte. markdown-renderer n'est pas touché car
react-markdown-preview utilise rehype-sanitize en interne.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Ajout de lib/rate-limit.js : fabrique de limiter en mémoire (closure +
Map avec nettoyage lazy), sans dépendance externe, réutilisable
- Ajout de middleware.js : intercepte /api/auth/register (5 req/15min)
et /api/auth/callback/credentials (10 req/5min), répond 429 + Retry-After
- Ajout de tasks/todo.md et tasks/lessons.md (suivi CLAUDE.md)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>