@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/dist/sdk/index.js CHANGED
@@ -16,7 +16,7 @@ import { createUploader } from '../services/uploader.js';
16
16
  import { createTDDService } from '../services/tdd-service.js';
17
17
  import { ScreenshotServer } from '../services/screenshot-server.js';
18
18
  import { loadConfig } from '../utils/config-loader.js';
19
- import { createComponentLogger } from '../utils/logger-factory.js';
19
+ import * as output from '../utils/output.js';
20
20
  import { VizzlyError } from '../errors/vizzly-error.js';
21
21
 
22
22
  /**
@@ -53,21 +53,21 @@ import { VizzlyError } from '../errors/vizzly-error.js';
53
53
  * await vizzly.stop();
54
54
  */
55
55
  export function createVizzly(config = {}, options = {}) {
56
- const logger = options.logger || createComponentLogger('SDK', {
57
- level: options.logLevel || 'info',
56
+ // Configure output based on options
57
+ output.configure({
58
58
  verbose: options.verbose || false
59
59
  });
60
60
 
61
61
  // Merge with loaded config
62
- const resolvedConfig = {
62
+ let resolvedConfig = {
63
63
  ...config
64
64
  };
65
65
 
66
66
  /**
67
67
  * Initialize SDK with config loading
68
68
  */
69
- const init = async () => {
70
- const fileConfig = await loadConfig();
69
+ let init = async () => {
70
+ let fileConfig = await loadConfig();
71
71
  Object.assign(resolvedConfig, fileConfig, config); // CLI config takes precedence
72
72
  return resolvedConfig;
73
73
  };
@@ -75,41 +75,39 @@ export function createVizzly(config = {}, options = {}) {
75
75
  /**
76
76
  * Create uploader service
77
77
  */
78
- const createUploaderService = (uploaderOptions = {}) => {
78
+ let createUploaderService = (uploaderOptions = {}) => {
79
79
  return createUploader({
80
80
  apiKey: resolvedConfig.apiKey,
81
81
  apiUrl: resolvedConfig.apiUrl
82
82
  }, {
83
83
  ...options,
84
- ...uploaderOptions,
85
- logger
84
+ ...uploaderOptions
86
85
  });
87
86
  };
88
87
 
89
88
  /**
90
89
  * Create TDD service
91
90
  */
92
- const createTDDServiceInstance = (tddOptions = {}) => {
91
+ let createTDDServiceInstance = (tddOptions = {}) => {
93
92
  return createTDDService(resolvedConfig, {
94
93
  ...options,
95
- ...tddOptions,
96
- logger
94
+ ...tddOptions
97
95
  });
98
96
  };
99
97
 
100
98
  /**
101
99
  * Upload screenshots (convenience method)
102
100
  */
103
- const upload = async uploadOptions => {
104
- const uploader = createUploaderService();
101
+ let upload = async uploadOptions => {
102
+ let uploader = createUploaderService();
105
103
  return uploader.upload(uploadOptions);
106
104
  };
107
105
 
108
106
  /**
109
107
  * Start TDD mode (convenience method)
110
108
  */
111
- const startTDD = async (tddOptions = {}) => {
112
- const tddService = createTDDServiceInstance();
109
+ let startTDD = async (tddOptions = {}) => {
110
+ let tddService = createTDDServiceInstance();
113
111
  return tddService.start(tddOptions);
114
112
  };
115
113
  return {
@@ -122,7 +120,6 @@ export function createVizzly(config = {}, options = {}) {
122
120
  createTDDService: createTDDServiceInstance,
123
121
  // Utilities
124
122
  loadConfig: () => loadConfig(),
125
- createLogger: loggerOptions => createComponentLogger('USER', loggerOptions),
126
123
  // Config access
127
124
  getConfig: () => ({
128
125
  ...resolvedConfig
@@ -151,13 +148,11 @@ export function createVizzly(config = {}, options = {}) {
151
148
  export class VizzlySDK extends EventEmitter {
152
149
  /**
153
150
  * @param {import('../types').VizzlyConfig} config - Configuration
154
- * @param {import('../utils/logger').Logger} logger - Logger instance
155
151
  * @param {Object} services - Service instances
156
152
  */
157
- constructor(config, logger, services) {
153
+ constructor(config, services) {
158
154
  super();
159
155
  this.config = config;
160
- this.logger = logger;
161
156
  this.services = services;
162
157
  this.server = null;
163
158
  this.currentBuildId = null;
@@ -172,7 +167,7 @@ export class VizzlySDK extends EventEmitter {
172
167
  await this.server.stop();
173
168
  this.server = null;
174
169
  this.emit('server:stopped');
175
- this.logger.info('Vizzly server stopped');
170
+ output.debug('Vizzly server stopped');
176
171
  }
177
172
  }
178
173
 
@@ -192,7 +187,7 @@ export class VizzlySDK extends EventEmitter {
192
187
  */
193
188
  async start() {
194
189
  if (this.server) {
195
- this.logger.warn('Server already running');
190
+ output.warn('Server already running');
196
191
  return {
197
192
  port: this.config.server?.port || 3000,
198
193
  url: `http://localhost:${this.config.server?.port || 3000}`
@@ -200,7 +195,7 @@ export class VizzlySDK extends EventEmitter {
200
195
  }
201
196
 
202
197
  // Create a simple build manager for screenshot collection
203
- const buildManager = {
198
+ let buildManager = {
204
199
  screenshots: new Map(),
205
200
  currentBuildId: null,
206
201
  async addScreenshot(buildId, screenshot) {
@@ -213,10 +208,10 @@ export class VizzlySDK extends EventEmitter {
213
208
  return this.screenshots.get(buildId) || [];
214
209
  }
215
210
  };
216
- this.server = new ScreenshotServer(this.config, this.logger, buildManager);
211
+ this.server = new ScreenshotServer(this.config, buildManager);
217
212
  await this.server.start();
218
- const port = this.config.server?.port || 3000;
219
- const serverInfo = {
213
+ let port = this.config.server?.port || 3000;
214
+ let serverInfo = {
220
215
  port,
221
216
  url: `http://localhost:${port}`
222
217
  };
@@ -240,15 +235,15 @@ export class VizzlySDK extends EventEmitter {
240
235
  }
241
236
 
242
237
  // Resolve Buffer or file path using shared utility
243
- const buffer = resolveImageBuffer(imageBuffer, 'screenshot');
238
+ let buffer = resolveImageBuffer(imageBuffer, 'screenshot');
244
239
 
245
240
  // Generate or use provided build ID
246
- const buildId = options.buildId || this.currentBuildId || 'default';
241
+ let buildId = options.buildId || this.currentBuildId || 'default';
247
242
  this.currentBuildId = buildId;
248
243
 
249
244
  // Convert Buffer to base64 for JSON transport
250
- const imageBase64 = buffer.toString('base64');
251
- const screenshotData = {
245
+ let imageBase64 = buffer.toString('base64');
246
+ let screenshotData = {
252
247
  buildId,
253
248
  name,
254
249
  image: imageBase64,
@@ -256,9 +251,9 @@ export class VizzlySDK extends EventEmitter {
256
251
  };
257
252
 
258
253
  // POST to the local screenshot server
259
- const serverUrl = `http://localhost:${this.config.server?.port || 3000}`;
254
+ let serverUrl = `http://localhost:${this.config.server?.port || 3000}`;
260
255
  try {
261
- const response = await fetch(`${serverUrl}/screenshot`, {
256
+ let response = await fetch(`${serverUrl}/screenshot`, {
262
257
  method: 'POST',
263
258
  headers: {
264
259
  'Content-Type': 'application/json'
@@ -266,7 +261,7 @@ export class VizzlySDK extends EventEmitter {
266
261
  body: JSON.stringify(screenshotData)
267
262
  });
268
263
  if (!response.ok) {
269
- const errorData = await response.json().catch(() => ({
264
+ let errorData = await response.json().catch(() => ({
270
265
  error: 'Unknown error'
271
266
  }));
272
267
  throw new VizzlyError(`Screenshot capture failed: ${errorData.error}`, 'SCREENSHOT_FAILED', {
@@ -280,7 +275,7 @@ export class VizzlySDK extends EventEmitter {
280
275
  buildId,
281
276
  options
282
277
  });
283
- this.logger.debug(`Screenshot captured: ${name}`);
278
+ output.debug(`Screenshot captured: ${name}`);
284
279
  } catch (error) {
285
280
  if (error instanceof VizzlyError) throw error;
286
281
  throw new VizzlyError(`Failed to send screenshot to server: ${error.message}`, 'SCREENSHOT_TRANSPORT_ERROR', {
@@ -303,14 +298,12 @@ export class VizzlySDK extends EventEmitter {
303
298
  apiKey: this.config.apiKey,
304
299
  apiUrl: this.config.apiUrl,
305
300
  upload: this.config.upload
306
- }, {
307
- logger: this.logger
308
301
  });
309
302
  }
310
303
 
311
304
  // Get the screenshots directory from config or default
312
- const screenshotsDir = options.screenshotsDir || this.config?.upload?.screenshotsDir || './screenshots';
313
- const uploadOptions = {
305
+ let screenshotsDir = options.screenshotsDir || this.config?.upload?.screenshotsDir || './screenshots';
306
+ let uploadOptions = {
314
307
  screenshotsDir,
315
308
  buildName: options.buildName || this.config.buildName,
316
309
  branch: options.branch || this.config.branch,
@@ -326,7 +319,7 @@ export class VizzlySDK extends EventEmitter {
326
319
  }
327
320
  };
328
321
  try {
329
- const result = await this.services.uploader.upload(uploadOptions);
322
+ let result = await this.services.uploader.upload(uploadOptions);
330
323
  this.emit('upload:completed', result);
331
324
  return result;
332
325
  } catch (error) {
@@ -346,15 +339,13 @@ export class VizzlySDK extends EventEmitter {
346
339
  async compare(name, imageBuffer) {
347
340
  if (!this.services?.tddService) {
348
341
  this.services = this.services || {};
349
- this.services.tddService = createTDDService(this.config, {
350
- logger: this.logger
351
- });
342
+ this.services.tddService = createTDDService(this.config);
352
343
  }
353
344
 
354
345
  // Resolve Buffer or file path using shared utility
355
- const buffer = resolveImageBuffer(imageBuffer, 'compare');
346
+ let buffer = resolveImageBuffer(imageBuffer, 'compare');
356
347
  try {
357
- const result = await this.services.tddService.compareScreenshot(name, buffer);
348
+ let result = await this.services.tddService.compareScreenshot(name, buffer);
358
349
  this.emit('comparison:completed', result);
359
350
  return result;
360
351
  } catch (error) {
@@ -369,7 +360,7 @@ export class VizzlySDK extends EventEmitter {
369
360
 
370
361
  // Re-export key utilities and errors
371
362
  export { loadConfig } from '../utils/config-loader.js';
372
- export { createLogger } from '../utils/logger.js';
363
+ export * as output from '../utils/output.js';
373
364
 
374
365
  // Export service creators for advanced usage
375
366
  export { createUploader } from '../services/uploader.js';
@@ -1,9 +1,8 @@
1
1
  import { Buffer } from 'buffer';
2
2
  import { existsSync, readFileSync } from 'fs';
3
3
  import { resolve } from 'path';
4
- import { createServiceLogger } from '../../utils/logger-factory.js';
4
+ import * as output from '../../utils/output.js';
5
5
  import { detectImageInputType } from '../../utils/image-input-detector.js';
6
- const logger = createServiceLogger('API-HANDLER');
7
6
 
8
7
  /**
9
8
  * API Handler - Non-blocking screenshot upload
@@ -41,7 +40,7 @@ export const createApiHandler = apiService => {
41
40
  let uploadPromises = [];
42
41
  const handleScreenshot = async (buildId, name, image, properties = {}) => {
43
42
  if (vizzlyDisabled) {
44
- logger.debug(`Screenshot captured (Vizzly disabled): ${name}`);
43
+ output.debug('upload', `${name} (disabled)`);
45
44
  return {
46
45
  statusCode: 200,
47
46
  body: {
@@ -81,7 +80,6 @@ export const createApiHandler = apiService => {
81
80
  }
82
81
  try {
83
82
  imageBuffer = readFileSync(filePath);
84
- logger.debug(`Loaded screenshot from file: ${filePath}`);
85
83
  } catch (error) {
86
84
  return {
87
85
  statusCode: 500,
@@ -117,10 +115,8 @@ export const createApiHandler = apiService => {
117
115
 
118
116
  // Fire upload in background - DON'T AWAIT!
119
117
  const uploadPromise = apiService.uploadScreenshot(buildId, name, imageBuffer, properties ?? {}).then(result => {
120
- if (result.skipped) {
121
- logger.debug(`Screenshot already exists, skipped: ${name}`);
122
- } else {
123
- logger.debug(`Screenshot uploaded: ${name}`);
118
+ if (!result.skipped) {
119
+ output.debug('upload', name);
124
120
  }
125
121
  return {
126
122
  success: true,
@@ -128,10 +124,11 @@ export const createApiHandler = apiService => {
128
124
  result
129
125
  };
130
126
  }).catch(uploadError => {
131
- logger.error(`❌ Failed to upload screenshot ${name}:`, uploadError.message);
127
+ output.debug('upload', `${name} failed`, {
128
+ error: uploadError.message
129
+ });
132
130
  vizzlyDisabled = true;
133
- const disabledMessage = '⚠️ Vizzly disabled due to upload error - continuing tests without visual testing';
134
- logger.warn(disabledMessage);
131
+ output.warn('Vizzly disabled due to upload error - continuing tests without visual testing');
135
132
  return {
136
133
  success: false,
137
134
  name,
@@ -160,14 +157,13 @@ export const createApiHandler = apiService => {
160
157
  */
161
158
  const flush = async () => {
162
159
  if (uploadPromises.length === 0) {
163
- logger.debug('No uploads to flush');
164
160
  return {
165
161
  uploaded: 0,
166
162
  failed: 0,
167
163
  total: 0
168
164
  };
169
165
  }
170
- logger.debug(`Flushing ${uploadPromises.length} background uploads...`);
166
+ output.debug('upload', `flushing ${uploadPromises.length} uploads`);
171
167
  const results = await Promise.allSettled(uploadPromises);
172
168
  let uploaded = 0;
173
169
  let failed = 0;
@@ -178,7 +174,10 @@ export const createApiHandler = apiService => {
178
174
  failed++;
179
175
  }
180
176
  });
181
- logger.debug(`Upload flush complete: ${uploaded} uploaded, ${failed} failed`);
177
+ output.debug('upload', 'flush complete', {
178
+ uploaded,
179
+ failed
180
+ });
182
181
 
183
182
  // Clear promises array
184
183
  uploadPromises = [];
@@ -192,7 +191,7 @@ export const createApiHandler = apiService => {
192
191
  vizzlyDisabled = false;
193
192
  screenshotCount = 0;
194
193
  uploadPromises = [];
195
- logger.debug('API handler cleanup completed');
194
+ // Silent cleanup
196
195
  };
197
196
  return {
198
197
  handleScreenshot,
@@ -2,14 +2,13 @@ import { Buffer } from 'buffer';
2
2
  import { writeFileSync, readFileSync, existsSync } from 'fs';
3
3
  import { join, resolve } from 'path';
4
4
  import honeydiff from '@vizzly-testing/honeydiff';
5
- import { createServiceLogger } from '../../utils/logger-factory.js';
5
+ import * as output from '../../utils/output.js';
6
6
  import { TddService } from '../../services/tdd-service.js';
7
7
  import { sanitizeScreenshotName, validateScreenshotProperties } from '../../utils/security.js';
8
8
  import { detectImageInputType } from '../../utils/image-input-detector.js';
9
9
  let {
10
10
  getDimensionsSync
11
11
  } = honeydiff;
12
- const logger = createServiceLogger('TDD-HANDLER');
13
12
 
14
13
  /**
15
14
  * Group comparisons by screenshot name with variant structure
@@ -115,7 +114,7 @@ export const createTddHandler = (config, workingDir, baselineBuild, baselineComp
115
114
  const data = readFileSync(reportPath, 'utf8');
116
115
  return JSON.parse(data);
117
116
  } catch (error) {
118
- logger.error('Failed to read report data:', error);
117
+ output.error('Failed to read report data:', error);
119
118
  return {
120
119
  timestamp: Date.now(),
121
120
  comparisons: [],
@@ -144,10 +143,8 @@ export const createTddHandler = (config, workingDir, baselineBuild, baselineComp
144
143
  const existingIndex = reportData.comparisons.findIndex(c => c.id === newComparison.id);
145
144
  if (existingIndex >= 0) {
146
145
  reportData.comparisons[existingIndex] = newComparison;
147
- logger.debug(`Updated comparison for ${newComparison.name} (${newComparison.properties?.viewport_width}x${newComparison.properties?.viewport_height})`);
148
146
  } else {
149
147
  reportData.comparisons.push(newComparison);
150
- logger.debug(`Added new comparison for ${newComparison.name} (${newComparison.properties?.viewport_width}x${newComparison.properties?.viewport_height})`);
151
148
  }
152
149
 
153
150
  // Generate grouped structure from flat comparisons
@@ -163,24 +160,23 @@ export const createTddHandler = (config, workingDir, baselineBuild, baselineComp
163
160
  errors: reportData.comparisons.filter(c => c.status === 'error').length
164
161
  };
165
162
  writeFileSync(reportPath, JSON.stringify(reportData, null, 2));
166
- logger.debug('Report data saved with grouped structure');
167
163
  } catch (error) {
168
- logger.error('Failed to update comparison:', error);
164
+ output.error('Failed to update comparison:', error);
169
165
  }
170
166
  };
171
167
  const initialize = async () => {
172
- logger.debug('TDD mode enabled - setting up local comparison');
168
+ output.debug('tdd', 'setting up local comparison');
173
169
 
174
170
  // In baseline update mode, skip all baseline loading/downloading
175
171
  if (setBaseline) {
176
- logger.debug('Ready for new baseline creation - all screenshots will be treated as new baselines');
172
+ output.debug('tdd', 'baseline update mode');
177
173
  return;
178
174
  }
179
175
 
180
176
  // Check if we have baseline override flags that should force a fresh download
181
177
  const shouldForceDownload = (baselineBuild || baselineComparison) && config.apiKey;
182
178
  if (shouldForceDownload) {
183
- logger.debug('Baseline override specified, downloading fresh baselines from Vizzly');
179
+ output.debug('tdd', 'downloading baselines from cloud');
184
180
  await tddService.downloadBaselines(config.build?.environment || 'test', config.build?.branch || null, baselineBuild, baselineComparison);
185
181
  return;
186
182
  }
@@ -188,13 +184,13 @@ export const createTddHandler = (config, workingDir, baselineBuild, baselineComp
188
184
  if (!baseline) {
189
185
  // Only download baselines if explicitly requested via baseline flags
190
186
  if ((baselineBuild || baselineComparison) && config.apiKey) {
191
- logger.debug('No local baseline found, downloading from Vizzly');
187
+ output.debug('tdd', 'downloading baselines from cloud');
192
188
  await tddService.downloadBaselines(config.build?.environment || 'test', config.build?.branch || null, baselineBuild, baselineComparison);
193
189
  } else {
194
- logger.debug('No local baseline found - will create new baselines from first screenshots');
190
+ output.debug('tdd', 'no baselines found, will create on first run');
195
191
  }
196
192
  } else {
197
- logger.debug(`Using existing baseline: ${baseline.buildName}`);
193
+ output.debug('tdd', `using baseline: ${baseline.buildName}`);
198
194
  }
199
195
  };
200
196
  const handleScreenshot = async (buildId, name, image, properties = {}) => {
@@ -275,7 +271,6 @@ export const createTddHandler = (config, workingDir, baselineBuild, baselineComp
275
271
  }
276
272
  try {
277
273
  imageBuffer = readFileSync(filePath);
278
- logger.debug(`Loaded screenshot from file: ${filePath}`);
279
274
  } catch (error) {
280
275
  return {
281
276
  statusCode: 500,
@@ -321,16 +316,16 @@ export const createTddHandler = (config, workingDir, baselineBuild, baselineComp
321
316
  if (!extractedProperties.viewport_height) {
322
317
  extractedProperties.viewport_height = dimensions.height;
323
318
  }
324
- logger.debug(`Auto-detected dimensions: ${dimensions.width}x${dimensions.height}`);
325
- } catch (err) {
326
- logger.debug(`Failed to auto-detect dimensions: ${err.message}`);
319
+ } catch {
320
+ // Dimensions will use defaults
327
321
  }
328
322
  }
329
323
 
330
324
  // Use the sanitized name as-is (no modification with browser/viewport)
331
325
  // Baseline matching uses signature logic (name + viewport_width + browser)
332
326
  const comparison = await tddService.compareScreenshot(sanitizedName, imageBuffer, extractedProperties);
333
- logger.debug(`Comparison result: ${comparison.status}`);
327
+
328
+ // Comparison tracked by tdd.js event handler
334
329
 
335
330
  // Convert absolute file paths to web-accessible URLs
336
331
  const convertPathToUrl = filePath => {
@@ -409,7 +404,8 @@ export const createTddHandler = (config, workingDir, baselineBuild, baselineComp
409
404
  }
410
405
  };
411
406
  }
412
- logger.debug(`✅ TDD: ${comparison.status.toUpperCase()} ${name}`);
407
+
408
+ // Debug output handled by tdd.js event handler
413
409
  return {
414
410
  statusCode: 200,
415
411
  body: {
@@ -445,16 +441,16 @@ export const createTddHandler = (config, workingDir, baselineBuild, baselineComp
445
441
  diff: null
446
442
  };
447
443
  updateComparison(updatedComparison);
448
- logger.info(`Baseline accepted for comparison ${comparisonId}`);
444
+ output.info(`Baseline accepted for comparison ${comparisonId}`);
449
445
  return result;
450
446
  } catch (error) {
451
- logger.error(`Failed to accept baseline for ${comparisonId}:`, error);
447
+ output.error(`Failed to accept baseline for ${comparisonId}:`, error);
452
448
  throw error;
453
449
  }
454
450
  };
455
451
  const acceptAllBaselines = async () => {
456
452
  try {
457
- logger.debug('Accepting all baselines');
453
+ output.debug('tdd', 'accepting all baselines');
458
454
  const reportData = readReportData();
459
455
  let acceptedCount = 0;
460
456
 
@@ -475,18 +471,18 @@ export const createTddHandler = (config, workingDir, baselineBuild, baselineComp
475
471
  acceptedCount++;
476
472
  }
477
473
  }
478
- logger.info(`Accepted ${acceptedCount} baselines`);
474
+ output.info(`Accepted ${acceptedCount} baselines`);
479
475
  return {
480
476
  count: acceptedCount
481
477
  };
482
478
  } catch (error) {
483
- logger.error('Failed to accept all baselines:', error);
479
+ output.error('Failed to accept all baselines:', error);
484
480
  throw error;
485
481
  }
486
482
  };
487
483
  const resetBaselines = async () => {
488
484
  try {
489
- logger.debug('Resetting baselines');
485
+ output.debug('tdd', 'resetting baselines');
490
486
  const reportData = readReportData();
491
487
  let deletedBaselines = 0;
492
488
  let deletedCurrents = 0;
@@ -504,9 +500,9 @@ export const createTddHandler = (config, workingDir, baselineBuild, baselineComp
504
500
  } = await import('fs');
505
501
  unlinkSync(baselinePath);
506
502
  deletedBaselines++;
507
- logger.debug(`Deleted baseline for ${comparison.name}`);
503
+ // Silent deletion
508
504
  } catch (error) {
509
- logger.warn(`Failed to delete baseline for ${comparison.name}: ${error.message}`);
505
+ output.warn(`Failed to delete baseline for ${comparison.name}: ${error.message}`);
510
506
  }
511
507
  }
512
508
  }
@@ -521,9 +517,9 @@ export const createTddHandler = (config, workingDir, baselineBuild, baselineComp
521
517
  } = await import('fs');
522
518
  unlinkSync(currentPath);
523
519
  deletedCurrents++;
524
- logger.debug(`Deleted current screenshot for ${comparison.name}`);
520
+ // Silent deletion
525
521
  } catch (error) {
526
- logger.warn(`Failed to delete current screenshot for ${comparison.name}: ${error.message}`);
522
+ output.warn(`Failed to delete current screenshot for ${comparison.name}: ${error.message}`);
527
523
  }
528
524
  }
529
525
  }
@@ -538,9 +534,9 @@ export const createTddHandler = (config, workingDir, baselineBuild, baselineComp
538
534
  } = await import('fs');
539
535
  unlinkSync(diffPath);
540
536
  deletedDiffs++;
541
- logger.debug(`Deleted diff for ${comparison.name}`);
537
+ output.debug(`Deleted diff for ${comparison.name}`);
542
538
  } catch (error) {
543
- logger.warn(`Failed to delete diff for ${comparison.name}: ${error.message}`);
539
+ output.warn(`Failed to delete diff for ${comparison.name}: ${error.message}`);
544
540
  }
545
541
  }
546
542
  }
@@ -554,9 +550,9 @@ export const createTddHandler = (config, workingDir, baselineBuild, baselineComp
554
550
  unlinkSync
555
551
  } = await import('fs');
556
552
  unlinkSync(metadataPath);
557
- logger.debug('Deleted baseline metadata');
553
+ output.debug('Deleted baseline metadata');
558
554
  } catch (error) {
559
- logger.warn(`Failed to delete baseline metadata: ${error.message}`);
555
+ output.warn(`Failed to delete baseline metadata: ${error.message}`);
560
556
  }
561
557
  }
562
558
 
@@ -574,7 +570,7 @@ export const createTddHandler = (config, workingDir, baselineBuild, baselineComp
574
570
  }
575
571
  };
576
572
  writeFileSync(reportPath, JSON.stringify(freshReportData, null, 2));
577
- logger.info(`Baselines reset - ${deletedBaselines} baselines deleted, ${deletedCurrents} current screenshots deleted, ${deletedDiffs} diffs deleted`);
573
+ output.info(`Baselines reset - ${deletedBaselines} baselines deleted, ${deletedCurrents} current screenshots deleted, ${deletedDiffs} diffs deleted`);
578
574
  return {
579
575
  success: true,
580
576
  deletedBaselines,
@@ -582,13 +578,12 @@ export const createTddHandler = (config, workingDir, baselineBuild, baselineComp
582
578
  deletedDiffs
583
579
  };
584
580
  } catch (error) {
585
- logger.error('Failed to reset baselines:', error);
581
+ output.error('Failed to reset baselines:', error);
586
582
  throw error;
587
583
  }
588
584
  };
589
585
  const cleanup = () => {
590
586
  // Report data is persisted to file, no in-memory cleanup needed
591
- logger.debug('TDD handler cleanup completed');
592
587
  };
593
588
  return {
594
589
  initialize,
@@ -597,6 +592,8 @@ export const createTddHandler = (config, workingDir, baselineBuild, baselineComp
597
592
  acceptBaseline,
598
593
  acceptAllBaselines,
599
594
  resetBaselines,
600
- cleanup
595
+ cleanup,
596
+ // Expose tddService for baseline download operations
597
+ tddService
601
598
  };
602
599
  };