@vizzly-testing/cli 0.14.0 → 0.15.1

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 (140) hide show
  1. package/dist/cli.js +70 -68
  2. package/dist/commands/doctor.js +30 -34
  3. package/dist/commands/finalize.js +24 -23
  4. package/dist/commands/init.js +30 -28
  5. package/dist/commands/login.js +49 -55
  6. package/dist/commands/logout.js +14 -19
  7. package/dist/commands/project.js +83 -103
  8. package/dist/commands/run.js +77 -89
  9. package/dist/commands/status.js +48 -49
  10. package/dist/commands/tdd-daemon.js +90 -86
  11. package/dist/commands/tdd.js +59 -88
  12. package/dist/commands/upload.js +57 -57
  13. package/dist/commands/whoami.js +40 -45
  14. package/dist/index.js +2 -5
  15. package/dist/plugin-loader.js +15 -17
  16. package/dist/reporter/reporter-bundle.css +1 -1
  17. package/dist/reporter/reporter-bundle.iife.js +74 -41
  18. package/dist/sdk/index.js +36 -45
  19. package/dist/server/handlers/api-handler.js +14 -15
  20. package/dist/server/handlers/tdd-handler.js +34 -37
  21. package/dist/server/http-server.js +75 -869
  22. package/dist/server/middleware/cors.js +22 -0
  23. package/dist/server/middleware/json-parser.js +35 -0
  24. package/dist/server/middleware/response.js +79 -0
  25. package/dist/server/routers/assets.js +91 -0
  26. package/dist/server/routers/auth.js +144 -0
  27. package/dist/server/routers/baseline.js +163 -0
  28. package/dist/server/routers/cloud-proxy.js +146 -0
  29. package/dist/server/routers/config.js +126 -0
  30. package/dist/server/routers/dashboard.js +130 -0
  31. package/dist/server/routers/health.js +61 -0
  32. package/dist/server/routers/projects.js +168 -0
  33. package/dist/server/routers/screenshot.js +86 -0
  34. package/dist/services/auth-service.js +1 -1
  35. package/dist/services/build-manager.js +13 -40
  36. package/dist/services/config-service.js +2 -4
  37. package/dist/services/html-report-generator.js +6 -5
  38. package/dist/services/index.js +64 -0
  39. package/dist/services/project-service.js +121 -40
  40. package/dist/services/screenshot-server.js +9 -9
  41. package/dist/services/server-manager.js +11 -18
  42. package/dist/services/static-report-generator.js +3 -4
  43. package/dist/services/tdd-service.js +246 -103
  44. package/dist/services/test-runner.js +24 -25
  45. package/dist/services/uploader.js +5 -4
  46. package/dist/types/commands/init.d.ts +1 -2
  47. package/dist/types/index.d.ts +2 -3
  48. package/dist/types/plugin-loader.d.ts +1 -2
  49. package/dist/types/reporter/src/api/client.d.ts +178 -0
  50. package/dist/types/reporter/src/components/app-router.d.ts +1 -3
  51. package/dist/types/reporter/src/components/code-block.d.ts +4 -0
  52. package/dist/types/reporter/src/components/comparison/comparison-modes/onion-skin-mode.d.ts +10 -0
  53. package/dist/types/reporter/src/components/comparison/comparison-modes/overlay-mode.d.ts +11 -0
  54. package/dist/types/reporter/src/components/comparison/comparison-modes/shared/base-comparison-mode.d.ts +14 -0
  55. package/dist/types/reporter/src/components/comparison/comparison-modes/shared/image-renderer.d.ts +30 -0
  56. package/dist/types/reporter/src/components/comparison/comparison-modes/toggle-view.d.ts +8 -0
  57. package/dist/types/reporter/src/components/comparison/comparison-viewer.d.ts +4 -0
  58. package/dist/types/reporter/src/components/comparison/screenshot-display.d.ts +16 -0
  59. package/dist/types/reporter/src/components/design-system/alert.d.ts +9 -0
  60. package/dist/types/reporter/src/components/design-system/badge.d.ts +17 -0
  61. package/dist/types/reporter/src/components/design-system/button.d.ts +19 -0
  62. package/dist/types/reporter/src/components/design-system/card.d.ts +31 -0
  63. package/dist/types/reporter/src/components/design-system/empty-state.d.ts +13 -0
  64. package/dist/types/reporter/src/components/design-system/form-controls.d.ts +44 -0
  65. package/dist/types/reporter/src/components/design-system/health-ring.d.ts +7 -0
  66. package/dist/types/reporter/src/components/design-system/index.d.ts +11 -0
  67. package/dist/types/reporter/src/components/design-system/modal.d.ts +10 -0
  68. package/dist/types/reporter/src/components/design-system/skeleton.d.ts +19 -0
  69. package/dist/types/reporter/src/components/design-system/spinner.d.ts +10 -0
  70. package/dist/types/reporter/src/components/design-system/tabs.d.ts +13 -0
  71. package/dist/types/reporter/src/components/layout/header.d.ts +5 -0
  72. package/dist/types/reporter/src/components/layout/index.d.ts +2 -0
  73. package/dist/types/reporter/src/components/layout/layout.d.ts +6 -0
  74. package/dist/types/reporter/src/components/views/builds-view.d.ts +1 -0
  75. package/dist/types/reporter/src/components/views/comparison-detail-view.d.ts +1 -4
  76. package/dist/types/reporter/src/components/views/comparisons-view.d.ts +1 -6
  77. package/dist/types/reporter/src/components/views/stats-view.d.ts +1 -6
  78. package/dist/types/reporter/src/components/waiting-for-screenshots.d.ts +1 -0
  79. package/dist/types/reporter/src/hooks/queries/use-auth-queries.d.ts +15 -0
  80. package/dist/types/reporter/src/hooks/queries/use-cloud-queries.d.ts +6 -0
  81. package/dist/types/reporter/src/hooks/queries/use-config-queries.d.ts +6 -0
  82. package/dist/types/reporter/src/hooks/queries/use-tdd-queries.d.ts +9 -0
  83. package/dist/types/reporter/src/lib/query-client.d.ts +2 -0
  84. package/dist/types/reporter/src/lib/query-keys.d.ts +13 -0
  85. package/dist/types/sdk/index.d.ts +2 -4
  86. package/dist/types/server/handlers/tdd-handler.d.ts +2 -0
  87. package/dist/types/server/http-server.d.ts +1 -1
  88. package/dist/types/server/middleware/cors.d.ts +11 -0
  89. package/dist/types/server/middleware/json-parser.d.ts +10 -0
  90. package/dist/types/server/middleware/response.d.ts +50 -0
  91. package/dist/types/server/routers/assets.d.ts +6 -0
  92. package/dist/types/server/routers/auth.d.ts +9 -0
  93. package/dist/types/server/routers/baseline.d.ts +13 -0
  94. package/dist/types/server/routers/cloud-proxy.d.ts +11 -0
  95. package/dist/types/server/routers/config.d.ts +9 -0
  96. package/dist/types/server/routers/dashboard.d.ts +6 -0
  97. package/dist/types/server/routers/health.d.ts +11 -0
  98. package/dist/types/server/routers/projects.d.ts +9 -0
  99. package/dist/types/server/routers/screenshot.d.ts +11 -0
  100. package/dist/types/services/build-manager.d.ts +4 -3
  101. package/dist/types/services/config-service.d.ts +2 -3
  102. package/dist/types/services/index.d.ts +7 -0
  103. package/dist/types/services/project-service.d.ts +6 -4
  104. package/dist/types/services/screenshot-server.d.ts +5 -5
  105. package/dist/types/services/server-manager.d.ts +5 -3
  106. package/dist/types/services/tdd-service.d.ts +12 -1
  107. package/dist/types/services/test-runner.d.ts +3 -3
  108. package/dist/types/utils/output.d.ts +84 -0
  109. package/dist/utils/config-loader.js +24 -48
  110. package/dist/utils/global-config.js +2 -17
  111. package/dist/utils/output.js +445 -0
  112. package/dist/utils/security.js +3 -4
  113. package/docs/api-reference.md +0 -1
  114. package/docs/plugins.md +33 -34
  115. package/package.json +3 -2
  116. package/dist/container/index.js +0 -215
  117. package/dist/services/base-service.js +0 -154
  118. package/dist/types/container/index.d.ts +0 -59
  119. package/dist/types/reporter/src/components/comparison/viewer-modes/onion-viewer.d.ts +0 -3
  120. package/dist/types/reporter/src/components/comparison/viewer-modes/overlay-viewer.d.ts +0 -3
  121. package/dist/types/reporter/src/components/comparison/viewer-modes/side-by-side-viewer.d.ts +0 -3
  122. package/dist/types/reporter/src/components/comparison/viewer-modes/toggle-viewer.d.ts +0 -3
  123. package/dist/types/reporter/src/components/dashboard/dashboard-header.d.ts +0 -5
  124. package/dist/types/reporter/src/components/dashboard/dashboard-stats.d.ts +0 -4
  125. package/dist/types/reporter/src/components/dashboard/empty-state.d.ts +0 -8
  126. package/dist/types/reporter/src/components/ui/form-field.d.ts +0 -16
  127. package/dist/types/reporter/src/components/ui/status-badge.d.ts +0 -5
  128. package/dist/types/reporter/src/hooks/use-auth.d.ts +0 -10
  129. package/dist/types/reporter/src/hooks/use-baseline-actions.d.ts +0 -5
  130. package/dist/types/reporter/src/hooks/use-config.d.ts +0 -9
  131. package/dist/types/reporter/src/hooks/use-projects.d.ts +0 -10
  132. package/dist/types/reporter/src/hooks/use-report-data.d.ts +0 -7
  133. package/dist/types/reporter/src/hooks/use-vizzly-api.d.ts +0 -9
  134. package/dist/types/services/base-service.d.ts +0 -71
  135. package/dist/types/utils/console-ui.d.ts +0 -61
  136. package/dist/types/utils/logger-factory.d.ts +0 -26
  137. package/dist/types/utils/logger.d.ts +0 -79
  138. package/dist/utils/console-ui.js +0 -241
  139. package/dist/utils/logger-factory.js +0 -76
  140. package/dist/utils/logger.js +0 -231
