claw-dashboard 2.1.1 → 2.2.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.
Files changed (89) hide show
  1. package/CHANGELOG.md +29 -1
  2. package/docs/API.md +1 -2
  3. package/index.js +31 -41
  4. package/package.json +22 -12
  5. package/src/auto-save.js +11 -5
  6. package/src/cli/export-snapshot.js +3 -1
  7. package/src/cli/import-snapshot.js +3 -1
  8. package/src/config.js +9 -15
  9. package/src/errors.js +0 -9
  10. package/src/security.js +6 -2
  11. package/src/snapshot.js +73 -26
  12. package/src/web-server.js +7 -10
  13. package/.c8rc.json +0 -38
  14. package/.dockerignore +0 -68
  15. package/.github/dependabot.yml +0 -45
  16. package/.github/pull_request_template.md +0 -39
  17. package/.github/workflows/ci.yml +0 -147
  18. package/.github/workflows/release.yml +0 -40
  19. package/.github/workflows/security.yml +0 -84
  20. package/.husky/pre-commit +0 -1
  21. package/.planning/codebase/ARCHITECTURE.md +0 -206
  22. package/.planning/codebase/INTEGRATIONS.md +0 -150
  23. package/.planning/codebase/STACK.md +0 -122
  24. package/.planning/codebase/STRUCTURE.md +0 -201
  25. package/CONTRIBUTING.md +0 -378
  26. package/Dockerfile +0 -54
  27. package/FEATURES.md +0 -307
  28. package/TODO.md +0 -28
  29. package/ai.openclaw.dashboard.plist +0 -35
  30. package/build-cjs.js +0 -127
  31. package/cjs-shim.js +0 -13
  32. package/dist/clawdash +0 -1729
  33. package/dist/clawdash.meta.json +0 -2236
  34. package/dist/widgets.cjs +0 -6511
  35. package/docker-compose.yml +0 -67
  36. package/esbuild.config.js +0 -158
  37. package/eslint.config.js +0 -56
  38. package/examples/plugins/README.md +0 -122
  39. package/examples/plugins/api-status/index.js +0 -294
  40. package/examples/plugins/api-status/plugin.json +0 -19
  41. package/examples/plugins/hello-world/index.js +0 -104
  42. package/examples/plugins/hello-world/plugin.json +0 -15
  43. package/examples/plugins/system-metrics-chart/index.js +0 -339
  44. package/examples/plugins/system-metrics-chart/plugin.json +0 -18
  45. package/examples/plugins/weather-widget/index.js +0 -136
  46. package/examples/plugins/weather-widget/plugin.json +0 -19
  47. package/index.cjs +0 -23005
  48. package/jest.config.js +0 -11
  49. package/scripts/release.js +0 -595
  50. package/src/database.js +0 -734
  51. package/tests/alerts.test.js +0 -437
  52. package/tests/auto-save.test.js +0 -529
  53. package/tests/cache.test.js +0 -317
  54. package/tests/cli.test.js +0 -351
  55. package/tests/command-palette.test.js +0 -320
  56. package/tests/config-processor.test.js +0 -452
  57. package/tests/config-validator.test.js +0 -710
  58. package/tests/config-watcher.test.js +0 -594
  59. package/tests/config.test.js +0 -755
  60. package/tests/database.test.js +0 -438
  61. package/tests/errors.test.js +0 -189
  62. package/tests/example-plugins.test.js +0 -624
  63. package/tests/integration.test.js +0 -1321
  64. package/tests/loading-states.test.js +0 -300
  65. package/tests/manifest-validation-on-load.test.js +0 -671
  66. package/tests/performance-monitor.test.js +0 -190
  67. package/tests/plugin-api-rate-limit.test.js +0 -302
  68. package/tests/plugin-errors.test.js +0 -311
  69. package/tests/plugin-lifecycle-e2e.test.js +0 -1036
  70. package/tests/plugin-reload.test.js +0 -764
  71. package/tests/rate-limiter.test.js +0 -539
  72. package/tests/removed-dependencies.test.js +0 -74
  73. package/tests/retry.test.js +0 -308
  74. package/tests/security.test.js +0 -411
  75. package/tests/settings-modal.test.js +0 -226
  76. package/tests/theme-selector.test.js +0 -57
  77. package/tests/utils.js +0 -242
  78. package/tests/utils.test.js +0 -317
  79. package/tests/validate-plugin-cli.test.js +0 -359
  80. package/tests/validation.test.js +0 -837
  81. package/tests/web-server.test.js +0 -646
  82. package/tests/widget-arrange-mode.test.js +0 -183
  83. package/tests/widget-config-hot-reload.test.js +0 -465
  84. package/tests/widget-dependency.test.js +0 -591
  85. package/tests/widget-error-boundary.test.js +0 -749
  86. package/tests/widget-error-isolation.test.js +0 -469
  87. package/tests/widget-integration.test.js +0 -1147
  88. package/tests/widget-refresh-intervals.test.js +0 -284
  89. package/tests/worker-pool.test.js +0 -522
