@vizzly-testing/cli 0.17.0 → 0.18.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 (64) hide show
  1. package/dist/cli.js +84 -58
  2. package/dist/client/index.js +6 -6
  3. package/dist/commands/doctor.js +15 -15
  4. package/dist/commands/finalize.js +7 -7
  5. package/dist/commands/init.js +28 -28
  6. package/dist/commands/login.js +23 -23
  7. package/dist/commands/logout.js +4 -4
  8. package/dist/commands/project.js +36 -36
  9. package/dist/commands/run.js +33 -33
  10. package/dist/commands/status.js +14 -14
  11. package/dist/commands/tdd-daemon.js +43 -43
  12. package/dist/commands/tdd.js +26 -26
  13. package/dist/commands/upload.js +32 -32
  14. package/dist/commands/whoami.js +12 -12
  15. package/dist/index.js +9 -14
  16. package/dist/plugin-loader.js +28 -28
  17. package/dist/reporter/reporter-bundle.css +1 -1
  18. package/dist/reporter/reporter-bundle.iife.js +19 -19
  19. package/dist/sdk/index.js +33 -35
  20. package/dist/server/handlers/api-handler.js +4 -4
  21. package/dist/server/handlers/tdd-handler.js +11 -11
  22. package/dist/server/http-server.js +21 -22
  23. package/dist/server/middleware/json-parser.js +1 -1
  24. package/dist/server/routers/assets.js +14 -14
  25. package/dist/server/routers/auth.js +14 -14
  26. package/dist/server/routers/baseline.js +8 -8
  27. package/dist/server/routers/cloud-proxy.js +15 -15
  28. package/dist/server/routers/config.js +11 -11
  29. package/dist/server/routers/dashboard.js +11 -11
  30. package/dist/server/routers/health.js +4 -4
  31. package/dist/server/routers/projects.js +19 -19
  32. package/dist/server/routers/screenshot.js +9 -9
  33. package/dist/services/api-service.js +16 -16
  34. package/dist/services/auth-service.js +17 -17
  35. package/dist/services/build-manager.js +3 -3
  36. package/dist/services/config-service.js +32 -32
  37. package/dist/services/html-report-generator.js +8 -8
  38. package/dist/services/index.js +11 -11
  39. package/dist/services/project-service.js +19 -19
  40. package/dist/services/report-generator/report.css +3 -3
  41. package/dist/services/report-generator/viewer.js +25 -23
  42. package/dist/services/screenshot-server.js +1 -1
  43. package/dist/services/server-manager.js +5 -5
  44. package/dist/services/static-report-generator.js +14 -14
  45. package/dist/services/tdd-service.js +98 -92
  46. package/dist/services/test-runner.js +3 -3
  47. package/dist/services/uploader.js +10 -8
  48. package/dist/types/config.d.ts +2 -1
  49. package/dist/types/index.d.ts +11 -1
  50. package/dist/types/sdk.d.ts +1 -1
  51. package/dist/utils/browser.js +3 -3
  52. package/dist/utils/build-history.js +12 -12
  53. package/dist/utils/config-loader.js +17 -17
  54. package/dist/utils/config-schema.js +6 -6
  55. package/dist/utils/environment-config.js +11 -0
  56. package/dist/utils/fetch-utils.js +2 -2
  57. package/dist/utils/file-helpers.js +2 -2
  58. package/dist/utils/git.js +3 -6
  59. package/dist/utils/global-config.js +28 -25
  60. package/dist/utils/output.js +136 -28
  61. package/dist/utils/package-info.js +3 -3
  62. package/dist/utils/security.js +12 -12
  63. package/docs/api-reference.md +52 -23
  64. package/package.json +9 -13
@@ -3,9 +3,9 @@
3
3
  * Handles configuration management endpoints
4
4
  */
5
5
 
6
- import { parseJsonBody } from '../middleware/json-parser.js';
7
- import { sendSuccess, sendError, sendServiceUnavailable } from '../middleware/response.js';
8
6
  import * as output from '../../utils/output.js';
7
+ import { parseJsonBody } from '../middleware/json-parser.js';
8
+ import { sendError, sendServiceUnavailable, sendSuccess } from '../middleware/response.js';
9
9
 
