@vizzly-testing/cli 0.10.3 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/.mcp.json +8 -0
- package/.claude-plugin/README.md +114 -0
- package/.claude-plugin/commands/debug-diff.md +153 -0
- package/.claude-plugin/commands/setup.md +137 -0
- package/.claude-plugin/commands/suggest-screenshots.md +111 -0
- package/.claude-plugin/commands/tdd-status.md +43 -0
- package/.claude-plugin/marketplace.json +28 -0
- package/.claude-plugin/mcp/vizzly-server/cloud-api-provider.js +354 -0
- package/.claude-plugin/mcp/vizzly-server/index.js +861 -0
- package/.claude-plugin/mcp/vizzly-server/local-tdd-provider.js +422 -0
- package/.claude-plugin/mcp/vizzly-server/token-resolver.js +185 -0
- package/.claude-plugin/plugin.json +14 -0
- package/README.md +168 -8
- package/dist/cli.js +64 -0
- package/dist/client/index.js +13 -3
- package/dist/commands/login.js +195 -0
- package/dist/commands/logout.js +71 -0
- package/dist/commands/project.js +351 -0
- package/dist/commands/run.js +30 -0
- package/dist/commands/whoami.js +162 -0
- package/dist/plugin-loader.js +4 -2
- package/dist/sdk/index.js +16 -4
- package/dist/services/api-service.js +50 -7
- package/dist/services/auth-service.js +226 -0
- package/dist/types/client/index.d.ts +9 -3
- package/dist/types/commands/login.d.ts +11 -0
- package/dist/types/commands/logout.d.ts +11 -0
- package/dist/types/commands/project.d.ts +28 -0
- package/dist/types/commands/whoami.d.ts +11 -0
- package/dist/types/sdk/index.d.ts +9 -4
- package/dist/types/services/api-service.d.ts +2 -1
- package/dist/types/services/auth-service.d.ts +59 -0
- package/dist/types/utils/browser.d.ts +6 -0
- package/dist/types/utils/config-loader.d.ts +1 -1
- package/dist/types/utils/config-schema.d.ts +8 -174
- package/dist/types/utils/file-helpers.d.ts +18 -0
- package/dist/types/utils/global-config.d.ts +84 -0
- package/dist/utils/browser.js +44 -0
- package/dist/utils/config-loader.js +69 -3
- package/dist/utils/file-helpers.js +64 -0
- package/dist/utils/global-config.js +259 -0
- package/docs/api-reference.md +177 -6
- package/docs/authentication.md +334 -0
- package/docs/getting-started.md +21 -2
- package/docs/plugins.md +27 -0
- package/docs/test-integration.md +60 -10
- package/package.json +5 -3
|
@@ -8,23 +8,26 @@ import { VizzlyError, AuthError } from '../errors/vizzly-error.js';
|
|
|
8
8
|
import crypto from 'crypto';
|
|
9
9
|
import { getPackageVersion } from '../utils/package-info.js';
|
|
10
10
|
import { getApiUrl, getApiToken, getUserAgent } from '../utils/environment-config.js';
|
|
11
|
+
import { getAuthTokens, saveAuthTokens } from '../utils/global-config.js';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* ApiService class for direct API communication
|
|
14
15
|
*/
|
|
15
16
|
export class ApiService {
|
|
16
17
|
constructor(options = {}) {
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
// Accept config as-is, no fallbacks to environment
|
|
19
|
+
// Config-loader handles all env/file resolution
|
|
20
|
+
this.baseUrl = options.apiUrl || options.baseUrl || getApiUrl();
|
|
21
|
+
this.token = options.apiKey || options.token || getApiToken(); // Accept both apiKey and token
|
|
19
22
|
this.uploadAll = options.uploadAll || false;
|
|
20
23
|
|
|
21
24
|
// Build User-Agent string
|
|
22
|
-
const command = options.command || 'run';
|
|
25
|
+
const command = options.command || 'run';
|
|
23
26
|
const baseUserAgent = `vizzly-cli/${getPackageVersion()} (${command})`;
|
|
24
27
|
const sdkUserAgent = options.userAgent || getUserAgent();
|
|
25
28
|
this.userAgent = sdkUserAgent ? `${baseUserAgent} ${sdkUserAgent}` : baseUserAgent;
|
|
26
29
|
if (!this.token && !options.allowNoToken) {
|
|
27
|
-
throw new VizzlyError('No API token provided. Set VIZZLY_TOKEN environment variable.');
|
|
30
|
+
throw new VizzlyError('No API token provided. Set VIZZLY_TOKEN environment variable or run "vizzly login".');
|
|
28
31
|
}
|
|
29
32
|
}
|
|
30
33
|
|
|
@@ -32,9 +35,10 @@ export class ApiService {
|
|
|
32
35
|
* Make an API request
|
|
33
36
|
* @param {string} endpoint - API endpoint
|
|
34
37
|
* @param {Object} options - Fetch options
|
|
38
|
+
* @param {boolean} isRetry - Internal flag to prevent infinite retry loops
|
|
35
39
|
* @returns {Promise<Object>} Response data
|
|
36
40
|
*/
|
|
37
|
-
async request(endpoint, options = {}) {
|
|
41
|
+
async request(endpoint, options = {}, isRetry = false) {
|
|
38
42
|
const url = `${this.baseUrl}${endpoint}`;
|
|
39
43
|
const headers = {
|
|
40
44
|
'User-Agent': this.userAgent,
|
|
@@ -59,9 +63,48 @@ export class ApiService {
|
|
|
59
63
|
// ignore
|
|
60
64
|
}
|
|
61
65
|
|
|
62
|
-
// Handle authentication errors with
|
|
66
|
+
// Handle authentication errors with automatic token refresh
|
|
67
|
+
if (response.status === 401 && !isRetry) {
|
|
68
|
+
// Attempt to refresh token if we have refresh token in global config
|
|
69
|
+
let auth = await getAuthTokens();
|
|
70
|
+
if (auth && auth.refreshToken) {
|
|
71
|
+
try {
|
|
72
|
+
// Attempt token refresh
|
|
73
|
+
let refreshResponse = await fetch(`${this.baseUrl}/api/auth/cli/refresh`, {
|
|
74
|
+
method: 'POST',
|
|
75
|
+
headers: {
|
|
76
|
+
'Content-Type': 'application/json',
|
|
77
|
+
'User-Agent': this.userAgent
|
|
78
|
+
},
|
|
79
|
+
body: JSON.stringify({
|
|
80
|
+
refreshToken: auth.refreshToken
|
|
81
|
+
})
|
|
82
|
+
});
|
|
83
|
+
if (refreshResponse.ok) {
|
|
84
|
+
let refreshData = await refreshResponse.json();
|
|
85
|
+
|
|
86
|
+
// Save new tokens to global config
|
|
87
|
+
await saveAuthTokens({
|
|
88
|
+
accessToken: refreshData.accessToken,
|
|
89
|
+
refreshToken: refreshData.refreshToken,
|
|
90
|
+
expiresAt: refreshData.expiresAt,
|
|
91
|
+
user: auth.user // Keep existing user data
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Update token for this service instance
|
|
95
|
+
this.token = refreshData.accessToken;
|
|
96
|
+
|
|
97
|
+
// Retry the original request with new token
|
|
98
|
+
return this.request(endpoint, options, true);
|
|
99
|
+
}
|
|
100
|
+
} catch {
|
|
101
|
+
// Token refresh failed, fall through to auth error
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
throw new AuthError('Invalid or expired API token. Please run "vizzly login" to authenticate.');
|
|
105
|
+
}
|
|
63
106
|
if (response.status === 401) {
|
|
64
|
-
throw new AuthError('Invalid or expired API token. Please
|
|
107
|
+
throw new AuthError('Invalid or expired API token. Please run "vizzly login" to authenticate.');
|
|
65
108
|
}
|
|
66
109
|
throw new VizzlyError(`API request failed: ${response.status}${errorText ? ` - ${errorText}` : ''} (URL: ${url})`);
|
|
67
110
|
}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication Service for Vizzly CLI
|
|
3
|
+
* Handles authentication flows with the Vizzly API
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { AuthError, VizzlyError } from '../errors/vizzly-error.js';
|
|
7
|
+
import { getApiUrl } from '../utils/environment-config.js';
|
|
8
|
+
import { getPackageVersion } from '../utils/package-info.js';
|
|
9
|
+
import { saveAuthTokens, clearAuthTokens, getAuthTokens } from '../utils/global-config.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* AuthService class for CLI authentication
|
|
13
|
+
*/
|
|
14
|
+
export class AuthService {
|
|
15
|
+
constructor(options = {}) {
|
|
16
|
+
this.baseUrl = options.baseUrl || getApiUrl();
|
|
17
|
+
this.userAgent = `vizzly-cli/${getPackageVersion()} (auth)`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Make an unauthenticated API request
|
|
22
|
+
* @param {string} endpoint - API endpoint
|
|
23
|
+
* @param {Object} options - Fetch options
|
|
24
|
+
* @returns {Promise<Object>} Response data
|
|
25
|
+
*/
|
|
26
|
+
async request(endpoint, options = {}) {
|
|
27
|
+
let url = `${this.baseUrl}${endpoint}`;
|
|
28
|
+
let headers = {
|
|
29
|
+
'User-Agent': this.userAgent,
|
|
30
|
+
...options.headers
|
|
31
|
+
};
|
|
32
|
+
let response = await fetch(url, {
|
|
33
|
+
...options,
|
|
34
|
+
headers
|
|
35
|
+
});
|
|
36
|
+
if (!response.ok) {
|
|
37
|
+
let errorText = '';
|
|
38
|
+
let errorData = null;
|
|
39
|
+
try {
|
|
40
|
+
let contentType = response.headers.get('content-type');
|
|
41
|
+
if (contentType && contentType.includes('application/json')) {
|
|
42
|
+
errorData = await response.json();
|
|
43
|
+
errorText = errorData.error || errorData.message || '';
|
|
44
|
+
} else {
|
|
45
|
+
errorText = await response.text();
|
|
46
|
+
}
|
|
47
|
+
} catch {
|
|
48
|
+
errorText = response.statusText || '';
|
|
49
|
+
}
|
|
50
|
+
if (response.status === 401) {
|
|
51
|
+
throw new AuthError(errorText || 'Invalid credentials. Please check your email/username and password.');
|
|
52
|
+
}
|
|
53
|
+
if (response.status === 429) {
|
|
54
|
+
throw new VizzlyError('Too many login attempts. Please try again later.', 'RATE_LIMIT_ERROR');
|
|
55
|
+
}
|
|
56
|
+
throw new VizzlyError(`Authentication request failed: ${response.status}${errorText ? ` - ${errorText}` : ''}`, 'AUTH_REQUEST_ERROR');
|
|
57
|
+
}
|
|
58
|
+
return response.json();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Make an authenticated API request
|
|
63
|
+
* @param {string} endpoint - API endpoint
|
|
64
|
+
* @param {Object} options - Fetch options
|
|
65
|
+
* @returns {Promise<Object>} Response data
|
|
66
|
+
*/
|
|
67
|
+
async authenticatedRequest(endpoint, options = {}) {
|
|
68
|
+
let auth = await getAuthTokens();
|
|
69
|
+
if (!auth || !auth.accessToken) {
|
|
70
|
+
throw new AuthError('No authentication token found. Please run "vizzly login" first.');
|
|
71
|
+
}
|
|
72
|
+
let url = `${this.baseUrl}${endpoint}`;
|
|
73
|
+
let headers = {
|
|
74
|
+
'User-Agent': this.userAgent,
|
|
75
|
+
Authorization: `Bearer ${auth.accessToken}`,
|
|
76
|
+
...options.headers
|
|
77
|
+
};
|
|
78
|
+
let response = await fetch(url, {
|
|
79
|
+
...options,
|
|
80
|
+
headers
|
|
81
|
+
});
|
|
82
|
+
if (!response.ok) {
|
|
83
|
+
let errorText = '';
|
|
84
|
+
try {
|
|
85
|
+
let contentType = response.headers.get('content-type');
|
|
86
|
+
if (contentType && contentType.includes('application/json')) {
|
|
87
|
+
let errorData = await response.json();
|
|
88
|
+
errorText = errorData.error || errorData.message || '';
|
|
89
|
+
} else {
|
|
90
|
+
errorText = await response.text();
|
|
91
|
+
}
|
|
92
|
+
} catch {
|
|
93
|
+
errorText = response.statusText || '';
|
|
94
|
+
}
|
|
95
|
+
if (response.status === 401) {
|
|
96
|
+
throw new AuthError('Authentication token is invalid or expired. Please run "vizzly login" again.');
|
|
97
|
+
}
|
|
98
|
+
throw new VizzlyError(`API request failed: ${response.status}${errorText ? ` - ${errorText}` : ''}`, 'API_REQUEST_ERROR');
|
|
99
|
+
}
|
|
100
|
+
return response.json();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Initiate OAuth device flow
|
|
105
|
+
* @returns {Promise<Object>} Device code, user code, verification URL
|
|
106
|
+
*/
|
|
107
|
+
async initiateDeviceFlow() {
|
|
108
|
+
return this.request('/api/auth/cli/device/initiate', {
|
|
109
|
+
method: 'POST',
|
|
110
|
+
headers: {
|
|
111
|
+
'Content-Type': 'application/json'
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Poll for device authorization
|
|
118
|
+
* @param {string} deviceCode - Device code from initiate
|
|
119
|
+
* @returns {Promise<Object>} Token data or pending status
|
|
120
|
+
*/
|
|
121
|
+
async pollDeviceAuthorization(deviceCode) {
|
|
122
|
+
return this.request('/api/auth/cli/device/poll', {
|
|
123
|
+
method: 'POST',
|
|
124
|
+
headers: {
|
|
125
|
+
'Content-Type': 'application/json'
|
|
126
|
+
},
|
|
127
|
+
body: JSON.stringify({
|
|
128
|
+
device_code: deviceCode
|
|
129
|
+
})
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Complete device flow and save tokens
|
|
135
|
+
* @param {Object} tokenData - Token response from poll
|
|
136
|
+
* @returns {Promise<Object>} Token data with user info
|
|
137
|
+
*/
|
|
138
|
+
async completeDeviceFlow(tokenData) {
|
|
139
|
+
// Save tokens to global config
|
|
140
|
+
await saveAuthTokens({
|
|
141
|
+
accessToken: tokenData.accessToken,
|
|
142
|
+
refreshToken: tokenData.refreshToken,
|
|
143
|
+
expiresAt: tokenData.expiresAt,
|
|
144
|
+
user: tokenData.user
|
|
145
|
+
});
|
|
146
|
+
return tokenData;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Refresh access token using refresh token
|
|
151
|
+
* @returns {Promise<Object>} New tokens
|
|
152
|
+
*/
|
|
153
|
+
async refresh() {
|
|
154
|
+
let auth = await getAuthTokens();
|
|
155
|
+
if (!auth || !auth.refreshToken) {
|
|
156
|
+
throw new AuthError('No refresh token found. Please run "vizzly login" first.');
|
|
157
|
+
}
|
|
158
|
+
let response = await this.request('/api/auth/cli/refresh', {
|
|
159
|
+
method: 'POST',
|
|
160
|
+
headers: {
|
|
161
|
+
'Content-Type': 'application/json'
|
|
162
|
+
},
|
|
163
|
+
body: JSON.stringify({
|
|
164
|
+
refreshToken: auth.refreshToken
|
|
165
|
+
})
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// Update tokens in global config
|
|
169
|
+
await saveAuthTokens({
|
|
170
|
+
accessToken: response.accessToken,
|
|
171
|
+
refreshToken: response.refreshToken,
|
|
172
|
+
expiresAt: response.expiresAt,
|
|
173
|
+
user: auth.user // Keep existing user data
|
|
174
|
+
});
|
|
175
|
+
return response;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Logout and revoke tokens
|
|
180
|
+
* @returns {Promise<void>}
|
|
181
|
+
*/
|
|
182
|
+
async logout() {
|
|
183
|
+
let auth = await getAuthTokens();
|
|
184
|
+
if (auth && auth.refreshToken) {
|
|
185
|
+
try {
|
|
186
|
+
// Attempt to revoke tokens on server
|
|
187
|
+
await this.request('/api/auth/cli/logout', {
|
|
188
|
+
method: 'POST',
|
|
189
|
+
headers: {
|
|
190
|
+
'Content-Type': 'application/json'
|
|
191
|
+
},
|
|
192
|
+
body: JSON.stringify({
|
|
193
|
+
refreshToken: auth.refreshToken
|
|
194
|
+
})
|
|
195
|
+
});
|
|
196
|
+
} catch (error) {
|
|
197
|
+
// If server request fails, still clear local tokens
|
|
198
|
+
console.warn('Warning: Failed to revoke tokens on server:', error.message);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Clear tokens from global config
|
|
203
|
+
await clearAuthTokens();
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Get current user information
|
|
208
|
+
* @returns {Promise<Object>} User and organization data
|
|
209
|
+
*/
|
|
210
|
+
async whoami() {
|
|
211
|
+
return this.authenticatedRequest('/api/auth/cli/whoami');
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Check if user is authenticated
|
|
216
|
+
* @returns {Promise<boolean>} True if authenticated
|
|
217
|
+
*/
|
|
218
|
+
async isAuthenticated() {
|
|
219
|
+
try {
|
|
220
|
+
await this.whoami();
|
|
221
|
+
return true;
|
|
222
|
+
} catch {
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Take a screenshot for visual regression testing
|
|
3
3
|
*
|
|
4
4
|
* @param {string} name - Unique name for the screenshot
|
|
5
|
-
* @param {Buffer} imageBuffer - PNG image data as a Buffer
|
|
5
|
+
* @param {Buffer|string} imageBuffer - PNG image data as a Buffer, or a file path to an image
|
|
6
6
|
* @param {Object} [options] - Optional configuration
|
|
7
7
|
* @param {Record<string, any>} [options.properties] - Additional properties to attach to the screenshot
|
|
8
8
|
* @param {number} [options.threshold=0] - Pixel difference threshold (0-100)
|
|
@@ -11,13 +11,17 @@
|
|
|
11
11
|
* @returns {Promise<void>}
|
|
12
12
|
*
|
|
13
13
|
* @example
|
|
14
|
-
* // Basic usage
|
|
14
|
+
* // Basic usage with Buffer
|
|
15
15
|
* import { vizzlyScreenshot } from '@vizzly-testing/cli/client';
|
|
16
16
|
*
|
|
17
17
|
* const screenshot = await page.screenshot();
|
|
18
18
|
* await vizzlyScreenshot('homepage', screenshot);
|
|
19
19
|
*
|
|
20
20
|
* @example
|
|
21
|
+
* // Basic usage with file path
|
|
22
|
+
* await vizzlyScreenshot('homepage', './screenshots/homepage.png');
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
21
25
|
* // With properties and threshold
|
|
22
26
|
* await vizzlyScreenshot('checkout-form', screenshot, {
|
|
23
27
|
* properties: {
|
|
@@ -28,8 +32,10 @@
|
|
|
28
32
|
* });
|
|
29
33
|
*
|
|
30
34
|
* @throws {VizzlyError} When screenshot capture fails or client is not initialized
|
|
35
|
+
* @throws {VizzlyError} When file path is provided but file doesn't exist
|
|
36
|
+
* @throws {VizzlyError} When file cannot be read due to permissions or I/O errors
|
|
31
37
|
*/
|
|
32
|
-
export function vizzlyScreenshot(name: string, imageBuffer: Buffer, options?: {
|
|
38
|
+
export function vizzlyScreenshot(name: string, imageBuffer: Buffer | string, options?: {
|
|
33
39
|
properties?: Record<string, any>;
|
|
34
40
|
threshold?: number;
|
|
35
41
|
fullPage?: boolean;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Login command implementation using OAuth device flow
|
|
3
|
+
* @param {Object} options - Command options
|
|
4
|
+
* @param {Object} globalOptions - Global CLI options
|
|
5
|
+
*/
|
|
6
|
+
export function loginCommand(options?: any, globalOptions?: any): Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* Validate login options
|
|
9
|
+
* @param {Object} options - Command options
|
|
10
|
+
*/
|
|
11
|
+
export function validateLoginOptions(): any[];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logout command implementation
|
|
3
|
+
* @param {Object} options - Command options
|
|
4
|
+
* @param {Object} globalOptions - Global CLI options
|
|
5
|
+
*/
|
|
6
|
+
export function logoutCommand(options?: any, globalOptions?: any): Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* Validate logout options
|
|
9
|
+
* @param {Object} options - Command options
|
|
10
|
+
*/
|
|
11
|
+
export function validateLogoutOptions(): any[];
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project select command - configure project for current directory
|
|
3
|
+
* @param {Object} options - Command options
|
|
4
|
+
* @param {Object} globalOptions - Global CLI options
|
|
5
|
+
*/
|
|
6
|
+
export function projectSelectCommand(options?: any, globalOptions?: any): Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* Project list command - show all configured projects
|
|
9
|
+
* @param {Object} _options - Command options (unused)
|
|
10
|
+
* @param {Object} globalOptions - Global CLI options
|
|
11
|
+
*/
|
|
12
|
+
export function projectListCommand(_options?: any, globalOptions?: any): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Project token command - show/regenerate token for current directory
|
|
15
|
+
* @param {Object} _options - Command options (unused)
|
|
16
|
+
* @param {Object} globalOptions - Global CLI options
|
|
17
|
+
*/
|
|
18
|
+
export function projectTokenCommand(_options?: any, globalOptions?: any): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Project remove command - remove project configuration for current directory
|
|
21
|
+
* @param {Object} _options - Command options (unused)
|
|
22
|
+
* @param {Object} globalOptions - Global CLI options
|
|
23
|
+
*/
|
|
24
|
+
export function projectRemoveCommand(_options?: any, globalOptions?: any): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Validate project command options
|
|
27
|
+
*/
|
|
28
|
+
export function validateProjectOptions(): any[];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whoami command implementation
|
|
3
|
+
* @param {Object} options - Command options
|
|
4
|
+
* @param {Object} globalOptions - Global CLI options
|
|
5
|
+
*/
|
|
6
|
+
export function whoamiCommand(options?: any, globalOptions?: any): Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* Validate whoami options
|
|
9
|
+
* @param {Object} options - Command options
|
|
10
|
+
*/
|
|
11
|
+
export function validateWhoamiOptions(): any[];
|
|
@@ -81,11 +81,14 @@ export class VizzlySDK {
|
|
|
81
81
|
/**
|
|
82
82
|
* Capture a screenshot
|
|
83
83
|
* @param {string} name - Screenshot name
|
|
84
|
-
* @param {Buffer} imageBuffer - Image data
|
|
84
|
+
* @param {Buffer|string} imageBuffer - Image data as a Buffer, or a file path to an image
|
|
85
85
|
* @param {import('../types').ScreenshotOptions} [options] - Options
|
|
86
86
|
* @returns {Promise<void>}
|
|
87
|
+
* @throws {VizzlyError} When server is not running
|
|
88
|
+
* @throws {VizzlyError} When file path is provided but file doesn't exist
|
|
89
|
+
* @throws {VizzlyError} When file cannot be read due to permissions or I/O errors
|
|
87
90
|
*/
|
|
88
|
-
screenshot(name: string, imageBuffer: Buffer, options?: any): Promise<void>;
|
|
91
|
+
screenshot(name: string, imageBuffer: Buffer | string, options?: any): Promise<void>;
|
|
89
92
|
/**
|
|
90
93
|
* Upload all captured screenshots
|
|
91
94
|
* @param {import('../types').UploadOptions} [options] - Upload options
|
|
@@ -95,10 +98,12 @@ export class VizzlySDK {
|
|
|
95
98
|
/**
|
|
96
99
|
* Run local comparison in TDD mode
|
|
97
100
|
* @param {string} name - Screenshot name
|
|
98
|
-
* @param {Buffer} imageBuffer - Current image
|
|
101
|
+
* @param {Buffer|string} imageBuffer - Current image as a Buffer, or a file path to an image
|
|
99
102
|
* @returns {Promise<import('../types').ComparisonResult>} Comparison result
|
|
103
|
+
* @throws {VizzlyError} When file path is provided but file doesn't exist
|
|
104
|
+
* @throws {VizzlyError} When file cannot be read due to permissions or I/O errors
|
|
100
105
|
*/
|
|
101
|
-
compare(name: string, imageBuffer: Buffer): Promise<any>;
|
|
106
|
+
compare(name: string, imageBuffer: Buffer | string): Promise<any>;
|
|
102
107
|
}
|
|
103
108
|
export { loadConfig } from "../utils/config-loader.js";
|
|
104
109
|
export { createLogger } from "../utils/logger.js";
|
|
@@ -11,9 +11,10 @@ export class ApiService {
|
|
|
11
11
|
* Make an API request
|
|
12
12
|
* @param {string} endpoint - API endpoint
|
|
13
13
|
* @param {Object} options - Fetch options
|
|
14
|
+
* @param {boolean} isRetry - Internal flag to prevent infinite retry loops
|
|
14
15
|
* @returns {Promise<Object>} Response data
|
|
15
16
|
*/
|
|
16
|
-
request(endpoint: string, options?: any): Promise<any>;
|
|
17
|
+
request(endpoint: string, options?: any, isRetry?: boolean): Promise<any>;
|
|
17
18
|
/**
|
|
18
19
|
* Get build information
|
|
19
20
|
* @param {string} buildId - Build ID
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AuthService class for CLI authentication
|
|
3
|
+
*/
|
|
4
|
+
export class AuthService {
|
|
5
|
+
constructor(options?: {});
|
|
6
|
+
baseUrl: any;
|
|
7
|
+
userAgent: string;
|
|
8
|
+
/**
|
|
9
|
+
* Make an unauthenticated API request
|
|
10
|
+
* @param {string} endpoint - API endpoint
|
|
11
|
+
* @param {Object} options - Fetch options
|
|
12
|
+
* @returns {Promise<Object>} Response data
|
|
13
|
+
*/
|
|
14
|
+
request(endpoint: string, options?: any): Promise<any>;
|
|
15
|
+
/**
|
|
16
|
+
* Make an authenticated API request
|
|
17
|
+
* @param {string} endpoint - API endpoint
|
|
18
|
+
* @param {Object} options - Fetch options
|
|
19
|
+
* @returns {Promise<Object>} Response data
|
|
20
|
+
*/
|
|
21
|
+
authenticatedRequest(endpoint: string, options?: any): Promise<any>;
|
|
22
|
+
/**
|
|
23
|
+
* Initiate OAuth device flow
|
|
24
|
+
* @returns {Promise<Object>} Device code, user code, verification URL
|
|
25
|
+
*/
|
|
26
|
+
initiateDeviceFlow(): Promise<any>;
|
|
27
|
+
/**
|
|
28
|
+
* Poll for device authorization
|
|
29
|
+
* @param {string} deviceCode - Device code from initiate
|
|
30
|
+
* @returns {Promise<Object>} Token data or pending status
|
|
31
|
+
*/
|
|
32
|
+
pollDeviceAuthorization(deviceCode: string): Promise<any>;
|
|
33
|
+
/**
|
|
34
|
+
* Complete device flow and save tokens
|
|
35
|
+
* @param {Object} tokenData - Token response from poll
|
|
36
|
+
* @returns {Promise<Object>} Token data with user info
|
|
37
|
+
*/
|
|
38
|
+
completeDeviceFlow(tokenData: any): Promise<any>;
|
|
39
|
+
/**
|
|
40
|
+
* Refresh access token using refresh token
|
|
41
|
+
* @returns {Promise<Object>} New tokens
|
|
42
|
+
*/
|
|
43
|
+
refresh(): Promise<any>;
|
|
44
|
+
/**
|
|
45
|
+
* Logout and revoke tokens
|
|
46
|
+
* @returns {Promise<void>}
|
|
47
|
+
*/
|
|
48
|
+
logout(): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Get current user information
|
|
51
|
+
* @returns {Promise<Object>} User and organization data
|
|
52
|
+
*/
|
|
53
|
+
whoami(): Promise<any>;
|
|
54
|
+
/**
|
|
55
|
+
* Check if user is authenticated
|
|
56
|
+
* @returns {Promise<boolean>} True if authenticated
|
|
57
|
+
*/
|
|
58
|
+
isAuthenticated(): Promise<boolean>;
|
|
59
|
+
}
|