mcp-from-openapi 2.6.1 → 2.7.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/esm/index.mjs CHANGED
@@ -6,9 +6,24 @@ function isReferenceObject(obj) {
6
6
  return obj && typeof obj === "object" && "$ref" in obj;
7
7
  }
8
8
  function toJsonSchema(schema) {
9
+ return convertSchema(schema, /* @__PURE__ */ new Set());
10
+ }
11
+ function convertSchema(schema, stack) {
9
12
  if (isReferenceObject(schema)) {
10
13
  return { $ref: schema.$ref };
11
14
  }
15
+ if (stack.has(schema)) {
16
+ return {};
17
+ }
18
+ stack.add(schema);
19
+ try {
20
+ return convertSchemaInner(schema, stack);
21
+ } finally {
22
+ stack.delete(schema);
23
+ }
24
+ }
25
+ function convertSchemaInner(schema, stack) {
26
+ const recurse = (value) => convertSchema(value, stack);
12
27
  const { exclusiveMaximum, exclusiveMinimum, maximum, minimum, ...rest } = schema;
13
28
  const { nullable, example, ...cleanRest } = rest;
14
29
  const result = { ...cleanRest };
@@ -60,34 +75,34 @@ function toJsonSchema(schema) {
60
75
  if (result["properties"] && typeof result["properties"] === "object") {
61
76
  const props = {};
62
77
  for (const [key, value] of Object.entries(result["properties"])) {
63
- props[key] = toJsonSchema(value);
78
+ props[key] = recurse(value);
64
79
  }
65
80
  result["properties"] = props;
66
81
  }
67
82
  if (result["items"]) {
68
83
  if (Array.isArray(result["items"])) {
69
- result["items"] = result["items"].map(toJsonSchema);
84
+ result["items"] = result["items"].map(recurse);
70
85
  } else {
71
- result["items"] = toJsonSchema(result["items"]);
86
+ result["items"] = recurse(result["items"]);
72
87
  }
73
88
  }
74
89
  if (result["additionalProperties"] && typeof result["additionalProperties"] === "object") {
75
- result["additionalProperties"] = toJsonSchema(result["additionalProperties"]);
90
+ result["additionalProperties"] = recurse(result["additionalProperties"]);
76
91
  }
77
92
  for (const key of ["allOf", "anyOf", "oneOf"]) {
78
93
  if (result[key] && Array.isArray(result[key])) {
79
- result[key] = result[key].map(toJsonSchema);
94
+ result[key] = result[key].map(recurse);
80
95
  }
81
96
  }
82
97
  if (result["not"]) {
83
- result["not"] = toJsonSchema(result["not"]);
98
+ result["not"] = recurse(result["not"]);
84
99
  }
85
100
  for (const key of ["patternProperties", "$defs", "definitions", "dependentSchemas"]) {
86
101
  const value = result[key];
87
102
  if (value && typeof value === "object" && !Array.isArray(value)) {
88
103
  const mapped = {};
89
104
  for (const [name, sub] of Object.entries(value)) {
90
- mapped[name] = toJsonSchema(sub);
105
+ mapped[name] = recurse(sub);
91
106
  }
92
107
  result[key] = mapped;
93
108
  }
@@ -104,11 +119,11 @@ function toJsonSchema(schema) {
104
119
  ]) {
105
120
  const value = result[key];
106
121
  if (value && typeof value === "object") {
107
- result[key] = toJsonSchema(value);
122
+ result[key] = recurse(value);
108
123
  }
109
124
  }
110
125
  if (Array.isArray(result["prefixItems"])) {
111
- result["prefixItems"] = result["prefixItems"].map(toJsonSchema);
126
+ result["prefixItems"] = result["prefixItems"].map(recurse);
112
127
  }
113
128
  if (wrapNullable) {
114
129
  const wrapper = {};
@@ -129,8 +144,11 @@ var ParameterResolver = class {
129
144
  namingStrategy;
130
145
  includeExamples;
131
146
  constructor(namingStrategy, options) {
132
- this.namingStrategy = namingStrategy ?? {
133
- conflictResolver: this.defaultConflictResolver
147
+ this.namingStrategy = {
148
+ ...namingStrategy,
149
+ // Bind a supplied resolver to its own strategy object so class-based
150
+ // strategies keep their `this` (we invoke it off a spread clone).
151
+ conflictResolver: namingStrategy?.conflictResolver ? namingStrategy.conflictResolver.bind(namingStrategy) : this.defaultConflictResolver
134
152
  };
135
153
  this.includeExamples = options?.includeExamples ?? false;
136
154
  }
@@ -312,6 +330,9 @@ var ParameterResolver = class {
312
330
  schema["deprecated"] = true;
313
331
  }
314
332
  schema["x-parameter-location"] = param.location;
333
+ if (param.location === "header") {
334
+ schema["x-mcp-header"] = param.name;
335
+ }
315
336
  if (param.style) {
316
337
  schema["x-parameter-style"] = param.style;
317
338
  }
@@ -406,6 +427,9 @@ var ParameterResolver = class {
406
427
  });
407
428
  const schemeInInput = includeInInput === true || Array.isArray(includeInInput) && includeInInput.includes(scheme);
408
429
  if (schemeInInput) {
430
+ if (paramLocation === "header") {
431
+ schema["x-mcp-header"] = headerKey;
432
+ }
409
433
  properties[inputKey] = schema;
410
434
  required.push(inputKey);
411
435
  }
@@ -1078,9 +1102,63 @@ function mergeOverrides(base, layer) {
1078
1102
  ...layer.description !== void 0 && { description: layer.description },
1079
1103
  ...(base.annotations || layer.annotations) && {
1080
1104
  annotations: { ...base.annotations, ...layer.annotations }
1081
- }
1105
+ },
1106
+ ...(base.meta || layer.meta) && { meta: { ...base.meta, ...layer.meta } },
1107
+ ...layer.icons !== void 0 && { icons: layer.icons }
1082
1108
  };
1083
1109
  }
1110
+ function cleanseMeta(node, seen) {
1111
+ if (!node || typeof node !== "object") {
1112
+ return node;
1113
+ }
1114
+ if (seen.has(node)) {
1115
+ return void 0;
1116
+ }
1117
+ seen.add(node);
1118
+ try {
1119
+ if (Array.isArray(node)) {
1120
+ return node.map((item) => cleanseMeta(item, seen));
1121
+ }
1122
+ const out = {};
1123
+ for (const [key, value] of Object.entries(node)) {
1124
+ if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
1125
+ out[key] = cleanseMeta(value, seen);
1126
+ }
1127
+ return out;
1128
+ } finally {
1129
+ seen.delete(node);
1130
+ }
1131
+ }
1132
+ function sanitizeMeta(value) {
1133
+ if (value && typeof value === "object" && !Array.isArray(value)) {
1134
+ return cleanseMeta(value, /* @__PURE__ */ new Set());
1135
+ }
1136
+ return void 0;
1137
+ }
1138
+ function isAllowedIconSrc(src) {
1139
+ const lower = src.toLowerCase();
1140
+ return lower.startsWith("https:") || lower.startsWith("data:");
1141
+ }
1142
+ function sanitizeIcons(value) {
1143
+ if (!Array.isArray(value)) {
1144
+ return void 0;
1145
+ }
1146
+ const icons = [];
1147
+ for (const entry of value) {
1148
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
1149
+ const raw = entry;
1150
+ if (typeof raw["src"] !== "string" || !isAllowedIconSrc(raw["src"])) continue;
1151
+ const icon = { src: raw["src"] };
1152
+ if (typeof raw["mimeType"] === "string") {
1153
+ icon.mimeType = raw["mimeType"];
1154
+ }
1155
+ if (Array.isArray(raw["sizes"]) && raw["sizes"].every((s) => typeof s === "string")) {
1156
+ icon.sizes = [...raw["sizes"]];
1157
+ }
1158
+ icons.push(icon);
1159
+ }
1160
+ return icons.length > 0 ? icons : void 0;
1161
+ }
1084
1162
  function readXMcp(node) {
1085
1163
  return node["x-mcp"];
1086
1164
  }
@@ -1129,16 +1207,24 @@ function extractExtensionOverrides(operation) {
1129
1207
  name: typeof ext["name"] === "string" ? ext["name"] : void 0,
1130
1208
  title: typeof ext["title"] === "string" ? ext["title"] : void 0,
1131
1209
  description: typeof ext["description"] === "string" ? ext["description"] : void 0,
1132
- annotations: pickAnnotations(ext["annotations"])
1210
+ annotations: pickAnnotations(ext["annotations"]),
1211
+ meta: sanitizeMeta(ext["meta"]),
1212
+ icons: sanitizeIcons(ext["icons"])
1133
1213
  });
1134
1214
  }
1135
1215
  const frontmcp = op["x-frontmcp"];
1136
- if (frontmcp && typeof frontmcp === "object" && frontmcp.annotations) {
1137
- const annotations = pickAnnotations(frontmcp.annotations);
1138
- result = mergeOverrides(result, {
1139
- annotations,
1140
- title: typeof frontmcp.annotations.title === "string" ? frontmcp.annotations.title : void 0
1141
- });
1216
+ if (frontmcp && typeof frontmcp === "object") {
1217
+ const layer = {
1218
+ meta: sanitizeMeta(frontmcp.meta),
1219
+ icons: sanitizeIcons(frontmcp.icons)
1220
+ };
1221
+ if (frontmcp.annotations) {
1222
+ layer.annotations = pickAnnotations(frontmcp.annotations);
1223
+ if (typeof frontmcp.annotations.title === "string") {
1224
+ layer.title = frontmcp.annotations.title;
1225
+ }
1226
+ }
1227
+ result = mergeOverrides(result, layer);
1142
1228
  }
1143
1229
  return result;
1144
1230
  }
@@ -1509,6 +1595,13 @@ var RequestBuildError = class extends OpenAPIToolError {
1509
1595
  super(message, context);
1510
1596
  }
1511
1597
  };
1598
+ var ArazzoError = class extends OpenAPIToolError {
1599
+ path;
1600
+ constructor(message, context) {
1601
+ super(message, context);
1602
+ this.path = context?.["path"];
1603
+ }
1604
+ };
1512
1605
  var SchemaError = class extends OpenAPIToolError {
1513
1606
  constructor(message, context) {
1514
1607
  super(message, context);
@@ -2061,7 +2154,8 @@ var Validator = class {
2061
2154
  code: "NO_PATHS"
2062
2155
  });
2063
2156
  } else {
2064
- this.validatePaths(document.paths, errors, warnings);
2157
+ const componentParameters = document.components?.parameters ?? {};
2158
+ this.validatePaths(document.paths, componentParameters, errors, warnings);
2065
2159
  }
