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