@executor-js/plugin-openapi 0.0.1 → 0.1.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/README.md +24 -23
- package/dist/api/group.d.ts +94 -38
- package/dist/api/handlers.d.ts +2 -2
- package/dist/chunk-RBE3CVB4.js +2837 -0
- package/dist/chunk-RBE3CVB4.js.map +1 -0
- package/dist/core.js +44 -50
- package/dist/core.js.map +1 -1
- package/dist/index.js +2 -5
- package/dist/index.js.map +1 -1
- package/dist/react/AddOpenApiSource.d.ts +13 -0
- package/dist/react/EditOpenApiSource.d.ts +2 -2
- package/dist/react/OpenApiSourceSummary.d.ts +3 -1
- package/dist/react/atoms.d.ts +129 -0
- package/dist/react/client.d.ts +88 -3
- package/dist/react/plugin-client.d.ts +2 -0
- package/dist/react/source-plugin.d.ts +1 -1
- package/dist/sdk/client-credentials-oauth.test.d.ts +1 -0
- package/dist/sdk/credential-status.d.ts +23 -0
- package/dist/sdk/credential-status.test.d.ts +1 -0
- package/dist/sdk/errors.d.ts +11 -10
- package/dist/sdk/form-urlencoded-body.test.d.ts +1 -0
- package/dist/sdk/index.d.ts +8 -10
- package/dist/sdk/invoke.d.ts +8 -17
- package/dist/sdk/multi-scope-bearer.test.d.ts +1 -0
- package/dist/sdk/multi-scope-oauth.test.d.ts +1 -0
- package/dist/sdk/non-json-body.test.d.ts +1 -0
- package/dist/sdk/oauth-refresh.test.d.ts +1 -0
- package/dist/sdk/openapi-utils.d.ts +35 -4
- package/dist/sdk/parse.d.ts +28 -4
- package/dist/sdk/plugin.d.ts +278 -23
- package/dist/sdk/preview-oauth2.test.d.ts +1 -0
- package/dist/sdk/preview.d.ts +86 -161
- package/dist/sdk/store.d.ts +201 -0
- package/dist/sdk/types.d.ts +234 -266
- package/dist/sdk/upstream-failures.test.d.ts +1 -0
- package/package.json +11 -22
- package/dist/chunk-KPGROAQO.js +0 -1279
- package/dist/chunk-KPGROAQO.js.map +0 -1
- package/dist/promise.d.ts +0 -6
- package/dist/sdk/config-file-store.d.ts +0 -10
- package/dist/sdk/kv-operation-store.d.ts +0 -4
- package/dist/sdk/operation-store.d.ts +0 -36
- package/dist/sdk/stored-source.d.ts +0 -51
package/dist/chunk-KPGROAQO.js
DELETED
|
@@ -1,1279 +0,0 @@
|
|
|
1
|
-
// src/sdk/errors.ts
|
|
2
|
-
import { Data, Schema } from "effect";
|
|
3
|
-
var OpenApiParseError = class extends Schema.TaggedError()(
|
|
4
|
-
"OpenApiParseError",
|
|
5
|
-
{
|
|
6
|
-
message: Schema.String
|
|
7
|
-
}
|
|
8
|
-
) {
|
|
9
|
-
};
|
|
10
|
-
var OpenApiExtractionError = class extends Schema.TaggedError()(
|
|
11
|
-
"OpenApiExtractionError",
|
|
12
|
-
{
|
|
13
|
-
message: Schema.String
|
|
14
|
-
}
|
|
15
|
-
) {
|
|
16
|
-
};
|
|
17
|
-
var OpenApiInvocationError = class extends Data.TaggedError("OpenApiInvocationError") {
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
// src/sdk/parse.ts
|
|
21
|
-
import SwaggerParser from "@apidevtools/swagger-parser";
|
|
22
|
-
import { Effect } from "effect";
|
|
23
|
-
import YAML from "yaml";
|
|
24
|
-
var parse = Effect.fn("OpenApi.parse")(function* (input) {
|
|
25
|
-
const api = yield* Effect.tryPromise({
|
|
26
|
-
try: async () => {
|
|
27
|
-
const source = input.startsWith("http://") || input.startsWith("https://") ? input : parseTextToObject(input);
|
|
28
|
-
try {
|
|
29
|
-
return await SwaggerParser.bundle(source);
|
|
30
|
-
} catch {
|
|
31
|
-
const parsed = await SwaggerParser.parse(source);
|
|
32
|
-
resolveRefsInPlace(parsed);
|
|
33
|
-
return parsed;
|
|
34
|
-
}
|
|
35
|
-
},
|
|
36
|
-
catch: (error) => new OpenApiParseError({
|
|
37
|
-
message: `Failed to parse OpenAPI document: ${error instanceof Error ? error.message : String(error)}`
|
|
38
|
-
})
|
|
39
|
-
});
|
|
40
|
-
if (!isOpenApi3(api)) {
|
|
41
|
-
return yield* new OpenApiExtractionErrorFromParse({
|
|
42
|
-
message: "Only OpenAPI 3.x documents are supported. Swagger 2.x documents should be converted first."
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
return api;
|
|
46
|
-
});
|
|
47
|
-
var OpenApiExtractionErrorFromParse = class extends OpenApiExtractionError {
|
|
48
|
-
};
|
|
49
|
-
var isOpenApi3 = (doc) => "openapi" in doc && typeof doc.openapi === "string" && doc.openapi.startsWith("3.");
|
|
50
|
-
var parseTextToObject = (text) => {
|
|
51
|
-
const trimmed = text.trim();
|
|
52
|
-
if (trimmed.length === 0) throw new Error("OpenAPI document is empty");
|
|
53
|
-
let parsed;
|
|
54
|
-
try {
|
|
55
|
-
parsed = JSON.parse(trimmed);
|
|
56
|
-
} catch {
|
|
57
|
-
parsed = YAML.parse(trimmed);
|
|
58
|
-
}
|
|
59
|
-
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
60
|
-
throw new Error("OpenAPI document must parse to an object");
|
|
61
|
-
}
|
|
62
|
-
return parsed;
|
|
63
|
-
};
|
|
64
|
-
var resolveRefsInPlace = (doc) => {
|
|
65
|
-
const lookup = (pointer) => {
|
|
66
|
-
if (!pointer.startsWith("#/")) return void 0;
|
|
67
|
-
const parts = pointer.slice(2).split("/");
|
|
68
|
-
let current = doc;
|
|
69
|
-
for (const part of parts) {
|
|
70
|
-
if (typeof current !== "object" || current === null) return void 0;
|
|
71
|
-
current = current[part];
|
|
72
|
-
}
|
|
73
|
-
return current;
|
|
74
|
-
};
|
|
75
|
-
const resolving = /* @__PURE__ */ new Set();
|
|
76
|
-
const resolveRef = (pointer) => {
|
|
77
|
-
if (resolving.has(pointer)) return void 0;
|
|
78
|
-
const target = lookup(pointer);
|
|
79
|
-
if (!target) return void 0;
|
|
80
|
-
resolving.add(pointer);
|
|
81
|
-
const cloned = deepClone(target);
|
|
82
|
-
walk(cloned);
|
|
83
|
-
resolving.delete(pointer);
|
|
84
|
-
return cloned;
|
|
85
|
-
};
|
|
86
|
-
const deepClone = (obj) => {
|
|
87
|
-
if (!obj || typeof obj !== "object") return obj;
|
|
88
|
-
if (Array.isArray(obj)) return obj.map(deepClone);
|
|
89
|
-
const result = {};
|
|
90
|
-
for (const [k, v] of Object.entries(obj)) {
|
|
91
|
-
result[k] = deepClone(v);
|
|
92
|
-
}
|
|
93
|
-
return result;
|
|
94
|
-
};
|
|
95
|
-
const walk = (obj) => {
|
|
96
|
-
if (!obj || typeof obj !== "object") return;
|
|
97
|
-
if (Array.isArray(obj)) {
|
|
98
|
-
for (let i = 0; i < obj.length; i++) {
|
|
99
|
-
const item = obj[i];
|
|
100
|
-
if (isRef(item)) {
|
|
101
|
-
const resolved = resolveRef(item.$ref);
|
|
102
|
-
if (resolved) obj[i] = resolved;
|
|
103
|
-
else obj[i] = { description: `Unresolved: ${item.$ref}` };
|
|
104
|
-
} else {
|
|
105
|
-
walk(item);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
const record = obj;
|
|
111
|
-
for (const [k, v] of Object.entries(record)) {
|
|
112
|
-
if (k === "$ref") continue;
|
|
113
|
-
if (isRef(v)) {
|
|
114
|
-
const resolved = resolveRef(v.$ref);
|
|
115
|
-
if (resolved) record[k] = resolved;
|
|
116
|
-
else record[k] = { description: `Unresolved: ${v.$ref}` };
|
|
117
|
-
} else {
|
|
118
|
-
walk(v);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
walk(doc);
|
|
123
|
-
};
|
|
124
|
-
var isRef = (v) => typeof v === "object" && v !== null && "$ref" in v && typeof v.$ref === "string";
|
|
125
|
-
|
|
126
|
-
// src/sdk/openapi-utils.ts
|
|
127
|
-
import { Option } from "effect";
|
|
128
|
-
var DocResolver = class {
|
|
129
|
-
constructor(doc) {
|
|
130
|
-
this.doc = doc;
|
|
131
|
-
}
|
|
132
|
-
doc;
|
|
133
|
-
/** Resolve a value that might be a $ref, returning the resolved object */
|
|
134
|
-
resolve(value) {
|
|
135
|
-
if (isRef2(value)) {
|
|
136
|
-
const resolved = this.resolvePointer(value.$ref);
|
|
137
|
-
return resolved;
|
|
138
|
-
}
|
|
139
|
-
return value;
|
|
140
|
-
}
|
|
141
|
-
resolvePointer(ref) {
|
|
142
|
-
if (!ref.startsWith("#/")) return null;
|
|
143
|
-
const segments = ref.slice(2).split("/");
|
|
144
|
-
let current = this.doc;
|
|
145
|
-
for (const segment of segments) {
|
|
146
|
-
if (typeof current !== "object" || current === null) return null;
|
|
147
|
-
current = current[segment];
|
|
148
|
-
}
|
|
149
|
-
return current;
|
|
150
|
-
}
|
|
151
|
-
};
|
|
152
|
-
var isRef2 = (value) => typeof value === "object" && value !== null && "$ref" in value;
|
|
153
|
-
var resolveBaseUrl = (servers) => {
|
|
154
|
-
const server = servers[0];
|
|
155
|
-
if (!server) return "";
|
|
156
|
-
let url = server.url;
|
|
157
|
-
if (Option.isSome(server.variables)) {
|
|
158
|
-
for (const [name, value] of Object.entries(server.variables.value)) {
|
|
159
|
-
url = url.replaceAll(`{${name}}`, value);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
return url;
|
|
163
|
-
};
|
|
164
|
-
var preferredContent = (content) => {
|
|
165
|
-
if (!content) return void 0;
|
|
166
|
-
const entries = Object.entries(content);
|
|
167
|
-
const pick = entries.find(([mt]) => mt === "application/json") ?? entries.find(([mt]) => mt.toLowerCase().includes("+json")) ?? entries.find(([mt]) => mt.toLowerCase().includes("json")) ?? entries[0];
|
|
168
|
-
return pick ? { mediaType: pick[0], media: pick[1] } : void 0;
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
// src/sdk/types.ts
|
|
172
|
-
import { Schema as Schema2 } from "effect";
|
|
173
|
-
var OperationId = Schema2.String.pipe(Schema2.brand("OperationId"));
|
|
174
|
-
var HttpMethod = Schema2.Literal(
|
|
175
|
-
"get",
|
|
176
|
-
"put",
|
|
177
|
-
"post",
|
|
178
|
-
"delete",
|
|
179
|
-
"patch",
|
|
180
|
-
"head",
|
|
181
|
-
"options",
|
|
182
|
-
"trace"
|
|
183
|
-
);
|
|
184
|
-
var ParameterLocation = Schema2.Literal("path", "query", "header", "cookie");
|
|
185
|
-
var OperationParameter = class extends Schema2.Class("OperationParameter")({
|
|
186
|
-
name: Schema2.String,
|
|
187
|
-
location: ParameterLocation,
|
|
188
|
-
required: Schema2.Boolean,
|
|
189
|
-
schema: Schema2.optionalWith(Schema2.Unknown, { as: "Option" }),
|
|
190
|
-
style: Schema2.optionalWith(Schema2.String, { as: "Option" }),
|
|
191
|
-
explode: Schema2.optionalWith(Schema2.Boolean, { as: "Option" }),
|
|
192
|
-
allowReserved: Schema2.optionalWith(Schema2.Boolean, { as: "Option" }),
|
|
193
|
-
description: Schema2.optionalWith(Schema2.String, { as: "Option" })
|
|
194
|
-
}) {
|
|
195
|
-
};
|
|
196
|
-
var OperationRequestBody = class extends Schema2.Class(
|
|
197
|
-
"OperationRequestBody"
|
|
198
|
-
)({
|
|
199
|
-
required: Schema2.Boolean,
|
|
200
|
-
contentType: Schema2.String,
|
|
201
|
-
schema: Schema2.optionalWith(Schema2.Unknown, { as: "Option" })
|
|
202
|
-
}) {
|
|
203
|
-
};
|
|
204
|
-
var ExtractedOperation = class extends Schema2.Class("ExtractedOperation")({
|
|
205
|
-
operationId: OperationId,
|
|
206
|
-
method: HttpMethod,
|
|
207
|
-
pathTemplate: Schema2.String,
|
|
208
|
-
summary: Schema2.optionalWith(Schema2.String, { as: "Option" }),
|
|
209
|
-
description: Schema2.optionalWith(Schema2.String, { as: "Option" }),
|
|
210
|
-
tags: Schema2.Array(Schema2.String),
|
|
211
|
-
parameters: Schema2.Array(OperationParameter),
|
|
212
|
-
requestBody: Schema2.optionalWith(OperationRequestBody, { as: "Option" }),
|
|
213
|
-
inputSchema: Schema2.optionalWith(Schema2.Unknown, { as: "Option" }),
|
|
214
|
-
outputSchema: Schema2.optionalWith(Schema2.Unknown, { as: "Option" }),
|
|
215
|
-
deprecated: Schema2.optionalWith(Schema2.Boolean, { default: () => false })
|
|
216
|
-
}) {
|
|
217
|
-
};
|
|
218
|
-
var ServerInfo = class extends Schema2.Class("ServerInfo")({
|
|
219
|
-
url: Schema2.String,
|
|
220
|
-
variables: Schema2.optionalWith(Schema2.Record({ key: Schema2.String, value: Schema2.String }), {
|
|
221
|
-
as: "Option"
|
|
222
|
-
})
|
|
223
|
-
}) {
|
|
224
|
-
};
|
|
225
|
-
var ExtractionResult = class extends Schema2.Class("ExtractionResult")({
|
|
226
|
-
title: Schema2.optionalWith(Schema2.String, { as: "Option" }),
|
|
227
|
-
version: Schema2.optionalWith(Schema2.String, { as: "Option" }),
|
|
228
|
-
servers: Schema2.Array(ServerInfo),
|
|
229
|
-
operations: Schema2.Array(ExtractedOperation)
|
|
230
|
-
}) {
|
|
231
|
-
};
|
|
232
|
-
var OperationBinding = class extends Schema2.Class("OperationBinding")({
|
|
233
|
-
method: HttpMethod,
|
|
234
|
-
pathTemplate: Schema2.String,
|
|
235
|
-
parameters: Schema2.Array(OperationParameter),
|
|
236
|
-
requestBody: Schema2.optionalWith(OperationRequestBody, { as: "Option" })
|
|
237
|
-
}) {
|
|
238
|
-
};
|
|
239
|
-
var HeaderValue = Schema2.Union(
|
|
240
|
-
Schema2.String,
|
|
241
|
-
Schema2.Struct({
|
|
242
|
-
secretId: Schema2.String,
|
|
243
|
-
prefix: Schema2.optional(Schema2.String)
|
|
244
|
-
})
|
|
245
|
-
);
|
|
246
|
-
var InvocationConfig = class extends Schema2.Class("InvocationConfig")({
|
|
247
|
-
baseUrl: Schema2.String,
|
|
248
|
-
/** Headers applied to every request. Values can reference secrets. */
|
|
249
|
-
headers: Schema2.optionalWith(Schema2.Record({ key: Schema2.String, value: HeaderValue }), {
|
|
250
|
-
default: () => ({})
|
|
251
|
-
})
|
|
252
|
-
}) {
|
|
253
|
-
};
|
|
254
|
-
var InvocationResult = class extends Schema2.Class("InvocationResult")({
|
|
255
|
-
status: Schema2.Number,
|
|
256
|
-
headers: Schema2.Record({ key: Schema2.String, value: Schema2.String }),
|
|
257
|
-
data: Schema2.NullOr(Schema2.Unknown),
|
|
258
|
-
error: Schema2.NullOr(Schema2.Unknown)
|
|
259
|
-
}) {
|
|
260
|
-
};
|
|
261
|
-
|
|
262
|
-
// src/sdk/extract.ts
|
|
263
|
-
import { Effect as Effect2, Option as Option2 } from "effect";
|
|
264
|
-
var HTTP_METHODS = [
|
|
265
|
-
"get",
|
|
266
|
-
"put",
|
|
267
|
-
"post",
|
|
268
|
-
"delete",
|
|
269
|
-
"patch",
|
|
270
|
-
"head",
|
|
271
|
-
"options",
|
|
272
|
-
"trace"
|
|
273
|
-
];
|
|
274
|
-
var VALID_PARAM_LOCATIONS = /* @__PURE__ */ new Set(["path", "query", "header", "cookie"]);
|
|
275
|
-
var extractParameters = (pathItem, operation, r) => {
|
|
276
|
-
const merged = /* @__PURE__ */ new Map();
|
|
277
|
-
for (const raw of pathItem.parameters ?? []) {
|
|
278
|
-
const p = r.resolve(raw);
|
|
279
|
-
if (!p) continue;
|
|
280
|
-
merged.set(`${p.in}:${p.name}`, p);
|
|
281
|
-
}
|
|
282
|
-
for (const raw of operation.parameters ?? []) {
|
|
283
|
-
const p = r.resolve(raw);
|
|
284
|
-
if (!p) continue;
|
|
285
|
-
merged.set(`${p.in}:${p.name}`, p);
|
|
286
|
-
}
|
|
287
|
-
return [...merged.values()].filter((p) => VALID_PARAM_LOCATIONS.has(p.in)).map(
|
|
288
|
-
(p) => new OperationParameter({
|
|
289
|
-
name: p.name,
|
|
290
|
-
location: p.in,
|
|
291
|
-
required: p.in === "path" ? true : p.required === true,
|
|
292
|
-
schema: Option2.fromNullable(p.schema),
|
|
293
|
-
style: Option2.fromNullable(p.style),
|
|
294
|
-
explode: Option2.fromNullable(p.explode),
|
|
295
|
-
allowReserved: Option2.fromNullable("allowReserved" in p ? p.allowReserved : void 0),
|
|
296
|
-
description: Option2.fromNullable(p.description)
|
|
297
|
-
})
|
|
298
|
-
);
|
|
299
|
-
};
|
|
300
|
-
var extractRequestBody = (operation, r) => {
|
|
301
|
-
if (!operation.requestBody) return void 0;
|
|
302
|
-
const body = r.resolve(operation.requestBody);
|
|
303
|
-
if (!body) return void 0;
|
|
304
|
-
const content = preferredContent(body.content);
|
|
305
|
-
if (!content) return void 0;
|
|
306
|
-
return new OperationRequestBody({
|
|
307
|
-
required: body.required === true,
|
|
308
|
-
contentType: content.mediaType,
|
|
309
|
-
schema: Option2.fromNullable(content.media.schema)
|
|
310
|
-
});
|
|
311
|
-
};
|
|
312
|
-
var extractOutputSchema = (operation, r) => {
|
|
313
|
-
if (!operation.responses) return void 0;
|
|
314
|
-
const entries = Object.entries(operation.responses);
|
|
315
|
-
const preferred = [
|
|
316
|
-
...entries.filter(([s]) => /^2\d\d$/.test(s)).sort(([a], [b]) => a.localeCompare(b)),
|
|
317
|
-
...entries.filter(([s]) => s === "default")
|
|
318
|
-
];
|
|
319
|
-
for (const [, ref] of preferred) {
|
|
320
|
-
const resp = r.resolve(ref);
|
|
321
|
-
if (!resp) continue;
|
|
322
|
-
const content = preferredContent(resp.content);
|
|
323
|
-
if (content?.media.schema) return content.media.schema;
|
|
324
|
-
}
|
|
325
|
-
return void 0;
|
|
326
|
-
};
|
|
327
|
-
var buildInputSchema = (parameters, requestBody) => {
|
|
328
|
-
const properties = {};
|
|
329
|
-
const required = [];
|
|
330
|
-
for (const param of parameters) {
|
|
331
|
-
properties[param.name] = Option2.getOrElse(param.schema, () => ({ type: "string" }));
|
|
332
|
-
if (param.required) required.push(param.name);
|
|
333
|
-
}
|
|
334
|
-
if (requestBody) {
|
|
335
|
-
properties.body = Option2.getOrElse(requestBody.schema, () => ({ type: "object" }));
|
|
336
|
-
if (requestBody.required) required.push("body");
|
|
337
|
-
}
|
|
338
|
-
if (Object.keys(properties).length === 0) return void 0;
|
|
339
|
-
return {
|
|
340
|
-
type: "object",
|
|
341
|
-
properties,
|
|
342
|
-
...required.length > 0 ? { required } : {},
|
|
343
|
-
additionalProperties: false
|
|
344
|
-
};
|
|
345
|
-
};
|
|
346
|
-
var deriveOperationId = (method, pathTemplate, operation) => operation.operationId ?? (`${method}_${pathTemplate.replace(/[^a-zA-Z0-9]+/g, "_")}`.replace(/^_+|_+$/g, "") || `${method}_operation`);
|
|
347
|
-
var extractServers = (doc) => (doc.servers ?? []).flatMap((server) => {
|
|
348
|
-
if (!server.url) return [];
|
|
349
|
-
const vars = server.variables ? Object.fromEntries(
|
|
350
|
-
Object.entries(server.variables).flatMap(
|
|
351
|
-
([name, v]) => v.default ? [[name, v.default]] : []
|
|
352
|
-
)
|
|
353
|
-
) : void 0;
|
|
354
|
-
return [
|
|
355
|
-
new ServerInfo({
|
|
356
|
-
url: server.url,
|
|
357
|
-
variables: vars && Object.keys(vars).length > 0 ? Option2.some(vars) : Option2.none()
|
|
358
|
-
})
|
|
359
|
-
];
|
|
360
|
-
});
|
|
361
|
-
var extract = Effect2.fn("OpenApi.extract")(function* (doc) {
|
|
362
|
-
const paths = doc.paths;
|
|
363
|
-
if (!paths) {
|
|
364
|
-
return yield* new OpenApiExtractionError({
|
|
365
|
-
message: "OpenAPI document has no paths defined"
|
|
366
|
-
});
|
|
367
|
-
}
|
|
368
|
-
const r = new DocResolver(doc);
|
|
369
|
-
const operations = [];
|
|
370
|
-
for (const [pathTemplate, pathItem] of Object.entries(paths).sort(
|
|
371
|
-
([a], [b]) => a.localeCompare(b)
|
|
372
|
-
)) {
|
|
373
|
-
if (!pathItem) continue;
|
|
374
|
-
for (const method of HTTP_METHODS) {
|
|
375
|
-
const operation = pathItem[method];
|
|
376
|
-
if (!operation) continue;
|
|
377
|
-
const parameters = extractParameters(pathItem, operation, r);
|
|
378
|
-
const requestBody = extractRequestBody(operation, r);
|
|
379
|
-
const inputSchema = buildInputSchema(parameters, requestBody);
|
|
380
|
-
const outputSchema = extractOutputSchema(operation, r);
|
|
381
|
-
const tags = (operation.tags ?? []).filter((t) => t.trim().length > 0);
|
|
382
|
-
operations.push(
|
|
383
|
-
new ExtractedOperation({
|
|
384
|
-
operationId: OperationId.make(deriveOperationId(method, pathTemplate, operation)),
|
|
385
|
-
method,
|
|
386
|
-
pathTemplate,
|
|
387
|
-
summary: Option2.fromNullable(operation.summary),
|
|
388
|
-
description: Option2.fromNullable(operation.description),
|
|
389
|
-
tags,
|
|
390
|
-
parameters,
|
|
391
|
-
requestBody: Option2.fromNullable(requestBody),
|
|
392
|
-
inputSchema: Option2.fromNullable(inputSchema),
|
|
393
|
-
outputSchema: Option2.fromNullable(outputSchema),
|
|
394
|
-
deprecated: operation.deprecated === true
|
|
395
|
-
})
|
|
396
|
-
);
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
return new ExtractionResult({
|
|
400
|
-
title: Option2.fromNullable(doc.info?.title),
|
|
401
|
-
version: Option2.fromNullable(doc.info?.version),
|
|
402
|
-
servers: extractServers(doc),
|
|
403
|
-
operations
|
|
404
|
-
});
|
|
405
|
-
});
|
|
406
|
-
|
|
407
|
-
// src/sdk/invoke.ts
|
|
408
|
-
import { Effect as Effect3, Layer, Option as Option3 } from "effect";
|
|
409
|
-
import { HttpClient, HttpClientRequest } from "@effect/platform";
|
|
410
|
-
import {
|
|
411
|
-
ToolInvocationResult,
|
|
412
|
-
ToolInvocationError
|
|
413
|
-
} from "@executor-js/sdk";
|
|
414
|
-
var CONTAINER_KEYS = {
|
|
415
|
-
path: ["path", "pathParams", "params"],
|
|
416
|
-
query: ["query", "queryParams", "params"],
|
|
417
|
-
header: ["headers", "header"],
|
|
418
|
-
cookie: ["cookies", "cookie"]
|
|
419
|
-
};
|
|
420
|
-
var readParamValue = (args, param) => {
|
|
421
|
-
const direct = args[param.name];
|
|
422
|
-
if (direct !== void 0) return direct;
|
|
423
|
-
for (const key of CONTAINER_KEYS[param.location] ?? []) {
|
|
424
|
-
const container = args[key];
|
|
425
|
-
if (typeof container === "object" && container !== null && !Array.isArray(container)) {
|
|
426
|
-
const nested = container[param.name];
|
|
427
|
-
if (nested !== void 0) return nested;
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
return void 0;
|
|
431
|
-
};
|
|
432
|
-
var resolvePath = Effect3.fn("OpenApi.resolvePath")(function* (pathTemplate, args, parameters) {
|
|
433
|
-
let resolved = pathTemplate;
|
|
434
|
-
for (const param of parameters) {
|
|
435
|
-
if (param.location !== "path") continue;
|
|
436
|
-
const value = readParamValue(args, param);
|
|
437
|
-
if (value === void 0 || value === null) {
|
|
438
|
-
if (param.required) {
|
|
439
|
-
return yield* new OpenApiInvocationError({
|
|
440
|
-
message: `Missing required path parameter: ${param.name}`,
|
|
441
|
-
statusCode: Option3.none()
|
|
442
|
-
});
|
|
443
|
-
}
|
|
444
|
-
continue;
|
|
445
|
-
}
|
|
446
|
-
resolved = resolved.replaceAll(`{${param.name}}`, encodeURIComponent(String(value)));
|
|
447
|
-
}
|
|
448
|
-
const remaining = [...resolved.matchAll(/\{([^{}]+)\}/g)].map((m) => m[1]).filter((v) => typeof v === "string");
|
|
449
|
-
for (const name of remaining) {
|
|
450
|
-
const value = args[name];
|
|
451
|
-
if (value !== void 0 && value !== null) {
|
|
452
|
-
resolved = resolved.replaceAll(`{${name}}`, encodeURIComponent(String(value)));
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
const unresolved = [...resolved.matchAll(/\{([^{}]+)\}/g)].map((m) => m[1]).filter((v) => typeof v === "string");
|
|
456
|
-
if (unresolved.length > 0) {
|
|
457
|
-
return yield* new OpenApiInvocationError({
|
|
458
|
-
message: `Unresolved path parameters: ${[...new Set(unresolved)].join(", ")}`,
|
|
459
|
-
statusCode: Option3.none()
|
|
460
|
-
});
|
|
461
|
-
}
|
|
462
|
-
return resolved;
|
|
463
|
-
});
|
|
464
|
-
var resolveHeaders = (headers, secrets, scopeId) => Effect3.gen(function* () {
|
|
465
|
-
const resolved = {};
|
|
466
|
-
for (const [name, value] of Object.entries(headers)) {
|
|
467
|
-
if (typeof value === "string") {
|
|
468
|
-
resolved[name] = value;
|
|
469
|
-
} else {
|
|
470
|
-
const secret = yield* secrets.resolve(value.secretId, scopeId).pipe(
|
|
471
|
-
Effect3.mapError(
|
|
472
|
-
() => new ToolInvocationError({
|
|
473
|
-
toolId: "",
|
|
474
|
-
message: `Failed to resolve secret "${value.secretId}" for header "${name}"`,
|
|
475
|
-
cause: void 0
|
|
476
|
-
})
|
|
477
|
-
)
|
|
478
|
-
);
|
|
479
|
-
resolved[name] = value.prefix ? `${value.prefix}${secret}` : secret;
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
return resolved;
|
|
483
|
-
});
|
|
484
|
-
var applyHeaders = (request, headers) => {
|
|
485
|
-
let req = request;
|
|
486
|
-
for (const [name, value] of Object.entries(headers)) {
|
|
487
|
-
req = HttpClientRequest.setHeader(req, name, value);
|
|
488
|
-
}
|
|
489
|
-
return req;
|
|
490
|
-
};
|
|
491
|
-
var isJsonContentType = (ct) => {
|
|
492
|
-
if (!ct) return false;
|
|
493
|
-
const normalized = ct.split(";")[0]?.trim().toLowerCase() ?? "";
|
|
494
|
-
return normalized === "application/json" || normalized.includes("+json") || normalized.includes("json");
|
|
495
|
-
};
|
|
496
|
-
var invoke = Effect3.fn("OpenApi.invoke")(function* (operation, args, config, resolvedHeaders) {
|
|
497
|
-
const client = yield* HttpClient.HttpClient;
|
|
498
|
-
const resolvedPath = yield* resolvePath(operation.pathTemplate, args, operation.parameters);
|
|
499
|
-
const path = resolvedPath.startsWith("/") ? resolvedPath : `/${resolvedPath}`;
|
|
500
|
-
let request = HttpClientRequest.make(operation.method.toUpperCase())(path);
|
|
501
|
-
for (const param of operation.parameters) {
|
|
502
|
-
if (param.location !== "query") continue;
|
|
503
|
-
const value = readParamValue(args, param);
|
|
504
|
-
if (value === void 0 || value === null) continue;
|
|
505
|
-
request = HttpClientRequest.setUrlParam(request, param.name, String(value));
|
|
506
|
-
}
|
|
507
|
-
for (const param of operation.parameters) {
|
|
508
|
-
if (param.location !== "header") continue;
|
|
509
|
-
const value = readParamValue(args, param);
|
|
510
|
-
if (value === void 0 || value === null) continue;
|
|
511
|
-
request = HttpClientRequest.setHeader(request, param.name, String(value));
|
|
512
|
-
}
|
|
513
|
-
if (Option3.isSome(operation.requestBody)) {
|
|
514
|
-
const rb = operation.requestBody.value;
|
|
515
|
-
const bodyValue = args.body ?? args.input;
|
|
516
|
-
if (bodyValue !== void 0) {
|
|
517
|
-
if (isJsonContentType(rb.contentType)) {
|
|
518
|
-
request = HttpClientRequest.bodyUnsafeJson(request, bodyValue);
|
|
519
|
-
} else {
|
|
520
|
-
request = HttpClientRequest.bodyText(request, String(bodyValue), rb.contentType);
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
request = applyHeaders(request, resolvedHeaders ?? {});
|
|
525
|
-
const response = yield* client.execute(request).pipe(
|
|
526
|
-
Effect3.mapError(
|
|
527
|
-
(err) => new OpenApiInvocationError({
|
|
528
|
-
message: `HTTP request failed: ${err.message}`,
|
|
529
|
-
statusCode: Option3.none(),
|
|
530
|
-
cause: err
|
|
531
|
-
})
|
|
532
|
-
)
|
|
533
|
-
);
|
|
534
|
-
const status = response.status;
|
|
535
|
-
const responseHeaders = { ...response.headers };
|
|
536
|
-
const contentType = response.headers["content-type"] ?? null;
|
|
537
|
-
const responseBody = status === 204 ? null : isJsonContentType(contentType) ? yield* response.json.pipe(Effect3.catchAll(() => response.text)) : yield* response.text;
|
|
538
|
-
const ok = status >= 200 && status < 300;
|
|
539
|
-
return new InvocationResult({
|
|
540
|
-
status,
|
|
541
|
-
headers: responseHeaders,
|
|
542
|
-
data: ok ? responseBody : null,
|
|
543
|
-
error: ok ? null : responseBody
|
|
544
|
-
});
|
|
545
|
-
});
|
|
546
|
-
var SAFE_METHODS = /* @__PURE__ */ new Set(["get", "head", "options"]);
|
|
547
|
-
var annotationsForOperation = (method, pathTemplate) => {
|
|
548
|
-
if (SAFE_METHODS.has(method.toLowerCase())) return {};
|
|
549
|
-
return {
|
|
550
|
-
requiresApproval: true,
|
|
551
|
-
approvalDescription: `${method.toUpperCase()} ${pathTemplate}`
|
|
552
|
-
};
|
|
553
|
-
};
|
|
554
|
-
var makeOpenApiInvoker = (opts) => ({
|
|
555
|
-
resolveAnnotations: (toolId) => Effect3.gen(function* () {
|
|
556
|
-
const entry = yield* opts.operationStore.get(toolId);
|
|
557
|
-
if (!entry) return void 0;
|
|
558
|
-
return annotationsForOperation(entry.binding.method, entry.binding.pathTemplate);
|
|
559
|
-
}),
|
|
560
|
-
invoke: (toolId, args) => Effect3.gen(function* () {
|
|
561
|
-
const entry = yield* opts.operationStore.get(toolId);
|
|
562
|
-
if (!entry) {
|
|
563
|
-
return yield* new ToolInvocationError({
|
|
564
|
-
toolId,
|
|
565
|
-
message: `No operation found for tool "${toolId}"`,
|
|
566
|
-
cause: void 0
|
|
567
|
-
});
|
|
568
|
-
}
|
|
569
|
-
const source = yield* opts.operationStore.getSource(entry.namespace);
|
|
570
|
-
if (!source) {
|
|
571
|
-
return yield* new ToolInvocationError({
|
|
572
|
-
toolId,
|
|
573
|
-
message: `No source found for namespace "${entry.namespace}"`,
|
|
574
|
-
cause: void 0
|
|
575
|
-
});
|
|
576
|
-
}
|
|
577
|
-
const { binding } = entry;
|
|
578
|
-
const { invocationConfig: config } = source;
|
|
579
|
-
const baseUrl = config.baseUrl;
|
|
580
|
-
const resolvedHeaders = yield* resolveHeaders(config.headers, opts.secrets, opts.scopeId);
|
|
581
|
-
const clientWithBaseUrl = baseUrl ? Layer.effect(
|
|
582
|
-
HttpClient.HttpClient,
|
|
583
|
-
Effect3.map(
|
|
584
|
-
HttpClient.HttpClient,
|
|
585
|
-
HttpClient.mapRequest(HttpClientRequest.prependUrl(baseUrl))
|
|
586
|
-
)
|
|
587
|
-
).pipe(Layer.provide(opts.httpClientLayer)) : opts.httpClientLayer;
|
|
588
|
-
const result = yield* invoke(
|
|
589
|
-
binding,
|
|
590
|
-
args ?? {},
|
|
591
|
-
config,
|
|
592
|
-
resolvedHeaders
|
|
593
|
-
).pipe(Effect3.provide(clientWithBaseUrl));
|
|
594
|
-
return new ToolInvocationResult({
|
|
595
|
-
data: result.data,
|
|
596
|
-
error: result.error,
|
|
597
|
-
status: result.status
|
|
598
|
-
});
|
|
599
|
-
}).pipe(
|
|
600
|
-
Effect3.catchAll((err) => {
|
|
601
|
-
if (typeof err === "object" && err !== null && "_tag" in err && err._tag === "ToolInvocationError") {
|
|
602
|
-
return Effect3.fail(err);
|
|
603
|
-
}
|
|
604
|
-
return Effect3.fail(
|
|
605
|
-
new ToolInvocationError({
|
|
606
|
-
toolId,
|
|
607
|
-
message: `OpenAPI invocation failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
608
|
-
cause: err
|
|
609
|
-
})
|
|
610
|
-
);
|
|
611
|
-
})
|
|
612
|
-
)
|
|
613
|
-
});
|
|
614
|
-
|
|
615
|
-
// src/sdk/kv-operation-store.ts
|
|
616
|
-
import { Effect as Effect4, Schema as Schema4 } from "effect";
|
|
617
|
-
import { scopeKv, makeInMemoryScopedKv } from "@executor-js/sdk";
|
|
618
|
-
|
|
619
|
-
// src/sdk/stored-source.ts
|
|
620
|
-
import { Schema as Schema3 } from "effect";
|
|
621
|
-
var StoredSourceSchema = class extends Schema3.Class("OpenApiStoredSource")({
|
|
622
|
-
namespace: Schema3.String,
|
|
623
|
-
name: Schema3.String,
|
|
624
|
-
config: Schema3.Struct({
|
|
625
|
-
spec: Schema3.String,
|
|
626
|
-
baseUrl: Schema3.optional(Schema3.String),
|
|
627
|
-
namespace: Schema3.optional(Schema3.String),
|
|
628
|
-
headers: Schema3.optional(Schema3.Record({ key: Schema3.String, value: HeaderValue }))
|
|
629
|
-
}),
|
|
630
|
-
// TODO(migration): make required once all rows have been migrated to
|
|
631
|
-
// carry invocationConfig. Left optional for decode compat with rows
|
|
632
|
-
// written before the source-level invocationConfig refactor.
|
|
633
|
-
invocationConfig: Schema3.optional(InvocationConfig)
|
|
634
|
-
}) {
|
|
635
|
-
};
|
|
636
|
-
|
|
637
|
-
// src/sdk/kv-operation-store.ts
|
|
638
|
-
var StoredEntry = class extends Schema4.Class("StoredEntry")({
|
|
639
|
-
namespace: Schema4.String,
|
|
640
|
-
binding: OperationBinding
|
|
641
|
-
}) {
|
|
642
|
-
};
|
|
643
|
-
var encodeEntry = Schema4.encodeSync(Schema4.parseJson(StoredEntry));
|
|
644
|
-
var decodeEntry = Schema4.decodeUnknownSync(Schema4.parseJson(StoredEntry));
|
|
645
|
-
var LegacyStoredEntry = class extends Schema4.Class("LegacyStoredEntry")({
|
|
646
|
-
namespace: Schema4.String,
|
|
647
|
-
binding: OperationBinding,
|
|
648
|
-
config: Schema4.optional(InvocationConfig)
|
|
649
|
-
}) {
|
|
650
|
-
};
|
|
651
|
-
var decodeLegacyEntry = Schema4.decodeUnknownSync(Schema4.parseJson(LegacyStoredEntry));
|
|
652
|
-
var encodeSource = Schema4.encodeSync(Schema4.parseJson(StoredSourceSchema));
|
|
653
|
-
var decodeSource = Schema4.decodeUnknownSync(Schema4.parseJson(StoredSourceSchema));
|
|
654
|
-
var makeStore = (bindings, sources) => {
|
|
655
|
-
const withKvTransaction = (kv, effect) => kv.withTransaction?.(effect) ?? effect;
|
|
656
|
-
const rehydrateInvocationConfig = (source) => Effect4.gen(function* () {
|
|
657
|
-
if (source.invocationConfig) return source;
|
|
658
|
-
let recovered = null;
|
|
659
|
-
const entries = yield* bindings.list();
|
|
660
|
-
for (const e of entries) {
|
|
661
|
-
const legacy = decodeLegacyEntry(e.value);
|
|
662
|
-
if (legacy.namespace === source.namespace && legacy.config) {
|
|
663
|
-
recovered = legacy.config;
|
|
664
|
-
break;
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
const invocationConfig = recovered ?? new InvocationConfig({
|
|
668
|
-
baseUrl: source.config.baseUrl ?? "",
|
|
669
|
-
headers: source.config.headers ?? {}
|
|
670
|
-
});
|
|
671
|
-
return { ...source, invocationConfig };
|
|
672
|
-
});
|
|
673
|
-
return {
|
|
674
|
-
get: (toolId) => Effect4.gen(function* () {
|
|
675
|
-
const raw = yield* bindings.get(toolId);
|
|
676
|
-
if (!raw) return null;
|
|
677
|
-
const entry = decodeEntry(raw);
|
|
678
|
-
return { binding: entry.binding, namespace: entry.namespace };
|
|
679
|
-
}),
|
|
680
|
-
put: (entries) => withKvTransaction(
|
|
681
|
-
bindings,
|
|
682
|
-
bindings.set(
|
|
683
|
-
entries.map(({ toolId, namespace, binding }) => ({
|
|
684
|
-
key: toolId,
|
|
685
|
-
value: encodeEntry(new StoredEntry({ namespace, binding }))
|
|
686
|
-
}))
|
|
687
|
-
)
|
|
688
|
-
),
|
|
689
|
-
remove: (toolId) => bindings.delete([toolId]).pipe(Effect4.asVoid),
|
|
690
|
-
listByNamespace: (namespace) => Effect4.gen(function* () {
|
|
691
|
-
const entries = yield* bindings.list();
|
|
692
|
-
const ids = [];
|
|
693
|
-
for (const e of entries) {
|
|
694
|
-
const entry = decodeEntry(e.value);
|
|
695
|
-
if (entry.namespace === namespace) ids.push(e.key);
|
|
696
|
-
}
|
|
697
|
-
return ids;
|
|
698
|
-
}),
|
|
699
|
-
removeByNamespace: (namespace) => Effect4.gen(function* () {
|
|
700
|
-
const entries = yield* bindings.list();
|
|
701
|
-
const ids = [];
|
|
702
|
-
for (const e of entries) {
|
|
703
|
-
const entry = decodeEntry(e.value);
|
|
704
|
-
if (entry.namespace === namespace) ids.push(e.key);
|
|
705
|
-
}
|
|
706
|
-
if (ids.length > 0) yield* bindings.delete(ids);
|
|
707
|
-
return ids;
|
|
708
|
-
}),
|
|
709
|
-
putSource: (source) => sources.set([{ key: source.namespace, value: encodeSource(source) }]),
|
|
710
|
-
removeSource: (namespace) => sources.delete([namespace]).pipe(Effect4.asVoid),
|
|
711
|
-
listSources: () => Effect4.gen(function* () {
|
|
712
|
-
const entries = yield* sources.list();
|
|
713
|
-
const out = [];
|
|
714
|
-
for (const e of entries) {
|
|
715
|
-
const raw = decodeSource(e.value);
|
|
716
|
-
out.push(
|
|
717
|
-
raw.invocationConfig ? raw : yield* rehydrateInvocationConfig(raw)
|
|
718
|
-
);
|
|
719
|
-
}
|
|
720
|
-
return out;
|
|
721
|
-
}),
|
|
722
|
-
getSource: (namespace) => Effect4.gen(function* () {
|
|
723
|
-
const raw = yield* sources.get(namespace);
|
|
724
|
-
if (!raw) return null;
|
|
725
|
-
const source = decodeSource(raw);
|
|
726
|
-
if (source.invocationConfig) return source;
|
|
727
|
-
const healed = yield* rehydrateInvocationConfig(source);
|
|
728
|
-
yield* sources.set([{ key: namespace, value: encodeSource(healed) }]);
|
|
729
|
-
return healed;
|
|
730
|
-
}),
|
|
731
|
-
getSourceConfig: (namespace) => Effect4.gen(function* () {
|
|
732
|
-
const raw = yield* sources.get(namespace);
|
|
733
|
-
if (!raw) return null;
|
|
734
|
-
const source = decodeSource(raw);
|
|
735
|
-
return source.config;
|
|
736
|
-
})
|
|
737
|
-
};
|
|
738
|
-
};
|
|
739
|
-
var makeKvOperationStore = (kv, namespace) => makeStore(scopeKv(kv, `${namespace}.bindings`), scopeKv(kv, `${namespace}.sources`));
|
|
740
|
-
var makeInMemoryOperationStore = () => makeStore(makeInMemoryScopedKv(), makeInMemoryScopedKv());
|
|
741
|
-
|
|
742
|
-
// src/sdk/preview.ts
|
|
743
|
-
import { Effect as Effect5, Option as Option4 } from "effect";
|
|
744
|
-
import { Schema as Schema5 } from "effect";
|
|
745
|
-
var SecurityScheme = class extends Schema5.Class("SecurityScheme")({
|
|
746
|
-
/** Key name in components.securitySchemes (e.g. "api_token") */
|
|
747
|
-
name: Schema5.String,
|
|
748
|
-
/** OpenAPI security scheme type */
|
|
749
|
-
type: Schema5.Literal("http", "apiKey", "oauth2", "openIdConnect"),
|
|
750
|
-
/** For type: "http" — e.g. "bearer", "basic" */
|
|
751
|
-
scheme: Schema5.optionalWith(Schema5.String, { as: "Option" }),
|
|
752
|
-
/** For type: "apiKey" — where the key goes */
|
|
753
|
-
in: Schema5.optionalWith(Schema5.Literal("header", "query", "cookie"), { as: "Option" }),
|
|
754
|
-
/** For type: "apiKey" — the header/query/cookie name */
|
|
755
|
-
headerName: Schema5.optionalWith(Schema5.String, { as: "Option" }),
|
|
756
|
-
description: Schema5.optionalWith(Schema5.String, { as: "Option" })
|
|
757
|
-
}) {
|
|
758
|
-
};
|
|
759
|
-
var AuthStrategy = class extends Schema5.Class("AuthStrategy")({
|
|
760
|
-
/** The security schemes required together for this strategy */
|
|
761
|
-
schemes: Schema5.Array(Schema5.String)
|
|
762
|
-
}) {
|
|
763
|
-
};
|
|
764
|
-
var HeaderPreset = class extends Schema5.Class("HeaderPreset")({
|
|
765
|
-
/** Human-readable label for the UI (e.g. "Bearer Token", "API Key + Email") */
|
|
766
|
-
label: Schema5.String,
|
|
767
|
-
/** Headers this strategy needs. Value is null when the user must provide it. */
|
|
768
|
-
headers: Schema5.Record({ key: Schema5.String, value: Schema5.NullOr(Schema5.String) }),
|
|
769
|
-
/** Which headers should be stored as secrets */
|
|
770
|
-
secretHeaders: Schema5.Array(Schema5.String)
|
|
771
|
-
}) {
|
|
772
|
-
};
|
|
773
|
-
var PreviewOperation = class extends Schema5.Class("PreviewOperation")({
|
|
774
|
-
operationId: Schema5.String,
|
|
775
|
-
method: HttpMethod,
|
|
776
|
-
path: Schema5.String,
|
|
777
|
-
summary: Schema5.optionalWith(Schema5.String, { as: "Option" }),
|
|
778
|
-
tags: Schema5.Array(Schema5.String),
|
|
779
|
-
deprecated: Schema5.Boolean
|
|
780
|
-
}) {
|
|
781
|
-
};
|
|
782
|
-
var SpecPreview = class extends Schema5.Class("SpecPreview")({
|
|
783
|
-
title: Schema5.optionalWith(Schema5.String, { as: "Option" }),
|
|
784
|
-
version: Schema5.optionalWith(Schema5.String, { as: "Option" }),
|
|
785
|
-
/** Reuses ServerInfo from extraction */
|
|
786
|
-
servers: Schema5.Array(Schema5.Unknown),
|
|
787
|
-
operationCount: Schema5.Number,
|
|
788
|
-
/** Lightweight operation list for the add-source UI */
|
|
789
|
-
operations: Schema5.Array(PreviewOperation),
|
|
790
|
-
tags: Schema5.Array(Schema5.String),
|
|
791
|
-
securitySchemes: Schema5.Array(SecurityScheme),
|
|
792
|
-
/** Valid auth strategies (each is a set of schemes used together) */
|
|
793
|
-
authStrategies: Schema5.Array(AuthStrategy),
|
|
794
|
-
/** Pre-built header presets derived from auth strategies */
|
|
795
|
-
headerPresets: Schema5.Array(HeaderPreset)
|
|
796
|
-
}) {
|
|
797
|
-
};
|
|
798
|
-
var extractSecuritySchemes = (rawSchemes) => Object.entries(rawSchemes).flatMap(([name, schemeOrRef]) => {
|
|
799
|
-
if (!schemeOrRef || typeof schemeOrRef !== "object") return [];
|
|
800
|
-
const scheme = schemeOrRef;
|
|
801
|
-
if ("$ref" in scheme) return [];
|
|
802
|
-
const type = scheme.type;
|
|
803
|
-
if (!["http", "apiKey", "oauth2", "openIdConnect"].includes(type)) return [];
|
|
804
|
-
return [
|
|
805
|
-
new SecurityScheme({
|
|
806
|
-
name,
|
|
807
|
-
type,
|
|
808
|
-
scheme: Option4.fromNullable(scheme.scheme),
|
|
809
|
-
in: Option4.fromNullable(scheme.in),
|
|
810
|
-
headerName: Option4.fromNullable(scheme.name),
|
|
811
|
-
description: Option4.fromNullable(scheme.description)
|
|
812
|
-
})
|
|
813
|
-
];
|
|
814
|
-
});
|
|
815
|
-
var buildHeaderPresets = (schemes, strategies) => {
|
|
816
|
-
const schemeMap = new Map(schemes.map((s) => [s.name, s]));
|
|
817
|
-
return strategies.flatMap((strategy) => {
|
|
818
|
-
const resolved = strategy.schemes.map((name) => schemeMap.get(name)).filter((s) => s !== void 0);
|
|
819
|
-
if (resolved.length === 0) return [];
|
|
820
|
-
const headers = {};
|
|
821
|
-
const secretHeaders = [];
|
|
822
|
-
const labelParts = [];
|
|
823
|
-
for (const scheme of resolved) {
|
|
824
|
-
if (scheme.type === "http" && Option4.getOrElse(scheme.scheme, () => "") === "bearer") {
|
|
825
|
-
headers["Authorization"] = null;
|
|
826
|
-
secretHeaders.push("Authorization");
|
|
827
|
-
labelParts.push("Bearer Token");
|
|
828
|
-
} else if (scheme.type === "http" && Option4.getOrElse(scheme.scheme, () => "") === "basic") {
|
|
829
|
-
headers["Authorization"] = null;
|
|
830
|
-
secretHeaders.push("Authorization");
|
|
831
|
-
labelParts.push("Basic Auth");
|
|
832
|
-
} else if (scheme.type === "apiKey" && Option4.getOrElse(scheme.in, () => "") === "header") {
|
|
833
|
-
const headerName = Option4.getOrElse(scheme.headerName, () => scheme.name);
|
|
834
|
-
headers[headerName] = null;
|
|
835
|
-
secretHeaders.push(headerName);
|
|
836
|
-
labelParts.push(scheme.name);
|
|
837
|
-
} else if (scheme.type === "apiKey") {
|
|
838
|
-
labelParts.push(`${scheme.name} (${Option4.getOrElse(scheme.in, () => "unknown")})`);
|
|
839
|
-
} else {
|
|
840
|
-
labelParts.push(scheme.name);
|
|
841
|
-
}
|
|
842
|
-
}
|
|
843
|
-
if (Object.keys(headers).length === 0 && resolved.length > 0) {
|
|
844
|
-
return [new HeaderPreset({ label: labelParts.join(" + "), headers: {}, secretHeaders: [] })];
|
|
845
|
-
}
|
|
846
|
-
return [new HeaderPreset({ label: labelParts.join(" + "), headers, secretHeaders })];
|
|
847
|
-
});
|
|
848
|
-
};
|
|
849
|
-
var collectTags = (result) => {
|
|
850
|
-
const tagSet = /* @__PURE__ */ new Set();
|
|
851
|
-
for (const op of result.operations) {
|
|
852
|
-
for (const tag of op.tags) tagSet.add(tag);
|
|
853
|
-
}
|
|
854
|
-
return [...tagSet].sort();
|
|
855
|
-
};
|
|
856
|
-
var previewSpec = Effect5.fn("OpenApi.previewSpec")(function* (specText) {
|
|
857
|
-
const doc = yield* parse(specText);
|
|
858
|
-
const result = yield* extract(doc);
|
|
859
|
-
const securitySchemes = extractSecuritySchemes(doc.components?.securitySchemes ?? {});
|
|
860
|
-
const rawSecurity = doc.security ?? [];
|
|
861
|
-
const authStrategies = rawSecurity.map(
|
|
862
|
-
(entry) => new AuthStrategy({ schemes: Object.keys(entry) })
|
|
863
|
-
);
|
|
864
|
-
return new SpecPreview({
|
|
865
|
-
title: result.title,
|
|
866
|
-
version: result.version,
|
|
867
|
-
servers: result.servers,
|
|
868
|
-
operationCount: result.operations.length,
|
|
869
|
-
operations: result.operations.map(
|
|
870
|
-
(op) => new PreviewOperation({
|
|
871
|
-
operationId: op.operationId,
|
|
872
|
-
method: op.method,
|
|
873
|
-
path: op.pathTemplate,
|
|
874
|
-
summary: op.summary,
|
|
875
|
-
tags: op.tags,
|
|
876
|
-
deprecated: op.deprecated
|
|
877
|
-
})
|
|
878
|
-
),
|
|
879
|
-
tags: collectTags(result),
|
|
880
|
-
securitySchemes,
|
|
881
|
-
authStrategies,
|
|
882
|
-
headerPresets: buildHeaderPresets(securitySchemes, authStrategies)
|
|
883
|
-
});
|
|
884
|
-
});
|
|
885
|
-
|
|
886
|
-
// src/sdk/plugin.ts
|
|
887
|
-
import { Effect as Effect6, Option as Option5, Schema as Schema6 } from "effect";
|
|
888
|
-
import { FetchHttpClient } from "@effect/platform";
|
|
889
|
-
import {
|
|
890
|
-
Source,
|
|
891
|
-
SourceDetectionResult,
|
|
892
|
-
definePlugin,
|
|
893
|
-
registerRuntimeTools,
|
|
894
|
-
runtimeTool,
|
|
895
|
-
ToolId
|
|
896
|
-
} from "@executor-js/sdk";
|
|
897
|
-
|
|
898
|
-
// src/sdk/definitions.ts
|
|
899
|
-
var splitWords = (value) => value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z0-9]+)/g, "$1 $2").replace(/[^a-zA-Z0-9]+/g, " ").trim().split(/\s+/).filter((part) => part.length > 0);
|
|
900
|
-
var normalizeWord = (value) => value.toLowerCase();
|
|
901
|
-
var toCamelCase = (value) => {
|
|
902
|
-
const words = splitWords(value).map(normalizeWord);
|
|
903
|
-
if (words.length === 0) return "tool";
|
|
904
|
-
const [first, ...rest] = words;
|
|
905
|
-
return `${first}${rest.map((p) => `${p[0]?.toUpperCase() ?? ""}${p.slice(1)}`).join("")}`;
|
|
906
|
-
};
|
|
907
|
-
var toPascalCase = (value) => {
|
|
908
|
-
const camel = toCamelCase(value);
|
|
909
|
-
return `${camel[0]?.toUpperCase() ?? ""}${camel.slice(1)}`;
|
|
910
|
-
};
|
|
911
|
-
var VERSION_SEGMENT_REGEX = /^v\d+(?:[._-]\d+)?$/i;
|
|
912
|
-
var IGNORED_PATH_SEGMENTS = /* @__PURE__ */ new Set(["api"]);
|
|
913
|
-
var pathSegmentsFromTemplate = (pathTemplate) => pathTemplate.split("/").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
914
|
-
var isPathParameterSegment = (segment) => segment.startsWith("{") && segment.endsWith("}");
|
|
915
|
-
var normalizeGroupSegment = (value) => {
|
|
916
|
-
const candidate = value?.trim();
|
|
917
|
-
if (!candidate) return null;
|
|
918
|
-
return toCamelCase(candidate);
|
|
919
|
-
};
|
|
920
|
-
var deriveVersionSegment = (pathTemplate) => pathSegmentsFromTemplate(pathTemplate).map((s) => s.toLowerCase()).find((s) => VERSION_SEGMENT_REGEX.test(s));
|
|
921
|
-
var derivePathGroup = (pathTemplate) => {
|
|
922
|
-
for (const segment of pathSegmentsFromTemplate(pathTemplate)) {
|
|
923
|
-
const lower = segment.toLowerCase();
|
|
924
|
-
if (VERSION_SEGMENT_REGEX.test(lower)) continue;
|
|
925
|
-
if (IGNORED_PATH_SEGMENTS.has(lower)) continue;
|
|
926
|
-
if (isPathParameterSegment(segment)) continue;
|
|
927
|
-
return normalizeGroupSegment(segment) ?? "root";
|
|
928
|
-
}
|
|
929
|
-
return "root";
|
|
930
|
-
};
|
|
931
|
-
var splitOperationIdSegments = (value) => value.split(/[/.]+/).map((s) => s.trim()).filter((s) => s.length > 0);
|
|
932
|
-
var deriveLeafSeed = (operationId, group) => {
|
|
933
|
-
const segments = splitOperationIdSegments(operationId);
|
|
934
|
-
if (segments.length > 1) {
|
|
935
|
-
const [first, ...rest] = segments;
|
|
936
|
-
if ((normalizeGroupSegment(first) ?? first) === group && rest.length > 0) {
|
|
937
|
-
return rest.join(" ");
|
|
938
|
-
}
|
|
939
|
-
}
|
|
940
|
-
return operationId;
|
|
941
|
-
};
|
|
942
|
-
var fallbackLeafSeed = (method, pathTemplate, group) => {
|
|
943
|
-
const relevantSegments = pathSegmentsFromTemplate(pathTemplate).filter((s) => !VERSION_SEGMENT_REGEX.test(s.toLowerCase())).filter((s) => !IGNORED_PATH_SEGMENTS.has(s.toLowerCase())).filter((s) => !isPathParameterSegment(s)).map((s) => normalizeGroupSegment(s) ?? s).filter((s) => s !== group);
|
|
944
|
-
const segmentSuffix = relevantSegments.map((s) => toPascalCase(s)).join("");
|
|
945
|
-
return `${method}${segmentSuffix || "Operation"}`;
|
|
946
|
-
};
|
|
947
|
-
var deriveLeaf = (operationId, method, pathTemplate, group) => {
|
|
948
|
-
const preferred = toCamelCase(deriveLeafSeed(operationId, group));
|
|
949
|
-
if (preferred.length > 0 && preferred !== group) return preferred;
|
|
950
|
-
return toCamelCase(fallbackLeafSeed(method, pathTemplate, group));
|
|
951
|
-
};
|
|
952
|
-
var resolveCollisions = (definitions) => {
|
|
953
|
-
const staged = definitions.map((d) => ({ ...d }));
|
|
954
|
-
const applyFactory = (items, factory) => {
|
|
955
|
-
const byPath = /* @__PURE__ */ new Map();
|
|
956
|
-
for (const item of items) {
|
|
957
|
-
const bucket = byPath.get(item.toolPath) ?? [];
|
|
958
|
-
bucket.push(item);
|
|
959
|
-
byPath.set(item.toolPath, bucket);
|
|
960
|
-
}
|
|
961
|
-
for (const bucket of byPath.values()) {
|
|
962
|
-
if (bucket.length < 2) continue;
|
|
963
|
-
for (const d of bucket) {
|
|
964
|
-
d.toolPath = factory(d);
|
|
965
|
-
}
|
|
966
|
-
}
|
|
967
|
-
};
|
|
968
|
-
applyFactory(
|
|
969
|
-
staged,
|
|
970
|
-
(d) => d.versionSegment ? `${d.group}.${d.versionSegment}.${d.leaf}` : d.toolPath
|
|
971
|
-
);
|
|
972
|
-
applyFactory(staged, (d) => {
|
|
973
|
-
const prefix = d.versionSegment ? `${d.group}.${d.versionSegment}` : d.group;
|
|
974
|
-
return `${prefix}.${d.leaf}${toPascalCase(d.method)}`;
|
|
975
|
-
});
|
|
976
|
-
applyFactory(staged, (d) => {
|
|
977
|
-
const prefix = d.versionSegment ? `${d.group}.${d.versionSegment}` : d.group;
|
|
978
|
-
return `${prefix}.${d.leaf}${toPascalCase(d.method)}${d.operationHash.slice(0, 8)}`;
|
|
979
|
-
});
|
|
980
|
-
return staged.map((d) => ({
|
|
981
|
-
toolPath: d.toolPath,
|
|
982
|
-
group: d.group,
|
|
983
|
-
leaf: d.leaf,
|
|
984
|
-
operationIndex: d.operationIndex,
|
|
985
|
-
operation: d.operation
|
|
986
|
-
}));
|
|
987
|
-
};
|
|
988
|
-
var stableHash = (value) => {
|
|
989
|
-
const str = JSON.stringify(value, Object.keys(value).sort());
|
|
990
|
-
let hash = 0;
|
|
991
|
-
for (let i = 0; i < str.length; i++) {
|
|
992
|
-
hash = (hash << 5) - hash + str.charCodeAt(i) | 0;
|
|
993
|
-
}
|
|
994
|
-
return Math.abs(hash).toString(36).padStart(8, "0");
|
|
995
|
-
};
|
|
996
|
-
var compileToolDefinitions = (operations) => {
|
|
997
|
-
const raw = operations.map((op, index) => {
|
|
998
|
-
const operationId = op.operationId;
|
|
999
|
-
const group = normalizeGroupSegment(op.tags[0]) ?? derivePathGroup(op.pathTemplate);
|
|
1000
|
-
const leaf = deriveLeaf(operationId, op.method, op.pathTemplate, group);
|
|
1001
|
-
const versionSegment = deriveVersionSegment(op.pathTemplate);
|
|
1002
|
-
const operationHash = stableHash({
|
|
1003
|
-
method: op.method,
|
|
1004
|
-
path: op.pathTemplate,
|
|
1005
|
-
operationId
|
|
1006
|
-
});
|
|
1007
|
-
return {
|
|
1008
|
-
toolPath: `${group}.${leaf}`,
|
|
1009
|
-
group,
|
|
1010
|
-
leaf,
|
|
1011
|
-
versionSegment,
|
|
1012
|
-
method: op.method,
|
|
1013
|
-
operationHash,
|
|
1014
|
-
operationIndex: index,
|
|
1015
|
-
operation: op
|
|
1016
|
-
};
|
|
1017
|
-
});
|
|
1018
|
-
return resolveCollisions(raw).sort((a, b) => a.toolPath.localeCompare(b.toolPath));
|
|
1019
|
-
};
|
|
1020
|
-
|
|
1021
|
-
// src/sdk/plugin.ts
|
|
1022
|
-
var PreviewSpecInputSchema = Schema6.Struct({
|
|
1023
|
-
spec: Schema6.String
|
|
1024
|
-
});
|
|
1025
|
-
var AddSourceInputSchema = Schema6.Struct({
|
|
1026
|
-
spec: Schema6.String,
|
|
1027
|
-
baseUrl: Schema6.optional(Schema6.String),
|
|
1028
|
-
namespace: Schema6.optional(Schema6.String),
|
|
1029
|
-
headers: Schema6.optional(Schema6.Record({ key: Schema6.String, value: HeaderValue }))
|
|
1030
|
-
});
|
|
1031
|
-
var AddSourceOutputSchema = Schema6.Struct({
|
|
1032
|
-
sourceId: Schema6.String,
|
|
1033
|
-
toolCount: Schema6.Number
|
|
1034
|
-
});
|
|
1035
|
-
var normalizeOpenApiRefs = (node) => {
|
|
1036
|
-
if (node == null || typeof node !== "object") return node;
|
|
1037
|
-
if (Array.isArray(node)) {
|
|
1038
|
-
let changed2 = false;
|
|
1039
|
-
const out = node.map((item) => {
|
|
1040
|
-
const n = normalizeOpenApiRefs(item);
|
|
1041
|
-
if (n !== item) changed2 = true;
|
|
1042
|
-
return n;
|
|
1043
|
-
});
|
|
1044
|
-
return changed2 ? out : node;
|
|
1045
|
-
}
|
|
1046
|
-
const obj = node;
|
|
1047
|
-
if (typeof obj.$ref === "string") {
|
|
1048
|
-
const match = obj.$ref.match(/^#\/components\/schemas\/(.+)$/);
|
|
1049
|
-
if (match) return { ...obj, $ref: `#/$defs/${match[1]}` };
|
|
1050
|
-
return obj;
|
|
1051
|
-
}
|
|
1052
|
-
let changed = false;
|
|
1053
|
-
const result = {};
|
|
1054
|
-
for (const [k, v] of Object.entries(obj)) {
|
|
1055
|
-
const n = normalizeOpenApiRefs(v);
|
|
1056
|
-
if (n !== v) changed = true;
|
|
1057
|
-
result[k] = n;
|
|
1058
|
-
}
|
|
1059
|
-
return changed ? result : obj;
|
|
1060
|
-
};
|
|
1061
|
-
var toRegistration = (def, namespace) => {
|
|
1062
|
-
const op = def.operation;
|
|
1063
|
-
const description = Option5.getOrElse(
|
|
1064
|
-
op.description,
|
|
1065
|
-
() => Option5.getOrElse(op.summary, () => `${op.method.toUpperCase()} ${op.pathTemplate}`)
|
|
1066
|
-
);
|
|
1067
|
-
return {
|
|
1068
|
-
id: ToolId.make(`${namespace}.${def.toolPath}`),
|
|
1069
|
-
pluginKey: "openapi",
|
|
1070
|
-
sourceId: namespace,
|
|
1071
|
-
name: def.toolPath,
|
|
1072
|
-
description,
|
|
1073
|
-
inputSchema: normalizeOpenApiRefs(Option5.getOrUndefined(op.inputSchema)),
|
|
1074
|
-
outputSchema: normalizeOpenApiRefs(Option5.getOrUndefined(op.outputSchema))
|
|
1075
|
-
};
|
|
1076
|
-
};
|
|
1077
|
-
var toBinding = (def) => new OperationBinding({
|
|
1078
|
-
method: def.operation.method,
|
|
1079
|
-
pathTemplate: def.operation.pathTemplate,
|
|
1080
|
-
parameters: [...def.operation.parameters],
|
|
1081
|
-
requestBody: def.operation.requestBody
|
|
1082
|
-
});
|
|
1083
|
-
var openApiPlugin = (options) => {
|
|
1084
|
-
const httpClientLayer = options?.httpClientLayer ?? FetchHttpClient.layer;
|
|
1085
|
-
const operationStore = options?.operationStore ?? makeInMemoryOperationStore();
|
|
1086
|
-
return definePlugin({
|
|
1087
|
-
key: "openapi",
|
|
1088
|
-
init: (ctx) => Effect6.gen(function* () {
|
|
1089
|
-
yield* ctx.tools.registerInvoker(
|
|
1090
|
-
"openapi",
|
|
1091
|
-
makeOpenApiInvoker({
|
|
1092
|
-
operationStore,
|
|
1093
|
-
httpClientLayer,
|
|
1094
|
-
secrets: ctx.secrets,
|
|
1095
|
-
scopeId: ctx.scope.id
|
|
1096
|
-
})
|
|
1097
|
-
);
|
|
1098
|
-
yield* ctx.sources.addManager({
|
|
1099
|
-
kind: "openapi",
|
|
1100
|
-
list: () => operationStore.listSources().pipe(
|
|
1101
|
-
Effect6.map(
|
|
1102
|
-
(metas) => metas.map(
|
|
1103
|
-
(s) => new Source({
|
|
1104
|
-
id: s.namespace,
|
|
1105
|
-
name: s.name,
|
|
1106
|
-
kind: "openapi",
|
|
1107
|
-
url: s.config.baseUrl,
|
|
1108
|
-
runtime: false,
|
|
1109
|
-
canRemove: true,
|
|
1110
|
-
canRefresh: false,
|
|
1111
|
-
canEdit: true
|
|
1112
|
-
})
|
|
1113
|
-
)
|
|
1114
|
-
)
|
|
1115
|
-
),
|
|
1116
|
-
remove: (sourceId) => Effect6.gen(function* () {
|
|
1117
|
-
yield* operationStore.removeByNamespace(sourceId);
|
|
1118
|
-
yield* operationStore.removeSource(sourceId);
|
|
1119
|
-
yield* ctx.tools.unregisterBySource(sourceId);
|
|
1120
|
-
}),
|
|
1121
|
-
detect: (url) => Effect6.gen(function* () {
|
|
1122
|
-
const trimmed = url.trim();
|
|
1123
|
-
if (!trimmed) return null;
|
|
1124
|
-
const parsed = yield* Effect6.try(() => new URL(trimmed)).pipe(Effect6.option);
|
|
1125
|
-
if (parsed._tag === "None") return null;
|
|
1126
|
-
const doc = yield* parse(trimmed).pipe(Effect6.catchAll(() => Effect6.succeed(null)));
|
|
1127
|
-
if (!doc) return null;
|
|
1128
|
-
const result = yield* extract(doc).pipe(Effect6.catchAll(() => Effect6.succeed(null)));
|
|
1129
|
-
if (!result) return null;
|
|
1130
|
-
const namespace = Option5.getOrElse(result.title, () => "api").toLowerCase().replace(/[^a-z0-9]+/g, "_");
|
|
1131
|
-
const name = Option5.getOrElse(result.title, () => namespace);
|
|
1132
|
-
return new SourceDetectionResult({
|
|
1133
|
-
kind: "openapi",
|
|
1134
|
-
confidence: "high",
|
|
1135
|
-
endpoint: trimmed,
|
|
1136
|
-
name,
|
|
1137
|
-
namespace
|
|
1138
|
-
});
|
|
1139
|
-
})
|
|
1140
|
-
});
|
|
1141
|
-
const addSpecInternal = (config) => Effect6.gen(function* () {
|
|
1142
|
-
const doc = yield* parse(config.spec);
|
|
1143
|
-
const result = yield* extract(doc);
|
|
1144
|
-
const namespace = config.namespace ?? Option5.getOrElse(result.title, () => "api").toLowerCase().replace(/[^a-z0-9]+/g, "_");
|
|
1145
|
-
if (doc.components?.schemas) {
|
|
1146
|
-
const defs = {};
|
|
1147
|
-
for (const [k, v] of Object.entries(doc.components.schemas)) {
|
|
1148
|
-
defs[k] = normalizeOpenApiRefs(v);
|
|
1149
|
-
}
|
|
1150
|
-
yield* ctx.tools.registerDefinitions(defs);
|
|
1151
|
-
}
|
|
1152
|
-
const baseUrl = config.baseUrl ?? resolveBaseUrl(result.servers);
|
|
1153
|
-
const invocationConfig = new InvocationConfig({
|
|
1154
|
-
baseUrl,
|
|
1155
|
-
headers: config.headers ?? {}
|
|
1156
|
-
});
|
|
1157
|
-
const definitions = compileToolDefinitions(result.operations);
|
|
1158
|
-
const registrations = definitions.map((def) => toRegistration(def, namespace));
|
|
1159
|
-
yield* operationStore.put(
|
|
1160
|
-
definitions.map((def) => ({
|
|
1161
|
-
toolId: ToolId.make(`${namespace}.${def.toolPath}`),
|
|
1162
|
-
namespace,
|
|
1163
|
-
binding: toBinding(def)
|
|
1164
|
-
}))
|
|
1165
|
-
);
|
|
1166
|
-
yield* ctx.tools.register(registrations);
|
|
1167
|
-
const sourceName = config.name ?? Option5.getOrElse(result.title, () => namespace);
|
|
1168
|
-
yield* operationStore.putSource({
|
|
1169
|
-
namespace,
|
|
1170
|
-
name: sourceName,
|
|
1171
|
-
config: {
|
|
1172
|
-
spec: config.spec,
|
|
1173
|
-
baseUrl: config.baseUrl,
|
|
1174
|
-
namespace: config.namespace,
|
|
1175
|
-
headers: config.headers
|
|
1176
|
-
},
|
|
1177
|
-
invocationConfig
|
|
1178
|
-
});
|
|
1179
|
-
return { sourceId: namespace, toolCount: registrations.length };
|
|
1180
|
-
});
|
|
1181
|
-
const runtimeTools = yield* registerRuntimeTools({
|
|
1182
|
-
registry: ctx.tools,
|
|
1183
|
-
sources: ctx.sources,
|
|
1184
|
-
pluginKey: "openapi",
|
|
1185
|
-
source: {
|
|
1186
|
-
id: "built-in",
|
|
1187
|
-
name: "Built In",
|
|
1188
|
-
kind: "built-in"
|
|
1189
|
-
},
|
|
1190
|
-
tools: [
|
|
1191
|
-
runtimeTool({
|
|
1192
|
-
id: "openapi.previewSpec",
|
|
1193
|
-
name: "openapi.previewSpec",
|
|
1194
|
-
description: "Preview an OpenAPI document before adding it as a source",
|
|
1195
|
-
inputSchema: PreviewSpecInputSchema,
|
|
1196
|
-
outputSchema: SpecPreview,
|
|
1197
|
-
handler: ({ spec }) => previewSpec(spec)
|
|
1198
|
-
}),
|
|
1199
|
-
runtimeTool({
|
|
1200
|
-
id: "openapi.addSource",
|
|
1201
|
-
name: "openapi.addSource",
|
|
1202
|
-
description: "Add an OpenAPI source and register its operations as tools",
|
|
1203
|
-
inputSchema: AddSourceInputSchema,
|
|
1204
|
-
outputSchema: AddSourceOutputSchema,
|
|
1205
|
-
handler: (input) => addSpecInternal(input)
|
|
1206
|
-
})
|
|
1207
|
-
]
|
|
1208
|
-
});
|
|
1209
|
-
return {
|
|
1210
|
-
extension: {
|
|
1211
|
-
previewSpec: (specText) => previewSpec(specText),
|
|
1212
|
-
addSpec: (config) => addSpecInternal(config).pipe(Effect6.map(({ toolCount }) => ({ toolCount }))),
|
|
1213
|
-
removeSpec: (namespace) => Effect6.gen(function* () {
|
|
1214
|
-
const toolIds = yield* operationStore.removeByNamespace(namespace);
|
|
1215
|
-
if (toolIds.length > 0) {
|
|
1216
|
-
yield* ctx.tools.unregister(toolIds);
|
|
1217
|
-
}
|
|
1218
|
-
yield* operationStore.removeSource(namespace);
|
|
1219
|
-
}),
|
|
1220
|
-
getSource: (namespace) => operationStore.getSource(namespace),
|
|
1221
|
-
updateSource: (namespace, input) => Effect6.gen(function* () {
|
|
1222
|
-
const existing = yield* operationStore.getSource(namespace);
|
|
1223
|
-
if (!existing) return;
|
|
1224
|
-
const updatedConfig = {
|
|
1225
|
-
...existing.config,
|
|
1226
|
-
...input.baseUrl !== void 0 ? { baseUrl: input.baseUrl } : {},
|
|
1227
|
-
...input.headers !== void 0 ? { headers: input.headers } : {}
|
|
1228
|
-
};
|
|
1229
|
-
const newInvocationConfig = new InvocationConfig({
|
|
1230
|
-
baseUrl: updatedConfig.baseUrl ?? existing.invocationConfig.baseUrl,
|
|
1231
|
-
headers: updatedConfig.headers ?? {}
|
|
1232
|
-
});
|
|
1233
|
-
yield* operationStore.putSource({
|
|
1234
|
-
namespace,
|
|
1235
|
-
name: input.name?.trim() || existing.name,
|
|
1236
|
-
config: updatedConfig,
|
|
1237
|
-
invocationConfig: newInvocationConfig
|
|
1238
|
-
});
|
|
1239
|
-
})
|
|
1240
|
-
},
|
|
1241
|
-
close: () => runtimeTools.close()
|
|
1242
|
-
};
|
|
1243
|
-
})
|
|
1244
|
-
});
|
|
1245
|
-
};
|
|
1246
|
-
|
|
1247
|
-
export {
|
|
1248
|
-
OpenApiParseError,
|
|
1249
|
-
OpenApiExtractionError,
|
|
1250
|
-
OpenApiInvocationError,
|
|
1251
|
-
parse,
|
|
1252
|
-
DocResolver,
|
|
1253
|
-
resolveBaseUrl,
|
|
1254
|
-
preferredContent,
|
|
1255
|
-
OperationId,
|
|
1256
|
-
HttpMethod,
|
|
1257
|
-
ParameterLocation,
|
|
1258
|
-
OperationParameter,
|
|
1259
|
-
OperationRequestBody,
|
|
1260
|
-
ExtractedOperation,
|
|
1261
|
-
ServerInfo,
|
|
1262
|
-
ExtractionResult,
|
|
1263
|
-
OperationBinding,
|
|
1264
|
-
InvocationConfig,
|
|
1265
|
-
InvocationResult,
|
|
1266
|
-
extract,
|
|
1267
|
-
invoke,
|
|
1268
|
-
makeOpenApiInvoker,
|
|
1269
|
-
makeKvOperationStore,
|
|
1270
|
-
makeInMemoryOperationStore,
|
|
1271
|
-
SecurityScheme,
|
|
1272
|
-
AuthStrategy,
|
|
1273
|
-
HeaderPreset,
|
|
1274
|
-
PreviewOperation,
|
|
1275
|
-
SpecPreview,
|
|
1276
|
-
previewSpec,
|
|
1277
|
-
openApiPlugin
|
|
1278
|
-
};
|
|
1279
|
-
//# sourceMappingURL=chunk-KPGROAQO.js.map
|