@@ -1,539 +0,0 @@
1
- /**
2
- * Unit tests for RateLimiter class
3
- */
4
-
5
- import alerts from '../src/alerts.js';
6
-
7
- const { RateLimiter } = alerts;
8
-
9
- describe('RateLimiter', () => {
10
- beforeEach(() => {
11
- alerts.resetRateLimit();
12
- });
13
-
14
- afterEach(() => {
15
- alerts.resetRateLimit();
16
- });
17
-
18
- describe('constructor', () => {
19
- test('should create RateLimiter with default options', () => {
20
- const limiter = new RateLimiter();
21
-
22
- expect(limiter.enabled).toBe(true);
23
- expect(limiter.windowMs).toBe(60000);
24
- expect(limiter.maxAlerts).toBe(5);
25
- expect(limiter.alwaysAllowCritical).toBe(true);
26
- expect(limiter.timestamps).toEqual({});
27
- });
28
-
29
- test('should create RateLimiter with custom options', () => {
30
- const limiter = new RateLimiter({
31
- enabled: false,
32
- windowMs: 30000,
33
- maxAlerts: 3,
34
- alwaysAllowCritical: false
35
- });
36
-
37
- expect(limiter.enabled).toBe(false);
38
- expect(limiter.windowMs).toBe(30000);
39
- expect(limiter.maxAlerts).toBe(3);
40
- expect(limiter.alwaysAllowCritical).toBe(false);
41
- });
42
-
43
- test('should partially apply custom options with defaults for others', () => {
44
- const limiter = new RateLimiter({
45
- maxAlerts: 10
46
- });
47
-
48
- expect(limiter.enabled).toBe(true); // default
49
- expect(limiter.windowMs).toBe(60000); // default
50
- expect(limiter.maxAlerts).toBe(10); // custom
51
- expect(limiter.alwaysAllowCritical).toBe(true); // default
52
- });
53
- });
54
-
55
- describe('check', () => {
56
- test('should allow all alerts when disabled', () => {
57
- const limiter = new RateLimiter({ enabled: false });
58
-
59
- for (let i = 0; i < 10; i++) {
60
- const result = limiter.check('cpu', 'warning');
61
- expect(result.allowed).toBe(true);
62
- expect(result.reason).toBe('rate_limiting_disabled');
63
- }
64
- });
65
-
66
- test('should allow alert when under limit', () => {
67
- const limiter = new RateLimiter({ maxAlerts: 3 });
68
-
69
- const result = limiter.check('cpu', 'warning');
70
- expect(result.allowed).toBe(true);
71
- expect(result.reason).toBe('ok');
72
- });
73
-
74
- test('should block alert when over limit', () => {
75
- const limiter = new RateLimiter({ maxAlerts: 2 });
76
-
77
- // Record two alerts to reach limit
78
- limiter.record('cpu', 'warning');
79
- limiter.record('cpu', 'warning');
80
-
81
- const result = limiter.check('cpu', 'warning');
82
- expect(result.allowed).toBe(false);
83
- expect(result.reason).toBe('rate_limit_exceeded');
84
- });
85
-
86
- test('should always allow critical when alwaysAllowCritical is true', () => {
87
- const limiter = new RateLimiter({
88
- maxAlerts: 1,
89
- alwaysAllowCritical: true
90
- });
91
-
92
- // Record one alert to reach limit
93
- limiter.record('cpu', 'warning');
94
-
95
- // Warning should be blocked
96
- const warningResult = limiter.check('cpu', 'warning');
97
- expect(warningResult.allowed).toBe(false);
98
-
99
- // Critical should be allowed
100
- const criticalResult = limiter.check('cpu', 'critical');
101
- expect(criticalResult.allowed).toBe(true);
102
- expect(criticalResult.reason).toBe('critical_always_allowed');
103
- });
104
-
105
- test('should block critical when alwaysAllowCritical is false', () => {
106
- const limiter = new RateLimiter({
107
- maxAlerts: 1,
108
- alwaysAllowCritical: false
109
- });
110
-
111
- // Record one alert to reach limit
112
- limiter.record('cpu', 'critical');
113
-
114
- // Another critical should be blocked
115
- const result = limiter.check('cpu', 'critical');
116
- expect(result.allowed).toBe(false);
117
- expect(result.reason).toBe('rate_limit_exceeded');
118
- });
119
-
120
- test('should track different alert types separately', () => {
121
- const limiter = new RateLimiter({ maxAlerts: 1 });
122
-
123
- // Fill up cpu
124
- limiter.record('cpu', 'warning');
125
- expect(limiter.check('cpu', 'warning').allowed).toBe(false);
126
-
127
- // Memory should still be allowed
128
- expect(limiter.check('memory', 'warning').allowed).toBe(true);
129
- });
130
-
131
- test('should default to warning level when not specified', () => {
132
- const limiter = new RateLimiter({ maxAlerts: 1 });
133
-
134
- limiter.record('cpu', 'warning');
135
-
136
- // Check without level should use warning
137
- const result = limiter.check('cpu');
138
- expect(result.allowed).toBe(false);
139
- });
140
- });
141
-
142
- describe('checkAndRecord', () => {
143
- test('should check and record when allowed', () => {
144
- const limiter = new RateLimiter({ maxAlerts: 2 });
145
-
146
- const result = limiter.checkAndRecord('cpu', 'warning');
147
- expect(result.allowed).toBe(true);
148
- expect(result.reason).toBe('ok');
149
-
150
- // Verify it was recorded
151
- expect(limiter.getCount('cpu')).toBe(1);
152
- });
153
-
154
- test('should check but not record when blocked', () => {
155
- const limiter = new RateLimiter({ maxAlerts: 1 });
156
-
157
- // First alert
158
- limiter.checkAndRecord('cpu', 'warning');
159
- expect(limiter.getCount('cpu')).toBe(1);
160
-
161
- // Second should be blocked and NOT recorded
162
- const result = limiter.checkAndRecord('cpu', 'warning');
163
- expect(result.allowed).toBe(false);
164
- expect(result.reason).toBe('rate_limit_exceeded');
165
- expect(limiter.getCount('cpu')).toBe(1); // Still 1, not incremented
166
- });
167
-
168
- test('should allow critical even when rate limited and record it', () => {
169
- const limiter = new RateLimiter({ maxAlerts: 1 });
170
-
171
- // Fill up with warning
172
- limiter.checkAndRecord('cpu', 'warning');
173
-
174
- // Critical should pass and be recorded
175
- const result = limiter.checkAndRecord('cpu', 'critical');
176
- expect(result.allowed).toBe(true);
177
- expect(result.reason).toBe('critical_always_allowed');
178
- expect(limiter.getCount('cpu')).toBe(2); // Both recorded
179
- });
180
-
181
- test('should not record when rate limiting disabled', () => {
182
- const limiter = new RateLimiter({ enabled: false });
183
-
184
- limiter.checkAndRecord('cpu', 'warning');
185
- limiter.checkAndRecord('cpu', 'warning');
186
-
187
- // Should not have recorded anything
188
- expect(limiter.getCount('cpu')).toBe(0);
189
- });
190
- });
191
-
192
- describe('record', () => {
193
- test('should record alert timestamp', () => {
194
- const limiter = new RateLimiter();
195
-
196
- limiter.record('cpu', 'warning');
197
- expect(limiter.getCount('cpu')).toBe(1);
198
-
199
- limiter.record('cpu', 'warning');
200
- expect(limiter.getCount('cpu')).toBe(2);
201
- });
202
-
203
- test('should not record when disabled', () => {
204
- const limiter = new RateLimiter({ enabled: false });
205
-
206
- limiter.record('cpu', 'warning');
207
- expect(limiter.getCount('cpu')).toBe(0);
208
- });
209
-
210
- test('should record multiple types independently', () => {
211
- const limiter = new RateLimiter();
212
-
213
- limiter.record('cpu', 'warning');
214
- limiter.record('cpu', 'warning');
215
- limiter.record('memory', 'warning');
216
-
217
- expect(limiter.getCount('cpu')).toBe(2);
218
- expect(limiter.getCount('memory')).toBe(1);
219
- expect(limiter.getCount('disk')).toBe(0);
220
- });
221
- });
222
-
223
- describe('getCount', () => {
224
- test('should return 0 when no alerts recorded', () => {
225
- const limiter = new RateLimiter();
226
- expect(limiter.getCount('cpu')).toBe(0);
227
- });
228
-
229
- test('should return count of alerts in current window', () => {
230
- const limiter = new RateLimiter({ windowMs: 60000 });
231
-
232
- limiter.record('cpu', 'warning');
233
- limiter.record('cpu', 'warning');
234
- limiter.record('cpu', 'warning');
235
-
236
- expect(limiter.getCount('cpu')).toBe(3);
237
- });
238
-
239
- test('should exclude expired timestamps', async () => {
240
- const limiter = new RateLimiter({ windowMs: 50 });
241
-
242
- limiter.record('cpu', 'warning');
243
- limiter.record('cpu', 'warning');
244
- expect(limiter.getCount('cpu')).toBe(2);
245
-
246
- // Wait for window to expire
247
- await new Promise(resolve => setTimeout(resolve, 60));
248
-
249
- // Old timestamps should be expired
250
- expect(limiter.getCount('cpu')).toBe(0);
251
- });
252
- });
253
-
254
- describe('getRetryAfter', () => {
255
- test('should return 0 when no alerts recorded', () => {
256
- const limiter = new RateLimiter();
257
- expect(limiter.getRetryAfter('cpu')).toBe(0);
258
- });
259
-
260
- test('should return 0 when under limit', () => {
261
- const limiter = new RateLimiter({ maxAlerts: 3 });
262
-
263
- limiter.record('cpu', 'warning');
264
- limiter.record('cpu', 'warning');
265
-
266
- expect(limiter.getRetryAfter('cpu')).toBe(0);
267
- });
268
-
269
- test('should return time until oldest expires when at limit', async () => {
270
- const windowMs = 100;
271
- const limiter = new RateLimiter({ maxAlerts: 2, windowMs });
272
-
273
- // Record two alerts at limit
274
- limiter.record('cpu', 'warning');
275
- await new Promise(resolve => setTimeout(resolve, 20));
276
- limiter.record('cpu', 'warning');
277
-
278
- // At limit, should return time until first expires
279
- const retryAfter = limiter.getRetryAfter('cpu');
280
- expect(retryAfter).toBeGreaterThan(0);
281
- expect(retryAfter).toBeLessThanOrEqual(windowMs);
282
- });
283
-
284
- test('should return 0 after window expires', async () => {
285
- const limiter = new RateLimiter({ maxAlerts: 1, windowMs: 50 });
286
-
287
- limiter.record('cpu', 'warning');
288
- expect(limiter.getRetryAfter('cpu')).toBeGreaterThan(0);
289
-
290
- // Wait for window to expire
291
- await new Promise(resolve => setTimeout(resolve, 60));
292
-
293
- expect(limiter.getRetryAfter('cpu')).toBe(0);
294
- });
295
-
296
- test('should handle different types independently', () => {
297
- const limiter = new RateLimiter({ maxAlerts: 1 });
298
-
299
- limiter.record('cpu', 'warning');
300
-
301
- expect(limiter.getRetryAfter('cpu')).toBeGreaterThan(0);
302
- expect(limiter.getRetryAfter('memory')).toBe(0);
303
- });
304
- });
305
-
306
- describe('getStatus', () => {
307
- test('should return full status object', () => {
308
- const limiter = new RateLimiter({
309
- enabled: true,
310
- windowMs: 30000,
311
- maxAlerts: 3,
312
- alwaysAllowCritical: false
313
- });
314
-
315
- const status = limiter.getStatus();
316
-
317
- expect(status.enabled).toBe(true);
318
- expect(status.windowMs).toBe(30000);
319
- expect(status.maxAlerts).toBe(3);
320
- expect(status.alwaysAllowCritical).toBe(false);
321
- expect(status.types).toEqual({});
322
- });
323
-
324
- test('should include type status for recorded alerts', () => {
325
- const limiter = new RateLimiter({ maxAlerts: 5 });
326
-
327
- limiter.record('cpu', 'warning');
328
- limiter.record('cpu', 'warning');
329
- limiter.record('memory', 'warning');
330
-
331
- const status = limiter.getStatus();
332
-
333
- expect(status.types.cpu).toEqual({
334
- current: 2,
335
- max: 5,
336
- retryAfter: 0
337
- });
338
-
339
- expect(status.types.memory).toEqual({
340
- current: 1,
341
- max: 5,
342
- retryAfter: 0
343
- });
344
-
345
- expect(status.types.disk).toBeUndefined();
346
- });
347
-
348
- test('should include retryAfter when at limit', () => {
349
- const limiter = new RateLimiter({ maxAlerts: 2 });
350
-
351
- limiter.record('cpu', 'warning');
352
- limiter.record('cpu', 'warning');
353
-
354
- const status = limiter.getStatus();
355
-
356
- expect(status.types.cpu.current).toBe(2);
357
- expect(status.types.cpu.retryAfter).toBeGreaterThan(0);
358
- });
359
-
360
- test('should exclude expired timestamps from status', async () => {
361
- const limiter = new RateLimiter({ maxAlerts: 2, windowMs: 50 });
362
-
363
- limiter.record('cpu', 'warning');
364
- limiter.record('cpu', 'warning');
365
-
366
- await new Promise(resolve => setTimeout(resolve, 60));
367
-
368
- const status = limiter.getStatus();
369
- expect(status.types.cpu.current).toBe(0);
370
- expect(status.types.cpu.retryAfter).toBe(0);
371
- });
372
- });
373
-
374
- describe('configure', () => {
375
- test('should update configuration', () => {
376
- const limiter = new RateLimiter();
377
-
378
- limiter.configure({
379
- enabled: false,
380
- windowMs: 30000,
381
- maxAlerts: 10,
382
- alwaysAllowCritical: false
383
- });
384
-
385
- expect(limiter.enabled).toBe(false);
386
- expect(limiter.windowMs).toBe(30000);
387
- expect(limiter.maxAlerts).toBe(10);
388
- expect(limiter.alwaysAllowCritical).toBe(false);
389
- });
390
-
391
- test('should partially update configuration', () => {
392
- const limiter = new RateLimiter();
393
-
394
- limiter.configure({ maxAlerts: 20 });
395
-
396
- expect(limiter.enabled).toBe(true); // unchanged
397
- expect(limiter.windowMs).toBe(60000); // unchanged
398
- expect(limiter.maxAlerts).toBe(20); // updated
399
- });
400
-
401
- test('should affect subsequent checks', () => {
402
- const limiter = new RateLimiter({ maxAlerts: 1 });
403
-
404
- limiter.record('cpu', 'warning');
405
- expect(limiter.check('cpu', 'warning').allowed).toBe(false);
406
-
407
- // Increase limit
408
- limiter.configure({ maxAlerts: 3 });
409
-
410
- // Should now be allowed
411
- expect(limiter.check('cpu', 'warning').allowed).toBe(true);
412
- });
413
- });
414
-
415
- describe('reset', () => {
416
- test('should clear all timestamps', () => {
417
- const limiter = new RateLimiter();
418
-
419
- limiter.record('cpu', 'warning');
420
- limiter.record('memory', 'warning');
421
-
422
- expect(limiter.getCount('cpu')).toBe(1);
423
- expect(limiter.getCount('memory')).toBe(1);
424
-
425
- limiter.reset();
426
-
427
- expect(limiter.getCount('cpu')).toBe(0);
428
- expect(limiter.getCount('memory')).toBe(0);
429
- expect(limiter.timestamps).toEqual({});
430
- });
431
-
432
- test('should allow alerts after reset', () => {
433
- const limiter = new RateLimiter({ maxAlerts: 1 });
434
-
435
- limiter.record('cpu', 'warning');
436
- expect(limiter.check('cpu', 'warning').allowed).toBe(false);
437
-
438
- limiter.reset();
439
-
440
- expect(limiter.check('cpu', 'warning').allowed).toBe(true);
441
- });
442
-
443
- test('should preserve configuration after reset', () => {
444
- const limiter = new RateLimiter({ maxAlerts: 10, windowMs: 30000 });
445
-
446
- limiter.reset();
447
-
448
- expect(limiter.maxAlerts).toBe(10);
449
- expect(limiter.windowMs).toBe(30000);
450
- });
451
- });
452
-
453
- describe('alwaysAllowCritical behavior', () => {
454
- test('should allow critical alerts past limit when true', () => {
455
- const limiter = new RateLimiter({
456
- maxAlerts: 1,
457
- alwaysAllowCritical: true
458
- });
459
-
460
- limiter.record('cpu', 'warning');
461
-
462
- expect(limiter.check('cpu', 'critical').allowed).toBe(true);
463
- expect(limiter.check('cpu', 'warning').allowed).toBe(false);
464
- });
465
-
466
- test('should block critical alerts past limit when false', () => {
467
- const limiter = new RateLimiter({
468
- maxAlerts: 1,
469
- alwaysAllowCritical: false
470
- });
471
-
472
- limiter.record('cpu', 'critical');
473
-
474
- expect(limiter.check('cpu', 'critical').allowed).toBe(false);
475
- });
476
-
477
- test('should respect level parameter variations', () => {
478
- const limiter = new RateLimiter({
479
- maxAlerts: 1,
480
- alwaysAllowCritical: true
481
- });
482
-
483
- limiter.record('cpu', 'warning');
484
-
485
- // Various non-critical levels should be blocked
486
- expect(limiter.check('cpu', 'warning').allowed).toBe(false);
487
- expect(limiter.check('cpu', 'info').allowed).toBe(false);
488
-
489
- // Critical should pass
490
- expect(limiter.check('cpu', 'critical').allowed).toBe(true);
491
- });
492
-
493
- test('should be configurable at runtime', () => {
494
- const limiter = new RateLimiter({
495
- maxAlerts: 1,
496
- alwaysAllowCritical: true
497
- });
498
-
499
- limiter.record('cpu', 'warning');
500
-
501
- // Initially allowed
502
- expect(limiter.check('cpu', 'critical').allowed).toBe(true);
503
-
504
- // Disable critical bypass
505
- limiter.configure({ alwaysAllowCritical: false });
506
-
507
- // Fill up again
508
- limiter.record('cpu', 'critical');
509
-
510
- // Should now be blocked
511
- expect(limiter.check('cpu', 'critical').allowed).toBe(false);
512
- });
513
- });
514
-
515
- describe('integration with global rate limiting', () => {
516
- test('should sync with global config on creation', () => {
517
- // Create limiter should sync its config to global
518
- new RateLimiter({ maxAlerts: 7 });
519
-
520
- const globalConfig = alerts.getRateLimit();
521
- expect(globalConfig.maxAlerts).toBe(7);
522
- });
523
-
524
- test('should sync with global config on configure', () => {
525
- const limiter = new RateLimiter();
526
-
527
- limiter.configure({ maxAlerts: 15 });
528
-
529
- const globalConfig = alerts.getRateLimit();
530
- expect(globalConfig.maxAlerts).toBe(15);
531
- });
532
-
533
- test('defaultRateLimiter instance should exist', () => {
534
- // Verify the exported defaultRateLimiter exists
535
- expect(alerts.defaultRateLimiter).toBeDefined();
536
- expect(alerts.defaultRateLimiter).toBeInstanceOf(RateLimiter);
537
- });
538
- });
539
- });
@@ -1,74 +0,0 @@
1
- /**
2
- * Tests for removed dependencies and widgets
3
- * Verifies cleanup after blessed-contrib and NetworkWidget removal
4
- */
5
-
6
- import { jest } from '@jest/globals';
7
- import { describe, test, expect } from '@jest/globals';
8
- import { readFileSync } from 'fs';
9
- import { fileURLToPath } from 'url';
10
- import { dirname, join } from 'path';
11
-
12
- const __filename = fileURLToPath(import.meta.url);
13
- const __dirname = dirname(__filename);
14
-
15
- describe('Removed dependencies cleanup', () => {
16
- describe('blessed-contrib removal', () => {
17
- test('should not have blessed-contrib in package.json dependencies', () => {
18
- const pkg = JSON.parse(
19
- readFileSync(join(__dirname, '../package.json'), 'utf8')
20
- );
21
- expect(pkg.dependencies).not.toHaveProperty('blessed-contrib');
22
- });
23
-
24
- test('should not import blessed-contrib in index.js', () => {
25
- const indexContent = readFileSync(join(__dirname, '../index.js'), 'utf8');
26
- expect(indexContent).not.toContain("import contrib from 'blessed-contrib'");
27
- expect(indexContent).not.toContain('blessed-contrib');
28
- });
29
- });
30
-
31
- describe('NetworkWidget removal', () => {
32
- test('should not export NetworkWidget from widgets/index.js', async () => {
33
- const widgets = await import('../src/widgets/index.js');
34
- expect(widgets.NetworkWidget).toBeUndefined();
35
- });
36
-
37
- test('should not have NetworkWidget in builtin-widgets exports', async () => {
38
- const builtin = await import('../src/widgets/builtin-widgets.js');
39
- expect(builtin.NetworkWidget).toBeUndefined();
40
- expect(builtin.WIDGET_REGISTRY).not.toHaveProperty('network');
41
- });
42
-
43
- test('builtin-widgets should not reference blessed-contrib', () => {
44
- const content = readFileSync(
45
- join(__dirname, '../src/widgets/builtin-widgets.js'),
46
- 'utf8'
47
- );
48
- expect(content).not.toContain('blessed-contrib');
49
- expect(content).not.toContain('contrib.sparkline');
50
- });
51
- });
52
-
53
- describe('@pm2/blessed migration', () => {
54
- test('should have @pm2/blessed as dependency', () => {
55
- const pkg = JSON.parse(
56
- readFileSync(join(__dirname, '../package.json'), 'utf8')
57
- );
58
- expect(pkg.dependencies).toHaveProperty('@pm2/blessed');
59
- });
60
-
61
- test('should have blessed aliased to @pm2/blessed', () => {
62
- const pkg = JSON.parse(
63
- readFileSync(join(__dirname, '../package.json'), 'utf8')
64
- );
65
- expect(pkg.dependencies.blessed).toBe('npm:@pm2/blessed@^0.1.81');
66
- });
67
-
68
- test('should be able to import blessed', async () => {
69
- // This verifies the alias is working
70
- const blessed = await import('blessed');
71
- expect(typeof blessed.default).toBe('function');
72
- });
73
- });
74
- });