@frontmcp/adapters 0.7.2 → 0.8.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/openapi/index.js CHANGED
@@ -29,7 +29,9 @@ var __decorateClass = (decorators, target, key, kind) => {
29
29
  var openapi_exports = {};
30
30
  __export(openapi_exports, {
31
31
  FRONTMCP_EXTENSION_KEY: () => FRONTMCP_EXTENSION_KEY,
32
- default: () => OpenapiAdapter
32
+ default: () => OpenapiAdapter,
33
+ forceJwtSecurity: () => forceJwtSecurity,
34
+ removeSecurityFromOperations: () => removeSecurityFromOperations
33
35
  });
34
36
  module.exports = __toCommonJS(openapi_exports);
35
37
 
@@ -149,9 +151,6 @@ function applyAdditionalHeaders(headers, additionalHeaders) {
149
151
  var DEFAULT_MAX_RESPONSE_SIZE = 10 * 1024 * 1024;
150
152
  async function parseResponse(response, options) {
151
153
  const maxSize = options?.maxResponseSize ?? DEFAULT_MAX_RESPONSE_SIZE;
152
- if (!response.ok) {
153
- throw new Error(`API request failed: ${response.status}`);
154
- }
155
154
  const contentLength = response.headers.get("content-length");
156
155
  if (contentLength) {
157
156
  const length = parseInt(contentLength, 10);
@@ -165,14 +164,29 @@ async function parseResponse(response, options) {
165
164
  throw new Error(`Response size (${byteSize} bytes) exceeds maximum allowed (${maxSize} bytes)`);
166
165
  }
167
166
  const contentType = response.headers.get("content-type");
167
+ let data;
168
168
  if (contentType?.toLowerCase().includes("application/json")) {
169
169
  try {
170
- return { data: JSON.parse(text) };
170
+ data = JSON.parse(text);
171
171
  } catch {
172
- return { data: text };
172
+ data = text;
173
173
  }
174
+ } else {
175
+ data = text;
176
+ }
177
+ if (!response.ok) {
178
+ return {
179
+ status: response.status,
180
+ ok: false,
181
+ data,
182
+ error: typeof data === "object" && data !== null && "message" in data ? String(data.message) : typeof data === "string" ? data : `HTTP ${response.status} error`
183
+ };
174
184
  }
175
- return { data: text };
185
+ return {
186
+ status: response.status,
187
+ ok: true,
188
+ data
189
+ };
176
190
  }
177
191
 
178
192
  // libs/adapters/src/openapi/openapi.security.ts
@@ -598,15 +612,32 @@ function createOpenApiTool(openapiTool, options, logger) {
598
612
  const metadata = openapiTool.metadata;
599
613
  const inputTransforms = metadata.adapter?.inputTransforms ?? [];
600
614
  const toolTransform = metadata.adapter?.toolTransform ?? {};
615
+ const postToolTransform = metadata.adapter?.postToolTransform;
601
616
  const frontmcpValidation = validateFrontMcpExtension(metadata.frontmcp, openapiTool.name, logger);
602
617
  const frontmcpExt = frontmcpValidation.data;
603
618
  const schemaResult = getZodSchemaFromJsonSchema(openapiTool.inputSchema, openapiTool.name, logger);
619
+ let wrappedOutputSchema;
620
+ if (openapiTool.outputSchema !== void 0) {
621
+ const baseOutputSchema = openapiTool.outputSchema ?? { type: "string" };
622
+ wrappedOutputSchema = {
623
+ type: "object",
624
+ properties: {
625
+ status: { type: "number", description: "HTTP status code" },
626
+ ok: { type: "boolean", description: "Whether the response was successful" },
627
+ data: baseOutputSchema,
628
+ error: { type: "string", description: "Error message for non-ok responses" }
629
+ },
630
+ required: ["status", "ok"]
631
+ };
632
+ }
604
633
  const toolMetadata = {
605
634
  id: openapiTool.name,
606
635
  name: openapiTool.name,
607
636
  description: openapiTool.description,
608
637
  inputSchema: schemaResult.schema.shape || {},
609
- rawInputSchema: openapiTool.inputSchema
638
+ rawInputSchema: openapiTool.inputSchema,
639
+ // Add output schema for tool/list to expose (only if not moved to description)
640
+ ...wrappedOutputSchema && { rawOutputSchema: wrappedOutputSchema }
610
641
  };
611
642
  if (schemaResult.conversionFailed) {
612
643
  toolMetadata["_schemaConversionFailed"] = true;
@@ -719,11 +750,71 @@ function createOpenApiTool(openapiTool, options, logger) {
719
750
  body: serializedBody,
720
751
  signal: controller.signal
721
752
  });
722
- return await parseResponse(response, { maxResponseSize: options.maxResponseSize });
753
+ const apiResponse = await parseResponse(response, { maxResponseSize: options.maxResponseSize });
754
+ let transformedData = apiResponse.data;
755
+ if (postToolTransform) {
756
+ const transformCtx = {
757
+ ctx,
758
+ tool: openapiTool,
759
+ status: apiResponse.status,
760
+ ok: apiResponse.ok,
761
+ adapterOptions: options
762
+ };
763
+ const shouldTransform = postToolTransform.filter ? postToolTransform.filter(transformCtx) : true;
764
+ if (shouldTransform) {
765
+ try {
766
+ transformedData = await postToolTransform.transform(apiResponse.data, transformCtx);
767
+ } catch (err) {
768
+ const errorMessage = err instanceof Error ? err.message : String(err);
769
+ const errorStack = err instanceof Error ? err.stack : void 0;
770
+ logger.error(`[${openapiTool.name}] Post-tool output transform failed`, {
771
+ error: errorMessage,
772
+ stack: errorStack,
773
+ status: apiResponse.status,
774
+ ok: apiResponse.ok
775
+ });
776
+ }
777
+ }
778
+ }
779
+ if (!apiResponse.ok) {
780
+ return {
781
+ content: [
782
+ {
783
+ type: "text",
784
+ text: JSON.stringify({
785
+ status: apiResponse.status,
786
+ error: apiResponse.error,
787
+ data: transformedData
788
+ })
789
+ }
790
+ ],
791
+ isError: true,
792
+ _meta: {
793
+ status: apiResponse.status,
794
+ errorCode: "OPENAPI_ERROR"
795
+ }
796
+ };
797
+ }
798
+ return {
799
+ status: apiResponse.status,
800
+ ok: true,
801
+ data: transformedData
802
+ };
723
803
  } catch (err) {
724
804
  if (err instanceof Error && err.name === "AbortError") {
725
- throw new Error(`Request timeout after ${requestTimeout}ms for tool '${openapiTool.name}'`);
805
+ const timeoutError = new Error(`Request timeout after ${requestTimeout}ms for tool '${openapiTool.name}'`);
806
+ logger.error(`[${openapiTool.name}] API request timeout`, {
807
+ timeout: requestTimeout,
808
+ url,
809
+ method: openapiTool.metadata.method.toUpperCase()
810
+ });
811
+ throw timeoutError;
726
812
  }
813
+ logger.error(`[${openapiTool.name}] API request failed`, {
814
+ url,
815
+ method: openapiTool.metadata.method.toUpperCase(),
816
+ error: err instanceof Error ? { name: err.name, message: err.message, stack: err.stack } : err
817
+ });
727
818
  throw err;
728
819
  } finally {
729
820
  clearTimeout(timeoutId);
@@ -894,6 +985,15 @@ Add one of the following to your adapter configuration:
894
985
  if (this.options.inputTransforms) {
895
986
  transformedTools = transformedTools.map((tool2) => this.applyInputTransforms(tool2));
896
987
  }
988
+ if (this.options.schemaTransforms) {
989
+ transformedTools = transformedTools.map((tool2) => this.applySchemaTransforms(tool2));
990
+ }
991
+ const dataTransforms = this.options.dataTransforms || this.options.outputTransforms;
992
+ if (this.options.outputSchema || dataTransforms) {
993
+ transformedTools = await Promise.all(
994
+ transformedTools.map((tool2) => this.applyOutputSchemaOptions(tool2, dataTransforms))
995
+ );
996
+ }
897
997
  const tools = transformedTools.map((openapiTool) => createOpenApiTool(openapiTool, this.options, this.logger));
898
998
  return { tools };
899
999
  }
@@ -1163,6 +1263,251 @@ ${opDescription}`;
1163
1263
  }
1164
1264
  };
1165
1265
  }
1266
+ /**
1267
+ * Apply schema transforms to an OpenAPI tool.
1268
+ * Modifies input and output schema definitions.
1269
+ * @private
1270
+ */
1271
+ applySchemaTransforms(tool2) {
1272
+ const opts = this.options.schemaTransforms;
1273
+ if (!opts) return tool2;
1274
+ const ctx = {
1275
+ tool: tool2,
1276
+ adapterOptions: this.options
1277
+ };
1278
+ let newInputSchema = tool2.inputSchema;
1279
+ let newOutputSchema = tool2.outputSchema;
1280
+ if (opts.input) {
1281
+ const inputTransform = this.collectInputSchemaTransform(tool2);
1282
+ if (inputTransform) {
1283
+ newInputSchema = inputTransform(newInputSchema, ctx);
1284
+ }
1285
+ }
1286
+ if (opts.output) {
1287
+ const outputTransform = this.collectOutputSchemaTransform(tool2);
1288
+ if (outputTransform) {
1289
+ newOutputSchema = outputTransform(newOutputSchema, ctx);
1290
+ }
1291
+ }
1292
+ if (newInputSchema === tool2.inputSchema && newOutputSchema === tool2.outputSchema) {
1293
+ return tool2;
1294
+ }
1295
+ this.logger.debug(`Applied schema transforms to '${tool2.name}'`);
1296
+ return {
1297
+ ...tool2,
1298
+ inputSchema: newInputSchema,
1299
+ outputSchema: newOutputSchema
1300
+ };
1301
+ }
1302
+ /**
1303
+ * Collect input schema transform for a specific tool.
1304
+ * @private
1305
+ */
1306
+ collectInputSchemaTransform(tool2) {
1307
+ const opts = this.options.schemaTransforms?.input;
1308
+ if (!opts) return void 0;
1309
+ if (opts.generator) {
1310
+ const generated = opts.generator(tool2);
1311
+ if (generated) return generated;
1312
+ }
1313
+ if (opts.perTool?.[tool2.name]) {
1314
+ return opts.perTool[tool2.name];
1315
+ }
1316
+ return opts.global;
1317
+ }
1318
+ /**
1319
+ * Collect output schema transform for a specific tool.
1320
+ * @private
1321
+ */
1322
+ collectOutputSchemaTransform(tool2) {
1323
+ const opts = this.options.schemaTransforms?.output;
1324
+ if (!opts) return void 0;
1325
+ if (opts.generator) {
1326
+ const generated = opts.generator(tool2);
1327
+ if (generated) return generated;
1328
+ }
1329
+ if (opts.perTool?.[tool2.name]) {
1330
+ return opts.perTool[tool2.name];
1331
+ }
1332
+ return opts.global;
1333
+ }
1334
+ /**
1335
+ * Apply output schema options to an OpenAPI tool.
1336
+ * Handles output schema mode and async description formatting.
1337
+ * @private
1338
+ */
1339
+ async applyOutputSchemaOptions(tool2, dataTransforms) {
1340
+ const outputSchemaOpts = this.options.outputSchema;
1341
+ let newDescription = tool2.description;
1342
+ let newOutputSchema = tool2.outputSchema;
1343
+ const mode = outputSchemaOpts?.mode ?? "definition";
1344
+ if (newOutputSchema && (mode === "description" || mode === "both")) {
1345
+ const descriptionFormat = outputSchemaOpts?.descriptionFormat ?? "summary";
1346
+ const formatter = outputSchemaOpts?.descriptionFormatter;
1347
+ const formatterCtx = {
1348
+ tool: tool2,
1349
+ adapterOptions: this.options,
1350
+ originalDescription: tool2.description
1351
+ };
1352
+ let schemaText;
1353
+ if (formatter) {
1354
+ schemaText = await Promise.resolve(formatter(newOutputSchema, formatterCtx));
1355
+ } else {
1356
+ schemaText = this.formatSchemaForDescription(newOutputSchema, descriptionFormat);
1357
+ }
1358
+ newDescription = tool2.description + schemaText;
1359
+ }
1360
+ if (mode === "description") {
1361
+ newOutputSchema = void 0;
1362
+ }
1363
+ const preTransform = this.collectPreToolTransformsFromDataTransforms(tool2, dataTransforms);
1364
+ if (preTransform) {
1365
+ const ctx = {
1366
+ tool: tool2,
1367
+ adapterOptions: this.options
1368
+ };
1369
+ if (preTransform.transformSchema) {
1370
+ newOutputSchema = preTransform.transformSchema(newOutputSchema, ctx);
1371
+ }
1372
+ if (preTransform.transformDescription) {
1373
+ newDescription = preTransform.transformDescription(newDescription, newOutputSchema, ctx);
1374
+ }
1375
+ }
1376
+ const postTransform = this.collectPostToolTransformsFromDataTransforms(tool2, dataTransforms);
1377
+ if (newDescription === tool2.description && newOutputSchema === tool2.outputSchema && !postTransform) {
1378
+ return tool2;
1379
+ }
1380
+ this.logger.debug(`Applied output schema options to '${tool2.name}' (mode: ${mode})`);
1381
+ const metadataRecord = tool2.metadata;
1382
+ const existingAdapter = metadataRecord["adapter"];
1383
+ return {
1384
+ ...tool2,
1385
+ description: newDescription,
1386
+ outputSchema: newOutputSchema,
1387
+ metadata: {
1388
+ ...tool2.metadata,
1389
+ adapter: {
1390
+ ...existingAdapter || {},
1391
+ ...postTransform && { postToolTransform: postTransform }
1392
+ }
1393
+ }
1394
+ };
1395
+ }
1396
+ /**
1397
+ * Format schema for description based on mode.
1398
+ * @private
1399
+ */
1400
+ formatSchemaForDescription(schema, mode) {
1401
+ switch (mode) {
1402
+ case "jsonSchema":
1403
+ return `
1404
+
1405
+ ## Output Schema
1406
+ \`\`\`json
1407
+ ${JSON.stringify(schema, null, 2)}
1408
+ \`\`\``;
1409
+ case "summary":
1410
+ return `
1411
+
1412
+ ## Returns
1413
+ ${this.formatSchemaAsSummary(schema)}`;
1414
+ default:
1415
+ return `
1416
+
1417
+ ## Returns
1418
+ ${this.formatSchemaAsSummary(schema)}`;
1419
+ }
1420
+ }
1421
+ /**
1422
+ * Collect pre-tool transforms from dataTransforms options.
1423
+ * @private
1424
+ */
1425
+ collectPreToolTransformsFromDataTransforms(tool2, dataTransforms) {
1426
+ const opts = dataTransforms?.preToolTransforms;
1427
+ if (!opts) return void 0;
1428
+ let result;
1429
+ if (opts.global) {
1430
+ result = { ...opts.global };
1431
+ }
1432
+ if (opts.perTool?.[tool2.name]) {
1433
+ result = { ...result, ...opts.perTool[tool2.name] };
1434
+ }
1435
+ if (opts.generator) {
1436
+ const generated = opts.generator(tool2);
1437
+ if (generated) {
1438
+ result = { ...result, ...generated };
1439
+ }
1440
+ }
1441
+ return result;
1442
+ }
1443
+ /**
1444
+ * Collect post-tool transforms from dataTransforms options.
1445
+ * @private
1446
+ */
1447
+ collectPostToolTransformsFromDataTransforms(tool2, dataTransforms) {
1448
+ const opts = dataTransforms?.postToolTransforms;
1449
+ if (!opts) return void 0;
1450
+ let result;
1451
+ if (opts.global) {
1452
+ result = { ...opts.global };
1453
+ }
1454
+ if (opts.perTool?.[tool2.name]) {
1455
+ const perTool = opts.perTool[tool2.name];
1456
+ result = result ? {
1457
+ transform: perTool.transform,
1458
+ filter: perTool.filter ?? result.filter
1459
+ } : perTool;
1460
+ }
1461
+ if (opts.generator) {
1462
+ const generated = opts.generator(tool2);
1463
+ if (generated) {
1464
+ result = result ? {
1465
+ transform: generated.transform,
1466
+ filter: generated.filter ?? result.filter
1467
+ } : generated;
1468
+ }
1469
+ }
1470
+ return result;
1471
+ }
1472
+ /**
1473
+ * Format JSON Schema as human-readable summary.
1474
+ * @private
1475
+ */
1476
+ formatSchemaAsSummary(schema) {
1477
+ const lines = [];
1478
+ if (schema.type === "object" && schema.properties) {
1479
+ const required = new Set(schema.required || []);
1480
+ for (const [name, propSchema] of Object.entries(schema.properties)) {
1481
+ const isRequired = required.has(name);
1482
+ const typeStr = this.getSchemaTypeString(propSchema);
1483
+ const desc = propSchema.description ? ` - ${propSchema.description}` : "";
1484
+ const reqStr = isRequired ? " (required)" : " (optional)";
1485
+ lines.push(`- **${name}**: ${typeStr}${reqStr}${desc}`);
1486
+ }
1487
+ } else if (schema.type === "array" && schema.items) {
1488
+ const itemType = this.getSchemaTypeString(schema.items);
1489
+ lines.push(`Array of ${itemType}`);
1490
+ } else {
1491
+ lines.push(this.getSchemaTypeString(schema));
1492
+ }
1493
+ return lines.join("\n");
1494
+ }
1495
+ /**
1496
+ * Get human-readable type string from JSON Schema.
1497
+ * @private
1498
+ */
1499
+ getSchemaTypeString(schema) {
1500
+ if (schema.type === "array") {
1501
+ return schema.items ? `${this.getSchemaTypeString(schema.items)}[]` : "array";
1502
+ }
1503
+ if (schema.type === "object") {
1504
+ return schema.title || "object";
1505
+ }
1506
+ if (Array.isArray(schema.type)) {
1507
+ return schema.type.join(" | ");
1508
+ }
1509
+ return schema.type || "any";
1510
+ }
1166
1511
  };