package/docs/plugins.md CHANGED
@@ -13,7 +13,7 @@ file.
13
13
  ## Benefits
14
14
 
15
15
  - **Zero Configuration** - Just `npm install` and the plugin is available
16
- - **Shared Infrastructure** - Plugins get access to config, logger, and services
16
+ - **Shared Infrastructure** - Plugins get access to config, output utilities, and services
17
17
  - **Independent Releases** - Plugins can iterate without requiring CLI updates
18
18
  - **Smaller Core** - Keep the main CLI lean by moving optional features to plugins
19
19
  - **Community Extensible** - Anyone can build and share plugins
@@ -95,14 +95,14 @@ export default {
95
95
  name: 'my-plugin',
96
96
  version: '1.0.0', // Optional but recommended
97
97
 
98
- register(program, { config, logger, services }) {
98
+ register(program, { config, output, services }) {
99
99
  // Register your command with Commander.js
100
100
  program
101
101
  .command('my-command <arg>')
102
102
  .description('Description of my command')
103
103
  .option('--option <value>', 'An option')
104
104
  .action(async (arg, options) => {
105
- logger.info(`Running my-command with ${arg}`);
105
+ output.info(`Running my-command with ${arg}`);
106
106
 
107
107
  // Access shared services if needed
108
108
  let apiService = await services.get('apiService');
@@ -131,14 +131,13 @@ The `register` function receives two arguments:
131
131
  1. **`program`** - [Commander.js](https://github.com/tj/commander.js) program instance for registering commands
132
132
  2. **`context`** - Object containing:
133
133
  - `config` - Merged Vizzly configuration object
134
- - `logger` - Shared logger instance with `.debug()`, `.info()`, `.warn()`, `.error()` methods
134
+ - `output` - Unified output module with `.debug()`, `.info()`, `.warn()`, `.error()`, `.success()` methods
135
135
  - `services` - Service container with access to internal Vizzly services
136
136
 
137
137
  ### Available Services
138
138
 
139
139
  Plugins can access these services from the container:
140
140
 
141
- - **`logger`** - Component logger for consistent output
142
141
  - **`apiService`** - Vizzly API client for interacting with the platform
143
142
  - **`uploader`** - Screenshot upload service
144
143
  - **`buildManager`** - Build lifecycle management
@@ -149,7 +148,7 @@ Plugins can access these services from the container:
149
148
  Example accessing a service:
150
149
 
151
150
  ```javascript
152
- register(program, { config, logger, services }) {
151
+ register(program, { config, output, services }) {
153
152
  program
154
153
  .command('upload-screenshots <dir>')
155
154
  .action(async (dir) => {
@@ -177,12 +176,12 @@ touch plugins/my-plugin.js
177
176
  export default {
178
177
  name: 'my-plugin',
179
178
  version: '1.0.0',
180
- register(program, { config, logger }) {
179
+ register(program, { config, output }) {
181
180
  program
182
181
  .command('greet <name>')
183
182
  .description('Greet someone')
184
183
  .action((name) => {
185
- logger.info(`Hello, ${name}!`);
184
+ output.info(`Hello, ${name}!`);
186
185
  });
187
186
  }
188
187
  };
@@ -255,33 +254,34 @@ export default {
255
254
  Always handle errors gracefully and provide helpful error messages:
256
255
 
257
256
  ```javascript
258
- register(program, { logger }) {
257
+ register(program, { output }) {
259
258
  program
260
259
  .command('process <file>')
261
260
  .action(async (file) => {
262
261
  try {
263
262
  if (!existsSync(file)) {
264
- logger.error(`File not found: ${file}`);
263
+ output.error(`File not found: ${file}`);
265
264
  process.exit(1);
266
265
  }
267
266
  // Process file...
268
267
  } catch (error) {
269
- logger.error(`Failed to process file: ${error.message}`);
268
+ output.error(`Failed to process file: ${error.message}`);
270
269
  process.exit(1);
271
270
  }
272
271
  });
273
272
  }
274
273
  ```
275
274
 
276
- ### Logging
275
+ ### Output
277
276
 
278
- Use the provided logger for consistent output across all CLI commands:
277
+ Use the provided output module for consistent CLI output:
279
278
 
280
279
  ```javascript
281
- logger.debug('Detailed debug info'); // Only shown with --verbose
282
- logger.info('Normal information'); // Standard output
283
- logger.warn('Warning message'); // Warning output
284
- logger.error('Error message'); // Error output
280
+ output.debug('Detailed debug info'); // Only shown with --verbose (stderr)
281
+ output.info('Normal information'); // Info messages (stdout)
282
+ output.success('Completed!'); // Success messages (stdout)
283
+ output.warn('Warning message'); // Warning messages (stderr)
284
+ output.error('Error message'); // Error messages (stderr)
285
285
  ```
286
286
 
287
287
  ### Async Operations
@@ -292,7 +292,7 @@ Use async/await for asynchronous operations:
292
292
  .action(async (options) => {
293
293
  let service = await services.get('apiService');
294
294
  let result = await service.doSomething();
295
- logger.info(`Result: ${result}`);
295
+ output.info(`Result: ${result}`);
296
296
  });
297
297
  ```
298
298
 
@@ -318,13 +318,13 @@ Validate user input and provide helpful error messages:
318
318
  ```javascript
319
319
  .action(async (path, options) => {
320
320
  if (!path) {
321
- logger.error('Path is required');
321
+ output.error('Path is required');
322
322
  process.exit(1);
323
323
  }
324
324
 
325
325
  if (!existsSync(path)) {
326
- logger.error(`Path not found: ${path}`);
327
- logger.info('Please provide a valid path to your build directory');
326
+ output.error(`Path not found: ${path}`);
327
+ output.info('Please provide a valid path to your build directory');
328
328
  process.exit(1);
329
329
  }
330
330
 
@@ -337,7 +337,7 @@ Validate user input and provide helpful error messages:
337
337
  Import heavy dependencies only when needed to keep CLI startup fast:
338
338
 
339
339
  ```javascript
340
- register(program, { logger }) {
340
+ register(program, { output }) {
341
341
  program
342
342
  .command('process-images <dir>')
343
343
  .action(async (dir) => {
@@ -356,7 +356,7 @@ register(program, { logger }) {
356
356
  export default {
357
357
  name: 'hello',
358
358
  version: '1.0.0',
359
- register(program, { logger }) {
359
+ register(program, { output }) {
360
360
  program
361
361
  .command('hello <name>')
362
362
  .description('Say hello')
@@ -366,7 +366,7 @@ export default {
366
366
  if (options.loud) {
367
367
  greeting = greeting.toUpperCase();
368
368
  }
369
- logger.info(greeting);
369
+ output.info(greeting);
370
370
  });
371
371
  }
372
372
  };
@@ -378,13 +378,13 @@ export default {
378
378
  export default {
379
379
  name: 'storybook',
380
380
  version: '1.0.0',
381
- register(program, { config, logger, services }) {
381
+ register(program, { config, output, services }) {
382
382
  program
383
383
  .command('storybook <path>')
384
384
  .description('Capture screenshots from Storybook build')
385
385
  .option('--viewports <list>', 'Comma-separated viewports', '1280x720')
386
386
  .action(async (path, options) => {
387
- logger.info(`Crawling Storybook at ${path}`);
387
+ output.info(`Crawling Storybook at ${path}`);
388
388
 
389
389
  // Import dependencies lazily
390
390
  let { crawlStorybook } = await import('./crawler.js');
@@ -392,16 +392,15 @@ export default {
392
392
  // Capture screenshots
393
393
  let screenshots = await crawlStorybook(path, {
394
394
  viewports: options.viewports.split(','),
395
- logger,
396
395
  });
397
396
 
398
- logger.info(`Captured ${screenshots.length} screenshots`);
397
+ output.info(`Captured ${screenshots.length} screenshots`);
399
398
 
400
399
  // Upload using Vizzly's uploader service
401
400
  let uploader = await services.get('uploader');
402
401
  await uploader.uploadScreenshots(screenshots);
403
402
 
404
- logger.info('Upload complete!');
403
+ output.success('Upload complete!');
405
404
  });
406
405
  }
407
406
  };
@@ -413,7 +412,7 @@ export default {
413
412
  export default {
414
413
  name: 'reports',
415
414
  version: '1.0.0',
416
- register(program, { logger }) {
415
+ register(program, { output }) {
417
416
  let reports = program
418
417
  .command('reports')
419
418
  .description('Report generation commands');
@@ -422,14 +421,14 @@ export default {
422
421
  .command('generate')
423
422
  .description('Generate a new report')
424
423
  .action(() => {
425
- logger.info('Generating report...');
424
+ output.info('Generating report...');
426
425
  });
427
426
 
428
427
  reports
429
428
  .command('list')
430
429
  .description('List all reports')
431
430
  .action(() => {
432
- logger.info('Listing reports...');
431
+ output.info('Listing reports...');
433
432
  });
434
433
  }
435
434
  };
@@ -474,10 +473,10 @@ If you're using TypeScript or want better IDE support, you can add JSDoc types:
474
473
  * @param {import('commander').Command} program
475
474
  * @param {Object} context
476
475
  * @param {Object} context.config
477
- * @param {Object} context.logger
476
+ * @param {Object} context.output
478
477
  * @param {Object} context.services
479
478
  */
480
- function register(program, { config, logger, services }) {
479
+ function register(program, { config, output, services }) {
481
480
  // Your plugin code with full autocomplete!
482
481
  }
483
482
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vizzly-testing/cli",
3
- "version": "0.14.0",
3
+ "version": "0.15.1",
4
4
  "description": "Visual review platform for UI developers and designers",
5
5
  "keywords": [
6
6
  "visual-testing",
@@ -84,7 +84,7 @@
84
84
  "cosmiconfig": "^9.0.0",
85
85
  "dotenv": "^17.2.1",
86
86
  "form-data": "^4.0.0",
87
- "glob": "^11.0.3",
87
+ "glob": "^13.0.0",
88
88
  "zod": "^4.1.12"
89
89
  },
90
90
  "devDependencies": {
@@ -98,6 +98,7 @@
98
98
  "@modelcontextprotocol/sdk": "^1.0.4",
99
99
  "@playwright/test": "^1.55.1",
100
100
  "@tailwindcss/postcss": "^4.1.13",
101
+ "@tanstack/react-query": "^5.90.11",
101
102
  "@vitejs/plugin-react": "^5.0.3",
102
103
  "@vitest/coverage-v8": "^4.0.3",
103
104
  "autoprefixer": "^10.4.21",
@@ -1,215 +0,0 @@
1
- import { EventEmitter } from 'events';
2
- import { VizzlyError } from '../errors/vizzly-error.js';
3
-
4
- /**
5
- * @typedef {Object} ServiceDefinition
6
- * @property {Function} factory - Factory function to create service instance
7
- * @property {boolean} [singleton=true] - Whether to cache the instance
8
- * @property {string[]} [dependencies=[]] - Array of dependency names
9
- */
10
-
11
- /**
12
- * Service container for dependency injection and lifecycle management
13
- */
14
- export class ServiceContainer extends EventEmitter {
15
- constructor() {
16
- super();
17
- this.services = new Map();
18
- this.instances = new Map();
19
- this.starting = new Map();
20
- }
21
-
22
- /**
23
- * Register a service
24
- * @param {string} name - Service name
25
- * @param {Function|ServiceDefinition} factoryOrDefinition - Factory function or service definition
26
- */
27
- register(name, factoryOrDefinition) {
28
- const definition = typeof factoryOrDefinition === 'function' ? {
29
- factory: factoryOrDefinition,
30
- singleton: true,
31
- dependencies: []
32
- } : factoryOrDefinition;
33
- this.services.set(name, definition);
34
- this.emit('service:registered', {
35
- name,
36
- definition
37
- });
38
- }
39
-
40
- /**
41
- * Get a service instance
42
- * @param {string} name - Service name
43
- * @returns {Promise<any>} Service instance
44
- */
45
- async get(name) {
46
- if (!this.services.has(name)) {
47
- throw new VizzlyError(`Service '${name}' not registered`, 'SERVICE_NOT_FOUND', {
48
- name
49
- });
50
- }
51
- const definition = this.services.get(name);
52
-
53
- // Return cached instance for singletons
54
- if (definition.singleton && this.instances.has(name)) {
55
- return this.instances.get(name);
56
- }
57
-
58
- // Prevent circular dependencies during startup
59
- if (this.starting.has(name)) {
60
- throw new VizzlyError(`Circular dependency detected for service '${name}'`, 'CIRCULAR_DEPENDENCY', {
61
- name
62
- });
63
- }
64
- try {
65
- this.starting.set(name, true);
66
-
67
- // Resolve dependencies
68
- const deps = await Promise.all((definition.dependencies || []).map(dep => this.get(dep)));
69
-
70
- // Create instance
71
- const instance = await definition.factory(...deps);
72
-
73
- // Cache singleton instances
74
- if (definition.singleton) {
75
- this.instances.set(name, instance);
76
- }
77
- this.emit('service:created', {
78
- name,
79
- instance
80
- });
81
- return instance;
82
- } finally {
83
- this.starting.delete(name);
84
- }
85
- }
86
-
87
- /**
88
- * Start all registered services
89
- */
90
- async startAll() {
91
- const services = Array.from(this.services.keys());
92
- for (const name of services) {
93
- const instance = await this.get(name);
94
- if (instance && typeof instance.start === 'function') {
95
- await instance.start();
96
- this.emit('service:started', {
97
- name,
98
- instance
99
- });
100
- }
101
- }
102
- }
103
-
104
- /**
105
- * Stop all services in reverse order
106
- */
107
- async stopAll() {
108
- const instances = Array.from(this.instances.entries()).reverse();
109
- for (const [name, instance] of instances) {
110
- if (instance && typeof instance.stop === 'function') {
111
- await instance.stop();
112
- this.emit('service:stopped', {
113
- name,
114
- instance
115
- });
116
- }
117
- }
118
- }
119
-
120
- /**
121
- * Clear all services and instances
122
- */
123
- clear() {
124
- this.services.clear();
125
- this.instances.clear();
126
- this.starting.clear();
127
- }
128
- }
129
-
130
- // Export singleton instance
131
- export const container = new ServiceContainer();
132
- /**
133
- * Create a configured service container
134
- * @param {Object} config - Configuration object
135
- * @returns {ServiceContainer}
136
- */
137
- export async function createServiceContainer(config, command = 'run') {
138
- const container = new ServiceContainer();
139
-
140
- // Dynamic ESM imports to avoid circular deps
141
- const [{
142
- createComponentLogger
143
- }, {
144
- ApiService
145
- }, {
146
- createUploader
147
- }, {
148
- createTDDService
149
- }, {
150
- TestRunner
151
- }, {
152
- BuildManager
153
- }, {
154
- ServerManager
155
- }, {
156
- AuthService
157
- }, {
158
- ConfigService
159
- }, {
160
- ProjectService
161
- }] = await Promise.all([import('../utils/logger-factory.js'), import('../services/api-service.js'), import('../services/uploader.js'), import('../services/tdd-service.js'), import('../services/test-runner.js'), import('../services/build-manager.js'), import('../services/server-manager.js'), import('../services/auth-service.js'), import('../services/config-service.js'), import('../services/project-service.js')]);
162
-
163
- // Create logger instance once
164
- const logger = createComponentLogger('CONTAINER', {
165
- level: config.logLevel || (config.verbose ? 'debug' : 'warn'),
166
- verbose: config.verbose || false
167
- });
168
-
169
- // Register services without circular dependencies
170
- container.register('logger', () => logger);
171
- container.register('apiService', () => new ApiService(config, {
172
- logger,
173
- allowNoToken: true
174
- }));
175
- container.register('authService', () => new AuthService({
176
- baseUrl: config.apiUrl
177
- }));
178
- container.register('configService', () => new ConfigService(config, {
179
- logger,
180
- projectRoot: process.cwd()
181
- }));
182
- container.register('projectService', {
183
- factory: async apiService => new ProjectService(config, {
184
- logger,
185
- apiService
186
- }),
187
- dependencies: ['apiService']
188
- });
189
- container.register('uploader', () => createUploader({
190
- ...config,
191
- command
192
- }, {
193
- logger
194
- }));
195
- container.register('buildManager', () => new BuildManager(config, logger));
196
- container.register('serverManager', {
197
- factory: async (configService, authService, projectService) => new ServerManager(config, {
198
- logger,
199
- services: {
200
- configService,
201
- authService,
202
- projectService
203
- }
204
- }),
205
- dependencies: ['configService', 'authService', 'projectService']
206
- });
207
- container.register('tddService', () => createTDDService(config, {
208
- logger
209
- }));
210
- container.register('testRunner', {
211
- factory: async (buildManager, serverManager, tddService) => new TestRunner(config, logger, buildManager, serverManager, tddService),
212
- dependencies: ['buildManager', 'serverManager', 'tddService']
213
- });
214
- return container;
215
- }
@@ -1,154 +0,0 @@
1
- /**
2
- * Base Service Class
3
- * Provides common functionality for all services
4
- */
5
-
6
- import { EventEmitter } from 'events';
7
- import { VizzlyError } from '../errors/vizzly-error.js';
8
- import { createStandardLogger } from '../utils/logger-factory.js';
9
-
10
- /**
11
- * @typedef {Object} ServiceOptions
12
- * @property {Object} logger - Logger instance
13
- * @property {AbortSignal} [signal] - Abort signal for cancellation
14
- */
15
-
16
- /**
17
- * Base class for all services
18
- * @extends EventEmitter
19
- */
20
- export class BaseService extends EventEmitter {
21
- /**
22
- * @param {Object} config - Service configuration
23
- * @param {ServiceOptions} options - Service options
24
- */
25
- constructor(config, options = {}) {
26
- super();
27
- this.config = config;
28
- this.logger = options.logger || createStandardLogger({
29
- level: 'info'
30
- });
31
- this.signal = options.signal;
32
- this.started = false;
33
- this.stopping = false;
34
-
35
- // Setup signal handling
36
- if (this.signal) {
37
- this.signal.addEventListener('abort', () => this.stop());
38
- }
39
- }
40
-
41
- /**
42
- * Start the service
43
- * @returns {Promise<void>}
44
- */
45
- async start() {
46
- if (this.started) {
47
- this.logger.warn(`${this.constructor.name} already started`);
48
- return;
49
- }
50
- try {
51
- this.emit('starting');
52
- await this.onStart();
53
- this.started = true;
54
- this.emit('started');
55
- } catch (error) {
56
- this.emit('error', error);
57
- throw new VizzlyError(`Failed to start ${this.constructor.name}`, 'SERVICE_START_FAILED', {
58
- service: this.constructor.name,
59
- error: error.message
60
- });
61
- }
62
- }
63
-
64
- /**
65
- * Stop the service
66
- * @returns {Promise<void>}
67
- */
68
- async stop() {
69
- if (!this.started || this.stopping) {
70
- return;
71
- }
72
- this.stopping = true;
73
- try {
74
- this.emit('stopping');
75
- await this.onStop();
76
- this.started = false;
77
- this.emit('stopped');
78
- } catch (error) {
79
- this.emit('error', error);
80
- throw new VizzlyError(`Failed to stop ${this.constructor.name}`, 'SERVICE_STOP_FAILED', {
81
- service: this.constructor.name,
82
- error: error.message
83
- });
84
- } finally {
85
- this.stopping = false;
86
- }
87
- }
88
-
89
- /**
90
- * Hook for service-specific start logic
91
- * @protected
92
- * @returns {Promise<void>}
93
- */
94
- async onStart() {
95
- // Override in subclasses
96
- }
97
-
98
- /**
99
- * Hook for service-specific stop logic
100
- * @protected
101
- * @returns {Promise<void>}
102
- */
103
- async onStop() {
104
- // Override in subclasses
105
- }
106
-
107
- /**
108
- * Emit a progress event
109
- * @param {string} phase - Progress phase
110
- * @param {string} message - Progress message
111
- * @param {Object} [data] - Additional data
112
- */
113
- emitProgress(phase, message, data = {}) {
114
- this.emit('progress', {
115
- phase,
116
- message,
117
- timestamp: new Date().toISOString(),
118
- ...data
119
- });
120
- }
121
-
122
- /**
123
- * Check if service is running
124
- * @returns {boolean}
125
- */
126
- isRunning() {
127
- return this.started && !this.stopping;
128
- }
129
-
130
- /**
131
- * Wait for service to be ready
132
- * @param {number} [timeout=30000] - Timeout in milliseconds
133
- * @returns {Promise<void>}
134
- */
135
- async waitForReady(timeout = 30000) {
136
- if (this.started) return;
137
- return new Promise((resolve, reject) => {
138
- const timer = setTimeout(() => {
139
- reject(new VizzlyError('Service start timeout', 'SERVICE_TIMEOUT', {
140
- service: this.constructor.name,
141
- timeout
142
- }));
143
- }, timeout);
144
- this.once('started', () => {
145
- clearTimeout(timer);
146
- resolve();
147
- });
148
- this.once('error', error => {
149
- clearTimeout(timer);
150
- reject(error);
151
- });
152
- });
153
- }
154
- }
@@ -1,59 +0,0 @@
1
- /**
2
- * Create a configured service container
3
- * @param {Object} config - Configuration object
4
- * @returns {ServiceContainer}
5
- */
6
- export function createServiceContainer(config: any, command?: string): ServiceContainer;
7
- /**
8
- * @typedef {Object} ServiceDefinition
9
- * @property {Function} factory - Factory function to create service instance
10
- * @property {boolean} [singleton=true] - Whether to cache the instance
11
- * @property {string[]} [dependencies=[]] - Array of dependency names
12
- */
13
- /**
14
- * Service container for dependency injection and lifecycle management
15
- */
16
- export class ServiceContainer {
17
- services: Map<any, any>;
18
- instances: Map<any, any>;
19
- starting: Map<any, any>;
20
- /**
21
- * Register a service
22
- * @param {string} name - Service name
23
- * @param {Function|ServiceDefinition} factoryOrDefinition - Factory function or service definition
24
- */
25
- register(name: string, factoryOrDefinition: Function | ServiceDefinition): void;
26
- /**
27
- * Get a service instance
28
- * @param {string} name - Service name
29
- * @returns {Promise<any>} Service instance
30
- */
31
- get(name: string): Promise<any>;
32
- /**
33
- * Start all registered services
34
- */
35
- startAll(): Promise<void>;
36
- /**
37
- * Stop all services in reverse order
38
- */
39
- stopAll(): Promise<void>;
40
- /**
41
- * Clear all services and instances
42
- */
43
- clear(): void;
44
- }
45
- export const container: ServiceContainer;
46
- export type ServiceDefinition = {
47
- /**
48
- * - Factory function to create service instance
49
- */
50
- factory: Function;
51
- /**
52
- * - Whether to cache the instance
53
- */
54
- singleton?: boolean;
55
- /**
56
- * - Array of dependency names
57
- */
58
- dependencies?: string[];
59
- };
@@ -1,3 +0,0 @@
1
- export default function OnionViewer({ comparison }: {
2
- comparison: any;
3
- }): any;
@@ -1,3 +0,0 @@
1
- export default function OverlayViewer({ comparison }: {
2
- comparison: any;
3
- }): any;
@@ -1,3 +0,0 @@
1
- export default function SideBySideViewer({ comparison }: {
2
- comparison: any;
3
- }): any;