@smartbear/mcp 0.12.1 → 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 +156 -93
- package/dist/bugsnag/client/api/Project.js +398 -276
- 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 -1281
- 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,191 +1,173 @@
|
|
|
1
|
-
import { ToolError } from "../../../common/
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
if (key in obj) {
|
|
9
|
-
result[key] = obj[key];
|
|
10
|
-
}
|
|
1
|
+
import { ToolError } from "../../../common/tools.js";
|
|
2
|
+
function pickFields(obj, keys) {
|
|
3
|
+
const result = {};
|
|
4
|
+
if (!obj) return result;
|
|
5
|
+
for (const key of keys) {
|
|
6
|
+
if (key in obj) {
|
|
7
|
+
result[key] = obj[key];
|
|
11
8
|
}
|
|
12
|
-
|
|
9
|
+
}
|
|
10
|
+
return result;
|
|
13
11
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
return arr.map((obj) => pickFields(obj, keys));
|
|
12
|
+
function pickFieldsFromArray(arr, keys) {
|
|
13
|
+
return arr.map((obj) => pickFields(obj, keys));
|
|
17
14
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const match = link.match(/<([^>]+)>;\s*rel="next"/)?.[1];
|
|
26
|
-
if (!match)
|
|
27
|
-
return null;
|
|
28
|
-
return match.replace(basePath, "");
|
|
15
|
+
function getNextUrlPathFromHeader(headers, basePath) {
|
|
16
|
+
if (!headers) return null;
|
|
17
|
+
const link = headers.get("link") || headers.get("Link");
|
|
18
|
+
if (!link) return null;
|
|
19
|
+
const match = link.match(/<([^>]+)>;\s*rel="next"/)?.[1];
|
|
20
|
+
if (!match) return null;
|
|
21
|
+
return match.replace(basePath, "");
|
|
29
22
|
}
|
|
30
|
-
// Utility to extract total count from headers
|
|
31
23
|
function getTotalCountFromHeader(headers) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
24
|
+
if (!headers) return null;
|
|
25
|
+
const totalCount = headers.get("X-Total-Count");
|
|
26
|
+
if (!totalCount) return null;
|
|
27
|
+
const parsed = parseInt(totalCount, 10);
|
|
28
|
+
return Number.isNaN(parsed) ? null : parsed;
|
|
29
|
+
}
|
|
30
|
+
function ensureFullUrl(url, basePath) {
|
|
31
|
+
return url.startsWith("http") ? url : `${basePath}${url}`;
|
|
39
32
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
33
|
+
function getQueryParams(nextUrl, options) {
|
|
34
|
+
const nextOptions = { query: {} };
|
|
35
|
+
if (nextUrl) {
|
|
36
|
+
nextOptions.query = {};
|
|
37
|
+
if (!nextUrl.includes("?")) {
|
|
38
|
+
throw new Error("nextUrl must contains query parameters");
|
|
44
39
|
}
|
|
45
|
-
|
|
46
|
-
|
|
40
|
+
new URLSearchParams(nextUrl.split("?")[1]).forEach((value, key) => {
|
|
41
|
+
nextOptions.query[key] = value;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return nextOptions;
|
|
45
|
+
}
|
|
46
|
+
class BaseAPI {
|
|
47
|
+
configuration;
|
|
48
|
+
filterFields;
|
|
49
|
+
constructor(configuration, filterFields) {
|
|
50
|
+
this.configuration = configuration;
|
|
51
|
+
this.filterFields = filterFields || [];
|
|
52
|
+
}
|
|
53
|
+
async requestObject(url, options = {}, fields) {
|
|
54
|
+
if (!this.configuration.basePath) {
|
|
55
|
+
throw new Error("Base path is not configured for API requests");
|
|
47
56
|
}
|
|
48
|
-
if (
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
return converted;
|
|
57
|
+
if (this.configuration.headers) {
|
|
58
|
+
options.headers = {
|
|
59
|
+
...this.configuration.headers,
|
|
60
|
+
...options.headers
|
|
61
|
+
};
|
|
55
62
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
// Merge nextUrl query parameters with options query parameters (usually filters)
|
|
65
|
-
export function getQueryParams(nextUrl, options) {
|
|
66
|
-
const nextOptions = { query: {} };
|
|
67
|
-
if (nextUrl) {
|
|
68
|
-
nextOptions.query = {};
|
|
69
|
-
if (!nextUrl.includes("?")) {
|
|
70
|
-
throw new Error("nextUrl must contains query parameters");
|
|
63
|
+
const response = await fetch(
|
|
64
|
+
ensureFullUrl(url, this.configuration.basePath),
|
|
65
|
+
{
|
|
66
|
+
...options,
|
|
67
|
+
headers: {
|
|
68
|
+
...options.headers,
|
|
69
|
+
...this.configuration.headers
|
|
71
70
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
}
|
|
72
|
+
);
|
|
73
|
+
if (!response.ok) {
|
|
74
|
+
const errorText = await response.text();
|
|
75
|
+
throw new Error(
|
|
76
|
+
`Request failed with status ${response.status}: ${errorText}`
|
|
77
|
+
);
|
|
75
78
|
}
|
|
76
|
-
|
|
77
|
-
|
|
79
|
+
const apiResponse = {
|
|
80
|
+
status: response.status,
|
|
81
|
+
headers: response.headers,
|
|
82
|
+
body: await response.json()
|
|
83
|
+
};
|
|
84
|
+
if (fields) {
|
|
85
|
+
apiResponse.body = pickFields(apiResponse.body, fields);
|
|
78
86
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
export class BaseAPI {
|
|
82
|
-
configuration;
|
|
83
|
-
filterFields;
|
|
84
|
-
constructor(configuration, filterFields) {
|
|
85
|
-
this.configuration = configuration;
|
|
86
|
-
this.filterFields = filterFields || [];
|
|
87
|
+
if (this.filterFields) {
|
|
88
|
+
this.sanitizeResponse(apiResponse.body);
|
|
87
89
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
90
|
+
return apiResponse;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Fetches an array of resources from the API with support for pagination and field filtering.
|
|
94
|
+
*
|
|
95
|
+
* @template T - The type of objects in the response array, must extend Record<string, any>
|
|
96
|
+
* @param url - The API endpoint URL to fetch data from
|
|
97
|
+
* @param options - Optional request configuration including headers and other fetch options
|
|
98
|
+
* @param fetchAll - Whether to automatically fetch all pages of paginated results (default: false)
|
|
99
|
+
* @param fields - Optional array of field names to include in the response objects
|
|
100
|
+
* @returns A Promise resolving to an ApiResponse containing an array of type T
|
|
101
|
+
*
|
|
102
|
+
* @throws {ToolError} When the HTTP request fails with a non-ok status
|
|
103
|
+
* @throws {Error} When the response data is not an array
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```typescript
|
|
107
|
+
* const response = await client.requestArray<User>('/users', {}, true, ['id', 'name']);
|
|
108
|
+
* console.log(response.body); // Array of User objects with only id and name fields
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
async requestArray(url, options = {}, fetchAll = true, fields) {
|
|
112
|
+
let results = [];
|
|
113
|
+
let nextUrl = url;
|
|
114
|
+
let apiResponse;
|
|
115
|
+
do {
|
|
116
|
+
nextUrl = ensureFullUrl(nextUrl, this.configuration.basePath);
|
|
117
|
+
const response = await fetch(nextUrl, {
|
|
118
|
+
...options,
|
|
119
|
+
headers: {
|
|
120
|
+
...options.headers,
|
|
121
|
+
...this.configuration.headers
|
|
91
122
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
this.sanitizeResponse(apiResponse.body);
|
|
119
|
-
}
|
|
120
|
-
return apiResponse;
|
|
123
|
+
});
|
|
124
|
+
if (!response.ok) {
|
|
125
|
+
const errorText = await response.text();
|
|
126
|
+
throw new ToolError(
|
|
127
|
+
`Request failed with status ${response.status}: ${errorText}`
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
const data = await response.json();
|
|
131
|
+
nextUrl = getNextUrlPathFromHeader(
|
|
132
|
+
response.headers,
|
|
133
|
+
this.configuration.basePath
|
|
134
|
+
);
|
|
135
|
+
if (!Array.isArray(data)) {
|
|
136
|
+
throw new Error("Expected response to be an array");
|
|
137
|
+
}
|
|
138
|
+
results = results.concat(data);
|
|
139
|
+
apiResponse = {
|
|
140
|
+
status: response.status,
|
|
141
|
+
headers: response.headers,
|
|
142
|
+
nextUrl,
|
|
143
|
+
totalCount: getTotalCountFromHeader(response.headers),
|
|
144
|
+
body: results
|
|
145
|
+
};
|
|
146
|
+
} while (fetchAll && nextUrl);
|
|
147
|
+
if (fields) {
|
|
148
|
+
apiResponse.body = pickFieldsFromArray(apiResponse.body, fields);
|
|
121
149
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
* @param url - The API endpoint URL to fetch data from
|
|
127
|
-
* @param options - Optional request configuration including headers and other fetch options
|
|
128
|
-
* @param fetchAll - Whether to automatically fetch all pages of paginated results (default: false)
|
|
129
|
-
* @param fields - Optional array of field names to include in the response objects
|
|
130
|
-
* @returns A Promise resolving to an ApiResponse containing an array of type T
|
|
131
|
-
*
|
|
132
|
-
* @throws {ToolError} When the HTTP request fails with a non-ok status
|
|
133
|
-
* @throws {Error} When the response data is not an array
|
|
134
|
-
*
|
|
135
|
-
* @example
|
|
136
|
-
* ```typescript
|
|
137
|
-
* const response = await client.requestArray<User>('/users', {}, true, ['id', 'name']);
|
|
138
|
-
* console.log(response.body); // Array of User objects with only id and name fields
|
|
139
|
-
* ```
|
|
140
|
-
*/
|
|
141
|
-
async requestArray(url, options = {}, fetchAll = true, fields) {
|
|
142
|
-
let results = [];
|
|
143
|
-
let nextUrl = url;
|
|
144
|
-
let apiResponse;
|
|
145
|
-
do {
|
|
146
|
-
nextUrl = ensureFullUrl(nextUrl, this.configuration.basePath);
|
|
147
|
-
const response = await fetch(nextUrl, {
|
|
148
|
-
...options,
|
|
149
|
-
headers: {
|
|
150
|
-
...options.headers,
|
|
151
|
-
...this.configuration.headers,
|
|
152
|
-
},
|
|
153
|
-
});
|
|
154
|
-
if (!response.ok) {
|
|
155
|
-
const errorText = await response.text();
|
|
156
|
-
throw new ToolError(`Request failed with status ${response.status}: ${errorText}`);
|
|
157
|
-
}
|
|
158
|
-
const data = convertKeysToCamelCase(await response.json());
|
|
159
|
-
nextUrl = getNextUrlPathFromHeader(response.headers, this.configuration.basePath);
|
|
160
|
-
if (!Array.isArray(data)) {
|
|
161
|
-
throw new Error("Expected response to be an array");
|
|
162
|
-
}
|
|
163
|
-
results = results.concat(data);
|
|
164
|
-
apiResponse = {
|
|
165
|
-
status: response.status,
|
|
166
|
-
headers: response.headers,
|
|
167
|
-
nextUrl: nextUrl,
|
|
168
|
-
totalCount: getTotalCountFromHeader(response.headers),
|
|
169
|
-
body: results,
|
|
170
|
-
};
|
|
171
|
-
} while (fetchAll && nextUrl);
|
|
172
|
-
if (fields) {
|
|
173
|
-
apiResponse.body = pickFieldsFromArray(apiResponse.body, fields);
|
|
174
|
-
}
|
|
175
|
-
if (this.filterFields) {
|
|
176
|
-
apiResponse.body.forEach((item) => {
|
|
177
|
-
this.sanitizeResponse(item);
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
return apiResponse;
|
|
150
|
+
if (this.filterFields) {
|
|
151
|
+
apiResponse.body.forEach((item) => {
|
|
152
|
+
this.sanitizeResponse(item);
|
|
153
|
+
});
|
|
181
154
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
155
|
+
return apiResponse;
|
|
156
|
+
}
|
|
157
|
+
sanitizeResponse(data) {
|
|
158
|
+
if (!data) return;
|
|
159
|
+
for (const key of this.filterFields) {
|
|
160
|
+
if (key in data) {
|
|
161
|
+
delete data[key];
|
|
162
|
+
}
|
|
190
163
|
}
|
|
164
|
+
}
|
|
191
165
|
}
|
|
166
|
+
export {
|
|
167
|
+
BaseAPI,
|
|
168
|
+
ensureFullUrl,
|
|
169
|
+
getNextUrlPathFromHeader,
|
|
170
|
+
getQueryParams,
|
|
171
|
+
pickFields,
|
|
172
|
+
pickFieldsFromArray
|
|
173
|
+
};
|
|
@@ -1,26 +1,29 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
1
|
+
class Configuration {
|
|
2
|
+
/**
|
|
3
|
+
* parameter for apiKey security
|
|
4
|
+
* @param name security name
|
|
5
|
+
* @memberof Configuration
|
|
6
|
+
*/
|
|
7
|
+
apiKey;
|
|
8
|
+
/**
|
|
9
|
+
* override base path
|
|
10
|
+
*
|
|
11
|
+
* @type {string}
|
|
12
|
+
* @memberof Configuration
|
|
13
|
+
*/
|
|
14
|
+
basePath;
|
|
15
|
+
/**
|
|
16
|
+
* Additional headers for API requests
|
|
17
|
+
* @type {Record<string, string>}
|
|
18
|
+
* @memberof Configuration
|
|
19
|
+
*/
|
|
20
|
+
headers;
|
|
21
|
+
constructor(param) {
|
|
22
|
+
this.apiKey = param.apiKey;
|
|
23
|
+
this.basePath = param.basePath;
|
|
24
|
+
this.headers = param.headers;
|
|
25
|
+
}
|
|
26
26
|
}
|
|
27
|
+
export {
|
|
28
|
+
Configuration
|
|
29
|
+
};
|
|
@@ -1,22 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Converts a FilterObject to URL search parameters
|
|
9
|
-
*
|
|
10
|
-
* @param filters The filter object to convert
|
|
11
|
-
* @returns URLSearchParams object with the encoded filters
|
|
12
|
-
*/
|
|
13
|
-
export function toUrlSearchParams(filters) {
|
|
14
|
-
const params = new URLSearchParams();
|
|
15
|
-
Object.entries(filters).forEach(([field, filterValues]) => {
|
|
16
|
-
filterValues.forEach((filterValue) => {
|
|
17
|
-
params.append(`filters[${field}][][type]`, filterValue.type);
|
|
18
|
-
params.append(`filters[${field}][][value]`, filterValue.value.toString());
|
|
19
|
-
});
|
|
1
|
+
function toUrlSearchParams(filters) {
|
|
2
|
+
const params = new URLSearchParams();
|
|
3
|
+
Object.entries(filters).forEach(([field, filterValues]) => {
|
|
4
|
+
filterValues.forEach((filterValue) => {
|
|
5
|
+
params.append(`filters[${field}][][type]`, filterValue.type);
|
|
6
|
+
params.append(`filters[${field}][][value]`, filterValue.value.toString());
|
|
20
7
|
});
|
|
21
|
-
|
|
8
|
+
});
|
|
9
|
+
return params;
|
|
22
10
|
}
|
|
11
|
+
export {
|
|
12
|
+
toUrlSearchParams
|
|
13
|
+
};
|