10
10
  /**
11
11
  * Create config router
@@ -26,7 +26,7 @@ export function createConfigRouter({
26
26
  // Get merged config with sources
27
27
  if (req.method === 'GET' && pathname === '/api/config') {
28
28
  try {
29
- let configData = await configService.getConfig('merged');
29
+ const configData = await configService.getConfig('merged');
30
30
  sendSuccess(res, configData);
31
31
  return true;
32
32
  } catch (error) {
@@ -41,7 +41,7 @@ export function createConfigRouter({
41
41
  // Get project-level config
42
42
  if (req.method === 'GET' && pathname === '/api/config/project') {
43
43
  try {
44
- let configData = await configService.getConfig('project');
44
+ const configData = await configService.getConfig('project');
45
45
  sendSuccess(res, configData);
46
46
  return true;
47
47
  } catch (error) {
@@ -56,7 +56,7 @@ export function createConfigRouter({
56
56
  // Get global config
57
57
  if (req.method === 'GET' && pathname === '/api/config/global') {
58
58
  try {
59
- let configData = await configService.getConfig('global');
59
+ const configData = await configService.getConfig('global');
60
60
  sendSuccess(res, configData);
61
61
  return true;
62
62
  } catch (error) {
@@ -71,8 +71,8 @@ export function createConfigRouter({
71
71
  // Update project config
72
72
  if (req.method === 'POST' && pathname === '/api/config/project') {
73
73
  try {
74
- let body = await parseJsonBody(req);
75
- let result = await configService.updateConfig('project', body);
74
+ const body = await parseJsonBody(req);
75
+ const result = await configService.updateConfig('project', body);
76
76
  sendSuccess(res, {
77
77
  success: true,
78
78
  ...result
@@ -90,8 +90,8 @@ export function createConfigRouter({
90
90
  // Update global config
91
91
  if (req.method === 'POST' && pathname === '/api/config/global') {
92
92
  try {
93
- let body = await parseJsonBody(req);
94
- let result = await configService.updateConfig('global', body);
93
+ const body = await parseJsonBody(req);
94
+ const result = await configService.updateConfig('global', body);
95
95
  sendSuccess(res, {
96
96
  success: true,
97
97
  ...result
@@ -109,8 +109,8 @@ export function createConfigRouter({
109
109
  // Validate config
110
110
  if (req.method === 'POST' && pathname === '/api/config/validate') {
111
111
  try {
112
- let body = await parseJsonBody(req);
113
- let result = await configService.validateConfig(body);
112
+ const body = await parseJsonBody(req);
113
+ const result = await configService.validateConfig(body);
114
114
  sendSuccess(res, result);
115
115
  return true;
116
116
  } catch (error) {
@@ -3,13 +3,13 @@
3
3
  * Serves the React SPA for all dashboard routes
4
4
  */
5
5
 
6
- import { readFileSync, existsSync } from 'fs';
7
- import { join } from 'path';
8
- import { sendHtml, sendSuccess } from '../middleware/response.js';
6
+ import { existsSync, readFileSync } from 'node:fs';
7
+ import { join } from 'node:path';
9
8
  import * as output from '../../utils/output.js';
9
+ import { sendHtml, sendSuccess } from '../middleware/response.js';
10
10
 
11
11
  // SPA routes that should serve the dashboard HTML
12
- let SPA_ROUTES = ['/', '/dashboard', '/stats', '/settings', '/projects', '/builds'];
12
+ const SPA_ROUTES = ['/', '/dashboard', '/stats', '/settings', '/projects', '/builds'];
13
13
 
