@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/api/endpoints.js
DELETED
|
@@ -1,421 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* API Endpoints - Functions for each API operation
|
|
3
|
-
*
|
|
4
|
-
* Each function takes a client as the first parameter and returns the API result.
|
|
5
|
-
* This keeps the functions pure (no hidden state) and easily testable.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { VizzlyError } from '../errors/vizzly-error.js';
|
|
9
|
-
import * as output from '../utils/output.js';
|
|
10
|
-
import { buildBuildPayload, buildEndpointWithParams, buildQueryParams, buildScreenshotPayload, buildScreenshotResolvePayload, buildShaCheckPayload, computeSha256 } from './core.js';
|
|
11
|
-
|
|
12
|
-
// ============================================================================
|
|
13
|
-
// Build Endpoints
|
|
14
|
-
// ============================================================================
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Get build information
|
|
18
|
-
* @param {Object} client - API client
|
|
19
|
-
* @param {string} buildId - Build ID
|
|
20
|
-
* @param {string|null} include - Optional include parameter (e.g., 'screenshots')
|
|
21
|
-
* @returns {Promise<Object>} Build data
|
|
22
|
-
*/
|
|
23
|
-
export async function getBuild(client, buildId, include = null) {
|
|
24
|
-
let endpoint = `/api/sdk/builds/${buildId}`;
|
|
25
|
-
if (include) {
|
|
26
|
-
endpoint = buildEndpointWithParams(endpoint, {
|
|
27
|
-
include
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
return client.request(endpoint);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Get the server-owned build processing and review status.
|
|
35
|
-
*
|
|
36
|
-
* This endpoint keeps processing, comparison, and review counts separate so
|
|
37
|
-
* callers do not have to reconstruct lifecycle state from legacy build fields.
|
|
38
|
-
*
|
|
39
|
-
* @param {Object} client - API client
|
|
40
|
-
* @param {string} buildId - Build ID
|
|
41
|
-
* @returns {Promise<Object>} Build status response
|
|
42
|
-
*/
|
|
43
|
-
export async function getBuildStatus(client, buildId) {
|
|
44
|
-
return client.request(`/api/sdk/builds/${buildId}/status`);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Get builds for a project
|
|
49
|
-
* @param {Object} client - API client
|
|
50
|
-
* @param {Object} filters - Filter options
|
|
51
|
-
* @returns {Promise<Array>} List of builds
|
|
52
|
-
*/
|
|
53
|
-
export async function getBuilds(client, filters = {}) {
|
|
54
|
-
let query = buildQueryParams(filters);
|
|
55
|
-
let endpoint = `/api/sdk/builds${query ? `?${query}` : ''}`;
|
|
56
|
-
return client.request(endpoint);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Create a new build
|
|
61
|
-
* @param {Object} client - API client
|
|
62
|
-
* @param {Object} metadata - Build metadata
|
|
63
|
-
* @returns {Promise<Object>} Created build data
|
|
64
|
-
*/
|
|
65
|
-
export async function createBuild(client, metadata) {
|
|
66
|
-
let payload = buildBuildPayload(metadata);
|
|
67
|
-
return client.request('/api/sdk/builds', {
|
|
68
|
-
method: 'POST',
|
|
69
|
-
headers: {
|
|
70
|
-
'Content-Type': 'application/json'
|
|
71
|
-
},
|
|
72
|
-
body: JSON.stringify({
|
|
73
|
-
build: payload
|
|
74
|
-
})
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Update build status
|
|
80
|
-
* @param {Object} client - API client
|
|
81
|
-
* @param {string} buildId - Build ID
|
|
82
|
-
* @param {string} status - Build status (pending|running|completed|failed)
|
|
83
|
-
* @param {number|null} [executionTimeMs=null] - Execution time in milliseconds
|
|
84
|
-
* @param {string} [failureReason] - Explanation sent only for a failed build
|
|
85
|
-
* @returns {Promise<Object>} Updated build data
|
|
86
|
-
*/
|
|
87
|
-
export async function updateBuildStatus(client, buildId, status, executionTimeMs = null, failureReason) {
|
|
88
|
-
let body = {
|
|
89
|
-
status
|
|
90
|
-
};
|
|
91
|
-
if (status === 'failed' && failureReason) body.failureReason = failureReason;
|
|
92
|
-
if (executionTimeMs != null) {
|
|
93
|
-
body.executionTimeMs = executionTimeMs;
|
|
94
|
-
}
|
|
95
|
-
return client.request(`/api/sdk/builds/${buildId}/status`, {
|
|
96
|
-
method: 'PUT',
|
|
97
|
-
headers: {
|
|
98
|
-
'Content-Type': 'application/json'
|
|
99
|
-
},
|
|
100
|
-
body: JSON.stringify(body)
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Mark a build completed or failed, with an optional failure explanation.
|
|
106
|
-
* @param {Object} client - API client
|
|
107
|
-
* @param {string} buildId - Build ID
|
|
108
|
-
* @param {boolean} [success=true] - Whether tests and uploads succeeded
|
|
109
|
-
* @param {number|null} [executionTimeMs=null] - Execution time in milliseconds
|
|
110
|
-
* @param {string} [failureReason] - Explanation sent only for a failed build
|
|
111
|
-
* @returns {Promise<Object>} Finalized build data
|
|
112
|
-
*/
|
|
113
|
-
export async function finalizeBuild(client, buildId, success = true, executionTimeMs = null, failureReason) {
|
|
114
|
-
let status = success ? 'completed' : 'failed';
|
|
115
|
-
return updateBuildStatus(client, buildId, status, executionTimeMs, failureReason);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Get TDD baselines for a build
|
|
120
|
-
* @param {Object} client - API client
|
|
121
|
-
* @param {string} buildId - Build ID
|
|
122
|
-
* @returns {Promise<Object>} { build, screenshots, signatureProperties }
|
|
123
|
-
*/
|
|
124
|
-
export async function getTddBaselines(client, buildId) {
|
|
125
|
-
return client.request(`/api/sdk/builds/${buildId}/tdd-baselines`);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// ============================================================================
|
|
129
|
-
// Screenshot Endpoints
|
|
130
|
-
// ============================================================================
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Check if SHAs already exist on the server
|
|
134
|
-
* @param {Object} client - API client
|
|
135
|
-
* @param {Array} screenshots - Screenshots to check (objects with sha256, or string SHAs)
|
|
136
|
-
* @param {string} buildId - Build ID for screenshot record creation
|
|
137
|
-
* @returns {Promise<Object>} { existing, missing, screenshots }
|
|
138
|
-
*/
|
|
139
|
-
export async function checkShas(client, screenshots, buildId) {
|
|
140
|
-
try {
|
|
141
|
-
let payload = buildShaCheckPayload(screenshots, buildId);
|
|
142
|
-
return await client.request('/api/sdk/check-shas', {
|
|
143
|
-
method: 'POST',
|
|
144
|
-
headers: {
|
|
145
|
-
'Content-Type': 'application/json'
|
|
146
|
-
},
|
|
147
|
-
body: JSON.stringify(payload)
|
|
148
|
-
});
|
|
149
|
-
} catch (error) {
|
|
150
|
-
// Continue without deduplication on error
|
|
151
|
-
output.debug('sha-check', 'failed, continuing without deduplication', {
|
|
152
|
-
error: error.message
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
// Extract SHAs for fallback response
|
|
156
|
-
let shaList = Array.isArray(screenshots) && screenshots.length > 0 && typeof screenshots[0] === 'object' ? screenshots.map(s => s.sha256) : screenshots;
|
|
157
|
-
return {
|
|
158
|
-
existing: [],
|
|
159
|
-
missing: shaList,
|
|
160
|
-
screenshots: []
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
function canUploadBytesAfterShaResolveError(error) {
|
|
165
|
-
let status = error?.context?.status;
|
|
166
|
-
|
|
167
|
-
// Network failures, older servers, and server errors should degrade to the
|
|
168
|
-
// slower byte upload path. Auth and ownership errors must still surface.
|
|
169
|
-
if (!status) return true;
|
|
170
|
-
if (status >= 500) return true;
|
|
171
|
-
if (status === 400 && error.message?.includes('image_data')) return true;
|
|
172
|
-
return false;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Upload a screenshot with SHA deduplication
|
|
177
|
-
* @param {Object} client - API client
|
|
178
|
-
* @param {string} buildId - Build ID
|
|
179
|
-
* @param {string} name - Screenshot name
|
|
180
|
-
* @param {Buffer} buffer - Screenshot data
|
|
181
|
-
* @param {Object} metadata - Additional metadata
|
|
182
|
-
* @param {boolean} skipDedup - Skip SHA deduplication (uploadAll mode)
|
|
183
|
-
* @returns {Promise<Object>} Upload result
|
|
184
|
-
*/
|
|
185
|
-
export async function uploadScreenshot(client, buildId, name, buffer, metadata = {}, skipDedup = false, screenshotOptions = {}) {
|
|
186
|
-
// Skip SHA deduplication if requested
|
|
187
|
-
if (skipDedup) {
|
|
188
|
-
let payload = buildScreenshotPayload(name, buffer, metadata, null, screenshotOptions);
|
|
189
|
-
return client.request(`/api/sdk/builds/${buildId}/screenshots`, {
|
|
190
|
-
method: 'POST',
|
|
191
|
-
headers: {
|
|
192
|
-
'Content-Type': 'application/json'
|
|
193
|
-
},
|
|
194
|
-
body: JSON.stringify(payload)
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// Normal flow with server-side SHA resolution.
|
|
199
|
-
let sha256 = computeSha256(buffer);
|
|
200
|
-
let resolvePayload = buildScreenshotResolvePayload(name, metadata, sha256, screenshotOptions);
|
|
201
|
-
try {
|
|
202
|
-
let resolveResult = await client.request(`/api/sdk/builds/${buildId}/screenshots`, {
|
|
203
|
-
method: 'POST',
|
|
204
|
-
headers: {
|
|
205
|
-
'Content-Type': 'application/json'
|
|
206
|
-
},
|
|
207
|
-
body: JSON.stringify(resolvePayload)
|
|
208
|
-
});
|
|
209
|
-
if (resolveResult?.upload_required === false) {
|
|
210
|
-
return {
|
|
211
|
-
message: 'Screenshot already exists, skipped upload',
|
|
212
|
-
sha256,
|
|
213
|
-
skipped: true,
|
|
214
|
-
screenshot: resolveResult,
|
|
215
|
-
fromExisting: true
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
} catch (error) {
|
|
219
|
-
if (!canUploadBytesAfterShaResolveError(error)) {
|
|
220
|
-
throw error;
|
|
221
|
-
}
|
|
222
|
-
output.debug('sha-resolve', 'failed, uploading screenshot bytes', {
|
|
223
|
-
error: error.message
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// File doesn't exist, or resolve failed; proceed with upload.
|
|
228
|
-
let payload = buildScreenshotPayload(name, buffer, metadata, sha256, screenshotOptions);
|
|
229
|
-
return client.request(`/api/sdk/builds/${buildId}/screenshots`, {
|
|
230
|
-
method: 'POST',
|
|
231
|
-
headers: {
|
|
232
|
-
'Content-Type': 'application/json'
|
|
233
|
-
},
|
|
234
|
-
body: JSON.stringify(payload)
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// ============================================================================
|
|
239
|
-
// Comparison Endpoints
|
|
240
|
-
// ============================================================================
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
* Get comparison information
|
|
244
|
-
* @param {Object} client - API client
|
|
245
|
-
* @param {string} comparisonId - Comparison ID
|
|
246
|
-
* @returns {Promise<Object>} Comparison data
|
|
247
|
-
*/
|
|
248
|
-
export async function getComparison(client, comparisonId) {
|
|
249
|
-
let response = await client.request(`/api/sdk/comparisons/${comparisonId}`);
|
|
250
|
-
return response.comparison;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* Get a build context bundle at the detail level the caller can consume.
|
|
255
|
-
*
|
|
256
|
-
* Passing detail selection to the API keeps compact callers from downloading
|
|
257
|
-
* raw Honeydiff geometry by default while preserving the unfiltered endpoint
|
|
258
|
-
* for raw and full context consumers.
|
|
259
|
-
*
|
|
260
|
-
* @param {Object} client - API client
|
|
261
|
-
* @param {string} buildId - Build ID
|
|
262
|
-
* @param {Object} options - Optional query params
|
|
263
|
-
* @returns {Promise<Object>} Build context bundle
|
|
264
|
-
*/
|
|
265
|
-
export async function getBuildContext(client, buildId, options = {}) {
|
|
266
|
-
let endpoint = buildEndpointWithParams(`/api/sdk/context/builds/${buildId}`, options);
|
|
267
|
-
return client.request(endpoint);
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* Get comparison context bundle with similarity and history
|
|
272
|
-
* @param {Object} client - API client
|
|
273
|
-
* @param {string} comparisonId - Comparison ID
|
|
274
|
-
* @param {Object} options - Optional query params
|
|
275
|
-
* @returns {Promise<Object>} Comparison context bundle
|
|
276
|
-
*/
|
|
277
|
-
export async function getComparisonContext(client, comparisonId, options = {}) {
|
|
278
|
-
let endpoint = buildEndpointWithParams(`/api/sdk/context/comparisons/${comparisonId}`, options);
|
|
279
|
-
return client.request(endpoint);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
/**
|
|
283
|
-
* Get screenshot context bundle for a screenshot name
|
|
284
|
-
* @param {Object} client - API client
|
|
285
|
-
* @param {string} screenshotName - Screenshot name
|
|
286
|
-
* @param {Object} options - Optional query params
|
|
287
|
-
* @returns {Promise<Object>} Screenshot context bundle
|
|
288
|
-
*/
|
|
289
|
-
export async function getScreenshotContext(client, screenshotName, options = {}) {
|
|
290
|
-
let encodedName = encodeURIComponent(screenshotName);
|
|
291
|
-
let endpoint = buildEndpointWithParams(`/api/sdk/context/screenshots/${encodedName}`, options);
|
|
292
|
-
return client.request(endpoint);
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
/**
|
|
296
|
-
* Get project-scoped similar comparisons for a fingerprint hash
|
|
297
|
-
* @param {Object} client - API client
|
|
298
|
-
* @param {string} fingerprintHash - Honeydiff fingerprint hash
|
|
299
|
-
* @param {Object} options - Optional query params
|
|
300
|
-
* @returns {Promise<Object>} Fingerprint context bundle
|
|
301
|
-
*/
|
|
302
|
-
export async function getSimilarFingerprintContext(client, fingerprintHash, options = {}) {
|
|
303
|
-
let encodedFingerprint = encodeURIComponent(fingerprintHash);
|
|
304
|
-
let endpoint = buildEndpointWithParams(`/api/sdk/context/fingerprints/${encodedFingerprint}/similar`, options);
|
|
305
|
-
return client.request(endpoint);
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
/**
|
|
309
|
-
* Get pending review queue context for a project
|
|
310
|
-
* @param {Object} client - API client
|
|
311
|
-
* @param {Object} options - Optional query params
|
|
312
|
-
* @returns {Promise<Object>} Review queue context bundle
|
|
313
|
-
*/
|
|
314
|
-
export async function getReviewQueueContext(client, options = {}) {
|
|
315
|
-
let endpoint = buildEndpointWithParams('/api/sdk/context/review-queue', options);
|
|
316
|
-
return client.request(endpoint);
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
/**
|
|
320
|
-
* Search for comparisons by name
|
|
321
|
-
* @param {Object} client - API client
|
|
322
|
-
* @param {string} name - Screenshot name to search for
|
|
323
|
-
* @param {Object} filters - Optional filters (branch, project, organization, limit, offset)
|
|
324
|
-
* @returns {Promise<Object>} Search results with comparisons and pagination
|
|
325
|
-
*/
|
|
326
|
-
export async function searchComparisons(client, name, filters = {}) {
|
|
327
|
-
if (!name || typeof name !== 'string') {
|
|
328
|
-
throw new VizzlyError('name is required and must be a non-empty string');
|
|
329
|
-
}
|
|
330
|
-
let {
|
|
331
|
-
branch,
|
|
332
|
-
project,
|
|
333
|
-
organization,
|
|
334
|
-
limit = 50,
|
|
335
|
-
offset = 0
|
|
336
|
-
} = filters;
|
|
337
|
-
let params = {
|
|
338
|
-
name,
|
|
339
|
-
limit: String(limit),
|
|
340
|
-
offset: String(offset)
|
|
341
|
-
};
|
|
342
|
-
if (branch) params.branch = branch;
|
|
343
|
-
if (project) params.project = project;
|
|
344
|
-
if (organization) params.organization = organization;
|
|
345
|
-
let endpoint = buildEndpointWithParams('/api/sdk/comparisons/search', params);
|
|
346
|
-
return client.request(endpoint);
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
// ============================================================================
|
|
350
|
-
// Auth/Token Endpoints
|
|
351
|
-
// ============================================================================
|
|
352
|
-
|
|
353
|
-
/**
|
|
354
|
-
* Get token context (organization and project info)
|
|
355
|
-
* @param {Object} client - API client
|
|
356
|
-
* @returns {Promise<Object>} Token context data
|
|
357
|
-
*/
|
|
358
|
-
export async function getTokenContext(client) {
|
|
359
|
-
return client.request('/api/sdk/token/context');
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
// ============================================================================
|
|
363
|
-
// Parallel Build Endpoints
|
|
364
|
-
// ============================================================================
|
|
365
|
-
|
|
366
|
-
/**
|
|
367
|
-
* Finalize a parallel build
|
|
368
|
-
* @param {Object} client - API client
|
|
369
|
-
* @param {string} parallelId - Parallel ID to finalize
|
|
370
|
-
* @returns {Promise<Object>} Finalization result
|
|
371
|
-
*/
|
|
372
|
-
export async function finalizeParallelBuild(client, parallelId) {
|
|
373
|
-
return client.request(`/api/sdk/parallel/${parallelId}/finalize`, {
|
|
374
|
-
method: 'POST',
|
|
375
|
-
headers: {
|
|
376
|
-
'Content-Type': 'application/json'
|
|
377
|
-
}
|
|
378
|
-
});
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
// ============================================================================
|
|
382
|
-
// Preview Endpoints
|
|
383
|
-
// ============================================================================
|
|
384
|
-
|
|
385
|
-
/**
|
|
386
|
-
* Upload preview ZIP file for a build
|
|
387
|
-
* @param {Object} client - API client
|
|
388
|
-
* @param {string} buildId - Build ID
|
|
389
|
-
* @param {Buffer} zipBuffer - ZIP file contents
|
|
390
|
-
* @returns {Promise<Object>} Upload result with preview URL
|
|
391
|
-
*/
|
|
392
|
-
export async function uploadPreviewZip(client, buildId, zipBuffer) {
|
|
393
|
-
// Use native FormData (Node 18+) with Blob for proper fetch compatibility
|
|
394
|
-
let formData = new FormData();
|
|
395
|
-
let blob = new Blob([zipBuffer], {
|
|
396
|
-
type: 'application/zip'
|
|
397
|
-
});
|
|
398
|
-
formData.append('file', blob, 'preview.zip');
|
|
399
|
-
return client.request(`/api/sdk/builds/${buildId}/preview/upload-zip`, {
|
|
400
|
-
method: 'POST',
|
|
401
|
-
body: formData
|
|
402
|
-
// Let fetch set the Content-Type with boundary automatically
|
|
403
|
-
});
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
/**
|
|
407
|
-
* Get preview info for a build
|
|
408
|
-
* @param {Object} client - API client
|
|
409
|
-
* @param {string} buildId - Build ID
|
|
410
|
-
* @returns {Promise<Object>} Preview info or null if not found
|
|
411
|
-
*/
|
|
412
|
-
export async function getPreviewInfo(client, buildId) {
|
|
413
|
-
try {
|
|
414
|
-
return await client.request(`/api/sdk/builds/${buildId}/preview`);
|
|
415
|
-
} catch (error) {
|
|
416
|
-
if (error.status === 404) {
|
|
417
|
-
return null;
|
|
418
|
-
}
|
|
419
|
-
throw error;
|
|
420
|
-
}
|
|
421
|
-
}
|
package/dist/api/index.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Vizzly API Module
|
|
3
|
-
*
|
|
4
|
-
* Functional API for interacting with the Vizzly platform.
|
|
5
|
-
*
|
|
6
|
-
* Usage:
|
|
7
|
-
* import { createApiClient, getBuild, createBuild } from '../api/index.js';
|
|
8
|
-
*
|
|
9
|
-
* let client = createApiClient({ token: 'xxx', command: 'run' });
|
|
10
|
-
* let build = await getBuild(client, buildId);
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
// Client factory
|
|
14
|
-
export { createApiClient, DEFAULT_API_URL } from './client.js';
|
|
15
|
-
// Core pure functions
|
|
16
|
-
export { buildApiUrl, buildAuthHeader, buildBuildPayload, buildEndpointWithParams, buildQueryParams, buildRequestHeaders, buildScreenshotCheckObject, buildScreenshotPayload, buildScreenshotResolvePayload, buildShaCheckPayload, buildUserAgent, computeSha256, extractErrorBody, findScreenshotBySha, isAuthError, isRateLimited, parseApiError, partitionByShaExistence, shaExists, shouldRetryWithRefresh } from './core.js';
|
|
17
|
-
|
|
18
|
-
// Endpoint functions
|
|
19
|
-
export { checkShas, createBuild, finalizeBuild, finalizeParallelBuild, getBuild, getBuildContext, getBuildStatus, getBuilds, getComparison, getComparisonContext, getPreviewInfo, getReviewQueueContext, getScreenshotContext, getSimilarFingerprintContext, getTddBaselines, getTokenContext, searchComparisons, updateBuildStatus, uploadPreviewZip, uploadScreenshot } from './endpoints.js';
|
package/dist/auth/core.js
DELETED
|
@@ -1,237 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Auth Core - Pure functions for authentication logic
|
|
3
|
-
*
|
|
4
|
-
* No I/O, no side effects - just data transformations.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { AuthError, VizzlyError } from '../errors/vizzly-error.js';
|
|
8
|
-
|
|
9
|
-
// ============================================================================
|
|
10
|
-
// Header Building
|
|
11
|
-
// ============================================================================
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Build Authorization header from access token
|
|
15
|
-
* @param {string|null} accessToken - Access token
|
|
16
|
-
* @returns {Object} Headers object with Authorization if token exists
|
|
17
|
-
*/
|
|
18
|
-
export function buildAuthHeader(accessToken) {
|
|
19
|
-
if (!accessToken) return {};
|
|
20
|
-
return {
|
|
21
|
-
Authorization: `Bearer ${accessToken}`
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Build User-Agent header for auth requests
|
|
27
|
-
* @param {string} version - CLI version
|
|
28
|
-
* @returns {string} User-Agent string
|
|
29
|
-
*/
|
|
30
|
-
export function buildAuthUserAgent(version) {
|
|
31
|
-
return `vizzly-cli/${version} (auth)`;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Build complete headers for a request
|
|
36
|
-
* @param {Object} options - Header options
|
|
37
|
-
* @returns {Object} Complete headers object
|
|
38
|
-
*/
|
|
39
|
-
export function buildRequestHeaders({
|
|
40
|
-
userAgent,
|
|
41
|
-
accessToken,
|
|
42
|
-
contentType,
|
|
43
|
-
extra = {}
|
|
44
|
-
}) {
|
|
45
|
-
return {
|
|
46
|
-
'User-Agent': userAgent,
|
|
47
|
-
...(accessToken ? buildAuthHeader(accessToken) : {}),
|
|
48
|
-
...(contentType ? {
|
|
49
|
-
'Content-Type': contentType
|
|
50
|
-
} : {}),
|
|
51
|
-
...extra
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// ============================================================================
|
|
56
|
-
// Error Parsing
|
|
57
|
-
// ============================================================================
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Parse error from API response
|
|
61
|
-
* @param {number} status - HTTP status code
|
|
62
|
-
* @param {Object|string} body - Response body (parsed JSON or text)
|
|
63
|
-
* @param {string} endpoint - API endpoint for context
|
|
64
|
-
* @returns {Error} Appropriate error type
|
|
65
|
-
*/
|
|
66
|
-
export function parseAuthError(status, body, _endpoint) {
|
|
67
|
-
let errorText = '';
|
|
68
|
-
if (typeof body === 'object' && body !== null) {
|
|
69
|
-
errorText = body.error || body.message || '';
|
|
70
|
-
} else if (typeof body === 'string') {
|
|
71
|
-
errorText = body;
|
|
72
|
-
}
|
|
73
|
-
let retryAfter = Number(body?.retryAfter);
|
|
74
|
-
let context = {
|
|
75
|
-
status,
|
|
76
|
-
serverCode: body?.code,
|
|
77
|
-
retryAfter: retryAfter > 0 ? retryAfter : undefined
|
|
78
|
-
};
|
|
79
|
-
if (status === 401) {
|
|
80
|
-
return new AuthError(errorText || 'Invalid credentials. Please check your email/username and password.', context);
|
|
81
|
-
}
|
|
82
|
-
if (status === 429) {
|
|
83
|
-
return new VizzlyError('Too many login attempts. Please try again later.', 'RATE_LIMIT_ERROR', context);
|
|
84
|
-
}
|
|
85
|
-
return new VizzlyError(`Authentication request failed: ${status}${errorText ? ` - ${errorText}` : ''}`, 'AUTH_REQUEST_ERROR', context);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Parse error for authenticated requests (different error messages)
|
|
90
|
-
* @param {number} status - HTTP status code
|
|
91
|
-
* @param {Object|string} body - Response body
|
|
92
|
-
* @param {string} endpoint - API endpoint
|
|
93
|
-
* @returns {Error} Appropriate error type
|
|
94
|
-
*/
|
|
95
|
-
export function parseAuthenticatedError(status, body, endpoint) {
|
|
96
|
-
let errorText = '';
|
|
97
|
-
if (typeof body === 'object' && body !== null) {
|
|
98
|
-
errorText = body.error || body.message || '';
|
|
99
|
-
} else if (typeof body === 'string') {
|
|
100
|
-
errorText = body;
|
|
101
|
-
}
|
|
102
|
-
if (status === 401) {
|
|
103
|
-
return new AuthError('Authentication token is invalid or expired. Please run "vizzly login" again.');
|
|
104
|
-
}
|
|
105
|
-
return new VizzlyError(`API request failed: ${status}${errorText ? ` - ${errorText}` : ''} (${endpoint})`, 'API_REQUEST_ERROR');
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// ============================================================================
|
|
109
|
-
// Payload Building
|
|
110
|
-
// ============================================================================
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Build device poll request payload
|
|
114
|
-
* @param {string} deviceCode - Device code from initiate
|
|
115
|
-
* @returns {Object} Request payload
|
|
116
|
-
*/
|
|
117
|
-
export function buildDevicePollPayload(deviceCode) {
|
|
118
|
-
return {
|
|
119
|
-
device_code: deviceCode
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Build refresh token request payload
|
|
125
|
-
* @param {string} refreshToken - Refresh token
|
|
126
|
-
* @returns {Object} Request payload
|
|
127
|
-
*/
|
|
128
|
-
export function buildRefreshPayload(refreshToken) {
|
|
129
|
-
return {
|
|
130
|
-
refreshToken
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Build logout request payload
|
|
136
|
-
* @param {string} refreshToken - Refresh token to revoke
|
|
137
|
-
* @returns {Object} Request payload
|
|
138
|
-
*/
|
|
139
|
-
export function buildLogoutPayload(refreshToken) {
|
|
140
|
-
return {
|
|
141
|
-
refreshToken
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// ============================================================================
|
|
146
|
-
// Token Handling
|
|
147
|
-
// ============================================================================
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Build token data for storage from API response
|
|
151
|
-
* @param {Object} response - API response with tokens
|
|
152
|
-
* @param {Object|null} existingUser - Existing user data to preserve
|
|
153
|
-
* @returns {Object} Token data for storage
|
|
154
|
-
*/
|
|
155
|
-
export function buildTokenData(response, existingUser = null) {
|
|
156
|
-
return {
|
|
157
|
-
accessToken: response.accessToken,
|
|
158
|
-
refreshToken: response.refreshToken,
|
|
159
|
-
expiresAt: response.expiresAt,
|
|
160
|
-
user: response.user || existingUser
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Validate that tokens exist and have required fields
|
|
166
|
-
* @param {Object|null} auth - Auth tokens object
|
|
167
|
-
* @param {string} requiredField - Field that must exist ('accessToken' or 'refreshToken')
|
|
168
|
-
* @returns {{ valid: boolean, error: Error|null }}
|
|
169
|
-
*/
|
|
170
|
-
export function validateTokens(auth, requiredField = 'accessToken') {
|
|
171
|
-
if (!auth?.[requiredField]) {
|
|
172
|
-
let message = requiredField === 'refreshToken' ? 'No refresh token found. Please run "vizzly login" first.' : 'No authentication token found. Please run "vizzly login" first.';
|
|
173
|
-
return {
|
|
174
|
-
valid: false,
|
|
175
|
-
error: new AuthError(message)
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
return {
|
|
179
|
-
valid: true,
|
|
180
|
-
error: null
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
export function normalizeDeviceFlowResponse(deviceFlow) {
|
|
184
|
-
let verificationUri = deviceFlow.verification_uri || deviceFlow.verificationUri;
|
|
185
|
-
let userCode = deviceFlow.user_code || deviceFlow.userCode;
|
|
186
|
-
let deviceCode = deviceFlow.device_code || deviceFlow.deviceCode;
|
|
187
|
-
if (!verificationUri || !userCode || !deviceCode) {
|
|
188
|
-
throw new Error('Invalid device flow response from server');
|
|
189
|
-
}
|
|
190
|
-
return {
|
|
191
|
-
verificationUri,
|
|
192
|
-
userCode,
|
|
193
|
-
deviceCode,
|
|
194
|
-
urlWithCode: deviceFlow.verification_uri_complete || deviceFlow.verificationUriComplete || `${verificationUri}?code=${encodeURIComponent(userCode)}`
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
export function resolveAuthorizedTokenData(pollResponse) {
|
|
198
|
-
let accessToken = pollResponse.tokens?.accessToken || pollResponse.tokens?.access_token;
|
|
199
|
-
if (accessToken) {
|
|
200
|
-
return pollResponse;
|
|
201
|
-
}
|
|
202
|
-
if (pollResponse.status === 'pending') {
|
|
203
|
-
throw new Error('Authorization not complete yet. Please complete the authorization in your browser and try running "vizzly login" again.');
|
|
204
|
-
}
|
|
205
|
-
if (pollResponse.status === 'expired') {
|
|
206
|
-
throw new Error('Device code expired. Please try logging in again.');
|
|
207
|
-
}
|
|
208
|
-
if (pollResponse.status === 'invalid') {
|
|
209
|
-
throw new Error('Device code is invalid or expired. Please try logging in again.');
|
|
210
|
-
}
|
|
211
|
-
if (pollResponse.status === 'denied') {
|
|
212
|
-
throw new Error('Authorization denied. Please try logging in again.');
|
|
213
|
-
}
|
|
214
|
-
throw new Error('Unexpected response from authorization server. Please try logging in again.');
|
|
215
|
-
}
|
|
216
|
-
export function buildTokens(tokenData, now = Date.now()) {
|
|
217
|
-
let tokensData = tokenData.tokens || tokenData;
|
|
218
|
-
let tokenExpiresIn = tokensData.expiresIn || tokensData.expires_in;
|
|
219
|
-
let tokenExpiresAt = tokenExpiresIn ? new Date(now + tokenExpiresIn * 1000).toISOString() : tokenData.expires_at || tokenData.expiresAt;
|
|
220
|
-
return {
|
|
221
|
-
accessToken: tokensData.accessToken || tokensData.access_token,
|
|
222
|
-
refreshToken: tokensData.refreshToken || tokensData.refresh_token,
|
|
223
|
-
expiresAt: tokenExpiresAt,
|
|
224
|
-
user: tokenData.user,
|
|
225
|
-
organizations: tokenData.organizations
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
/** Map protocol codes without depending on the server's human-readable text. */
|
|
230
|
-
export function deviceAuthorizationStatus(error) {
|
|
231
|
-
return {
|
|
232
|
-
AUTHORIZATION_PENDING: 'pending',
|
|
233
|
-
ACCESS_DENIED: 'denied',
|
|
234
|
-
EXPIRED_TOKEN: 'expired',
|
|
235
|
-
INVALID_DEVICE_CODE: 'invalid'
|
|
236
|
-
}[error.context?.serverCode];
|
|
237
|
-
}
|