@smartbear/mcp 0.12.0 → 0.13.1
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 +30 -6
- package/dist/bugsnag/client/api/CurrentUser.js +50 -26
- package/dist/bugsnag/client/api/Error.js +158 -57
- package/dist/bugsnag/client/api/Project.js +398 -243
- package/dist/bugsnag/client/api/api.js +4087 -3837
- package/dist/bugsnag/client/api/base.js +155 -173
- package/dist/bugsnag/client/api/configuration.js +28 -25
- package/dist/bugsnag/client/filters.js +11 -20
- package/dist/bugsnag/client.js +1398 -1277
- package/dist/bugsnag/input-schemas.js +39 -57
- package/dist/collaborator/client.js +335 -371
- package/dist/common/bugsnag.js +5 -3
- package/dist/common/cache.js +50 -57
- package/dist/common/client-registry.js +106 -119
- package/dist/common/info.js +7 -3
- package/dist/common/register-clients.js +0 -16
- package/dist/common/server.js +270 -228
- package/dist/common/tools.js +19 -0
- package/dist/common/transport-http.js +252 -343
- package/dist/common/transport-stdio.js +40 -37
- package/dist/common/zod-utils.js +20 -0
- package/dist/index.js +18 -23
- package/dist/package.json.js +11 -0
- package/dist/pactflow/client/ai.js +142 -169
- package/dist/pactflow/client/base.js +41 -51
- package/dist/pactflow/client/prompt-utils.js +93 -84
- package/dist/pactflow/client/prompts.js +95 -92
- package/dist/pactflow/client/tools.js +94 -83
- package/dist/pactflow/client/utils.js +60 -64
- package/dist/pactflow/client.js +399 -320
- package/dist/qmetry/client/api/client-api.js +43 -41
- package/dist/qmetry/client/api/error-handler.js +264 -310
- package/dist/qmetry/client/auto-resolve.js +78 -99
- package/dist/qmetry/client/automation.js +139 -162
- package/dist/qmetry/client/handlers.js +49 -46
- package/dist/qmetry/client/issues.js +133 -115
- package/dist/qmetry/client/project.js +153 -174
- package/dist/qmetry/client/requirement.js +82 -70
- package/dist/qmetry/client/testcase.js +240 -208
- package/dist/qmetry/client/testsuite.js +332 -293
- package/dist/qmetry/client/tools/automation-tools.js +291 -288
- package/dist/qmetry/client/tools/index.js +16 -13
- package/dist/qmetry/client/tools/issue-tools.js +534 -543
- package/dist/qmetry/client/tools/project-tools.js +635 -656
- package/dist/qmetry/client/tools/requirement-tools.js +525 -528
- package/dist/qmetry/client/tools/testcase-tools.js +773 -786
- package/dist/qmetry/client/tools/testsuite-tools.js +1069 -1083
- package/dist/qmetry/client/utils.js +8 -14
- package/dist/qmetry/client.js +111 -109
- package/dist/qmetry/config/constants.js +48 -44
- package/dist/qmetry/config/rest-endpoints.js +51 -48
- package/dist/qmetry/types/automation.js +7 -7
- package/dist/qmetry/types/common.js +763 -1049
- package/dist/qmetry/types/issues.js +26 -19
- package/dist/qmetry/types/project.js +32 -25
- package/dist/qmetry/types/requirements.js +26 -21
- package/dist/qmetry/types/testcase.js +55 -44
- package/dist/qmetry/types/testsuite.js +66 -52
- package/dist/reflect/client.js +284 -226
- package/dist/swagger/client/api.js +645 -662
- package/dist/swagger/client/configuration.js +31 -33
- package/dist/swagger/client/portal-types.js +204 -244
- package/dist/swagger/client/registry-types.js +62 -96
- package/dist/swagger/client/tools.js +148 -158
- package/dist/swagger/client/user-management-types.js +11 -22
- package/dist/swagger/client.js +143 -135
- package/dist/swagger/config-utils.js +10 -16
- package/dist/zephyr/client.js +43 -42
- package/dist/zephyr/common/api-client.js +35 -30
- package/dist/zephyr/common/auth-service.js +16 -13
- package/dist/zephyr/common/rest-api-schemas.js +3173 -5146
- package/dist/zephyr/tool/environment/get-environments.js +66 -66
- package/dist/zephyr/tool/priority/get-priorities.js +41 -41
- package/dist/zephyr/tool/project/get-project.js +37 -37
- package/dist/zephyr/tool/project/get-projects.js +46 -46
- package/dist/zephyr/tool/status/get-statuses.js +47 -47
- package/dist/zephyr/tool/test-case/get-test-case.js +37 -37
- package/dist/zephyr/tool/test-case/get-test-cases.js +62 -62
- package/dist/zephyr/tool/test-cycle/get-test-cycle.js +37 -37
- package/dist/zephyr/tool/test-cycle/get-test-cycles.js +70 -70
- package/dist/zephyr/tool/test-execution/get-test-execution.js +37 -37
- package/dist/zephyr/tool/test-execution/get-test-executions.js +43 -43
- package/package.json +5 -5
- package/dist/bugsnag/client/api/index.js +0 -6
- package/dist/common/types.js +0 -6
- package/dist/qmetry/client/tools/types.js +0 -1
- package/dist/swagger/client/index.js +0 -6
- package/dist/tests/unit/bugsnag/utils/factories.js +0 -86
- package/dist/zephyr/tool/zephyr-tool.js +0 -1
|
@@ -1,329 +1,283 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* QMetry API Error Handling Utilities
|
|
3
|
-
*
|
|
4
|
-
* This module provides centralized error handling for QMetry API operations,
|
|
5
|
-
* including user-friendly error messages and troubleshooting guidance.
|
|
6
|
-
*
|
|
7
|
-
* Handles common error scenarios:
|
|
8
|
-
* - SSL/TLS Certificate errors (corporate proxies like Zscaler)
|
|
9
|
-
* - Authentication/Authorization failures
|
|
10
|
-
* - CORS (Cross-Origin Resource Sharing) issues
|
|
11
|
-
* - Project access errors
|
|
12
|
-
* - Network connectivity problems
|
|
13
|
-
* - Generic API errors with helpful troubleshooting
|
|
14
|
-
*/
|
|
15
|
-
/**
|
|
16
|
-
* Error message templates for common QMetry API issues
|
|
17
|
-
*/
|
|
18
1
|
const ERROR_TEMPLATES = {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
2
|
+
AUTHENTICATION_FAILED: (baseUrl, errorText) => `QMetry API Authentication Failed: Invalid or expired API key.
|
|
3
|
+
|
|
4
|
+
To resolve this issue:
|
|
5
|
+
1. Log into your QMetry Test Management instance: ${baseUrl}
|
|
6
|
+
2. Search Open API → Go To Open API Page
|
|
7
|
+
3. Generate a new API key OR copy an existing valid key
|
|
8
|
+
4. Copy the API key to your clipboard
|
|
9
|
+
5. Restart VS Code or reload the MCP server
|
|
10
|
+
6. When prompted, paste the new API key for 'QMetry Open API Key'
|
|
11
|
+
|
|
12
|
+
Note: API keys may expire or be revoked. Always use the latest key from your QMetry instance.
|
|
13
|
+
Original error: ${errorText}`,
|
|
14
|
+
AUTHORIZATION_ERROR: (errorText) => `QMetry Authorization Error: Insufficient permissions.
|
|
15
|
+
|
|
16
|
+
Your API key is valid but lacks the necessary permissions for this operation.
|
|
17
|
+
|
|
18
|
+
Possible causes:
|
|
19
|
+
1. Your user role doesn't have access to this resource
|
|
20
|
+
2. The project permissions are restricted
|
|
21
|
+
3. The specific operation requires higher privileges
|
|
22
|
+
|
|
23
|
+
To resolve:
|
|
24
|
+
1. Contact your QMetry administrator to review your permissions
|
|
25
|
+
2. Verify you have the correct project access
|
|
26
|
+
3. Check if your user role includes the required privileges
|
|
27
|
+
|
|
28
|
+
Original error: ${errorText}`,
|
|
29
|
+
PROJECT_ACCESS_ERROR: (project, errorText) => `QMetry Project Access Error: Cannot access project '${project}'.
|
|
30
|
+
|
|
31
|
+
Possible causes:
|
|
32
|
+
1. API key lacks permissions for this project
|
|
33
|
+
2. Project key '${project}' doesn't exist or is archived
|
|
34
|
+
3. Your user account doesn't have access to this project
|
|
35
|
+
|
|
36
|
+
To resolve:
|
|
37
|
+
1. Verify the project key is correct
|
|
38
|
+
2. Check your QMetry permissions for this project
|
|
39
|
+
3. Contact your QMetry administrator if needed
|
|
40
|
+
|
|
41
|
+
Original error: ${errorText}`,
|
|
42
|
+
GENERIC_API_ERROR: (status, baseUrl, errorText) => `QMetry API request failed (${status}): ${errorText}
|
|
43
|
+
|
|
44
|
+
Troubleshooting tips:
|
|
45
|
+
Verify your QMetry instance URL: ${baseUrl}
|
|
46
|
+
Check if your API key is valid and not expired
|
|
47
|
+
Ensure you have the necessary permissions
|
|
48
|
+
Try accessing QMetry directly in your browser to confirm connectivity`,
|
|
49
|
+
CORS_ERROR: (baseUrl, errorText) => `QMetry API CORS Error: Cross-Origin Request Blocked.
|
|
50
|
+
|
|
51
|
+
CORS (Cross-Origin Resource Sharing) issue detected:
|
|
52
|
+
Your browser is blocking the request due to CORS policy
|
|
53
|
+
The QMetry server may not be configured to allow requests from this origin
|
|
54
|
+
|
|
55
|
+
Possible solutions:
|
|
56
|
+
1. Contact your QMetry administrator to configure CORS headers
|
|
57
|
+
2. Ensure the QMetry instance URL is correct: ${baseUrl}
|
|
58
|
+
3. If using a proxy, verify proxy CORS configuration
|
|
59
|
+
4. Try accessing QMetry from the same domain/protocol
|
|
60
|
+
5. Check if browser extensions are blocking the request
|
|
61
|
+
|
|
62
|
+
Technical details: ${errorText}`,
|
|
63
|
+
SSL_CERTIFICATE_ERROR: (baseUrl, errorText) => `QMetry API SSL Certificate Error: Unable to verify certificate.
|
|
64
|
+
|
|
65
|
+
SSL/TLS Certificate verification failed - Common in corporate networks:
|
|
66
|
+
• Corporate proxy/firewall (Zscaler, Forcepoint, etc.) is intercepting HTTPS traffic
|
|
67
|
+
• Self-signed or corporate certificates are being used
|
|
68
|
+
• Certificate chain validation is failing
|
|
69
|
+
|
|
70
|
+
Solution for corporate network environments:
|
|
71
|
+
Contact your IT administrator to:
|
|
72
|
+
• Add QMetry domain to certificate bypass list
|
|
73
|
+
• Configure corporate certificates properly
|
|
74
|
+
• Whitelist the QMetry API endpoints
|
|
75
|
+
Target URL: ${baseUrl}
|
|
76
|
+
Technical details: ${errorText}`,
|
|
77
|
+
INVALID_URL_ERROR: (baseUrl, path, errorText) => `QMetry API Invalid URL Error: The API endpoint appears to be incorrect.
|
|
78
|
+
|
|
79
|
+
Request details:
|
|
80
|
+
• Base URL: ${baseUrl}
|
|
81
|
+
• API Path: ${path}
|
|
82
|
+
• Full URL: ${baseUrl}${path}
|
|
83
|
+
|
|
84
|
+
Common URL issues:
|
|
85
|
+
1. Wrong API endpoint path (check QMetry API documentation)
|
|
86
|
+
2. Typo in the URL path (missing '/', wrong spelling)
|
|
87
|
+
3. API version mismatch (v1, v2, etc.)
|
|
88
|
+
4. Incorrect base URL (should end with QMetry instance domain)
|
|
89
|
+
5. Body stream errors (often caused by malformed URLs or wrong HTTP method)
|
|
90
|
+
|
|
91
|
+
Troubleshooting steps:
|
|
92
|
+
1. Verify the API endpoint in QMetry documentation
|
|
93
|
+
2. Check the QMetry instance URL is correct
|
|
94
|
+
3. Test the endpoint manually using a REST client
|
|
95
|
+
4. Ensure the API path matches the expected format
|
|
96
|
+
5. If you see 'Body is unusable' errors, check for URL typos or wrong endpoints
|
|
97
|
+
|
|
98
|
+
Expected URL format: https://your-qmetry-instance.com/rest/...
|
|
99
|
+
Server response: ${errorText}`
|
|
98
100
|
};
|
|
99
|
-
/**
|
|
100
|
-
* Checks if the error is related to authentication (invalid/expired API key)
|
|
101
|
-
*/
|
|
102
101
|
function isAuthenticationError(context) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
errorData?.code === "CO.INVALID_API_KEY" ||
|
|
106
|
-
errorData?.message?.toLowerCase().includes("invalid api key"));
|
|
102
|
+
const { status, errorData } = context;
|
|
103
|
+
return status === 401 || errorData?.code === "CO.INVALID_API_KEY" || errorData?.message?.toLowerCase().includes("invalid api key");
|
|
107
104
|
}
|
|
108
|
-
/**
|
|
109
|
-
* Checks if the error is related to authorization (insufficient permissions)
|
|
110
|
-
*/
|
|
111
105
|
function isAuthorizationError(context) {
|
|
112
|
-
|
|
113
|
-
|
|
106
|
+
const { status } = context;
|
|
107
|
+
return status === 403;
|
|
114
108
|
}
|
|
115
|
-
/**
|
|
116
|
-
* Checks if the error is related to project access
|
|
117
|
-
*/
|
|
118
109
|
function isProjectAccessError(context) {
|
|
119
|
-
|
|
120
|
-
|
|
110
|
+
const { status, path } = context;
|
|
111
|
+
return status === 404 && (path?.includes("project") ?? false);
|
|
121
112
|
}
|
|
122
|
-
/**
|
|
123
|
-
* Checks if the error is related to CORS (Cross-Origin Resource Sharing)
|
|
124
|
-
*/
|
|
125
113
|
function isCorsError(context) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
// Check error text for CORS-related keywords
|
|
147
|
-
return corsIndicators.some((indicator) => lowercaseErrorText.includes(indicator));
|
|
114
|
+
const { status, errorText, isCorsError: isCorsError2 } = context;
|
|
115
|
+
if (isCorsError2) {
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
const corsIndicators = [
|
|
119
|
+
"cors",
|
|
120
|
+
"cross-origin",
|
|
121
|
+
"cross origin",
|
|
122
|
+
"preflight",
|
|
123
|
+
"access-control-allow-origin",
|
|
124
|
+
"network error when attempting to fetch resource",
|
|
125
|
+
"failed to fetch"
|
|
126
|
+
];
|
|
127
|
+
const lowercaseErrorText = errorText.toLowerCase();
|
|
128
|
+
if (status === 0) {
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
return corsIndicators.some(
|
|
132
|
+
(indicator) => lowercaseErrorText.includes(indicator)
|
|
133
|
+
);
|
|
148
134
|
}
|
|
149
|
-
/**
|
|
150
|
-
* Checks if the error is related to SSL/TLS certificate issues
|
|
151
|
-
*/
|
|
152
135
|
function isSslCertificateError(context) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
return true;
|
|
175
|
-
}
|
|
176
|
-
// Check error text for SSL-related keywords
|
|
177
|
-
return sslErrorIndicators.some((indicator) => lowercaseErrorText.includes(indicator));
|
|
136
|
+
const { errorText } = context;
|
|
137
|
+
const sslErrorIndicators = [
|
|
138
|
+
"unable to get local issuer certificate",
|
|
139
|
+
"unable_to_get_issuer_cert_locally",
|
|
140
|
+
"self signed certificate",
|
|
141
|
+
"certificate verify failed",
|
|
142
|
+
"ssl certificate problem",
|
|
143
|
+
"certificate has expired",
|
|
144
|
+
"certificate authority is invalid",
|
|
145
|
+
"untrusted certificate",
|
|
146
|
+
"cert authority invalid",
|
|
147
|
+
"tls certificate verification failed",
|
|
148
|
+
"certificate validation error"
|
|
149
|
+
];
|
|
150
|
+
const lowercaseErrorText = errorText.toLowerCase();
|
|
151
|
+
if (lowercaseErrorText.includes("unable_to_get_issuer_cert_locally") || lowercaseErrorText.includes("cert_untrusted") || lowercaseErrorText.includes("cert_authority_invalid") || lowercaseErrorText.includes("certificate verify failed")) {
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
return sslErrorIndicators.some(
|
|
155
|
+
(indicator) => lowercaseErrorText.includes(indicator)
|
|
156
|
+
);
|
|
178
157
|
}
|
|
179
|
-
/**
|
|
180
|
-
* Checks if the error is related to invalid/wrong API URL
|
|
181
|
-
*/
|
|
182
158
|
function isInvalidUrlError(context) {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
return true;
|
|
218
|
-
}
|
|
219
|
-
return false;
|
|
159
|
+
const { status, errorText, errorData } = context;
|
|
160
|
+
const lowercaseErrorText = errorText.toLowerCase();
|
|
161
|
+
if (status === 404) {
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
const urlErrorIndicators = [
|
|
165
|
+
"not found",
|
|
166
|
+
"resource not found",
|
|
167
|
+
"endpoint not found",
|
|
168
|
+
"path not found",
|
|
169
|
+
"url not found",
|
|
170
|
+
"route not found",
|
|
171
|
+
"invalid endpoint",
|
|
172
|
+
"unknown endpoint",
|
|
173
|
+
"method not allowed",
|
|
174
|
+
"no handler found",
|
|
175
|
+
"404",
|
|
176
|
+
// Body stream errors that often indicate wrong URL/malformed requests
|
|
177
|
+
"body is unusable",
|
|
178
|
+
"body has already been read",
|
|
179
|
+
"request body already read",
|
|
180
|
+
"body stream already consumed",
|
|
181
|
+
"invalid request body",
|
|
182
|
+
"malformed request"
|
|
183
|
+
];
|
|
184
|
+
if (urlErrorIndicators.some(
|
|
185
|
+
(indicator) => lowercaseErrorText.includes(indicator)
|
|
186
|
+
)) {
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
if (errorData?.error?.toLowerCase().includes("not found") || errorData?.message?.toLowerCase().includes("not found")) {
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
192
|
+
return false;
|
|
220
193
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
return new Error(ERROR_TEMPLATES.GENERIC_API_ERROR(status, baseUrl, errorText));
|
|
194
|
+
function createQMetryError(context) {
|
|
195
|
+
const { status, errorText, baseUrl, project } = context;
|
|
196
|
+
if (isSslCertificateError(context)) {
|
|
197
|
+
return new Error(ERROR_TEMPLATES.SSL_CERTIFICATE_ERROR(baseUrl, errorText));
|
|
198
|
+
}
|
|
199
|
+
if (isCorsError(context)) {
|
|
200
|
+
return new Error(ERROR_TEMPLATES.CORS_ERROR(baseUrl, errorText));
|
|
201
|
+
}
|
|
202
|
+
if (isAuthenticationError(context)) {
|
|
203
|
+
return new Error(ERROR_TEMPLATES.AUTHENTICATION_FAILED(baseUrl, errorText));
|
|
204
|
+
}
|
|
205
|
+
if (isAuthorizationError(context)) {
|
|
206
|
+
return new Error(ERROR_TEMPLATES.AUTHORIZATION_ERROR(errorText));
|
|
207
|
+
}
|
|
208
|
+
if (isProjectAccessError(context) && project) {
|
|
209
|
+
return new Error(ERROR_TEMPLATES.PROJECT_ACCESS_ERROR(project, errorText));
|
|
210
|
+
}
|
|
211
|
+
if (isInvalidUrlError(context)) {
|
|
212
|
+
const path = context.path || "";
|
|
213
|
+
return new Error(
|
|
214
|
+
ERROR_TEMPLATES.INVALID_URL_ERROR(baseUrl, path, errorText)
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
return new Error(
|
|
218
|
+
ERROR_TEMPLATES.GENERIC_API_ERROR(status, baseUrl, errorText)
|
|
219
|
+
);
|
|
248
220
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
const context = {
|
|
268
|
-
status: response.status,
|
|
269
|
-
errorData,
|
|
270
|
-
errorText,
|
|
271
|
-
baseUrl,
|
|
272
|
-
project,
|
|
273
|
-
path,
|
|
274
|
-
};
|
|
275
|
-
throw createQMetryError(context);
|
|
221
|
+
async function handleQMetryApiError(response, baseUrl, project, path) {
|
|
222
|
+
let errorData;
|
|
223
|
+
let errorText;
|
|
224
|
+
try {
|
|
225
|
+
errorData = await response.json();
|
|
226
|
+
errorText = JSON.stringify(errorData);
|
|
227
|
+
} catch {
|
|
228
|
+
errorText = await response.text() || `HTTP ${response.status}`;
|
|
229
|
+
}
|
|
230
|
+
const context = {
|
|
231
|
+
status: response.status,
|
|
232
|
+
errorData,
|
|
233
|
+
errorText,
|
|
234
|
+
baseUrl,
|
|
235
|
+
project,
|
|
236
|
+
path
|
|
237
|
+
};
|
|
238
|
+
throw createQMetryError(context);
|
|
276
239
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
* @param path - Optional API path context
|
|
284
|
-
*/
|
|
285
|
-
export function handleQMetryFetchError(error, baseUrl, project, path) {
|
|
286
|
-
// Extract comprehensive error information
|
|
287
|
-
let errorText = error.message || error.toString();
|
|
288
|
-
// Check if error has a cause property with more details (common for SSL errors)
|
|
289
|
-
if (error.cause && typeof error.cause === "object") {
|
|
290
|
-
const cause = error.cause;
|
|
291
|
-
if (cause.message) {
|
|
292
|
-
errorText += ` | Cause: ${cause.message}`;
|
|
293
|
-
}
|
|
294
|
-
if (cause.code) {
|
|
295
|
-
errorText += ` | Code: ${cause.code}`;
|
|
296
|
-
}
|
|
297
|
-
// Add the full cause details for better debugging
|
|
298
|
-
if (cause.toString && typeof cause.toString === "function") {
|
|
299
|
-
errorText += ` | Details: ${cause.toString()}`;
|
|
300
|
-
}
|
|
240
|
+
function handleQMetryFetchError(error, baseUrl, project, path) {
|
|
241
|
+
let errorText = error.message || error.toString();
|
|
242
|
+
if (error.cause && typeof error.cause === "object") {
|
|
243
|
+
const cause = error.cause;
|
|
244
|
+
if (cause.message) {
|
|
245
|
+
errorText += ` | Cause: ${cause.message}`;
|
|
301
246
|
}
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
if (fullErrorString.includes("unable to get local issuer certificate") ||
|
|
305
|
-
fullErrorString.includes("UNABLE_TO_GET_ISSUER_CERT_LOCALLY")) {
|
|
306
|
-
errorText +=
|
|
307
|
-
" | SSL Certificate Error: Corporate proxy/firewall intercepting HTTPS";
|
|
247
|
+
if (cause.code) {
|
|
248
|
+
errorText += ` | Code: ${cause.code}`;
|
|
308
249
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
250
|
+
if (cause.toString && typeof cause.toString === "function") {
|
|
251
|
+
errorText += ` | Details: ${cause.toString()}`;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
const fullErrorString = JSON.stringify(
|
|
255
|
+
error,
|
|
256
|
+
Object.getOwnPropertyNames(error)
|
|
257
|
+
);
|
|
258
|
+
if (fullErrorString.includes("unable to get local issuer certificate") || fullErrorString.includes("UNABLE_TO_GET_ISSUER_CERT_LOCALLY")) {
|
|
259
|
+
errorText += " | SSL Certificate Error: Corporate proxy/firewall intercepting HTTPS";
|
|
260
|
+
}
|
|
261
|
+
const tempContext = {
|
|
262
|
+
status: 0,
|
|
263
|
+
errorText
|
|
264
|
+
};
|
|
265
|
+
const isSSLError = isSslCertificateError(tempContext);
|
|
266
|
+
const isURLError = isInvalidUrlError(tempContext);
|
|
267
|
+
const context = {
|
|
268
|
+
status: 0,
|
|
269
|
+
// Status 0 typically indicates network/CORS/SSL issues
|
|
270
|
+
errorText,
|
|
271
|
+
baseUrl,
|
|
272
|
+
project,
|
|
273
|
+
path,
|
|
274
|
+
// Only assume CORS if it's not an SSL or URL error
|
|
275
|
+
isCorsError: !isSSLError && !isURLError
|
|
276
|
+
};
|
|
277
|
+
throw createQMetryError(context);
|
|
329
278
|
}
|
|
279
|
+
export {
|
|
280
|
+
createQMetryError,
|
|
281
|
+
handleQMetryApiError,
|
|
282
|
+
handleQMetryFetchError
|
|
283
|
+
};
|