14
14
  /**
15
15
  * Create dashboard router
@@ -24,10 +24,10 @@ export function createDashboardRouter() {
24
24
 
25
25
  // API endpoint for fetching report data
26
26
  if (pathname === '/api/report-data') {
27
- let reportDataPath = join(process.cwd(), '.vizzly', 'report-data.json');
27
+ const reportDataPath = join(process.cwd(), '.vizzly', 'report-data.json');
28
28
  if (existsSync(reportDataPath)) {
29
29
  try {
30
- let data = readFileSync(reportDataPath, 'utf8');
30
+ const data = readFileSync(reportDataPath, 'utf8');
31
31
  res.setHeader('Content-Type', 'application/json');
32
32
  res.statusCode = 200;
33
33
  res.end(data);
@@ -50,8 +50,8 @@ export function createDashboardRouter() {
50
50
 
51
51
  // API endpoint for real-time status
52
52
  if (pathname === '/api/status') {
53
- let reportDataPath = join(process.cwd(), '.vizzly', 'report-data.json');
54
- let baselineMetadataPath = join(process.cwd(), '.vizzly', 'baselines', 'metadata.json');
53
+ const reportDataPath = join(process.cwd(), '.vizzly', 'report-data.json');
54
+ const baselineMetadataPath = join(process.cwd(), '.vizzly', 'baselines', 'metadata.json');
55
55
  let reportData = null;
56
56
  let baselineInfo = null;
57
57
  if (existsSync(reportDataPath)) {
@@ -84,11 +84,11 @@ export function createDashboardRouter() {
84
84
 
85
85
  // Serve React SPA for dashboard routes
86
86
  if (SPA_ROUTES.includes(pathname) || pathname.startsWith('/comparison/')) {
87
- let reportDataPath = join(process.cwd(), '.vizzly', 'report-data.json');
87
+ const reportDataPath = join(process.cwd(), '.vizzly', 'report-data.json');
88
88
  let reportData = null;
89
89
  if (existsSync(reportDataPath)) {
90
90
  try {
91
- let data = readFileSync(reportDataPath, 'utf8');
91
+ const data = readFileSync(reportDataPath, 'utf8');
92
92
  reportData = JSON.parse(data);
93
93
  } catch (error) {
94
94
  output.debug('Could not read report data:', {
@@ -96,7 +96,7 @@ export function createDashboardRouter() {
96
96
  });
97
97
  }
98
98
  }
99
- let dashboardHtml = `
99
+ const dashboardHtml = `
100
100
  <!DOCTYPE html>
101
101
  <html>
102
102
  <head>
@@ -3,8 +3,8 @@
3
3
  * Health check endpoint with diagnostics
4
4
  */
5
5
 
6
- import { readFileSync, existsSync } from 'fs';
7
- import { join } from 'path';
6
+ import { existsSync, readFileSync } from 'node:fs';
7
+ import { join } from 'node:path';
8
8
  import { sendSuccess } from '../middleware/response.js';
9
9
 
10
10
  /**
@@ -22,8 +22,8 @@ export function createHealthRouter({
22
22
  if (req.method !== 'GET' || pathname !== '/health') {
23
23
  return false;
24
24
  }
25
- let reportDataPath = join(process.cwd(), '.vizzly', 'report-data.json');
26
- let baselineMetadataPath = join(process.cwd(), '.vizzly', 'baselines', 'metadata.json');
25
+ const reportDataPath = join(process.cwd(), '.vizzly', 'report-data.json');
26
+ const baselineMetadataPath = join(process.cwd(), '.vizzly', 'baselines', 'metadata.json');
27
27
  let reportData = null;
28
28
  let baselineInfo = null;
29
29
  if (existsSync(reportDataPath)) {
@@ -3,9 +3,9 @@
3
3
  * Handles project management and builds endpoints
4
4
  */
5
5
 
6
- import { parseJsonBody } from '../middleware/json-parser.js';
7
- import { sendSuccess, sendError, sendServiceUnavailable } from '../middleware/response.js';
8
6
  import * as output from '../../utils/output.js';
7
+ import { parseJsonBody } from '../middleware/json-parser.js';
8
+ import { sendError, sendServiceUnavailable, sendSuccess } from '../middleware/response.js';
9
9
 
