@vizzly-testing/cli 0.39.1 → 0.39.2
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/README.md +8 -0
- package/bin/vizzly.js +1 -1
- package/dist/{cli.js → adapters/cli/cli.js} +41 -35
- package/dist/adapters/cli/setup.js +34 -0
- package/dist/{client → adapters/client}/index.js +6 -7
- package/dist/adapters/http/cloud-proxy.js +29 -0
- package/dist/{server → adapters/http}/http-server.js +12 -13
- package/dist/{server-manager/operations.js → adapters/http/server-lifecycle.js} +10 -13
- package/dist/{server-manager/index.js → adapters/http/server-manager.js} +23 -27
- package/dist/{plugin-api.js → adapters/plugins/plugin-api.js} +1 -1
- package/dist/{plugin-loader.js → adapters/plugins/plugin-loader.js} +1 -1
- package/dist/{services/index.js → adapters/plugins/services.js} +4 -9
- package/dist/adapters/sdk/index.d.ts +89 -0
- package/dist/{sdk → adapters/sdk}/index.js +22 -19
- package/dist/{commands/api.js → domains/api/api.commands.js} +3 -3
- package/dist/{auth/client.js → domains/auth/auth-client.js} +4 -3
- package/dist/domains/auth/auth-errors.js +50 -0
- package/dist/domains/auth/auth-headers.js +41 -0
- package/dist/domains/auth/auth.normalizers.js +50 -0
- package/dist/{server/routers/auth.js → domains/auth/auth.routes.js} +9 -9
- package/dist/domains/auth/auth.rules.js +19 -0
- package/dist/domains/auth/auth.serializers.js +32 -0
- package/dist/{auth/operations.js → domains/auth/auth.service.js} +115 -17
- package/dist/domains/auth/auth.validations.js +21 -0
- package/dist/{api/client.js → domains/auth/cloud-client.js} +11 -18
- package/dist/{commands/login.js → domains/auth/login.commands.js} +11 -8
- package/dist/{commands/logout.js → domains/auth/logout.commands.js} +6 -4
- package/dist/domains/auth/token-store.js +81 -0
- package/dist/{commands/whoami.js → domains/auth/whoami.commands.js} +6 -3
- package/dist/domains/baselines/baseline-download.js +192 -0
- package/dist/domains/baselines/baseline-write.js +22 -0
- package/dist/{server/routers/baseline.js → domains/baselines/baseline.routes.js} +3 -3
- package/dist/{tdd/services/baseline-manager.js → domains/baselines/baseline.service.js} +1 -39
- package/dist/{commands/baselines.js → domains/baselines/baselines.commands.js} +3 -3
- package/dist/domains/baselines/cloud-baselines.js +9 -0
- package/dist/domains/baselines/cloud-baselines.routes.js +42 -0
- package/dist/domains/builds/build.normalizers.js +35 -0
- package/dist/domains/builds/build.serializers.js +164 -0
- package/dist/domains/builds/build.service.js +119 -0
- package/dist/domains/builds/build.validations.js +39 -0
- package/dist/{commands/builds.js → domains/builds/builds.commands.js} +6 -74
- package/dist/domains/builds/cloud-builds.routes.js +31 -0
- package/dist/{commands/finalize.js → domains/builds/finalize.commands.js} +5 -17
- package/dist/{commands/status.js → domains/builds/status.commands.js} +9 -120
- package/dist/domains/comparisons/cloud-comparisons.js +43 -0
- package/dist/{tdd/services/comparison-service.js → domains/comparisons/comparison.service.js} +1 -1
- package/dist/{commands/comparisons.js → domains/comparisons/comparisons.commands.js} +7 -5
- package/dist/domains/config/config-defaults.js +27 -0
- package/dist/{utils → domains/config}/config-discovery.js +1 -9
- package/dist/{utils → domains/config}/config-loader.js +10 -9
- package/dist/{commands/config-cmd.js → domains/config/config.commands.js} +4 -4
- package/dist/{types → domains/config}/config.d.ts +3 -3
- package/dist/domains/config/config.normalizers.js +126 -0
- package/dist/{server/routers/config.js → domains/config/config.routes.js} +13 -13
- package/dist/domains/config/config.rules.js +47 -0
- package/dist/domains/config/config.serializers.js +202 -0
- package/dist/domains/config/config.service.js +625 -0
- package/dist/{utils/config-schema.js → domains/config/config.validations.js} +9 -9
- package/dist/{utils/environment-config.js → domains/config/environment.js} +1 -8
- package/dist/domains/context/compact-context.validations.js +60 -0
- package/dist/domains/context/context-presentation.js +368 -0
- package/dist/domains/context/context.commands.js +385 -0
- package/dist/domains/context/context.serializers.js +157 -0
- package/dist/domains/context/context.service.js +76 -0
- package/dist/domains/context/context.validations.js +100 -0
- package/dist/{context → domains/context}/local-workspace-provider.js +1 -1
- package/dist/{commands/doctor.js → domains/diagnostics/doctor.commands.js} +6 -5
- package/dist/{server/routers/health.js → domains/diagnostics/health.routes.js} +11 -20
- package/dist/{commands/preview.js → domains/previews/preview.commands.js} +9 -7
- package/dist/domains/previews/preview.service.js +37 -0
- package/dist/domains/projects/cloud-projects.routes.js +28 -0
- package/dist/{commands/orgs.js → domains/projects/orgs.commands.js} +6 -8
- package/dist/{utils → domains/projects}/project-binding.js +3 -3
- package/dist/domains/projects/project-errors.js +61 -0
- package/dist/{utils → domains/projects}/project-link-store.js +2 -2
- package/dist/domains/projects/project-requests.js +61 -0
- package/dist/{commands/project.js → domains/projects/project.commands.js} +9 -41
- package/dist/domains/projects/project.normalizers.js +69 -0
- package/dist/{project/operations.js → domains/projects/project.service.js} +89 -16
- package/dist/domains/projects/project.validations.js +31 -0
- package/dist/{commands/projects.js → domains/projects/projects.commands.js} +6 -8
- package/dist/{server/routers/projects.js → domains/projects/projects.routes.js} +5 -5
- package/dist/domains/reports/dashboard.routes.js +96 -0
- package/dist/{server/routers/events.js → domains/reports/events.routes.js} +14 -36
- package/dist/domains/reports/report-assets.routes.js +81 -0
- package/dist/domains/reports/report-state.js +51 -0
- package/dist/domains/reports/report-store.js +85 -0
- package/dist/domains/reports/report.serializers.js +99 -0
- package/dist/{services/static-report-generator.js → domains/reports/report.service.js} +11 -33
- package/dist/{commands/review.js → domains/review/review.commands.js} +4 -4
- package/dist/domains/runs/run-environment.js +69 -0
- package/dist/{services/test-runner.js → domains/runs/run-events.js} +11 -9
- package/dist/{commands/run.js → domains/runs/run.commands.js} +16 -13
- package/dist/domains/runs/run.normalizers.js +8 -0
- package/dist/domains/runs/run.rules.js +56 -0
- package/dist/domains/runs/run.serializers.js +101 -0
- package/dist/{test-runner/operations.js → domains/runs/run.service.js} +35 -7
- package/dist/domains/runs/run.validations.js +17 -0
- package/dist/{utils/session.js → domains/runs/session-store.js} +3 -2
- package/dist/{server/handlers/api-handler.js → domains/screenshots/cloud-handler.js} +4 -4
- package/dist/domains/screenshots/cloud-screenshots.js +109 -0
- package/dist/{utils/file-helpers.js → domains/screenshots/image-files.js} +1 -1
- package/dist/domains/screenshots/screenshot-hash.js +53 -0
- package/dist/domains/screenshots/screenshot-server-options.js +28 -0
- package/dist/{screenshot-server/operations.js → domains/screenshots/screenshot-server.js} +14 -1
- package/dist/domains/screenshots/screenshot.normalizers.js +40 -0
- package/dist/{server/routers/screenshot.js → domains/screenshots/screenshot.routes.js} +4 -4
- package/dist/domains/screenshots/screenshot.serializers.js +146 -0
- package/dist/{utils/security.js → domains/screenshots/screenshot.validations.js} +20 -70
- package/dist/{init/agents.js → domains/setup/agent-setup.js} +4 -5
- package/dist/{commands/init.js → domains/setup/init.commands.js} +10 -41
- package/dist/{server/handlers/tdd-handler.js → domains/tdd/screenshot-handler.js} +46 -281
- package/dist/{commands/tdd-daemon.js → domains/tdd/tdd-daemon.commands.js} +6 -6
- package/dist/{commands/tdd-screenshots.js → domains/tdd/tdd-screenshots.commands.js} +5 -5
- package/dist/{commands/tdd.js → domains/tdd/tdd.commands.js} +16 -15
- package/dist/{tdd/tdd-service.js → domains/tdd/tdd.service.js} +81 -405
- package/dist/{utils → domains/updates}/cli-update.js +4 -6
- package/dist/{utils → domains/updates}/update-notifications.js +7 -7
- package/dist/domains/uploads/upload-defaults.js +4 -0
- package/dist/domains/uploads/upload-files.js +32 -0
- package/dist/domains/uploads/upload-settings.js +21 -0
- package/dist/domains/uploads/upload-timing.js +18 -0
- package/dist/{commands/upload.js → domains/uploads/upload.commands.js} +11 -9
- package/dist/domains/uploads/upload.normalizers.js +60 -0
- package/dist/domains/uploads/upload.serializers.js +179 -0
- package/dist/{uploader/operations.js → domains/uploads/upload.service.js} +85 -28
- package/dist/domains/uploads/upload.validations.js +77 -0
- package/dist/index.js +12 -12
- package/dist/reporter/reporter-bundle.iife.js +86 -86
- package/dist/reporter-ssr/ssr-entry.js +2 -2
- package/dist/shared/cloud-protocol.js +171 -0
- package/dist/{utils → shared}/file-changes.js +1 -1
- package/dist/shared/files.js +9 -0
- package/dist/{utils → shared}/global-config.js +7 -78
- package/dist/shared/log-level.js +7 -0
- package/dist/{utils → shared}/output.js +1 -1
- package/dist/{utils → shared}/package-info.js +5 -4
- package/dist/shared/paths.js +57 -0
- package/package.json +23 -22
- package/dist/api/core.js +0 -382
- package/dist/api/endpoints.js +0 -421
- package/dist/api/index.js +0 -19
- package/dist/auth/core.js +0 -237
- package/dist/auth/index.js +0 -31
- package/dist/commands/context.js +0 -1066
- package/dist/config/core.js +0 -439
- package/dist/config/operations.js +0 -327
- package/dist/project/core.js +0 -211
- package/dist/screenshot-server/core.js +0 -161
- package/dist/screenshot-server/index.js +0 -11
- package/dist/server/routers/assets.js +0 -95
- package/dist/server/routers/cloud-proxy.js +0 -146
- package/dist/server/routers/dashboard.js +0 -172
- package/dist/services/auth-service.js +0 -117
- package/dist/services/config-service.js +0 -313
- package/dist/services/project-service.js +0 -88
- package/dist/test-runner/core.js +0 -293
- package/dist/test-runner/index.js +0 -13
- package/dist/types/sdk.d.ts +0 -186
- package/dist/uploader/core.js +0 -432
- package/dist/uploader/index.js +0 -88
- /package/dist/{types/client.d.ts → adapters/client/index.d.ts} +0 -0
- /package/dist/{server → adapters/http}/middleware/cors.js +0 -0
- /package/dist/{server → adapters/http}/middleware/json-parser.js +0 -0
- /package/dist/{server → adapters/http}/middleware/response.js +0 -0
- /package/dist/{server-manager/core.js → adapters/http/server-options.js} +0 -0
- /package/dist/{utils/login-poll-wait.js → domains/auth/login-wait.js} +0 -0
- /package/dist/{tdd/metadata → domains/baselines}/baseline-metadata.js +0 -0
- /package/dist/{services/build-manager.js → domains/builds/build-info.js} +0 -0
- /package/dist/{tdd/services/result-service.js → domains/comparisons/comparison-results.js} +0 -0
- /package/dist/{init/core.js → domains/config/config-plan.js} +0 -0
- /package/dist/{utils/config-helpers.js → domains/config/config.js} +0 -0
- /package/dist/{utils/visual-context-normalizers.js → domains/context/context.normalizers.js} +0 -0
- /package/dist/{context → domains/context}/provider-resolver.js +0 -0
- /package/dist/{utils/context.js → domains/diagnostics/environment-context.js} +0 -0
- /package/dist/{utils/report-data.js → domains/reports/report.normalizers.js} +0 -0
- /package/dist/{utils/image-input-detector.js → domains/screenshots/image-input.js} +0 -0
- /package/dist/{tdd/core/signature.js → domains/screenshots/screenshot-identity.js} +0 -0
- /package/dist/{utils → domains/screenshots}/screenshot-options.js +0 -0
- /package/dist/{init/prompts.js → domains/setup/setup-prompts.js} +0 -0
- /package/dist/{tdd → domains/tdd}/runtime-context.js +0 -0
- /package/dist/{tdd → domains/tdd}/server-registry.js +0 -0
- /package/dist/{commands/tdd-daemon-process.js → domains/tdd/tdd-daemon-process.commands.js} +0 -0
- /package/dist/{utils → domains/updates}/update-check.js +0 -0
- /package/dist/{types/index.d.ts → index.d.ts} +0 -0
- /package/dist/{utils → shared}/api-url.js +0 -0
- /package/dist/{utils → shared}/async-utils.js +0 -0
- /package/dist/{utils → shared}/browser.js +0 -0
- /package/dist/{utils → shared}/ci-env.js +0 -0
- /package/dist/{utils → shared}/colors.js +0 -0
- /package/dist/{utils → shared}/fetch-utils.js +0 -0
- /package/dist/{utils → shared}/git.js +0 -0
- /package/dist/{utils → shared}/patterns.js +0 -0
- /package/dist/{utils → shared}/secret-store.js +0 -0
- /package/dist/{errors → shared}/vizzly-error.js +0 -0
package/dist/types/sdk.d.ts
DELETED
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Vizzly SDK Type Definitions
|
|
3
|
-
* Full SDK for custom integrations
|
|
4
|
-
* @module @vizzly-testing/cli/sdk
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { EventEmitter } from 'node:events';
|
|
8
|
-
|
|
9
|
-
// Re-export common types
|
|
10
|
-
export {
|
|
11
|
-
BaselineData,
|
|
12
|
-
ComparisonResult,
|
|
13
|
-
OutputUtils,
|
|
14
|
-
ScreenshotOptions,
|
|
15
|
-
TddResults,
|
|
16
|
-
TddService,
|
|
17
|
-
Uploader,
|
|
18
|
-
UploadOptions,
|
|
19
|
-
UploadResult,
|
|
20
|
-
VizzlyConfig,
|
|
21
|
-
} from './index';
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* VizzlySDK class - Full SDK for custom integrations
|
|
25
|
-
*
|
|
26
|
-
* @example
|
|
27
|
-
* import { createVizzly } from '@vizzly-testing/cli/sdk';
|
|
28
|
-
*
|
|
29
|
-
* const vizzly = await createVizzly({
|
|
30
|
-
* apiKey: process.env.VIZZLY_TOKEN,
|
|
31
|
-
* server: { port: 3003 }
|
|
32
|
-
* });
|
|
33
|
-
*
|
|
34
|
-
* await vizzly.start();
|
|
35
|
-
* await vizzly.screenshot('test', buffer);
|
|
36
|
-
* await vizzly.upload();
|
|
37
|
-
* await vizzly.stop();
|
|
38
|
-
*/
|
|
39
|
-
export class VizzlySDK extends EventEmitter {
|
|
40
|
-
config: import('./index').VizzlyConfig;
|
|
41
|
-
|
|
42
|
-
constructor(config: import('./index').VizzlyConfig, services: unknown);
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Reload file config and re-apply current in-memory overrides.
|
|
46
|
-
*/
|
|
47
|
-
init(): Promise<import('./index').VizzlyConfig>;
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Merge new config values into the active SDK config.
|
|
51
|
-
*/
|
|
52
|
-
updateConfig(
|
|
53
|
-
newConfig: Partial<import('./index').VizzlyConfig>
|
|
54
|
-
): import('./index').VizzlyConfig;
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Start the Vizzly server
|
|
58
|
-
* @returns Server information including port and URL
|
|
59
|
-
*/
|
|
60
|
-
start(): Promise<{ port: number; url: string }>;
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Stop the Vizzly server
|
|
64
|
-
*/
|
|
65
|
-
stop(): Promise<void>;
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Get current configuration
|
|
69
|
-
*/
|
|
70
|
-
getConfig(): import('./index').VizzlyConfig;
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Capture a screenshot
|
|
74
|
-
* @param name - Screenshot name
|
|
75
|
-
* @param imageBuffer - Image data as a Buffer, or a file path to an image
|
|
76
|
-
* @param options - Screenshot options
|
|
77
|
-
* @throws VizzlyError when server is not running
|
|
78
|
-
* @throws VizzlyError when file path is provided but file doesn't exist
|
|
79
|
-
*/
|
|
80
|
-
screenshot(
|
|
81
|
-
name: string,
|
|
82
|
-
imageBuffer: Buffer | string,
|
|
83
|
-
options?: import('./index').ScreenshotOptions
|
|
84
|
-
): Promise<void>;
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Upload all captured screenshots
|
|
88
|
-
* @param options - Upload options
|
|
89
|
-
* @returns Upload result with build URL and stats
|
|
90
|
-
*/
|
|
91
|
-
upload(
|
|
92
|
-
options?: import('./index').UploadOptions
|
|
93
|
-
): Promise<import('./index').UploadResult>;
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Run local comparison in TDD mode
|
|
97
|
-
* @param name - Screenshot name
|
|
98
|
-
* @param imageBuffer - Current image as a Buffer, or a file path to an image
|
|
99
|
-
* @returns Comparison result
|
|
100
|
-
*/
|
|
101
|
-
compare(
|
|
102
|
-
name: string,
|
|
103
|
-
imageBuffer: Buffer | string
|
|
104
|
-
): Promise<import('./index').ComparisonResult>;
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Create an uploader using the SDK config.
|
|
108
|
-
*/
|
|
109
|
-
createUploader(options?: {
|
|
110
|
-
upload?: import('./index').UploadConfig;
|
|
111
|
-
signal?: AbortSignal;
|
|
112
|
-
batchSize?: number;
|
|
113
|
-
timeout?: number;
|
|
114
|
-
}): import('./index').Uploader;
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Create a local TDD service using the SDK config.
|
|
118
|
-
*/
|
|
119
|
-
createTDDService(options?: {
|
|
120
|
-
workingDir?: string;
|
|
121
|
-
setBaseline?: boolean;
|
|
122
|
-
authService?: unknown;
|
|
123
|
-
}): import('./index').TddService;
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Start a local TDD service.
|
|
127
|
-
*/
|
|
128
|
-
startTDD(options?: {
|
|
129
|
-
workingDir?: string;
|
|
130
|
-
setBaseline?: boolean;
|
|
131
|
-
authService?: unknown;
|
|
132
|
-
}): Promise<unknown>;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Create a new Vizzly SDK instance
|
|
137
|
-
*
|
|
138
|
-
* @param config - Configuration options
|
|
139
|
-
* @param options - Additional options
|
|
140
|
-
* @returns Configured Vizzly SDK instance
|
|
141
|
-
*
|
|
142
|
-
* @example
|
|
143
|
-
* const vizzly = await createVizzly({
|
|
144
|
-
* apiKey: process.env.VIZZLY_TOKEN,
|
|
145
|
-
* apiUrl: 'https://app.vizzly.dev',
|
|
146
|
-
* server: { port: 3003 }
|
|
147
|
-
* });
|
|
148
|
-
*/
|
|
149
|
-
export function createVizzly(
|
|
150
|
-
config?: import('./index').VizzlyConfig,
|
|
151
|
-
options?: { verbose?: boolean }
|
|
152
|
-
): Promise<VizzlySDK>;
|
|
153
|
-
|
|
154
|
-
/** Load configuration from file and environment */
|
|
155
|
-
export function loadConfig(options?: {
|
|
156
|
-
cwd?: string;
|
|
157
|
-
}): Promise<import('./index').VizzlyConfig>;
|
|
158
|
-
|
|
159
|
-
/** Output utilities */
|
|
160
|
-
export const output: import('./index').OutputUtils;
|
|
161
|
-
|
|
162
|
-
/** Create an uploader instance */
|
|
163
|
-
export function createUploader(
|
|
164
|
-
config?: {
|
|
165
|
-
apiKey?: string;
|
|
166
|
-
apiUrl?: string;
|
|
167
|
-
userAgent?: string;
|
|
168
|
-
command?: string;
|
|
169
|
-
upload?: import('./index').UploadConfig;
|
|
170
|
-
},
|
|
171
|
-
options?: {
|
|
172
|
-
signal?: AbortSignal;
|
|
173
|
-
batchSize?: number;
|
|
174
|
-
timeout?: number;
|
|
175
|
-
}
|
|
176
|
-
): import('./index').Uploader;
|
|
177
|
-
|
|
178
|
-
/** Create a TDD service instance */
|
|
179
|
-
export function createTDDService(
|
|
180
|
-
config: import('./index').VizzlyConfig,
|
|
181
|
-
options?: {
|
|
182
|
-
workingDir?: string;
|
|
183
|
-
setBaseline?: boolean;
|
|
184
|
-
authService?: unknown;
|
|
185
|
-
}
|
|
186
|
-
): import('./index').TddService;
|
package/dist/uploader/core.js
DELETED
|
@@ -1,432 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Uploader Core - Pure functions for upload logic
|
|
3
|
-
*
|
|
4
|
-
* No I/O, no side effects - just data transformations.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import crypto from 'node:crypto';
|
|
8
|
-
import { basename } from 'node:path';
|
|
9
|
-
|
|
10
|
-
// ============================================================================
|
|
11
|
-
// Constants
|
|
12
|
-
// ============================================================================
|
|
13
|
-
|
|
14
|
-
export const DEFAULT_BATCH_SIZE = 50;
|
|
15
|
-
export const DEFAULT_SHA_CHECK_BATCH_SIZE = 100;
|
|
16
|
-
export const DEFAULT_TIMEOUT = 30000; // 30 seconds
|
|
17
|
-
export const DEFAULT_BUILD_POLL_INTERVAL = 1000; // 1 second
|
|
18
|
-
|
|
19
|
-
// ============================================================================
|
|
20
|
-
// Validation
|
|
21
|
-
// ============================================================================
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Validate API key is present
|
|
25
|
-
* @param {string|undefined} apiKey - API key to validate
|
|
26
|
-
* @returns {{ valid: boolean, error: string|null }}
|
|
27
|
-
*/
|
|
28
|
-
export function validateApiKey(apiKey) {
|
|
29
|
-
if (!apiKey) {
|
|
30
|
-
return {
|
|
31
|
-
valid: false,
|
|
32
|
-
error: 'API key is required'
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
return {
|
|
36
|
-
valid: true,
|
|
37
|
-
error: null
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Validate screenshots directory path
|
|
43
|
-
* @param {string|undefined} screenshotsDir - Directory path
|
|
44
|
-
* @returns {{ valid: boolean, error: string|null }}
|
|
45
|
-
*/
|
|
46
|
-
export function validateScreenshotsDir(screenshotsDir) {
|
|
47
|
-
if (!screenshotsDir) {
|
|
48
|
-
return {
|
|
49
|
-
valid: false,
|
|
50
|
-
error: 'Screenshots directory is required'
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
return {
|
|
54
|
-
valid: true,
|
|
55
|
-
error: null
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Validate directory stats
|
|
61
|
-
* @param {Object} stats - fs.stat result
|
|
62
|
-
* @param {string} path - Directory path for error message
|
|
63
|
-
* @returns {{ valid: boolean, error: string|null }}
|
|
64
|
-
*/
|
|
65
|
-
export function validateDirectoryStats(stats, path) {
|
|
66
|
-
if (!stats.isDirectory()) {
|
|
67
|
-
return {
|
|
68
|
-
valid: false,
|
|
69
|
-
error: `${path} is not a directory`
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
return {
|
|
73
|
-
valid: true,
|
|
74
|
-
error: null
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Validate files were found
|
|
80
|
-
* @param {Array} files - Array of file paths
|
|
81
|
-
* @param {string} directory - Directory that was searched
|
|
82
|
-
* @returns {{ valid: boolean, error: string|null, context?: Object }}
|
|
83
|
-
*/
|
|
84
|
-
export function validateFilesFound(files, directory) {
|
|
85
|
-
if (!files || files.length === 0) {
|
|
86
|
-
return {
|
|
87
|
-
valid: false,
|
|
88
|
-
error: 'No screenshot files found',
|
|
89
|
-
context: {
|
|
90
|
-
directory,
|
|
91
|
-
pattern: '**/*.png'
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
return {
|
|
96
|
-
valid: true,
|
|
97
|
-
error: null
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// ============================================================================
|
|
102
|
-
// Browser Extraction
|
|
103
|
-
// ============================================================================
|
|
104
|
-
|
|
105
|
-
const KNOWN_BROWSERS = ['chrome', 'firefox', 'safari', 'edge', 'webkit'];
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Extract browser name from filename
|
|
109
|
-
* @param {string} filename - The screenshot filename
|
|
110
|
-
* @returns {string|null} Browser name or null if not found
|
|
111
|
-
*/
|
|
112
|
-
export function extractBrowserFromFilename(filename) {
|
|
113
|
-
let lowerFilename = filename.toLowerCase();
|
|
114
|
-
for (let browser of KNOWN_BROWSERS) {
|
|
115
|
-
if (lowerFilename.includes(browser)) {
|
|
116
|
-
return browser;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
return null;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// ============================================================================
|
|
123
|
-
// Build Info Construction
|
|
124
|
-
// ============================================================================
|
|
125
|
-
|
|
126
|
-
function buildUploadMetadata(options) {
|
|
127
|
-
let metadata = {
|
|
128
|
-
...(options.metadata || {})
|
|
129
|
-
};
|
|
130
|
-
let comparison = {
|
|
131
|
-
...(metadata.comparison || {})
|
|
132
|
-
};
|
|
133
|
-
if (options.threshold !== undefined) {
|
|
134
|
-
comparison.threshold = options.threshold;
|
|
135
|
-
}
|
|
136
|
-
if (options.minClusterSize !== undefined) {
|
|
137
|
-
comparison.minClusterSize = options.minClusterSize;
|
|
138
|
-
}
|
|
139
|
-
if (Object.keys(comparison).length > 0) {
|
|
140
|
-
metadata.comparison = comparison;
|
|
141
|
-
}
|
|
142
|
-
return Object.keys(metadata).length > 0 ? metadata : undefined;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Build API build info payload
|
|
147
|
-
* @param {Object} options - Upload options
|
|
148
|
-
* @param {string} [defaultBranch] - Default branch to use
|
|
149
|
-
* @returns {Object} Build info payload
|
|
150
|
-
*/
|
|
151
|
-
export function buildBuildInfo(options, defaultBranch = 'main') {
|
|
152
|
-
let buildInfo = {
|
|
153
|
-
name: options.buildName || `Upload ${new Date().toISOString()}`,
|
|
154
|
-
branch: options.branch || defaultBranch || 'main',
|
|
155
|
-
commit_sha: options.commit,
|
|
156
|
-
commit_message: options.message,
|
|
157
|
-
commit_author_name: options.commitAuthorName,
|
|
158
|
-
commit_author_email: options.commitAuthorEmail,
|
|
159
|
-
environment: options.environment || 'production',
|
|
160
|
-
threshold: options.threshold,
|
|
161
|
-
github_pull_request_number: options.pullRequestNumber,
|
|
162
|
-
parallel_id: options.parallelId
|
|
163
|
-
};
|
|
164
|
-
let metadata = buildUploadMetadata(options);
|
|
165
|
-
if (metadata) {
|
|
166
|
-
buildInfo.metadata = metadata;
|
|
167
|
-
}
|
|
168
|
-
return buildInfo;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// ============================================================================
|
|
172
|
-
// File Metadata Processing
|
|
173
|
-
// ============================================================================
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Compute SHA256 hash of a buffer
|
|
177
|
-
* @param {Buffer} buffer - File buffer
|
|
178
|
-
* @returns {string} Hex-encoded SHA256 hash
|
|
179
|
-
*/
|
|
180
|
-
export function computeSha256(buffer) {
|
|
181
|
-
return crypto.createHash('sha256').update(buffer).digest('hex');
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Build file metadata object
|
|
186
|
-
* @param {string} filePath - Path to file
|
|
187
|
-
* @param {Buffer} buffer - File contents
|
|
188
|
-
* @returns {Object} File metadata
|
|
189
|
-
*/
|
|
190
|
-
export function buildFileMetadata(filePath, buffer) {
|
|
191
|
-
return {
|
|
192
|
-
path: filePath,
|
|
193
|
-
filename: basename(filePath),
|
|
194
|
-
buffer,
|
|
195
|
-
sha256: computeSha256(buffer)
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Convert file metadata to screenshot check format
|
|
201
|
-
* @param {Object} file - File metadata
|
|
202
|
-
* @returns {Object} Screenshot format for SHA check
|
|
203
|
-
*/
|
|
204
|
-
export function fileToScreenshotFormat(file) {
|
|
205
|
-
let browser = extractBrowserFromFilename(file.filename);
|
|
206
|
-
return {
|
|
207
|
-
sha256: file.sha256,
|
|
208
|
-
name: file.filename.replace(/\.png$/, ''),
|
|
209
|
-
filename: file.filename,
|
|
210
|
-
properties: browser ? {
|
|
211
|
-
browser
|
|
212
|
-
} : {}
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* Partition files into those that need upload and those that exist
|
|
218
|
-
* @param {Array} fileMetadata - All file metadata
|
|
219
|
-
* @param {Set} existingShas - Set of SHAs that already exist
|
|
220
|
-
* @returns {{ toUpload: Array, existing: Array }}
|
|
221
|
-
*/
|
|
222
|
-
export function partitionFilesByExistence(fileMetadata, existingShas) {
|
|
223
|
-
return {
|
|
224
|
-
toUpload: fileMetadata.filter(f => !existingShas.has(f.sha256)),
|
|
225
|
-
existing: fileMetadata.filter(f => existingShas.has(f.sha256))
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// ============================================================================
|
|
230
|
-
// Progress Reporting
|
|
231
|
-
// ============================================================================
|
|
232
|
-
|
|
233
|
-
/**
|
|
234
|
-
* Build scanning phase progress
|
|
235
|
-
* @param {number} total - Total files found
|
|
236
|
-
* @returns {Object} Progress object
|
|
237
|
-
*/
|
|
238
|
-
export function buildScanningProgress(total) {
|
|
239
|
-
return {
|
|
240
|
-
phase: 'scanning',
|
|
241
|
-
message: `Found ${total} screenshots`,
|
|
242
|
-
total
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Build processing phase progress
|
|
248
|
-
* @param {number} current - Current file number
|
|
249
|
-
* @param {number} total - Total files
|
|
250
|
-
* @returns {Object} Progress object
|
|
251
|
-
*/
|
|
252
|
-
export function buildProcessingProgress(current, total) {
|
|
253
|
-
return {
|
|
254
|
-
phase: 'processing',
|
|
255
|
-
message: 'Processing files',
|
|
256
|
-
current,
|
|
257
|
-
total
|
|
258
|
-
};
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
/**
|
|
262
|
-
* Build deduplication phase progress
|
|
263
|
-
* @param {number} toUpload - Files to upload
|
|
264
|
-
* @param {number} existing - Existing files
|
|
265
|
-
* @param {number} total - Total files
|
|
266
|
-
* @returns {Object} Progress object
|
|
267
|
-
*/
|
|
268
|
-
export function buildDeduplicationProgress(toUpload, existing, total) {
|
|
269
|
-
return {
|
|
270
|
-
phase: 'deduplication',
|
|
271
|
-
message: `Checking for duplicates (${toUpload} to upload, ${existing} existing)`,
|
|
272
|
-
toUpload,
|
|
273
|
-
existing,
|
|
274
|
-
total
|
|
275
|
-
};
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
/**
|
|
279
|
-
* Build uploading phase progress
|
|
280
|
-
* @param {number} current - Current upload number
|
|
281
|
-
* @param {number} total - Total to upload
|
|
282
|
-
* @returns {Object} Progress object
|
|
283
|
-
*/
|
|
284
|
-
export function buildUploadingProgress(current, total) {
|
|
285
|
-
return {
|
|
286
|
-
phase: 'uploading',
|
|
287
|
-
message: 'Uploading screenshots',
|
|
288
|
-
current,
|
|
289
|
-
total
|
|
290
|
-
};
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
/**
|
|
294
|
-
* Build completed phase progress
|
|
295
|
-
* @param {string} buildId - Build ID
|
|
296
|
-
* @param {string|null} url - Build URL
|
|
297
|
-
* @returns {Object} Progress object
|
|
298
|
-
*/
|
|
299
|
-
export function buildCompletedProgress(buildId, url) {
|
|
300
|
-
return {
|
|
301
|
-
phase: 'completed',
|
|
302
|
-
message: 'Upload completed',
|
|
303
|
-
buildId,
|
|
304
|
-
url
|
|
305
|
-
};
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
// ============================================================================
|
|
309
|
-
// Result Building
|
|
310
|
-
// ============================================================================
|
|
311
|
-
|
|
312
|
-
/**
|
|
313
|
-
* Build successful upload result
|
|
314
|
-
* @param {Object} options - Options
|
|
315
|
-
* @param {string} options.buildId - Build ID
|
|
316
|
-
* @param {string|null} options.url - Build URL
|
|
317
|
-
* @param {number} options.total - Total files
|
|
318
|
-
* @param {number} options.uploaded - Files uploaded
|
|
319
|
-
* @param {number} options.skipped - Files skipped
|
|
320
|
-
* @returns {Object} Upload result
|
|
321
|
-
*/
|
|
322
|
-
export function buildUploadResult({
|
|
323
|
-
buildId,
|
|
324
|
-
url,
|
|
325
|
-
total,
|
|
326
|
-
uploaded,
|
|
327
|
-
skipped
|
|
328
|
-
}) {
|
|
329
|
-
return {
|
|
330
|
-
success: true,
|
|
331
|
-
buildId,
|
|
332
|
-
url,
|
|
333
|
-
stats: {
|
|
334
|
-
total,
|
|
335
|
-
uploaded,
|
|
336
|
-
skipped
|
|
337
|
-
}
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
/**
|
|
342
|
-
* Build wait result from build response
|
|
343
|
-
* @param {Object} build - Build object from API
|
|
344
|
-
* @returns {Object} Wait result
|
|
345
|
-
*/
|
|
346
|
-
export function buildWaitResult(build) {
|
|
347
|
-
let totalComparisons = build.total_comparisons;
|
|
348
|
-
let passedComparisons = build.identical_comparisons;
|
|
349
|
-
let failedComparisons = build.changed_comparisons;
|
|
350
|
-
let newComparisons = build.new_comparisons;
|
|
351
|
-
let identicalComparisons = build.identical_comparisons;
|
|
352
|
-
let hasComparisonCounts = build.total_comparisons !== undefined || build.new_comparisons !== undefined || build.changed_comparisons !== undefined || build.identical_comparisons !== undefined;
|
|
353
|
-
let result = {
|
|
354
|
-
status: build.status,
|
|
355
|
-
build,
|
|
356
|
-
passedComparisons,
|
|
357
|
-
failedComparisons,
|
|
358
|
-
newComparisons,
|
|
359
|
-
identicalComparisons,
|
|
360
|
-
visual_review: build.visual_review || null,
|
|
361
|
-
totalComparisons
|
|
362
|
-
};
|
|
363
|
-
if (hasComparisonCounts) {
|
|
364
|
-
result.comparisons = totalComparisons;
|
|
365
|
-
}
|
|
366
|
-
if (build.url) {
|
|
367
|
-
result.url = build.url;
|
|
368
|
-
}
|
|
369
|
-
return result;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// ============================================================================
|
|
373
|
-
// Configuration
|
|
374
|
-
// ============================================================================
|
|
375
|
-
|
|
376
|
-
/**
|
|
377
|
-
* Resolve batch size from options and config
|
|
378
|
-
* @param {Object} options - Runtime options
|
|
379
|
-
* @param {Object} uploadConfig - Upload configuration
|
|
380
|
-
* @returns {number} Resolved batch size
|
|
381
|
-
*/
|
|
382
|
-
export function resolveBatchSize(options, uploadConfig) {
|
|
383
|
-
return Number(options?.batchSize ?? uploadConfig?.batchSize ?? DEFAULT_BATCH_SIZE);
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
/**
|
|
387
|
-
* Resolve timeout from options and config
|
|
388
|
-
* @param {Object} options - Runtime options
|
|
389
|
-
* @param {Object} uploadConfig - Upload configuration
|
|
390
|
-
* @returns {number} Resolved timeout in ms
|
|
391
|
-
*/
|
|
392
|
-
export function resolveTimeout(options, uploadConfig) {
|
|
393
|
-
return Number(options?.timeout ?? uploadConfig?.timeout ?? DEFAULT_TIMEOUT);
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
/**
|
|
397
|
-
* Check if timeout has been exceeded
|
|
398
|
-
* @param {number} startTime - Start timestamp
|
|
399
|
-
* @param {number} timeout - Timeout in ms
|
|
400
|
-
* @returns {boolean} True if timed out
|
|
401
|
-
*/
|
|
402
|
-
export function isTimedOut(startTime, timeout, now = Date.now()) {
|
|
403
|
-
return now - startTime >= timeout;
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
/**
|
|
407
|
-
* Get elapsed time since start
|
|
408
|
-
* @param {number} startTime - Start timestamp
|
|
409
|
-
* @returns {number} Elapsed time in ms
|
|
410
|
-
*/
|
|
411
|
-
export function getElapsedTime(startTime, now = Date.now()) {
|
|
412
|
-
return now - startTime;
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
/**
|
|
416
|
-
* Build glob pattern for screenshots
|
|
417
|
-
* @param {string} directory - Base directory
|
|
418
|
-
* @returns {string} Glob pattern
|
|
419
|
-
*/
|
|
420
|
-
export function buildScreenshotPattern(directory) {
|
|
421
|
-
return `${directory}/**/*.png`;
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
/**
|
|
425
|
-
* Extract status code from error message
|
|
426
|
-
* @param {string} errorMessage - Error message
|
|
427
|
-
* @returns {string} Status code or 'unknown'
|
|
428
|
-
*/
|
|
429
|
-
export function extractStatusCodeFromError(errorMessage) {
|
|
430
|
-
let match = String(errorMessage || '').match(/API request failed: (\d+)/);
|
|
431
|
-
return match ? match[1] : 'unknown';
|
|
432
|
-
}
|
package/dist/uploader/index.js
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Uploader Module
|
|
3
|
-
*
|
|
4
|
-
* Exports pure functions (core), I/O operations, and the public uploader
|
|
5
|
-
* factory for screenshot uploading.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { readFile, stat } from 'node:fs/promises';
|
|
9
|
-
import { glob } from 'glob';
|
|
10
|
-
import { checkShas, createApiClient, createBuild } from '../api/index.js';
|
|
11
|
-
import { TimeoutError, UploadError, ValidationError } from '../errors/vizzly-error.js';
|
|
12
|
-
import { getDefaultBranch } from '../utils/git.js';
|
|
13
|
-
import * as output from '../utils/output.js';
|
|
14
|
-
import { resolveBatchSize, resolveTimeout } from './core.js';
|
|
15
|
-
import { upload as uploadOperation, waitForBuild as waitForBuildOperation } from './operations.js';
|
|
16
|
-
export function createUploader({
|
|
17
|
-
apiKey,
|
|
18
|
-
apiUrl,
|
|
19
|
-
userAgent,
|
|
20
|
-
command,
|
|
21
|
-
upload: uploadConfig = {}
|
|
22
|
-
} = {}, options = {}) {
|
|
23
|
-
let signal = options.signal || new AbortController().signal;
|
|
24
|
-
let client = createApiClient({
|
|
25
|
-
baseUrl: apiUrl,
|
|
26
|
-
token: apiKey,
|
|
27
|
-
command: command || 'upload',
|
|
28
|
-
sdkUserAgent: userAgent,
|
|
29
|
-
allowNoToken: true
|
|
30
|
-
});
|
|
31
|
-
let batchSize = resolveBatchSize(options, uploadConfig);
|
|
32
|
-
let timeout = resolveTimeout(options, uploadConfig);
|
|
33
|
-
let deps = options.deps || {
|
|
34
|
-
client,
|
|
35
|
-
createBuild,
|
|
36
|
-
getDefaultBranch,
|
|
37
|
-
glob,
|
|
38
|
-
readFile,
|
|
39
|
-
stat,
|
|
40
|
-
checkShas,
|
|
41
|
-
createError: (message, code, context) => {
|
|
42
|
-
let error = new UploadError(message, context);
|
|
43
|
-
error.code = code;
|
|
44
|
-
return error;
|
|
45
|
-
},
|
|
46
|
-
createValidationError: (message, context) => new ValidationError(message, context),
|
|
47
|
-
createUploadError: (message, context) => new UploadError(message, context),
|
|
48
|
-
createTimeoutError: (message, context) => new TimeoutError(message, context),
|
|
49
|
-
output
|
|
50
|
-
};
|
|
51
|
-
async function upload(uploadOptions) {
|
|
52
|
-
return uploadOperation({
|
|
53
|
-
uploadOptions,
|
|
54
|
-
config: {
|
|
55
|
-
apiKey,
|
|
56
|
-
apiUrl
|
|
57
|
-
},
|
|
58
|
-
signal,
|
|
59
|
-
batchSize,
|
|
60
|
-
deps: {
|
|
61
|
-
...deps,
|
|
62
|
-
client: deps.client || client
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
async function waitForBuild(buildId, waitTimeout = timeout) {
|
|
67
|
-
return waitForBuildOperation({
|
|
68
|
-
buildId,
|
|
69
|
-
timeout: waitTimeout,
|
|
70
|
-
signal,
|
|
71
|
-
client: deps.client || client,
|
|
72
|
-
deps: {
|
|
73
|
-
createError: deps.createError,
|
|
74
|
-
createTimeoutError: deps.createTimeoutError
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
return {
|
|
79
|
-
upload,
|
|
80
|
-
waitForBuild
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Core - pure functions
|
|
85
|
-
export { buildBuildInfo, buildCompletedProgress, buildDeduplicationProgress, buildFileMetadata, buildProcessingProgress, buildScanningProgress, buildScreenshotPattern, buildUploadingProgress, buildUploadResult, buildWaitResult, computeSha256, DEFAULT_BATCH_SIZE, DEFAULT_BUILD_POLL_INTERVAL, DEFAULT_SHA_CHECK_BATCH_SIZE, DEFAULT_TIMEOUT, extractBrowserFromFilename, extractStatusCodeFromError, fileToScreenshotFormat, getElapsedTime, isTimedOut, partitionFilesByExistence, resolveBatchSize, resolveTimeout, validateApiKey, validateDirectoryStats, validateFilesFound, validateScreenshotsDir } from './core.js';
|
|
86
|
-
|
|
87
|
-
// Operations - I/O with dependency injection
|
|
88
|
-
export { checkExistingFiles, findScreenshots, processFiles, upload, uploadFiles, waitForBuild } from './operations.js';
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|