mcp-from-openapi 2.6.1 → 2.8.0

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/index.js CHANGED
@@ -30,8 +30,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ ArazzoError: () => ArazzoError,
33
34
  BLOCKED_HOSTNAMES: () => BLOCKED_HOSTNAMES,
34
35
  BUILTIN_FORMAT_RESOLVERS: () => BUILTIN_FORMAT_RESOLVERS,
36
+ CODECALL_RESERVED_NAMESPACES: () => CODECALL_RESERVED_NAMESPACES,
35
37
  GenerationError: () => GenerationError,
36
38
  LoadError: () => LoadError,
37
39
  OpenAPIToolError: () => OpenAPIToolError,
@@ -58,10 +60,14 @@ __export(index_exports, {
58
60
  decodeIpv4MappedIpv6: () => decodeIpv4MappedIpv6,
59
61
  defaultLookup: () => defaultLookup,
60
62
  demoteFormats: () => demoteFormats,
63
+ deriveSecurityElicitations: () => deriveSecurityElicitations,
64
+ dottedNaming: () => dottedNaming,
65
+ emitToolTypeScript: () => emitToolTypeScript,
61
66
  enforceClosedObjects: () => enforceClosedObjects,
62
67
  ensureArrayItems: () => ensureArrayItems,
63
68
  estimateToolTokens: () => estimateToolTokens,
64
69
  extractExtensionOverrides: () => extractExtensionOverrides,
70
+ fromArazzo: () => fromArazzo,
65
71
  inferAnnotationsFromMethod: () => inferAnnotationsFromMethod,
66
72
  inlineLocalRefs: () => inlineLocalRefs,
67
73
  isBlockedAddress: () => isBlockedAddress,
@@ -69,11 +75,13 @@ __export(index_exports, {
69
75
  isReferenceObject: () => isReferenceObject,
70
76
  lintDocument: () => lintDocument,
71
77
  normalizeSsrfOptions: () => normalizeSsrfOptions,
78
+ parseRuntimeExpression: () => parseRuntimeExpression,
72
79
  requireAllProperties: () => requireAllProperties,
73
80
  resolveExtensionEnabled: () => resolveExtensionEnabled,
74
81
  resolveSchemaFormats: () => resolveSchemaFormats,
75
82
  safeFetch: () => safeFetch,
76
83
  toJsonSchema: () => toJsonSchema,
84
+ toPascalIdentifier: () => toPascalIdentifier,
77
85
  toSdkTool: () => toSdkTool
78
86
  });
79
87
  module.exports = __toCommonJS(index_exports);
@@ -86,9 +94,24 @@ function isReferenceObject(obj) {
86
94
  return obj && typeof obj === "object" && "$ref" in obj;
87
95
  }
88
96
  function toJsonSchema(schema) {
97
+ return convertSchema(schema, /* @__PURE__ */ new Set());
98
+ }
99
+ function convertSchema(schema, stack) {
89
100
  if (isReferenceObject(schema)) {
90
101
  return { $ref: schema.$ref };
91
102
  }
103
+ if (stack.has(schema)) {
104
+ return {};
105
+ }
106
+ stack.add(schema);
107
+ try {
108
+ return convertSchemaInner(schema, stack);
109
+ } finally {
110
+ stack.delete(schema);
111
+ }
112
+ }
113
+ function convertSchemaInner(schema, stack) {
114
+ const recurse = (value) => convertSchema(value, stack);
92
115
  const { exclusiveMaximum, exclusiveMinimum, maximum, minimum, ...rest } = schema;
93
116
  const { nullable, example, ...cleanRest } = rest;
94
117
  const result = { ...cleanRest };
@@ -140,34 +163,34 @@ function toJsonSchema(schema) {
140
163
  if (result["properties"] && typeof result["properties"] === "object") {
141
164
  const props = {};
142
165
  for (const [key, value] of Object.entries(result["properties"])) {
143
- props[key] = toJsonSchema(value);
166
+ props[key] = recurse(value);
144
167
  }
145
168
  result["properties"] = props;
146
169
  }
147
170
  if (result["items"]) {
148
171
  if (Array.isArray(result["items"])) {
149
- result["items"] = result["items"].map(toJsonSchema);
172
+ result["items"] = result["items"].map(recurse);
150
173
  } else {
151
- result["items"] = toJsonSchema(result["items"]);
174
+ result["items"] = recurse(result["items"]);
152
175
  }
153
176
  }
154
177
  if (result["additionalProperties"] && typeof result["additionalProperties"] === "object") {
155
- result["additionalProperties"] = toJsonSchema(result["additionalProperties"]);
178
+ result["additionalProperties"] = recurse(result["additionalProperties"]);
156
179
  }
157
180
  for (const key of ["allOf", "anyOf", "oneOf"]) {
158
181
  if (result[key] && Array.isArray(result[key])) {
159
- result[key] = result[key].map(toJsonSchema);
182
+ result[key] = result[key].map(recurse);
160
183
  }
161
184
  }
162
185
  if (result["not"]) {
163
- result["not"] = toJsonSchema(result["not"]);
186
+ result["not"] = recurse(result["not"]);
164
187
  }
165
188
  for (const key of ["patternProperties", "$defs", "definitions", "dependentSchemas"]) {
166
189
  const value = result[key];
167
190
  if (value && typeof value === "object" && !Array.isArray(value)) {
168
191
  const mapped = {};
169
192
  for (const [name, sub] of Object.entries(value)) {
170
- mapped[name] = toJsonSchema(sub);
193
+ mapped[name] = recurse(sub);
171
194
  }
172
195
  result[key] = mapped;
173
196
  }
@@ -184,11 +207,11 @@ function toJsonSchema(schema) {
184
207
  ]) {
185
208
  const value = result[key];
186
209
  if (value && typeof value === "object") {
187
- result[key] = toJsonSchema(value);
210
+ result[key] = recurse(value);
188
211
  }
189
212
  }
190
213
  if (Array.isArray(result["prefixItems"])) {
191
- result["prefixItems"] = result["prefixItems"].map(toJsonSchema);
214
+ result["prefixItems"] = result["prefixItems"].map(recurse);
192
215
  }
193
216
  if (wrapNullable) {
194
217
  const wrapper = {};
@@ -209,8 +232,11 @@ var ParameterResolver = class {
209
232
  namingStrategy;
210
233
  includeExamples;
211
234
  constructor(namingStrategy, options) {
212
- this.namingStrategy = namingStrategy ?? {
213
- conflictResolver: this.defaultConflictResolver
235
+ this.namingStrategy = {
236
+ ...namingStrategy,
237
+ // Bind a supplied resolver to its own strategy object so class-based
238
+ // strategies keep their `this` (we invoke it off a spread clone).
239
+ conflictResolver: namingStrategy?.conflictResolver ? namingStrategy.conflictResolver.bind(namingStrategy) : this.defaultConflictResolver
214
240
  };
215
241
  this.includeExamples = options?.includeExamples ?? false;
216
242
  }
@@ -392,6 +418,9 @@ var ParameterResolver = class {
392
418
  schema["deprecated"] = true;
393
419
  }
394
420
  schema["x-parameter-location"] = param.location;
421
+ if (param.location === "header") {
422
+ schema["x-mcp-header"] = param.name;
423
+ }
395
424
  if (param.style) {
396
425
  schema["x-parameter-style"] = param.style;
397
426
  }
@@ -486,6 +515,9 @@ var ParameterResolver = class {
486
515
  });
487
516
  const schemeInInput = includeInInput === true || Array.isArray(includeInInput) && includeInInput.includes(scheme);
488
517
  if (schemeInInput) {
518
+ if (paramLocation === "header") {
519
+ schema["x-mcp-header"] = headerKey;
520
+ }
489
521
  properties[inputKey] = schema;
490
522
  required.push(inputKey);
491
523
  }
@@ -1158,9 +1190,63 @@ function mergeOverrides(base, layer) {
1158
1190
  ...layer.description !== void 0 && { description: layer.description },
1159
1191
  ...(base.annotations || layer.annotations) && {
1160
1192
  annotations: { ...base.annotations, ...layer.annotations }
1161
- }
1193
+ },
1194
+ ...(base.meta || layer.meta) && { meta: { ...base.meta, ...layer.meta } },
1195
+ ...layer.icons !== void 0 && { icons: layer.icons }
1162
1196
  };
1163
1197
  }
1198
+ function cleanseMeta(node, seen) {
1199
+ if (!node || typeof node !== "object") {
1200
+ return node;
1201
+ }
1202
+ if (seen.has(node)) {
1203
+ return void 0;
1204
+ }
1205
+ seen.add(node);
1206
+ try {
1207
+ if (Array.isArray(node)) {
1208
+ return node.map((item) => cleanseMeta(item, seen));
1209
+ }
1210
+ const out = {};
1211
+ for (const [key, value] of Object.entries(node)) {
1212
+ if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
1213
+ out[key] = cleanseMeta(value, seen);
1214
+ }
1215
+ return out;
1216
+ } finally {
1217
+ seen.delete(node);
1218
+ }
1219
+ }
1220
+ function sanitizeMeta(value) {
1221
+ if (value && typeof value === "object" && !Array.isArray(value)) {
1222
+ return cleanseMeta(value, /* @__PURE__ */ new Set());
1223
+ }
1224
+ return void 0;
1225
+ }
1226
+ function isAllowedIconSrc(src) {
1227
+ const lower = src.toLowerCase();
1228
+ return lower.startsWith("https:") || lower.startsWith("data:");
1229
+ }
1230
+ function sanitizeIcons(value) {
1231
+ if (!Array.isArray(value)) {
1232
+ return void 0;
1233
+ }
1234
+ const icons = [];
1235
+ for (const entry of value) {
1236
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
1237
+ const raw = entry;
1238
+ if (typeof raw["src"] !== "string" || !isAllowedIconSrc(raw["src"])) continue;
1239
+ const icon = { src: raw["src"] };
1240
+ if (typeof raw["mimeType"] === "string") {
1241
+ icon.mimeType = raw["mimeType"];
1242
+ }
1243
+ if (Array.isArray(raw["sizes"]) && raw["sizes"].every((s) => typeof s === "string")) {
1244
+ icon.sizes = [...raw["sizes"]];
1245
+ }
1246
+ icons.push(icon);
1247
+ }
1248
+ return icons.length > 0 ? icons : void 0;
1249
+ }
1164
1250
  function readXMcp(node) {
1165
1251
  return node["x-mcp"];
1166
1252
  }
@@ -1209,16 +1295,24 @@ function extractExtensionOverrides(operation) {
1209
1295
  name: typeof ext["name"] === "string" ? ext["name"] : void 0,
1210
1296
  title: typeof ext["title"] === "string" ? ext["title"] : void 0,
1211
1297
  description: typeof ext["description"] === "string" ? ext["description"] : void 0,
1212
- annotations: pickAnnotations(ext["annotations"])
1298
+ annotations: pickAnnotations(ext["annotations"]),
1299
+ meta: sanitizeMeta(ext["meta"]),
1300
+ icons: sanitizeIcons(ext["icons"])
1213
1301
  });
1214
1302
  }
1215
1303
  const frontmcp = op["x-frontmcp"];
1216
- if (frontmcp && typeof frontmcp === "object" && frontmcp.annotations) {
1217
- const annotations = pickAnnotations(frontmcp.annotations);
1218
- result = mergeOverrides(result, {
1219
- annotations,
1220
- title: typeof frontmcp.annotations.title === "string" ? frontmcp.annotations.title : void 0
1221
- });
1304
+ if (frontmcp && typeof frontmcp === "object") {
1305
+ const layer = {
1306
+ meta: sanitizeMeta(frontmcp.meta),
1307
+ icons: sanitizeIcons(frontmcp.icons)
1308
+ };
1309
+ if (frontmcp.annotations) {
1310
+ layer.annotations = pickAnnotations(frontmcp.annotations);
1311
+ if (typeof frontmcp.annotations.title === "string") {
1312
+ layer.title = frontmcp.annotations.title;
1313
+ }
1314
+ }
1315
+ result = mergeOverrides(result, layer);
1222
1316
  }
1223
1317
  return result;
1224
1318
  }
@@ -1589,6 +1683,13 @@ var RequestBuildError = class extends OpenAPIToolError {
1589
1683
  super(message, context);
1590
1684
  }
1591
1685
  };
1686
+ var ArazzoError = class extends OpenAPIToolError {
1687
+ path;
1688
+ constructor(message, context) {
1689
+ super(message, context);
1690
+ this.path = context?.["path"];
1691
+ }
1692
+ };
1592
1693
  var SchemaError = class extends OpenAPIToolError {
1593
1694
  constructor(message, context) {
1594
1695
  super(message, context);
@@ -2141,7 +2242,8 @@ var Validator = class {
2141
2242
  code: "NO_PATHS"
2142
2243
  });
2143
2244
  } else {
2144
- this.validatePaths(document.paths, errors, warnings);
2245
+ const componentParameters = document.components?.parameters ?? {};
2246
+ this.validatePaths(document.paths, componentParameters, errors, warnings);
2145
2247
  }
2146
2248
  if (!document.servers || document.servers.length === 0) {
2147
2249
  warnings.push({
@@ -2172,7 +2274,18 @@ var Validator = class {
2172
2274
  /**
2173
2275
  * Validate paths
2174
2276
  */
2175
- validatePaths(paths, errors, warnings) {
2277
+ /**
2278
+ * Resolve a local `#/components/parameters/<name>` reference (JSON Pointer
2279
+ * tokens decoded). Returns undefined for external or dangling references.
2280
+ */
2281
+ resolveParameterRef(param, componentParameters) {
2282
+ if (!param || typeof param !== "object" || !("$ref" in param)) return param;
2283
+ const match = /^#\/components\/parameters\/(.+)$/.exec(String(param.$ref));
2284
+ if (!match) return void 0;
2285
+ const name = match[1].replace(/~1/g, "/").replace(/~0/g, "~");
2286
+ return componentParameters[name];
2287
+ }
2288
+ validatePaths(paths, componentParameters, errors, warnings) {
2176
2289
  for (const [path, pathItem] of Object.entries(paths)) {
2177
2290
  if (!pathItem) continue;
2178
2291
  if (!path.startsWith("/")) {
@@ -2184,11 +2297,15 @@ var Validator = class {
2184
2297
  }
2185
2298
  const methods = ["get", "post", "put", "patch", "delete", "head", "options", "trace"];
2186
2299
  let hasOperations = false;
2300
+ const pathLevelParameters = Array.isArray(pathItem.parameters) ? pathItem.parameters : [];
2301
+ if (pathLevelParameters.length > 0) {
2302
+ this.validateParameters(pathLevelParameters, `/paths/${path}/parameters`, errors, warnings);
2303
+ }
2187
2304
  for (const method of methods) {
2188
2305
  const operation = pathItem[method];
2189
2306
  if (operation) {
2190
2307
  hasOperations = true;
2191
- this.validateOperation(operation, path, method, errors, warnings);
2308
+ this.validateOperation(operation, path, method, errors, warnings, pathLevelParameters, componentParameters);
2192
2309
  }
2193
2310
  }
2194
2311
  if (!hasOperations && !pathItem.$ref) {
@@ -2203,7 +2320,7 @@ var Validator = class {
2203
2320
  /**
2204
2321
  * Validate an operation
2205
2322
  */
2206
- validateOperation(operation, path, method, errors, warnings) {
2323
+ validateOperation(operation, path, method, errors, warnings, pathLevelParameters = [], componentParameters = {}) {
2207
2324
  const basePath = `/paths/${path}/${method}`;
2208
2325
  if (!operation.operationId) {
2209
2326
  warnings.push({
@@ -2220,14 +2337,18 @@ var Validator = class {
2220
2337
  });
2221
2338
  }
2222
2339
  if (operation.parameters) {
2223
- this.validateParameters(operation.parameters, path, method, errors, warnings);
2340
+ this.validateParameters(operation.parameters, `${basePath}/parameters`, errors, warnings);
2224
2341
  }
2342
+ const allParameters = [...pathLevelParameters, ...operation.parameters ?? []].map(
2343
+ (p) => this.resolveParameterRef(p, componentParameters)
2344
+ );
2345
+ const hasUnresolvableRefs = allParameters.some((p) => p === void 0);
2225
2346
  const pathParams = path.match(/\{([^{}]+)\}/g)?.map((p) => p.slice(1, -1)) ?? [];
2226
2347
  const definedPathParams = new Set(
2227
- operation.parameters?.filter((p) => p.in === "path").map((p) => p.name) ?? []
2348
+ allParameters.filter((p) => p && p.in === "path").map((p) => p.name)
2228
2349
  );
2229
2350
  for (const param of pathParams) {
2230
- if (!definedPathParams.has(param)) {
2351
+ if (!hasUnresolvableRefs && !definedPathParams.has(param)) {
2231
2352
  errors.push({
2232
2353
  message: `Path parameter '${param}' not defined in parameters: ${method.toUpperCase()} ${path}`,
2233
2354
  path: `${basePath}/parameters`,
@@ -2239,11 +2360,13 @@ var Validator = class {
2239
2360
  /**
2240
2361
  * Validate parameters
2241
2362
  */
2242
- validateParameters(parameters, path, method, errors, warnings) {
2243
- const basePath = `/paths/${path}/${method}/parameters`;
2363
+ validateParameters(parameters, basePath, errors, warnings) {
2244
2364
  for (let i = 0; i < parameters.length; i++) {
2245
2365
  const param = parameters[i];
2246
2366
  const paramPath = `${basePath}/${i}`;
2367
+ if (param && typeof param === "object" && "$ref" in param) {
2368
+ continue;
2369
+ }
2247
2370
  if (!param.name) {
2248
2371
  errors.push({
2249
2372
  message: "Parameter missing name",
@@ -2391,6 +2514,376 @@ function resolveSchemaFormats(schema, resolvers) {
2391
2514
  return result;
2392
2515
  }
2393
2516
 
2517
+ // src/type-signature.ts
2518
+ var DEFAULT_MAX_DEPTH = 8;
2519
+ var IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
2520
+ function toPascalIdentifier(toolName) {
2521
+ const segments = toolName.split(/[^A-Za-z0-9]+/).filter((s) => s.length > 0);
2522
+ const joined = segments.map((s) => s[0].toUpperCase() + s.slice(1)).join("");
2523
+ if (joined === "") {
2524
+ return "Tool";
2525
+ }
2526
+ return /^[0-9]/.test(joined) ? `T${joined}` : joined;
2527
+ }
2528
+ function lowerFirst(name) {
2529
+ return name[0].toLowerCase() + name.slice(1);
2530
+ }
2531
+ function isSchemaRecord(value) {
2532
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2533
+ }
2534
+ function isNullSchema(value) {
2535
+ return isSchemaRecord(value) && value["type"] === "null";
2536
+ }
2537
+ function paren(expr) {
2538
+ return expr.includes(" | ") || expr.includes(" & ") ? `(${expr})` : expr;
2539
+ }
2540
+ function dedupe(parts) {
2541
+ return [...new Set(parts)];
2542
+ }
2543
+ function quoteKey(name) {
2544
+ return IDENTIFIER.test(name) ? name : JSON.stringify(name);
2545
+ }
2546
+ function literalOf(value) {
2547
+ if (value === null) {
2548
+ return "null";
2549
+ }
2550
+ const t = typeof value;
2551
+ if (t === "number") {
2552
+ return Number.isFinite(value) ? JSON.stringify(value) : "number";
2553
+ }
2554
+ if (t === "string" || t === "boolean") {
2555
+ return JSON.stringify(value);
2556
+ }
2557
+ return "unknown";
2558
+ }
2559
+ var RESERVED_WORDS = /* @__PURE__ */ new Set([
2560
+ "break",
2561
+ "case",
2562
+ "catch",
2563
+ "class",
2564
+ "const",
2565
+ "continue",
2566
+ "debugger",
2567
+ "default",
2568
+ "delete",
2569
+ "do",
2570
+ "else",
2571
+ "enum",
2572
+ "export",
2573
+ "extends",
2574
+ "false",
2575
+ "finally",
2576
+ "for",
2577
+ "function",
2578
+ "if",
2579
+ "import",
2580
+ "in",
2581
+ "instanceof",
2582
+ "new",
2583
+ "null",
2584
+ "return",
2585
+ "super",
2586
+ "switch",
2587
+ "this",
2588
+ "throw",
2589
+ "true",
2590
+ "try",
2591
+ "typeof",
2592
+ "var",
2593
+ "void",
2594
+ "while",
2595
+ "with",
2596
+ "implements",
2597
+ "interface",
2598
+ "let",
2599
+ "package",
2600
+ "private",
2601
+ "protected",
2602
+ "public",
2603
+ "static",
2604
+ "yield",
2605
+ "await"
2606
+ ]);
2607
+ function escapeJsdoc(text) {
2608
+ return text.replace(/\*\//g, "*\\/");
2609
+ }
2610
+ function jsdocLines(prop) {
2611
+ if (!isSchemaRecord(prop)) {
2612
+ return [];
2613
+ }
2614
+ const lines = [];
2615
+ const description = prop["description"];
2616
+ if (typeof description === "string" && description !== "") {
2617
+ lines.push(...escapeJsdoc(description).split("\n"));
2618
+ }
2619
+ const format = prop["format"];
2620
+ if (typeof format === "string" && format !== "") {
2621
+ lines.push(`@format ${escapeJsdoc(format)}`);
2622
+ }
2623
+ if ("default" in prop && !(typeof prop["default"] === "number" && !Number.isFinite(prop["default"]))) {
2624
+ const rendered = JSON.stringify(prop["default"]);
2625
+ if (rendered !== void 0) {
2626
+ lines.push(`@default ${escapeJsdoc(rendered)}`);
2627
+ }
2628
+ }
2629
+ if (prop["deprecated"] === true) {
2630
+ lines.push("@deprecated");
2631
+ }
2632
+ return lines;
2633
+ }
2634
+ function renderJsdoc(lines, indent) {
2635
+ if (lines.length === 1) {
2636
+ return `${indent}/** ${lines[0]} */
2637
+ `;
2638
+ }
2639
+ return `${indent}/**
2640
+ ${lines.map((l) => `${indent} * ${l}`).join("\n")}
2641
+ ${indent} */
2642
+ `;
2643
+ }
2644
+ function hasObjectShape(r) {
2645
+ return r["type"] === "object" || r["type"] === void 0 && (r["properties"] !== void 0 || r["additionalProperties"] !== void 0 || r["patternProperties"] !== void 0);
2646
+ }
2647
+ function typeExpr(schema, ctx, depth, indent) {
2648
+ if (schema === true) {
2649
+ return "unknown";
2650
+ }
2651
+ if (schema === false) {
2652
+ return "never";
2653
+ }
2654
+ if (!isSchemaRecord(schema)) {
2655
+ return "unknown";
2656
+ }
2657
+ if (ctx.stack.has(schema)) {
2658
+ return "unknown";
2659
+ }
2660
+ if (depth >= ctx.maxDepth) {
2661
+ return "unknown";
2662
+ }
2663
+ if (schema["$ref"] !== void 0) {
2664
+ return "unknown";
2665
+ }
2666
+ ctx.stack.add(schema);
2667
+ try {
2668
+ return typeExprInner(schema, ctx, depth, indent);
2669
+ } finally {
2670
+ ctx.stack.delete(schema);
2671
+ }
2672
+ }
2673
+ function typeExprInner(r, ctx, depth, indent) {
2674
+ if ("const" in r) {
2675
+ const rendered = literalOf(r["const"]);
2676
+ if (rendered !== "unknown") {
2677
+ return rendered;
2678
+ }
2679
+ }
2680
+ const enumMembers = r["enum"];
2681
+ if (Array.isArray(enumMembers)) {
2682
+ if (enumMembers.length === 0) {
2683
+ return "unknown";
2684
+ }
2685
+ return dedupe(enumMembers.map(literalOf)).join(" | ");
2686
+ }
2687
+ const anyOf = r["anyOf"];
2688
+ if (Array.isArray(anyOf) && anyOf.length === 2) {
2689
+ const nullIdx = anyOf.findIndex(isNullSchema);
2690
+ if (nullIdx >= 0 && !isNullSchema(anyOf[1 - nullIdx])) {
2691
+ return `${paren(typeExpr(anyOf[1 - nullIdx], ctx, depth + 1, indent))} | null`;
2692
+ }
2693
+ }
2694
+ const allOf = r["allOf"];
2695
+ if (Array.isArray(allOf)) {
2696
+ const parts = allOf.map((m) => paren(typeExpr(m, ctx, depth + 1, indent)));
2697
+ if (r["properties"] !== void 0) {
2698
+ parts.push(paren(objectExpr(r, ctx, depth, indent)));
2699
+ }
2700
+ return parts.length === 0 ? "unknown" : dedupe(parts).join(" & ");
2701
+ }
2702
+ const union = Array.isArray(r["oneOf"]) ? r["oneOf"] : Array.isArray(anyOf) ? anyOf : void 0;
2703
+ if (union) {
2704
+ if (union.length === 0) {
2705
+ return "unknown";
2706
+ }
2707
+ return dedupe(union.map((m) => typeExpr(m, ctx, depth + 1, indent))).join(" | ");
2708
+ }
2709
+ const type = r["type"];
2710
+ if (Array.isArray(type)) {
2711
+ const parts = type.filter((t) => typeof t === "string").map((t) => typeExpr({ ...r, type: t }, ctx, depth, indent));
2712
+ return parts.length === 0 ? "unknown" : dedupe(parts).join(" | ");
2713
+ }
2714
+ switch (type) {
2715
+ case "string":
2716
+ return "string";
2717
+ case "number":
2718
+ case "integer":
2719
+ return "number";
2720
+ case "boolean":
2721
+ return "boolean";
2722
+ case "null":
2723
+ return "null";
2724
+ case "array":
2725
+ return arrayExpr(r, ctx, depth, indent);
2726
+ default:
2727
+ if (hasObjectShape(r)) {
2728
+ return objectExpr(r, ctx, depth, indent);
2729
+ }
2730
+ return "unknown";
2731
+ }
2732
+ }
2733
+ function arrayExpr(r, ctx, depth, indent) {
2734
+ const items = r["items"];
2735
+ const prefix = Array.isArray(r["prefixItems"]) ? r["prefixItems"] : Array.isArray(items) ? items : void 0;
2736
+ if (prefix) {
2737
+ const parts = prefix.map((m) => typeExpr(m, ctx, depth + 1, indent));
2738
+ let rest = "";
2739
+ if (Array.isArray(r["prefixItems"]) && items !== void 0 && !Array.isArray(items)) {
2740
+ rest = `, ...${paren(typeExpr(items, ctx, depth + 1, indent))}[]`;
2741
+ }
2742
+ return `[${parts.join(", ")}${rest}]`;
2743
+ }
2744
+ if (items === void 0) {
2745
+ return "unknown[]";
2746
+ }
2747
+ return `${paren(typeExpr(items, ctx, depth + 1, indent))}[]`;
2748
+ }
2749
+ function objectExpr(r, ctx, depth, indent) {
2750
+ const properties = isSchemaRecord(r["properties"]) ? r["properties"] : {};
2751
+ const entries = Object.entries(properties);
2752
+ const required = new Set(Array.isArray(r["required"]) ? r["required"] : []);
2753
+ const extraTypes = [];
2754
+ const ap = r["additionalProperties"];
2755
+ if (ap === true) {
2756
+ extraTypes.push("unknown");
2757
+ } else if (isSchemaRecord(ap)) {
2758
+ extraTypes.push(typeExpr(ap, ctx, depth + 1, indent));
2759
+ }
2760
+ const patternProps = r["patternProperties"];
2761
+ if (isSchemaRecord(patternProps)) {
2762
+ for (const value of Object.values(patternProps)) {
2763
+ extraTypes.push(typeExpr(value, ctx, depth + 1, indent));
2764
+ }
2765
+ }
2766
+ const extra = extraTypes.length > 0 ? dedupe(extraTypes).join(" | ") : void 0;
2767
+ if (entries.length === 0) {
2768
+ if (extra !== void 0) {
2769
+ return `Record<string, ${extra}>`;
2770
+ }
2771
+ return ap === false ? "Record<string, never>" : "Record<string, unknown>";
2772
+ }
2773
+ const suffix = extra !== void 0 ? ` & Record<string, ${extra}>` : "";
2774
+ if (ctx.mode === "compact") {
2775
+ const members = entries.map(
2776
+ ([key, prop]) => `${quoteKey(key)}${required.has(key) ? "" : "?"}: ${typeExpr(prop, ctx, depth + 1, indent)}`
2777
+ );
2778
+ return `{ ${members.join("; ")} }${suffix}`;
2779
+ }
2780
+ const inner = indent + " ";
2781
+ let body = "{\n";
2782
+ for (const [key, prop] of entries) {
2783
+ const doc = jsdocLines(prop);
2784
+ if (doc.length > 0) {
2785
+ body += renderJsdoc(doc, inner);
2786
+ }
2787
+ body += `${inner}${quoteKey(key)}${required.has(key) ? "" : "?"}: ${typeExpr(prop, ctx, depth + 1, inner)};
2788
+ `;
2789
+ }
2790
+ body += `${indent}}`;
2791
+ return `${body}${suffix}`;
2792
+ }
2793
+ function isPlainObjectBody(schema) {
2794
+ if (!isSchemaRecord(schema) || schema["$ref"] !== void 0) {
2795
+ return false;
2796
+ }
2797
+ if ("const" in schema && literalOf(schema["const"]) !== "unknown" || Array.isArray(schema["enum"])) {
2798
+ return false;
2799
+ }
2800
+ if (Array.isArray(schema["allOf"]) || Array.isArray(schema["oneOf"]) || Array.isArray(schema["anyOf"])) {
2801
+ return false;
2802
+ }
2803
+ if (Array.isArray(schema["type"]) || !hasObjectShape(schema)) {
2804
+ return false;
2805
+ }
2806
+ const properties = isSchemaRecord(schema["properties"]) ? schema["properties"] : {};
2807
+ if (Object.keys(properties).length === 0) {
2808
+ return false;
2809
+ }
2810
+ const ap = schema["additionalProperties"];
2811
+ if (ap === true || isSchemaRecord(ap) || isSchemaRecord(schema["patternProperties"])) {
2812
+ return false;
2813
+ }
2814
+ return true;
2815
+ }
2816
+ function namedRoot(name, schema, ctx) {
2817
+ const expr = typeExpr(schema, ctx, 0, "");
2818
+ return isPlainObjectBody(schema) ? `interface ${name} ${expr}` : `type ${name} = ${expr};`;
2819
+ }
2820
+ function paramList(inputSchema, typeText) {
2821
+ if (inputSchema === true) {
2822
+ return `(input?: ${typeText})`;
2823
+ }
2824
+ if (!isSchemaRecord(inputSchema)) {
2825
+ return "()";
2826
+ }
2827
+ const properties = isSchemaRecord(inputSchema["properties"]) ? inputSchema["properties"] : {};
2828
+ const keys = Object.keys(properties);
2829
+ if (keys.length === 0) {
2830
+ const ap = inputSchema["additionalProperties"];
2831
+ const hasExtra = ap === true || isSchemaRecord(ap) || isSchemaRecord(inputSchema["patternProperties"]);
2832
+ const objectish = inputSchema["type"] === "object" || inputSchema["type"] === void 0;
2833
+ const composed = Array.isArray(inputSchema["allOf"]) || Array.isArray(inputSchema["oneOf"]) || Array.isArray(inputSchema["anyOf"]) || Array.isArray(inputSchema["enum"]) || "const" in inputSchema;
2834
+ return objectish && !hasExtra && !composed ? "()" : `(input: ${typeText})`;
2835
+ }
2836
+ const required = new Set(Array.isArray(inputSchema["required"]) ? inputSchema["required"] : []);
2837
+ const allOptional = keys.every((k) => !required.has(k));
2838
+ return allOptional ? `(input?: ${typeText})` : `(input: ${typeText})`;
2839
+ }
2840
+ function outputVariantsDeclaration(name, variants, ctx) {
2841
+ const lines = variants.map((member) => {
2842
+ let comment = "";
2843
+ if (isSchemaRecord(member)) {
2844
+ const status = member["x-status-code"];
2845
+ if (typeof status === "number" || typeof status === "string") {
2846
+ const contentType = member["x-content-type"];
2847
+ const ct = typeof contentType === "string" ? ` (${escapeJsdoc(contentType)})` : "";
2848
+ comment = `/** status ${escapeJsdoc(String(status))}${ct} */ `;
2849
+ }
2850
+ }
2851
+ return ` | ${comment}${typeExpr(member, ctx, 1, " ")}`;
2852
+ });
2853
+ return `type ${name} =
2854
+ ${lines.join("\n")};`;
2855
+ }
2856
+ function emitToolTypeScript(toolName, description, inputSchema, outputSchema, options = {}) {
2857
+ const maxDepth = typeof options.maxDepth === "number" && Number.isFinite(options.maxDepth) ? Math.max(1, Math.floor(options.maxDepth)) : DEFAULT_MAX_DEPTH;
2858
+ const compact = { mode: "compact", maxDepth, stack: /* @__PURE__ */ new Set() };
2859
+ const pretty = { mode: "pretty", maxDepth, stack: /* @__PURE__ */ new Set() };
2860
+ const inputCompact = typeExpr(inputSchema, compact, 0, "");
2861
+ const outputCompact = outputSchema === void 0 ? "unknown" : typeExpr(outputSchema, compact, 0, "");
2862
+ const signature = `${paramList(inputSchema, inputCompact)} => Promise<${outputCompact}>`;
2863
+ const base = toPascalIdentifier(toolName);
2864
+ const inputName = `${base}Input`;
2865
+ const outputName = `${base}Output`;
2866
+ const blocks = [];
2867
+ if (typeof description === "string" && description !== "") {
2868
+ blocks.push(renderJsdoc(escapeJsdoc(description).split("\n"), "").trimEnd());
2869
+ }
2870
+ blocks.push(namedRoot(inputName, inputSchema, pretty));
2871
+ const outputUnion = isSchemaRecord(outputSchema) && Array.isArray(outputSchema["oneOf"]) ? outputSchema["oneOf"] : void 0;
2872
+ if (outputSchema === void 0) {
2873
+ blocks.push(`type ${outputName} = unknown;`);
2874
+ } else if (outputUnion && outputUnion.some((m) => isSchemaRecord(m) && m["x-status-code"] !== void 0)) {
2875
+ blocks.push(outputVariantsDeclaration(outputName, outputUnion, pretty));
2876
+ } else {
2877
+ blocks.push(namedRoot(outputName, outputSchema, pretty));
2878
+ }
2879
+ let fnName = lowerFirst(base);
2880
+ if (RESERVED_WORDS.has(fnName)) {
2881
+ fnName = `${fnName}_`;
2882
+ }
2883
+ blocks.push(`declare function ${fnName}${paramList(inputSchema, inputName)}: Promise<${outputName}>;`);
2884
+ return { signature, declaration: blocks.join("\n\n") };
2885
+ }
2886
+
2394
2887
  // src/ssrf.ts
2395
2888
  var BLOCKED_HOSTNAMES = /* @__PURE__ */ new Set([
2396
2889
  "localhost",
@@ -2578,6 +3071,8 @@ function nodePinnedTransport(modules) {
2578
3071
  const requestOptions = {
2579
3072
  method: "GET",
2580
3073
  signal,
3074
+ // A pooled keep-alive socket is keyed by host:port only and would skip the pinned lookup.
3075
+ agent: false,
2581
3076
  headers: { ...headers, "accept-encoding": "identity" }
2582
3077
  };
2583
3078
  if (pinned.length > 0) {
@@ -2799,6 +3294,25 @@ function globToRegExp(glob) {
2799
3294
  function matchesAnyGlob(path, globs) {
2800
3295
  return globs.some((glob) => globToRegExp(glob).test(path));
2801
3296
  }
3297
+ function iconsFromInfoLogo(info) {
3298
+ if (!info || typeof info !== "object") {
3299
+ return void 0;
3300
+ }
3301
+ const logo = info["x-logo"];
3302
+ let src;
3303
+ if (typeof logo === "string") {
3304
+ src = logo;
3305
+ } else if (logo && typeof logo === "object" && !Array.isArray(logo)) {
3306
+ const url = logo["url"];
3307
+ if (typeof url === "string") {
3308
+ src = url;
3309
+ }
3310
+ }
3311
+ if (src !== void 0 && isAllowedIconSrc(src)) {
3312
+ return [{ src }];
3313
+ }
3314
+ return void 0;
3315
+ }
2802
3316
  function trimUnderscores(value) {
2803
3317
  let start = 0;
2804
3318
  let end = value.length;
@@ -3181,6 +3695,14 @@ var OpenAPIToolGenerator = class _OpenAPIToolGenerator {
3181
3695
  attempts++;
3182
3696
  }
3183
3697
  tool = { ...tool, name: deduped };
3698
+ if (tool.metadata.typescript) {
3699
+ tool.metadata = {
3700
+ ...tool.metadata,
3701
+ typescript: emitToolTypeScript(deduped, tool.description, tool.inputSchema, tool.outputSchema, {
3702
+ maxDepth: Math.max(1, options.maxSchemaDepth ?? 10)
3703
+ })
3704
+ };
3705
+ }
3184
3706
  }
3185
3707
  usedNames.add(tool.name);
3186
3708
  tools.push(tool);
@@ -3229,7 +3751,13 @@ var OpenAPIToolGenerator = class _OpenAPIToolGenerator {
3229
3751
  const responseBuilder = new ResponseBuilder(options);
3230
3752
  const outputSchema = responseBuilder.build(operation.responses);
3231
3753
  const overrides = extractExtensionOverrides(operation);
3232
- const name = this.generateToolName(pathStr, method, overrides.name ?? operation.operationId, options);
3754
+ const name = this.generateToolName(
3755
+ pathStr,
3756
+ method,
3757
+ overrides.name ?? operation.operationId,
3758
+ options,
3759
+ operation
3760
+ );
3233
3761
  const description = overrides.description ?? composeDescription(operation, method, pathStr, options.descriptionStrategy ?? "summaryOnly");
3234
3762
  const title = overrides.title ?? operation.summary;
3235
3763
  const inferred = options.inferAnnotations !== false ? inferAnnotationsFromMethod(method.toLowerCase()) : void 0;
@@ -3294,11 +3822,48 @@ var OpenAPIToolGenerator = class _OpenAPIToolGenerator {
3294
3822
  Returns: ${summary}`;
3295
3823
  }
3296
3824
  }
3825
+ if (options.emitTypeSignatures) {
3826
+ metadata.typescript = emitToolTypeScript(name, finalDescription, resolvedInputSchema, resolvedOutputSchema, {
3827
+ // Print at least as deep as the schemas were truncated, so the
3828
+ // emitted types never collapse levels the schema still carries.
3829
+ maxDepth: Math.max(1, options.maxSchemaDepth ?? 10)
3830
+ });
3831
+ }
3832
+ let toolMeta;
3833
+ if (overrides.meta) {
3834
+ toolMeta = {};
3835
+ for (const [key, value] of Object.entries(overrides.meta)) {
3836
+ if (!key.startsWith("dev.agentfront.openapi/")) {
3837
+ toolMeta[key] = value;
3838
+ }
3839
+ }
3840
+ }
3841
+ if (options.emitMeta) {
3842
+ const info = document.info;
3843
+ toolMeta = {
3844
+ ...toolMeta,
3845
+ "dev.agentfront.openapi/operation": {
3846
+ path: pathStr,
3847
+ method,
3848
+ ...operation.operationId !== void 0 && { operationId: operation.operationId },
3849
+ ...operation.tags && { tags: [...operation.tags] },
3850
+ ...operation.deprecated !== void 0 && { deprecated: operation.deprecated },
3851
+ ...typeof info?.["title"] === "string" && { specTitle: info["title"] },
3852
+ ...typeof info?.["version"] === "string" && { specVersion: info["version"] }
3853
+ }
3854
+ };
3855
+ }
3856
+ if (toolMeta && Object.keys(toolMeta).length === 0) {
3857
+ toolMeta = void 0;
3858
+ }
3859
+ const icons = overrides.icons ?? (options.inheritDocumentIcons ? iconsFromInfoLogo(document.info) : void 0);
3297
3860
  return {
3298
3861
  name,
3299
3862
  ...title !== void 0 && { title },
3300
3863
  description: finalDescription,
3301
3864
  ...annotations && { annotations },
3865
+ ...toolMeta && { _meta: toolMeta },
3866
+ ...icons && { icons },
3302
3867
  inputSchema: resolvedInputSchema,
3303
3868
  outputSchema: resolvedOutputSchema,
3304
3869
  mapper,
@@ -3366,10 +3931,10 @@ Returns: ${summary}`;
3366
3931
  /**
3367
3932
  * Generate a tool name
3368
3933
  */
3369
- generateToolName(path, method, operationId, options = {}) {
3934
+ generateToolName(path, method, operationId, options = {}, operation) {
3370
3935
  let rawName;
3371
3936
  if (options.namingStrategy?.toolNameGenerator) {
3372
- rawName = options.namingStrategy.toolNameGenerator(path, method, operationId);
3937
+ rawName = options.namingStrategy.toolNameGenerator(path, method, operationId, operation);
3373
3938
  } else if (operationId) {
3374
3939
  rawName = operationId;
3375
3940
  } else {
@@ -3707,6 +4272,1213 @@ function createSecurityContext(auth) {
3707
4272
  };
3708
4273
  }
3709
4274
 
4275
+ // src/naming-presets.ts
4276
+ var CODECALL_RESERVED_NAMESPACES = [
4277
+ "console",
4278
+ "Math",
4279
+ "JSON",
4280
+ "Object",
4281
+ "Promise",
4282
+ "Array",
4283
+ "String",
4284
+ "Number",
4285
+ "Boolean",
4286
+ "Date",
4287
+ "RegExp",
4288
+ "Error",
4289
+ "Symbol",
4290
+ "Map",
4291
+ "Set",
4292
+ "WeakMap",
4293
+ "WeakSet",
4294
+ "globalThis",
4295
+ "global",
4296
+ "window",
4297
+ "self",
4298
+ "undefined",
4299
+ "null",
4300
+ "true",
4301
+ "false",
4302
+ "NaN",
4303
+ "Infinity",
4304
+ "callTool",
4305
+ "getTool",
4306
+ "mcpLog",
4307
+ "mcpNotify"
4308
+ ];
4309
+ function sanitizeIdentifier(value) {
4310
+ if (value === void 0) {
4311
+ return "";
4312
+ }
4313
+ let out = value.replace(/[^A-Za-z0-9_]+/g, "_").replace(/_+/g, "_");
4314
+ let start = 0;
4315
+ let end = out.length;
4316
+ while (start < end && out[start] === "_") start++;
4317
+ while (end > start && out[end - 1] === "_") end--;
4318
+ out = out.slice(start, end);
4319
+ if (out === "") {
4320
+ return "";
4321
+ }
4322
+ return /^[0-9]/.test(out) ? `_${out}` : out;
4323
+ }
4324
+ function firstPathSegment(path) {
4325
+ for (const segment of path.split("/")) {
4326
+ if (segment !== "" && !segment.startsWith("{")) {
4327
+ return sanitizeIdentifier(segment);
4328
+ }
4329
+ }
4330
+ return "";
4331
+ }
4332
+ function pathMethodHalf(method, path, ns) {
4333
+ const segments = path.split("/").filter((s) => s !== "").map((s) => {
4334
+ const templated = s.replace(/\{([^{}]+)\}/g, "by_$1");
4335
+ return sanitizeIdentifier(templated);
4336
+ }).filter((s) => s !== "");
4337
+ if (segments.length > 0 && segments[0] === ns) {
4338
+ segments.shift();
4339
+ }
4340
+ const joined = segments.join("_");
4341
+ return joined === "" ? method : `${method}_${joined}`;
4342
+ }
4343
+ function dottedNaming(options = {}) {
4344
+ const namespaceFrom = options.namespaceFrom ?? "tag";
4345
+ const reserved = /* @__PURE__ */ new Set([...CODECALL_RESERVED_NAMESPACES, ...options.reservedNamespaces ?? []]);
4346
+ return {
4347
+ toolNameGenerator: (path, method, operationId, operation) => {
4348
+ let ns = "";
4349
+ if (namespaceFrom === "tag") {
4350
+ ns = sanitizeIdentifier(operation?.tags?.[0]);
4351
+ }
4352
+ if (ns === "") {
4353
+ ns = firstPathSegment(path);
4354
+ }
4355
+ if (ns === "") {
4356
+ ns = "api";
4357
+ }
4358
+ if (ns.startsWith("_")) {
4359
+ ns = `n${ns.slice(1)}`;
4360
+ }
4361
+ if (reserved.has(ns)) {
4362
+ ns = `${ns}_`;
4363
+ }
4364
+ const methodHalf = sanitizeIdentifier(operationId) || pathMethodHalf(method, path, ns);
4365
+ return `${ns}.${methodHalf}`;
4366
+ }
4367
+ };
4368
+ }
4369
+
4370
+ // src/elicitation.ts
4371
+ function buildElicitation(source) {
4372
+ const { scheme, type } = source;
4373
+ if (type === "http") {
4374
+ const httpScheme = (source.httpScheme ?? "bearer").toLowerCase();
4375
+ if (httpScheme === "basic" || httpScheme === "digest") {
4376
+ return {
4377
+ scheme,
4378
+ message: `Provide HTTP ${httpScheme} credentials for "${scheme}".`,
4379
+ requestedSchema: {
4380
+ type: "object",
4381
+ properties: {
4382
+ username: { type: "string", title: "Username" },
4383
+ password: { type: "string", title: "Password", description: "Handled as a secret \u2014 never logged." }
4384
+ },
4385
+ required: ["username", "password"]
4386
+ }
4387
+ };
4388
+ }
4389
+ const format = source.bearerFormat ? ` (${source.bearerFormat})` : "";
4390
+ return {
4391
+ scheme,
4392
+ message: `Provide the ${httpScheme} token for "${scheme}".`,
4393
+ requestedSchema: {
4394
+ type: "object",
4395
+ properties: {
4396
+ token: { type: "string", title: "Token", description: `HTTP ${httpScheme} authentication token${format}.` }
4397
+ },
4398
+ required: ["token"]
4399
+ }
4400
+ };
4401
+ }
4402
+ if (type === "apiKey") {
4403
+ const keyName = source.apiKeyName ?? scheme;
4404
+ const location = source.apiKeyIn ?? "header";
4405
+ return {
4406
+ scheme,
4407
+ message: `Provide the API key for "${scheme}".`,
4408
+ requestedSchema: {
4409
+ type: "object",
4410
+ properties: {
4411
+ apiKey: { type: "string", title: "API key", description: `API key "${keyName}" sent via ${location}.` }
4412
+ },
4413
+ required: ["apiKey"]
4414
+ }
4415
+ };
4416
+ }
4417
+ if (type === "oauth2" || type === "openIdConnect") {
4418
+ const scopes = source.scopes && source.scopes.length > 0 ? ` Scopes: ${source.scopes.join(", ")}.` : "";
4419
+ return {
4420
+ scheme,
4421
+ message: `Provide an OAuth2 access token for "${scheme}".${scopes}`,
4422
+ requestedSchema: {
4423
+ type: "object",
4424
+ properties: {
4425
+ accessToken: { type: "string", title: "Access token", description: `OAuth2 access token.${scopes}` }
4426
+ },
4427
+ required: ["accessToken"]
4428
+ }
4429
+ };
4430
+ }
4431
+ return void 0;
4432
+ }
4433
+ function deriveSecurityElicitations(tool) {
4434
+ const sources = [];
4435
+ const seen = /* @__PURE__ */ new Set();
4436
+ for (const entry of tool.mapper) {
4437
+ const security = entry.security;
4438
+ if (security && !seen.has(security.scheme)) {
4439
+ seen.add(security.scheme);
4440
+ sources.push(security);
4441
+ }
4442
+ }
4443
+ if (sources.length === 0 && tool.metadata.security) {
4444
+ for (const requirement of tool.metadata.security) {
4445
+ if (!seen.has(requirement.scheme)) {
4446
+ seen.add(requirement.scheme);
4447
+ sources.push({
4448
+ scheme: requirement.scheme,
4449
+ type: requirement.type,
4450
+ httpScheme: requirement.httpScheme,
4451
+ bearerFormat: requirement.bearerFormat,
4452
+ scopes: requirement.scopes,
4453
+ apiKeyName: requirement.name,
4454
+ apiKeyIn: requirement.in
4455
+ });
4456
+ }
4457
+ }
4458
+ }
4459
+ const result = [];
4460
+ for (const source of sources) {
4461
+ const elicitation = buildElicitation(source);
4462
+ if (elicitation) {
4463
+ result.push(elicitation);
4464
+ }
4465
+ }
4466
+ return result;
4467
+ }
4468
+
4469
+ // src/arazzo-expressions.ts
4470
+ var EXACT_ROOTS = {
4471
+ $url: "url",
4472
+ $method: "method",
4473
+ $statusCode: "statusCode"
4474
+ };
4475
+ var DOTTED_ROOTS = {
4476
+ $inputs: "inputs",
4477
+ $outputs: "outputs",
4478
+ $steps: "steps",
4479
+ $workflows: "workflows",
4480
+ $sourceDescriptions: "sourceDescriptions",
4481
+ $components: "components"
4482
+ };
4483
+ var KNOWN_ROOT = /^\$(?:(?:url|method|statusCode)$|(?:request|response|message)\.|(?:inputs|outputs|steps|workflows|sourceDescriptions|components)\.)/;
4484
+ function fail(message, docPath, expression) {
4485
+ throw new ArazzoError(message, { path: docPath, expression });
4486
+ }
4487
+ var TOKEN = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
4488
+ function parseSourceRef(prefix, rest, raw, docPath) {
4489
+ if (rest.startsWith("header.")) {
4490
+ const name = rest.slice("header.".length);
4491
+ if (name === "" || !TOKEN.test(name)) {
4492
+ fail(`Invalid header name in runtime expression "${raw}"`, docPath, raw);
4493
+ }
4494
+ return { type: prefix, raw, path: [], source: "header", name };
4495
+ }
4496
+ if (rest.startsWith("query.") || rest.startsWith("path.")) {
4497
+ const source = rest.startsWith("query.") ? "query" : "path";
4498
+ const name = rest.slice(source.length + 1);
4499
+ if (name === "") {
4500
+ fail(`Empty ${source} parameter name in runtime expression "${raw}"`, docPath, raw);
4501
+ }
4502
+ return { type: prefix, raw, path: [], source, name };
4503
+ }
4504
+ if (rest === "body" || rest.startsWith("body#")) {
4505
+ const node = { type: prefix, raw, path: [], source: "body" };
4506
+ if (rest.startsWith("body#")) {
4507
+ const pointer = rest.slice("body#".length);
4508
+ if (pointer !== "" && !pointer.startsWith("/")) {
4509
+ fail(`JSON Pointer in "${raw}" must be empty or start with "/"`, docPath, raw);
4510
+ }
4511
+ node.pointer = pointer;
4512
+ }
4513
+ return node;
4514
+ }
4515
+ fail(`Invalid $${prefix} reference "${raw}" \u2014 expected header.<name>, query.<name>, path.<name>, or body[#<pointer>]`, docPath, raw);
4516
+ }
4517
+ function parseRuntimeExpression(raw, docPath = "") {
4518
+ const exact = EXACT_ROOTS[raw];
4519
+ if (exact) {
4520
+ return { type: exact, raw, path: [] };
4521
+ }
4522
+ for (const key of Object.keys(EXACT_ROOTS)) {
4523
+ if (raw.startsWith(key) && raw !== key) {
4524
+ fail(`Unexpected characters after "${key}" in runtime expression "${raw}"`, docPath, raw);
4525
+ }
4526
+ }
4527
+ for (const prefix of ["request", "response", "message"]) {
4528
+ if (raw.startsWith(`$${prefix}.`)) {
4529
+ return parseSourceRef(prefix, raw.slice(prefix.length + 2), raw, docPath);
4530
+ }
4531
+ }
4532
+ const dot = raw.indexOf(".");
4533
+ const rootToken = dot === -1 ? raw : raw.slice(0, dot);
4534
+ const root = DOTTED_ROOTS[rootToken];
4535
+ if (root) {
4536
+ const rest = dot === -1 ? "" : raw.slice(dot + 1);
4537
+ if (rest === "") {
4538
+ fail(`Runtime expression "${raw}" is missing a name after "${rootToken}."`, docPath, raw);
4539
+ }
4540
+ const path = rest.split(".");
4541
+ if (path.some((segment) => segment === "" || /\s/.test(segment))) {
4542
+ fail(`Runtime expression "${raw}" contains an empty or whitespace path segment`, docPath, raw);
4543
+ }
4544
+ return { type: root, raw, path };
4545
+ }
4546
+ fail(`Invalid runtime expression "${raw}"`, docPath, raw);
4547
+ }
4548
+ function parseExpressionValue(value, docPath = "") {
4549
+ if (typeof value !== "string") {
4550
+ return { kind: "literal", value };
4551
+ }
4552
+ if (value.startsWith("$")) {
4553
+ if (KNOWN_ROOT.test(value)) {
4554
+ return { kind: "expression", expression: parseRuntimeExpression(value, docPath) };
4555
+ }
4556
+ return { kind: "literal", value };
4557
+ }
4558
+ if (!value.includes("{$")) {
4559
+ return { kind: "literal", value };
4560
+ }
4561
+ const parts = [];
4562
+ let cursor = 0;
4563
+ while (cursor < value.length) {
4564
+ const open = value.indexOf("{$", cursor);
4565
+ if (open === -1) {
4566
+ parts.push(value.slice(cursor));
4567
+ break;
4568
+ }
4569
+ if (open > cursor) {
4570
+ parts.push(value.slice(cursor, open));
4571
+ }
4572
+ const close = value.indexOf("}", open);
4573
+ if (close === -1) {
4574
+ fail(`Unterminated "{$" template expression in "${value}"`, docPath, value);
4575
+ }
4576
+ parts.push(parseRuntimeExpression(value.slice(open + 1, close), docPath));
4577
+ cursor = close + 1;
4578
+ }
4579
+ return { kind: "template", raw: value, parts };
4580
+ }
4581
+ function escapePointerSegment(segment) {
4582
+ return segment.replace(/~/g, "~0").replace(/\//g, "~1");
4583
+ }
4584
+ function collectPayloadExpressions(payload, docPath = "") {
4585
+ const found = [];
4586
+ const seen = /* @__PURE__ */ new Set();
4587
+ const visit = (node, pointer) => {
4588
+ if (typeof node === "string") {
4589
+ const value = parseExpressionValue(node, docPath);
4590
+ if (value.kind !== "literal") {
4591
+ found.push({ pointer, value });
4592
+ }
4593
+ return;
4594
+ }
4595
+ if (!node || typeof node !== "object") {
4596
+ return;
4597
+ }
4598
+ if (seen.has(node)) {
4599
+ return;
4600
+ }
4601
+ seen.add(node);
4602
+ if (Array.isArray(node)) {
4603
+ node.forEach((item, index) => visit(item, `${pointer}/${index}`));
4604
+ return;
4605
+ }
4606
+ for (const [key, value] of Object.entries(node)) {
4607
+ visit(value, `${pointer}/${escapePointerSegment(key)}`);
4608
+ }
4609
+ };
4610
+ visit(payload, "");
4611
+ return found;
4612
+ }
4613
+
4614
+ // src/arazzo.ts
4615
+ var yaml2 = __toESM(require("yaml"));
4616
+ var ID_PATTERN = /^[A-Za-z0-9_-]+$/;
4617
+ var OUTPUT_KEY_PATTERN = /^[a-zA-Z0-9.\-_]+$/;
4618
+ var VERSION_PATTERN = /^1\.0\.\d+$/;
4619
+ var HTTP_METHODS = ["get", "post", "put", "patch", "delete", "head", "options", "trace"];
4620
+ var PARAMETER_LOCATIONS = ["path", "query", "header", "cookie"];
4621
+ var OUTPUT_DERIVATION_MAX_DEPTH = 8;
4622
+ function err(message, path, extra) {
4623
+ throw new ArazzoError(message, { path, ...extra });
4624
+ }
4625
+ function toPlainJson(value) {
4626
+ try {
4627
+ return JSON.parse(JSON.stringify(value));
4628
+ } catch (error) {
4629
+ const message = error instanceof Error ? error.message : String(error);
4630
+ throw new ArazzoError(`Arazzo document must be JSON-serializable (acyclic, bounded depth): ${message}`, {
4631
+ path: ""
4632
+ });
4633
+ }
4634
+ }
4635
+ function parseArazzoInput(input) {
4636
+ if (typeof input === "string") {
4637
+ let parsed;
4638
+ try {
4639
+ parsed = yaml2.parse(input);
4640
+ } catch (error) {
4641
+ const message = error instanceof Error ? error.message : String(error);
4642
+ throw new ArazzoError(`Failed to parse Arazzo document: ${message}`, { path: "" });
4643
+ }
4644
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
4645
+ err("Arazzo document must be an object", "");
4646
+ }
4647
+ return toPlainJson(parsed);
4648
+ }
4649
+ if (!input || typeof input !== "object" || Array.isArray(input)) {
4650
+ err("Arazzo document must be an object", "");
4651
+ }
4652
+ return toPlainJson(input);
4653
+ }
4654
+ function validateCriteria(criteria, path) {
4655
+ if (criteria === void 0) return;
4656
+ if (!Array.isArray(criteria)) {
4657
+ err("successCriteria/criteria must be an array", path);
4658
+ }
4659
+ criteria.forEach((criterion, index) => {
4660
+ const cPath = `${path}/${index}`;
4661
+ if (!criterion || typeof criterion !== "object") {
4662
+ err("Criterion must be an object", cPath);
4663
+ }
4664
+ if (typeof criterion.condition !== "string" || criterion.condition === "") {
4665
+ err('Criterion requires a non-empty string "condition"', cPath);
4666
+ }
4667
+ const type = criterion.type;
4668
+ let effectiveType;
4669
+ if (type !== void 0) {
4670
+ if (typeof type === "string") {
4671
+ if (!["simple", "regex", "jsonpath", "xpath"].includes(type)) {
4672
+ err(`Unknown criterion type "${type}"`, cPath);
4673
+ }
4674
+ effectiveType = type;
4675
+ } else if (type && typeof type === "object") {
4676
+ if (type.type !== "jsonpath" && type.type !== "xpath" || typeof type.version !== "string") {
4677
+ err('Criterion Expression Type Object requires "type" (jsonpath|xpath) and "version"', cPath);
4678
+ }
4679
+ effectiveType = type.type;
4680
+ } else {
4681
+ err('Criterion "type" must be a string or a Criterion Expression Type Object', cPath);
4682
+ }
4683
+ }
4684
+ if (criterion.context !== void 0 && typeof criterion.context !== "string") {
4685
+ err('Criterion "context" must be a runtime expression string', cPath);
4686
+ }
4687
+ if (effectiveType !== void 0 && effectiveType !== "simple" && criterion.context === void 0) {
4688
+ err(`Criterion of type "${effectiveType}" requires a "context" expression`, cPath);
4689
+ }
4690
+ });
4691
+ }
4692
+ function validateActions(actions, kind, path) {
4693
+ if (actions === void 0) return;
4694
+ if (!Array.isArray(actions)) {
4695
+ err("Actions must be an array", path);
4696
+ }
4697
+ actions.forEach((action, index) => {
4698
+ const aPath = `${path}/${index}`;
4699
+ if (!action || typeof action !== "object") {
4700
+ err("Action must be an object", aPath);
4701
+ }
4702
+ if ("reference" in action) {
4703
+ return;
4704
+ }
4705
+ validateActionObject(action, kind, aPath);
4706
+ });
4707
+ }
4708
+ function validateActionObject(action, kind, aPath) {
4709
+ const act = action;
4710
+ if (typeof act.name !== "string" || act.name === "") {
4711
+ err('Action requires a non-empty string "name"', aPath);
4712
+ }
4713
+ const allowed = kind === "success" ? ["end", "goto"] : ["end", "retry", "goto"];
4714
+ if (!allowed.includes(act.type)) {
4715
+ err(`Invalid ${kind}-action type "${String(act.type)}" (allowed: ${allowed.join(", ")})`, aPath);
4716
+ }
4717
+ const targets = [act.workflowId, act.stepId].filter((t) => t !== void 0).length;
4718
+ if (act.type === "goto" && targets !== 1) {
4719
+ err('A "goto" action requires exactly one of "workflowId" or "stepId"', aPath);
4720
+ }
4721
+ if (act.type === "end" && targets !== 0) {
4722
+ err('An "end" action must not specify "workflowId" or "stepId"', aPath);
4723
+ }
4724
+ if (act.retryAfter !== void 0 && (typeof act.retryAfter !== "number" || act.retryAfter < 0)) {
4725
+ err('"retryAfter" must be a non-negative number', aPath);
4726
+ }
4727
+ if (act.retryLimit !== void 0 && (typeof act.retryLimit !== "number" || !Number.isInteger(act.retryLimit) || act.retryLimit < 0)) {
4728
+ err('"retryLimit" must be a non-negative integer', aPath);
4729
+ }
4730
+ validateCriteria(act.criteria, `${aPath}/criteria`);
4731
+ }
4732
+ function validateParameters(parameters, requireIn, path) {
4733
+ if (parameters === void 0) return;
4734
+ if (!Array.isArray(parameters)) {
4735
+ err("Parameters must be an array", path);
4736
+ }
4737
+ const seen = /* @__PURE__ */ new Set();
4738
+ parameters.forEach((parameter, index) => {
4739
+ const pPath = `${path}/${index}`;
4740
+ if (!parameter || typeof parameter !== "object") {
4741
+ err("Parameter must be an object", pPath);
4742
+ }
4743
+ if ("reference" in parameter) {
4744
+ return;
4745
+ }
4746
+ validateParameterObject(parameter, requireIn, pPath);
4747
+ const param = parameter;
4748
+ const key = `${param.name} ${param.in ?? ""}`;
4749
+ if (seen.has(key)) {
4750
+ err(`Duplicate parameter "${param.name}"${param.in ? ` (in: ${param.in})` : ""}`, pPath);
4751
+ }
4752
+ seen.add(key);
4753
+ });
4754
+ }
4755
+ function validateParameterObject(param, requireIn, pPath) {
4756
+ if (typeof param.name !== "string" || param.name === "") {
4757
+ err('Parameter requires a non-empty string "name"', pPath);
4758
+ }
4759
+ const paramName = param.name;
4760
+ if (!("value" in param)) {
4761
+ err(`Parameter "${paramName}" requires a "value"`, pPath);
4762
+ }
4763
+ if (param.in !== void 0 && !PARAMETER_LOCATIONS.includes(param.in)) {
4764
+ err(`Invalid parameter location "${String(param.in)}"`, pPath);
4765
+ }
4766
+ if (requireIn === true && param.in === void 0) {
4767
+ err(`Parameter "${param.name}" on an operation step requires "in"`, pPath);
4768
+ }
4769
+ if (requireIn === false && param.in !== void 0) {
4770
+ err(`Parameter "${param.name}" on a workflowId step must not specify "in"`, pPath);
4771
+ }
4772
+ }
4773
+ function validateOutputs(outputs, path) {
4774
+ if (outputs === void 0) return;
4775
+ if (!outputs || typeof outputs !== "object" || Array.isArray(outputs)) {
4776
+ err('"outputs" must be an object of name \u2192 runtime expression', path);
4777
+ }
4778
+ for (const [key, value] of Object.entries(outputs)) {
4779
+ if (!OUTPUT_KEY_PATTERN.test(key)) {
4780
+ err(`Invalid output name "${key}"`, `${path}/${key}`);
4781
+ }
4782
+ if (typeof value !== "string") {
4783
+ err(`Output "${key}" must be a runtime expression string`, `${path}/${key}`);
4784
+ }
4785
+ }
4786
+ }
4787
+ function validateDocument(doc) {
4788
+ if (typeof doc.arazzo !== "string" || !VERSION_PATTERN.test(doc.arazzo)) {
4789
+ err(`Unsupported arazzo version "${String(doc.arazzo)}" (expected 1.0.x)`, "/arazzo");
4790
+ }
4791
+ if (!doc.info || typeof doc.info !== "object" || typeof doc.info.title !== "string" || typeof doc.info.version !== "string") {
4792
+ err('"info" requires string "title" and "version"', "/info");
4793
+ }
4794
+ if (!Array.isArray(doc.sourceDescriptions) || doc.sourceDescriptions.length === 0) {
4795
+ err('"sourceDescriptions" must be a non-empty array', "/sourceDescriptions");
4796
+ }
4797
+ const sourceNames = /* @__PURE__ */ new Set();
4798
+ doc.sourceDescriptions.forEach((source, index) => {
4799
+ const sPath = `/sourceDescriptions/${index}`;
4800
+ if (!source || typeof source !== "object" || typeof source.name !== "string" || !ID_PATTERN.test(source.name)) {
4801
+ err('Source description requires a "name" matching [A-Za-z0-9_-]+', sPath);
4802
+ }
4803
+ if (typeof source.url !== "string" || source.url === "") {
4804
+ err(`Source "${source.name}" requires a string "url"`, sPath);
4805
+ }
4806
+ if (source.type !== void 0 && source.type !== "openapi" && source.type !== "arazzo") {
4807
+ err(`Source "${source.name}" has invalid type "${String(source.type)}"`, sPath);
4808
+ }
4809
+ if (sourceNames.has(source.name)) {
4810
+ err(`Duplicate source description name "${source.name}"`, sPath);
4811
+ }
4812
+ sourceNames.add(source.name);
4813
+ });
4814
+ if (!Array.isArray(doc.workflows) || doc.workflows.length === 0) {
4815
+ err('"workflows" must be a non-empty array', "/workflows");
4816
+ }
4817
+ const workflowIds = /* @__PURE__ */ new Set();
4818
+ doc.workflows.forEach((workflow, wIndex) => {
4819
+ const wPath = `/workflows/${wIndex}`;
4820
+ if (!workflow || typeof workflow !== "object" || typeof workflow.workflowId !== "string" || !ID_PATTERN.test(workflow.workflowId)) {
4821
+ err('Workflow requires a "workflowId" matching [A-Za-z0-9_-]+', wPath);
4822
+ }
4823
+ if (workflowIds.has(workflow.workflowId)) {
4824
+ err(`Duplicate workflowId "${workflow.workflowId}"`, wPath);
4825
+ }
4826
+ workflowIds.add(workflow.workflowId);
4827
+ if (!Array.isArray(workflow.steps) || workflow.steps.length === 0) {
4828
+ err(`Workflow "${workflow.workflowId}" requires a non-empty "steps" array`, `${wPath}/steps`);
4829
+ }
4830
+ validateParameters(workflow.parameters, void 0, `${wPath}/parameters`);
4831
+ validateActions(workflow.successActions, "success", `${wPath}/successActions`);
4832
+ validateActions(workflow.failureActions, "failure", `${wPath}/failureActions`);
4833
+ validateOutputs(workflow.outputs, `${wPath}/outputs`);
4834
+ const stepIds = /* @__PURE__ */ new Set();
4835
+ workflow.steps.forEach((step, sIndex) => {
4836
+ const sPath = `${wPath}/steps/${sIndex}`;
4837
+ if (!step || typeof step !== "object" || typeof step.stepId !== "string" || !ID_PATTERN.test(step.stepId)) {
4838
+ err('Step requires a "stepId" matching [A-Za-z0-9_-]+', sPath);
4839
+ }
4840
+ if (stepIds.has(step.stepId)) {
4841
+ err(`Duplicate stepId "${step.stepId}" in workflow "${workflow.workflowId}"`, sPath);
4842
+ }
4843
+ stepIds.add(step.stepId);
4844
+ const kinds = [step.operationId, step.operationPath, step.workflowId].filter((k) => k !== void 0).length;
4845
+ if (kinds !== 1) {
4846
+ err(`Step "${step.stepId}" requires exactly one of "operationId", "operationPath", or "workflowId"`, sPath);
4847
+ }
4848
+ validateParameters(step.parameters, step.workflowId !== void 0 ? false : true, `${sPath}/parameters`);
4849
+ validateCriteria(step.successCriteria, `${sPath}/successCriteria`);
4850
+ validateActions(step.onSuccess, "success", `${sPath}/onSuccess`);
4851
+ validateActions(step.onFailure, "failure", `${sPath}/onFailure`);
4852
+ validateOutputs(step.outputs, `${sPath}/outputs`);
4853
+ });
4854
+ });
4855
+ }
4856
+ function ownComponent(group, name) {
4857
+ if (!group || !Object.prototype.hasOwnProperty.call(group, name)) {
4858
+ return void 0;
4859
+ }
4860
+ const value = group[name];
4861
+ return value !== null && typeof value === "object" ? value : void 0;
4862
+ }
4863
+ function resolveReusable(entry, components, expectedGroup, path) {
4864
+ if (!entry || typeof entry !== "object" || !("reference" in entry)) {
4865
+ return entry;
4866
+ }
4867
+ const reusable = entry;
4868
+ if (typeof reusable.reference !== "string") {
4869
+ err('Reusable Object "reference" must be a string', path);
4870
+ }
4871
+ const ast = parseRuntimeExpression(reusable.reference, path);
4872
+ if (ast.type !== "components" || ast.path.length < 2 || ast.path[0] !== expectedGroup) {
4873
+ err(`Reference "${reusable.reference}" must point at $components.${expectedGroup}.<name>`, path);
4874
+ }
4875
+ const name = ast.path.slice(1).join(".");
4876
+ const target = ownComponent(components?.[expectedGroup], name);
4877
+ if (!target) {
4878
+ err(`Unknown reference "$components.${expectedGroup}.${name}"`, path);
4879
+ }
4880
+ const resolved = JSON.parse(JSON.stringify(target));
4881
+ if (expectedGroup === "parameters" && "value" in reusable) {
4882
+ resolved.value = reusable.value;
4883
+ }
4884
+ return resolved;
4885
+ }
4886
+ function resolveInputRefs(node, components, path, seen) {
4887
+ if (Array.isArray(node)) {
4888
+ return node.map((item) => resolveInputRefs(item, components, path, seen));
4889
+ }
4890
+ if (!node || typeof node !== "object") {
4891
+ return node;
4892
+ }
4893
+ const record = node;
4894
+ const ref = record["$ref"];
4895
+ if (typeof ref === "string") {
4896
+ const prefix = "#/components/inputs/";
4897
+ if (!ref.startsWith(prefix)) {
4898
+ err(`Unsupported $ref "${ref}" in workflow inputs (only ${prefix}<name> is resolvable)`, path);
4899
+ }
4900
+ const name = ref.slice(prefix.length);
4901
+ const target = ownComponent(components?.inputs, name);
4902
+ if (!target) {
4903
+ err(`Unknown workflow inputs reference "${ref}"`, path);
4904
+ }
4905
+ if (seen.has(name)) {
4906
+ err(`Cyclic workflow inputs reference "${ref}"`, path);
4907
+ }
4908
+ seen.add(name);
4909
+ const resolved = resolveInputRefs(target, components, path, seen);
4910
+ seen.delete(name);
4911
+ return resolved;
4912
+ }
4913
+ const out = {};
4914
+ for (const [key, value] of Object.entries(record)) {
4915
+ out[key] = resolveInputRefs(value, components, path, seen);
4916
+ }
4917
+ return out;
4918
+ }
4919
+ async function prepareSources(doc, options) {
4920
+ const declared = new Map(doc.sourceDescriptions.map((s) => [s.name, s]));
4921
+ const generators = /* @__PURE__ */ new Map();
4922
+ const sourceTypes = /* @__PURE__ */ new Map();
4923
+ for (const [name, source] of Object.entries(options.sources ?? {})) {
4924
+ if (!declared.has(name)) {
4925
+ err(`options.sources contains "${name}", which is not a declared source description`, "/sourceDescriptions", {
4926
+ declared: [...declared.keys()]
4927
+ });
4928
+ }
4929
+ if (source instanceof OpenAPIToolGenerator) {
4930
+ generators.set(name, source);
4931
+ } else {
4932
+ generators.set(name, await OpenAPIToolGenerator.fromJSON(source, options.loadOptions));
4933
+ }
4934
+ }
4935
+ for (const [name, source] of declared) {
4936
+ sourceTypes.set(name, source.type ?? "openapi");
4937
+ }
4938
+ const operationIndex = /* @__PURE__ */ new Map();
4939
+ for (const [name, generator] of generators) {
4940
+ const document = generator.getDocument();
4941
+ for (const [pathStr, pathItem] of Object.entries(document.paths ?? {})) {
4942
+ if (!pathItem || typeof pathItem !== "object") continue;
4943
+ for (const method of HTTP_METHODS) {
4944
+ const operation = pathItem[method];
4945
+ if (!operation || typeof operation !== "object") continue;
4946
+ const operationId = operation["operationId"];
4947
+ if (typeof operationId !== "string") continue;
4948
+ const hits = operationIndex.get(operationId) ?? [];
4949
+ hits.push({ source: name, path: pathStr, method });
4950
+ operationIndex.set(operationId, hits);
4951
+ }
4952
+ }
4953
+ }
4954
+ return { generators, operationIndex, sourceTypes };
4955
+ }
4956
+ function requireGenerator(ctx, source, path) {
4957
+ if (ctx.sourceTypes.get(source) === "arazzo") {
4958
+ err(`Source "${source}" has type "arazzo" \u2014 nested Arazzo sources are not supported`, path);
4959
+ }
4960
+ const generator = ctx.generators.get(source);
4961
+ if (!generator) {
4962
+ err(`No document supplied for source "${source}" (add it to options.sources)`, path, {
4963
+ supplied: [...ctx.generators.keys()]
4964
+ });
4965
+ }
4966
+ return generator;
4967
+ }
4968
+ function parseOperationPath(value, path) {
4969
+ if (!value.startsWith("{")) {
4970
+ err(`operationPath "${value}" must start with a "{$sourceDescriptions...}" expression`, path);
4971
+ }
4972
+ const close = value.indexOf("}");
4973
+ if (close === -1) {
4974
+ err(`operationPath "${value}" is missing "}"`, path);
4975
+ }
4976
+ const ast = parseRuntimeExpression(value.slice(1, close), path);
4977
+ if (ast.type !== "sourceDescriptions" || ast.path.length !== 2 || ast.path[1] !== "url") {
4978
+ err(`operationPath "${value}" must reference $sourceDescriptions.<name>.url`, path);
4979
+ }
4980
+ const source = ast.path[0];
4981
+ const rest = value.slice(close + 1);
4982
+ if (!rest.startsWith("#/")) {
4983
+ err(`operationPath "${value}" requires a "#/paths/..." JSON Pointer after the source expression`, path);
4984
+ }
4985
+ const segments = rest.slice(2).split("/").map((segment) => segment.replace(/~1/g, "/").replace(/~0/g, "~"));
4986
+ if (segments.length !== 3 || segments[0] !== "paths") {
4987
+ err(`operationPath pointer in "${value}" must have the shape #/paths/<path>/<method>`, path);
4988
+ }
4989
+ const method = segments[2].toLowerCase();
4990
+ if (!HTTP_METHODS.includes(method)) {
4991
+ err(`operationPath "${value}" ends in unknown HTTP method "${segments[2]}"`, path);
4992
+ }
4993
+ return { source, path: segments[1], method };
4994
+ }
4995
+ function resolveOperationRef(step, ctx, path) {
4996
+ if (step.operationPath !== void 0) {
4997
+ return parseOperationPath(step.operationPath, path);
4998
+ }
4999
+ const ref = step.operationId;
5000
+ if (ref.startsWith("$")) {
5001
+ const ast = parseRuntimeExpression(ref, path);
5002
+ if (ast.type !== "sourceDescriptions" || ast.path.length < 2) {
5003
+ err(`operationId expression "${ref}" must be $sourceDescriptions.<name>.<operationId>`, path);
5004
+ }
5005
+ const source = ast.path[0];
5006
+ const operationId = ast.path.slice(1).join(".");
5007
+ const hits2 = (ctx.operationIndex.get(operationId) ?? []).filter((h) => h.source === source);
5008
+ if (hits2.length === 0) {
5009
+ requireGenerator(ctx, source, path);
5010
+ err(`operationId "${operationId}" not found in source "${source}"`, path);
5011
+ }
5012
+ if (hits2.length > 1) {
5013
+ err(`operationId "${operationId}" is duplicated inside source "${source}"`, path, { hits: hits2 });
5014
+ }
5015
+ return { ...hits2[0], operationId };
5016
+ }
5017
+ const hits = ctx.operationIndex.get(ref) ?? [];
5018
+ if (hits.length === 0) {
5019
+ err(`operationId "${ref}" not found in any supplied source (${[...ctx.generators.keys()].join(", ") || "none"})`, path);
5020
+ }
5021
+ if (hits.length > 1) {
5022
+ err(
5023
+ `operationId "${ref}" is ambiguous across sources (${hits.map((h) => h.source).join(", ")}) \u2014 pin it with $sourceDescriptions.<name>.${ref}`,
5024
+ path,
5025
+ { hits }
5026
+ );
5027
+ }
5028
+ return { ...hits[0], operationId: ref };
5029
+ }
5030
+ function checkCycles(edges, kind) {
5031
+ const state = /* @__PURE__ */ new Map();
5032
+ for (const start of edges.keys()) {
5033
+ if (state.get(start) === "done") continue;
5034
+ const stack = [{ node: start, next: 0 }];
5035
+ state.set(start, "visiting");
5036
+ while (stack.length > 0) {
5037
+ const frame = stack[stack.length - 1];
5038
+ const targets = edges.get(frame.node) ?? [];
5039
+ if (frame.next >= targets.length) {
5040
+ state.set(frame.node, "done");
5041
+ stack.pop();
5042
+ continue;
5043
+ }
5044
+ const target = targets[frame.next++];
5045
+ const targetState = state.get(target);
5046
+ if (targetState === "visiting") {
5047
+ const cycle = [...stack.map((f) => f.node), target];
5048
+ err(`Cyclic ${kind}: ${cycle.slice(cycle.indexOf(target)).join(" -> ")}`, "/workflows");
5049
+ }
5050
+ if (targetState !== "done") {
5051
+ state.set(target, "visiting");
5052
+ stack.push({ node: target, next: 0 });
5053
+ }
5054
+ }
5055
+ }
5056
+ }
5057
+ function toCriterionIR(criterion, path) {
5058
+ const ir = {
5059
+ condition: criterion.condition,
5060
+ type: "simple"
5061
+ };
5062
+ if (criterion.context !== void 0) {
5063
+ ir.context = parseRuntimeExpression(criterion.context, path);
5064
+ }
5065
+ if (typeof criterion.type === "string") {
5066
+ ir.type = criterion.type;
5067
+ } else if (criterion.type) {
5068
+ ir.type = criterion.type.type;
5069
+ ir.version = criterion.type.version;
5070
+ }
5071
+ return ir;
5072
+ }
5073
+ function toActionIR(action, kind, path) {
5074
+ const failure = action;
5075
+ return {
5076
+ name: action.name,
5077
+ kind,
5078
+ type: action.type,
5079
+ ...action.workflowId !== void 0 && { workflowId: action.workflowId },
5080
+ ...action.stepId !== void 0 && { stepId: action.stepId },
5081
+ ...failure.retryAfter !== void 0 && { retryAfter: failure.retryAfter },
5082
+ ...failure.retryLimit !== void 0 && { retryLimit: failure.retryLimit },
5083
+ ...action.criteria && { criteria: action.criteria.map((c, i) => toCriterionIR(c, `${path}/criteria/${i}`)) }
5084
+ };
5085
+ }
5086
+ function resolveActions(actions, kind, components, path) {
5087
+ const group = kind === "success" ? "successActions" : "failureActions";
5088
+ return actions.map((action, index) => {
5089
+ const aPath = `${path}/${index}`;
5090
+ const concrete = resolveReusable(action, components, group, aPath);
5091
+ validateActionObject(concrete, kind, aPath);
5092
+ return toActionIR(concrete, kind, aPath);
5093
+ });
5094
+ }
5095
+ function resolveParameters(parameters, components, requireIn, path) {
5096
+ const seen = /* @__PURE__ */ new Set();
5097
+ return parameters.map((parameter, index) => {
5098
+ const pPath = `${path}/${index}`;
5099
+ const concrete = resolveReusable(parameter, components, "parameters", pPath);
5100
+ validateParameterObject(concrete, requireIn, pPath);
5101
+ const key = `${concrete.name} ${concrete.in ?? ""}`;
5102
+ if (seen.has(key)) {
5103
+ err(`Duplicate parameter "${concrete.name}"${concrete.in ? ` (in: ${concrete.in})` : ""}`, pPath);
5104
+ }
5105
+ seen.add(key);
5106
+ return {
5107
+ name: concrete.name,
5108
+ ...concrete.in !== void 0 && { in: concrete.in },
5109
+ value: parseExpressionValue(concrete.value, pPath)
5110
+ };
5111
+ });
5112
+ }
5113
+ function parseOutputs(outputs, path) {
5114
+ if (!outputs) return void 0;
5115
+ const parsed = {};
5116
+ for (const [name, expression] of Object.entries(outputs)) {
5117
+ parsed[name] = parseRuntimeExpression(expression, `${path}/${name}`);
5118
+ }
5119
+ return parsed;
5120
+ }
5121
+ async function resolveStepOperation(ref, ctx, docPath) {
5122
+ const key = `${ref.source} ${ref.method} ${ref.path}`;
5123
+ let cached = ctx.operationCache.get(key);
5124
+ if (!cached) {
5125
+ const generator = requireGenerator(ctx.sources, ref.source, docPath);
5126
+ cached = generator.generateTool(ref.path, ref.method, ctx.generateOptions).catch((error) => {
5127
+ const message = error instanceof Error ? error.message : String(error);
5128
+ throw new ArazzoError(
5129
+ `Failed to resolve ${ref.method.toUpperCase()} ${ref.path} from source "${ref.source}": ${message}`,
5130
+ { path: docPath, source: ref.source }
5131
+ );
5132
+ });
5133
+ ctx.operationCache.set(key, cached);
5134
+ }
5135
+ return cached;
5136
+ }
5137
+ async function buildStepIR(step, ctx, path) {
5138
+ const components = ctx.doc.components;
5139
+ const base = {
5140
+ stepId: step.stepId,
5141
+ ...step.description !== void 0 && { description: step.description },
5142
+ ...step.parameters && {
5143
+ parameters: resolveParameters(
5144
+ step.parameters,
5145
+ components,
5146
+ step.workflowId !== void 0 ? false : true,
5147
+ `${path}/parameters`
5148
+ )
5149
+ },
5150
+ ...step.successCriteria && {
5151
+ successCriteria: step.successCriteria.map((c, i) => toCriterionIR(c, `${path}/successCriteria/${i}`))
5152
+ },
5153
+ ...step.onSuccess && { onSuccess: resolveActions(step.onSuccess, "success", components, `${path}/onSuccess`) },
5154
+ ...step.onFailure && { onFailure: resolveActions(step.onFailure, "failure", components, `${path}/onFailure`) },
5155
+ ...step.outputs && { outputs: parseOutputs(step.outputs, `${path}/outputs`) }
5156
+ };
5157
+ if (step.workflowId !== void 0) {
5158
+ if (step.requestBody !== void 0) {
5159
+ err(`Step "${step.stepId}" invokes a workflow and must not declare a requestBody`, `${path}/requestBody`);
5160
+ }
5161
+ if (step.workflowId.startsWith("$")) {
5162
+ err(`Step "${step.stepId}" invokes a workflow in another Arazzo document \u2014 nested Arazzo sources are not supported`, path);
5163
+ }
5164
+ if (!ctx.workflowIds.has(step.workflowId)) {
5165
+ err(`Step "${step.stepId}" references unknown workflow "${step.workflowId}"`, path);
5166
+ }
5167
+ const ir2 = { kind: "workflow", workflowId: step.workflowId, ...base };
5168
+ return ir2;
5169
+ }
5170
+ const ref = resolveOperationRef(step, ctx.sources, path);
5171
+ const tool = await resolveStepOperation(ref, ctx, path);
5172
+ const operation = {
5173
+ inputSchema: tool.inputSchema,
5174
+ outputSchema: tool.outputSchema,
5175
+ mapper: tool.mapper,
5176
+ ...tool.metadata.security && { security: tool.metadata.security },
5177
+ ...tool.metadata.servers && { servers: tool.metadata.servers }
5178
+ };
5179
+ let requestBody;
5180
+ if (step.requestBody !== void 0) {
5181
+ if (!step.requestBody || typeof step.requestBody !== "object") {
5182
+ err(`Step "${step.stepId}" requestBody must be an object`, `${path}/requestBody`);
5183
+ }
5184
+ requestBody = {
5185
+ ...step.requestBody.contentType !== void 0 && { contentType: step.requestBody.contentType },
5186
+ ...step.requestBody.payload !== void 0 && { payload: step.requestBody.payload }
5187
+ };
5188
+ const expressions = collectPayloadExpressions(step.requestBody.payload, `${path}/requestBody/payload`);
5189
+ if (expressions.length > 0) {
5190
+ requestBody.payloadExpressions = expressions;
5191
+ }
5192
+ if (step.requestBody.replacements !== void 0) {
5193
+ if (!Array.isArray(step.requestBody.replacements)) {
5194
+ err(`Step "${step.stepId}" requestBody.replacements must be an array`, `${path}/requestBody/replacements`);
5195
+ }
5196
+ requestBody.replacements = step.requestBody.replacements.map((replacement, index) => {
5197
+ const rPath = `${path}/requestBody/replacements/${index}`;
5198
+ if (!replacement || typeof replacement !== "object" || typeof replacement.target !== "string") {
5199
+ err('Replacement requires a string "target"', rPath);
5200
+ }
5201
+ return { target: replacement.target, value: parseExpressionValue(replacement.value, rPath) };
5202
+ });
5203
+ }
5204
+ }
5205
+ const ir = {
5206
+ kind: "operation",
5207
+ source: ref.source,
5208
+ path: ref.path,
5209
+ method: ref.method,
5210
+ ...ref.operationId !== void 0 && { operationId: ref.operationId },
5211
+ operation,
5212
+ ...requestBody && { requestBody },
5213
+ ...base
5214
+ };
5215
+ return ir;
5216
+ }
5217
+ function isRecord(value) {
5218
+ return typeof value === "object" && value !== null && !Array.isArray(value);
5219
+ }
5220
+ function walkPointer(schema, pointer) {
5221
+ if (pointer === void 0 || pointer === "") {
5222
+ return schema;
5223
+ }
5224
+ let node = schema;
5225
+ for (const rawSegment of pointer.slice(1).split("/")) {
5226
+ const segment = rawSegment.replace(/~1/g, "/").replace(/~0/g, "~");
5227
+ if (!isRecord(node)) return void 0;
5228
+ const properties = node["properties"];
5229
+ if (isRecord(properties) && properties[segment] !== void 0) {
5230
+ node = properties[segment];
5231
+ continue;
5232
+ }
5233
+ if (/^\d+$/.test(segment) && node["items"] !== void 0 && !Array.isArray(node["items"])) {
5234
+ node = node["items"];
5235
+ continue;
5236
+ }
5237
+ return void 0;
5238
+ }
5239
+ return node;
5240
+ }
5241
+ function primaryResponseSchema(outputSchema) {
5242
+ if (isRecord(outputSchema) && Array.isArray(outputSchema["oneOf"])) {
5243
+ const variants = outputSchema["oneOf"];
5244
+ if (variants.length > 0 && variants.every((v) => isRecord(v) && v["x-status-code"] !== void 0)) {
5245
+ return variants[0];
5246
+ }
5247
+ }
5248
+ return outputSchema;
5249
+ }
5250
+ function deriveOutputSchema(ast, steps, inputSchema, depth, stepContext) {
5251
+ if (depth >= OUTPUT_DERIVATION_MAX_DEPTH) {
5252
+ return {};
5253
+ }
5254
+ if (ast.type === "statusCode") {
5255
+ return { type: "number" };
5256
+ }
5257
+ if (ast.type === "url" || ast.type === "method") {
5258
+ return { type: "string" };
5259
+ }
5260
+ if (ast.type === "response") {
5261
+ if (ast.source !== "body") {
5262
+ return { type: "string" };
5263
+ }
5264
+ if (!stepContext) {
5265
+ return {};
5266
+ }
5267
+ const body = primaryResponseSchema(stepContext.operation.outputSchema);
5268
+ const target = walkPointer(body, ast.pointer);
5269
+ return isRecord(target) ? target : {};
5270
+ }
5271
+ if (ast.type === "inputs") {
5272
+ const properties = isRecord(inputSchema) ? inputSchema["properties"] : void 0;
5273
+ const target = isRecord(properties) ? properties[ast.path.join(".")] : void 0;
5274
+ return isRecord(target) ? target : {};
5275
+ }
5276
+ if (ast.type === "steps" && ast.path.length >= 3 && ast.path[1] === "outputs") {
5277
+ const step = steps.get(ast.path[0]);
5278
+ if (step?.kind === "operation") {
5279
+ const stepOutput = step.outputs?.[ast.path.slice(2).join(".")];
5280
+ if (stepOutput) {
5281
+ return deriveOutputSchema(stepOutput, steps, inputSchema, depth + 1, step);
5282
+ }
5283
+ }
5284
+ return {};
5285
+ }
5286
+ return {};
5287
+ }
5288
+ function deriveOutputsSchema(outputs, steps, inputSchema) {
5289
+ if (!outputs) {
5290
+ return void 0;
5291
+ }
5292
+ const stepMap = new Map(steps.map((s) => [s.stepId, s]));
5293
+ const properties = {};
5294
+ for (const [name, ast] of Object.entries(outputs)) {
5295
+ const derived = deriveOutputSchema(ast, stepMap, inputSchema, 0);
5296
+ const copied = JSON.parse(JSON.stringify(derived));
5297
+ properties[name] = { ...copied, description: `Arazzo output: ${ast.raw}` };
5298
+ }
5299
+ return { type: "object", properties };
5300
+ }
5301
+ function applySchemaPipeline(schema, options, isInputRoot) {
5302
+ const formatResolvers = {
5303
+ ...options.resolveFormats ? BUILTIN_FORMAT_RESOLVERS : {},
5304
+ ...options.formatResolvers
5305
+ };
5306
+ let resolved = Object.keys(formatResolvers).length > 0 ? resolveSchemaFormats(schema, formatResolvers) : schema;
5307
+ resolved = SchemaBuilder.truncateDepth(resolved, Math.max(1, options.maxSchemaDepth ?? 10));
5308
+ if (options.stripExamples) resolved = SchemaBuilder.stripExamples(resolved);
5309
+ if (options.maxDescriptionLength !== void 0) {
5310
+ resolved = SchemaBuilder.capDescriptions(resolved, options.maxDescriptionLength);
5311
+ }
5312
+ if (options.maxProperties !== void 0) {
5313
+ if (isInputRoot) {
5314
+ const properties = resolved.properties;
5315
+ if (properties && typeof properties === "object") {
5316
+ const limited = {};
5317
+ for (const [key, value] of Object.entries(properties)) {
5318
+ limited[key] = SchemaBuilder.limitProperties(value, options.maxProperties);
5319
+ }
5320
+ resolved = { ...resolved, properties: limited };
5321
+ }
5322
+ } else {
5323
+ resolved = SchemaBuilder.limitProperties(resolved, options.maxProperties);
5324
+ }
5325
+ }
5326
+ if (options.target) {
5327
+ resolved = applyClientTarget(resolved, options.target);
5328
+ }
5329
+ return resolved;
5330
+ }
5331
+ function buildWorkflowTool(workflow, stepIRs, ctx, wPath) {
5332
+ const options = ctx.generateOptions;
5333
+ let inputSchema;
5334
+ let rawInputSchema;
5335
+ if (workflow.inputs !== void 0) {
5336
+ const resolved = resolveInputRefs(workflow.inputs, ctx.doc.components, `${wPath}/inputs`, /* @__PURE__ */ new Set());
5337
+ rawInputSchema = toJsonSchema(resolved);
5338
+ inputSchema = applySchemaPipeline(rawInputSchema, options, true);
5339
+ } else {
5340
+ inputSchema = { type: "object", properties: {} };
5341
+ }
5342
+ const derivedOutput = deriveOutputsSchema(parseOutputs(workflow.outputs, `${wPath}/outputs`), stepIRs, rawInputSchema);
5343
+ const outputSchema = derivedOutput ? applySchemaPipeline(derivedOutput, options, false) : void 0;
5344
+ const name = normalizeToolName(workflow.workflowId, options.maxToolNameLength ?? 64, workflow.workflowId);
5345
+ const description = workflow.summary && workflow.description ? `${workflow.summary}
5346
+
5347
+ ${workflow.description}` : workflow.summary ?? workflow.description ?? `Arazzo workflow: ${workflow.workflowId}`;
5348
+ const operationSteps = stepIRs.filter((s) => s.kind === "operation");
5349
+ const allReadOnly = operationSteps.length === stepIRs.length && operationSteps.every((s) => inferAnnotationsFromMethod(s.method).readOnlyHint === true);
5350
+ const security = [];
5351
+ const seenSecurity = /* @__PURE__ */ new Set();
5352
+ for (const step of operationSteps) {
5353
+ for (const requirement of step.operation.security ?? []) {
5354
+ const key = JSON.stringify(requirement);
5355
+ if (!seenSecurity.has(key)) {
5356
+ seenSecurity.add(key);
5357
+ security.push(requirement);
5358
+ }
5359
+ }
5360
+ }
5361
+ const ir = {
5362
+ arazzoVersion: ctx.doc.arazzo,
5363
+ workflowId: workflow.workflowId,
5364
+ ...workflow.summary !== void 0 && { summary: workflow.summary },
5365
+ ...workflow.description !== void 0 && { description: workflow.description },
5366
+ ...rawInputSchema !== void 0 && { inputSchema: rawInputSchema },
5367
+ ...workflow.dependsOn && { dependsOn: workflow.dependsOn },
5368
+ ...workflow.parameters && {
5369
+ parameters: resolveParameters(workflow.parameters, ctx.doc.components, void 0, `${wPath}/parameters`)
5370
+ },
5371
+ steps: stepIRs,
5372
+ ...workflow.successActions && {
5373
+ successActions: resolveActions(workflow.successActions, "success", ctx.doc.components, `${wPath}/successActions`)
5374
+ },
5375
+ ...workflow.failureActions && {
5376
+ failureActions: resolveActions(workflow.failureActions, "failure", ctx.doc.components, `${wPath}/failureActions`)
5377
+ },
5378
+ ...workflow.outputs && { outputs: parseOutputs(workflow.outputs, `${wPath}/outputs`) }
5379
+ };
5380
+ const tool = {
5381
+ name,
5382
+ ...workflow.summary !== void 0 && { title: workflow.summary },
5383
+ description,
5384
+ ...allReadOnly && {
5385
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }
5386
+ },
5387
+ inputSchema,
5388
+ outputSchema,
5389
+ // A workflow tool has no single HTTP shape — each step's mapper lives at
5390
+ // metadata.workflow.steps[*].operation.mapper
5391
+ mapper: [],
5392
+ metadata: {
5393
+ path: `arazzo:${workflow.workflowId}`,
5394
+ method: "post",
5395
+ operationId: workflow.workflowId,
5396
+ ...workflow.summary !== void 0 && { operationSummary: workflow.summary },
5397
+ ...workflow.description !== void 0 && { operationDescription: workflow.description },
5398
+ ...security.length > 0 && { security },
5399
+ workflow: ir
5400
+ }
5401
+ };
5402
+ if (options.emitTypeSignatures) {
5403
+ tool.metadata.typescript = emitToolTypeScript(name, description, inputSchema, outputSchema, {
5404
+ maxDepth: Math.max(1, options.maxSchemaDepth ?? 10)
5405
+ });
5406
+ }
5407
+ return tool;
5408
+ }
5409
+ async function fromArazzo(document, options) {
5410
+ const doc = parseArazzoInput(document);
5411
+ validateDocument(doc);
5412
+ const sources = await prepareSources(doc, options);
5413
+ const workflowIds = new Set(doc.workflows.map((w) => w.workflowId));
5414
+ const dependsEdges = /* @__PURE__ */ new Map();
5415
+ const nestedEdges = /* @__PURE__ */ new Map();
5416
+ const declaredSources = new Set(doc.sourceDescriptions.map((s) => s.name));
5417
+ doc.workflows.forEach((workflow, index) => {
5418
+ if (workflow.dependsOn !== void 0 && !Array.isArray(workflow.dependsOn)) {
5419
+ err(`Workflow "${workflow.workflowId}" dependsOn must be an array of workflowIds`, `/workflows/${index}/dependsOn`);
5420
+ }
5421
+ const localTargets = [];
5422
+ for (const target of workflow.dependsOn ?? []) {
5423
+ if (typeof target !== "string") {
5424
+ err(`Workflow "${workflow.workflowId}" dependsOn entries must be strings`, `/workflows/${index}/dependsOn`);
5425
+ }
5426
+ if (target.startsWith("$")) {
5427
+ const ast = parseRuntimeExpression(target, `/workflows/${index}/dependsOn`);
5428
+ if (ast.type !== "sourceDescriptions" || ast.path.length < 2 || !declaredSources.has(ast.path[0])) {
5429
+ err(
5430
+ `Workflow "${workflow.workflowId}" dependsOn "${target}" must reference a declared source ($sourceDescriptions.<name>.<workflowId>)`,
5431
+ `/workflows/${index}/dependsOn`
5432
+ );
5433
+ }
5434
+ continue;
5435
+ }
5436
+ if (!workflowIds.has(target)) {
5437
+ err(`Workflow "${workflow.workflowId}" dependsOn unknown workflow "${target}"`, `/workflows/${index}/dependsOn`);
5438
+ }
5439
+ localTargets.push(target);
5440
+ }
5441
+ dependsEdges.set(workflow.workflowId, localTargets);
5442
+ nestedEdges.set(
5443
+ workflow.workflowId,
5444
+ workflow.steps.filter((s) => s.workflowId !== void 0 && !s.workflowId.startsWith("$")).map((s) => s.workflowId)
5445
+ );
5446
+ });
5447
+ checkCycles(dependsEdges, "dependsOn chain");
5448
+ checkCycles(nestedEdges, "workflow invocation");
5449
+ const ctx = {
5450
+ doc,
5451
+ sources,
5452
+ generateOptions: options.generateOptions ?? {},
5453
+ workflowIds,
5454
+ operationCache: /* @__PURE__ */ new Map()
5455
+ };
5456
+ const tools = [];
5457
+ const usedNames = /* @__PURE__ */ new Set();
5458
+ for (let wIndex = 0; wIndex < doc.workflows.length; wIndex++) {
5459
+ const workflow = doc.workflows[wIndex];
5460
+ const wPath = `/workflows/${wIndex}`;
5461
+ const stepIRs = [];
5462
+ for (let sIndex = 0; sIndex < workflow.steps.length; sIndex++) {
5463
+ stepIRs.push(await buildStepIR(workflow.steps[sIndex], ctx, `${wPath}/steps/${sIndex}`));
5464
+ }
5465
+ let tool = buildWorkflowTool(workflow, stepIRs, ctx, wPath);
5466
+ if (usedNames.has(tool.name)) {
5467
+ const maxLength = ctx.generateOptions.maxToolNameLength ?? 64;
5468
+ let seed = workflow.workflowId;
5469
+ let deduped = normalizeToolName(`${tool.name}_${fnv1aHex(seed)}`, maxLength, seed);
5470
+ while (usedNames.has(deduped)) {
5471
+ seed += "#";
5472
+ deduped = normalizeToolName(`${tool.name}_${fnv1aHex(seed)}`, maxLength, seed);
5473
+ }
5474
+ tool = { ...tool, name: deduped };
5475
+ }
5476
+ usedNames.add(tool.name);
5477
+ tools.push(tool);
5478
+ }
5479
+ return tools;
5480
+ }
5481
+
3710
5482
  // src/request-builder.ts
3711
5483
  var RESERVED_DECODE = {
3712
5484
  "%3A": ":",
@@ -3943,7 +5715,7 @@ function buildHttpRequest(tool, input, options = {}) {
3943
5715
  case "body":
3944
5716
  hasBody = true;
3945
5717
  contentType = contentType ?? mapper.serialization?.contentType ?? "application/json";
3946
- if (mapper.serialization?.binary) binaryBody = true;
5718
+ if (mapper.serialization?.binary && mapper.wholeBody) binaryBody = true;
3947
5719
  if (mapper.wholeBody) {
3948
5720
  rawBody = value;
3949
5721
  } else {
@@ -4008,7 +5780,7 @@ function buildHttpRequest(tool, input, options = {}) {
4008
5780
  if (typeof Blob !== "undefined" && v instanceof Blob) {
4009
5781
  form.append(k, v);
4010
5782
  } else if (v instanceof Uint8Array) {
4011
- form.append(k, new Blob([v]));
5783
+ form.append(k, new Blob([new Uint8Array(v)]));
4012
5784
  } else if (isPlainObject(v) || Array.isArray(v)) {
4013
5785
  form.append(k, JSON.stringify(v));
4014
5786
  } else {
@@ -4040,13 +5812,14 @@ function buildHttpRequest(tool, input, options = {}) {
4040
5812
  // src/sdk.ts
4041
5813
  function toSdkTool(tool, wrapper) {
4042
5814
  const wrapSchema = wrapper?.fromJsonSchema ?? ((schema) => schema);
5815
+ const outputSchema = tool.outputSchema !== void 0 && tool.outputSchema["type"] === "object" ? tool.outputSchema : void 0;
4043
5816
  return [
4044
5817
  tool.name,
4045
5818
  {
4046
5819
  ...tool.title !== void 0 && { title: tool.title },
4047
5820
  description: tool.description,
4048
5821
  inputSchema: wrapSchema(tool.inputSchema),
4049
- ...tool.outputSchema !== void 0 && { outputSchema: wrapSchema(tool.outputSchema) },
5822
+ ...outputSchema !== void 0 && { outputSchema: wrapSchema(outputSchema) },
4050
5823
  ...tool.annotations !== void 0 && { annotations: tool.annotations }
4051
5824
  }
4052
5825
  ];
@@ -4091,8 +5864,10 @@ function analyzeToolSet(tools, options = {}) {
4091
5864
  }
4092
5865
  // Annotate the CommonJS export names for ESM import in node:
4093
5866
  0 && (module.exports = {
5867
+ ArazzoError,
4094
5868
  BLOCKED_HOSTNAMES,
4095
5869
  BUILTIN_FORMAT_RESOLVERS,
5870
+ CODECALL_RESERVED_NAMESPACES,
4096
5871
  GenerationError,
4097
5872
  LoadError,
4098
5873
  OpenAPIToolError,
@@ -4119,10 +5894,14 @@ function analyzeToolSet(tools, options = {}) {
4119
5894
  decodeIpv4MappedIpv6,
4120
5895
  defaultLookup,
4121
5896
  demoteFormats,
5897
+ deriveSecurityElicitations,
5898
+ dottedNaming,
5899
+ emitToolTypeScript,
4122
5900
  enforceClosedObjects,
4123
5901
  ensureArrayItems,
4124
5902
  estimateToolTokens,
4125
5903
  extractExtensionOverrides,
5904
+ fromArazzo,
4126
5905
  inferAnnotationsFromMethod,
4127
5906
  inlineLocalRefs,
4128
5907
  isBlockedAddress,
@@ -4130,10 +5909,12 @@ function analyzeToolSet(tools, options = {}) {
4130
5909
  isReferenceObject,
4131
5910
  lintDocument,
4132
5911
  normalizeSsrfOptions,
5912
+ parseRuntimeExpression,
4133
5913
  requireAllProperties,
4134
5914
  resolveExtensionEnabled,
4135
5915
  resolveSchemaFormats,
4136
5916
  safeFetch,
4137
5917
  toJsonSchema,
5918
+ toPascalIdentifier,
4138
5919
  toSdkTool
4139
5920
  });