10
10
  /**
11
11
  * Create projects router
@@ -26,7 +26,7 @@ export function createProjectsRouter({
26
26
  // List all projects from API
27
27
  if (req.method === 'GET' && pathname === '/api/projects') {
28
28
  try {
29
- let projects = await projectService.listProjects();
29
+ const projects = await projectService.listProjects();
30
30
  sendSuccess(res, {
31
31
  projects
32
32
  });
@@ -43,7 +43,7 @@ export function createProjectsRouter({
43
43
  // List project directory mappings
44
44
  if (req.method === 'GET' && pathname === '/api/projects/mappings') {
45
45
  try {
46
- let mappings = await projectService.listMappings();
46
+ const mappings = await projectService.listMappings();
47
47
  sendSuccess(res, {
48
48
  mappings
49
49
  });
@@ -60,15 +60,15 @@ export function createProjectsRouter({
60
60
  // Create or update project mapping
61
61
  if (req.method === 'POST' && pathname === '/api/projects/mappings') {
62
62
  try {
63
- let body = await parseJsonBody(req);
64
- let {
63
+ const body = await parseJsonBody(req);
64
+ const {
65
65
  directory,
66
66
  projectSlug,
67
67
  organizationSlug,
68
68
  token,
69
69
  projectName
70
70
  } = body;
71
- let mapping = await projectService.createMapping(directory, {
71
+ const mapping = await projectService.createMapping(directory, {
72
72
  projectSlug,
73
73
  organizationSlug,
74
74
  token,
@@ -91,7 +91,7 @@ export function createProjectsRouter({
91
91
  // Delete project mapping
92
92
  if (req.method === 'DELETE' && pathname.startsWith('/api/projects/mappings/')) {
93
93
  try {
94
- let directory = decodeURIComponent(pathname.replace('/api/projects/mappings/', ''));
94
+ const directory = decodeURIComponent(pathname.replace('/api/projects/mappings/', ''));
95
95
  await projectService.removeMapping(directory);
96
96
  sendSuccess(res, {
97
97
  success: true,
@@ -114,15 +114,15 @@ export function createProjectsRouter({
114
114
  return true;
115
115
  }
116
116
  try {
117
- let currentDir = process.cwd();
118
- let mapping = await projectService.getMapping(currentDir);
117
+ const currentDir = process.cwd();
118
+ const mapping = await projectService.getMapping(currentDir);
119
119
  if (!mapping || !mapping.projectSlug || !mapping.organizationSlug) {
120
120
  sendError(res, 400, 'No project configured for this directory');
121
121
  return true;
122
122
  }
123
- let limit = parseInt(parsedUrl.searchParams.get('limit') || '10', 10);
124
- let branch = parsedUrl.searchParams.get('branch') || undefined;
125
- let builds = await projectService.getRecentBuilds(mapping.projectSlug, mapping.organizationSlug, {
123
+ const limit = parseInt(parsedUrl.searchParams.get('limit') || '10', 10);
124
+ const branch = parsedUrl.searchParams.get('branch') || undefined;
125
+ const builds = await projectService.getRecentBuilds(mapping.projectSlug, mapping.organizationSlug, {
126
126
  limit,
127
127
  branch
128
128
  });
@@ -140,14 +140,14 @@ export function createProjectsRouter({
140
140
  }
141
141
 
142
142
  // Get builds for a specific project (used by /builds page)
143
- let projectBuildsMatch = pathname.match(/^\/api\/projects\/([^/]+)\/([^/]+)\/builds$/);
143
+ const projectBuildsMatch = pathname.match(/^\/api\/projects\/([^/]+)\/([^/]+)\/builds$/);
144
144
  if (req.method === 'GET' && projectBuildsMatch) {
145
145
  try {
146
- let organizationSlug = decodeURIComponent(projectBuildsMatch[1]);
147
- let projectSlug = decodeURIComponent(projectBuildsMatch[2]);
148
- let limit = parseInt(parsedUrl.searchParams.get('limit') || '20', 10);
149
- let branch = parsedUrl.searchParams.get('branch') || undefined;
150
- let builds = await projectService.getRecentBuilds(projectSlug, organizationSlug, {
146
+ const organizationSlug = decodeURIComponent(projectBuildsMatch[1]);
147
+ const projectSlug = decodeURIComponent(projectBuildsMatch[2]);
148
+ const limit = parseInt(parsedUrl.searchParams.get('limit') || '20', 10);
149
+ const branch = parsedUrl.searchParams.get('branch') || undefined;
150
+ const builds = await projectService.getRecentBuilds(projectSlug, organizationSlug, {
151
151
  limit,
152
152
  branch
153
153
  });
@@ -3,9 +3,9 @@
3
3
  * Handles screenshot uploads and legacy baseline accept
4
4
  */
