juxscript 1.1.153 → 1.1.154
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/machinery/errors.js +134 -113
- package/package.json +1 -1
package/machinery/errors.js
CHANGED
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Generates an injectable client-side error collector script.
|
|
3
|
-
*
|
|
4
|
-
* Displays them in a floating overlay panel in the browser.
|
|
3
|
+
* Full-screen overlay similar to Vite's error screen.
|
|
5
4
|
*
|
|
6
5
|
* @param {Object} options
|
|
7
|
-
* @param {boolean} [options.enabled=true]
|
|
8
|
-
* @param {number} [options.maxErrors=50]
|
|
9
|
-
* @param {string} [options.position='bottom-right'] - Panel position
|
|
6
|
+
* @param {boolean} [options.enabled=true]
|
|
7
|
+
* @param {number} [options.maxErrors=50]
|
|
10
8
|
* @returns {string} Inline script to inject into HTML
|
|
11
9
|
*/
|
|
12
10
|
export function generateErrorCollector(options = {}) {
|
|
13
11
|
const {
|
|
14
12
|
enabled = true,
|
|
15
|
-
maxErrors = 50
|
|
16
|
-
position = 'bottom-right'
|
|
13
|
+
maxErrors = 50
|
|
17
14
|
} = options;
|
|
18
15
|
|
|
19
16
|
if (!enabled) return '';
|
|
@@ -21,93 +18,110 @@ export function generateErrorCollector(options = {}) {
|
|
|
21
18
|
return `
|
|
22
19
|
<script>
|
|
23
20
|
(function() {
|
|
24
|
-
var
|
|
25
|
-
var
|
|
26
|
-
var
|
|
27
|
-
var
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
'
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
'
|
|
45
|
-
'
|
|
46
|
-
'
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
'border:1px solid #e74c3c;border-radius:8px;font-family:monospace;' +
|
|
61
|
-
'font-size:1rem;display:flex;flex-direction:column;' +
|
|
62
|
-
'box-shadow:0 4px 16px rgba(0,0,0,0.4);'
|
|
63
|
-
);
|
|
64
|
-
|
|
65
|
-
// Header
|
|
21
|
+
var __errors = [];
|
|
22
|
+
var __maxErrors = ${maxErrors};
|
|
23
|
+
var __overlay = null;
|
|
24
|
+
var __list = null;
|
|
25
|
+
|
|
26
|
+
function createOverlay() {
|
|
27
|
+
__overlay = document.createElement('div');
|
|
28
|
+
__overlay.id = '__jux-error-overlay';
|
|
29
|
+
__overlay.setAttribute('style', [
|
|
30
|
+
'position:fixed',
|
|
31
|
+
'top:0',
|
|
32
|
+
'left:0',
|
|
33
|
+
'width:100vw',
|
|
34
|
+
'height:100vh',
|
|
35
|
+
'z-index:99999',
|
|
36
|
+
'background:rgba(0,0,0,0.85)',
|
|
37
|
+
'color:#f8f8f8',
|
|
38
|
+
'font-family:monospace',
|
|
39
|
+
'font-size:14px',
|
|
40
|
+
'overflow-y:auto',
|
|
41
|
+
'padding:0',
|
|
42
|
+
'margin:0',
|
|
43
|
+
'box-sizing:border-box'
|
|
44
|
+
].join(';'));
|
|
45
|
+
|
|
46
|
+
var container = document.createElement('div');
|
|
47
|
+
container.setAttribute('style', [
|
|
48
|
+
'max-width:960px',
|
|
49
|
+
'margin:40px auto',
|
|
50
|
+
'padding:24px 32px',
|
|
51
|
+
'border:2px solid #ff5555',
|
|
52
|
+
'border-radius:8px',
|
|
53
|
+
'background:#1a1a1a'
|
|
54
|
+
].join(';'));
|
|
55
|
+
|
|
56
|
+
// Title bar
|
|
66
57
|
var header = document.createElement('div');
|
|
67
|
-
header.setAttribute('style',
|
|
68
|
-
'
|
|
69
|
-
'
|
|
70
|
-
'
|
|
71
|
-
|
|
72
|
-
|
|
58
|
+
header.setAttribute('style', [
|
|
59
|
+
'display:flex',
|
|
60
|
+
'justify-content:space-between',
|
|
61
|
+
'align-items:center',
|
|
62
|
+
'margin-bottom:16px',
|
|
63
|
+
'padding-bottom:12px',
|
|
64
|
+
'border-bottom:1px solid #333'
|
|
65
|
+
].join(';'));
|
|
66
|
+
|
|
67
|
+
var title = document.createElement('div');
|
|
68
|
+
title.setAttribute('style', 'color:#ff5555;font-size:16px;font-weight:bold;');
|
|
69
|
+
title.textContent = 'Runtime Error';
|
|
70
|
+
header.appendChild(title);
|
|
71
|
+
|
|
72
|
+
var actions = document.createElement('div');
|
|
73
|
+
actions.setAttribute('style', 'display:flex;gap:8px;');
|
|
73
74
|
|
|
74
75
|
var clearBtn = document.createElement('button');
|
|
75
76
|
clearBtn.textContent = 'Clear';
|
|
76
|
-
clearBtn.setAttribute('style',
|
|
77
|
-
'background:transparent
|
|
78
|
-
'
|
|
79
|
-
|
|
77
|
+
clearBtn.setAttribute('style', [
|
|
78
|
+
'background:transparent',
|
|
79
|
+
'border:1px solid #555',
|
|
80
|
+
'color:#aaa',
|
|
81
|
+
'padding:4px 12px',
|
|
82
|
+
'border-radius:4px',
|
|
83
|
+
'cursor:pointer',
|
|
84
|
+
'font-family:monospace',
|
|
85
|
+
'font-size:12px'
|
|
86
|
+
].join(';'));
|
|
80
87
|
clearBtn.addEventListener('click', clearErrors);
|
|
81
|
-
header.appendChild(clearBtn);
|
|
82
|
-
|
|
83
|
-
__juxPanel.appendChild(header);
|
|
84
|
-
|
|
85
|
-
// List
|
|
86
|
-
__juxList = document.createElement('div');
|
|
87
|
-
__juxList.setAttribute('style',
|
|
88
|
-
'overflow-y:auto;max-height:300px;padding:8px;'
|
|
89
|
-
);
|
|
90
|
-
__juxPanel.appendChild(__juxList);
|
|
91
88
|
|
|
92
|
-
document.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
89
|
+
var closeBtn = document.createElement('button');
|
|
90
|
+
closeBtn.textContent = 'Close';
|
|
91
|
+
closeBtn.setAttribute('style', [
|
|
92
|
+
'background:transparent',
|
|
93
|
+
'border:1px solid #555',
|
|
94
|
+
'color:#aaa',
|
|
95
|
+
'padding:4px 12px',
|
|
96
|
+
'border-radius:4px',
|
|
97
|
+
'cursor:pointer',
|
|
98
|
+
'font-family:monospace',
|
|
99
|
+
'font-size:12px'
|
|
100
|
+
].join(';'));
|
|
101
|
+
closeBtn.addEventListener('click', function() {
|
|
102
|
+
__overlay.style.display = 'none';
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
actions.appendChild(clearBtn);
|
|
106
|
+
actions.appendChild(closeBtn);
|
|
107
|
+
header.appendChild(actions);
|
|
108
|
+
container.appendChild(header);
|
|
109
|
+
|
|
110
|
+
__list = document.createElement('div');
|
|
111
|
+
container.appendChild(__list);
|
|
112
|
+
|
|
113
|
+
__overlay.appendChild(container);
|
|
114
|
+
document.body.appendChild(__overlay);
|
|
98
115
|
}
|
|
99
116
|
|
|
100
117
|
function clearErrors() {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
__juxBadge.style.display = 'none';
|
|
105
|
-
__juxPanel.style.display = 'none';
|
|
106
|
-
__juxVisible = false;
|
|
118
|
+
__errors = [];
|
|
119
|
+
if (__list) __list.innerHTML = '';
|
|
120
|
+
if (__overlay) __overlay.style.display = 'none';
|
|
107
121
|
}
|
|
108
122
|
|
|
109
123
|
function addError(type, message, source, line, col, stack) {
|
|
110
|
-
if (
|
|
124
|
+
if (__errors.length >= __maxErrors) __errors.shift();
|
|
111
125
|
|
|
112
126
|
var entry = {
|
|
113
127
|
type: type,
|
|
@@ -118,39 +132,50 @@ export function generateErrorCollector(options = {}) {
|
|
|
118
132
|
stack: stack || '',
|
|
119
133
|
time: new Date().toLocaleTimeString()
|
|
120
134
|
};
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if (!__juxPanel) createPanel();
|
|
135
|
+
__errors.push(entry);
|
|
124
136
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
__juxBadge.style.display = 'flex';
|
|
137
|
+
if (!__overlay) createOverlay();
|
|
138
|
+
__overlay.style.display = 'block';
|
|
128
139
|
|
|
129
|
-
// ✅ Auto-open panel on first error
|
|
130
|
-
if (!__juxVisible) {
|
|
131
|
-
__juxVisible = true;
|
|
132
|
-
__juxPanel.style.display = 'flex';
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Add to list
|
|
136
140
|
var item = document.createElement('div');
|
|
137
|
-
item.setAttribute('style',
|
|
138
|
-
'padding:
|
|
139
|
-
'
|
|
140
|
-
|
|
141
|
+
item.setAttribute('style', [
|
|
142
|
+
'padding:12px 16px',
|
|
143
|
+
'margin-bottom:8px',
|
|
144
|
+
'background:#222',
|
|
145
|
+
'border-left:3px solid #ff5555',
|
|
146
|
+
'border-radius:4px'
|
|
147
|
+
].join(';'));
|
|
148
|
+
|
|
149
|
+
var typeLabel = type === 'error' ? 'Error' : type === 'rejection' ? 'Unhandled Rejection' : 'console.error';
|
|
141
150
|
|
|
142
|
-
var
|
|
151
|
+
var meta = entry.source ? entry.source + ':' + entry.line + ':' + entry.col : '';
|
|
143
152
|
|
|
144
153
|
item.innerHTML =
|
|
145
|
-
'<div style="color:#888;font-size:
|
|
146
|
-
|
|
147
|
-
|
|
154
|
+
'<div style="color:#888;font-size:12px;margin-bottom:4px;">' +
|
|
155
|
+
typeLabel + (meta ? ' ' + escapeHtml(meta) : '') +
|
|
156
|
+
'<span style="float:right;">' + entry.time + '</span>' +
|
|
148
157
|
'</div>' +
|
|
149
|
-
'<div style="word-break:break-word;">' +
|
|
150
|
-
|
|
158
|
+
'<div style="color:#ff8888;white-space:pre-wrap;word-break:break-word;">' +
|
|
159
|
+
escapeHtml(entry.message) +
|
|
160
|
+
'</div>' +
|
|
161
|
+
(entry.stack ?
|
|
162
|
+
'<pre style="margin:8px 0 0;padding:8px;font-size:12px;color:#888;' +
|
|
163
|
+
'white-space:pre-wrap;background:#1a1a1a;border-radius:4px;' +
|
|
164
|
+
'border:1px solid #333;max-height:200px;overflow-y:auto;">' +
|
|
165
|
+
escapeHtml(cleanStack(entry.stack)) +
|
|
166
|
+
'</pre>'
|
|
167
|
+
: '');
|
|
168
|
+
|
|
169
|
+
__list.appendChild(item);
|
|
170
|
+
}
|
|
151
171
|
|
|
152
|
-
|
|
153
|
-
|
|
172
|
+
function cleanStack(stack) {
|
|
173
|
+
// Remove the first line if it duplicates the message
|
|
174
|
+
var lines = stack.split('\\n');
|
|
175
|
+
if (lines.length > 1 && lines[0].indexOf('Error:') !== -1) {
|
|
176
|
+
lines.shift();
|
|
177
|
+
}
|
|
178
|
+
return lines.join('\\n').trim();
|
|
154
179
|
}
|
|
155
180
|
|
|
156
181
|
function escapeHtml(str) {
|
|
@@ -159,12 +184,10 @@ export function generateErrorCollector(options = {}) {
|
|
|
159
184
|
|
|
160
185
|
// --- Hooks ---
|
|
161
186
|
|
|
162
|
-
// 1. window.onerror
|
|
163
187
|
window.onerror = function(msg, source, line, col, err) {
|
|
164
188
|
addError('error', msg, source, line, col, err && err.stack ? err.stack : '');
|
|
165
189
|
};
|
|
166
190
|
|
|
167
|
-
// 2. Unhandled promise rejections
|
|
168
191
|
window.addEventListener('unhandledrejection', function(e) {
|
|
169
192
|
var reason = e.reason;
|
|
170
193
|
var msg = reason instanceof Error ? reason.message : String(reason);
|
|
@@ -172,7 +195,6 @@ export function generateErrorCollector(options = {}) {
|
|
|
172
195
|
addError('rejection', msg, '', 0, 0, stack);
|
|
173
196
|
});
|
|
174
197
|
|
|
175
|
-
// 3. Intercept console.error
|
|
176
198
|
var _origConsoleError = console.error;
|
|
177
199
|
console.error = function() {
|
|
178
200
|
var args = Array.prototype.slice.call(arguments);
|
|
@@ -183,11 +205,10 @@ export function generateErrorCollector(options = {}) {
|
|
|
183
205
|
_origConsoleError.apply(console, arguments);
|
|
184
206
|
};
|
|
185
207
|
|
|
186
|
-
// Expose API for programmatic access
|
|
187
208
|
window.__juxErrors = {
|
|
188
|
-
list: function() { return
|
|
209
|
+
list: function() { return __errors.slice(); },
|
|
189
210
|
clear: clearErrors,
|
|
190
|
-
count: function() { return
|
|
211
|
+
count: function() { return __errors.length; }
|
|
191
212
|
};
|
|
192
213
|
})();
|
|
193
214
|
</script>`;
|