@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.
Files changed (195) hide show
  1. package/README.md +8 -0
  2. package/bin/vizzly.js +1 -1
  3. package/dist/{cli.js → adapters/cli/cli.js} +41 -35
  4. package/dist/adapters/cli/setup.js +34 -0
  5. package/dist/{client → adapters/client}/index.js +6 -7
  6. package/dist/adapters/http/cloud-proxy.js +29 -0
  7. package/dist/{server → adapters/http}/http-server.js +12 -13
  8. package/dist/{server-manager/operations.js → adapters/http/server-lifecycle.js} +10 -13
  9. package/dist/{server-manager/index.js → adapters/http/server-manager.js} +23 -27
  10. package/dist/{plugin-api.js → adapters/plugins/plugin-api.js} +1 -1
  11. package/dist/{plugin-loader.js → adapters/plugins/plugin-loader.js} +1 -1
  12. package/dist/{services/index.js → adapters/plugins/services.js} +4 -9
  13. package/dist/adapters/sdk/index.d.ts +89 -0
  14. package/dist/{sdk → adapters/sdk}/index.js +22 -19
  15. package/dist/{commands/api.js → domains/api/api.commands.js} +3 -3
  16. package/dist/{auth/client.js → domains/auth/auth-client.js} +4 -3
  17. package/dist/domains/auth/auth-errors.js +50 -0
  18. package/dist/domains/auth/auth-headers.js +41 -0
  19. package/dist/domains/auth/auth.normalizers.js +50 -0
  20. package/dist/{server/routers/auth.js → domains/auth/auth.routes.js} +9 -9
  21. package/dist/domains/auth/auth.rules.js +19 -0
  22. package/dist/domains/auth/auth.serializers.js +32 -0
  23. package/dist/{auth/operations.js → domains/auth/auth.service.js} +115 -17
  24. package/dist/domains/auth/auth.validations.js +21 -0
  25. package/dist/{api/client.js → domains/auth/cloud-client.js} +11 -18
  26. package/dist/{commands/login.js → domains/auth/login.commands.js} +11 -8
  27. package/dist/{commands/logout.js → domains/auth/logout.commands.js} +6 -4
  28. package/dist/domains/auth/token-store.js +81 -0
  29. package/dist/{commands/whoami.js → domains/auth/whoami.commands.js} +6 -3
  30. package/dist/domains/baselines/baseline-download.js +192 -0
  31. package/dist/domains/baselines/baseline-write.js +22 -0
  32. package/dist/{server/routers/baseline.js → domains/baselines/baseline.routes.js} +3 -3
  33. package/dist/{tdd/services/baseline-manager.js → domains/baselines/baseline.service.js} +1 -39
  34. package/dist/{commands/baselines.js → domains/baselines/baselines.commands.js} +3 -3
  35. package/dist/domains/baselines/cloud-baselines.js +9 -0
  36. package/dist/domains/baselines/cloud-baselines.routes.js +42 -0
  37. package/dist/domains/builds/build.normalizers.js +35 -0
  38. package/dist/domains/builds/build.serializers.js +164 -0
  39. package/dist/domains/builds/build.service.js +119 -0
  40. package/dist/domains/builds/build.validations.js +39 -0
  41. package/dist/{commands/builds.js → domains/builds/builds.commands.js} +6 -74
  42. package/dist/domains/builds/cloud-builds.routes.js +31 -0
  43. package/dist/{commands/finalize.js → domains/builds/finalize.commands.js} +5 -17
  44. package/dist/{commands/status.js → domains/builds/status.commands.js} +9 -120
  45. package/dist/domains/comparisons/cloud-comparisons.js +43 -0
  46. package/dist/{tdd/services/comparison-service.js → domains/comparisons/comparison.service.js} +1 -1
  47. package/dist/{commands/comparisons.js → domains/comparisons/comparisons.commands.js} +7 -5
  48. package/dist/domains/config/config-defaults.js +27 -0
  49. package/dist/{utils → domains/config}/config-discovery.js +1 -9
  50. package/dist/{utils → domains/config}/config-loader.js +10 -9
  51. package/dist/{commands/config-cmd.js → domains/config/config.commands.js} +4 -4
  52. package/dist/{types → domains/config}/config.d.ts +3 -3
  53. package/dist/domains/config/config.normalizers.js +126 -0
  54. package/dist/{server/routers/config.js → domains/config/config.routes.js} +13 -13
  55. package/dist/domains/config/config.rules.js +47 -0
  56. package/dist/domains/config/config.serializers.js +202 -0
  57. package/dist/domains/config/config.service.js +625 -0
  58. package/dist/{utils/config-schema.js → domains/config/config.validations.js} +9 -9
  59. package/dist/{utils/environment-config.js → domains/config/environment.js} +1 -8
  60. package/dist/domains/context/compact-context.validations.js +60 -0
  61. package/dist/domains/context/context-presentation.js +368 -0
  62. package/dist/domains/context/context.commands.js +385 -0
  63. package/dist/domains/context/context.serializers.js +157 -0
  64. package/dist/domains/context/context.service.js +76 -0
  65. package/dist/domains/context/context.validations.js +100 -0
  66. package/dist/{context → domains/context}/local-workspace-provider.js +1 -1
  67. package/dist/{commands/doctor.js → domains/diagnostics/doctor.commands.js} +6 -5
  68. package/dist/{server/routers/health.js → domains/diagnostics/health.routes.js} +11 -20
  69. package/dist/{commands/preview.js → domains/previews/preview.commands.js} +9 -7
  70. package/dist/domains/previews/preview.service.js +37 -0
  71. package/dist/domains/projects/cloud-projects.routes.js +28 -0
  72. package/dist/{commands/orgs.js → domains/projects/orgs.commands.js} +6 -8
  73. package/dist/{utils → domains/projects}/project-binding.js +3 -3
  74. package/dist/domains/projects/project-errors.js +61 -0
  75. package/dist/{utils → domains/projects}/project-link-store.js +2 -2
  76. package/dist/domains/projects/project-requests.js +61 -0
  77. package/dist/{commands/project.js → domains/projects/project.commands.js} +9 -41
  78. package/dist/domains/projects/project.normalizers.js +69 -0
  79. package/dist/{project/operations.js → domains/projects/project.service.js} +89 -16
  80. package/dist/domains/projects/project.validations.js +31 -0
  81. package/dist/{commands/projects.js → domains/projects/projects.commands.js} +6 -8
  82. package/dist/{server/routers/projects.js → domains/projects/projects.routes.js} +5 -5
  83. package/dist/domains/reports/dashboard.routes.js +96 -0
  84. package/dist/{server/routers/events.js → domains/reports/events.routes.js} +14 -36
  85. package/dist/domains/reports/report-assets.routes.js +81 -0
  86. package/dist/domains/reports/report-state.js +51 -0
  87. package/dist/domains/reports/report-store.js +85 -0
  88. package/dist/domains/reports/report.serializers.js +99 -0
  89. package/dist/{services/static-report-generator.js → domains/reports/report.service.js} +11 -33
  90. package/dist/{commands/review.js → domains/review/review.commands.js} +4 -4
  91. package/dist/domains/runs/run-environment.js +69 -0
  92. package/dist/{services/test-runner.js → domains/runs/run-events.js} +11 -9
  93. package/dist/{commands/run.js → domains/runs/run.commands.js} +16 -13
  94. package/dist/domains/runs/run.normalizers.js +8 -0
  95. package/dist/domains/runs/run.rules.js +56 -0
  96. package/dist/domains/runs/run.serializers.js +101 -0
  97. package/dist/{test-runner/operations.js → domains/runs/run.service.js} +35 -7
  98. package/dist/domains/runs/run.validations.js +17 -0
  99. package/dist/{utils/session.js → domains/runs/session-store.js} +3 -2
  100. package/dist/{server/handlers/api-handler.js → domains/screenshots/cloud-handler.js} +4 -4
  101. package/dist/domains/screenshots/cloud-screenshots.js +109 -0
  102. package/dist/{utils/file-helpers.js → domains/screenshots/image-files.js} +1 -1
  103. package/dist/domains/screenshots/screenshot-hash.js +53 -0
  104. package/dist/domains/screenshots/screenshot-server-options.js +28 -0
  105. package/dist/{screenshot-server/operations.js → domains/screenshots/screenshot-server.js} +14 -1
  106. package/dist/domains/screenshots/screenshot.normalizers.js +40 -0
  107. package/dist/{server/routers/screenshot.js → domains/screenshots/screenshot.routes.js} +4 -4
  108. package/dist/domains/screenshots/screenshot.serializers.js +146 -0
  109. package/dist/{utils/security.js → domains/screenshots/screenshot.validations.js} +20 -70
  110. package/dist/{init/agents.js → domains/setup/agent-setup.js} +4 -5
  111. package/dist/{commands/init.js → domains/setup/init.commands.js} +10 -41
  112. package/dist/{server/handlers/tdd-handler.js → domains/tdd/screenshot-handler.js} +46 -281
  113. package/dist/{commands/tdd-daemon.js → domains/tdd/tdd-daemon.commands.js} +6 -6
  114. package/dist/{commands/tdd-screenshots.js → domains/tdd/tdd-screenshots.commands.js} +5 -5
  115. package/dist/{commands/tdd.js → domains/tdd/tdd.commands.js} +16 -15
  116. package/dist/{tdd/tdd-service.js → domains/tdd/tdd.service.js} +81 -405
  117. package/dist/{utils → domains/updates}/cli-update.js +4 -6
  118. package/dist/{utils → domains/updates}/update-notifications.js +7 -7
  119. package/dist/domains/uploads/upload-defaults.js +4 -0
  120. package/dist/domains/uploads/upload-files.js +32 -0
  121. package/dist/domains/uploads/upload-settings.js +21 -0
  122. package/dist/domains/uploads/upload-timing.js +18 -0
  123. package/dist/{commands/upload.js → domains/uploads/upload.commands.js} +11 -9
  124. package/dist/domains/uploads/upload.normalizers.js +60 -0
  125. package/dist/domains/uploads/upload.serializers.js +179 -0
  126. package/dist/{uploader/operations.js → domains/uploads/upload.service.js} +85 -28
  127. package/dist/domains/uploads/upload.validations.js +77 -0
  128. package/dist/index.js +12 -12
  129. package/dist/reporter/reporter-bundle.iife.js +86 -86
  130. package/dist/reporter-ssr/ssr-entry.js +2 -2
  131. package/dist/shared/cloud-protocol.js +171 -0
  132. package/dist/{utils → shared}/file-changes.js +1 -1
  133. package/dist/shared/files.js +9 -0
  134. package/dist/{utils → shared}/global-config.js +7 -78
  135. package/dist/shared/log-level.js +7 -0
  136. package/dist/{utils → shared}/output.js +1 -1
  137. package/dist/{utils → shared}/package-info.js +5 -4
  138. package/dist/shared/paths.js +57 -0
  139. package/package.json +23 -22
  140. package/dist/api/core.js +0 -382
  141. package/dist/api/endpoints.js +0 -421
  142. package/dist/api/index.js +0 -19
  143. package/dist/auth/core.js +0 -237
  144. package/dist/auth/index.js +0 -31
  145. package/dist/commands/context.js +0 -1066
  146. package/dist/config/core.js +0 -439
  147. package/dist/config/operations.js +0 -327
  148. package/dist/project/core.js +0 -211
  149. package/dist/screenshot-server/core.js +0 -161
  150. package/dist/screenshot-server/index.js +0 -11
  151. package/dist/server/routers/assets.js +0 -95
  152. package/dist/server/routers/cloud-proxy.js +0 -146
  153. package/dist/server/routers/dashboard.js +0 -172
  154. package/dist/services/auth-service.js +0 -117
  155. package/dist/services/config-service.js +0 -313
  156. package/dist/services/project-service.js +0 -88
  157. package/dist/test-runner/core.js +0 -293
  158. package/dist/test-runner/index.js +0 -13
  159. package/dist/types/sdk.d.ts +0 -186
  160. package/dist/uploader/core.js +0 -432
  161. package/dist/uploader/index.js +0 -88
  162. /package/dist/{types/client.d.ts → adapters/client/index.d.ts} +0 -0
  163. /package/dist/{server → adapters/http}/middleware/cors.js +0 -0
  164. /package/dist/{server → adapters/http}/middleware/json-parser.js +0 -0
  165. /package/dist/{server → adapters/http}/middleware/response.js +0 -0
  166. /package/dist/{server-manager/core.js → adapters/http/server-options.js} +0 -0
  167. /package/dist/{utils/login-poll-wait.js → domains/auth/login-wait.js} +0 -0
  168. /package/dist/{tdd/metadata → domains/baselines}/baseline-metadata.js +0 -0
  169. /package/dist/{services/build-manager.js → domains/builds/build-info.js} +0 -0
  170. /package/dist/{tdd/services/result-service.js → domains/comparisons/comparison-results.js} +0 -0
  171. /package/dist/{init/core.js → domains/config/config-plan.js} +0 -0
  172. /package/dist/{utils/config-helpers.js → domains/config/config.js} +0 -0
  173. /package/dist/{utils/visual-context-normalizers.js → domains/context/context.normalizers.js} +0 -0
  174. /package/dist/{context → domains/context}/provider-resolver.js +0 -0
  175. /package/dist/{utils/context.js → domains/diagnostics/environment-context.js} +0 -0
  176. /package/dist/{utils/report-data.js → domains/reports/report.normalizers.js} +0 -0
  177. /package/dist/{utils/image-input-detector.js → domains/screenshots/image-input.js} +0 -0
  178. /package/dist/{tdd/core/signature.js → domains/screenshots/screenshot-identity.js} +0 -0
  179. /package/dist/{utils → domains/screenshots}/screenshot-options.js +0 -0
  180. /package/dist/{init/prompts.js → domains/setup/setup-prompts.js} +0 -0
  181. /package/dist/{tdd → domains/tdd}/runtime-context.js +0 -0
  182. /package/dist/{tdd → domains/tdd}/server-registry.js +0 -0
  183. /package/dist/{commands/tdd-daemon-process.js → domains/tdd/tdd-daemon-process.commands.js} +0 -0
  184. /package/dist/{utils → domains/updates}/update-check.js +0 -0
  185. /package/dist/{types/index.d.ts → index.d.ts} +0 -0
  186. /package/dist/{utils → shared}/api-url.js +0 -0
  187. /package/dist/{utils → shared}/async-utils.js +0 -0
  188. /package/dist/{utils → shared}/browser.js +0 -0
  189. /package/dist/{utils → shared}/ci-env.js +0 -0
  190. /package/dist/{utils → shared}/colors.js +0 -0
  191. /package/dist/{utils → shared}/fetch-utils.js +0 -0
  192. /package/dist/{utils → shared}/git.js +0 -0
  193. /package/dist/{utils → shared}/patterns.js +0 -0
  194. /package/dist/{utils → shared}/secret-store.js +0 -0
  195. /package/dist/{errors → shared}/vizzly-error.js +0 -0
