mcp4openapi 0.1.0 → 0.2.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 +137 -95
- package/dist/scripts/validate-profile.js +3 -3
- package/dist/scripts/validate-profile.js.map +1 -1
- package/dist/src/composite-executor.d.ts +3 -1
- package/dist/src/composite-executor.d.ts.map +1 -1
- package/dist/src/composite-executor.js +16 -5
- package/dist/src/composite-executor.js.map +1 -1
- package/dist/src/constants.d.ts +49 -0
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +49 -0
- package/dist/src/constants.js.map +1 -1
- package/dist/src/errors.d.ts +6 -0
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +13 -0
- package/dist/src/errors.js.map +1 -1
- package/dist/src/generated-schemas.d.ts +832 -52
- package/dist/src/generated-schemas.d.ts.map +1 -1
- package/dist/src/generated-schemas.js +31 -8
- package/dist/src/generated-schemas.js.map +1 -1
- package/dist/src/http-client-factory.d.ts.map +1 -1
- package/dist/src/http-client-factory.js +14 -3
- package/dist/src/http-client-factory.js.map +1 -1
- package/dist/src/http-transport.d.ts +65 -0
- package/dist/src/http-transport.d.ts.map +1 -1
- package/dist/src/http-transport.js +921 -77
- package/dist/src/http-transport.js.map +1 -1
- package/dist/src/index.js +108 -8
- package/dist/src/index.js.map +1 -1
- package/dist/src/interceptors.d.ts +3 -0
- package/dist/src/interceptors.d.ts.map +1 -1
- package/dist/src/interceptors.js +76 -8
- package/dist/src/interceptors.js.map +1 -1
- package/dist/src/logger.d.ts +1 -1
- package/dist/src/logger.js +3 -3
- package/dist/src/logger.js.map +1 -1
- package/dist/src/mcp-server.d.ts +33 -0
- package/dist/src/mcp-server.d.ts.map +1 -1
- package/dist/src/mcp-server.js +263 -54
- package/dist/src/mcp-server.js.map +1 -1
- package/dist/src/oauth-provider.d.ts +92 -0
- package/dist/src/oauth-provider.d.ts.map +1 -0
- package/dist/src/oauth-provider.js +588 -0
- package/dist/src/oauth-provider.js.map +1 -0
- package/dist/src/openapi-parser.d.ts +16 -0
- package/dist/src/openapi-parser.d.ts.map +1 -1
- package/dist/src/openapi-parser.js +141 -6
- package/dist/src/openapi-parser.js.map +1 -1
- package/dist/src/profile-loader.d.ts +2 -2
- package/dist/src/profile-loader.d.ts.map +1 -1
- package/dist/src/profile-loader.js +45 -24
- package/dist/src/profile-loader.js.map +1 -1
- package/dist/src/testing/fixtures.d.ts +189 -0
- package/dist/src/testing/fixtures.d.ts.map +1 -1
- package/dist/src/testing/fixtures.js +144 -0
- package/dist/src/testing/fixtures.js.map +1 -1
- package/dist/src/testing/mock-gitlab-server.d.ts +26 -17
- package/dist/src/testing/mock-gitlab-server.d.ts.map +1 -1
- package/dist/src/testing/mock-gitlab-server.js +567 -304
- package/dist/src/testing/mock-gitlab-server.js.map +1 -1
- package/dist/src/types/http-transport.d.ts +16 -0
- package/dist/src/types/http-transport.d.ts.map +1 -1
- package/dist/src/types/openapi.d.ts +5 -0
- package/dist/src/types/openapi.d.ts.map +1 -1
- package/dist/src/types/profile.d.ts +112 -3
- package/dist/src/types/profile.d.ts.map +1 -1
- package/dist/src/validation-utils.d.ts +12 -0
- package/dist/src/validation-utils.d.ts.map +1 -1
- package/dist/src/validation-utils.js +17 -0
- package/dist/src/validation-utils.js.map +1 -1
- package/package.json +12 -3
- package/profile-schema.json +169 -7
- package/dist/composite-executor.d.ts +0 -65
- package/dist/composite-executor.d.ts.map +0 -1
- package/dist/composite-executor.js +0 -147
- package/dist/composite-executor.js.map +0 -1
- package/dist/constants.d.ts +0 -36
- package/dist/constants.d.ts.map +0 -1
- package/dist/constants.js +0 -36
- package/dist/constants.js.map +0 -1
- package/dist/http-transport.d.ts +0 -195
- package/dist/http-transport.d.ts.map +0 -1
- package/dist/http-transport.js +0 -760
- package/dist/http-transport.js.map +0 -1
- package/dist/interceptors.d.ts +0 -74
- package/dist/interceptors.d.ts.map +0 -1
- package/dist/interceptors.js +0 -220
- package/dist/interceptors.js.map +0 -1
- package/dist/logger.d.ts +0 -81
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js +0 -264
- package/dist/logger.js.map +0 -1
- package/dist/mcp-server.d.ts +0 -110
- package/dist/mcp-server.d.ts.map +0 -1
- package/dist/mcp-server.js +0 -568
- package/dist/mcp-server.js.map +0 -1
- package/dist/metrics.d.ts +0 -86
- package/dist/metrics.d.ts.map +0 -1
- package/dist/metrics.js +0 -229
- package/dist/metrics.js.map +0 -1
- package/dist/openapi-parser.d.ts +0 -35
- package/dist/openapi-parser.d.ts.map +0 -1
- package/dist/openapi-parser.js +0 -160
- package/dist/openapi-parser.js.map +0 -1
- package/dist/profile-loader.d.ts +0 -25
- package/dist/profile-loader.d.ts.map +0 -1
- package/dist/profile-loader.js +0 -134
- package/dist/profile-loader.js.map +0 -1
- package/dist/schema-validator.d.ts +0 -32
- package/dist/schema-validator.d.ts.map +0 -1
- package/dist/schema-validator.js +0 -126
- package/dist/schema-validator.js.map +0 -1
- package/dist/testing/fixtures.d.ts +0 -186
- package/dist/testing/fixtures.d.ts.map +0 -1
- package/dist/testing/fixtures.js +0 -135
- package/dist/testing/fixtures.js.map +0 -1
- package/dist/testing/http-integration.test.d.ts +0 -7
- package/dist/testing/http-integration.test.d.ts.map +0 -1
- package/dist/testing/http-integration.test.js +0 -383
- package/dist/testing/http-integration.test.js.map +0 -1
- package/dist/testing/http-multiuser.test.d.ts +0 -10
- package/dist/testing/http-multiuser.test.d.ts.map +0 -1
- package/dist/testing/http-multiuser.test.js +0 -255
- package/dist/testing/http-multiuser.test.js.map +0 -1
- package/dist/testing/integration.test.d.ts +0 -8
- package/dist/testing/integration.test.d.ts.map +0 -1
- package/dist/testing/integration.test.js +0 -247
- package/dist/testing/integration.test.js.map +0 -1
- package/dist/testing/mock-gitlab-server.d.ts +0 -34
- package/dist/testing/mock-gitlab-server.d.ts.map +0 -1
- package/dist/testing/mock-gitlab-server.js +0 -224
- package/dist/testing/mock-gitlab-server.js.map +0 -1
- package/dist/testing/test-types.d.ts +0 -59
- package/dist/testing/test-types.d.ts.map +0 -1
- package/dist/testing/test-types.js +0 -7
- package/dist/testing/test-types.js.map +0 -1
- package/dist/tool-generator.d.ts +0 -43
- package/dist/tool-generator.d.ts.map +0 -1
- package/dist/tool-generator.js +0 -123
- package/dist/tool-generator.js.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/dist/types/http-transport.d.ts +0 -39
- package/dist/types/http-transport.d.ts.map +0 -1
- package/dist/types/http-transport.js +0 -8
- package/dist/types/http-transport.js.map +0 -1
- package/dist/types/openapi.d.ts +0 -50
- package/dist/types/openapi.d.ts.map +0 -1
- package/dist/types/openapi.js +0 -9
- package/dist/types/openapi.js.map +0 -1
- package/dist/types/profile.d.ts +0 -76
- package/dist/types/profile.d.ts.map +0 -1
- package/dist/types/profile.js +0 -9
- package/dist/types/profile.js.map +0 -1
package/profile-schema.json
CHANGED
|
@@ -30,6 +30,17 @@
|
|
|
30
30
|
}
|
|
31
31
|
]
|
|
32
32
|
},
|
|
33
|
+
"resource_name": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"description": "OAuth 2.0 Protected Resource name (overrides OpenAPI info.title). Defaults to 'MCP Server' if not specified.",
|
|
36
|
+
"examples": ["GitLab Production API", "GitHub Enterprise API"]
|
|
37
|
+
},
|
|
38
|
+
"resource_documentation": {
|
|
39
|
+
"type": "string",
|
|
40
|
+
"format": "uri",
|
|
41
|
+
"description": "OAuth 2.0 Protected Resource documentation URL (overrides OpenAPI externalDocs.url). Omitted if not specified.",
|
|
42
|
+
"examples": ["https://docs.gitlab.com/ee/api/", "https://docs.github.com/rest"]
|
|
43
|
+
},
|
|
33
44
|
"tools": {
|
|
34
45
|
"type": "array",
|
|
35
46
|
"description": "List of MCP tools defined in this profile",
|
|
@@ -217,7 +228,19 @@
|
|
|
217
228
|
"description": "HTTP interceptor configuration (auth, rate limiting, retry)",
|
|
218
229
|
"properties": {
|
|
219
230
|
"auth": {
|
|
220
|
-
"
|
|
231
|
+
"oneOf": [
|
|
232
|
+
{
|
|
233
|
+
"$ref": "#/definitions/Auth"
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
"type": "array",
|
|
237
|
+
"items": {
|
|
238
|
+
"$ref": "#/definitions/Auth"
|
|
239
|
+
},
|
|
240
|
+
"minItems": 1,
|
|
241
|
+
"description": "Multiple authentication methods (tried in order of priority)"
|
|
242
|
+
}
|
|
243
|
+
]
|
|
221
244
|
},
|
|
222
245
|
"base_url": {
|
|
223
246
|
"$ref": "#/definitions/BaseUrl"
|
|
@@ -239,18 +262,25 @@
|
|
|
239
262
|
},
|
|
240
263
|
"Auth": {
|
|
241
264
|
"type": "object",
|
|
242
|
-
"required": ["type"
|
|
265
|
+
"required": ["type"],
|
|
243
266
|
"properties": {
|
|
244
267
|
"type": {
|
|
245
268
|
"type": "string",
|
|
246
|
-
"enum": ["bearer", "query", "custom-header"],
|
|
269
|
+
"enum": ["bearer", "query", "custom-header", "oauth"],
|
|
247
270
|
"description": "Authentication type"
|
|
248
271
|
},
|
|
272
|
+
"priority": {
|
|
273
|
+
"type": "integer",
|
|
274
|
+
"description": "Priority for multi-auth (lower = higher priority). Default: 0. Used when multiple auth methods are configured.",
|
|
275
|
+
"default": 0,
|
|
276
|
+
"minimum": 0,
|
|
277
|
+
"examples": [0, 1, 2]
|
|
278
|
+
},
|
|
249
279
|
"value_from_env": {
|
|
250
280
|
"type": "string",
|
|
251
|
-
"description": "Environment variable name containing the auth token",
|
|
281
|
+
"description": "Environment variable name containing the auth token (required for bearer, query, custom-header)",
|
|
252
282
|
"pattern": "^[A-Z][A-Z0-9_]*$",
|
|
253
|
-
"examples": ["
|
|
283
|
+
"examples": ["MCP4_API_TOKEN", "GITLAB_TOKEN"]
|
|
254
284
|
},
|
|
255
285
|
"header_name": {
|
|
256
286
|
"type": "string",
|
|
@@ -261,9 +291,48 @@
|
|
|
261
291
|
"type": "string",
|
|
262
292
|
"description": "Query parameter name (required for query type)",
|
|
263
293
|
"examples": ["api_key", "token"]
|
|
294
|
+
},
|
|
295
|
+
"oauth_config": {
|
|
296
|
+
"$ref": "#/definitions/OAuthConfig"
|
|
297
|
+
},
|
|
298
|
+
"oauth_rate_limit": {
|
|
299
|
+
"type": "object",
|
|
300
|
+
"description": "OAuth rate limiting configuration. Overrides default OAuth rate limits (10 requests per 15 minutes).",
|
|
301
|
+
"properties": {
|
|
302
|
+
"max_requests": {
|
|
303
|
+
"type": "number",
|
|
304
|
+
"description": "Maximum number of OAuth requests allowed per window",
|
|
305
|
+
"minimum": 1,
|
|
306
|
+
"examples": [10, 20, 50]
|
|
307
|
+
},
|
|
308
|
+
"window_ms": {
|
|
309
|
+
"type": "number",
|
|
310
|
+
"description": "Rate limit window in milliseconds",
|
|
311
|
+
"minimum": 1000,
|
|
312
|
+
"examples": [900000, 1800000, 3600000]
|
|
313
|
+
}
|
|
314
|
+
},
|
|
315
|
+
"required": ["max_requests", "window_ms"]
|
|
264
316
|
}
|
|
265
317
|
},
|
|
266
318
|
"allOf": [
|
|
319
|
+
{
|
|
320
|
+
"if": {
|
|
321
|
+
"properties": {
|
|
322
|
+
"type": {
|
|
323
|
+
"enum": ["bearer", "query", "custom-header"]
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
},
|
|
327
|
+
"then": {
|
|
328
|
+
"required": ["value_from_env"],
|
|
329
|
+
"properties": {
|
|
330
|
+
"value_from_env": {
|
|
331
|
+
"type": "string"
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
},
|
|
267
336
|
{
|
|
268
337
|
"if": {
|
|
269
338
|
"properties": {
|
|
@@ -297,9 +366,102 @@
|
|
|
297
366
|
}
|
|
298
367
|
}
|
|
299
368
|
}
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
"if": {
|
|
372
|
+
"properties": {
|
|
373
|
+
"type": {
|
|
374
|
+
"const": "oauth"
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
},
|
|
378
|
+
"then": {
|
|
379
|
+
"required": ["oauth_config"],
|
|
380
|
+
"properties": {
|
|
381
|
+
"oauth_config": {
|
|
382
|
+
"$ref": "#/definitions/OAuthConfig"
|
|
383
|
+
},
|
|
384
|
+
"oauth_rate_limit": {
|
|
385
|
+
"type": "object",
|
|
386
|
+
"description": "OAuth rate limiting configuration. Overrides default OAuth rate limits (10 requests per 15 minutes).",
|
|
387
|
+
"properties": {
|
|
388
|
+
"max_requests": {
|
|
389
|
+
"type": "number",
|
|
390
|
+
"description": "Maximum number of OAuth requests allowed per window",
|
|
391
|
+
"minimum": 1
|
|
392
|
+
},
|
|
393
|
+
"window_ms": {
|
|
394
|
+
"type": "number",
|
|
395
|
+
"description": "Rate limit window in milliseconds",
|
|
396
|
+
"minimum": 1000
|
|
397
|
+
}
|
|
398
|
+
},
|
|
399
|
+
"required": ["max_requests", "window_ms"]
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
300
403
|
}
|
|
301
404
|
]
|
|
302
405
|
},
|
|
406
|
+
"OAuthConfig": {
|
|
407
|
+
"type": "object",
|
|
408
|
+
"description": "OAuth 2.0 configuration. Must provide EITHER 'issuer' (endpoints auto-derived) OR both 'authorization_endpoint' and 'token_endpoint' (explicit).",
|
|
409
|
+
"properties": {
|
|
410
|
+
"issuer": {
|
|
411
|
+
"type": "string",
|
|
412
|
+
"description": "OAuth 2.0 issuer URL (RFC 8414). When provided, authorization_endpoint and token_endpoint are auto-derived via /.well-known/oauth-authorization-server or standard paths. Supports ${env:VAR} syntax.",
|
|
413
|
+
"examples": ["https://gitlab.example.com", "${env:MCP4_OAUTH_ISSUER}"]
|
|
414
|
+
},
|
|
415
|
+
"authorization_endpoint": {
|
|
416
|
+
"type": "string",
|
|
417
|
+
"description": "OAuth 2.0 authorization endpoint. Optional if issuer is provided. Supports ${env:VAR} syntax.",
|
|
418
|
+
"examples": ["https://gitlab.example.com/oauth/authorize", "${env:OAUTH_AUTHORIZATION_URL}"]
|
|
419
|
+
},
|
|
420
|
+
"token_endpoint": {
|
|
421
|
+
"type": "string",
|
|
422
|
+
"description": "OAuth 2.0 token endpoint. Optional if issuer is provided. Supports ${env:VAR} syntax.",
|
|
423
|
+
"examples": ["https://gitlab.example.com/oauth/token", "${env:OAUTH_TOKEN_URL}"]
|
|
424
|
+
},
|
|
425
|
+
"client_id": {
|
|
426
|
+
"type": "string",
|
|
427
|
+
"description": "Pre-registered OAuth client ID (supports ${env:VAR} syntax). Optional for dynamic registration.",
|
|
428
|
+
"examples": ["${env:MCP4_OAUTH_CLIENT_ID}"]
|
|
429
|
+
},
|
|
430
|
+
"client_secret": {
|
|
431
|
+
"type": "string",
|
|
432
|
+
"description": "Pre-registered OAuth client secret (supports ${env:VAR} syntax). Optional for public clients.",
|
|
433
|
+
"examples": ["${env:MCP4_OAUTH_CLIENT_SECRET}"]
|
|
434
|
+
},
|
|
435
|
+
"scopes": {
|
|
436
|
+
"type": "array",
|
|
437
|
+
"description": "OAuth 2.0 scopes to request. Optional - if not provided, no scopes will be requested (some APIs don't require scopes)",
|
|
438
|
+
"items": {
|
|
439
|
+
"type": "string"
|
|
440
|
+
},
|
|
441
|
+
"examples": [["api", "read_user"], ["read_repository", "write_repository"]]
|
|
442
|
+
},
|
|
443
|
+
"redirect_uri": {
|
|
444
|
+
"type": "string",
|
|
445
|
+
"description": "OAuth callback URI. Defaults to http://{MCP4_HOST}:{MCP4_PORT}/oauth/callback",
|
|
446
|
+
"examples": ["https://<your-mcp-server-host>/oauth/callback"]
|
|
447
|
+
},
|
|
448
|
+
"registration_endpoint": {
|
|
449
|
+
"type": "string",
|
|
450
|
+
"description": "Client registration endpoint for dynamic registration (RFC 7591)",
|
|
451
|
+
"examples": ["https://gitlab.example.com/oauth/register"]
|
|
452
|
+
},
|
|
453
|
+
"introspection_endpoint": {
|
|
454
|
+
"type": "string",
|
|
455
|
+
"description": "Token introspection endpoint (RFC 7662)",
|
|
456
|
+
"examples": ["https://gitlab.example.com/oauth/introspect"]
|
|
457
|
+
},
|
|
458
|
+
"revocation_endpoint": {
|
|
459
|
+
"type": "string",
|
|
460
|
+
"description": "Token revocation endpoint (RFC 7009)",
|
|
461
|
+
"examples": ["https://gitlab.example.com/oauth/revoke"]
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
},
|
|
303
465
|
"BaseUrl": {
|
|
304
466
|
"type": "object",
|
|
305
467
|
"required": ["value_from_env"],
|
|
@@ -308,13 +470,13 @@
|
|
|
308
470
|
"type": "string",
|
|
309
471
|
"description": "Environment variable name containing the base URL",
|
|
310
472
|
"pattern": "^[A-Z][A-Z0-9_]*$",
|
|
311
|
-
"examples": ["
|
|
473
|
+
"examples": ["MCP4_API_BASE_URL"]
|
|
312
474
|
},
|
|
313
475
|
"default": {
|
|
314
476
|
"type": "string",
|
|
315
477
|
"format": "uri",
|
|
316
478
|
"description": "Default base URL if environment variable is not set",
|
|
317
|
-
"examples": ["https://gitlab.com/api/v4"]
|
|
479
|
+
"examples": ["https://www.gitlab.com/api/v4"]
|
|
318
480
|
}
|
|
319
481
|
}
|
|
320
482
|
},
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Composite action executor for chaining API calls
|
|
3
|
-
*
|
|
4
|
-
* Why: Reduces roundtrips by fetching related data in sequence (e.g., MR + comments).
|
|
5
|
-
* Aggregates results into single JSON structure as defined by store_as paths.
|
|
6
|
-
*/
|
|
7
|
-
import type { CompositeStep } from './types/profile.js';
|
|
8
|
-
import type { HttpClient } from './interceptors.js';
|
|
9
|
-
import { OpenAPIParser } from './openapi-parser.js';
|
|
10
|
-
export interface CompositeResult {
|
|
11
|
-
data: Record<string, unknown>;
|
|
12
|
-
completed_steps: number;
|
|
13
|
-
total_steps: number;
|
|
14
|
-
errors?: StepError[];
|
|
15
|
-
}
|
|
16
|
-
export interface StepError {
|
|
17
|
-
step_index: number;
|
|
18
|
-
step_call: string;
|
|
19
|
-
error: string;
|
|
20
|
-
timestamp: string;
|
|
21
|
-
}
|
|
22
|
-
export declare class CompositeExecutor {
|
|
23
|
-
private parser;
|
|
24
|
-
private httpClient?;
|
|
25
|
-
constructor(parser: OpenAPIParser, httpClient?: HttpClient);
|
|
26
|
-
/**
|
|
27
|
-
* Execute a series of API calls and merge results
|
|
28
|
-
*
|
|
29
|
-
* Why sequential: Steps may depend on previous results (e.g., get MR ID, then fetch comments).
|
|
30
|
-
* Could parallelize independent steps in future optimization.
|
|
31
|
-
*
|
|
32
|
-
* Supports partial results: If allowPartial=true, continues after errors and returns
|
|
33
|
-
* what was completed. Useful for composite actions where some data is better than none.
|
|
34
|
-
*/
|
|
35
|
-
execute(steps: CompositeStep[], args: Record<string, unknown>, allowPartial?: boolean, httpClient?: HttpClient): Promise<CompositeResult>;
|
|
36
|
-
/**
|
|
37
|
-
* Parse composite step call syntax
|
|
38
|
-
*
|
|
39
|
-
* Format: "GET /projects/{id}/merge_requests/{iid}"
|
|
40
|
-
*/
|
|
41
|
-
private parseCall;
|
|
42
|
-
/**
|
|
43
|
-
* Resolve path template with actual values
|
|
44
|
-
*
|
|
45
|
-
* Example: "/projects/{id}" + {id: "123"} => "/projects/123"
|
|
46
|
-
*/
|
|
47
|
-
private resolvePath;
|
|
48
|
-
/**
|
|
49
|
-
* Extract query parameters from args based on operation definition
|
|
50
|
-
*/
|
|
51
|
-
private extractQueryParams;
|
|
52
|
-
/**
|
|
53
|
-
* Store value at JSONPath-like location
|
|
54
|
-
*
|
|
55
|
-
* Why nested: Allows semantic structure (comments belong under merge_request object).
|
|
56
|
-
*
|
|
57
|
-
* Examples:
|
|
58
|
-
* - "merge_request" => { merge_request: value }
|
|
59
|
-
* - "merge_request.comments" => { merge_request: { comments: value } }
|
|
60
|
-
*
|
|
61
|
-
* Validates path navigation to prevent overwriting non-object values.
|
|
62
|
-
*/
|
|
63
|
-
private storeResult;
|
|
64
|
-
}
|
|
65
|
-
//# sourceMappingURL=composite-executor.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"composite-executor.d.ts","sourceRoot":"","sources":["../src/composite-executor.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,iBAAiB;IAE1B,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,UAAU,CAAC;gBADX,MAAM,EAAE,aAAa,EACrB,UAAU,CAAC,EAAE,UAAU;IAGjC;;;;;;;;OAQG;IACG,OAAO,CACX,KAAK,EAAE,aAAa,EAAE,EACtB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,YAAY,GAAE,OAAe,EAC7B,UAAU,CAAC,EAAE,UAAU,GACtB,OAAO,CAAC,eAAe,CAAC;IAoE3B;;;;OAIG;IACH,OAAO,CAAC,SAAS;IAQjB;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAUnB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAkB1B;;;;;;;;;;OAUG;IACH,OAAO,CAAC,WAAW;CAwBpB"}
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Composite action executor for chaining API calls
|
|
3
|
-
*
|
|
4
|
-
* Why: Reduces roundtrips by fetching related data in sequence (e.g., MR + comments).
|
|
5
|
-
* Aggregates results into single JSON structure as defined by store_as paths.
|
|
6
|
-
*/
|
|
7
|
-
export class CompositeExecutor {
|
|
8
|
-
parser;
|
|
9
|
-
httpClient;
|
|
10
|
-
constructor(parser, httpClient) {
|
|
11
|
-
this.parser = parser;
|
|
12
|
-
this.httpClient = httpClient;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Execute a series of API calls and merge results
|
|
16
|
-
*
|
|
17
|
-
* Why sequential: Steps may depend on previous results (e.g., get MR ID, then fetch comments).
|
|
18
|
-
* Could parallelize independent steps in future optimization.
|
|
19
|
-
*
|
|
20
|
-
* Supports partial results: If allowPartial=true, continues after errors and returns
|
|
21
|
-
* what was completed. Useful for composite actions where some data is better than none.
|
|
22
|
-
*/
|
|
23
|
-
async execute(steps, args, allowPartial = false, httpClient) {
|
|
24
|
-
const result = {};
|
|
25
|
-
const errors = [];
|
|
26
|
-
let completedSteps = 0;
|
|
27
|
-
for (let i = 0; i < steps.length; i++) {
|
|
28
|
-
const step = steps[i];
|
|
29
|
-
try {
|
|
30
|
-
const { method, path, operation } = this.parseCall(step.call);
|
|
31
|
-
if (!operation) {
|
|
32
|
-
throw new Error(`Operation not found for call: ${step.call}`);
|
|
33
|
-
}
|
|
34
|
-
// Substitute path parameters from args
|
|
35
|
-
const resolvedPath = this.resolvePath(path, args);
|
|
36
|
-
// Execute request
|
|
37
|
-
const client = httpClient || this.httpClient;
|
|
38
|
-
if (!client) {
|
|
39
|
-
throw new Error('HTTP client not provided');
|
|
40
|
-
}
|
|
41
|
-
const response = await client.request(method, resolvedPath, {
|
|
42
|
-
params: this.extractQueryParams(operation, args),
|
|
43
|
-
});
|
|
44
|
-
// Store result at specified path
|
|
45
|
-
this.storeResult(result, step.store_as, response.body);
|
|
46
|
-
completedSteps++;
|
|
47
|
-
}
|
|
48
|
-
catch (error) {
|
|
49
|
-
const stepError = {
|
|
50
|
-
step_index: i,
|
|
51
|
-
step_call: step.call,
|
|
52
|
-
error: error instanceof Error ? error.message : String(error),
|
|
53
|
-
timestamp: new Date().toISOString(),
|
|
54
|
-
};
|
|
55
|
-
errors.push(stepError);
|
|
56
|
-
// Store error in result for debugging
|
|
57
|
-
this.storeResult(result, `${step.store_as}_error`, stepError);
|
|
58
|
-
if (!allowPartial) {
|
|
59
|
-
throw new Error(`Composite step ${i + 1}/${steps.length} failed: ${stepError.error}\n` +
|
|
60
|
-
`Completed steps: ${completedSteps}\n` +
|
|
61
|
-
`Failed step: ${step.call}`);
|
|
62
|
-
}
|
|
63
|
-
// Continue with next step if partial results allowed
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
return {
|
|
67
|
-
data: result,
|
|
68
|
-
completed_steps: completedSteps,
|
|
69
|
-
total_steps: steps.length,
|
|
70
|
-
errors: errors.length > 0 ? errors : undefined,
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Parse composite step call syntax
|
|
75
|
-
*
|
|
76
|
-
* Format: "GET /projects/{id}/merge_requests/{iid}"
|
|
77
|
-
*/
|
|
78
|
-
parseCall(call) {
|
|
79
|
-
const [method, path] = call.split(' ');
|
|
80
|
-
const pathInfo = this.parser.getPath(path);
|
|
81
|
-
const operation = pathInfo?.operations[method.toLowerCase()];
|
|
82
|
-
return { method, path, operation };
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Resolve path template with actual values
|
|
86
|
-
*
|
|
87
|
-
* Example: "/projects/{id}" + {id: "123"} => "/projects/123"
|
|
88
|
-
*/
|
|
89
|
-
resolvePath(template, args) {
|
|
90
|
-
return template.replace(/\{(\w+)\}/g, (_, key) => {
|
|
91
|
-
const value = args[key];
|
|
92
|
-
if (value === undefined) {
|
|
93
|
-
throw new Error(`Missing path parameter: ${key}`);
|
|
94
|
-
}
|
|
95
|
-
return String(value);
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Extract query parameters from args based on operation definition
|
|
100
|
-
*/
|
|
101
|
-
extractQueryParams(operation, args) {
|
|
102
|
-
const params = {};
|
|
103
|
-
for (const param of operation.parameters) {
|
|
104
|
-
if (param.in === 'query' && args[param.name] !== undefined) {
|
|
105
|
-
const value = args[param.name];
|
|
106
|
-
// Pass arrays as-is for HttpClient serialization
|
|
107
|
-
if (Array.isArray(value)) {
|
|
108
|
-
params[param.name] = value.map(String);
|
|
109
|
-
}
|
|
110
|
-
else {
|
|
111
|
-
params[param.name] = String(value);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
return params;
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Store value at JSONPath-like location
|
|
119
|
-
*
|
|
120
|
-
* Why nested: Allows semantic structure (comments belong under merge_request object).
|
|
121
|
-
*
|
|
122
|
-
* Examples:
|
|
123
|
-
* - "merge_request" => { merge_request: value }
|
|
124
|
-
* - "merge_request.comments" => { merge_request: { comments: value } }
|
|
125
|
-
*
|
|
126
|
-
* Validates path navigation to prevent overwriting non-object values.
|
|
127
|
-
*/
|
|
128
|
-
storeResult(target, path, value) {
|
|
129
|
-
const parts = path.split('.');
|
|
130
|
-
let current = target;
|
|
131
|
-
for (let i = 0; i < parts.length - 1; i++) {
|
|
132
|
-
const part = parts[i];
|
|
133
|
-
const existing = current[part];
|
|
134
|
-
// Validate we can navigate through this path
|
|
135
|
-
if (existing !== undefined && (typeof existing !== 'object' || existing === null)) {
|
|
136
|
-
throw new Error(`Cannot store at path '${path}': ` +
|
|
137
|
-
`'${parts.slice(0, i + 1).join('.')}' is ${typeof existing}, not an object`);
|
|
138
|
-
}
|
|
139
|
-
if (!current[part]) {
|
|
140
|
-
current[part] = {};
|
|
141
|
-
}
|
|
142
|
-
current = current[part];
|
|
143
|
-
}
|
|
144
|
-
current[parts[parts.length - 1]] = value;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
//# sourceMappingURL=composite-executor.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"composite-executor.js","sourceRoot":"","sources":["../src/composite-executor.ts"],"names":[],"mappings":"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"}
|
package/dist/constants.d.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Application constants
|
|
3
|
-
*
|
|
4
|
-
* Why: Centralized constants improve readability and maintainability.
|
|
5
|
-
* Magic numbers scattered through code are harder to understand and change.
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* Time conversion constants
|
|
9
|
-
*/
|
|
10
|
-
export declare const TIME: {
|
|
11
|
-
readonly MS_PER_SECOND: 1000;
|
|
12
|
-
readonly MS_PER_MINUTE: 60000;
|
|
13
|
-
readonly MS_PER_HOUR: 3600000;
|
|
14
|
-
readonly SECONDS_PER_MINUTE: 60;
|
|
15
|
-
readonly MINUTES_PER_HOUR: 60;
|
|
16
|
-
};
|
|
17
|
-
/**
|
|
18
|
-
* HTTP status codes
|
|
19
|
-
*
|
|
20
|
-
* Why: Named constants more readable than numeric literals.
|
|
21
|
-
* Makes intent clear (STATUS_TOO_MANY_REQUESTS vs 429).
|
|
22
|
-
*/
|
|
23
|
-
export declare const HTTP_STATUS: {
|
|
24
|
-
readonly OK: 200;
|
|
25
|
-
readonly MULTIPLE_CHOICES: 300;
|
|
26
|
-
readonly BAD_REQUEST: 400;
|
|
27
|
-
readonly UNAUTHORIZED: 401;
|
|
28
|
-
readonly FORBIDDEN: 403;
|
|
29
|
-
readonly NOT_FOUND: 404;
|
|
30
|
-
readonly TOO_MANY_REQUESTS: 429;
|
|
31
|
-
readonly INTERNAL_SERVER_ERROR: 500;
|
|
32
|
-
readonly BAD_GATEWAY: 502;
|
|
33
|
-
readonly SERVICE_UNAVAILABLE: 503;
|
|
34
|
-
readonly GATEWAY_TIMEOUT: 504;
|
|
35
|
-
};
|
|
36
|
-
//# sourceMappingURL=constants.d.ts.map
|
package/dist/constants.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,eAAO,MAAM,IAAI;;;;;;CAMP,CAAC;AAEX;;;;;GAKG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;CAYd,CAAC"}
|
package/dist/constants.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Application constants
|
|
3
|
-
*
|
|
4
|
-
* Why: Centralized constants improve readability and maintainability.
|
|
5
|
-
* Magic numbers scattered through code are harder to understand and change.
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* Time conversion constants
|
|
9
|
-
*/
|
|
10
|
-
export const TIME = {
|
|
11
|
-
MS_PER_SECOND: 1000,
|
|
12
|
-
MS_PER_MINUTE: 60000,
|
|
13
|
-
MS_PER_HOUR: 3600000,
|
|
14
|
-
SECONDS_PER_MINUTE: 60,
|
|
15
|
-
MINUTES_PER_HOUR: 60,
|
|
16
|
-
};
|
|
17
|
-
/**
|
|
18
|
-
* HTTP status codes
|
|
19
|
-
*
|
|
20
|
-
* Why: Named constants more readable than numeric literals.
|
|
21
|
-
* Makes intent clear (STATUS_TOO_MANY_REQUESTS vs 429).
|
|
22
|
-
*/
|
|
23
|
-
export const HTTP_STATUS = {
|
|
24
|
-
OK: 200,
|
|
25
|
-
MULTIPLE_CHOICES: 300,
|
|
26
|
-
BAD_REQUEST: 400,
|
|
27
|
-
UNAUTHORIZED: 401,
|
|
28
|
-
FORBIDDEN: 403,
|
|
29
|
-
NOT_FOUND: 404,
|
|
30
|
-
TOO_MANY_REQUESTS: 429,
|
|
31
|
-
INTERNAL_SERVER_ERROR: 500,
|
|
32
|
-
BAD_GATEWAY: 502,
|
|
33
|
-
SERVICE_UNAVAILABLE: 503,
|
|
34
|
-
GATEWAY_TIMEOUT: 504,
|
|
35
|
-
};
|
|
36
|
-
//# sourceMappingURL=constants.js.map
|
package/dist/constants.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG;IAClB,aAAa,EAAE,IAAI;IACnB,aAAa,EAAE,KAAK;IACpB,WAAW,EAAE,OAAO;IACpB,kBAAkB,EAAE,EAAE;IACtB,gBAAgB,EAAE,EAAE;CACZ,CAAC;AAEX;;;;;GAKG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,EAAE,EAAE,GAAG;IACP,gBAAgB,EAAE,GAAG;IACrB,WAAW,EAAE,GAAG;IAChB,YAAY,EAAE,GAAG;IACjB,SAAS,EAAE,GAAG;IACd,SAAS,EAAE,GAAG;IACd,iBAAiB,EAAE,GAAG;IACtB,qBAAqB,EAAE,GAAG;IAC1B,WAAW,EAAE,GAAG;IAChB,mBAAmB,EAAE,GAAG;IACxB,eAAe,EAAE,GAAG;CACZ,CAAC"}
|