feat: frontend error capture — diagnostic instantané pour Hermes
- app.js: intercepte window.onerror + unhandledrejection Envoie automatiquement au backend via POST /api/frontend-error Déduplication, throttling 1/sec, max 50 erreurs buffer local window.__flowdeck_errors accessible en console debug - api.py: 2 nouvelles routes POST /api/frontend-error — reçoit erreurs JS, déduplique, logge GET /api/frontend-errors?clear=true — Hermes lit les erreurs - csrf.py: exemption /api/frontend-error du CSRF Usage Hermes après chaque déploiement: curl -s http://localhost:8080/api/frontend-errors | jq . → Voir TOUTES les erreurs JS en temps réel
This commit is contained in:
@@ -1,6 +1,59 @@
|
||||
// FlowDeck Notion UI — Client-side logic
|
||||
// Alpine.js + SortableJS + HTMX + Mobile support
|
||||
|
||||
// ── Frontend Error Capture ──────────────────────────────────
|
||||
// Intercepte TOUTES les erreurs JS et les envoie au backend.
|
||||
// Hermes peut les consulter via GET /api/frontend-errors.
|
||||
(function() {
|
||||
'use strict';
|
||||
const MAX_ERRORS = 50;
|
||||
var _fd_errors = [];
|
||||
var _fd_throttle = 0;
|
||||
|
||||
function _fd_send(error) {
|
||||
_fd_errors.push(error);
|
||||
if (_fd_errors.length > MAX_ERRORS) _fd_errors.shift();
|
||||
// Throttle: max 1 POST per second
|
||||
var now = Date.now();
|
||||
if (now - _fd_throttle < 1000) return;
|
||||
_fd_throttle = now;
|
||||
try {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', '/api/frontend-error', true);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.send(JSON.stringify(error));
|
||||
} catch(e) { /* fail silently */ }
|
||||
}
|
||||
|
||||
window.addEventListener('error', function(e) {
|
||||
_fd_send({
|
||||
type: 'error',
|
||||
message: e.message || 'Unknown error',
|
||||
source: e.filename || '',
|
||||
line: e.lineno || 0,
|
||||
col: e.colno || 0,
|
||||
stack: (e.error && e.error.stack) ? String(e.error.stack).substring(0, 2000) : '',
|
||||
url: window.location.href,
|
||||
userAgent: navigator.userAgent.substring(0, 200),
|
||||
time: new Date().toISOString()
|
||||
});
|
||||
});
|
||||
|
||||
window.addEventListener('unhandledrejection', function(e) {
|
||||
_fd_send({
|
||||
type: 'unhandledrejection',
|
||||
message: e.reason ? (e.reason.message || String(e.reason)) : 'Promise rejected',
|
||||
stack: (e.reason && e.reason.stack) ? String(e.reason.stack).substring(0, 2000) : '',
|
||||
url: window.location.href,
|
||||
userAgent: navigator.userAgent.substring(0, 200),
|
||||
time: new Date().toISOString()
|
||||
});
|
||||
});
|
||||
|
||||
// Expose pour le debug console
|
||||
window.__flowdeck_errors = _fd_errors;
|
||||
})();
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user