2066
2160
  if (!document.servers || document.servers.length === 0) {
2067
2161
  warnings.push({
@@ -2092,7 +2186,18 @@ var Validator = class {
2092
2186
  /**
2093
2187
  * Validate paths
2094
2188
  */
2095
- validatePaths(paths, errors, warnings) {
2189
+ /**
2190
+ * Resolve a local `#/components/parameters/<name>` reference (JSON Pointer
2191
+ * tokens decoded). Returns undefined for external or dangling references.
2192
+ */
2193
+ resolveParameterRef(param, componentParameters) {
2194
+ if (!param || typeof param !== "object" || !("$ref" in param)) return param;
2195
+ const match = /^#\/components\/parameters\/(.+)$/.exec(String(param.$ref));
2196
+ if (!match) return void 0;
2197
+ const name = match[1].replace(/~1/g, "/").replace(/~0/g, "~");
2198
+ return componentParameters[name];
2199
+ }
2200
+ validatePaths(paths, componentParameters, errors, warnings) {
2096
2201
  for (const [path, pathItem] of Object.entries(paths)) {
2097
2202
  if (!pathItem) continue;
2098
2203
  if (!path.startsWith("/")) {
@@ -2104,11 +2209,15 @@ var Validator = class {
2104
2209
  }
2105
2210
  const methods = ["get", "post", "put", "patch", "delete", "head", "options", "trace"];
2106
2211
  let hasOperations = false;
2212
+ const pathLevelParameters = Array.isArray(pathItem.parameters) ? pathItem.parameters : [];
2213
+ if (pathLevelParameters.length > 0) {
2214
+ this.validateParameters(pathLevelParameters, `/paths/${path}/parameters`, errors, warnings);
2215
+ }
2107
2216
  for (const method of methods) {
2108
2217
  const operation = pathItem[method];
2109
2218
  if (operation) {
2110
2219
  hasOperations = true;
2111
- this.validateOperation(operation, path, method, errors, warnings);
2220
+ this.validateOperation(operation, path, method, errors, warnings, pathLevelParameters, componentParameters);
2112
2221
  }
2113
2222
  }
2114
2223
  if (!hasOperations && !pathItem.$ref) {
@@ -2123,7 +2232,7 @@ var Validator = class {
2123
2232
  /**
2124
2233
  * Validate an operation
2125
2234
  */
2126
- validateOperation(operation, path, method, errors, warnings) {
2235
+ validateOperation(operation, path, method, errors, warnings, pathLevelParameters = [], componentParameters = {}) {
2127
2236
  const basePath = `/paths/${path}/${method}`;
2128
2237
  if (!operation.operationId) {
2129
2238
  warnings.push({
@@ -2140,14 +2249,18 @@ var Validator = class {
2140
2249
  });
2141
2250
  }
2142
2251
  if (operation.parameters) {
2143
- this.validateParameters(operation.parameters, path, method, errors, warnings);
2252
+ this.validateParameters(operation.parameters, `${basePath}/parameters`, errors, warnings);
2144
2253
  }
2254
+ const allParameters = [...pathLevelParameters, ...operation.parameters ?? []].map(
2255
+ (p) => this.resolveParameterRef(p, componentParameters)
2256
+ );
2257
+ const hasUnresolvableRefs = allParameters.some((p) => p === void 0);
2145
2258
  const pathParams = path.match(/\{([^{}]+)\}/g)?.map((p) => p.slice(1, -1)) ?? [];
2146
2259
  const definedPathParams = new Set(
2147
- operation.parameters?.filter((p) => p.in === "path").map((p) => p.name) ?? []
2260
+ allParameters.filter((p) => p && p.in === "path").map((p) => p.name)
2148
2261
  );
2149
2262
  for (const param of pathParams) {
2150
- if (!definedPathParams.has(param)) {
2263
+ if (!hasUnresolvableRefs && !definedPathParams.has(param)) {
2151
2264
  errors.push({
2152
2265
  message: `Path parameter '${param}' not defined in parameters: ${method.toUpperCase()} ${path}`,
2153
2266
  path: `${basePath}/parameters`,
@@ -2159,11 +2272,13 @@ var Validator = class {
2159
2272
  /**
2160
2273
  * Validate parameters
2161
2274
  */
2162
- validateParameters(parameters, path, method, errors, warnings) {
2163
- const basePath = `/paths/${path}/${method}/parameters`;
2275
+ validateParameters(parameters, basePath, errors, warnings) {
2164
2276
  for (let i = 0; i < parameters.length; i++) {
2165
2277
  const param = parameters[i];
2166
2278
  const paramPath = `${basePath}/${i}`;
2279
+ if (param && typeof param === "object" && "$ref" in param) {
2280
+ continue;
2281
+ }
2167
2282
  if (!param.name) {
2168
2283
  errors.push({
2169
2284
  message: "Parameter missing name",
@@ -2311,6 +2426,376 @@ function resolveSchemaFormats(schema, resolvers) {
2311
2426
  return result;
2312
2427
  }
2313
2428
 
2429
+ // src/type-signature.ts
2430
+ var DEFAULT_MAX_DEPTH = 8;
2431
+ var IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
2432
+ function toPascalIdentifier(toolName) {
2433
+ const segments = toolName.split(/[^A-Za-z0-9]+/).filter((s) => s.length > 0);
2434
+ const joined = segments.map((s) => s[0].toUpperCase() + s.slice(1)).join("");
2435
+ if (joined === "") {
2436
+ return "Tool";
2437
+ }
2438
+ return /^[0-9]/.test(joined) ? `T${joined}` : joined;
2439
+ }
2440
+ function lowerFirst(name) {
2441
+ return name[0].toLowerCase() + name.slice(1);
2442
+ }
2443
+ function isSchemaRecord(value) {
2444
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2445
+ }
2446
+ function isNullSchema(value) {
2447
+ return isSchemaRecord(value) && value["type"] === "null";
2448
+ }
2449
+ function paren(expr) {
2450
+ return expr.includes(" | ") || expr.includes(" & ") ? `(${expr})` : expr;
2451
+ }
2452
+ function dedupe(parts) {
2453
+ return [...new Set(parts)];
2454
+ }
2455
+ function quoteKey(name) {
2456
+ return IDENTIFIER.test(name) ? name : JSON.stringify(name);
2457
+ }
2458
+ function literalOf(value) {
2459
+ if (value === null) {
2460
+ return "null";
2461
+ }
2462
+ const t = typeof value;
2463
+ if (t === "number") {
2464
+ return Number.isFinite(value) ? JSON.stringify(value) : "number";
2465
+ }
2466
+ if (t === "string" || t === "boolean") {
2467
+ return JSON.stringify(value);
2468
+ }
2469
+ return "unknown";
2470
+ }
2471
+ var RESERVED_WORDS = /* @__PURE__ */ new Set([
2472
+ "break",
2473
+ "case",
2474
+ "catch",
2475
+ "class",
2476
+ "const",
2477
+ "continue",
2478
+ "debugger",
2479
+ "default",
2480
+ "delete",
2481
+ "do",
2482
+ "else",
2483
+ "enum",
2484
+ "export",
2485
+ "extends",
2486
+ "false",
2487
+ "finally",
2488
+ "for",
2489
+ "function",
2490
+ "if",
2491
+ "import",
2492
+ "in",
2493
+ "instanceof",
2494
+ "new",
2495
+ "null",
2496
+ "return",
2497
+ "super",
2498
+ "switch",
2499
+ "this",
2500
+ "throw",
2501
+ "true",
2502
+ "try",
2503
+ "typeof",
2504
+ "var",
2505
+ "void",
2506
+ "while",
2507
+ "with",
2508
+ "implements",
2509
+ "interface",
2510
+ "let",
2511
+ "package",
2512
+ "private",
2513
+ "protected",
2514
+ "public",
2515
+ "static",
2516
+ "yield",
2517
+ "await"
2518
+ ]);
2519
+ function escapeJsdoc(text) {
2520
+ return text.replace(/\*\//g, "*\\/");
2521
+ }
2522
+ function jsdocLines(prop) {
2523
+ if (!isSchemaRecord(prop)) {
2524
+ return [];
2525
+ }
2526
+ const lines = [];
2527
+ const description = prop["description"];
2528
+ if (typeof description === "string" && description !== "") {
2529
+ lines.push(...escapeJsdoc(description).split("\n"));
2530
+ }
2531
+ const format = prop["format"];
2532
+ if (typeof format === "string" && format !== "") {
2533
+ lines.push(`@format ${escapeJsdoc(format)}`);
2534
+ }
2535
+ if ("default" in prop && !(typeof prop["default"] === "number" && !Number.isFinite(prop["default"]))) {
2536
+ const rendered = JSON.stringify(prop["default"]);
2537
+ if (rendered !== void 0) {
2538
+ lines.push(`@default ${escapeJsdoc(rendered)}`);
2539
+ }
2540
+ }
2541
+ if (prop["deprecated"] === true) {
2542
+ lines.push("@deprecated");
2543
+ }
2544
+ return lines;
2545
+ }
2546
+ function renderJsdoc(lines, indent) {
2547
+ if (lines.length === 1) {
2548
+ return `${indent}/** ${lines[0]} */
2549
+ `;
2550
+ }
2551
+ return `${indent}/**
2552
+ ${lines.map((l) => `${indent} * ${l}`).join("\n")}
2553
+ ${indent} */
2554
+ `;
2555
+ }
2556
+ function hasObjectShape(r) {
2557
+ return r["type"] === "object" || r["type"] === void 0 && (r["properties"] !== void 0 || r["additionalProperties"] !== void 0 || r["patternProperties"] !== void 0);
2558
+ }
2559
+ function typeExpr(schema, ctx, depth, indent) {
2560
+ if (schema === true) {
2561
+ return "unknown";
2562
+ }
2563
+ if (schema === false) {
2564
+ return "never";
2565
+ }
2566
+ if (!isSchemaRecord(schema)) {
2567
+ return "unknown";
2568
+ }
2569
+ if (ctx.stack.has(schema)) {
2570
+ return "unknown";
2571
+ }
2572
+ if (depth >= ctx.maxDepth) {
2573
+ return "unknown";
2574
+ }
2575
+ if (schema["$ref"] !== void 0) {
2576
+ return "unknown";
2577
+ }
2578
+ ctx.stack.add(schema);
2579
+ try {
2580
+ return typeExprInner(schema, ctx, depth, indent);
2581
+ } finally {
2582
+ ctx.stack.delete(schema);
2583
+ }
2584
+ }
2585
+ function typeExprInner(r, ctx, depth, indent) {
2586
+ if ("const" in r) {
2587
+ const rendered = literalOf(r["const"]);
2588
+ if (rendered !== "unknown") {
2589
+ return rendered;
2590
+ }
2591
+ }
2592
+ const enumMembers = r["enum"];
2593
+ if (Array.isArray(enumMembers)) {
2594
+ if (enumMembers.length === 0) {
2595
+ return "unknown";
2596
+ }
2597
+ return dedupe(enumMembers.map(literalOf)).join(" | ");
2598
+ }
2599
+ const anyOf = r["anyOf"];
2600
+ if (Array.isArray(anyOf) && anyOf.length === 2) {
2601
+ const nullIdx = anyOf.findIndex(isNullSchema);
2602
+ if (nullIdx >= 0 && !isNullSchema(anyOf[1 - nullIdx])) {
2603
+ return `${paren(typeExpr(anyOf[1 - nullIdx], ctx, depth + 1, indent))} | null`;
2604
+ }
2605
+ }
2606
+ const allOf = r["allOf"];
2607
+ if (Array.isArray(allOf)) {
2608
+ const parts = allOf.map((m) => paren(typeExpr(m, ctx, depth + 1, indent)));
2609
+ if (r["properties"] !== void 0) {
2610
+ parts.push(paren(objectExpr(r, ctx, depth, indent)));
2611
+ }
2612
+ return parts.length === 0 ? "unknown" : dedupe(parts).join(" & ");
2613
+ }
2614
+ const union = Array.isArray(r["oneOf"]) ? r["oneOf"] : Array.isArray(anyOf) ? anyOf : void 0;
2615
+ if (union) {
2616
+ if (union.length === 0) {
2617
+ return "unknown";
2618
+ }
2619
+ return dedupe(union.map((m) => typeExpr(m, ctx, depth + 1, indent))).join(" | ");
2620
+ }
2621
+ const type = r["type"];
2622
+ if (Array.isArray(type)) {
2623
+ const parts = type.filter((t) => typeof t === "string").map((t) => typeExpr({ ...r, type: t }, ctx, depth, indent));
2624
+ return parts.length === 0 ? "unknown" : dedupe(parts).join(" | ");
2625
+ }
2626
+ switch (type) {
2627
+ case "string":
2628
+ return "string";
2629
+ case "number":
2630
+ case "integer":
2631
+ return "number";
2632
+ case "boolean":
2633
+ return "boolean";
2634
+ case "null":
2635
+ return "null";
2636
+ case "array":
2637
+ return arrayExpr(r, ctx, depth, indent);
2638
+ default:
2639
+ if (hasObjectShape(r)) {
2640
+ return objectExpr(r, ctx, depth, indent);
2641
+ }
2642
+ return "unknown";
2643
+ }
2644
+ }
2645
+ function arrayExpr(r, ctx, depth, indent) {
2646
+ const items = r["items"];
2647
+ const prefix = Array.isArray(r["prefixItems"]) ? r["prefixItems"] : Array.isArray(items) ? items : void 0;
2648
+ if (prefix) {
2649
+ const parts = prefix.map((m) => typeExpr(m, ctx, depth + 1, indent));
2650
+ let rest = "";
2651
+ if (Array.isArray(r["prefixItems"]) && items !== void 0 && !Array.isArray(items)) {
2652
+ rest = `, ...${paren(typeExpr(items, ctx, depth + 1, indent))}[]`;
2653
+ }
2654
+ return `[${parts.join(", ")}${rest}]`;
2655
+ }
2656
+ if (items === void 0) {
2657
+ return "unknown[]";
2658
+ }
2659
+ return `${paren(typeExpr(items, ctx, depth + 1, indent))}[]`;
2660
+ }
2661
+ function objectExpr(r, ctx, depth, indent) {
2662
+ const properties = isSchemaRecord(r["properties"]) ? r["properties"] : {};
2663
+ const entries = Object.entries(properties);
2664
+ const required = new Set(Array.isArray(r["required"]) ? r["required"] : []);
2665
+ const extraTypes = [];
2666
+ const ap = r["additionalProperties"];
2667
+ if (ap === true) {
2668
+ extraTypes.push("unknown");
2669
+ } else if (isSchemaRecord(ap)) {
2670
+ extraTypes.push(typeExpr(ap, ctx, depth + 1, indent));
2671
+ }
2672
+ const patternProps = r["patternProperties"];
2673
+ if (isSchemaRecord(patternProps)) {
2674
+ for (const value of Object.values(patternProps)) {
2675
+ extraTypes.push(typeExpr(value, ctx, depth + 1, indent));
2676
+ }
2677
+ }
2678
+ const extra = extraTypes.length > 0 ? dedupe(extraTypes).join(" | ") : void 0;
2679
+ if (entries.length === 0) {
2680
+ if (extra !== void 0) {
2681
+ return `Record<string, ${extra}>`;
2682
+ }
2683
+ return ap === false ? "Record<string, never>" : "Record<string, unknown>";
2684
+ }
2685
+ const suffix = extra !== void 0 ? ` & Record<string, ${extra}>` : "";
2686
+ if (ctx.mode === "compact") {
2687
+ const members = entries.map(
2688
+ ([key, prop]) => `${quoteKey(key)}${required.has(key) ? "" : "?"}: ${typeExpr(prop, ctx, depth + 1, indent)}`
2689
+ );
2690
+ return `{ ${members.join("; ")} }${suffix}`;
2691
+ }
2692
+ const inner = indent + " ";
2693
+ let body = "{\n";
2694
+ for (const [key, prop] of entries) {
2695
+ const doc = jsdocLines(prop);
2696
+ if (doc.length > 0) {
2697
+ body += renderJsdoc(doc, inner);
2698
+ }
2699
+ body += `${inner}${quoteKey(key)}${required.has(key) ? "" : "?"}: ${typeExpr(prop, ctx, depth + 1, inner)};
2700
+ `;
2701
+ }
2702
+ body += `${indent}}`;
2703
+ return `${body}${suffix}`;
2704
+ }
2705
+ function isPlainObjectBody(schema) {
2706
+ if (!isSchemaRecord(schema) || schema["$ref"] !== void 0) {
2707
+ return false;
2708
+ }
2709
+ if ("const" in schema && literalOf(schema["const"]) !== "unknown" || Array.isArray(schema["enum"])) {
2710
+ return false;
2711
+ }
2712
+ if (Array.isArray(schema["allOf"]) || Array.isArray(schema["oneOf"]) || Array.isArray(schema["anyOf"])) {
2713
+ return false;
2714
+ }
2715
+ if (Array.isArray(schema["type"]) || !hasObjectShape(schema)) {
2716
+ return false;
2717
+ }
2718
+ const properties = isSchemaRecord(schema["properties"]) ? schema["properties"] : {};
2719
+ if (Object.keys(properties).length === 0) {
2720
+ return false;
2721
+ }
2722
+ const ap = schema["additionalProperties"];
2723
+ if (ap === true || isSchemaRecord(ap) || isSchemaRecord(schema["patternProperties"])) {
2724
+ return false;
2725
+ }
2726
+ return true;
2727
+ }
2728
+ function namedRoot(name, schema, ctx) {
2729
+ const expr = typeExpr(schema, ctx, 0, "");
2730
+ return isPlainObjectBody(schema) ? `interface ${name} ${expr}` : `type ${name} = ${expr};`;
2731
+ }
2732
+ function paramList(inputSchema, typeText) {
2733
+ if (inputSchema === true) {
2734
+ return `(input?: ${typeText})`;
2735
+ }
2736
+ if (!isSchemaRecord(inputSchema)) {
2737
+ return "()";
2738
+ }
2739
+ const properties = isSchemaRecord(inputSchema["properties"]) ? inputSchema["properties"] : {};
2740
+ const keys = Object.keys(properties);
2741
+ if (keys.length === 0) {
2742
+ const ap = inputSchema["additionalProperties"];
2743
+ const hasExtra = ap === true || isSchemaRecord(ap) || isSchemaRecord(inputSchema["patternProperties"]);
2744
+ const objectish = inputSchema["type"] === "object" || inputSchema["type"] === void 0;
2745
+ const composed = Array.isArray(inputSchema["allOf"]) || Array.isArray(inputSchema["oneOf"]) || Array.isArray(inputSchema["anyOf"]) || Array.isArray(inputSchema["enum"]) || "const" in inputSchema;
2746
+ return objectish && !hasExtra && !composed ? "()" : `(input: ${typeText})`;
2747
+ }
2748
+ const required = new Set(Array.isArray(inputSchema["required"]) ? inputSchema["required"] : []);
2749
+ const allOptional = keys.every((k) => !required.has(k));
2750
+ return allOptional ? `(input?: ${typeText})` : `(input: ${typeText})`;
2751
+ }
2752
+ function outputVariantsDeclaration(name, variants, ctx) {
2753
+ const lines = variants.map((member) => {
2754
+ let comment = "";
2755
+ if (isSchemaRecord(member)) {
2756
+ const status = member["x-status-code"];
2757
+ if (typeof status === "number" || typeof status === "string") {
2758
+ const contentType = member["x-content-type"];
2759
+ const ct = typeof contentType === "string" ? ` (${escapeJsdoc(contentType)})` : "";
2760
+ comment = `/** status ${escapeJsdoc(String(status))}${ct} */ `;
2761
+ }
2762
+ }
2763
+ return ` | ${comment}${typeExpr(member, ctx, 1, " ")}`;
2764
+ });
2765
+ return `type ${name} =
2766
+ ${lines.join("\n")};`;
2767
+ }
2768
+ function emitToolTypeScript(toolName, description, inputSchema, outputSchema, options = {}) {
2769
+ const maxDepth = typeof options.maxDepth === "number" && Number.isFinite(options.maxDepth) ? Math.max(1, Math.floor(options.maxDepth)) : DEFAULT_MAX_DEPTH;
2770
+ const compact = { mode: "compact", maxDepth, stack: /* @__PURE__ */ new Set() };
2771
+ const pretty = { mode: "pretty", maxDepth, stack: /* @__PURE__ */ new Set() };
2772
+ const inputCompact = typeExpr(inputSchema, compact, 0, "");
2773
+ const outputCompact = outputSchema === void 0 ? "unknown" : typeExpr(outputSchema, compact, 0, "");
2774
+ const signature = `${paramList(inputSchema, inputCompact)} => Promise<${outputCompact}>`;
2775
+ const base = toPascalIdentifier(toolName);
2776
+ const inputName = `${base}Input`;
2777
+ const outputName = `${base}Output`;
2778
+ const blocks = [];
2779
+ if (typeof description === "string" && description !== "") {
2780
+ blocks.push(renderJsdoc(escapeJsdoc(description).split("\n"), "").trimEnd());
2781
+ }
2782
+ blocks.push(namedRoot(inputName, inputSchema, pretty));
2783
+ const outputUnion = isSchemaRecord(outputSchema) && Array.isArray(outputSchema["oneOf"]) ? outputSchema["oneOf"] : void 0;
2784
+ if (outputSchema === void 0) {
2785
+ blocks.push(`type ${outputName} = unknown;`);
2786
+ } else if (outputUnion && outputUnion.some((m) => isSchemaRecord(m) && m["x-status-code"] !== void 0)) {
2787
+ blocks.push(outputVariantsDeclaration(outputName, outputUnion, pretty));
2788
+ } else {
2789
+ blocks.push(namedRoot(outputName, outputSchema, pretty));
2790
+ }
2791
+ let fnName = lowerFirst(base);
2792
+ if (RESERVED_WORDS.has(fnName)) {
2793
+ fnName = `${fnName}_`;
2794
+ }
2795
+ blocks.push(`declare function ${fnName}${paramList(inputSchema, inputName)}: Promise<${outputName}>;`);
2796
+ return { signature, declaration: blocks.join("\n\n") };
2797
+ }
2798
+
2314
2799
  // src/ssrf.ts
2315
2800
  var BLOCKED_HOSTNAMES = /* @__PURE__ */ new Set([
2316
2801
  "localhost",
@@ -2719,6 +3204,25 @@ function globToRegExp(glob) {
2719
3204
  function matchesAnyGlob(path, globs) {
2720
3205
  return globs.some((glob) => globToRegExp(glob).test(path));
2721
3206
  }
3207
+ function iconsFromInfoLogo(info) {
3208
+ if (!info || typeof info !== "object") {
3209
+ return void 0;
3210
+ }
3211
+ const logo = info["x-logo"];
3212
+ let src;
3213
+ if (typeof logo === "string") {
3214
+ src = logo;
3215
+ } else if (logo && typeof logo === "object" && !Array.isArray(logo)) {
3216
+ const url = logo["url"];
3217
+ if (typeof url === "string") {
3218
+ src = url;
3219
+ }
3220
+ }
3221
+ if (src !== void 0 && isAllowedIconSrc(src)) {
3222
+ return [{ src }];
3223
+ }
3224
+ return void 0;
3225
+ }
2722
3226
  function trimUnderscores(value) {
2723
3227
  let start = 0;
2724
3228
  let end = value.length;
@@ -3101,6 +3605,14 @@ var OpenAPIToolGenerator = class _OpenAPIToolGenerator {
3101
3605
  attempts++;
3102
3606
  }
3103
3607
  tool = { ...tool, name: deduped };
3608
+ if (tool.metadata.typescript) {
3609
+ tool.metadata = {
3610
+ ...tool.metadata,
3611
+ typescript: emitToolTypeScript(deduped, tool.description, tool.inputSchema, tool.outputSchema, {
3612
+ maxDepth: Math.max(1, options.maxSchemaDepth ?? 10)
3613
+ })
3614
+ };
3615
+ }
3104
3616
  }
3105
3617
  usedNames.add(tool.name);
3106
3618
  tools.push(tool);
@@ -3149,7 +3661,13 @@ var OpenAPIToolGenerator = class _OpenAPIToolGenerator {
3149
3661
  const responseBuilder = new ResponseBuilder(options);
3150
3662
  const outputSchema = responseBuilder.build(operation.responses);
3151
3663
  const overrides = extractExtensionOverrides(operation);
3152
- const name = this.generateToolName(pathStr, method, overrides.name ?? operation.operationId, options);
3664
+ const name = this.generateToolName(
3665
+ pathStr,
3666
+ method,
3667
+ overrides.name ?? operation.operationId,
3668
+ options,
3669
+ operation
3670
+ );
3153
3671
  const description = overrides.description ?? composeDescription(operation, method, pathStr, options.descriptionStrategy ?? "summaryOnly");
3154
3672
  const title = overrides.title ?? operation.summary;
3155
3673
  const inferred = options.inferAnnotations !== false ? inferAnnotationsFromMethod(method.toLowerCase()) : void 0;
@@ -3214,11 +3732,48 @@ var OpenAPIToolGenerator = class _OpenAPIToolGenerator {
3214
3732
  Returns: ${summary}`;
3215
3733
  }
3216
3734
  }
3735
+ if (options.emitTypeSignatures) {
3736
+ metadata.typescript = emitToolTypeScript(name, finalDescription, resolvedInputSchema, resolvedOutputSchema, {
3737
+ // Print at least as deep as the schemas were truncated, so the
3738
+ // emitted types never collapse levels the schema still carries.
3739
+ maxDepth: Math.max(1, options.maxSchemaDepth ?? 10)
3740
+ });
3741
+ }
3742
+ let toolMeta;
3743
+ if (overrides.meta) {
3744
+ toolMeta = {};
3745
+ for (const [key, value] of Object.entries(overrides.meta)) {
3746
+ if (!key.startsWith("dev.agentfront.openapi/")) {
3747
+ toolMeta[key] = value;
3748
+ }
3749
+ }
3750
+ }
3751
+ if (options.emitMeta) {
3752
+ const info = document.info;
3753
+ toolMeta = {
3754
+ ...toolMeta,
3755
+ "dev.agentfront.openapi/operation": {
3756
+ path: pathStr,
3757
+ method,
3758
+ ...operation.operationId !== void 0 && { operationId: operation.operationId },
3759
+ ...operation.tags && { tags: [...operation.tags] },
3760
+ ...operation.deprecated !== void 0 && { deprecated: operation.deprecated },
3761
+ ...typeof info?.["title"] === "string" && { specTitle: info["title"] },
3762
+ ...typeof info?.["version"] === "string" && { specVersion: info["version"] }
3763
+ }
3764
+ };
3765
+ }
3766
+ if (toolMeta && Object.keys(toolMeta).length === 0) {
3767
+ toolMeta = void 0;
3768
+ }
3769
+ const icons = overrides.icons ?? (options.inheritDocumentIcons ? iconsFromInfoLogo(document.info) : void 0);
3217
3770
  return {
3218
3771
  name,
3219
3772
  ...title !== void 0 && { title },
3220
3773
  description: finalDescription,
3221
3774
  ...annotations && { annotations },
3775
+ ...toolMeta && { _meta: toolMeta },
3776
+ ...icons && { icons },
3222
3777
  inputSchema: resolvedInputSchema,
3223
3778
  outputSchema: resolvedOutputSchema,
3224
3779
  mapper,
@@ -3286,10 +3841,10 @@ Returns: ${summary}`;
3286
3841
  /**
3287
3842
  * Generate a tool name
3288
3843
  */
3289
- generateToolName(path, method, operationId, options = {}) {
3844
+ generateToolName(path, method, operationId, options = {}, operation) {
3290
3845
  let rawName;
3291
3846
  if (options.namingStrategy?.toolNameGenerator) {
3292
- rawName = options.namingStrategy.toolNameGenerator(path, method, operationId);
3847
+ rawName = options.namingStrategy.toolNameGenerator(path, method, operationId, operation);
3293
3848
  } else if (operationId) {
3294
3849
  rawName = operationId;
3295
3850
  } else {
@@ -3627,6 +4182,1213 @@ function createSecurityContext(auth) {
3627
4182
  };
3628
4183
  }
3629
4184
 
4185
+ // src/naming-presets.ts
4186
+ var CODECALL_RESERVED_NAMESPACES = [
4187
+ "console",
4188
+ "Math",
4189
+ "JSON",
4190
+ "Object",
4191
+ "Promise",
4192
+ "Array",
4193
+ "String",
4194
+ "Number",
4195
+ "Boolean",
4196
+ "Date",
4197
+ "RegExp",
4198
+ "Error",
4199
+ "Symbol",
4200
+ "Map",
4201
+ "Set",
4202
+ "WeakMap",
4203
+ "WeakSet",
4204
+ "globalThis",
4205
+ "global",
4206
+ "window",
4207
+ "self",
4208
+ "undefined",
4209
+ "null",
4210
+ "true",
4211
+ "false",
4212
+ "NaN",
4213
+ "Infinity",
4214
+ "callTool",
4215
+ "getTool",
4216
+ "mcpLog",
4217
+ "mcpNotify"
4218
+ ];
4219
+ function sanitizeIdentifier(value) {
4220
+ if (value === void 0) {
4221
+ return "";
4222
+ }
4223
+ let out = value.replace(/[^A-Za-z0-9_]+/g, "_").replace(/_+/g, "_");
4224
+ let start = 0;
4225
+ let end = out.length;
4226
+ while (start < end && out[start] === "_") start++;
4227
+ while (end > start && out[end - 1] === "_") end--;
4228
+ out = out.slice(start, end);
4229
+ if (out === "") {
4230
+ return "";
4231
+ }
4232
+ return /^[0-9]/.test(out) ? `_${out}` : out;
4233
+ }
4234
+ function firstPathSegment(path) {
4235
+ for (const segment of path.split("/")) {
4236
+ if (segment !== "" && !segment.startsWith("{")) {
4237
+ return sanitizeIdentifier(segment);
4238
+ }
4239
+ }
4240
+ return "";
4241
+ }
4242
+ function pathMethodHalf(method, path, ns) {
4243
+ const segments = path.split("/").filter((s) => s !== "").map((s) => {
4244
+ const templated = s.replace(/\{([^{}]+)\}/g, "by_$1");
4245
+ return sanitizeIdentifier(templated);
4246
+ }).filter((s) => s !== "");
4247
+ if (segments.length > 0 && segments[0] === ns) {
4248
+ segments.shift();
4249
+ }
4250
+ const joined = segments.join("_");
4251
+ return joined === "" ? method : `${method}_${joined}`;
4252
+ }
4253
+ function dottedNaming(options = {}) {
4254
+ const namespaceFrom = options.namespaceFrom ?? "tag";
4255
+ const reserved = /* @__PURE__ */ new Set([...CODECALL_RESERVED_NAMESPACES, ...options.reservedNamespaces ?? []]);
4256
+ return {
4257
+ toolNameGenerator: (path, method, operationId, operation) => {
4258
+ let ns = "";
4259
+ if (namespaceFrom === "tag") {
4260
+ ns = sanitizeIdentifier(operation?.tags?.[0]);
4261
+ }
4262
+ if (ns === "") {
4263
+ ns = firstPathSegment(path);
4264
+ }
4265
+ if (ns === "") {
4266
+ ns = "api";
4267
+ }
4268
+ if (ns.startsWith("_")) {
4269
+ ns = `n${ns.slice(1)}`;
4270
+ }
4271
+ if (reserved.has(ns)) {
4272
+ ns = `${ns}_`;
4273
+ }
4274
+ const methodHalf = sanitizeIdentifier(operationId) || pathMethodHalf(method, path, ns);
4275
+ return `${ns}.${methodHalf}`;
4276
+ }
4277
+ };
4278
+ }
4279
+
4280
+ // src/elicitation.ts
4281
+ function buildElicitation(source) {
4282
+ const { scheme, type } = source;
4283
+ if (type === "http") {
4284
+ const httpScheme = (source.httpScheme ?? "bearer").toLowerCase();
4285
+ if (httpScheme === "basic" || httpScheme === "digest") {
4286
+ return {
4287
+ scheme,
4288
+ message: `Provide HTTP ${httpScheme} credentials for "${scheme}".`,
4289
+ requestedSchema: {
4290
+ type: "object",
4291
+ properties: {
4292
+ username: { type: "string", title: "Username" },
4293
+ password: { type: "string", title: "Password", description: "Handled as a secret \u2014 never logged." }
4294
+ },
4295
+ required: ["username", "password"]
4296
+ }
4297
+ };
4298
+ }
4299
+ const format = source.bearerFormat ? ` (${source.bearerFormat})` : "";
4300
+ return {
4301
+ scheme,
4302
+ message: `Provide the ${httpScheme} token for "${scheme}".`,
4303
+ requestedSchema: {
4304
+ type: "object",
4305
+ properties: {
4306
+ token: { type: "string", title: "Token", description: `HTTP ${httpScheme} authentication token${format}.` }
4307
+ },
4308
+ required: ["token"]
4309
+ }
4310
+ };
4311
+ }
4312
+ if (type === "apiKey") {
4313
+ const keyName = source.apiKeyName ?? scheme;
4314
+ const location = source.apiKeyIn ?? "header";
4315
+ return {
4316
+ scheme,
4317
+ message: `Provide the API key for "${scheme}".`,
4318
+ requestedSchema: {
4319
+ type: "object",
4320
+ properties: {
4321
+ apiKey: { type: "string", title: "API key", description: `API key "${keyName}" sent via ${location}.` }
4322
+ },
4323
+ required: ["apiKey"]
4324
+ }
4325
+ };
4326
+ }
4327
+ if (type === "oauth2" || type === "openIdConnect") {
4328
+ const scopes = source.scopes && source.scopes.length > 0 ? ` Scopes: ${source.scopes.join(", ")}.` : "";
4329
+ return {
4330
+ scheme,
4331
+ message: `Provide an OAuth2 access token for "${scheme}".${scopes}`,
4332
+ requestedSchema: {
4333
+ type: "object",
4334
+ properties: {
4335
+ accessToken: { type: "string", title: "Access token", description: `OAuth2 access token.${scopes}` }
4336
+ },
4337
+ required: ["accessToken"]
4338
+ }
4339
+ };
4340
+ }
4341
+ return void 0;
4342
+ }
4343
+ function deriveSecurityElicitations(tool) {
4344
+ const sources = [];
4345
+ const seen = /* @__PURE__ */ new Set();
4346
+ for (const entry of tool.mapper) {
4347
+ const security = entry.security;
4348
+ if (security && !seen.has(security.scheme)) {
4349
+ seen.add(security.scheme);
4350
+ sources.push(security);
4351
+ }
4352
+ }
4353
+ if (sources.length === 0 && tool.metadata.security) {
4354
+ for (const requirement of tool.metadata.security) {
4355
+ if (!seen.has(requirement.scheme)) {
4356
+ seen.add(requirement.scheme);
4357
+ sources.push({
4358
+ scheme: requirement.scheme,
4359
+ type: requirement.type,
4360
+ httpScheme: requirement.httpScheme,
4361
+ bearerFormat: requirement.bearerFormat,
4362
+ scopes: requirement.scopes,
4363
+ apiKeyName: requirement.name,
4364
+ apiKeyIn: requirement.in
4365
+ });
4366
+ }
4367
+ }
4368
+ }
4369
+ const result = [];
4370
+ for (const source of sources) {
4371
+ const elicitation = buildElicitation(source);
4372
+ if (elicitation) {
4373
+ result.push(elicitation);
4374
+ }
4375
+ }
4376
+ return result;
4377
+ }
4378
+
4379
+ // src/arazzo-expressions.ts
4380
+ var EXACT_ROOTS = {
4381
+ $url: "url",
4382
+ $method: "method",
4383
+ $statusCode: "statusCode"
4384
+ };
4385
+ var DOTTED_ROOTS = {
4386
+ $inputs: "inputs",
4387
+ $outputs: "outputs",
4388
+ $steps: "steps",
4389
+ $workflows: "workflows",
4390
+ $sourceDescriptions: "sourceDescriptions",
4391
+ $components: "components"
4392
+ };
4393
+ var KNOWN_ROOT = /^\$(?:(?:url|method|statusCode)$|(?:request|response|message)\.|(?:inputs|outputs|steps|workflows|sourceDescriptions|components)\.)/;
4394
+ function fail(message, docPath, expression) {
4395
+ throw new ArazzoError(message, { path: docPath, expression });
4396
+ }
4397
+ var TOKEN = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
4398
+ function parseSourceRef(prefix, rest, raw, docPath) {
4399
+ if (rest.startsWith("header.")) {
4400
+ const name = rest.slice("header.".length);
4401
+ if (name === "" || !TOKEN.test(name)) {
4402
+ fail(`Invalid header name in runtime expression "${raw}"`, docPath, raw);
4403
+ }
4404
+ return { type: prefix, raw, path: [], source: "header", name };
4405
+ }
4406
+ if (rest.startsWith("query.") || rest.startsWith("path.")) {
4407
+ const source = rest.startsWith("query.") ? "query" : "path";
4408
+ const name = rest.slice(source.length + 1);
4409
+ if (name === "") {
4410
+ fail(`Empty ${source} parameter name in runtime expression "${raw}"`, docPath, raw);
4411
+ }
4412
+ return { type: prefix, raw, path: [], source, name };
4413
+ }
4414
+ if (rest === "body" || rest.startsWith("body#")) {
4415
+ const node = { type: prefix, raw, path: [], source: "body" };
4416
+ if (rest.startsWith("body#")) {
4417
+ const pointer = rest.slice("body#".length);
4418
+ if (pointer !== "" && !pointer.startsWith("/")) {
4419
+ fail(`JSON Pointer in "${raw}" must be empty or start with "/"`, docPath, raw);
4420
+ }
4421
+ node.pointer = pointer;
4422
+ }
4423
+ return node;
4424
+ }
4425
+ fail(`Invalid $${prefix} reference "${raw}" \u2014 expected header.<name>, query.<name>, path.<name>, or body[#<pointer>]`, docPath, raw);
4426
+ }
4427
+ function parseRuntimeExpression(raw, docPath = "") {
4428
+ const exact = EXACT_ROOTS[raw];
4429
+ if (exact) {
4430
+ return { type: exact, raw, path: [] };
4431
+ }
4432
+ for (const key of Object.keys(EXACT_ROOTS)) {
4433
+ if (raw.startsWith(key) && raw !== key) {
4434
+ fail(`Unexpected characters after "${key}" in runtime expression "${raw}"`, docPath, raw);
4435
+ }
4436
+ }
4437
+ for (const prefix of ["request", "response", "message"]) {
4438
+ if (raw.startsWith(`$${prefix}.`)) {
4439
+ return parseSourceRef(prefix, raw.slice(prefix.length + 2), raw, docPath);
4440
+ }
4441
+ }
4442
+ const dot = raw.indexOf(".");
4443
+ const rootToken = dot === -1 ? raw : raw.slice(0, dot);
4444
+ const root = DOTTED_ROOTS[rootToken];
4445
+ if (root) {
4446
+ const rest = dot === -1 ? "" : raw.slice(dot + 1);
4447
+ if (rest === "") {
4448
+ fail(`Runtime expression "${raw}" is missing a name after "${rootToken}."`, docPath, raw);
4449
+ }
4450
+ const path = rest.split(".");
4451
+ if (path.some((segment) => segment === "" || /\s/.test(segment))) {
4452
+ fail(`Runtime expression "${raw}" contains an empty or whitespace path segment`, docPath, raw);
4453
+ }
4454
+ return { type: root, raw, path };
4455
+ }
4456
+ fail(`Invalid runtime expression "${raw}"`, docPath, raw);
4457
+ }
4458
+ function parseExpressionValue(value, docPath = "") {
4459
+ if (typeof value !== "string") {
4460
+ return { kind: "literal", value };
4461
+ }
4462
+ if (value.startsWith("$")) {
4463
+ if (KNOWN_ROOT.test(value)) {
4464
+ return { kind: "expression", expression: parseRuntimeExpression(value, docPath) };
4465
+ }
4466
+ return { kind: "literal", value };
4467
+ }
4468
+ if (!value.includes("{$")) {
4469
+ return { kind: "literal", value };
4470
+ }
4471
+ const parts = [];
4472
+ let cursor = 0;
4473
+ while (cursor < value.length) {
4474
+ const open = value.indexOf("{$", cursor);
4475
+ if (open === -1) {
4476
+ parts.push(value.slice(cursor));
4477
+ break;
4478
+ }
4479
+ if (open > cursor) {
4480
+ parts.push(value.slice(cursor, open));
4481
+ }
4482
+ const close = value.indexOf("}", open);
4483
+ if (close === -1) {
4484
+ fail(`Unterminated "{$" template expression in "${value}"`, docPath, value);
4485
+ }
4486
+ parts.push(parseRuntimeExpression(value.slice(open + 1, close), docPath));
4487
+ cursor = close + 1;
4488
+ }
4489
+ return { kind: "template", raw: value, parts };
4490
+ }
4491
+ function escapePointerSegment(segment) {
4492
+ return segment.replace(/~/g, "~0").replace(/\//g, "~1");
4493
+ }
4494
+ function collectPayloadExpressions(payload, docPath = "") {
4495
+ const found = [];
4496
+ const seen = /* @__PURE__ */ new Set();
4497
+ const visit = (node, pointer) => {
4498
+ if (typeof node === "string") {
4499
+ const value = parseExpressionValue(node, docPath);
4500
+ if (value.kind !== "literal") {
4501
+ found.push({ pointer, value });
4502
+ }
4503
+ return;
4504
+ }
4505
+ if (!node || typeof node !== "object") {
4506
+ return;
4507
+ }
4508
+ if (seen.has(node)) {
4509
+ return;
4510
+ }
4511
+ seen.add(node);
4512
+ if (Array.isArray(node)) {
4513
+ node.forEach((item, index) => visit(item, `${pointer}/${index}`));
4514
+ return;
4515
+ }
4516
+ for (const [key, value] of Object.entries(node)) {
4517
+ visit(value, `${pointer}/${escapePointerSegment(key)}`);
4518
+ }
4519
+ };
4520
+ visit(payload, "");
4521
+ return found;
4522
+ }
4523
+
4524
+ // src/arazzo.ts
4525
+ import * as yaml2 from "yaml";
4526
+ var ID_PATTERN = /^[A-Za-z0-9_-]+$/;
4527
+ var OUTPUT_KEY_PATTERN = /^[a-zA-Z0-9.\-_]+$/;
4528
+ var VERSION_PATTERN = /^1\.0\.\d+$/;
4529
+ var HTTP_METHODS = ["get", "post", "put", "patch", "delete", "head", "options", "trace"];
4530
+ var PARAMETER_LOCATIONS = ["path", "query", "header", "cookie"];
4531
+ var OUTPUT_DERIVATION_MAX_DEPTH = 8;
4532
+ function err(message, path, extra) {
4533
+ throw new ArazzoError(message, { path, ...extra });
4534
+ }
4535
+ function toPlainJson(value) {
4536
+ try {
4537
+ return JSON.parse(JSON.stringify(value));
4538
+ } catch (error) {
4539
+ const message = error instanceof Error ? error.message : String(error);
4540
+ throw new ArazzoError(`Arazzo document must be JSON-serializable (acyclic, bounded depth): ${message}`, {
4541
+ path: ""
4542
+ });
4543
+ }
4544
+ }
4545
+ function parseArazzoInput(input) {
4546
+ if (typeof input === "string") {
4547
+ let parsed;
4548
+ try {
4549
+ parsed = yaml2.parse(input);
4550
+ } catch (error) {
4551
+ const message = error instanceof Error ? error.message : String(error);
4552
+ throw new ArazzoError(`Failed to parse Arazzo document: ${message}`, { path: "" });
4553
+ }
4554
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
4555
+ err("Arazzo document must be an object", "");
4556
+ }
4557
+ return toPlainJson(parsed);
4558
+ }
4559
+ if (!input || typeof input !== "object" || Array.isArray(input)) {
4560
+ err("Arazzo document must be an object", "");
4561
+ }
4562
+ return toPlainJson(input);
4563
+ }
4564
+ function validateCriteria(criteria, path) {
4565
+ if (criteria === void 0) return;
4566
+ if (!Array.isArray(criteria)) {
4567
+ err("successCriteria/criteria must be an array", path);
4568
+ }
4569
+ criteria.forEach((criterion, index) => {
4570
+ const cPath = `${path}/${index}`;
4571
+ if (!criterion || typeof criterion !== "object") {
4572
+ err("Criterion must be an object", cPath);
4573
+ }
4574
+ if (typeof criterion.condition !== "string" || criterion.condition === "") {
4575
+ err('Criterion requires a non-empty string "condition"', cPath);
4576
+ }
4577
+ const type = criterion.type;
4578
+ let effectiveType;
4579
+ if (type !== void 0) {
4580
+ if (typeof type === "string") {
4581
+ if (!["simple", "regex", "jsonpath", "xpath"].includes(type)) {
4582
+ err(`Unknown criterion type "${type}"`, cPath);
4583
+ }
4584
+ effectiveType = type;
4585
+ } else if (type && typeof type === "object") {
4586
+ if (type.type !== "jsonpath" && type.type !== "xpath" || typeof type.version !== "string") {
4587
+ err('Criterion Expression Type Object requires "type" (jsonpath|xpath) and "version"', cPath);
4588
+ }
4589
+ effectiveType = type.type;
4590
+ } else {
4591
+ err('Criterion "type" must be a string or a Criterion Expression Type Object', cPath);
4592
+ }
4593
+ }
4594
+ if (criterion.context !== void 0 && typeof criterion.context !== "string") {
4595
+ err('Criterion "context" must be a runtime expression string', cPath);
4596
+ }
4597
+ if (effectiveType !== void 0 && effectiveType !== "simple" && criterion.context === void 0) {
4598
+ err(`Criterion of type "${effectiveType}" requires a "context" expression`, cPath);
4599
+ }
4600
+ });
4601
+ }
4602
+ function validateActions(actions, kind, path) {
4603
+ if (actions === void 0) return;
4604
+ if (!Array.isArray(actions)) {
4605
+ err("Actions must be an array", path);
4606
+ }
4607
+ actions.forEach((action, index) => {
4608
+ const aPath = `${path}/${index}`;
4609
+ if (!action || typeof action !== "object") {
4610
+ err("Action must be an object", aPath);
4611
+ }
4612
+ if ("reference" in action) {
4613
+ return;
4614
+ }
4615
+ validateActionObject(action, kind, aPath);
4616
+ });
4617
+ }
4618
+ function validateActionObject(action, kind, aPath) {
4619
+ const act = action;
4620
+ if (typeof act.name !== "string" || act.name === "") {
4621
+ err('Action requires a non-empty string "name"', aPath);
4622
+ }
4623
+ const allowed = kind === "success" ? ["end", "goto"] : ["end", "retry", "goto"];
4624
+ if (!allowed.includes(act.type)) {
4625
+ err(`Invalid ${kind}-action type "${String(act.type)}" (allowed: ${allowed.join(", ")})`, aPath);
4626
+ }
4627
+ const targets = [act.workflowId, act.stepId].filter((t) => t !== void 0).length;
4628
+ if (act.type === "goto" && targets !== 1) {
4629
+ err('A "goto" action requires exactly one of "workflowId" or "stepId"', aPath);
4630
+ }
4631
+ if (act.type === "end" && targets !== 0) {
4632
+ err('An "end" action must not specify "workflowId" or "stepId"', aPath);
4633
+ }
4634
+ if (act.retryAfter !== void 0 && (typeof act.retryAfter !== "number" || act.retryAfter < 0)) {
4635
+ err('"retryAfter" must be a non-negative number', aPath);
4636
+ }
4637
+ if (act.retryLimit !== void 0 && (typeof act.retryLimit !== "number" || !Number.isInteger(act.retryLimit) || act.retryLimit < 0)) {
4638
+ err('"retryLimit" must be a non-negative integer', aPath);
4639
+ }
4640
+ validateCriteria(act.criteria, `${aPath}/criteria`);
4641
+ }
4642
+ function validateParameters(parameters, requireIn, path) {
4643
+ if (parameters === void 0) return;
4644
+ if (!Array.isArray(parameters)) {
4645
+ err("Parameters must be an array", path);
4646
+ }
4647
+ const seen = /* @__PURE__ */ new Set();
4648
+ parameters.forEach((parameter, index) => {
4649
+ const pPath = `${path}/${index}`;
4650
+ if (!parameter || typeof parameter !== "object") {
4651
+ err("Parameter must be an object", pPath);
4652
+ }
4653
+ if ("reference" in parameter) {
4654
+ return;
4655
+ }
4656
+ validateParameterObject(parameter, requireIn, pPath);
4657
+ const param = parameter;
4658
+ const key = `${param.name} ${param.in ?? ""}`;
4659
+ if (seen.has(key)) {
4660
+ err(`Duplicate parameter "${param.name}"${param.in ? ` (in: ${param.in})` : ""}`, pPath);
4661
+ }
4662
+ seen.add(key);
4663
+ });
4664
+ }
4665
+ function validateParameterObject(param, requireIn, pPath) {
4666
+ if (typeof param.name !== "string" || param.name === "") {
4667
+ err('Parameter requires a non-empty string "name"', pPath);
4668
+ }
4669
+ const paramName = param.name;
4670
+ if (!("value" in param)) {
4671
+ err(`Parameter "${paramName}" requires a "value"`, pPath);
4672
+ }
4673
+ if (param.in !== void 0 && !PARAMETER_LOCATIONS.includes(param.in)) {
4674
+ err(`Invalid parameter location "${String(param.in)}"`, pPath);
4675
+ }
4676
+ if (requireIn === true && param.in === void 0) {
4677
+ err(`Parameter "${param.name}" on an operation step requires "in"`, pPath);
4678
+ }
4679
+ if (requireIn === false && param.in !== void 0) {
4680
+ err(`Parameter "${param.name}" on a workflowId step must not specify "in"`, pPath);
4681
+ }
4682
+ }
4683
+ function validateOutputs(outputs, path) {
4684
+ if (outputs === void 0) return;
4685
+ if (!outputs || typeof outputs !== "object" || Array.isArray(outputs)) {
4686
+ err('"outputs" must be an object of name \u2192 runtime expression', path);
4687
+ }
4688
+ for (const [key, value] of Object.entries(outputs)) {
4689
+ if (!OUTPUT_KEY_PATTERN.test(key)) {
4690
+ err(`Invalid output name "${key}"`, `${path}/${key}`);
4691
+ }
4692
+ if (typeof value !== "string") {
4693
+ err(`Output "${key}" must be a runtime expression string`, `${path}/${key}`);
4694
+ }
4695
+ }
4696
+ }
4697
+ function validateDocument(doc) {
4698
+ if (typeof doc.arazzo !== "string" || !VERSION_PATTERN.test(doc.arazzo)) {
4699
+ err(`Unsupported arazzo version "${String(doc.arazzo)}" (expected 1.0.x)`, "/arazzo");
4700
+ }
4701
+ if (!doc.info || typeof doc.info !== "object" || typeof doc.info.title !== "string" || typeof doc.info.version !== "string") {
4702
+ err('"info" requires string "title" and "version"', "/info");
4703
+ }
4704
+ if (!Array.isArray(doc.sourceDescriptions) || doc.sourceDescriptions.length === 0) {
4705
+ err('"sourceDescriptions" must be a non-empty array', "/sourceDescriptions");
4706
+ }
4707
+ const sourceNames = /* @__PURE__ */ new Set();
4708
+ doc.sourceDescriptions.forEach((source, index) => {
4709
+ const sPath = `/sourceDescriptions/${index}`;
4710
+ if (!source || typeof source !== "object" || typeof source.name !== "string" || !ID_PATTERN.test(source.name)) {
4711
+ err('Source description requires a "name" matching [A-Za-z0-9_-]+', sPath);
4712
+ }
4713
+ if (typeof source.url !== "string" || source.url === "") {
4714
+ err(`Source "${source.name}" requires a string "url"`, sPath);
4715
+ }
4716
+ if (source.type !== void 0 && source.type !== "openapi" && source.type !== "arazzo") {
4717
+ err(`Source "${source.name}" has invalid type "${String(source.type)}"`, sPath);
4718
+ }
4719
+ if (sourceNames.has(source.name)) {
4720
+ err(`Duplicate source description name "${source.name}"`, sPath);
4721
+ }
4722
+ sourceNames.add(source.name);
4723
+ });
4724
+ if (!Array.isArray(doc.workflows) || doc.workflows.length === 0) {
4725
+ err('"workflows" must be a non-empty array', "/workflows");
4726
+ }
4727
+ const workflowIds = /* @__PURE__ */ new Set();
4728
+ doc.workflows.forEach((workflow, wIndex) => {
4729
+ const wPath = `/workflows/${wIndex}`;
4730
+ if (!workflow || typeof workflow !== "object" || typeof workflow.workflowId !== "string" || !ID_PATTERN.test(workflow.workflowId)) {
4731
+ err('Workflow requires a "workflowId" matching [A-Za-z0-9_-]+', wPath);
4732
+ }
4733
+ if (workflowIds.has(workflow.workflowId)) {
4734
+ err(`Duplicate workflowId "${workflow.workflowId}"`, wPath);
4735
+ }
4736
+ workflowIds.add(workflow.workflowId);
4737
+ if (!Array.isArray(workflow.steps) || workflow.steps.length === 0) {
4738
+ err(`Workflow "${workflow.workflowId}" requires a non-empty "steps" array`, `${wPath}/steps`);
4739
+ }
4740
+ validateParameters(workflow.parameters, void 0, `${wPath}/parameters`);
4741
+ validateActions(workflow.successActions, "success", `${wPath}/successActions`);
4742
+ validateActions(workflow.failureActions, "failure", `${wPath}/failureActions`);
4743
+ validateOutputs(workflow.outputs, `${wPath}/outputs`);
4744
+ const stepIds = /* @__PURE__ */ new Set();
4745
+ workflow.steps.forEach((step, sIndex) => {
4746
+ const sPath = `${wPath}/steps/${sIndex}`;
4747
+ if (!step || typeof step !== "object" || typeof step.stepId !== "string" || !ID_PATTERN.test(step.stepId)) {
4748
+ err('Step requires a "stepId" matching [A-Za-z0-9_-]+', sPath);
4749
+ }
4750
+ if (stepIds.has(step.stepId)) {
4751
+ err(`Duplicate stepId "${step.stepId}" in workflow "${workflow.workflowId}"`, sPath);
4752
+ }
4753
+ stepIds.add(step.stepId);
4754
+ const kinds = [step.operationId, step.operationPath, step.workflowId].filter((k) => k !== void 0).length;
4755
+ if (kinds !== 1) {
4756
+ err(`Step "${step.stepId}" requires exactly one of "operationId", "operationPath", or "workflowId"`, sPath);
4757
+ }
4758
+ validateParameters(step.parameters, step.workflowId !== void 0 ? false : true, `${sPath}/parameters`);
4759
+ validateCriteria(step.successCriteria, `${sPath}/successCriteria`);
4760
+ validateActions(step.onSuccess, "success", `${sPath}/onSuccess`);
4761
+ validateActions(step.onFailure, "failure", `${sPath}/onFailure`);
4762
+ validateOutputs(step.outputs, `${sPath}/outputs`);
4763
+ });
4764
+ });
4765
+ }
4766
+ function ownComponent(group, name) {
4767
+ if (!group || !Object.prototype.hasOwnProperty.call(group, name)) {
4768
+ return void 0;
4769
+ }
4770
+ const value = group[name];
4771
+ return value !== null && typeof value === "object" ? value : void 0;
4772
+ }
4773
+ function resolveReusable(entry, components, expectedGroup, path) {
4774
+ if (!entry || typeof entry !== "object" || !("reference" in entry)) {
4775
+ return entry;
4776
+ }
4777
+ const reusable = entry;
4778
+ if (typeof reusable.reference !== "string") {
4779
+ err('Reusable Object "reference" must be a string', path);
4780
+ }
4781
+ const ast = parseRuntimeExpression(reusable.reference, path);
4782
+ if (ast.type !== "components" || ast.path.length < 2 || ast.path[0] !== expectedGroup) {
4783
+ err(`Reference "${reusable.reference}" must point at $components.${expectedGroup}.<name>`, path);
4784
+ }
4785
+ const name = ast.path.slice(1).join(".");
4786
+ const target = ownComponent(components?.[expectedGroup], name);
4787
+ if (!target) {
4788
+ err(`Unknown reference "$components.${expectedGroup}.${name}"`, path);
4789
+ }
4790
+ const resolved = JSON.parse(JSON.stringify(target));
4791
+ if (expectedGroup === "parameters" && "value" in reusable) {
4792
+ resolved.value = reusable.value;
4793
+ }
4794
+ return resolved;
4795
+ }
4796
+ function resolveInputRefs(node, components, path, seen) {
4797
+ if (Array.isArray(node)) {
4798
+ return node.map((item) => resolveInputRefs(item, components, path, seen));
4799
+ }
4800
+ if (!node || typeof node !== "object") {
4801
+ return node;
4802
+ }
4803
+ const record = node;
4804
+ const ref = record["$ref"];
4805
+ if (typeof ref === "string") {
4806
+ const prefix = "#/components/inputs/";
4807
+ if (!ref.startsWith(prefix)) {
4808
+ err(`Unsupported $ref "${ref}" in workflow inputs (only ${prefix}<name> is resolvable)`, path);
4809
+ }
4810
+ const name = ref.slice(prefix.length);
4811
+ const target = ownComponent(components?.inputs, name);
4812
+ if (!target) {
4813
+ err(`Unknown workflow inputs reference "${ref}"`, path);
4814
+ }
4815
+ if (seen.has(name)) {
4816
+ err(`Cyclic workflow inputs reference "${ref}"`, path);
4817
+ }
4818
+ seen.add(name);
4819
+ const resolved = resolveInputRefs(target, components, path, seen);
4820
+ seen.delete(name);
4821
+ return resolved;
4822
+ }
4823
+ const out = {};
4824
+ for (const [key, value] of Object.entries(record)) {
4825
+ out[key] = resolveInputRefs(value, components, path, seen);
4826
+ }
4827
+ return out;
4828
+ }
4829
+ async function prepareSources(doc, options) {
4830
+ const declared = new Map(doc.sourceDescriptions.map((s) => [s.name, s]));
4831
+ const generators = /* @__PURE__ */ new Map();
4832
+ const sourceTypes = /* @__PURE__ */ new Map();
4833
+ for (const [name, source] of Object.entries(options.sources ?? {})) {
4834
+ if (!declared.has(name)) {
4835
+ err(`options.sources contains "${name}", which is not a declared source description`, "/sourceDescriptions", {
4836
+ declared: [...declared.keys()]
4837
+ });
4838
+ }
4839
+ if (source instanceof OpenAPIToolGenerator) {
4840
+ generators.set(name, source);
4841
+ } else {
4842
+ generators.set(name, await OpenAPIToolGenerator.fromJSON(source, options.loadOptions));
4843
+ }
4844
+ }
4845
+ for (const [name, source] of declared) {
4846
+ sourceTypes.set(name, source.type ?? "openapi");
4847
+ }
4848
+ const operationIndex = /* @__PURE__ */ new Map();
4849
+ for (const [name, generator] of generators) {
4850
+ const document = generator.getDocument();
4851
+ for (const [pathStr, pathItem] of Object.entries(document.paths ?? {})) {
4852
+ if (!pathItem || typeof pathItem !== "object") continue;
4853
+ for (const method of HTTP_METHODS) {
4854
+ const operation = pathItem[method];
4855
+ if (!operation || typeof operation !== "object") continue;
4856
+ const operationId = operation["operationId"];
4857
+ if (typeof operationId !== "string") continue;
4858
+ const hits = operationIndex.get(operationId) ?? [];
4859
+ hits.push({ source: name, path: pathStr, method });
4860
+ operationIndex.set(operationId, hits);
4861
+ }
4862
+ }
4863
+ }
4864
+ return { generators, operationIndex, sourceTypes };
4865
+ }
4866
+ function requireGenerator(ctx, source, path) {
4867
+ if (ctx.sourceTypes.get(source) === "arazzo") {
4868
+ err(`Source "${source}" has type "arazzo" \u2014 nested Arazzo sources are not supported`, path);
4869
+ }
4870
+ const generator = ctx.generators.get(source);
4871
+ if (!generator) {
4872
+ err(`No document supplied for source "${source}" (add it to options.sources)`, path, {
4873
+ supplied: [...ctx.generators.keys()]
4874
+ });
4875
+ }
4876
+ return generator;
4877
+ }
4878
+ function parseOperationPath(value, path) {
4879
+ if (!value.startsWith("{")) {
4880
+ err(`operationPath "${value}" must start with a "{$sourceDescriptions...}" expression`, path);
4881
+ }
4882
+ const close = value.indexOf("}");
4883
+ if (close === -1) {
4884
+ err(`operationPath "${value}" is missing "}"`, path);
4885
+ }
4886
+ const ast = parseRuntimeExpression(value.slice(1, close), path);
4887
+ if (ast.type !== "sourceDescriptions" || ast.path.length !== 2 || ast.path[1] !== "url") {
4888
+ err(`operationPath "${value}" must reference $sourceDescriptions.<name>.url`, path);
4889
+ }
4890
+ const source = ast.path[0];
4891
+ const rest = value.slice(close + 1);
4892
+ if (!rest.startsWith("#/")) {
4893
+ err(`operationPath "${value}" requires a "#/paths/..." JSON Pointer after the source expression`, path);
4894
+ }
4895
+ const segments = rest.slice(2).split("/").map((segment) => segment.replace(/~1/g, "/").replace(/~0/g, "~"));
4896
+ if (segments.length !== 3 || segments[0] !== "paths") {
4897
+ err(`operationPath pointer in "${value}" must have the shape #/paths/<path>/<method>`, path);
4898
+ }
4899
+ const method = segments[2].toLowerCase();
4900
+ if (!HTTP_METHODS.includes(method)) {
4901
+ err(`operationPath "${value}" ends in unknown HTTP method "${segments[2]}"`, path);
4902
+ }
4903
+ return { source, path: segments[1], method };
4904
+ }
4905
+ function resolveOperationRef(step, ctx, path) {
4906
+ if (step.operationPath !== void 0) {
4907
+ return parseOperationPath(step.operationPath, path);
4908
+ }
4909
+ const ref = step.operationId;
4910
+ if (ref.startsWith("$")) {
4911
+ const ast = parseRuntimeExpression(ref, path);
4912
+ if (ast.type !== "sourceDescriptions" || ast.path.length < 2) {
4913
+ err(`operationId expression "${ref}" must be $sourceDescriptions.<name>.<operationId>`, path);
4914
+ }
4915
+ const source = ast.path[0];
4916
+ const operationId = ast.path.slice(1).join(".");
4917
+ const hits2 = (ctx.operationIndex.get(operationId) ?? []).filter((h) => h.source === source);
4918
+ if (hits2.length === 0) {
4919
+ requireGenerator(ctx, source, path);
4920
+ err(`operationId "${operationId}" not found in source "${source}"`, path);
4921
+ }
4922
+ if (hits2.length > 1) {
4923
+ err(`operationId "${operationId}" is duplicated inside source "${source}"`, path, { hits: hits2 });
4924
+ }
4925
+ return { ...hits2[0], operationId };
4926
+ }
4927
+ const hits = ctx.operationIndex.get(ref) ?? [];
4928
+ if (hits.length === 0) {
4929
+ err(`operationId "${ref}" not found in any supplied source (${[...ctx.generators.keys()].join(", ") || "none"})`, path);
4930
+ }
4931
+ if (hits.length > 1) {
4932
+ err(
4933
+ `operationId "${ref}" is ambiguous across sources (${hits.map((h) => h.source).join(", ")}) \u2014 pin it with $sourceDescriptions.<name>.${ref}`,
4934
+ path,
4935
+ { hits }
4936
+ );
4937
+ }
4938
+ return { ...hits[0], operationId: ref };
4939
+ }
4940
+ function checkCycles(edges, kind) {
4941
+ const state = /* @__PURE__ */ new Map();
4942
+ for (const start of edges.keys()) {
4943
+ if (state.get(start) === "done") continue;
4944
+ const stack = [{ node: start, next: 0 }];
4945
+ state.set(start, "visiting");
4946
+ while (stack.length > 0) {
4947
+ const frame = stack[stack.length - 1];
4948
+ const targets = edges.get(frame.node) ?? [];
4949
+ if (frame.next >= targets.length) {
4950
+ state.set(frame.node, "done");
4951
+ stack.pop();
4952
+ continue;
4953
+ }
4954
+ const target = targets[frame.next++];
4955
+ const targetState = state.get(target);
4956
+ if (targetState === "visiting") {
4957
+ const cycle = [...stack.map((f) => f.node), target];
4958
+ err(`Cyclic ${kind}: ${cycle.slice(cycle.indexOf(target)).join(" -> ")}`, "/workflows");
4959
+ }
4960
+ if (targetState !== "done") {
4961
+ state.set(target, "visiting");
4962
+ stack.push({ node: target, next: 0 });
4963
+ }
4964
+ }
4965
+ }
4966
+ }
4967
+ function toCriterionIR(criterion, path) {
4968
+ const ir = {
4969
+ condition: criterion.condition,
4970
+ type: "simple"
4971
+ };
4972
+ if (criterion.context !== void 0) {
4973
+ ir.context = parseRuntimeExpression(criterion.context, path);
4974
+ }
4975
+ if (typeof criterion.type === "string") {
4976
+ ir.type = criterion.type;
4977
+ } else if (criterion.type) {
4978
+ ir.type = criterion.type.type;
4979
+ ir.version = criterion.type.version;
4980
+ }
4981
+ return ir;
4982
+ }
4983
+ function toActionIR(action, kind, path) {
4984
+ const failure = action;
4985
+ return {
4986
+ name: action.name,
4987
+ kind,
4988
+ type: action.type,
4989
+ ...action.workflowId !== void 0 && { workflowId: action.workflowId },
4990
+ ...action.stepId !== void 0 && { stepId: action.stepId },
4991
+ ...failure.retryAfter !== void 0 && { retryAfter: failure.retryAfter },
4992
+ ...failure.retryLimit !== void 0 && { retryLimit: failure.retryLimit },
4993
+ ...action.criteria && { criteria: action.criteria.map((c, i) => toCriterionIR(c, `${path}/criteria/${i}`)) }
4994
+ };
4995
+ }
4996
+ function resolveActions(actions, kind, components, path) {
4997
+ const group = kind === "success" ? "successActions" : "failureActions";
4998
+ return actions.map((action, index) => {
4999
+ const aPath = `${path}/${index}`;
5000
+ const concrete = resolveReusable(action, components, group, aPath);
5001
+ validateActionObject(concrete, kind, aPath);
5002
+ return toActionIR(concrete, kind, aPath);
5003
+ });
5004
+ }
5005
+ function resolveParameters(parameters, components, requireIn, path) {
5006
+ const seen = /* @__PURE__ */ new Set();
5007
+ return parameters.map((parameter, index) => {
5008
+ const pPath = `${path}/${index}`;
5009
+ const concrete = resolveReusable(parameter, components, "parameters", pPath);
5010
+ validateParameterObject(concrete, requireIn, pPath);
5011
+ const key = `${concrete.name} ${concrete.in ?? ""}`;
5012
+ if (seen.has(key)) {
5013
+ err(`Duplicate parameter "${concrete.name}"${concrete.in ? ` (in: ${concrete.in})` : ""}`, pPath);
5014
+ }
5015
+ seen.add(key);
5016
+ return {
5017
+ name: concrete.name,
5018
+ ...concrete.in !== void 0 && { in: concrete.in },
5019
+ value: parseExpressionValue(concrete.value, pPath)
5020
+ };
5021
+ });
5022
+ }
5023
+ function parseOutputs(outputs, path) {
5024
+ if (!outputs) return void 0;
5025
+ const parsed = {};
5026
+ for (const [name, expression] of Object.entries(outputs)) {
5027
+ parsed[name] = parseRuntimeExpression(expression, `${path}/${name}`);
5028
+ }
5029
+ return parsed;
5030
+ }
5031
+ async function resolveStepOperation(ref, ctx, docPath) {
5032
+ const key = `${ref.source} ${ref.method} ${ref.path}`;
5033
+ let cached = ctx.operationCache.get(key);
5034
+ if (!cached) {
5035
+ const generator = requireGenerator(ctx.sources, ref.source, docPath);
5036
+ cached = generator.generateTool(ref.path, ref.method, ctx.generateOptions).catch((error) => {
5037
+ const message = error instanceof Error ? error.message : String(error);
5038
+ throw new ArazzoError(
5039
+ `Failed to resolve ${ref.method.toUpperCase()} ${ref.path} from source "${ref.source}": ${message}`,
5040
+ { path: docPath, source: ref.source }
5041
+ );
5042
+ });
5043
+ ctx.operationCache.set(key, cached);
5044
+ }
5045
+ return cached;
5046
+ }
5047
+ async function buildStepIR(step, ctx, path) {
5048
+ const components = ctx.doc.components;
5049
+ const base = {
5050
+ stepId: step.stepId,
5051
+ ...step.description !== void 0 && { description: step.description },
5052
+ ...step.parameters && {
5053
+ parameters: resolveParameters(
5054
+ step.parameters,
5055
+ components,
5056
+ step.workflowId !== void 0 ? false : true,
5057
+ `${path}/parameters`
5058
+ )
5059
+ },
5060
+ ...step.successCriteria && {
5061
+ successCriteria: step.successCriteria.map((c, i) => toCriterionIR(c, `${path}/successCriteria/${i}`))
5062
+ },
5063
+ ...step.onSuccess && { onSuccess: resolveActions(step.onSuccess, "success", components, `${path}/onSuccess`) },
5064
+ ...step.onFailure && { onFailure: resolveActions(step.onFailure, "failure", components, `${path}/onFailure`) },
5065
+ ...step.outputs && { outputs: parseOutputs(step.outputs, `${path}/outputs`) }
5066
+ };
5067
+ if (step.workflowId !== void 0) {
5068
+ if (step.requestBody !== void 0) {
5069
+ err(`Step "${step.stepId}" invokes a workflow and must not declare a requestBody`, `${path}/requestBody`);
5070
+ }
5071
+ if (step.workflowId.startsWith("$")) {
5072
+ err(`Step "${step.stepId}" invokes a workflow in another Arazzo document \u2014 nested Arazzo sources are not supported`, path);
5073
+ }
5074
+ if (!ctx.workflowIds.has(step.workflowId)) {
5075
+ err(`Step "${step.stepId}" references unknown workflow "${step.workflowId}"`, path);
5076
+ }
5077
+ const ir2 = { kind: "workflow", workflowId: step.workflowId, ...base };
5078
+ return ir2;
5079
+ }
5080
+ const ref = resolveOperationRef(step, ctx.sources, path);
5081
+ const tool = await resolveStepOperation(ref, ctx, path);
5082
+ const operation = {
5083
+ inputSchema: tool.inputSchema,
5084
+ outputSchema: tool.outputSchema,
5085
+ mapper: tool.mapper,
5086
+ ...tool.metadata.security && { security: tool.metadata.security },
5087
+ ...tool.metadata.servers && { servers: tool.metadata.servers }
5088
+ };
5089
+ let requestBody;
5090
+ if (step.requestBody !== void 0) {
5091
+ if (!step.requestBody || typeof step.requestBody !== "object") {
5092
+ err(`Step "${step.stepId}" requestBody must be an object`, `${path}/requestBody`);
5093
+ }
5094
+ requestBody = {
5095
+ ...step.requestBody.contentType !== void 0 && { contentType: step.requestBody.contentType },
5096
+ ...step.requestBody.payload !== void 0 && { payload: step.requestBody.payload }
5097
+ };
5098
+ const expressions = collectPayloadExpressions(step.requestBody.payload, `${path}/requestBody/payload`);
5099
+ if (expressions.length > 0) {
5100
+ requestBody.payloadExpressions = expressions;
5101
+ }
5102
+ if (step.requestBody.replacements !== void 0) {
5103
+ if (!Array.isArray(step.requestBody.replacements)) {
5104
+ err(`Step "${step.stepId}" requestBody.replacements must be an array`, `${path}/requestBody/replacements`);
5105
+ }
5106
+ requestBody.replacements = step.requestBody.replacements.map((replacement, index) => {
5107
+ const rPath = `${path}/requestBody/replacements/${index}`;
5108
+ if (!replacement || typeof replacement !== "object" || typeof replacement.target !== "string") {
5109
+ err('Replacement requires a string "target"', rPath);
5110
+ }
5111
+ return { target: replacement.target, value: parseExpressionValue(replacement.value, rPath) };
5112
+ });
5113
+ }
5114
+ }
5115
+ const ir = {
5116
+ kind: "operation",
5117
+ source: ref.source,
5118
+ path: ref.path,
5119
+ method: ref.method,
5120
+ ...ref.operationId !== void 0 && { operationId: ref.operationId },
5121
+ operation,
5122
+ ...requestBody && { requestBody },
5123
+ ...base
5124
+ };
5125
+ return ir;
5126
+ }
5127
+ function isRecord(value) {
5128
+ return typeof value === "object" && value !== null && !Array.isArray(value);
5129
+ }
5130
+ function walkPointer(schema, pointer) {
5131
+ if (pointer === void 0 || pointer === "") {
5132
+ return schema;
5133
+ }
5134
+ let node = schema;
5135
+ for (const rawSegment of pointer.slice(1).split("/")) {
5136
+ const segment = rawSegment.replace(/~1/g, "/").replace(/~0/g, "~");
5137
+ if (!isRecord(node)) return void 0;
5138
+ const properties = node["properties"];
5139
+ if (isRecord(properties) && properties[segment] !== void 0) {
5140
+ node = properties[segment];
5141
+ continue;
5142
+ }
5143
+ if (/^\d+$/.test(segment) && node["items"] !== void 0 && !Array.isArray(node["items"])) {
5144
+ node = node["items"];
5145
+ continue;
5146
+ }
5147
+ return void 0;
5148
+ }
5149
+ return node;
5150
+ }
5151
+ function primaryResponseSchema(outputSchema) {
5152
+ if (isRecord(outputSchema) && Array.isArray(outputSchema["oneOf"])) {
5153
+ const variants = outputSchema["oneOf"];
5154
+ if (variants.length > 0 && variants.every((v) => isRecord(v) && v["x-status-code"] !== void 0)) {
5155
+ return variants[0];
5156
+ }
5157
+ }
5158
+ return outputSchema;
5159
+ }
5160
+ function deriveOutputSchema(ast, steps, inputSchema, depth, stepContext) {
5161
+ if (depth >= OUTPUT_DERIVATION_MAX_DEPTH) {
5162
+ return {};
5163
+ }
5164
+ if (ast.type === "statusCode") {
5165
+ return { type: "number" };
5166
+ }
5167
+ if (ast.type === "url" || ast.type === "method") {
5168
+ return { type: "string" };
5169
+ }
5170
+ if (ast.type === "response") {
5171
+ if (ast.source !== "body") {
5172
+ return { type: "string" };
5173
+ }
5174
+ if (!stepContext) {
5175
+ return {};
5176
+ }
5177
+ const body = primaryResponseSchema(stepContext.operation.outputSchema);
5178
+ const target = walkPointer(body, ast.pointer);
5179
+ return isRecord(target) ? target : {};
5180
+ }
5181
+ if (ast.type === "inputs") {
5182
+ const properties = isRecord(inputSchema) ? inputSchema["properties"] : void 0;
5183
+ const target = isRecord(properties) ? properties[ast.path.join(".")] : void 0;
5184
+ return isRecord(target) ? target : {};
5185
+ }
5186
+ if (ast.type === "steps" && ast.path.length >= 3 && ast.path[1] === "outputs") {
5187
+ const step = steps.get(ast.path[0]);
5188
+ if (step?.kind === "operation") {
5189
+ const stepOutput = step.outputs?.[ast.path.slice(2).join(".")];
5190
+ if (stepOutput) {
5191
+ return deriveOutputSchema(stepOutput, steps, inputSchema, depth + 1, step);
5192
+ }
5193
+ }
5194
+ return {};
5195
+ }
5196
+ return {};
5197
+ }
5198
+ function deriveOutputsSchema(outputs, steps, inputSchema) {
5199
+ if (!outputs) {
5200
+ return void 0;
5201
+ }
5202
+ const stepMap = new Map(steps.map((s) => [s.stepId, s]));
5203
+ const properties = {};
5204
+ for (const [name, ast] of Object.entries(outputs)) {
5205
+ const derived = deriveOutputSchema(ast, stepMap, inputSchema, 0);
5206
+ const copied = JSON.parse(JSON.stringify(derived));
5207
+ properties[name] = { ...copied, description: `Arazzo output: ${ast.raw}` };
5208
+ }
5209
+ return { type: "object", properties };
5210
+ }
5211
+ function applySchemaPipeline(schema, options, isInputRoot) {
5212
+ const formatResolvers = {
5213
+ ...options.resolveFormats ? BUILTIN_FORMAT_RESOLVERS : {},
5214
+ ...options.formatResolvers
5215
+ };
5216
+ let resolved = Object.keys(formatResolvers).length > 0 ? resolveSchemaFormats(schema, formatResolvers) : schema;
5217
+ resolved = SchemaBuilder.truncateDepth(resolved, Math.max(1, options.maxSchemaDepth ?? 10));
5218
+ if (options.stripExamples) resolved = SchemaBuilder.stripExamples(resolved);
5219
+ if (options.maxDescriptionLength !== void 0) {
5220
+ resolved = SchemaBuilder.capDescriptions(resolved, options.maxDescriptionLength);
5221
+ }
5222
+ if (options.maxProperties !== void 0) {
5223
+ if (isInputRoot) {
5224
+ const properties = resolved.properties;
5225
+ if (properties && typeof properties === "object") {
5226
+ const limited = {};
5227
+ for (const [key, value] of Object.entries(properties)) {
5228
+ limited[key] = SchemaBuilder.limitProperties(value, options.maxProperties);
5229
+ }
5230
+ resolved = { ...resolved, properties: limited };
5231
+ }
5232
+ } else {
5233
+ resolved = SchemaBuilder.limitProperties(resolved, options.maxProperties);
5234
+ }
5235
+ }
5236
+ if (options.target) {
5237
+ resolved = applyClientTarget(resolved, options.target);
5238
+ }
5239
+ return resolved;
5240
+ }
5241
+ function buildWorkflowTool(workflow, stepIRs, ctx, wPath) {
5242
+ const options = ctx.generateOptions;
5243
+ let inputSchema;
5244
+ let rawInputSchema;
5245
+ if (workflow.inputs !== void 0) {
5246
+ const resolved = resolveInputRefs(workflow.inputs, ctx.doc.components, `${wPath}/inputs`, /* @__PURE__ */ new Set());
5247
+ rawInputSchema = toJsonSchema(resolved);
5248
+ inputSchema = applySchemaPipeline(rawInputSchema, options, true);
5249
+ } else {
5250
+ inputSchema = { type: "object", properties: {} };
5251
+ }
5252
+ const derivedOutput = deriveOutputsSchema(parseOutputs(workflow.outputs, `${wPath}/outputs`), stepIRs, rawInputSchema);
5253
+ const outputSchema = derivedOutput ? applySchemaPipeline(derivedOutput, options, false) : void 0;
5254
+ const name = normalizeToolName(workflow.workflowId, options.maxToolNameLength ?? 64, workflow.workflowId);
5255
+ const description = workflow.summary && workflow.description ? `${workflow.summary}
5256
+
5257
+ ${workflow.description}` : workflow.summary ?? workflow.description ?? `Arazzo workflow: ${workflow.workflowId}`;
5258
+ const operationSteps = stepIRs.filter((s) => s.kind === "operation");
5259
+ const allReadOnly = operationSteps.length === stepIRs.length && operationSteps.every((s) => inferAnnotationsFromMethod(s.method).readOnlyHint === true);
5260
+ const security = [];
5261
+ const seenSecurity = /* @__PURE__ */ new Set();
5262
+ for (const step of operationSteps) {
5263
+ for (const requirement of step.operation.security ?? []) {
5264
+ const key = JSON.stringify(requirement);
5265
+ if (!seenSecurity.has(key)) {
5266
+ seenSecurity.add(key);
5267
+ security.push(requirement);
5268
+ }
5269
+ }
5270
+ }
5271
+ const ir = {
5272
+ arazzoVersion: ctx.doc.arazzo,
5273
+ workflowId: workflow.workflowId,
5274
+ ...workflow.summary !== void 0 && { summary: workflow.summary },
5275
+ ...workflow.description !== void 0 && { description: workflow.description },
5276
+ ...rawInputSchema !== void 0 && { inputSchema: rawInputSchema },
5277
+ ...workflow.dependsOn && { dependsOn: workflow.dependsOn },
5278
+ ...workflow.parameters && {
5279
+ parameters: resolveParameters(workflow.parameters, ctx.doc.components, void 0, `${wPath}/parameters`)
5280
+ },
5281
+ steps: stepIRs,
5282
+ ...workflow.successActions && {
5283
+ successActions: resolveActions(workflow.successActions, "success", ctx.doc.components, `${wPath}/successActions`)
5284
+ },
5285
+ ...workflow.failureActions && {
5286
+ failureActions: resolveActions(workflow.failureActions, "failure", ctx.doc.components, `${wPath}/failureActions`)
5287
+ },
5288
+ ...workflow.outputs && { outputs: parseOutputs(workflow.outputs, `${wPath}/outputs`) }
5289
+ };
5290
+ const tool = {
5291
+ name,
5292
+ ...workflow.summary !== void 0 && { title: workflow.summary },
5293
+ description,
5294
+ ...allReadOnly && {
5295
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }
5296
+ },
5297
+ inputSchema,
5298
+ outputSchema,
5299
+ // A workflow tool has no single HTTP shape — each step's mapper lives at
5300
+ // metadata.workflow.steps[*].operation.mapper
5301
+ mapper: [],
5302
+ metadata: {
5303
+ path: `arazzo:${workflow.workflowId}`,
5304
+ method: "post",
5305
+ operationId: workflow.workflowId,
5306
+ ...workflow.summary !== void 0 && { operationSummary: workflow.summary },
5307
+ ...workflow.description !== void 0 && { operationDescription: workflow.description },
5308
+ ...security.length > 0 && { security },
5309
+ workflow: ir
5310
+ }
5311
+ };
5312
+ if (options.emitTypeSignatures) {
5313
+ tool.metadata.typescript = emitToolTypeScript(name, description, inputSchema, outputSchema, {
5314
+ maxDepth: Math.max(1, options.maxSchemaDepth ?? 10)
5315
+ });
5316
+ }
5317
+ return tool;
5318
+ }
5319
+ async function fromArazzo(document, options) {
5320
+ const doc = parseArazzoInput(document);
5321
+ validateDocument(doc);
5322
+ const sources = await prepareSources(doc, options);
5323
+ const workflowIds = new Set(doc.workflows.map((w) => w.workflowId));
5324
+ const dependsEdges = /* @__PURE__ */ new Map();
5325
+ const nestedEdges = /* @__PURE__ */ new Map();
5326
+ const declaredSources = new Set(doc.sourceDescriptions.map((s) => s.name));
5327
+ doc.workflows.forEach((workflow, index) => {
5328
+ if (workflow.dependsOn !== void 0 && !Array.isArray(workflow.dependsOn)) {
5329
+ err(`Workflow "${workflow.workflowId}" dependsOn must be an array of workflowIds`, `/workflows/${index}/dependsOn`);
5330
+ }
5331
+ const localTargets = [];
5332
+ for (const target of workflow.dependsOn ?? []) {
5333
+ if (typeof target !== "string") {
5334
+ err(`Workflow "${workflow.workflowId}" dependsOn entries must be strings`, `/workflows/${index}/dependsOn`);
5335
+ }
5336
+ if (target.startsWith("$")) {
5337
+ const ast = parseRuntimeExpression(target, `/workflows/${index}/dependsOn`);
5338
+ if (ast.type !== "sourceDescriptions" || ast.path.length < 2 || !declaredSources.has(ast.path[0])) {
5339
+ err(
5340
+ `Workflow "${workflow.workflowId}" dependsOn "${target}" must reference a declared source ($sourceDescriptions.<name>.<workflowId>)`,
5341
+ `/workflows/${index}/dependsOn`
5342
+ );
5343
+ }
5344
+ continue;
5345
+ }
5346
+ if (!workflowIds.has(target)) {
5347
+ err(`Workflow "${workflow.workflowId}" dependsOn unknown workflow "${target}"`, `/workflows/${index}/dependsOn`);
5348
+ }
5349
+ localTargets.push(target);
5350
+ }
5351
+ dependsEdges.set(workflow.workflowId, localTargets);
5352
+ nestedEdges.set(
5353
+ workflow.workflowId,
5354
+ workflow.steps.filter((s) => s.workflowId !== void 0 && !s.workflowId.startsWith("$")).map((s) => s.workflowId)
5355
+ );
5356
+ });
5357
+ checkCycles(dependsEdges, "dependsOn chain");
5358
+ checkCycles(nestedEdges, "workflow invocation");
5359
+ const ctx = {
5360
+ doc,
5361
+ sources,
5362
+ generateOptions: options.generateOptions ?? {},
5363
+ workflowIds,
5364
+ operationCache: /* @__PURE__ */ new Map()
5365
+ };
5366
+ const tools = [];
5367
+ const usedNames = /* @__PURE__ */ new Set();
5368
+ for (let wIndex = 0; wIndex < doc.workflows.length; wIndex++) {
5369
+ const workflow = doc.workflows[wIndex];
5370
+ const wPath = `/workflows/${wIndex}`;
5371
+ const stepIRs = [];
5372
+ for (let sIndex = 0; sIndex < workflow.steps.length; sIndex++) {
5373
+ stepIRs.push(await buildStepIR(workflow.steps[sIndex], ctx, `${wPath}/steps/${sIndex}`));
5374
+ }
5375
+ let tool = buildWorkflowTool(workflow, stepIRs, ctx, wPath);
5376
+ if (usedNames.has(tool.name)) {
5377
+ const maxLength = ctx.generateOptions.maxToolNameLength ?? 64;
5378
+ let seed = workflow.workflowId;
5379
+ let deduped = normalizeToolName(`${tool.name}_${fnv1aHex(seed)}`, maxLength, seed);
5380
+ while (usedNames.has(deduped)) {
5381
+ seed += "#";
5382
+ deduped = normalizeToolName(`${tool.name}_${fnv1aHex(seed)}`, maxLength, seed);
5383
+ }
5384
+ tool = { ...tool, name: deduped };
5385
+ }
5386
+ usedNames.add(tool.name);
5387
+ tools.push(tool);
5388
+ }
5389
+ return tools;
5390
+ }
5391
+
3630
5392
  // src/request-builder.ts
3631
5393
  var RESERVED_DECODE = {
3632
5394
  "%3A": ":",
@@ -3863,7 +5625,7 @@ function buildHttpRequest(tool, input, options = {}) {
3863
5625
  case "body":
3864
5626
  hasBody = true;
3865
5627
  contentType = contentType ?? mapper.serialization?.contentType ?? "application/json";
3866
- if (mapper.serialization?.binary) binaryBody = true;
5628
+ if (mapper.serialization?.binary && mapper.wholeBody) binaryBody = true;
3867
5629
  if (mapper.wholeBody) {
3868
5630
  rawBody = value;
3869
5631
  } else {
@@ -3960,13 +5722,14 @@ function buildHttpRequest(tool, input, options = {}) {
3960
5722
  // src/sdk.ts
3961
5723
  function toSdkTool(tool, wrapper) {
3962
5724
  const wrapSchema = wrapper?.fromJsonSchema ?? ((schema) => schema);
5725
+ const outputSchema = tool.outputSchema !== void 0 && tool.outputSchema["type"] === "object" ? tool.outputSchema : void 0;
3963
5726
  return [
3964
5727
  tool.name,
3965
5728
  {
3966
5729
  ...tool.title !== void 0 && { title: tool.title },
3967
5730
  description: tool.description,
3968
5731
  inputSchema: wrapSchema(tool.inputSchema),
3969
- ...tool.outputSchema !== void 0 && { outputSchema: wrapSchema(tool.outputSchema) },
5732
+ ...outputSchema !== void 0 && { outputSchema: wrapSchema(outputSchema) },
3970
5733
  ...tool.annotations !== void 0 && { annotations: tool.annotations }
3971
5734
  }
3972
5735
  ];
@@ -4010,8 +5773,10 @@ function analyzeToolSet(tools, options = {}) {
4010
5773
  return { toolCount: tools.length, estimatedTokens, perTool, warnings };
4011
5774
  }
4012
5775
  export {
5776
+ ArazzoError,
4013
5777
  BLOCKED_HOSTNAMES,
4014
5778
  BUILTIN_FORMAT_RESOLVERS,
5779
+ CODECALL_RESERVED_NAMESPACES,
4015
5780
  GenerationError,
4016
5781
  LoadError,
4017
5782
  OpenAPIToolError,
@@ -4038,10 +5803,14 @@ export {
4038
5803
  decodeIpv4MappedIpv6,
4039
5804
  defaultLookup,
4040
5805
  demoteFormats,
5806
+ deriveSecurityElicitations,
5807
+ dottedNaming,
5808
+ emitToolTypeScript,
4041
5809
  enforceClosedObjects,
4042
5810
  ensureArrayItems,
4043
5811
  estimateToolTokens,
4044
5812
  extractExtensionOverrides,
5813
+ fromArazzo,
4045
5814
  inferAnnotationsFromMethod,
4046
5815
  inlineLocalRefs,
4047
5816
  isBlockedAddress,
@@ -4049,10 +5818,12 @@ export {
4049
5818
  isReferenceObject,
4050
5819
  lintDocument,
4051
5820
  normalizeSsrfOptions,
5821
+ parseRuntimeExpression,
4052
5822
  requireAllProperties,
4053
5823
  resolveExtensionEnabled,
4054
5824
  resolveSchemaFormats,
4055
5825
  safeFetch,
4056
5826
  toJsonSchema,
5827
+ toPascalIdentifier,
4057
5828
  toSdkTool
4058
5829
  };