1167
1512
  OpenapiAdapter = __decorateClass([
1168
1513
  (0, import_sdk2.Adapter)({
@@ -1173,7 +1518,110 @@ OpenapiAdapter = __decorateClass([
1173
1518
 
1174
1519
  // libs/adapters/src/openapi/openapi.types.ts
1175
1520
  var FRONTMCP_EXTENSION_KEY = "x-frontmcp";
1521
+
1522
+ // libs/adapters/src/openapi/openapi.spec-utils.ts
1523
+ function deepClone(obj) {
1524
+ return JSON.parse(JSON.stringify(obj));
1525
+ }
1526
+ function forceJwtSecurity(spec, options = {}) {
1527
+ const result = deepClone(spec);
1528
+ const {
1529
+ schemeName = "BearerAuth",
1530
+ schemeType = "bearer",
1531
+ apiKeyIn = "header",
1532
+ apiKeyName = "X-API-Key",
1533
+ operations,
1534
+ description
1535
+ } = options;
1536
+ if (!result.components) {
1537
+ result.components = {};
1538
+ }
1539
+ if (!result.components.securitySchemes) {
1540
+ result.components.securitySchemes = {};
1541
+ }
1542
+ let securityScheme;
1543
+ switch (schemeType) {
1544
+ case "bearer":
1545
+ securityScheme = {
1546
+ type: "http",
1547
+ scheme: "bearer",
1548
+ bearerFormat: "JWT",
1549
+ description: description ?? "JWT Bearer token authentication"
1550
+ };
1551
+ break;
1552
+ case "apiKey":
1553
+ securityScheme = {
1554
+ type: "apiKey",
1555
+ in: apiKeyIn,
1556
+ name: apiKeyName,
1557
+ description: description ?? `API Key authentication via ${apiKeyIn}`
1558
+ };
1559
+ break;
1560
+ case "basic":
1561
+ securityScheme = {
1562
+ type: "http",
1563
+ scheme: "basic",
1564
+ description: description ?? "HTTP Basic authentication"
1565
+ };
1566
+ break;
1567
+ default:
1568
+ throw new Error(`Unsupported scheme type: ${schemeType}`);
1569
+ }
1570
+ result.components.securitySchemes[schemeName] = securityScheme;
1571
+ const securityRequirement = {
1572
+ [schemeName]: []
1573
+ };
1574
+ if (!result.paths) {
1575
+ return result;
1576
+ }
1577
+ const operationSet = operations ? new Set(operations) : null;
1578
+ for (const [, pathItem] of Object.entries(result.paths)) {
1579
+ if (!pathItem) continue;
1580
+ const methods = ["get", "put", "post", "delete", "options", "head", "patch", "trace"];
1581
+ for (const method of methods) {
1582
+ const operation = pathItem[method];
1583
+ if (!operation) continue;
1584
+ if (operationSet) {
1585
+ if (!operation.operationId || !operationSet.has(operation.operationId)) {
1586
+ continue;
1587
+ }
1588
+ }
1589
+ if (!operation.security) {
1590
+ operation.security = [];
1591
+ }
1592
+ const hasSecurityRequirement = operation.security.some((req) => Object.keys(req).includes(schemeName));
1593
+ if (!hasSecurityRequirement) {
1594
+ operation.security.push(securityRequirement);
1595
+ }
1596
+ }
1597
+ }
1598
+ return result;
1599
+ }
1600
+ function removeSecurityFromOperations(spec, operations) {
1601
+ const result = deepClone(spec);
1602
+ if (!result.paths) {
1603
+ return result;
1604
+ }
1605
+ const operationSet = operations ? new Set(operations) : null;
1606
+ for (const [, pathItem] of Object.entries(result.paths)) {
1607
+ if (!pathItem) continue;
1608
+ const methods = ["get", "put", "post", "delete", "options", "head", "patch", "trace"];
1609
+ for (const method of methods) {
1610
+ const operation = pathItem[method];
1611
+ if (!operation) continue;
1612
+ if (operationSet) {
1613
+ if (!operation.operationId || !operationSet.has(operation.operationId)) {
1614
+ continue;
1615
+ }
1616
+ }
1617
+ operation.security = [];
1618
+ }
1619
+ }
1620
+ return result;
1621
+ }
1176
1622
  // Annotate the CommonJS export names for ESM import in node:
1177
1623
  0 && (module.exports = {
1178
- FRONTMCP_EXTENSION_KEY
1624
+ FRONTMCP_EXTENSION_KEY,
1625
+ forceJwtSecurity,
1626
+ removeSecurityFromOperations
1179
1627
  });
@@ -48,5 +48,52 @@ export default class OpenapiAdapter extends DynamicAdapter<OpenApiAdapterOptions
48
48
  * @private
49
49
  */
50
50
  private filterSecuritySchemes;
51
+ /**
52
+ * Apply schema transforms to an OpenAPI tool.
53
+ * Modifies input and output schema definitions.
54
+ * @private
55
+ */
56
+ private applySchemaTransforms;
57
+ /**
58
+ * Collect input schema transform for a specific tool.
59
+ * @private
60
+ */
61
+ private collectInputSchemaTransform;
62
+ /**
63
+ * Collect output schema transform for a specific tool.
64
+ * @private
65
+ */
66
+ private collectOutputSchemaTransform;
67
+ /**
68
+ * Apply output schema options to an OpenAPI tool.
69
+ * Handles output schema mode and async description formatting.
70
+ * @private
71
+ */
72
+ private applyOutputSchemaOptions;
73
+ /**
74
+ * Format schema for description based on mode.
75
+ * @private
76
+ */
77
+ private formatSchemaForDescription;
78
+ /**
79
+ * Collect pre-tool transforms from dataTransforms options.
80
+ * @private
81
+ */
82
+ private collectPreToolTransformsFromDataTransforms;
83
+ /**
84
+ * Collect post-tool transforms from dataTransforms options.
85
+ * @private
86
+ */
87
+ private collectPostToolTransformsFromDataTransforms;
88
+ /**
89
+ * Format JSON Schema as human-readable summary.
90
+ * @private
91
+ */
92
+ private formatSchemaAsSummary;
93
+ /**
94
+ * Get human-readable type string from JSON Schema.
95
+ * @private
96
+ */
97
+ private getSchemaTypeString;
51
98
  }
52
99
  //# sourceMappingURL=openapi.adapter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"openapi.adapter.d.ts","sourceRoot":"","sources":["../../src/openapi/openapi.adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,cAAc,EAAE,uBAAuB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACjG,OAAO,EAAE,qBAAqB,EAAyD,MAAM,iBAAiB,CAAC;AA2B/G,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,cAAc,CAAC,qBAAqB,CAAC;IAC/E,OAAO,CAAC,SAAS,CAAC,CAAuB;IACzC,OAAO,CAAC,MAAM,CAAiB;IACxB,OAAO,EAAE,qBAAqB,CAAC;gBAE1B,OAAO,EAAE,qBAAqB;IAO1C;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI;IAIjC,KAAK,IAAI,OAAO,CAAC,uBAAuB,CAAC;IAkG/C;;;OAGG;YACW,mBAAmB;IAqBjC;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IA0C5B;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IA4D7B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAsC3B;;;OAGG;IACH,OAAO,CAAC,wBAAwB;IAuBhC;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;IAoD5B;;;;OAIG;IACH,OAAO,CAAC,qBAAqB;CA0D9B"}
1
+ {"version":3,"file":"openapi.adapter.d.ts","sourceRoot":"","sources":["../../src/openapi/openapi.adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,cAAc,EAAE,uBAAuB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACjG,OAAO,EACL,qBAAqB,EAWtB,MAAM,iBAAiB,CAAC;AA2BzB,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,cAAc,CAAC,qBAAqB,CAAC;IAC/E,OAAO,CAAC,SAAS,CAAC,CAAuB;IACzC,OAAO,CAAC,MAAM,CAAiB;IACxB,OAAO,EAAE,qBAAqB,CAAC;gBAE1B,OAAO,EAAE,qBAAqB;IAO1C;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI;IAIjC,KAAK,IAAI,OAAO,CAAC,uBAAuB,CAAC;IAgH/C;;;OAGG;YACW,mBAAmB;IAqBjC;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IA0C5B;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IA4D7B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAsC3B;;;OAGG;IACH,OAAO,CAAC,wBAAwB;IAuBhC;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;IAoD5B;;;;OAIG;IACH,OAAO,CAAC,qBAAqB;IA2D7B;;;;OAIG;IACH,OAAO,CAAC,qBAAqB;IA0C7B;;;OAGG;IACH,OAAO,CAAC,2BAA2B;IAiBnC;;;OAGG;IACH,OAAO,CAAC,4BAA4B;IAmBpC;;;;OAIG;YACW,wBAAwB;IAiFtC;;;OAGG;IACH,OAAO,CAAC,0BAA0B;IAgBlC;;;OAGG;IACH,OAAO,CAAC,0CAA0C;IA8BlD;;;OAGG;IACH,OAAO,CAAC,2CAA2C;IAyCnD;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAuB7B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;CAY5B"}
@@ -0,0 +1,86 @@
1
+ import type { OpenAPIV3, OpenAPIV3_1 } from 'openapi-types';
2
+ /**
3
+ * Options for forcing security on OpenAPI operations
4
+ */
5
+ export interface ForceSecurityOptions {
6
+ /**
7
+ * Security scheme name to add/override.
8
+ * @default 'BearerAuth'
9
+ */
10
+ schemeName?: string;
11
+ /**
12
+ * Security scheme type.
13
+ * - 'bearer': HTTP Bearer authentication (JWT)
14
+ * - 'apiKey': API Key authentication
15
+ * - 'basic': HTTP Basic authentication
16
+ * @default 'bearer'
17
+ */
18
+ schemeType?: 'bearer' | 'apiKey' | 'basic';
19
+ /**
20
+ * For apiKey type: where to send the API key.
21
+ * @default 'header'
22
+ */
23
+ apiKeyIn?: 'header' | 'query' | 'cookie';
24
+ /**
25
+ * For apiKey type: the name of the header/query/cookie.
26
+ * @default 'X-API-Key'
27
+ */
28
+ apiKeyName?: string;
29
+ /**
30
+ * Apply security only to these operation IDs.
31
+ * If not specified, applies to all operations.
32
+ */
33
+ operations?: string[];
34
+ /**
35
+ * Description for the security scheme.
36
+ */
37
+ description?: string;
38
+ }
39
+ type OpenAPIDocument = OpenAPIV3.Document | OpenAPIV3_1.Document;
40
+ /**
41
+ * Modify OpenAPI spec to force JWT/Bearer security on operations.
42
+ * Returns a new spec object (does not mutate input).
43
+ *
44
+ * @param spec - Original OpenAPI specification
45
+ * @param options - Security configuration options
46
+ * @returns Modified OpenAPI specification with security applied
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * import { forceJwtSecurity } from '@frontmcp/adapters/openapi';
51
+ *
52
+ * // Force Bearer auth on all operations
53
+ * const securedSpec = forceJwtSecurity(originalSpec);
54
+ *
55
+ * // Force Bearer auth with custom scheme name
56
+ * const securedSpec = forceJwtSecurity(originalSpec, {
57
+ * schemeName: 'JWTAuth',
58
+ * description: 'JWT Bearer token authentication'
59
+ * });
60
+ *
61
+ * // Force auth on specific operations only
62
+ * const securedSpec = forceJwtSecurity(originalSpec, {
63
+ * operations: ['createUser', 'updateUser', 'deleteUser']
64
+ * });
65
+ *
66
+ * // Force API Key auth
67
+ * const securedSpec = forceJwtSecurity(originalSpec, {
68
+ * schemeName: 'ApiKeyAuth',
69
+ * schemeType: 'apiKey',
70
+ * apiKeyIn: 'header',
71
+ * apiKeyName: 'X-API-Key'
72
+ * });
73
+ * ```
74
+ */
75
+ export declare function forceJwtSecurity(spec: OpenAPIDocument, options?: ForceSecurityOptions): OpenAPIDocument;
76
+ /**
77
+ * Remove security requirements from specific operations.
78
+ * Returns a new spec object (does not mutate input).
79
+ *
80
+ * @param spec - Original OpenAPI specification
81
+ * @param operations - Operation IDs to remove security from. If not specified, removes from all.
82
+ * @returns Modified OpenAPI specification
83
+ */
84
+ export declare function removeSecurityFromOperations(spec: OpenAPIDocument, operations?: string[]): OpenAPIDocument;
85
+ export {};
86
+ //# sourceMappingURL=openapi.spec-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openapi.spec-utils.d.ts","sourceRoot":"","sources":["../../src/openapi/openapi.spec-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5D;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;IAE3C;;;OAGG;IACH,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;IAEzC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IAEtB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,KAAK,eAAe,GAAG,SAAS,CAAC,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC;AAUjE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,eAAe,EAAE,OAAO,GAAE,oBAAyB,GAAG,eAAe,CAuG3G;AAED;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,eAAe,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,eAAe,CAgC1G"}
@@ -1 +1 @@
1
- {"version":3,"file":"openapi.tool.d.ts","sourceRoot":"","sources":["../../src/openapi/openapi.tool.ts"],"names":[],"mappings":"AACA,OAAO,EAAQ,cAAc,EAAE,MAAM,eAAe,CAAC;AAErD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EACV,qBAAqB,EAItB,MAAM,iBAAiB,CAAC;AASzB;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,cAAc,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,EAAE,cAAc,cAgLpH"}
1
+ {"version":3,"file":"openapi.tool.d.ts","sourceRoot":"","sources":["../../src/openapi/openapi.tool.ts"],"names":[],"mappings":"AACA,OAAO,EAAQ,cAAc,EAAE,MAAM,eAAe,CAAC;AAErD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EACV,qBAAqB,EAKtB,MAAM,iBAAiB,CAAC;AASzB;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,cAAc,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,EAAE,cAAc,cA+QpH"}