@@ -1,327 +0,0 @@
1
- /**
2
- * Config Operations - Configuration operations with dependency injection
3
- *
4
- * Each operation takes its dependencies as parameters:
5
- * - explorer: cosmiconfig explorer for project config
6
- * - globalConfigStore: for reading/writing global config
7
- * - fileWriter: for writing project config files
8
- *
9
- * This makes them trivially testable without mocking modules.
10
- */
11
-
12
- import { join } from 'node:path';
13
- import { VizzlyError } from '../errors/vizzly-error.js';
14
- import { buildGlobalConfigResult, buildMergedConfigResult, buildProjectConfigResult, deepMerge, extractCosmiconfigResult, extractEnvOverrides, getConfigFormat, serializeConfig, validateReadScope, validateWriteScope } from './core.js';
15
-
16
- // ============================================================================
17
- // Read Operations
18
- // ============================================================================
19
-
20
- /**
21
- * Get project-level config from vizzly.config.js or similar
22
- * @param {Object} explorer - Cosmiconfig explorer with search method
23
- * @param {string} projectRoot - Project root directory
24
- * @returns {Promise<{ config: Object, filepath: string|null, isEmpty: boolean }>}
25
- */
26
- export async function getProjectConfig(explorer, projectRoot) {
27
- let result = explorer.search(projectRoot);
28
- let {
29
- config,
30
- filepath
31
- } = extractCosmiconfigResult(result);
32
- return buildProjectConfigResult(config, filepath);
33
- }
34
-
35
- /**
36
- * Get global config from ~/.vizzly/config.json
37
- * @param {Object} globalConfigStore - Store with load and getPath methods
38
- * @returns {Promise<{ config: Object, filepath: string, isEmpty: boolean }>}
39
- */
40
- export async function getGlobalConfig(globalConfigStore) {
41
- let config = await globalConfigStore.load();
42
- let filepath = globalConfigStore.getPath();
43
- return buildGlobalConfigResult(config, filepath);
44
- }
45
-
46
- /**
47
- * Get merged config from all sources with source tracking
48
- * @param {Object} options - Options
49
- * @param {Object} options.explorer - Cosmiconfig explorer
50
- * @param {Object} options.globalConfigStore - Global config store
51
- * @param {string} options.projectRoot - Project root directory
52
- * @param {Object} [options.env] - Environment variables (defaults to process.env)
53
- * @returns {Promise<{ config: Object, sources: Object, projectFilepath: string|null, globalFilepath: string }>}
54
- */
55
- export async function getMergedConfig({
56
- explorer,
57
- globalConfigStore,
58
- projectRoot,
59
- env = process.env
60
- }) {
61
- let projectConfigData = await getProjectConfig(explorer, projectRoot);
62
- let globalConfigData = await getGlobalConfig(globalConfigStore);
63
- let envOverrides = extractEnvOverrides(env);
64
- return buildMergedConfigResult({
65
- projectConfig: projectConfigData.config,
66
- globalConfig: globalConfigData.config,
67
- envOverrides,
68
- projectFilepath: projectConfigData.filepath,
69
- globalFilepath: globalConfigData.filepath
70
- });
71
- }
72
-
73
- /**
74
- * Get configuration based on scope
75
- * @param {Object} options - Options
76
- * @param {string} options.scope - 'project', 'global', or 'merged'
77
- * @param {Object} options.explorer - Cosmiconfig explorer
78
- * @param {Object} options.globalConfigStore - Global config store
79
- * @param {string} options.projectRoot - Project root directory
80
- * @param {Object} [options.env] - Environment variables
81
- * @returns {Promise<Object>} Config result based on scope
82
- */
83
- export async function getConfig({
84
- scope = 'merged',
85
- explorer,
86
- globalConfigStore,
87
- projectRoot,
88
- env
89
- }) {
90
- let validation = validateReadScope(scope);
91
- if (!validation.valid) {
92
- throw validation.error;
93
- }
94
- if (scope === 'project') {
95
- return getProjectConfig(explorer, projectRoot);
96
- }
97
- if (scope === 'global') {
98
- return getGlobalConfig(globalConfigStore);
99
- }
100
- return getMergedConfig({
101
- explorer,
102
- globalConfigStore,
103
- projectRoot,
104
- env
105
- });
106
- }
107
-
108
- // ============================================================================
109
- // Write Operations
110
- // ============================================================================
111
-
112
- /**
113
- * Update project-level config
114
- * @param {Object} options - Options
115
- * @param {Object} options.updates - Config updates to apply
116
- * @param {Object} options.explorer - Cosmiconfig explorer
117
- * @param {string} options.projectRoot - Project root directory
118
- * @param {Function} options.writeFile - Async file writer (path, content) => Promise
119
- * @param {Function} options.readFile - Async file reader (path) => Promise<string>
120
- * @param {Function} options.validate - Config validator
121
- * @returns {Promise<{ config: Object, filepath: string }>}
122
- */
123
- export async function updateProjectConfig({
124
- updates,
125
- explorer,
126
- projectRoot,
127
- writeFile,
128
- readFile,
129
- validate
130
- }) {
131
- let result = explorer.search(projectRoot);
132
- let {
133
- config: currentConfig,
134
- filepath: configPath
135
- } = extractCosmiconfigResult(result);
136
-
137
- // Determine config file path - create new if none exists
138
- if (!configPath) {
139
- configPath = join(projectRoot, 'vizzly.config.js');
140
- currentConfig = {};
141
- }
142
-
143
- // Merge updates with current config
144
- let newConfig = deepMerge(currentConfig, updates);
145
-
146
- // Validate before writing
147
- try {
148
- validate(newConfig);
149
- } catch (error) {
150
- throw new VizzlyError(`Invalid configuration: ${error.message}`, 'CONFIG_VALIDATION_ERROR', {
151
- errors: error.errors
152
- });
153
- }
154
-
155
- // Write config file based on format
156
- await writeProjectConfigFile({
157
- filepath: configPath,
158
- config: newConfig,
159
- writeFile,
160
- readFile
161
- });
162
-
163
- // Clear cosmiconfig cache
164
- explorer.clearCaches();
165
- return {
166
- config: newConfig,
167
- filepath: configPath
168
- };
169
- }
170
-
171
- /**
172
- * Write project config to file
173
- * @param {Object} options - Options
174
- * @param {string} options.filepath - Path to write to
175
- * @param {Object} options.config - Config object
176
- * @param {Function} options.writeFile - Async file writer
177
- * @param {Function} options.readFile - Async file reader (for package.json)
178
- * @returns {Promise<void>}
179
- */
180
- export async function writeProjectConfigFile({
181
- filepath,
182
- config,
183
- writeFile,
184
- readFile
185
- }) {
186
- let format = getConfigFormat(filepath);
187
- if (format === 'package') {
188
- // For package.json, merge into existing
189
- let pkgContent = await readFile(filepath);
190
- let pkg;
191
- try {
192
- pkg = JSON.parse(pkgContent);
193
- } catch (error) {
194
- throw new VizzlyError(`Failed to parse package.json: ${error.message}`, 'INVALID_PACKAGE_JSON');
195
- }
196
- pkg.vizzly = config;
197
- await writeFile(filepath, JSON.stringify(pkg, null, 2));
198
- return;
199
- }
200
- let serialized = serializeConfig(config, filepath);
201
- if (serialized.error) {
202
- throw serialized.error;
203
- }
204
- await writeFile(filepath, serialized.content);
205
- }
206
-
207
- /**
208
- * Update global config
209
- * @param {Object} options - Options
210
- * @param {Object} options.updates - Config updates to apply
211
- * @param {Object} options.globalConfigStore - Global config store with load and save methods
212
- * @returns {Promise<{ config: Object, filepath: string }>}
213
- */
214
- export async function updateGlobalConfig({
215
- updates,
216
- globalConfigStore
217
- }) {
218
- let currentConfig = await globalConfigStore.load();
219
- let newConfig = deepMerge(currentConfig, updates);
220
- await globalConfigStore.save(newConfig);
221
- return {
222
- config: newConfig,
223
- filepath: globalConfigStore.getPath()
224
- };
225
- }
226
-
227
- /**
228
- * Update configuration based on scope
229
- * @param {Object} options - Options
230
- * @param {string} options.scope - 'project' or 'global'
231
- * @param {Object} options.updates - Config updates to apply
232
- * @param {Object} options.explorer - Cosmiconfig explorer
233
- * @param {Object} options.globalConfigStore - Global config store
234
- * @param {string} options.projectRoot - Project root directory
235
- * @param {Function} options.writeFile - Async file writer
236
- * @param {Function} options.readFile - Async file reader
237
- * @param {Function} options.validate - Config validator
238
- * @returns {Promise<{ config: Object, filepath: string }>}
239
- */
240
- export async function updateConfig({
241
- scope,
242
- updates,
243
- explorer,
244
- globalConfigStore,
245
- projectRoot,
246
- writeFile,
247
- readFile,
248
- validate
249
- }) {
250
- let validation = validateWriteScope(scope);
251
- if (!validation.valid) {
252
- throw validation.error;
253
- }
254
- if (scope === 'project') {
255
- return updateProjectConfig({
256
- updates,
257
- explorer,
258
- projectRoot,
259
- writeFile,
260
- readFile,
261
- validate
262
- });
263
- }
264
- return updateGlobalConfig({
265
- updates,
266
- globalConfigStore
267
- });
268
- }
269
-
270
- // ============================================================================
271
- // Validation Operations
272
- // ============================================================================
273
-
274
- /**
275
- * Validate configuration object
276
- * @param {Object} config - Config to validate
277
- * @param {Function} validateFn - Validation function
278
- * @returns {{ valid: boolean, config: Object|null, errors: Array }}
279
- */
280
- export function validateConfig(config, validateFn) {
281
- try {
282
- let validated = validateFn(config);
283
- return {
284
- valid: true,
285
- config: validated,
286
- errors: []
287
- };
288
- } catch (error) {
289
- return {
290
- valid: false,
291
- config: null,
292
- errors: error.errors || [{
293
- message: error.message
294
- }]
295
- };
296
- }
297
- }
298
-
299
- // ============================================================================
300
- // Source Lookup
301
- // ============================================================================
302
-
303
- /**
304
- * Get the source of a specific config key
305
- * @param {Object} options - Options
306
- * @param {string} options.key - Config key to look up
307
- * @param {Object} options.explorer - Cosmiconfig explorer
308
- * @param {Object} options.globalConfigStore - Global config store
309
- * @param {string} options.projectRoot - Project root directory
310
- * @param {Object} [options.env] - Environment variables
311
- * @returns {Promise<string>} Source ('default', 'global', 'project', 'env', 'unknown')
312
- */
313
- export async function getConfigSource({
314
- key,
315
- explorer,
316
- globalConfigStore,
317
- projectRoot,
318
- env
319
- }) {
320
- let merged = await getMergedConfig({
321
- explorer,
322
- globalConfigStore,
323
- projectRoot,
324
- env
325
- });
326
- return merged.sources[key] || 'unknown';
327
- }
@@ -1,211 +0,0 @@
1
- /**
2
- * Project Core - Pure functions for project logic
3
- *
4
- * No I/O, no side effects - just data transformations.
5
- */
6
-
7
- import { VizzlyError } from '../errors/vizzly-error.js';
8
-
9
- // ============================================================================
10
- // API Request Helpers
11
- // ============================================================================
12
-
13
- /**
14
- * Build query params for builds API request
15
- * @param {Object} options - Query options
16
- * @param {number} [options.limit] - Number of builds to fetch
17
- * @param {string} [options.branch] - Filter by branch
18
- * @returns {string} Query string (empty string if no params)
19
- */
20
- export function buildBuildsQueryParams(options = {}) {
21
- let params = new globalThis.URLSearchParams();
22
- if (options.limit) {
23
- params.append('limit', String(options.limit));
24
- }
25
- if (options.branch) {
26
- params.append('branch', options.branch);
27
- }
28
- let query = params.toString();
29
- return query ? `?${query}` : '';
30
- }
31
-
32
- /**
33
- * Build organization header object
34
- * @param {string} organizationSlug - Organization slug
35
- * @returns {Object} Headers object with X-Organization header
36
- */
37
- export function buildOrgHeader(organizationSlug) {
38
- return {
39
- 'X-Organization': organizationSlug
40
- };
41
- }
42
-
43
- /**
44
- * Build API URL for project endpoint
45
- * @param {string} projectSlug - Project slug
46
- * @returns {string} API URL path
47
- */
48
- export function buildProjectUrl(projectSlug) {
49
- return `/api/project/${projectSlug}`;
50
- }
51
-
52
- /**
53
- * Build API URL for builds endpoint
54
- * @param {string} projectSlug - Project slug
55
- * @param {Object} options - Query options
56
- * @returns {string} Full API URL path with query params
57
- */
58
- export function buildBuildsUrl(projectSlug, options = {}) {
59
- let queryString = buildBuildsQueryParams(options);
60
- return `/api/build/${projectSlug}${queryString}`;
61
- }
62
-
63
- /**
64
- * Build API URL for project tokens endpoint
65
- * @param {string} organizationSlug - Organization slug
66
- * @param {string} projectSlug - Project slug
67
- * @param {string} [tokenId] - Optional token ID for specific token operations
68
- * @returns {string} API URL path
69
- */
70
- export function buildTokensUrl(_organizationSlug, projectSlug, tokenId) {
71
- let base = `/api/project/${projectSlug}/tokens`;
72
- return tokenId ? `${base}/${tokenId}` : base;
73
- }
74
-
75
- // ============================================================================
76
- // Response Extraction
77
- // ============================================================================
78
-
79
- /**
80
- * Extract projects from API response
81
- * @param {Object} response - API response
82
- * @returns {Array} Array of projects
83
- */
84
- export function extractProjects(response) {
85
- return response?.projects || [];
86
- }
87
-
88
- /**
89
- * Extract project from API response
90
- * @param {Object} response - API response
91
- * @returns {Object} Project object
92
- */
93
- export function extractProject(response) {
94
- return response?.project || response;
95
- }
96
-
97
- /**
98
- * Extract builds from API response
99
- * @param {Object} response - API response
100
- * @returns {Array} Array of builds
101
- */
102
- export function extractBuilds(response) {
103
- return response?.builds || [];
104
- }
105
-
106
- /**
107
- * Extract token from API response
108
- * @param {Object} response - API response
109
- * @returns {Object} Token object
110
- */
111
- export function extractToken(response) {
112
- return response?.token;
113
- }
114
-
115
- /**
116
- * Extract tokens from API response
117
- * @param {Object} response - API response
118
- * @returns {Array} Array of tokens
119
- */
120
- export function extractTokens(response) {
121
- return response?.tokens || [];
122
- }
123
-
124
- /**
125
- * Enrich projects with organization info
126
- * @param {Array} projects - Array of projects
127
- * @param {Object} org - Organization object
128
- * @param {string} org.slug - Organization slug
129
- * @param {string} org.name - Organization name
130
- * @returns {Array} Projects with organization info added
131
- */
132
- export function enrichProjectsWithOrg(projects, org) {
133
- return projects.map(project => ({
134
- ...project,
135
- organizationSlug: org.slug,
136
- organizationName: org.name
137
- }));
138
- }
139
-
140
- /**
141
- * Extract organizations from whoami response
142
- * @param {Object} whoamiResponse - Whoami API response
143
- * @returns {Array} Array of organizations
144
- */
145
- export function extractOrganizations(whoamiResponse) {
146
- return whoamiResponse?.organizations || [];
147
- }
148
-
149
- // ============================================================================
150
- // Error Building
151
- // ============================================================================
152
-
153
- /**
154
- * Build error for project fetch failure
155
- * @param {Error} originalError - Original error
156
- * @returns {VizzlyError} Wrapped error
157
- */
158
- export function buildProjectFetchError(originalError) {
159
- return new VizzlyError(`Failed to fetch project: ${originalError.message}`, 'PROJECT_FETCH_FAILED', {
160
- originalError
161
- });
162
- }
163
-
164
- /**
165
- * Build error for no authentication available
166
- * @returns {VizzlyError} No auth error
167
- */
168
- export function buildNoAuthError() {
169
- return new VizzlyError('No authentication available', 'NO_AUTH_SERVICE');
170
- }
171
-
172
- /**
173
- * Build error for no API service available
174
- * @returns {VizzlyError} No API service error
175
- */
176
- export function buildNoApiServiceError() {
177
- return new VizzlyError('API service not available', 'NO_API_SERVICE');
178
- }
179
-
180
- /**
181
- * Build error for token creation failure
182
- * @param {Error} originalError - Original error
183
- * @returns {VizzlyError} Wrapped error
184
- */
185
- export function buildTokenCreateError(originalError) {
186
- return new VizzlyError(`Failed to create project token: ${originalError.message}`, 'TOKEN_CREATE_FAILED', {
187
- originalError
188
- });
189
- }
190
-
191
- /**
192
- * Build error for token fetch failure
193
- * @param {Error} originalError - Original error
194
- * @returns {VizzlyError} Wrapped error
195
- */
196
- export function buildTokensFetchError(originalError) {
197
- return new VizzlyError(`Failed to fetch project tokens: ${originalError.message}`, 'TOKENS_FETCH_FAILED', {
198
- originalError
199
- });
200
- }
201
-
202
- /**
203
- * Build error for token revoke failure
204
- * @param {Error} originalError - Original error
205
- * @returns {VizzlyError} Wrapped error
206
- */
207
- export function buildTokenRevokeError(originalError) {
208
- return new VizzlyError(`Failed to revoke project token: ${originalError.message}`, 'TOKEN_REVOKE_FAILED', {
209
- originalError
210
- });
211
- }
@@ -1,161 +0,0 @@
1
- /**
2
- * Screenshot Server Core - Pure functions for screenshot server logic
3
- *
4
- * No I/O, no side effects - just data transformations.
5
- */
6
-
7
- import { getScreenshotOptionsPayload } from '../utils/screenshot-options.js';
8
-
9
- // ============================================================================
10
- // Request Validation
11
- // ============================================================================
12
-
13
- /**
14
- * Validate screenshot request body
15
- * @param {Object} body - Request body
16
- * @returns {{ valid: boolean, error: string|null }}
17
- */
18
- export function validateScreenshotRequest(body) {
19
- if (!body?.name || !body?.image) {
20
- return {
21
- valid: false,
22
- error: 'name and image are required'
23
- };
24
- }
25
- return {
26
- valid: true,
27
- error: null
28
- };
29
- }
30
-
31
- /**
32
- * Check if request is for the screenshot endpoint
33
- * @param {string} method - HTTP method
34
- * @param {string} url - Request URL
35
- * @returns {boolean}
36
- */
37
- export function isScreenshotEndpoint(method, url) {
38
- return method === 'POST' && url === '/screenshot';
39
- }
40
-
41
- // ============================================================================
42
- // Build ID Handling
43
- // ============================================================================
44
-
45
- /**
46
- * Get effective build ID (falls back to 'default')
47
- * @param {string|null|undefined} buildId - Build ID from request
48
- * @returns {string}
49
- */
50
- export function getEffectiveBuildId(buildId) {
51
- return buildId || 'default';
52
- }
53
-
54
- // ============================================================================
55
- // Response Building
56
- // ============================================================================
57
-
58
- /**
59
- * Build success response object
60
- * @returns {{ status: number, body: Object }}
61
- */
62
- export function buildSuccessResponse() {
63
- return {
64
- status: 200,
65
- body: {
66
- success: true
67
- }
68
- };
69
- }
70
-
71
- /**
72
- * Build error response object
73
- * @param {number} status - HTTP status code
74
- * @param {string} message - Error message
75
- * @returns {{ status: number, body: Object }}
76
- */
77
- export function buildErrorResponse(status, message) {
78
- return {
79
- status,
80
- body: {
81
- error: message
82
- }
83
- };
84
- }
85
-
86
- /**
87
- * Build not found response
88
- * @returns {{ status: number, body: Object }}
89
- */
90
- export function buildNotFoundResponse() {
91
- return buildErrorResponse(404, 'Not found');
92
- }
93
-
94
- /**
95
- * Build bad request response
96
- * @param {string} message - Error message
97
- * @returns {{ status: number, body: Object }}
98
- */
99
- export function buildBadRequestResponse(message) {
100
- return buildErrorResponse(400, message);
101
- }
102
-
103
- /**
104
- * Build internal error response
105
- * @returns {{ status: number, body: Object }}
106
- */
107
- export function buildInternalErrorResponse() {
108
- return buildErrorResponse(500, 'Internal server error');
109
- }
110
-
111
- // ============================================================================
112
- // Server Configuration
113
- // ============================================================================
114
-
115
- /**
116
- * Build server listen options
117
- * @param {Object} config - Server configuration
118
- * @returns {{ port: number, host: string }}
119
- */
120
- export function buildServerListenOptions(config) {
121
- return {
122
- port: config?.server?.port || 3000,
123
- host: '127.0.0.1'
124
- };
125
- }
126
-
127
- /**
128
- * Build server started message
129
- * @param {number} port - Server port
130
- * @returns {string}
131
- */
132
- export function buildServerStartedMessage(port) {
133
- return `Screenshot server listening on http://127.0.0.1:${port}`;
134
- }
135
-
136
- /**
137
- * Build server stopped message
138
- * @returns {string}
139
- */
140
- export function buildServerStoppedMessage() {
141
- return 'Screenshot server stopped';
142
- }
143
-
144
- // ============================================================================
145
- // Screenshot Data Extraction
146
- // ============================================================================
147
-
148
- /**
149
- * Extract screenshot data from request body
150
- * @param {Object} body - Request body
151
- * @returns {{ name: string, image: string, properties?: Object }}
152
- */
153
- export function extractScreenshotData(body) {
154
- let screenshotData = {
155
- name: body.name,
156
- image: body.image,
157
- properties: body.properties
158
- };
159
- Object.assign(screenshotData, getScreenshotOptionsPayload(body));
160
- return screenshotData;
161
- }
@@ -1,11 +0,0 @@
1
- /**
2
- * Screenshot Server Module
3
- *
4
- * Exports pure functions (core) and I/O operations for screenshot server functionality.
5
- */
6
-
7
- // Core - pure functions
8
- export { buildBadRequestResponse, buildErrorResponse, buildInternalErrorResponse, buildNotFoundResponse, buildServerListenOptions, buildServerStartedMessage, buildServerStoppedMessage, buildSuccessResponse, extractScreenshotData, getEffectiveBuildId, isScreenshotEndpoint, validateScreenshotRequest } from './core.js';
9
-
10
- // Operations - I/O with dependency injection
11
- export { handleRequest, parseRequestBody, startServer, stopServer } from './operations.js';