5
5
 
6
- import { parseJsonBody } from '../middleware/json-parser.js';
7
- import { sendJson, sendError } from '../middleware/response.js';
8
6
  import * as output from '../../utils/output.js';
7
+ import { parseJsonBody } from '../middleware/json-parser.js';
8
+ import { sendError, sendJson } from '../middleware/response.js';
9
9
 
10
10
  /**
11
11
  * Create screenshot router
@@ -26,8 +26,8 @@ export function createScreenshotRouter({
26
26
  // Main screenshot upload endpoint
27
27
  if (pathname === '/screenshot') {
28
28
  try {
29
- let body = await parseJsonBody(req);
30
- let {
29
+ const body = await parseJsonBody(req);
30
+ const {
31
31
  buildId,
32
32
  name,
33
33
  properties,
@@ -39,8 +39,8 @@ export function createScreenshotRouter({
39
39
  }
40
40
 
41
41
  // Use buildId from request body, or fall back to server's buildId
42
- let effectiveBuildId = buildId || defaultBuildId;
43
- let result = await screenshotHandler.handleScreenshot(effectiveBuildId, name, image, properties);
42
+ const effectiveBuildId = buildId || defaultBuildId;
43
+ const result = await screenshotHandler.handleScreenshot(effectiveBuildId, name, image, properties);
44
44
  sendJson(res, result.statusCode, result.body);
45
45
  return true;
46
46
  } catch (error) {
@@ -55,8 +55,8 @@ export function createScreenshotRouter({
55
55
  // Legacy accept-baseline endpoint
56
56
  if (pathname === '/accept-baseline') {
57
57
  try {
58
- let body = await parseJsonBody(req);
59
- let {
58
+ const body = await parseJsonBody(req);
59
+ const {
60
60
  id
61
61
  } = body;
62
62
  if (!id) {
@@ -64,7 +64,7 @@ export function createScreenshotRouter({
64
64
  return true;
65
65
  }
66
66
  if (screenshotHandler.acceptBaseline) {
67
- let result = await screenshotHandler.acceptBaseline(id);
67
+ const result = await screenshotHandler.acceptBaseline(id);
68
68
  sendJson(res, 200, {
69
69
  success: true,
70
70
  ...result
@@ -3,12 +3,12 @@
3
3
  * Handles HTTP requests to the Vizzly API
4
4
  */
5
5
 
6
- import { URLSearchParams } from 'url';
7
- import { VizzlyError, AuthError } from '../errors/vizzly-error.js';
8
- import crypto from 'crypto';
9
- import { getPackageVersion } from '../utils/package-info.js';
10
- import { getApiUrl, getApiToken, getUserAgent } from '../utils/environment-config.js';
6
+ import crypto from 'node:crypto';
7
+ import { URLSearchParams } from 'node:url';
8
+ import { AuthError, VizzlyError } from '../errors/vizzly-error.js';
9
+ import { getApiToken, getApiUrl, getUserAgent } from '../utils/environment-config.js';
11
10
  import { getAuthTokens, saveAuthTokens } from '../utils/global-config.js';
11
+ import { getPackageVersion } from '../utils/package-info.js';
12
12
 
13
13
  /**
14
14
  * ApiService class for direct API communication
@@ -66,11 +66,11 @@ export class ApiService {
66
66
  // Handle authentication errors with automatic token refresh
67
67
  if (response.status === 401 && !isRetry) {
68
68
  // Attempt to refresh token if we have refresh token in global config
69
- let auth = await getAuthTokens();
70
- if (auth && auth.refreshToken) {
69
+ const auth = await getAuthTokens();
70
+ if (auth?.refreshToken) {
71
71
  try {
72
72
  // Attempt token refresh
73
- let refreshResponse = await fetch(`${this.baseUrl}/api/auth/cli/refresh`, {
73
+ const refreshResponse = await fetch(`${this.baseUrl}/api/auth/cli/refresh`, {
74
74
  method: 'POST',
75
75
  headers: {
76
76
  'Content-Type': 'application/json',
@@ -81,7 +81,7 @@ export class ApiService {
81
81
  })
82
82
  });
83
83
  if (refreshResponse.ok) {
84
- let refreshData = await refreshResponse.json();
84
+ const refreshData = await refreshResponse.json();
85
85
 
86
86
  // Save new tokens to global config
87
87
  await saveAuthTokens({
@@ -128,7 +128,7 @@ export class ApiService {
128
128
  * @returns {Promise<Object>} Comparison data
129
129
  */
