@honeybee-ai/waggle-cli 1.0.21 → 1.0.23
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/dist/brood.d.ts +38 -0
- package/dist/brood.js +96 -0
- package/dist/brood.js.map +1 -1
- package/dist/cli.js +9 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/funnel.d.ts +58 -0
- package/dist/commands/funnel.js +1031 -0
- package/dist/commands/funnel.js.map +1 -0
- package/dist/commands/up.js +88 -0
- package/dist/commands/up.js.map +1 -1
- package/dist/lib/dance-loader.d.ts +32 -0
- package/dist/lib/dance-loader.js +66 -0
- package/dist/lib/dance-loader.js.map +1 -0
- package/dist/lib/graphql-loader.d.ts +57 -0
- package/dist/lib/graphql-loader.js +283 -0
- package/dist/lib/graphql-loader.js.map +1 -0
- package/dist/lib/header-resolver.d.ts +9 -0
- package/dist/lib/header-resolver.js +32 -0
- package/dist/lib/header-resolver.js.map +1 -0
- package/dist/lib/openapi-loader.d.ts +17 -0
- package/dist/lib/openapi-loader.js +164 -0
- package/dist/lib/openapi-loader.js.map +1 -0
- package/dist/wgl.js +735 -445
- package/dist/wgl.js.map +4 -4
- package/package.json +1 -1
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GraphQL → FunnelToolDef[] loader.
|
|
3
|
+
*
|
|
4
|
+
* Two modes:
|
|
5
|
+
* 1. URL source → introspect the endpoint
|
|
6
|
+
* 2. File source → parse local .graphql schema (needs --graphql-url for requests)
|
|
7
|
+
*
|
|
8
|
+
* Each Query/Mutation field becomes a funnel tool.
|
|
9
|
+
* Zero new npm deps.
|
|
10
|
+
*/
|
|
11
|
+
import { readFileSync } from 'node:fs';
|
|
12
|
+
import { resolve } from 'node:path';
|
|
13
|
+
const TIMEOUT_MS = 30_000;
|
|
14
|
+
const VALID_NAME_RE = /^[a-zA-Z0-9_]+$/;
|
|
15
|
+
const INTROSPECTION_QUERY = `{
|
|
16
|
+
__schema {
|
|
17
|
+
queryType { name }
|
|
18
|
+
mutationType { name }
|
|
19
|
+
types {
|
|
20
|
+
name
|
|
21
|
+
kind
|
|
22
|
+
fields {
|
|
23
|
+
name
|
|
24
|
+
description
|
|
25
|
+
args { name description type { kind name ofType { kind name ofType { kind name ofType { kind name } } } } }
|
|
26
|
+
type { kind name ofType { kind name ofType { kind name ofType { kind name } } } }
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}`;
|
|
31
|
+
/** Resolve a GQL type ref to a simple type string for tool params. */
|
|
32
|
+
function resolveTypeName(ref) {
|
|
33
|
+
if (ref.name)
|
|
34
|
+
return ref.name;
|
|
35
|
+
if (ref.ofType)
|
|
36
|
+
return resolveTypeName(ref.ofType);
|
|
37
|
+
return 'String';
|
|
38
|
+
}
|
|
39
|
+
/** Map GQL scalar types to simpler param types. */
|
|
40
|
+
function gqlTypeToParamType(ref) {
|
|
41
|
+
const name = resolveTypeName(ref);
|
|
42
|
+
switch (name) {
|
|
43
|
+
case 'Int':
|
|
44
|
+
case 'Float': return 'number';
|
|
45
|
+
case 'Boolean': return 'boolean';
|
|
46
|
+
case 'ID':
|
|
47
|
+
case 'String': return 'string';
|
|
48
|
+
default: return 'string'; // Enums, custom scalars → string
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/** Get scalar field names from a type for auto-selection sets. */
|
|
52
|
+
function getScalarFields(typeName, types) {
|
|
53
|
+
const resolvedName = typeName;
|
|
54
|
+
const typeDef = types.find(t => t.name === resolvedName);
|
|
55
|
+
if (!typeDef?.fields)
|
|
56
|
+
return [];
|
|
57
|
+
return typeDef.fields
|
|
58
|
+
.filter(f => {
|
|
59
|
+
const name = resolveTypeName(f.type);
|
|
60
|
+
return ['String', 'Int', 'Float', 'Boolean', 'ID'].includes(name) ||
|
|
61
|
+
// Also include NON_NULL wrappers of scalars
|
|
62
|
+
(f.type.kind === 'NON_NULL' && f.type.ofType && ['String', 'Int', 'Float', 'Boolean', 'ID'].includes(resolveTypeName(f.type.ofType)));
|
|
63
|
+
})
|
|
64
|
+
.map(f => f.name);
|
|
65
|
+
}
|
|
66
|
+
/** Build a selection set string for a return type. */
|
|
67
|
+
function buildSelectionSet(returnType, types) {
|
|
68
|
+
const typeName = resolveTypeName(returnType);
|
|
69
|
+
const scalars = getScalarFields(typeName, types);
|
|
70
|
+
if (scalars.length > 0)
|
|
71
|
+
return `{ ${scalars.join(' ')} }`;
|
|
72
|
+
return ''; // Scalar return type, no selection needed
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Load GraphQL tools from a URL (introspection) or local schema file.
|
|
76
|
+
*
|
|
77
|
+
* @param source - URL or file path
|
|
78
|
+
* @param endpointUrl - Required if source is a file (where to send queries)
|
|
79
|
+
* @param headers - Pre-resolved headers for introspection + query requests
|
|
80
|
+
*/
|
|
81
|
+
export async function loadGraphQLTools(source, endpointUrl, headers) {
|
|
82
|
+
const isUrl = source.startsWith('http://') || source.startsWith('https://');
|
|
83
|
+
const queryEndpoint = isUrl ? source : endpointUrl;
|
|
84
|
+
if (!queryEndpoint) {
|
|
85
|
+
throw new Error(`GraphQL: source "${source}" is a file — pass --graphql-url to specify the query endpoint`);
|
|
86
|
+
}
|
|
87
|
+
let schema;
|
|
88
|
+
if (isUrl) {
|
|
89
|
+
// Introspect the endpoint
|
|
90
|
+
schema = await introspect(source, headers);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
// Parse local schema file for type information, then introspect if possible
|
|
94
|
+
// For local files, we still need introspection for full type resolution.
|
|
95
|
+
// Try introspecting the endpoint; fall back to basic schema parsing.
|
|
96
|
+
try {
|
|
97
|
+
schema = await introspect(queryEndpoint, headers);
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// Fall back to basic file parsing
|
|
101
|
+
schema = parseSchemaFile(source);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const types = schema.data.__schema.types;
|
|
105
|
+
const queryTypeName = schema.data.__schema.queryType?.name;
|
|
106
|
+
const mutationTypeName = schema.data.__schema.mutationType?.name;
|
|
107
|
+
const tools = [];
|
|
108
|
+
// Process query fields
|
|
109
|
+
if (queryTypeName) {
|
|
110
|
+
const queryType = types.find(t => t.name === queryTypeName);
|
|
111
|
+
if (queryType?.fields) {
|
|
112
|
+
for (const field of queryType.fields) {
|
|
113
|
+
if (field.name.startsWith('__'))
|
|
114
|
+
continue; // Skip introspection fields
|
|
115
|
+
const tool = fieldToTool(field, 'query', queryEndpoint, headers || {}, types);
|
|
116
|
+
if (tool)
|
|
117
|
+
tools.push(tool);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// Process mutation fields
|
|
122
|
+
if (mutationTypeName) {
|
|
123
|
+
const mutationType = types.find(t => t.name === mutationTypeName);
|
|
124
|
+
if (mutationType?.fields) {
|
|
125
|
+
for (const field of mutationType.fields) {
|
|
126
|
+
if (field.name.startsWith('__'))
|
|
127
|
+
continue;
|
|
128
|
+
const tool = fieldToTool(field, 'mutation', queryEndpoint, headers || {}, types);
|
|
129
|
+
if (tool)
|
|
130
|
+
tools.push(tool);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return tools;
|
|
135
|
+
}
|
|
136
|
+
async function introspect(url, headers) {
|
|
137
|
+
const controller = new AbortController();
|
|
138
|
+
const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
139
|
+
try {
|
|
140
|
+
const resp = await fetch(url, {
|
|
141
|
+
method: 'POST',
|
|
142
|
+
headers: { 'Content-Type': 'application/json', ...headers },
|
|
143
|
+
body: JSON.stringify({ query: INTROSPECTION_QUERY }),
|
|
144
|
+
signal: controller.signal,
|
|
145
|
+
});
|
|
146
|
+
clearTimeout(timer);
|
|
147
|
+
if (!resp.ok) {
|
|
148
|
+
throw new Error(`GraphQL introspection failed: HTTP ${resp.status}`);
|
|
149
|
+
}
|
|
150
|
+
const result = await resp.json();
|
|
151
|
+
if (!result.data?.__schema) {
|
|
152
|
+
throw new Error('GraphQL introspection: invalid response (missing __schema)');
|
|
153
|
+
}
|
|
154
|
+
return result;
|
|
155
|
+
}
|
|
156
|
+
catch (err) {
|
|
157
|
+
clearTimeout(timer);
|
|
158
|
+
if (err instanceof Error && err.name === 'AbortError') {
|
|
159
|
+
throw new Error(`GraphQL introspection timed out after ${TIMEOUT_MS / 1000}s`);
|
|
160
|
+
}
|
|
161
|
+
throw err;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/** Basic .graphql schema file parser — extracts Query/Mutation types. */
|
|
165
|
+
function parseSchemaFile(filePath) {
|
|
166
|
+
const abs = resolve(filePath);
|
|
167
|
+
const content = readFileSync(abs, 'utf8');
|
|
168
|
+
const types = [];
|
|
169
|
+
let queryTypeName = null;
|
|
170
|
+
let mutationTypeName = null;
|
|
171
|
+
// Match type blocks: `type Query { ... }` or `type Mutation { ... }`
|
|
172
|
+
const typeBlockRe = /type\s+(\w+)\s*\{([^}]*)}/g;
|
|
173
|
+
let match;
|
|
174
|
+
while ((match = typeBlockRe.exec(content)) !== null) {
|
|
175
|
+
const typeName = match[1];
|
|
176
|
+
const body = match[2];
|
|
177
|
+
if (typeName === 'Query')
|
|
178
|
+
queryTypeName = 'Query';
|
|
179
|
+
if (typeName === 'Mutation')
|
|
180
|
+
mutationTypeName = 'Mutation';
|
|
181
|
+
// Parse fields: `fieldName(arg1: Type!, arg2: Type): ReturnType`
|
|
182
|
+
const fields = [];
|
|
183
|
+
const fieldRe = /(\w+)\s*(?:\(([^)]*)\))?\s*:\s*([^\n#![\]]+[!\]\s]*)/g;
|
|
184
|
+
let fieldMatch;
|
|
185
|
+
while ((fieldMatch = fieldRe.exec(body)) !== null) {
|
|
186
|
+
const fieldName = fieldMatch[1];
|
|
187
|
+
const argsStr = fieldMatch[2] || '';
|
|
188
|
+
const returnTypeStr = fieldMatch[3].trim().replace(/!$/, '');
|
|
189
|
+
const args = [];
|
|
190
|
+
if (argsStr) {
|
|
191
|
+
// Parse args: `name: Type!`
|
|
192
|
+
const argRe = /(\w+)\s*:\s*(\w+)(!?)/g;
|
|
193
|
+
let argMatch;
|
|
194
|
+
while ((argMatch = argRe.exec(argsStr)) !== null) {
|
|
195
|
+
args.push({
|
|
196
|
+
name: argMatch[1],
|
|
197
|
+
type: { kind: 'SCALAR', name: argMatch[2] },
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
fields.push({
|
|
202
|
+
name: fieldName,
|
|
203
|
+
args,
|
|
204
|
+
type: { kind: 'OBJECT', name: returnTypeStr.replace(/[[\]!]/g, '').trim() },
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
types.push({ name: typeName, kind: 'OBJECT', fields });
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
data: {
|
|
211
|
+
__schema: {
|
|
212
|
+
queryType: queryTypeName ? { name: queryTypeName } : null,
|
|
213
|
+
mutationType: mutationTypeName ? { name: mutationTypeName } : null,
|
|
214
|
+
types,
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
function fieldToTool(field, opType, endpoint, headers, types) {
|
|
220
|
+
if (!VALID_NAME_RE.test(field.name))
|
|
221
|
+
return null;
|
|
222
|
+
const description = field.description || `GraphQL ${opType}: ${field.name}`;
|
|
223
|
+
// Build params from field args
|
|
224
|
+
const params = {};
|
|
225
|
+
for (const arg of field.args) {
|
|
226
|
+
params[arg.name] = {
|
|
227
|
+
type: gqlTypeToParamType(arg.type),
|
|
228
|
+
description: arg.description,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
// Build selection set
|
|
232
|
+
const selectionSet = buildSelectionSet(field.type, types);
|
|
233
|
+
// Capture for closure
|
|
234
|
+
const fieldName = field.name;
|
|
235
|
+
const capturedArgs = field.args;
|
|
236
|
+
const handler = async (args) => {
|
|
237
|
+
// Build argument string for the query
|
|
238
|
+
const argParts = [];
|
|
239
|
+
const variables = {};
|
|
240
|
+
for (const arg of capturedArgs) {
|
|
241
|
+
if (args[arg.name] !== undefined) {
|
|
242
|
+
variables[arg.name] = args[arg.name];
|
|
243
|
+
const gqlType = resolveTypeName(arg.type);
|
|
244
|
+
argParts.push(`$${arg.name}: ${gqlType}${arg.type.kind === 'NON_NULL' ? '!' : ''}`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
// Build inline variable references
|
|
248
|
+
const fieldArgs = capturedArgs
|
|
249
|
+
.filter(a => args[a.name] !== undefined)
|
|
250
|
+
.map(a => `${a.name}: $${a.name}`)
|
|
251
|
+
.join(', ');
|
|
252
|
+
const varDecl = argParts.length > 0 ? `(${argParts.join(', ')})` : '';
|
|
253
|
+
const fieldArgStr = fieldArgs ? `(${fieldArgs})` : '';
|
|
254
|
+
const query = `${opType}${varDecl} { ${fieldName}${fieldArgStr}${selectionSet ? ' ' + selectionSet : ''} }`;
|
|
255
|
+
const controller = new AbortController();
|
|
256
|
+
const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
257
|
+
try {
|
|
258
|
+
const resp = await fetch(endpoint, {
|
|
259
|
+
method: 'POST',
|
|
260
|
+
headers: { 'Content-Type': 'application/json', ...headers },
|
|
261
|
+
body: JSON.stringify({ query, variables }),
|
|
262
|
+
signal: controller.signal,
|
|
263
|
+
});
|
|
264
|
+
clearTimeout(timer);
|
|
265
|
+
const result = await resp.json();
|
|
266
|
+
if (result.errors?.length) {
|
|
267
|
+
return { ok: false, error: result.errors[0].message };
|
|
268
|
+
}
|
|
269
|
+
return { ok: true, data: result.data?.[fieldName] };
|
|
270
|
+
}
|
|
271
|
+
catch (err) {
|
|
272
|
+
clearTimeout(timer);
|
|
273
|
+
if (err instanceof Error && err.name === 'AbortError') {
|
|
274
|
+
return { ok: false, error: `Request timed out after ${TIMEOUT_MS / 1000}s` };
|
|
275
|
+
}
|
|
276
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
return { name: fieldName, description, params, handler };
|
|
280
|
+
}
|
|
281
|
+
// Exported for testing
|
|
282
|
+
export { parseSchemaFile, introspect };
|
|
283
|
+
//# sourceMappingURL=graphql-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graphql-loader.js","sourceRoot":"","sources":["../../src/lib/graphql-loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve --api-header values with ${VAR} env interpolation.
|
|
3
|
+
*
|
|
4
|
+
* Input: ["Authorization: Bearer ${API_KEY}", "X-Custom: static"]
|
|
5
|
+
* Output: { Authorization: "Bearer sk-...", "X-Custom": "static" }
|
|
6
|
+
*
|
|
7
|
+
* Warns on unresolved vars (missing from process.env).
|
|
8
|
+
*/
|
|
9
|
+
export declare function resolveHeaders(raw: string[]): Record<string, string>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve --api-header values with ${VAR} env interpolation.
|
|
3
|
+
*
|
|
4
|
+
* Input: ["Authorization: Bearer ${API_KEY}", "X-Custom: static"]
|
|
5
|
+
* Output: { Authorization: "Bearer sk-...", "X-Custom": "static" }
|
|
6
|
+
*
|
|
7
|
+
* Warns on unresolved vars (missing from process.env).
|
|
8
|
+
*/
|
|
9
|
+
export function resolveHeaders(raw) {
|
|
10
|
+
const headers = {};
|
|
11
|
+
for (const entry of raw) {
|
|
12
|
+
const colonIdx = entry.indexOf(':');
|
|
13
|
+
if (colonIdx <= 0) {
|
|
14
|
+
console.warn(`Skipping malformed header (expected "Name: value"): ${entry}`);
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
const name = entry.slice(0, colonIdx).trim();
|
|
18
|
+
let value = entry.slice(colonIdx + 1).trim();
|
|
19
|
+
// Interpolate ${VAR} from process.env
|
|
20
|
+
value = value.replace(/\$\{([^}]+)\}/g, (_match, varName) => {
|
|
21
|
+
const envVal = process.env[varName];
|
|
22
|
+
if (envVal === undefined) {
|
|
23
|
+
console.warn(`Warning: env var ${varName} not set (in header "${name}")`);
|
|
24
|
+
return '';
|
|
25
|
+
}
|
|
26
|
+
return envVal;
|
|
27
|
+
});
|
|
28
|
+
headers[name] = value;
|
|
29
|
+
}
|
|
30
|
+
return headers;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=header-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"header-resolver.js","sourceRoot":"","sources":["../../src/lib/header-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,UAAU,cAAc,CAAC,GAAa;IAC1C,MAAM,OAAO,GAA2B,EAAE,CAAC;IAE3C,KAAK,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC;QACxB,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;YAClB,OAAO,CAAC,IAAI,CAAC,uDAAuD,KAAK,EAAE,CAAC,CAAC;YAC7E,SAAS;QACX,CAAC;QACD,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7C,IAAI,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAE7C,sCAAsC;QACtC,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,MAAM,EAAE,OAAe,EAAE,EAAE;YAClE,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACpC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACzB,OAAO,CAAC,IAAI,CAAC,oBAAoB,OAAO,wBAAwB,IAAI,IAAI,CAAC,CAAC;gBAC1E,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;IACxB,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAPI 3.x → FunnelToolDef[] loader.
|
|
3
|
+
*
|
|
4
|
+
* Parses an OpenAPI spec (YAML/JSON) and converts each operation with
|
|
5
|
+
* an operationId into a funnel tool that proxies HTTP requests.
|
|
6
|
+
*
|
|
7
|
+
* Zero new npm deps — js-yaml already installed.
|
|
8
|
+
*/
|
|
9
|
+
import type { FunnelToolDef } from './dance-loader.js';
|
|
10
|
+
/**
|
|
11
|
+
* Load an OpenAPI 3.x spec and return funnel tool definitions.
|
|
12
|
+
*
|
|
13
|
+
* @param filePath - Path to YAML/JSON spec file
|
|
14
|
+
* @param baseUrl - Override base URL (falls back to spec.servers[0].url)
|
|
15
|
+
* @param headers - Pre-resolved headers to include in every request
|
|
16
|
+
*/
|
|
17
|
+
export declare function loadOpenAPITools(filePath: string, baseUrl?: string, headers?: Record<string, string>): Promise<FunnelToolDef[]>;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAPI 3.x → FunnelToolDef[] loader.
|
|
3
|
+
*
|
|
4
|
+
* Parses an OpenAPI spec (YAML/JSON) and converts each operation with
|
|
5
|
+
* an operationId into a funnel tool that proxies HTTP requests.
|
|
6
|
+
*
|
|
7
|
+
* Zero new npm deps — js-yaml already installed.
|
|
8
|
+
*/
|
|
9
|
+
import { readFileSync } from 'node:fs';
|
|
10
|
+
import { resolve } from 'node:path';
|
|
11
|
+
import yaml from 'js-yaml';
|
|
12
|
+
const VALID_NAME_RE = /^[a-zA-Z0-9_-]+$/;
|
|
13
|
+
const BODY_METHODS = new Set(['post', 'put', 'patch']);
|
|
14
|
+
const RESPONSE_LIMIT = 10 * 1024 * 1024; // 10MB
|
|
15
|
+
const TIMEOUT_MS = 30_000;
|
|
16
|
+
/**
|
|
17
|
+
* Load an OpenAPI 3.x spec and return funnel tool definitions.
|
|
18
|
+
*
|
|
19
|
+
* @param filePath - Path to YAML/JSON spec file
|
|
20
|
+
* @param baseUrl - Override base URL (falls back to spec.servers[0].url)
|
|
21
|
+
* @param headers - Pre-resolved headers to include in every request
|
|
22
|
+
*/
|
|
23
|
+
export async function loadOpenAPITools(filePath, baseUrl, headers) {
|
|
24
|
+
const abs = resolve(filePath);
|
|
25
|
+
const content = readFileSync(abs, 'utf8');
|
|
26
|
+
const spec = (abs.endsWith('.json') ? JSON.parse(content) : yaml.load(content));
|
|
27
|
+
// Resolve base URL
|
|
28
|
+
let resolvedBase = baseUrl;
|
|
29
|
+
if (!resolvedBase) {
|
|
30
|
+
const servers = spec.servers;
|
|
31
|
+
if (servers?.[0]?.url) {
|
|
32
|
+
resolvedBase = servers[0].url;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (!resolvedBase) {
|
|
36
|
+
throw new Error(`OpenAPI spec ${filePath}: no base URL — pass --api-url or add servers[0].url to spec`);
|
|
37
|
+
}
|
|
38
|
+
// Strip trailing slash
|
|
39
|
+
resolvedBase = resolvedBase.replace(/\/+$/, '');
|
|
40
|
+
const paths = spec.paths;
|
|
41
|
+
if (!paths)
|
|
42
|
+
return [];
|
|
43
|
+
const tools = [];
|
|
44
|
+
for (const [pathTemplate, methods] of Object.entries(paths)) {
|
|
45
|
+
for (const [method, operation] of Object.entries(methods)) {
|
|
46
|
+
// Skip non-operation keys (parameters, summary, etc.)
|
|
47
|
+
if (!operation || typeof operation !== 'object' || !operation.operationId)
|
|
48
|
+
continue;
|
|
49
|
+
const opId = operation.operationId;
|
|
50
|
+
if (!VALID_NAME_RE.test(opId)) {
|
|
51
|
+
console.warn(`OpenAPI: skipping operation with invalid operationId "${opId}"`);
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
const description = operation.summary || operation.description || `${method.toUpperCase()} ${pathTemplate}`;
|
|
55
|
+
// Build params from path/query/header parameters
|
|
56
|
+
const params = {};
|
|
57
|
+
const pathParams = [];
|
|
58
|
+
const queryParams = [];
|
|
59
|
+
if (operation.parameters) {
|
|
60
|
+
for (const p of operation.parameters) {
|
|
61
|
+
const paramType = p.schema?.type || 'string';
|
|
62
|
+
params[p.name] = { type: paramType, description: p.description };
|
|
63
|
+
if (p.in === 'path')
|
|
64
|
+
pathParams.push(p.name);
|
|
65
|
+
if (p.in === 'query')
|
|
66
|
+
queryParams.push(p.name);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Body params for POST/PUT/PATCH
|
|
70
|
+
if (BODY_METHODS.has(method)) {
|
|
71
|
+
const bodySchema = operation.requestBody?.content?.['application/json']?.schema;
|
|
72
|
+
if (bodySchema?.properties) {
|
|
73
|
+
for (const [propName, propDef] of Object.entries(bodySchema.properties)) {
|
|
74
|
+
params[propName] = { type: propDef.type || 'string', description: propDef.description };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// Capture for closure
|
|
79
|
+
const httpMethod = method.toUpperCase();
|
|
80
|
+
const template = pathTemplate;
|
|
81
|
+
const base = resolvedBase;
|
|
82
|
+
const hdrs = headers || {};
|
|
83
|
+
const isBodyMethod = BODY_METHODS.has(method);
|
|
84
|
+
const capturedPathParams = pathParams;
|
|
85
|
+
const capturedQueryParams = queryParams;
|
|
86
|
+
const handler = async (args) => {
|
|
87
|
+
// Build URL: replace path params
|
|
88
|
+
let path = template;
|
|
89
|
+
for (const p of capturedPathParams) {
|
|
90
|
+
const val = args[p];
|
|
91
|
+
if (val !== undefined) {
|
|
92
|
+
path = path.replace(`{${p}}`, encodeURIComponent(String(val)));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Append query params
|
|
96
|
+
const qParts = [];
|
|
97
|
+
for (const p of capturedQueryParams) {
|
|
98
|
+
if (args[p] !== undefined) {
|
|
99
|
+
qParts.push(`${encodeURIComponent(p)}=${encodeURIComponent(String(args[p]))}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const queryStr = qParts.length > 0 ? `?${qParts.join('&')}` : '';
|
|
103
|
+
const url = `${base}${path}${queryStr}`;
|
|
104
|
+
// Build request
|
|
105
|
+
const reqHeaders = { ...hdrs };
|
|
106
|
+
const fetchOpts = { method: httpMethod, headers: reqHeaders };
|
|
107
|
+
if (isBodyMethod) {
|
|
108
|
+
reqHeaders['Content-Type'] = 'application/json';
|
|
109
|
+
// Body = all args minus path and query params
|
|
110
|
+
const bodyArgs = {};
|
|
111
|
+
for (const [k, v] of Object.entries(args)) {
|
|
112
|
+
if (!capturedPathParams.includes(k) && !capturedQueryParams.includes(k)) {
|
|
113
|
+
bodyArgs[k] = v;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (Object.keys(bodyArgs).length > 0) {
|
|
117
|
+
fetchOpts.body = JSON.stringify(bodyArgs);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// Execute with timeout
|
|
121
|
+
const controller = new AbortController();
|
|
122
|
+
const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
123
|
+
fetchOpts.signal = controller.signal;
|
|
124
|
+
try {
|
|
125
|
+
const resp = await fetch(url, fetchOpts);
|
|
126
|
+
clearTimeout(timer);
|
|
127
|
+
// Read response with size limit
|
|
128
|
+
const respText = await resp.text();
|
|
129
|
+
if (respText.length > RESPONSE_LIMIT) {
|
|
130
|
+
return { ok: false, error: `Response exceeds ${RESPONSE_LIMIT / 1024 / 1024}MB limit` };
|
|
131
|
+
}
|
|
132
|
+
let body;
|
|
133
|
+
try {
|
|
134
|
+
body = JSON.parse(respText);
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
body = respText;
|
|
138
|
+
}
|
|
139
|
+
if (resp.ok) {
|
|
140
|
+
return {
|
|
141
|
+
ok: true,
|
|
142
|
+
data: {
|
|
143
|
+
status: resp.status,
|
|
144
|
+
headers: Object.fromEntries(resp.headers.entries()),
|
|
145
|
+
body,
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
return { ok: false, error: `HTTP ${resp.status}: ${typeof body === 'string' ? body : JSON.stringify(body)}` };
|
|
150
|
+
}
|
|
151
|
+
catch (err) {
|
|
152
|
+
clearTimeout(timer);
|
|
153
|
+
if (err instanceof Error && err.name === 'AbortError') {
|
|
154
|
+
return { ok: false, error: `Request timed out after ${TIMEOUT_MS / 1000}s` };
|
|
155
|
+
}
|
|
156
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
tools.push({ name: opId, description, params, handler });
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return tools;
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=openapi-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openapi-loader.js","sourceRoot":"","sources":["../../src/lib/openapi-loader.ts"],"names":[],"mappings":"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"}
|