@vizzly-testing/cli 0.14.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +68 -68
- package/dist/commands/doctor.js +30 -34
- package/dist/commands/finalize.js +24 -23
- package/dist/commands/init.js +30 -28
- package/dist/commands/login.js +49 -55
- package/dist/commands/logout.js +14 -19
- package/dist/commands/project.js +83 -103
- package/dist/commands/run.js +77 -89
- package/dist/commands/status.js +48 -49
- package/dist/commands/tdd-daemon.js +90 -86
- package/dist/commands/tdd.js +59 -88
- package/dist/commands/upload.js +57 -57
- package/dist/commands/whoami.js +40 -45
- package/dist/index.js +2 -5
- package/dist/plugin-loader.js +15 -17
- package/dist/reporter/reporter-bundle.css +1 -1
- package/dist/reporter/reporter-bundle.iife.js +74 -41
- package/dist/sdk/index.js +36 -45
- package/dist/server/handlers/api-handler.js +14 -15
- package/dist/server/handlers/tdd-handler.js +34 -37
- package/dist/server/http-server.js +75 -869
- package/dist/server/middleware/cors.js +22 -0
- package/dist/server/middleware/json-parser.js +35 -0
- package/dist/server/middleware/response.js +79 -0
- package/dist/server/routers/assets.js +91 -0
- package/dist/server/routers/auth.js +144 -0
- package/dist/server/routers/baseline.js +163 -0
- package/dist/server/routers/cloud-proxy.js +146 -0
- package/dist/server/routers/config.js +126 -0
- package/dist/server/routers/dashboard.js +130 -0
- package/dist/server/routers/health.js +61 -0
- package/dist/server/routers/projects.js +168 -0
- package/dist/server/routers/screenshot.js +86 -0
- package/dist/services/auth-service.js +1 -1
- package/dist/services/build-manager.js +13 -40
- package/dist/services/config-service.js +2 -4
- package/dist/services/html-report-generator.js +6 -5
- package/dist/services/index.js +64 -0
- package/dist/services/project-service.js +121 -40
- package/dist/services/screenshot-server.js +9 -9
- package/dist/services/server-manager.js +11 -18
- package/dist/services/static-report-generator.js +3 -4
- package/dist/services/tdd-service.js +246 -103
- package/dist/services/test-runner.js +24 -25
- package/dist/services/uploader.js +5 -4
- package/dist/types/commands/init.d.ts +1 -2
- package/dist/types/index.d.ts +2 -3
- package/dist/types/plugin-loader.d.ts +1 -2
- package/dist/types/reporter/src/api/client.d.ts +178 -0
- package/dist/types/reporter/src/components/app-router.d.ts +1 -3
- package/dist/types/reporter/src/components/code-block.d.ts +4 -0
- package/dist/types/reporter/src/components/comparison/comparison-modes/onion-skin-mode.d.ts +10 -0
- package/dist/types/reporter/src/components/comparison/comparison-modes/overlay-mode.d.ts +11 -0
- package/dist/types/reporter/src/components/comparison/comparison-modes/shared/base-comparison-mode.d.ts +14 -0
- package/dist/types/reporter/src/components/comparison/comparison-modes/shared/image-renderer.d.ts +30 -0
- package/dist/types/reporter/src/components/comparison/comparison-modes/toggle-view.d.ts +8 -0
- package/dist/types/reporter/src/components/comparison/comparison-viewer.d.ts +4 -0
- package/dist/types/reporter/src/components/comparison/screenshot-display.d.ts +16 -0
- package/dist/types/reporter/src/components/design-system/alert.d.ts +9 -0
- package/dist/types/reporter/src/components/design-system/badge.d.ts +17 -0
- package/dist/types/reporter/src/components/design-system/button.d.ts +19 -0
- package/dist/types/reporter/src/components/design-system/card.d.ts +31 -0
- package/dist/types/reporter/src/components/design-system/empty-state.d.ts +13 -0
- package/dist/types/reporter/src/components/design-system/form-controls.d.ts +44 -0
- package/dist/types/reporter/src/components/design-system/health-ring.d.ts +7 -0
- package/dist/types/reporter/src/components/design-system/index.d.ts +11 -0
- package/dist/types/reporter/src/components/design-system/modal.d.ts +10 -0
- package/dist/types/reporter/src/components/design-system/skeleton.d.ts +19 -0
- package/dist/types/reporter/src/components/design-system/spinner.d.ts +10 -0
- package/dist/types/reporter/src/components/design-system/tabs.d.ts +13 -0
- package/dist/types/reporter/src/components/layout/header.d.ts +5 -0
- package/dist/types/reporter/src/components/layout/index.d.ts +2 -0
- package/dist/types/reporter/src/components/layout/layout.d.ts +6 -0
- package/dist/types/reporter/src/components/views/builds-view.d.ts +1 -0
- package/dist/types/reporter/src/components/views/comparison-detail-view.d.ts +1 -4
- package/dist/types/reporter/src/components/views/comparisons-view.d.ts +1 -6
- package/dist/types/reporter/src/components/views/stats-view.d.ts +1 -6
- package/dist/types/reporter/src/components/waiting-for-screenshots.d.ts +1 -0
- package/dist/types/reporter/src/hooks/queries/use-auth-queries.d.ts +15 -0
- package/dist/types/reporter/src/hooks/queries/use-cloud-queries.d.ts +6 -0
- package/dist/types/reporter/src/hooks/queries/use-config-queries.d.ts +6 -0
- package/dist/types/reporter/src/hooks/queries/use-tdd-queries.d.ts +9 -0
- package/dist/types/reporter/src/lib/query-client.d.ts +2 -0
- package/dist/types/reporter/src/lib/query-keys.d.ts +13 -0
- package/dist/types/sdk/index.d.ts +2 -4
- package/dist/types/server/handlers/tdd-handler.d.ts +2 -0
- package/dist/types/server/http-server.d.ts +1 -1
- package/dist/types/server/middleware/cors.d.ts +11 -0
- package/dist/types/server/middleware/json-parser.d.ts +10 -0
- package/dist/types/server/middleware/response.d.ts +50 -0
- package/dist/types/server/routers/assets.d.ts +6 -0
- package/dist/types/server/routers/auth.d.ts +9 -0
- package/dist/types/server/routers/baseline.d.ts +13 -0
- package/dist/types/server/routers/cloud-proxy.d.ts +11 -0
- package/dist/types/server/routers/config.d.ts +9 -0
- package/dist/types/server/routers/dashboard.d.ts +6 -0
- package/dist/types/server/routers/health.d.ts +11 -0
- package/dist/types/server/routers/projects.d.ts +9 -0
- package/dist/types/server/routers/screenshot.d.ts +11 -0
- package/dist/types/services/build-manager.d.ts +4 -3
- package/dist/types/services/config-service.d.ts +2 -3
- package/dist/types/services/index.d.ts +7 -0
- package/dist/types/services/project-service.d.ts +6 -4
- package/dist/types/services/screenshot-server.d.ts +5 -5
- package/dist/types/services/server-manager.d.ts +5 -3
- package/dist/types/services/tdd-service.d.ts +12 -1
- package/dist/types/services/test-runner.d.ts +3 -3
- package/dist/types/utils/output.d.ts +84 -0
- package/dist/utils/config-loader.js +24 -48
- package/dist/utils/global-config.js +2 -17
- package/dist/utils/output.js +445 -0
- package/dist/utils/security.js +3 -4
- package/docs/api-reference.md +0 -1
- package/docs/plugins.md +22 -22
- package/package.json +3 -2
- package/dist/container/index.js +0 -215
- package/dist/services/base-service.js +0 -154
- package/dist/types/container/index.d.ts +0 -59
- package/dist/types/reporter/src/components/comparison/viewer-modes/onion-viewer.d.ts +0 -3
- package/dist/types/reporter/src/components/comparison/viewer-modes/overlay-viewer.d.ts +0 -3
- package/dist/types/reporter/src/components/comparison/viewer-modes/side-by-side-viewer.d.ts +0 -3
- package/dist/types/reporter/src/components/comparison/viewer-modes/toggle-viewer.d.ts +0 -3
- package/dist/types/reporter/src/components/dashboard/dashboard-header.d.ts +0 -5
- package/dist/types/reporter/src/components/dashboard/dashboard-stats.d.ts +0 -4
- package/dist/types/reporter/src/components/dashboard/empty-state.d.ts +0 -8
- package/dist/types/reporter/src/components/ui/form-field.d.ts +0 -16
- package/dist/types/reporter/src/components/ui/status-badge.d.ts +0 -5
- package/dist/types/reporter/src/hooks/use-auth.d.ts +0 -10
- package/dist/types/reporter/src/hooks/use-baseline-actions.d.ts +0 -5
- package/dist/types/reporter/src/hooks/use-config.d.ts +0 -9
- package/dist/types/reporter/src/hooks/use-projects.d.ts +0 -10
- package/dist/types/reporter/src/hooks/use-report-data.d.ts +0 -7
- package/dist/types/reporter/src/hooks/use-vizzly-api.d.ts +0 -9
- package/dist/types/services/base-service.d.ts +0 -71
- package/dist/types/utils/console-ui.d.ts +0 -61
- package/dist/types/utils/logger-factory.d.ts +0 -26
- package/dist/types/utils/logger.d.ts +0 -79
- package/dist/utils/console-ui.js +0 -241
- package/dist/utils/logger-factory.js +0 -76
- package/dist/utils/logger.js +0 -231
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
* Manages reading and writing Vizzly configuration files
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { BaseService } from './base-service.js';
|
|
7
6
|
import { cosmiconfigSync } from 'cosmiconfig';
|
|
8
7
|
import { writeFile, readFile } from 'fs/promises';
|
|
9
8
|
import { join } from 'path';
|
|
@@ -13,11 +12,10 @@ import { loadGlobalConfig, saveGlobalConfig, getGlobalConfigPath } from '../util
|
|
|
13
12
|
|
|
14
13
|
/**
|
|
15
14
|
* ConfigService for reading and writing configuration
|
|
16
|
-
* @extends BaseService
|
|
17
15
|
*/
|
|
18
|
-
export class ConfigService
|
|
16
|
+
export class ConfigService {
|
|
19
17
|
constructor(config, options = {}) {
|
|
20
|
-
|
|
18
|
+
this.config = config;
|
|
21
19
|
this.projectRoot = options.projectRoot || process.cwd();
|
|
22
20
|
this.explorer = cosmiconfigSync('vizzly');
|
|
23
21
|
}
|
|
@@ -7,8 +7,7 @@ import { writeFile, mkdir } from 'fs/promises';
|
|
|
7
7
|
import { existsSync } from 'fs';
|
|
8
8
|
import { join, relative, dirname } from 'path';
|
|
9
9
|
import { fileURLToPath } from 'url';
|
|
10
|
-
import
|
|
11
|
-
const logger = createServiceLogger('HTML-REPORT');
|
|
10
|
+
import * as output from '../utils/output.js';
|
|
12
11
|
export class HtmlReportGenerator {
|
|
13
12
|
constructor(workingDir, config) {
|
|
14
13
|
this.workingDir = workingDir;
|
|
@@ -93,10 +92,12 @@ export class HtmlReportGenerator {
|
|
|
93
92
|
recursive: true
|
|
94
93
|
});
|
|
95
94
|
await writeFile(this.reportPath, htmlContent, 'utf8');
|
|
96
|
-
|
|
95
|
+
output.debug('report', 'generated html report');
|
|
97
96
|
return this.reportPath;
|
|
98
97
|
} catch (error) {
|
|
99
|
-
|
|
98
|
+
output.debug('report', 'html generation failed', {
|
|
99
|
+
error: error.message
|
|
100
|
+
});
|
|
100
101
|
throw new Error(`Report generation failed: ${error.message}`);
|
|
101
102
|
}
|
|
102
103
|
}
|
|
@@ -108,7 +109,7 @@ export class HtmlReportGenerator {
|
|
|
108
109
|
*/
|
|
109
110
|
processComparison(comparison) {
|
|
110
111
|
if (!comparison || typeof comparison !== 'object') {
|
|
111
|
-
|
|
112
|
+
output.warn('Invalid comparison object provided');
|
|
112
113
|
return null;
|
|
113
114
|
}
|
|
114
115
|
return {
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Service Factory
|
|
3
|
+
* Creates all services with explicit dependencies - no DI container needed
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { ApiService } from './api-service.js';
|
|
7
|
+
import { AuthService } from './auth-service.js';
|
|
8
|
+
import { ConfigService } from './config-service.js';
|
|
9
|
+
import { ProjectService } from './project-service.js';
|
|
10
|
+
import { createUploader } from './uploader.js';
|
|
11
|
+
import { BuildManager } from './build-manager.js';
|
|
12
|
+
import { ServerManager } from './server-manager.js';
|
|
13
|
+
import { createTDDService } from './tdd-service.js';
|
|
14
|
+
import { TestRunner } from './test-runner.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Create all services with their dependencies
|
|
18
|
+
* @param {Object} config - Configuration object
|
|
19
|
+
* @param {string} [command='run'] - Command context ('run', 'tdd', 'status')
|
|
20
|
+
* @returns {Object} Services object
|
|
21
|
+
*/
|
|
22
|
+
export function createServices(config, command = 'run') {
|
|
23
|
+
let apiService = new ApiService({
|
|
24
|
+
...config,
|
|
25
|
+
allowNoToken: true
|
|
26
|
+
});
|
|
27
|
+
let authService = new AuthService({
|
|
28
|
+
baseUrl: config.apiUrl
|
|
29
|
+
});
|
|
30
|
+
let configService = new ConfigService(config, {
|
|
31
|
+
projectRoot: process.cwd()
|
|
32
|
+
});
|
|
33
|
+
let projectService = new ProjectService(config, {
|
|
34
|
+
apiService,
|
|
35
|
+
authService
|
|
36
|
+
});
|
|
37
|
+
let uploader = createUploader({
|
|
38
|
+
...config,
|
|
39
|
+
command
|
|
40
|
+
});
|
|
41
|
+
let buildManager = new BuildManager(config);
|
|
42
|
+
let tddService = createTDDService(config, {
|
|
43
|
+
authService
|
|
44
|
+
});
|
|
45
|
+
let serverManager = new ServerManager(config, {
|
|
46
|
+
services: {
|
|
47
|
+
configService,
|
|
48
|
+
authService,
|
|
49
|
+
projectService
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
let testRunner = new TestRunner(config, buildManager, serverManager, tddService);
|
|
53
|
+
return {
|
|
54
|
+
apiService,
|
|
55
|
+
authService,
|
|
56
|
+
configService,
|
|
57
|
+
projectService,
|
|
58
|
+
uploader,
|
|
59
|
+
buildManager,
|
|
60
|
+
serverManager,
|
|
61
|
+
tddService,
|
|
62
|
+
testRunner
|
|
63
|
+
};
|
|
64
|
+
}
|
|
@@ -3,18 +3,17 @@
|
|
|
3
3
|
* Manages project mappings and project-related operations
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { BaseService } from './base-service.js';
|
|
7
6
|
import { VizzlyError } from '../errors/vizzly-error.js';
|
|
8
7
|
import { getProjectMappings, saveProjectMapping, deleteProjectMapping, getProjectMapping } from '../utils/global-config.js';
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
10
|
* ProjectService for managing project mappings and operations
|
|
12
|
-
* @extends BaseService
|
|
13
11
|
*/
|
|
14
|
-
export class ProjectService
|
|
12
|
+
export class ProjectService {
|
|
15
13
|
constructor(config, options = {}) {
|
|
16
|
-
|
|
14
|
+
this.config = config;
|
|
17
15
|
this.apiService = options.apiService;
|
|
16
|
+
this.authService = options.authService;
|
|
18
17
|
}
|
|
19
18
|
|
|
20
19
|
/**
|
|
@@ -100,22 +99,64 @@ export class ProjectService extends BaseService {
|
|
|
100
99
|
|
|
101
100
|
/**
|
|
102
101
|
* List all projects from API
|
|
103
|
-
*
|
|
102
|
+
* Uses OAuth authentication (authService) when available, falls back to API token
|
|
103
|
+
* @returns {Promise<Array>} Array of projects with organization info
|
|
104
104
|
*/
|
|
105
105
|
async listProjects() {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
// Try OAuth-based request first (user login via device flow)
|
|
107
|
+
if (this.authService) {
|
|
108
|
+
try {
|
|
109
|
+
// First get the user's organizations via whoami
|
|
110
|
+
let whoami = await this.authService.authenticatedRequest('/api/auth/cli/whoami', {
|
|
111
|
+
method: 'GET'
|
|
112
|
+
});
|
|
113
|
+
let organizations = whoami.organizations || [];
|
|
114
|
+
if (organizations.length === 0) {
|
|
115
|
+
return [];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Fetch projects for each organization
|
|
119
|
+
let allProjects = [];
|
|
120
|
+
for (let org of organizations) {
|
|
121
|
+
try {
|
|
122
|
+
let response = await this.authService.authenticatedRequest('/api/project', {
|
|
123
|
+
method: 'GET',
|
|
124
|
+
headers: {
|
|
125
|
+
'X-Organization': org.slug
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// Add organization info to each project
|
|
130
|
+
let projects = (response.projects || []).map(project => ({
|
|
131
|
+
...project,
|
|
132
|
+
organizationSlug: org.slug,
|
|
133
|
+
organizationName: org.name
|
|
134
|
+
}));
|
|
135
|
+
allProjects.push(...projects);
|
|
136
|
+
} catch {
|
|
137
|
+
// Silently skip failed orgs
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return allProjects;
|
|
141
|
+
} catch {
|
|
142
|
+
// Fall back to API token
|
|
143
|
+
}
|
|
109
144
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
145
|
+
|
|
146
|
+
// Fall back to API token-based request (tokens are org-scoped, so no org header needed)
|
|
147
|
+
if (this.apiService) {
|
|
148
|
+
try {
|
|
149
|
+
let response = await this.apiService.request('/api/project', {
|
|
150
|
+
method: 'GET'
|
|
151
|
+
});
|
|
152
|
+
return response.projects || [];
|
|
153
|
+
} catch {
|
|
154
|
+
return [];
|
|
155
|
+
}
|
|
118
156
|
}
|
|
157
|
+
|
|
158
|
+
// No authentication available
|
|
159
|
+
return [];
|
|
119
160
|
}
|
|
120
161
|
|
|
121
162
|
/**
|
|
@@ -125,23 +166,43 @@ export class ProjectService extends BaseService {
|
|
|
125
166
|
* @returns {Promise<Object>} Project details
|
|
126
167
|
*/
|
|
127
168
|
async getProject(projectSlug, organizationSlug) {
|
|
128
|
-
|
|
129
|
-
|
|
169
|
+
// Try OAuth-based request first
|
|
170
|
+
if (this.authService) {
|
|
171
|
+
try {
|
|
172
|
+
let response = await this.authService.authenticatedRequest(`/api/project/${projectSlug}`, {
|
|
173
|
+
method: 'GET',
|
|
174
|
+
headers: {
|
|
175
|
+
'X-Organization': organizationSlug
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
return response.project || response;
|
|
179
|
+
} catch {
|
|
180
|
+
// Fall back to API token
|
|
181
|
+
}
|
|
130
182
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
183
|
+
|
|
184
|
+
// Fall back to API token
|
|
185
|
+
if (this.apiService) {
|
|
186
|
+
try {
|
|
187
|
+
let response = await this.apiService.request(`/api/project/${projectSlug}`, {
|
|
188
|
+
method: 'GET',
|
|
189
|
+
headers: {
|
|
190
|
+
'X-Organization': organizationSlug
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
return response.project || response;
|
|
194
|
+
} catch (error) {
|
|
195
|
+
throw new VizzlyError(`Failed to fetch project: ${error.message}`, 'PROJECT_FETCH_FAILED', {
|
|
196
|
+
originalError: error
|
|
197
|
+
});
|
|
198
|
+
}
|
|
140
199
|
}
|
|
200
|
+
throw new VizzlyError('No authentication available', 'NO_AUTH_SERVICE');
|
|
141
201
|
}
|
|
142
202
|
|
|
143
203
|
/**
|
|
144
204
|
* Get recent builds for a project
|
|
205
|
+
* Uses OAuth authentication (authService) when available, falls back to API token
|
|
145
206
|
* @param {string} projectSlug - Project slug
|
|
146
207
|
* @param {string} organizationSlug - Organization slug
|
|
147
208
|
* @param {Object} options - Query options
|
|
@@ -150,24 +211,44 @@ export class ProjectService extends BaseService {
|
|
|
150
211
|
* @returns {Promise<Array>} Array of builds
|
|
151
212
|
*/
|
|
152
213
|
async getRecentBuilds(projectSlug, organizationSlug, options = {}) {
|
|
153
|
-
if (!this.apiService) {
|
|
154
|
-
// Return empty array if not authenticated
|
|
155
|
-
return [];
|
|
156
|
-
}
|
|
157
214
|
let queryParams = new globalThis.URLSearchParams();
|
|
158
215
|
if (options.limit) queryParams.append('limit', String(options.limit));
|
|
159
216
|
if (options.branch) queryParams.append('branch', options.branch);
|
|
160
217
|
let query = queryParams.toString();
|
|
161
|
-
let url = `/api/
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
218
|
+
let url = `/api/build/${projectSlug}${query ? `?${query}` : ''}`;
|
|
219
|
+
|
|
220
|
+
// Try OAuth-based request first (user login via device flow)
|
|
221
|
+
if (this.authService) {
|
|
222
|
+
try {
|
|
223
|
+
let response = await this.authService.authenticatedRequest(url, {
|
|
224
|
+
method: 'GET',
|
|
225
|
+
headers: {
|
|
226
|
+
'X-Organization': organizationSlug
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
return response.builds || [];
|
|
230
|
+
} catch {
|
|
231
|
+
// Fall back to API token
|
|
232
|
+
}
|
|
170
233
|
}
|
|
234
|
+
|
|
235
|
+
// Fall back to API token-based request
|
|
236
|
+
if (this.apiService) {
|
|
237
|
+
try {
|
|
238
|
+
let response = await this.apiService.request(url, {
|
|
239
|
+
method: 'GET',
|
|
240
|
+
headers: {
|
|
241
|
+
'X-Organization': organizationSlug
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
return response.builds || [];
|
|
245
|
+
} catch {
|
|
246
|
+
return [];
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// No authentication available
|
|
251
|
+
return [];
|
|
171
252
|
}
|
|
172
253
|
|
|
173
254
|
/**
|
|
@@ -4,32 +4,32 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { createServer } from 'http';
|
|
7
|
-
import { BaseService } from './base-service.js';
|
|
8
7
|
import { VizzlyError } from '../errors/vizzly-error.js';
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
import * as output from '../utils/output.js';
|
|
9
|
+
export class ScreenshotServer {
|
|
10
|
+
constructor(config, buildManager) {
|
|
11
|
+
this.config = config;
|
|
12
12
|
this.buildManager = buildManager;
|
|
13
13
|
this.server = null;
|
|
14
14
|
}
|
|
15
|
-
async
|
|
15
|
+
async start() {
|
|
16
16
|
this.server = createServer(this.handleRequest.bind(this));
|
|
17
17
|
return new Promise((resolve, reject) => {
|
|
18
18
|
this.server.listen(this.config.server.port, '127.0.0.1', error => {
|
|
19
19
|
if (error) {
|
|
20
20
|
reject(new VizzlyError(`Failed to start screenshot server: ${error.message}`, 'SERVER_ERROR'));
|
|
21
21
|
} else {
|
|
22
|
-
|
|
22
|
+
output.info(`Screenshot server listening on http://127.0.0.1:${this.config.server.port}`);
|
|
23
23
|
resolve();
|
|
24
24
|
}
|
|
25
25
|
});
|
|
26
26
|
});
|
|
27
27
|
}
|
|
28
|
-
async
|
|
28
|
+
async stop() {
|
|
29
29
|
if (this.server) {
|
|
30
30
|
return new Promise(resolve => {
|
|
31
31
|
this.server.close(() => {
|
|
32
|
-
|
|
32
|
+
output.info('Screenshot server stopped');
|
|
33
33
|
resolve();
|
|
34
34
|
});
|
|
35
35
|
});
|
|
@@ -65,7 +65,7 @@ export class ScreenshotServer extends BaseService {
|
|
|
65
65
|
success: true
|
|
66
66
|
}));
|
|
67
67
|
} catch (error) {
|
|
68
|
-
|
|
68
|
+
output.error('Failed to process screenshot:', error);
|
|
69
69
|
res.statusCode = 500;
|
|
70
70
|
res.end(JSON.stringify({
|
|
71
71
|
error: 'Internal server error'
|
|
@@ -3,15 +3,14 @@
|
|
|
3
3
|
* Manages the HTTP server with functional handlers
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { BaseService } from './base-service.js';
|
|
7
6
|
import { createHttpServer } from '../server/http-server.js';
|
|
8
7
|
import { createTddHandler } from '../server/handlers/tdd-handler.js';
|
|
9
8
|
import { createApiHandler } from '../server/handlers/api-handler.js';
|
|
10
9
|
import { writeFileSync, mkdirSync } from 'fs';
|
|
11
10
|
import { join } from 'path';
|
|
12
|
-
export class ServerManager
|
|
11
|
+
export class ServerManager {
|
|
13
12
|
constructor(config, options = {}) {
|
|
14
|
-
|
|
13
|
+
this.config = config;
|
|
15
14
|
this.httpServer = null;
|
|
16
15
|
this.handler = null;
|
|
17
16
|
this.services = options.services || {};
|
|
@@ -20,9 +19,6 @@ export class ServerManager extends BaseService {
|
|
|
20
19
|
this.buildId = buildId;
|
|
21
20
|
this.tddMode = tddMode;
|
|
22
21
|
this.setBaseline = setBaseline;
|
|
23
|
-
return super.start();
|
|
24
|
-
}
|
|
25
|
-
async onStart() {
|
|
26
22
|
const port = this.config?.server?.port || 47392;
|
|
27
23
|
if (this.tddMode) {
|
|
28
24
|
this.handler = createTddHandler(this.config, process.cwd(), this.config?.baselineBuildId, this.config?.baselineComparisonId, this.setBaseline);
|
|
@@ -32,12 +28,14 @@ export class ServerManager extends BaseService {
|
|
|
32
28
|
this.handler = createApiHandler(apiService);
|
|
33
29
|
}
|
|
34
30
|
|
|
35
|
-
// Pass buildId in services so http-server can use
|
|
36
|
-
const
|
|
31
|
+
// Pass buildId and tddService in services so http-server can use them
|
|
32
|
+
const servicesWithExtras = {
|
|
37
33
|
...this.services,
|
|
38
|
-
buildId: this.buildId
|
|
34
|
+
buildId: this.buildId,
|
|
35
|
+
// Expose tddService for baseline download operations (TDD mode only)
|
|
36
|
+
tddService: this.tddMode ? this.handler.tddService : null
|
|
39
37
|
};
|
|
40
|
-
this.httpServer = createHttpServer(port, this.handler,
|
|
38
|
+
this.httpServer = createHttpServer(port, this.handler, servicesWithExtras);
|
|
41
39
|
if (this.httpServer) {
|
|
42
40
|
await this.httpServer.start();
|
|
43
41
|
}
|
|
@@ -62,10 +60,8 @@ export class ServerManager extends BaseService {
|
|
|
62
60
|
serverInfo.buildId = this.buildId;
|
|
63
61
|
}
|
|
64
62
|
writeFileSync(serverFile, JSON.stringify(serverInfo, null, 2));
|
|
65
|
-
|
|
66
|
-
} catch (error) {
|
|
63
|
+
} catch {
|
|
67
64
|
// Non-fatal - SDK can still use health check or environment variables
|
|
68
|
-
this.logger.debug(`Failed to write server.json: ${error.message}`);
|
|
69
65
|
}
|
|
70
66
|
}
|
|
71
67
|
async createApiService() {
|
|
@@ -76,19 +72,16 @@ export class ServerManager extends BaseService {
|
|
|
76
72
|
return new ApiService({
|
|
77
73
|
...this.config,
|
|
78
74
|
command: 'run'
|
|
79
|
-
}, {
|
|
80
|
-
logger: this.logger
|
|
81
75
|
});
|
|
82
76
|
}
|
|
83
|
-
async
|
|
77
|
+
async stop() {
|
|
84
78
|
if (this.httpServer) {
|
|
85
79
|
await this.httpServer.stop();
|
|
86
80
|
}
|
|
87
81
|
if (this.handler?.cleanup) {
|
|
88
82
|
try {
|
|
89
83
|
this.handler.cleanup();
|
|
90
|
-
} catch
|
|
91
|
-
this.logger.debug('Handler cleanup error:', error.message);
|
|
84
|
+
} catch {
|
|
92
85
|
// Don't throw - cleanup errors shouldn't fail the stop process
|
|
93
86
|
}
|
|
94
87
|
}
|
|
@@ -7,8 +7,7 @@ import { writeFile, mkdir, copyFile } from 'fs/promises';
|
|
|
7
7
|
import { existsSync } from 'fs';
|
|
8
8
|
import { join, dirname } from 'path';
|
|
9
9
|
import { fileURLToPath } from 'url';
|
|
10
|
-
import
|
|
11
|
-
const logger = createServiceLogger('STATIC-REPORT');
|
|
10
|
+
import * as output from '../utils/output.js';
|
|
12
11
|
let __filename = fileURLToPath(import.meta.url);
|
|
13
12
|
let __dirname = dirname(__filename);
|
|
14
13
|
let PROJECT_ROOT = join(__dirname, '..', '..');
|
|
@@ -49,10 +48,10 @@ export class StaticReportGenerator {
|
|
|
49
48
|
// Generate HTML with embedded data
|
|
50
49
|
let htmlContent = this.generateHtmlTemplate(reportData);
|
|
51
50
|
await writeFile(this.reportPath, htmlContent, 'utf8');
|
|
52
|
-
|
|
51
|
+
output.debug('report', 'generated static report');
|
|
53
52
|
return this.reportPath;
|
|
54
53
|
} catch (error) {
|
|
55
|
-
|
|
54
|
+
output.error(`Failed to generate static report: ${error.message}`);
|
|
56
55
|
throw new Error(`Report generation failed: ${error.message}`);
|
|
57
56
|
}
|
|
58
57
|
}
|