130
130
  async getComparison(comparisonId) {
131
- let response = await this.request(`/api/sdk/comparisons/${comparisonId}`);
131
+ const response = await this.request(`/api/sdk/comparisons/${comparisonId}`);
132
132
  return response.comparison;
133
133
  }
134
134
 
@@ -145,7 +145,7 @@ export class ApiService {
145
145
  if (!name || typeof name !== 'string') {
146
146
  throw new VizzlyError('name is required and must be a non-empty string');
147
147
  }
148
- let {
148
+ const {
149
149
  branch,
150
150
  limit = 50,
151
151
  offset = 0
@@ -274,7 +274,7 @@ export class ApiService {
274
274
 
275
275
  // Check if this SHA with signature already exists
276
276
  const checkResult = await this.checkShas(screenshotCheck, buildId);
277
- if (checkResult.existing && checkResult.existing.includes(sha256)) {
277
+ if (checkResult.existing?.includes(sha256)) {
278
278
  // File already exists with same signature, screenshot record was automatically created
279
279
  const screenshot = checkResult.screenshots?.find(s => s.sha256 === sha256);
280
280
  return {
@@ -366,13 +366,13 @@ export class ApiService {
366
366
  * @returns {Promise<Object>} Hotspot analysis data
367
367
  */
368
368
  async getScreenshotHotspots(screenshotName, options = {}) {
369
- let {
369
+ const {
370
370
  windowSize = 20
371
371
  } = options;
372
- let queryParams = new URLSearchParams({
372
+ const queryParams = new URLSearchParams({
373
373
  windowSize: String(windowSize)
374
374
  });
375
- let encodedName = encodeURIComponent(screenshotName);
375
+ const encodedName = encodeURIComponent(screenshotName);
376
376
  return this.request(`/api/sdk/screenshots/${encodedName}/hotspots?${queryParams}`);
377
377
  }
378
378
 
@@ -385,7 +385,7 @@ export class ApiService {
385
385
  * @returns {Promise<Object>} Hotspots keyed by screenshot name
386
386
  */
387
387
  async getBatchHotspots(screenshotNames, options = {}) {
388
- let {
388
+ const {
389
389
  windowSize = 20
390
390
  } = options;
391
391
  return this.request('/api/sdk/screenshots/hotspots', {
@@ -5,8 +5,8 @@
5
5
 
6
6
  import { AuthError, VizzlyError } from '../errors/vizzly-error.js';
7
7
  import { getApiUrl } from '../utils/environment-config.js';
8
+ import { clearAuthTokens, getAuthTokens, saveAuthTokens } from '../utils/global-config.js';
8
9
  import { getPackageVersion } from '../utils/package-info.js';
9
- import { saveAuthTokens, clearAuthTokens, getAuthTokens } from '../utils/global-config.js';
10
10
 
11
11
  /**
12
12
  * AuthService class for CLI authentication
@@ -24,12 +24,12 @@ export class AuthService {
24
24
  * @returns {Promise<Object>} Response data
25
25
  */
26
26
  async request(endpoint, options = {}) {
27
- let url = `${this.baseUrl}${endpoint}`;
28
- let headers = {
27
+ const url = `${this.baseUrl}${endpoint}`;
28
+ const headers = {
29
29
  'User-Agent': this.userAgent,
30
30
  ...options.headers
31
31
  };
32
- let response = await fetch(url, {
32
+ const response = await fetch(url, {
33
33
  ...options,
34
34
  headers
35
35
  });
@@ -37,8 +37,8 @@ export class AuthService {
37
37
  let errorText = '';
38
38
  let errorData = null;
39
39
  try {
40
- let contentType = response.headers.get('content-type');
41
- if (contentType && contentType.includes('application/json')) {
40
+ const contentType = response.headers.get('content-type');
41
+ if (contentType?.includes('application/json')) {
42
42
  errorData = await response.json();
43
43
  errorText = errorData.error || errorData.message || '';
44
44
  } else {
@@ -65,26 +65,26 @@ export class AuthService {
65
65
  * @returns {Promise<Object>} Response data
66
66
  */
67
67
  async authenticatedRequest(endpoint, options = {}) {
68
- let auth = await getAuthTokens();
68
+ const auth = await getAuthTokens();
69
69
  if (!auth || !auth.accessToken) {
70
70
  throw new AuthError('No authentication token found. Please run "vizzly login" first.');
71
71
  }
72
- let url = `${this.baseUrl}${endpoint}`;
73
- let headers = {
72
+ const url = `${this.baseUrl}${endpoint}`;
73
+ const headers = {
74
74
  'User-Agent': this.userAgent,
75
75
  Authorization: `Bearer ${auth.accessToken}`,
76
76
  ...options.headers
77
77
  };
78
- let response = await fetch(url, {
78
+ const response = await fetch(url, {
79
79
  ...options,
80
80
  headers
81
81
  });
82
82
  if (!response.ok) {
83
83
  let errorText = '';
84
84
  try {
85
- let contentType = response.headers.get('content-type');
86
- if (contentType && contentType.includes('application/json')) {
87
- let errorData = await response.json();
85
+ const contentType = response.headers.get('content-type');
86
+ if (contentType?.includes('application/json')) {
87
+ const errorData = await response.json();
88
88
  errorText = errorData.error || errorData.message || '';
89
89
  } else {
90
90
  errorText = await response.text();
@@ -151,11 +151,11 @@ export class AuthService {
151
151
  * @returns {Promise<Object>} New tokens
152
152
  */
153
153
  async refresh() {
154
- let auth = await getAuthTokens();
154
+ const auth = await getAuthTokens();
155
155
  if (!auth || !auth.refreshToken) {
156
156
  throw new AuthError('No refresh token found. Please run "vizzly login" first.');
157
157
  }
158
- let response = await this.request('/api/auth/cli/refresh', {
158
+ const response = await this.request('/api/auth/cli/refresh', {
159
159
  method: 'POST',
160
160
  headers: {
161
161
  'Content-Type': 'application/json'
@@ -180,8 +180,8 @@ export class AuthService {
180
180
  * @returns {Promise<void>}
181
181
  */
182
182
  async logout() {
183
- let auth = await getAuthTokens();
184
- if (auth && auth.refreshToken) {
183
+ const auth = await getAuthTokens();
184
+ if (auth?.refreshToken) {
185
185
  try {
186
186
  // Attempt to revoke tokens on server
187
187
  await this.request('/api/auth/cli/logout', {
@@ -3,7 +3,7 @@
3
3
  * Manages the build lifecycle and coordinates test execution
4
4
  */
5
5
 
6
- import crypto from 'crypto';
6
+ import crypto from 'node:crypto';
7
7
  import { VizzlyError } from '../errors/vizzly-error.js';
8
8
 
9
9
  /**
@@ -127,7 +127,7 @@ export class BuildManager {
127
127
  this.buildQueue = [];
128
128
  }
129
129
  async createBuild(buildOptions) {
130
- let build = createBuildObject(buildOptions);
130
+ const build = createBuildObject(buildOptions);
131
131
  this.currentBuild = build;
132
132
  return build;
133
133
  }
@@ -156,7 +156,7 @@ export class BuildManager {
156
156
  return this.currentBuild;
157
157
  }
158
158
  queueBuild(buildOptions) {
159
- let queuedBuild = createQueuedBuild(buildOptions);
159
+ const queuedBuild = createQueuedBuild(buildOptions);
160
160
  this.buildQueue.push(queuedBuild);
161
161
  }
162
162
  async clear() {