claw-dashboard 1.9.0 → 2.0.0
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/.c8rc.json +38 -0
- package/.dockerignore +68 -0
- package/.github/dependabot.yml +45 -0
- package/.github/pull_request_template.md +39 -0
- package/.github/workflows/ci.yml +147 -0
- package/.github/workflows/release.yml +40 -0
- package/.github/workflows/security.yml +84 -0
- package/.husky/pre-commit +1 -0
- package/.planning/codebase/ARCHITECTURE.md +206 -0
- package/.planning/codebase/INTEGRATIONS.md +150 -0
- package/.planning/codebase/STACK.md +122 -0
- package/.planning/codebase/STRUCTURE.md +201 -0
- package/CHANGELOG.md +293 -0
- package/CONTRIBUTING.md +378 -0
- package/Dockerfile +54 -0
- package/FEATURES.md +195 -21
- package/README.md +83 -6
- package/TODO.md +28 -0
- package/build-cjs.js +127 -0
- package/cjs-shim.js +13 -0
- package/dist/clawdash +1729 -0
- package/dist/clawdash.meta.json +2236 -0
- package/dist/widgets.cjs +6511 -0
- package/docker-compose.yml +67 -0
- package/docs/API.md +1050 -0
- package/docs/PLUGINS.md +1504 -0
- package/esbuild.config.js +158 -0
- package/eslint.config.js +56 -0
- package/examples/plugins/README.md +122 -0
- package/examples/plugins/api-status/index.js +294 -0
- package/examples/plugins/api-status/plugin.json +19 -0
- package/examples/plugins/hello-world/index.js +104 -0
- package/examples/plugins/hello-world/plugin.json +15 -0
- package/examples/plugins/system-metrics-chart/index.js +339 -0
- package/examples/plugins/system-metrics-chart/plugin.json +18 -0
- package/examples/plugins/weather-widget/index.js +136 -0
- package/examples/plugins/weather-widget/plugin.json +19 -0
- package/index.cjs +23005 -0
- package/index.js +5236 -566
- package/jest.config.js +11 -0
- package/man/clawdash.1 +276 -0
- package/package.json +54 -5
- package/schemas/plugin-manifest.json +128 -0
- package/scripts/release.js +595 -0
- package/src/alerts.js +693 -0
- package/src/auto-save.js +584 -0
- package/src/cache.js +390 -0
- package/src/checksum.js +146 -0
- package/src/cli/args.js +110 -0
- package/src/cli/export-schedule.js +423 -0
- package/src/cli/export-snapshot.js +138 -0
- package/src/cli/help.js +69 -0
- package/src/cli/import-snapshot.js +230 -0
- package/src/cli/index.js +14 -0
- package/src/cli/list-templates.js +69 -0
- package/src/cli/validate-config.js +76 -0
- package/src/cli/validate-plugin.js +187 -0
- package/src/cli/version.js +15 -0
- package/src/config-validator.js +586 -0
- package/src/config-watcher.js +401 -0
- package/src/config.js +684 -0
- package/src/container-detector.js +499 -0
- package/src/database.js +734 -0
- package/src/differential-render.js +327 -0
- package/src/errors.js +169 -0
- package/src/export-scheduler.js +581 -0
- package/src/gateway-manager.js +685 -0
- package/src/hints.js +371 -0
- package/src/loading-states.js +509 -0
- package/src/logger.js +185 -0
- package/src/memory-pressure.js +467 -0
- package/src/performance-monitor.js +374 -0
- package/src/plugin-errors.js +586 -0
- package/src/plugin-manifest-validator.js +219 -0
- package/src/plugin-reload.js +481 -0
- package/src/plugin-scaffold.js +1941 -0
- package/src/plugin-validator.js +284 -0
- package/src/retry.js +218 -0
- package/src/security.js +860 -0
- package/src/snapshot.js +372 -0
- package/src/splash.js +115 -0
- package/src/theme-selector.js +411 -0
- package/src/themes.js +874 -0
- package/src/transitions.js +534 -0
- package/src/types.d.ts +174 -0
- package/src/validation.js +926 -0
- package/src/web-server.js +885 -0
- package/src/widgets/builtin-widgets.js +1057 -0
- package/src/widgets/config-processor.js +401 -0
- package/src/widgets/dependency-resolver.js +596 -0
- package/src/widgets/index.js +79 -0
- package/src/widgets/plugin-api.js +845 -0
- package/src/widgets/widget-error-boundary.js +773 -0
- package/src/widgets/widget-error-isolation.js +551 -0
- package/src/widgets/widget-loader.js +1437 -0
- package/src/workers/system-worker.js +130 -0
- package/src/workers/worker-pool.js +633 -0
- package/tests/alerts.test.js +437 -0
- package/tests/auto-save.test.js +529 -0
- package/tests/cache.test.js +317 -0
- package/tests/cli.test.js +351 -0
- package/tests/command-palette.test.js +320 -0
- package/tests/config-processor.test.js +452 -0
- package/tests/config-validator.test.js +710 -0
- package/tests/config-watcher.test.js +594 -0
- package/tests/config.test.js +755 -0
- package/tests/database.test.js +438 -0
- package/tests/errors.test.js +189 -0
- package/tests/example-plugins.test.js +624 -0
- package/tests/integration.test.js +1321 -0
- package/tests/loading-states.test.js +300 -0
- package/tests/manifest-validation-on-load.test.js +671 -0
- package/tests/performance-monitor.test.js +190 -0
- package/tests/plugin-api-rate-limit.test.js +302 -0
- package/tests/plugin-errors.test.js +311 -0
- package/tests/plugin-lifecycle-e2e.test.js +1036 -0
- package/tests/plugin-reload.test.js +764 -0
- package/tests/rate-limiter.test.js +539 -0
- package/tests/retry.test.js +308 -0
- package/tests/security.test.js +411 -0
- package/tests/settings-modal.test.js +226 -0
- package/tests/theme-selector.test.js +57 -0
- package/tests/utils.js +242 -0
- package/tests/utils.test.js +317 -0
- package/tests/validate-plugin-cli.test.js +359 -0
- package/tests/validation.test.js +837 -0
- package/tests/web-server.test.js +646 -0
- package/tests/widget-arrange-mode.test.js +183 -0
- package/tests/widget-config-hot-reload.test.js +465 -0
- package/tests/widget-dependency.test.js +591 -0
- package/tests/widget-error-boundary.test.js +749 -0
- package/tests/widget-error-isolation.test.js +469 -0
- package/tests/widget-integration.test.js +1147 -0
- package/tests/widget-refresh-intervals.test.js +284 -0
- package/tests/worker-pool.test.js +522 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Differential Rendering Module
|
|
3
|
+
* Optimizes blessed screen rendering by tracking widget state and only
|
|
4
|
+
* updating components that have actually changed.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import logger from './logger.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Widget state tracker for differential rendering
|
|
11
|
+
* Tracks content, styles, and labels to minimize unnecessary re-renders
|
|
12
|
+
*/
|
|
13
|
+
export class WidgetStateTracker {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.states = new Map();
|
|
16
|
+
this.stats = {
|
|
17
|
+
totalUpdates: 0,
|
|
18
|
+
skippedUpdates: 0,
|
|
19
|
+
actualUpdates: 0,
|
|
20
|
+
screenRenders: 0,
|
|
21
|
+
skippedRenders: 0
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Generate a hash for comparing complex objects
|
|
27
|
+
* @param {*} value - Value to hash
|
|
28
|
+
* @returns {string} Hash string
|
|
29
|
+
*/
|
|
30
|
+
_hash(value) {
|
|
31
|
+
if (value === null || value === undefined) return String(value);
|
|
32
|
+
if (typeof value === 'object') return JSON.stringify(value);
|
|
33
|
+
return String(value);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Track widget content update
|
|
38
|
+
* @param {string} widgetId - Unique widget identifier
|
|
39
|
+
* @param {string} newContent - New content to set
|
|
40
|
+
* @param {Function} updateFn - Function to call if update is needed
|
|
41
|
+
* @returns {boolean} True if update was performed
|
|
42
|
+
*/
|
|
43
|
+
trackContent(widgetId, newContent, updateFn) {
|
|
44
|
+
const key = `${widgetId}:content`;
|
|
45
|
+
const current = this.states.get(key);
|
|
46
|
+
const newValue = String(newContent ?? '');
|
|
47
|
+
|
|
48
|
+
this.stats.totalUpdates++;
|
|
49
|
+
|
|
50
|
+
if (current === newValue) {
|
|
51
|
+
this.stats.skippedUpdates++;
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
this.states.set(key, newValue);
|
|
56
|
+
this.stats.actualUpdates++;
|
|
57
|
+
updateFn(newValue);
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Track style update for a widget
|
|
63
|
+
* @param {string} widgetId - Unique widget identifier
|
|
64
|
+
* @param {string} styleProp - Style property name
|
|
65
|
+
* @param {*} newValue - New style value
|
|
66
|
+
* @param {Function} updateFn - Function to call if update is needed
|
|
67
|
+
* @returns {boolean} True if update was performed
|
|
68
|
+
*/
|
|
69
|
+
trackStyle(widgetId, styleProp, newValue, updateFn) {
|
|
70
|
+
const key = `${widgetId}:style:${styleProp}`;
|
|
71
|
+
const current = this.states.get(key);
|
|
72
|
+
const hashedNew = this._hash(newValue);
|
|
73
|
+
|
|
74
|
+
if (current === hashedNew) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
this.states.set(key, hashedNew);
|
|
79
|
+
updateFn(newValue);
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Track label update for a widget
|
|
85
|
+
* @param {string} widgetId - Unique widget identifier
|
|
86
|
+
* @param {string} newLabel - New label value
|
|
87
|
+
* @param {Function} updateFn - Function to call if update is needed
|
|
88
|
+
* @returns {boolean} True if update was performed
|
|
89
|
+
*/
|
|
90
|
+
trackLabel(widgetId, newLabel, updateFn) {
|
|
91
|
+
const key = `${widgetId}:label`;
|
|
92
|
+
const current = this.states.get(key);
|
|
93
|
+
const newValue = String(newLabel ?? '');
|
|
94
|
+
|
|
95
|
+
if (current === newValue) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
this.states.set(key, newValue);
|
|
100
|
+
updateFn(newValue);
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Reset state for a specific widget (e.g., after resize)
|
|
106
|
+
* @param {string} widgetId - Widget identifier
|
|
107
|
+
*/
|
|
108
|
+
resetWidget(widgetId) {
|
|
109
|
+
for (const key of this.states.keys()) {
|
|
110
|
+
if (key.startsWith(`${widgetId}:`)) {
|
|
111
|
+
this.states.delete(key);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Reset all tracked state
|
|
118
|
+
*/
|
|
119
|
+
resetAll() {
|
|
120
|
+
this.states.clear();
|
|
121
|
+
logger.debug('Differential render state reset');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Get current statistics
|
|
126
|
+
* @returns {Object} Statistics object
|
|
127
|
+
*/
|
|
128
|
+
getStats() {
|
|
129
|
+
const efficiency = this.stats.totalUpdates > 0
|
|
130
|
+
? ((this.stats.skippedUpdates / this.stats.totalUpdates) * 100).toFixed(1)
|
|
131
|
+
: 0;
|
|
132
|
+
const renderEfficiency = this.stats.screenRenders > 0
|
|
133
|
+
? ((this.stats.skippedRenders / (this.stats.screenRenders + this.stats.skippedRenders)) * 100).toFixed(1)
|
|
134
|
+
: 0;
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
...this.stats,
|
|
138
|
+
efficiency: `${efficiency}%`,
|
|
139
|
+
renderEfficiency: `${renderEfficiency}%`,
|
|
140
|
+
trackedWidgets: this.states.size
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Reset statistics
|
|
146
|
+
*/
|
|
147
|
+
resetStats() {
|
|
148
|
+
this.stats = {
|
|
149
|
+
totalUpdates: 0,
|
|
150
|
+
skippedUpdates: 0,
|
|
151
|
+
actualUpdates: 0,
|
|
152
|
+
screenRenders: 0,
|
|
153
|
+
skippedRenders: 0
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Differential renderer that batches updates and minimizes screen.render() calls
|
|
160
|
+
*/
|
|
161
|
+
export class DifferentialRenderer {
|
|
162
|
+
constructor(screen) {
|
|
163
|
+
this.screen = screen;
|
|
164
|
+
this.tracker = new WidgetStateTracker();
|
|
165
|
+
this.pendingChanges = new Set();
|
|
166
|
+
this.batchMode = false;
|
|
167
|
+
this.deferredRender = null;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Start batching mode - screen.render() will be deferred
|
|
172
|
+
*/
|
|
173
|
+
beginBatch() {
|
|
174
|
+
this.batchMode = true;
|
|
175
|
+
this.pendingChanges.clear();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* End batching and render if changes occurred
|
|
180
|
+
*/
|
|
181
|
+
endBatch() {
|
|
182
|
+
this.batchMode = false;
|
|
183
|
+
const hasChanges = this.pendingChanges.size > 0;
|
|
184
|
+
this.pendingChanges.clear();
|
|
185
|
+
|
|
186
|
+
if (hasChanges) {
|
|
187
|
+
this.tracker.stats.screenRenders++;
|
|
188
|
+
this.screen.render();
|
|
189
|
+
return true;
|
|
190
|
+
} else {
|
|
191
|
+
this.tracker.stats.skippedRenders++;
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Request a screen render, may be deferred in batch mode
|
|
198
|
+
*/
|
|
199
|
+
requestRender() {
|
|
200
|
+
if (this.batchMode) {
|
|
201
|
+
this.pendingChanges.add('render');
|
|
202
|
+
} else {
|
|
203
|
+
this.tracker.stats.screenRenders++;
|
|
204
|
+
this.screen.render();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Set widget content with differential tracking
|
|
210
|
+
* @param {string} widgetId - Widget identifier
|
|
211
|
+
* @param {Object} widget - Blessed widget
|
|
212
|
+
* @param {string} content - New content
|
|
213
|
+
* @returns {boolean} True if content was updated
|
|
214
|
+
*/
|
|
215
|
+
setContent(widgetId, widget, content) {
|
|
216
|
+
if (!widget || widget.destroyed) return false;
|
|
217
|
+
|
|
218
|
+
const changed = this.tracker.trackContent(widgetId, content, (newContent) => {
|
|
219
|
+
widget.setContent(newContent);
|
|
220
|
+
this.pendingChanges.add(widgetId);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
return changed;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Set widget style property with differential tracking
|
|
228
|
+
* @param {string} widgetId - Widget identifier
|
|
229
|
+
* @param {Object} widget - Blessed widget
|
|
230
|
+
* @param {string} prop - Style property
|
|
231
|
+
* @param {*} value - New value
|
|
232
|
+
* @returns {boolean} True if style was updated
|
|
233
|
+
*/
|
|
234
|
+
setStyle(widgetId, widget, prop, value) {
|
|
235
|
+
if (!widget || widget.destroyed) return false;
|
|
236
|
+
|
|
237
|
+
const changed = this.tracker.trackStyle(widgetId, prop, value, (newValue) => {
|
|
238
|
+
widget.style[prop] = newValue;
|
|
239
|
+
this.pendingChanges.add(`${widgetId}:style`);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
return changed;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Set widget foreground color with differential tracking
|
|
247
|
+
* @param {string} widgetId - Widget identifier
|
|
248
|
+
* @param {Object} widget - Blessed widget
|
|
249
|
+
* @param {string} color - New color
|
|
250
|
+
* @returns {boolean} True if color was updated
|
|
251
|
+
*/
|
|
252
|
+
setFg(widgetId, widget, color) {
|
|
253
|
+
return this.setStyle(widgetId, widget, 'fg', color);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Set border color with differential tracking
|
|
258
|
+
* @param {string} widgetId - Widget identifier
|
|
259
|
+
* @param {Object} widget - Blessed widget with border
|
|
260
|
+
* @param {string} color - New color
|
|
261
|
+
* @returns {boolean} True if border was updated
|
|
262
|
+
*/
|
|
263
|
+
setBorderFg(widgetId, widget, color) {
|
|
264
|
+
if (!widget || widget.destroyed || !widget.style.border) return false;
|
|
265
|
+
|
|
266
|
+
const changed = this.tracker.trackStyle(widgetId, 'border.fg', color, (newValue) => {
|
|
267
|
+
widget.style.border.fg = newValue;
|
|
268
|
+
this.pendingChanges.add(`${widgetId}:border`);
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
return changed;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Set widget label with differential tracking
|
|
276
|
+
* @param {string} widgetId - Widget identifier
|
|
277
|
+
* @param {Object} widget - Blessed widget
|
|
278
|
+
* @param {string} label - New label
|
|
279
|
+
* @returns {boolean} True if label was updated
|
|
280
|
+
*/
|
|
281
|
+
setLabel(widgetId, widget, label) {
|
|
282
|
+
if (!widget || widget.destroyed) return false;
|
|
283
|
+
|
|
284
|
+
const changed = this.tracker.trackLabel(widgetId, label, (newLabel) => {
|
|
285
|
+
widget.setLabel(newLabel);
|
|
286
|
+
this.pendingChanges.add(`${widgetId}:label`);
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
return changed;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Reset state for a widget (useful after resize events)
|
|
294
|
+
* @param {string} widgetId - Widget identifier
|
|
295
|
+
*/
|
|
296
|
+
resetWidget(widgetId) {
|
|
297
|
+
this.tracker.resetWidget(widgetId);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Reset all tracked state
|
|
302
|
+
*/
|
|
303
|
+
resetAll() {
|
|
304
|
+
this.tracker.resetAll();
|
|
305
|
+
this.pendingChanges.clear();
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Get rendering statistics
|
|
310
|
+
* @returns {Object} Statistics
|
|
311
|
+
*/
|
|
312
|
+
getStats() {
|
|
313
|
+
return this.tracker.getStats();
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Reset statistics
|
|
318
|
+
*/
|
|
319
|
+
resetStats() {
|
|
320
|
+
this.tracker.resetStats();
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
export default {
|
|
325
|
+
WidgetStateTracker,
|
|
326
|
+
DifferentialRenderer
|
|
327
|
+
};
|
package/src/errors.js
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom error classes for Claw Dashboard
|
|
3
|
+
* Provides specific error types for better error handling and debugging
|
|
4
|
+
* @module errors
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Base error class for all dashboard-specific errors
|
|
9
|
+
* @extends Error
|
|
10
|
+
*/
|
|
11
|
+
export class DashboardError extends Error {
|
|
12
|
+
constructor(message, code = 'DASHBOARD_ERROR', details = {}) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.name = 'DashboardError';
|
|
15
|
+
this.code = code;
|
|
16
|
+
this.details = details;
|
|
17
|
+
this.timestamp = new Date().toISOString();
|
|
18
|
+
Error.captureStackTrace(this, this.constructor);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
toJSON() {
|
|
22
|
+
return {
|
|
23
|
+
name: this.name,
|
|
24
|
+
message: this.message,
|
|
25
|
+
code: this.code,
|
|
26
|
+
details: this.details,
|
|
27
|
+
timestamp: this.timestamp,
|
|
28
|
+
stack: this.stack
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Configuration related errors
|
|
34
|
+
export class ConfigError extends DashboardError {
|
|
35
|
+
constructor(message, details = {}) {
|
|
36
|
+
super(message, 'CONFIG_ERROR', details);
|
|
37
|
+
this.name = 'ConfigError';
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Settings validation or load/save errors
|
|
42
|
+
export class SettingsError extends DashboardError {
|
|
43
|
+
constructor(message, details = {}) {
|
|
44
|
+
super(message, 'SETTINGS_ERROR', details);
|
|
45
|
+
this.name = 'SettingsError';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Gateway/OpenClaw communication errors
|
|
50
|
+
export class GatewayError extends DashboardError {
|
|
51
|
+
constructor(message, details = {}) {
|
|
52
|
+
super(message, 'GATEWAY_ERROR', details);
|
|
53
|
+
this.name = 'GatewayError';
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Session-related errors
|
|
58
|
+
export class SessionError extends DashboardError {
|
|
59
|
+
constructor(message, details = {}) {
|
|
60
|
+
super(message, 'SESSION_ERROR', details);
|
|
61
|
+
this.name = 'SessionError';
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Data fetch errors (systeminformation, CLI commands)
|
|
66
|
+
export class DataFetchError extends DashboardError {
|
|
67
|
+
constructor(message, details = {}) {
|
|
68
|
+
super(message, 'DATA_FETCH_ERROR', details);
|
|
69
|
+
this.name = 'DataFetchError';
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Authentication/authorization errors
|
|
74
|
+
export class AuthError extends DashboardError {
|
|
75
|
+
constructor(message, details = {}) {
|
|
76
|
+
super(message, 'AUTH_ERROR', details);
|
|
77
|
+
this.name = 'AuthError';
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Network-related errors
|
|
82
|
+
export class NetworkError extends DashboardError {
|
|
83
|
+
constructor(message, details = {}) {
|
|
84
|
+
super(message, 'NETWORK_ERROR', details);
|
|
85
|
+
this.name = 'NetworkError';
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// UI/Rendering errors
|
|
90
|
+
export class UIError extends DashboardError {
|
|
91
|
+
constructor(message, details = {}) {
|
|
92
|
+
super(message, 'UI_ERROR', details);
|
|
93
|
+
this.name = 'UIError';
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Database errors
|
|
98
|
+
export class DatabaseError extends DashboardError {
|
|
99
|
+
constructor(message, details = {}) {
|
|
100
|
+
super(message, 'DATABASE_ERROR', details);
|
|
101
|
+
this.name = 'DatabaseError';
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Validation errors
|
|
106
|
+
export class ValidationError extends DashboardError {
|
|
107
|
+
constructor(message, details = {}) {
|
|
108
|
+
super(message, 'VALIDATION_ERROR', details);
|
|
109
|
+
this.name = 'ValidationError';
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Timeout errors
|
|
114
|
+
export class TimeoutError extends DashboardError {
|
|
115
|
+
constructor(message, details = {}) {
|
|
116
|
+
super(message, 'TIMEOUT_ERROR', details);
|
|
117
|
+
this.name = 'TimeoutError';
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Worker pool overload errors
|
|
122
|
+
export class WorkerPoolOverloadError extends DashboardError {
|
|
123
|
+
constructor(message, details = {}) {
|
|
124
|
+
super(message, 'WORKER_POOL_OVERLOAD', details);
|
|
125
|
+
this.name = 'WorkerPoolOverloadError';
|
|
126
|
+
this.degradationLevel = details.degradationLevel || 'none';
|
|
127
|
+
this.queueSize = details.queueSize || 0;
|
|
128
|
+
this.utilizationPercent = details.utilizationPercent || 0;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Checksum verification errors
|
|
133
|
+
export class ChecksumError extends DashboardError {
|
|
134
|
+
constructor(message, details = {}) {
|
|
135
|
+
super(message, 'CHECKSUM_ERROR', details);
|
|
136
|
+
this.name = 'ChecksumError';
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Error code constants for programmatic handling
|
|
141
|
+
export const ERROR_CODES = {
|
|
142
|
+
CONFIG_ERROR: 'CONFIG_ERROR',
|
|
143
|
+
SETTINGS_ERROR: 'SETTINGS_ERROR',
|
|
144
|
+
GATEWAY_ERROR: 'GATEWAY_ERROR',
|
|
145
|
+
SESSION_ERROR: 'SESSION_ERROR',
|
|
146
|
+
DATA_FETCH_ERROR: 'DATA_FETCH_ERROR',
|
|
147
|
+
AUTH_ERROR: 'AUTH_ERROR',
|
|
148
|
+
NETWORK_ERROR: 'NETWORK_ERROR',
|
|
149
|
+
UI_ERROR: 'UI_ERROR',
|
|
150
|
+
DATABASE_ERROR: 'DATABASE_ERROR',
|
|
151
|
+
VALIDATION_ERROR: 'VALIDATION_ERROR',
|
|
152
|
+
TIMEOUT_ERROR: 'TIMEOUT_ERROR',
|
|
153
|
+
CHECKSUM_ERROR: 'CHECKSUM_ERROR',
|
|
154
|
+
WORKER_POOL_OVERLOAD: 'WORKER_POOL_OVERLOAD',
|
|
155
|
+
DASHBOARD_ERROR: 'DASHBOARD_ERROR'
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
// Helper to check if error is a dashboard error
|
|
159
|
+
export function isDashboardError(error) {
|
|
160
|
+
return error instanceof DashboardError;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Helper to get error code or default
|
|
164
|
+
export function getErrorCode(error) {
|
|
165
|
+
if (error instanceof DashboardError) {
|
|
166
|
+
return error.code;
|
|
167
|
+
}
|
|
168
|
+
return 'UNKNOWN_ERROR';
|
|
169
|
+
}
|