@executor-js/plugin-openapi 1.4.33 → 1.5.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.
Files changed (81) hide show
  1. package/dist/AddOpenApiSource-7M52SRUX.js +893 -0
  2. package/dist/AddOpenApiSource-7M52SRUX.js.map +1 -0
  3. package/dist/EditOpenApiSource-WTAMRJUK.js +68 -0
  4. package/dist/EditOpenApiSource-WTAMRJUK.js.map +1 -0
  5. package/dist/OpenApiAccountsPanel-3VJJXNQF.js +112 -0
  6. package/dist/OpenApiAccountsPanel-3VJJXNQF.js.map +1 -0
  7. package/dist/api/group.d.ts +104 -225
  8. package/dist/api/index.d.ts +127 -271
  9. package/dist/{chunk-BB5IAKRG.js → chunk-AQ7JDDRM.js} +12 -2
  10. package/dist/chunk-AQ7JDDRM.js.map +1 -0
  11. package/dist/chunk-BSLE6HCE.js +181 -0
  12. package/dist/chunk-BSLE6HCE.js.map +1 -0
  13. package/dist/chunk-MZWZQ24W.js +226 -0
  14. package/dist/chunk-MZWZQ24W.js.map +1 -0
  15. package/dist/chunk-OSIFYIQP.js +623 -0
  16. package/dist/chunk-OSIFYIQP.js.map +1 -0
  17. package/dist/chunk-QSSRVK6M.js +139 -0
  18. package/dist/chunk-QSSRVK6M.js.map +1 -0
  19. package/dist/chunk-V7VCHYOY.js +1544 -0
  20. package/dist/chunk-V7VCHYOY.js.map +1 -0
  21. package/dist/{chunk-AN4HJFNP.js → chunk-YVRI7KRC.js} +162 -186
  22. package/dist/chunk-YVRI7KRC.js.map +1 -0
  23. package/dist/client.js +9 -8
  24. package/dist/client.js.map +1 -1
  25. package/dist/core.js +28 -11
  26. package/dist/index.js +11 -4
  27. package/dist/react/AddOpenApiSource.d.ts +2 -13
  28. package/dist/react/GoogleProductPicker.d.ts +9 -0
  29. package/dist/react/OpenApiAccountsPanel.d.ts +6 -0
  30. package/dist/react/OpenApiSourceDetailsFields.d.ts +3 -2
  31. package/dist/react/atoms.d.ts +177 -192
  32. package/dist/react/auth-method-config.d.ts +15 -0
  33. package/dist/react/client.d.ts +103 -224
  34. package/dist/react/index.d.ts +2 -2
  35. package/dist/react/source-plugin.d.ts +2 -2
  36. package/dist/sdk/config.d.ts +75 -0
  37. package/dist/sdk/configure.test.d.ts +1 -0
  38. package/dist/sdk/describe-auth-methods.test.d.ts +1 -0
  39. package/dist/sdk/errors.d.ts +4 -6
  40. package/dist/sdk/extract.d.ts +7 -5
  41. package/dist/sdk/google-bundle.test.d.ts +1 -0
  42. package/dist/sdk/google-discovery.d.ts +43 -0
  43. package/dist/sdk/google-discovery.test.d.ts +1 -0
  44. package/dist/sdk/google-oauth-batches.d.ts +13 -0
  45. package/dist/sdk/google-oauth-batches.test.d.ts +1 -0
  46. package/dist/sdk/google-oauth-scopes.d.ts +3 -0
  47. package/dist/sdk/google-oauth-scopes.test.d.ts +1 -0
  48. package/dist/sdk/google-presets.d.ts +16 -0
  49. package/dist/sdk/google-presets.test.d.ts +1 -0
  50. package/dist/sdk/google-product-picker-scopes.test.d.ts +1 -0
  51. package/dist/sdk/index.d.ts +7 -5
  52. package/dist/sdk/invoke.d.ts +6 -9
  53. package/dist/sdk/openapi-utils.d.ts +1 -0
  54. package/dist/sdk/plugin.d.ts +74 -231
  55. package/dist/sdk/presets.d.ts +2 -1
  56. package/dist/sdk/preview.d.ts +20 -15
  57. package/dist/sdk/query-serialization.test.d.ts +1 -0
  58. package/dist/sdk/store.d.ts +14 -41
  59. package/dist/sdk/types.d.ts +23 -51
  60. package/dist/testing/index.d.ts +49 -38
  61. package/dist/testing.js +46 -18
  62. package/dist/testing.js.map +1 -1
  63. package/package.json +6 -4
  64. package/dist/AddOpenApiSource-NSCULGTM.js +0 -19
  65. package/dist/AddOpenApiSource-NSCULGTM.js.map +0 -1
  66. package/dist/EditOpenApiSource-MV7NYTRP.js +0 -774
  67. package/dist/EditOpenApiSource-MV7NYTRP.js.map +0 -1
  68. package/dist/OpenApiSourceSummary-7JBS7PUV.js +0 -122
  69. package/dist/OpenApiSourceSummary-7JBS7PUV.js.map +0 -1
  70. package/dist/chunk-2ZKKZYZH.js +0 -1181
  71. package/dist/chunk-2ZKKZYZH.js.map +0 -1
  72. package/dist/chunk-AN4HJFNP.js.map +0 -1
  73. package/dist/chunk-BB5IAKRG.js.map +0 -1
  74. package/dist/chunk-PRVJDE43.js +0 -2101
  75. package/dist/chunk-PRVJDE43.js.map +0 -1
  76. package/dist/chunk-X5JX3KTA.js +0 -201
  77. package/dist/chunk-X5JX3KTA.js.map +0 -1
  78. package/dist/react/OpenApiSourceSummary.d.ts +0 -5
  79. package/dist/sdk/credential-status.d.ts +0 -23
  80. package/dist/sdk/source-contracts.d.ts +0 -55
  81. /package/dist/{sdk/credential-status.test.d.ts → react/auth-method-config.test.d.ts} +0 -0
@@ -1,2101 +0,0 @@
1
- import {
2
- openApiPresets
3
- } from "./chunk-BB5IAKRG.js";
4
- import {
5
- ConfiguredHeaderBinding,
6
- HeaderValue,
7
- InvocationResult,
8
- OAuth2SourceConfig,
9
- OpenApiAuthRequiredError,
10
- OpenApiExtractionError,
11
- OpenApiInvocationError,
12
- OpenApiOAuthError,
13
- OperationBinding,
14
- extract,
15
- parse,
16
- previewSpec,
17
- resolveSpecText
18
- } from "./chunk-AN4HJFNP.js";
19
-
20
- // src/sdk/invoke.ts
21
- import { Effect, Layer, Option } from "effect";
22
- import { HttpClient, HttpClientRequest } from "effect/unstable/http";
23
- var CONTAINER_KEYS = {
24
- path: ["path", "pathParams", "params"],
25
- query: ["query", "queryParams", "params"],
26
- header: ["headers", "header"],
27
- cookie: ["cookies", "cookie"]
28
- };
29
- var readParamValue = (args, param) => {
30
- const direct = args[param.name];
31
- if (direct !== void 0) return direct;
32
- for (const key of CONTAINER_KEYS[param.location] ?? []) {
33
- const container = args[key];
34
- if (typeof container === "object" && container !== null && !Array.isArray(container)) {
35
- const nested = container[param.name];
36
- if (nested !== void 0) return nested;
37
- }
38
- }
39
- return void 0;
40
- };
41
- var resolvePath = Effect.fn("OpenApi.resolvePath")(function* (pathTemplate, args, parameters) {
42
- let resolved = pathTemplate;
43
- for (const param of parameters) {
44
- if (param.location !== "path") continue;
45
- const value = readParamValue(args, param);
46
- if (value === void 0 || value === null) {
47
- if (param.required) {
48
- return yield* new OpenApiInvocationError({
49
- message: `Missing required path parameter: ${param.name}`,
50
- statusCode: Option.none()
51
- });
52
- }
53
- continue;
54
- }
55
- resolved = resolved.replaceAll(`{${param.name}}`, encodeURIComponent(String(value)));
56
- }
57
- const remaining = [...resolved.matchAll(/\{([^{}]+)\}/g)].map((m) => m[1]).filter((v) => typeof v === "string");
58
- for (const name of remaining) {
59
- const value = args[name];
60
- if (value !== void 0 && value !== null) {
61
- resolved = resolved.replaceAll(`{${name}}`, encodeURIComponent(String(value)));
62
- }
63
- }
64
- const unresolved = [...resolved.matchAll(/\{([^{}]+)\}/g)].map((m) => m[1]).filter((v) => typeof v === "string");
65
- if (unresolved.length > 0) {
66
- return yield* new OpenApiInvocationError({
67
- message: `Unresolved path parameters: ${[...new Set(unresolved)].join(", ")}`,
68
- statusCode: Option.none()
69
- });
70
- }
71
- return resolved;
72
- });
73
- var resolveHeaders = (headers, secrets) => {
74
- const entries = Object.entries(headers);
75
- const secretCount = entries.reduce(
76
- (acc, [, value]) => typeof value === "string" ? acc : acc + 1,
77
- 0
78
- );
79
- return Effect.gen(function* () {
80
- const values = yield* Effect.all(
81
- entries.map(
82
- ([name, value]) => typeof value === "string" ? Effect.succeed({ name, value }) : secrets.get(value.secretId).pipe(
83
- Effect.catchTag(
84
- "SecretOwnedByConnectionError",
85
- () => Effect.fail(
86
- new OpenApiInvocationError({
87
- message: `Failed to resolve secret "${value.secretId}" for header "${name}"`,
88
- statusCode: Option.none()
89
- })
90
- )
91
- ),
92
- Effect.flatMap(
93
- (secret) => secret === null ? Effect.fail(
94
- new OpenApiInvocationError({
95
- message: `Failed to resolve secret "${value.secretId}" for header "${name}"`,
96
- statusCode: Option.none()
97
- })
98
- ) : Effect.succeed({
99
- name,
100
- value: value.prefix ? `${value.prefix}${secret}` : secret
101
- })
102
- )
103
- )
104
- ),
105
- { concurrency: "unbounded" }
106
- );
107
- const resolved = {};
108
- for (const { name, value } of values) resolved[name] = value;
109
- return resolved;
110
- }).pipe(
111
- Effect.withSpan("plugin.openapi.secret.resolve", {
112
- attributes: {
113
- "plugin.openapi.headers.total": entries.length,
114
- "plugin.openapi.headers.secret_count": secretCount
115
- }
116
- })
117
- );
118
- };
119
- var applyHeaders = (request, headers) => {
120
- let req = request;
121
- for (const [name, value] of Object.entries(headers)) {
122
- req = HttpClientRequest.setHeader(req, name, value);
123
- }
124
- return req;
125
- };
126
- var normalizeContentType = (ct) => ct?.split(";")[0]?.trim().toLowerCase() ?? "";
127
- var isJsonContentType = (ct) => {
128
- const normalized = normalizeContentType(ct);
129
- if (!normalized) return false;
130
- return normalized === "application/json" || normalized.includes("+json") || normalized.includes("json");
131
- };
132
- var isFormUrlEncoded = (ct) => normalizeContentType(ct) === "application/x-www-form-urlencoded";
133
- var isMultipartFormData = (ct) => normalizeContentType(ct).startsWith("multipart/form-data");
134
- var isXmlContentType = (ct) => {
135
- const normalized = normalizeContentType(ct);
136
- if (!normalized) return false;
137
- return normalized === "application/xml" || normalized === "text/xml" || normalized.endsWith("+xml");
138
- };
139
- var isTextContentType = (ct) => normalizeContentType(ct).startsWith("text/");
140
- var isOctetStream = (ct) => normalizeContentType(ct) === "application/octet-stream";
141
- var toUint8Array = (value) => {
142
- if (value instanceof Uint8Array) return value;
143
- if (value instanceof ArrayBuffer) return new Uint8Array(value);
144
- if (ArrayBuffer.isView(value)) {
145
- const view = value;
146
- return new Uint8Array(view.buffer, view.byteOffset, view.byteLength);
147
- }
148
- if (Array.isArray(value) && value.every((v) => typeof v === "number")) {
149
- return new Uint8Array(value);
150
- }
151
- return null;
152
- };
153
- var toArrayBuffer = (bytes) => {
154
- const copy = new ArrayBuffer(bytes.byteLength);
155
- new Uint8Array(copy).set(bytes);
156
- return copy;
157
- };
158
- var DEFAULT_FORM_STYLE = {
159
- style: "form",
160
- explode: true,
161
- allowReserved: false
162
- };
163
- var resolveStyleExplode = (e) => {
164
- if (!e) return DEFAULT_FORM_STYLE;
165
- return {
166
- style: Option.getOrElse(e.style, () => DEFAULT_FORM_STYLE.style),
167
- explode: Option.getOrElse(e.explode, () => DEFAULT_FORM_STYLE.explode),
168
- allowReserved: Option.getOrElse(e.allowReserved, () => DEFAULT_FORM_STYLE.allowReserved)
169
- };
170
- };
171
- var RESERVED_UNENCODED_RE = /[A-Za-z0-9\-._~:/?#[\]@!$&'()*+,;=]/;
172
- var encodeFormValue = (v, allowReserved) => {
173
- const raw = typeof v === "object" && v !== null ? JSON.stringify(v) : String(v);
174
- if (!allowReserved) return encodeURIComponent(raw);
175
- let out = "";
176
- for (const ch of raw) {
177
- out += RESERVED_UNENCODED_RE.test(ch) ? ch : encodeURIComponent(ch);
178
- }
179
- return out;
180
- };
181
- var serializeFormUrlEncoded = (value, encoding) => {
182
- const parts = [];
183
- for (const [key, raw] of Object.entries(value)) {
184
- if (raw === void 0 || raw === null) continue;
185
- const { style, explode, allowReserved } = resolveStyleExplode(encoding?.[key]);
186
- const encKey = encodeURIComponent(key);
187
- if (Array.isArray(raw)) {
188
- if (explode) {
189
- for (const v of raw) {
190
- parts.push(`${encKey}=${encodeFormValue(v, allowReserved)}`);
191
- }
192
- } else {
193
- const sep = style === "spaceDelimited" ? " " : style === "pipeDelimited" ? "|" : ",";
194
- parts.push(
195
- `${encKey}=${encodeFormValue(
196
- raw.map((v) => typeof v === "object" ? JSON.stringify(v) : String(v)).join(sep),
197
- allowReserved
198
- )}`
199
- );
200
- }
201
- continue;
202
- }
203
- if (typeof raw === "object") {
204
- const entries = Object.entries(raw).filter(
205
- ([, v]) => v !== void 0 && v !== null
206
- );
207
- if (style === "deepObject") {
208
- for (const [subkey, subval] of entries) {
209
- parts.push(
210
- `${encodeURIComponent(`${key}[${subkey}]`)}=${encodeFormValue(subval, allowReserved)}`
211
- );
212
- }
213
- } else if (explode) {
214
- for (const [subkey, subval] of entries) {
215
- parts.push(`${encodeURIComponent(subkey)}=${encodeFormValue(subval, allowReserved)}`);
216
- }
217
- } else {
218
- const flat = entries.flatMap(([k, v]) => [
219
- k,
220
- typeof v === "object" ? JSON.stringify(v) : String(v)
221
- ]);
222
- parts.push(`${encKey}=${encodeFormValue(flat.join(","), allowReserved)}`);
223
- }
224
- continue;
225
- }
226
- parts.push(`${encKey}=${encodeFormValue(raw, allowReserved)}`);
227
- }
228
- return parts.join("&");
229
- };
230
- var coerceFormDataRecord = (value, encoding) => {
231
- const out = {};
232
- for (const [key, raw] of Object.entries(value)) {
233
- if (raw === void 0 || raw === null) continue;
234
- const partType = encoding?.[key] ? Option.getOrUndefined(encoding[key].contentType) : void 0;
235
- if (partType) {
236
- const isJson = partType.startsWith("application/json") || partType.includes("+json");
237
- const serialized = typeof raw === "string" ? raw : isJson ? JSON.stringify(raw) : typeof raw === "object" ? JSON.stringify(raw) : String(raw);
238
- out[key] = new Blob([serialized], { type: partType });
239
- continue;
240
- }
241
- if (typeof raw === "string" || typeof raw === "number" || typeof raw === "boolean" || raw instanceof Blob || typeof File !== "undefined" && raw instanceof File) {
242
- out[key] = raw;
243
- continue;
244
- }
245
- if (Array.isArray(raw)) {
246
- out[key] = raw.map(
247
- (v) => typeof v === "string" || typeof v === "number" || typeof v === "boolean" || v instanceof Blob || typeof File !== "undefined" && v instanceof File ? v : JSON.stringify(v)
248
- );
249
- continue;
250
- }
251
- const bytes = toUint8Array(raw);
252
- if (bytes) {
253
- out[key] = new Blob([toArrayBuffer(bytes)]);
254
- continue;
255
- }
256
- out[key] = JSON.stringify(raw);
257
- }
258
- return out;
259
- };
260
- var applyRequestBody = (request, contentType, bodyValue, encoding) => {
261
- if (isJsonContentType(contentType)) {
262
- if (typeof bodyValue === "string") {
263
- return HttpClientRequest.bodyText(request, bodyValue, contentType);
264
- }
265
- return HttpClientRequest.bodyJsonUnsafe(request, bodyValue);
266
- }
267
- if (isFormUrlEncoded(contentType)) {
268
- if (typeof bodyValue === "string") {
269
- return HttpClientRequest.bodyText(request, bodyValue, contentType);
270
- }
271
- if (typeof bodyValue === "object" && bodyValue !== null && !Array.isArray(bodyValue)) {
272
- const serialized = serializeFormUrlEncoded(bodyValue, encoding);
273
- return HttpClientRequest.bodyText(request, serialized, contentType);
274
- }
275
- return HttpClientRequest.bodyUrlParams(
276
- request,
277
- bodyValue
278
- );
279
- }
280
- if (isMultipartFormData(contentType)) {
281
- if (bodyValue instanceof FormData) {
282
- return HttpClientRequest.bodyFormData(request, bodyValue);
283
- }
284
- if (typeof bodyValue === "object" && bodyValue !== null) {
285
- return HttpClientRequest.bodyFormDataRecord(
286
- request,
287
- coerceFormDataRecord(bodyValue, encoding)
288
- );
289
- }
290
- return HttpClientRequest.bodyText(request, String(bodyValue), contentType);
291
- }
292
- if (isOctetStream(contentType)) {
293
- const bytes2 = toUint8Array(bodyValue);
294
- if (bytes2) return HttpClientRequest.bodyUint8Array(request, bytes2, contentType);
295
- if (typeof bodyValue === "string") {
296
- return HttpClientRequest.bodyText(request, bodyValue, contentType);
297
- }
298
- return HttpClientRequest.bodyText(request, JSON.stringify(bodyValue), contentType);
299
- }
300
- if (isXmlContentType(contentType) || isTextContentType(contentType)) {
301
- if (typeof bodyValue === "string") {
302
- return HttpClientRequest.bodyText(request, bodyValue, contentType);
303
- }
304
- const bytes2 = toUint8Array(bodyValue);
305
- if (bytes2) return HttpClientRequest.bodyUint8Array(request, bytes2, contentType);
306
- return HttpClientRequest.bodyText(request, JSON.stringify(bodyValue), contentType);
307
- }
308
- if (typeof bodyValue === "string") {
309
- return HttpClientRequest.bodyText(request, bodyValue, contentType);
310
- }
311
- const bytes = toUint8Array(bodyValue);
312
- if (bytes) return HttpClientRequest.bodyUint8Array(request, bytes, contentType);
313
- return HttpClientRequest.bodyText(request, JSON.stringify(bodyValue), contentType);
314
- };
315
- var invoke = Effect.fn("OpenApi.invoke")(function* (operation, args, resolvedHeaders, sourceQueryParams = {}) {
316
- const client = yield* HttpClient.HttpClient;
317
- yield* Effect.annotateCurrentSpan({
318
- "http.method": operation.method.toUpperCase(),
319
- "http.route": operation.pathTemplate,
320
- "plugin.openapi.method": operation.method.toUpperCase(),
321
- "plugin.openapi.path_template": operation.pathTemplate,
322
- "plugin.openapi.headers.resolved_count": Object.keys(resolvedHeaders).length
323
- });
324
- const resolvedPath = yield* resolvePath(operation.pathTemplate, args, operation.parameters);
325
- const path = resolvedPath.startsWith("/") ? resolvedPath : `/${resolvedPath}`;
326
- let request = HttpClientRequest.make(operation.method.toUpperCase())(path);
327
- for (const [name, value] of Object.entries(sourceQueryParams)) {
328
- request = HttpClientRequest.setUrlParam(request, name, value);
329
- }
330
- for (const param of operation.parameters) {
331
- if (param.location !== "query") continue;
332
- const value = readParamValue(args, param);
333
- if (value === void 0 || value === null) continue;
334
- request = HttpClientRequest.setUrlParam(request, param.name, String(value));
335
- }
336
- for (const param of operation.parameters) {
337
- if (param.location !== "header") continue;
338
- const value = readParamValue(args, param);
339
- if (value === void 0 || value === null) continue;
340
- request = HttpClientRequest.setHeader(request, param.name, String(value));
341
- }
342
- if (Option.isSome(operation.requestBody)) {
343
- const rb = operation.requestBody.value;
344
- const bodyValue = args.body ?? args.input;
345
- if (bodyValue !== void 0) {
346
- const contentsOpt = Option.getOrUndefined(rb.contents);
347
- const requestedCt = typeof args.contentType === "string" ? args.contentType : void 0;
348
- const selected = contentsOpt && requestedCt ? contentsOpt.find((c) => c.contentType === requestedCt) : void 0;
349
- const chosenCt = selected?.contentType ?? rb.contentType;
350
- const chosenEncoding = selected ? Option.getOrUndefined(selected.encoding) : contentsOpt && contentsOpt[0] ? Option.getOrUndefined(contentsOpt[0].encoding) : void 0;
351
- request = applyRequestBody(request, chosenCt, bodyValue, chosenEncoding);
352
- }
353
- }
354
- request = applyHeaders(request, resolvedHeaders);
355
- const response = yield* client.execute(request).pipe(
356
- Effect.mapError(
357
- (err) => new OpenApiInvocationError({
358
- message: "HTTP request failed",
359
- statusCode: Option.none(),
360
- cause: err
361
- })
362
- )
363
- );
364
- const status = response.status;
365
- yield* Effect.annotateCurrentSpan({
366
- "http.status_code": status
367
- });
368
- const responseHeaders = { ...response.headers };
369
- const contentType = response.headers["content-type"] ?? null;
370
- const mapBodyError = Effect.mapError(
371
- (err) => new OpenApiInvocationError({
372
- message: "Failed to read response body",
373
- statusCode: Option.some(status),
374
- cause: err
375
- })
376
- );
377
- const responseBody = status === 204 ? null : isJsonContentType(contentType) ? yield* response.json.pipe(
378
- Effect.catch(() => response.text),
379
- mapBodyError
380
- ) : yield* response.text.pipe(mapBodyError);
381
- const ok = status >= 200 && status < 300;
382
- return InvocationResult.make({
383
- status,
384
- headers: responseHeaders,
385
- data: ok ? responseBody : null,
386
- error: ok ? null : responseBody
387
- });
388
- });
389
- var invokeWithLayer = (operation, args, baseUrl, resolvedHeaders, sourceQueryParams, httpClientLayer) => {
390
- const clientWithBaseUrl = baseUrl ? Layer.effect(
391
- HttpClient.HttpClient,
392
- Effect.map(
393
- Effect.service(HttpClient.HttpClient),
394
- HttpClient.mapRequest(HttpClientRequest.prependUrl(baseUrl))
395
- )
396
- ).pipe(Layer.provide(httpClientLayer)) : httpClientLayer;
397
- return invoke(operation, args, resolvedHeaders, sourceQueryParams).pipe(
398
- Effect.provide(clientWithBaseUrl),
399
- Effect.withSpan("plugin.openapi.invoke", {
400
- attributes: {
401
- "plugin.openapi.method": operation.method.toUpperCase(),
402
- "plugin.openapi.path_template": operation.pathTemplate,
403
- "plugin.openapi.base_url": baseUrl
404
- }
405
- })
406
- );
407
- };
408
- var REQUIRE_APPROVAL = /* @__PURE__ */ new Set(["post", "put", "patch", "delete"]);
409
- var annotationsForOperation = (method, pathTemplate) => {
410
- const m = method.toLowerCase();
411
- if (!REQUIRE_APPROVAL.has(m)) return {};
412
- return {
413
- requiresApproval: true,
414
- approvalDescription: `${method.toUpperCase()} ${pathTemplate}`
415
- };
416
- };
417
-
418
- // src/sdk/store.ts
419
- import { Effect as Effect2, Option as Option2, Predicate, Schema } from "effect";
420
- var openapiSchema = {};
421
- var SOURCE_COLLECTION = "source";
422
- var OPERATION_COLLECTION = "operation";
423
- var encodeBinding = Schema.encodeSync(OperationBinding);
424
- var decodeBinding = Schema.decodeUnknownSync(OperationBinding);
425
- var decodeBindingJson = Schema.decodeUnknownSync(Schema.fromJsonString(OperationBinding));
426
- var decodeOAuth2SourceConfigOption = Schema.decodeUnknownOption(OAuth2SourceConfig);
427
- var decodeOAuth2SourceConfigJsonOption = Schema.decodeUnknownOption(
428
- Schema.fromJsonString(OAuth2SourceConfig)
429
- );
430
- var encodeOAuth2SourceConfig = Schema.encodeSync(OAuth2SourceConfig);
431
- var NullableString = Schema.NullOr(Schema.String);
432
- var OptionalNullableString = Schema.optional(NullableString);
433
- var ConfiguredHeaderBindingStorage = Schema.Struct({
434
- kind: Schema.Literal("binding"),
435
- slot: Schema.String,
436
- prefix: OptionalNullableString
437
- });
438
- var ConfiguredHeaderValueStorage = Schema.Union([Schema.String, ConfiguredHeaderBindingStorage]);
439
- var ConfiguredHeaderMapStorage = Schema.Record(Schema.String, ConfiguredHeaderValueStorage);
440
- var SpecFetchCredentialsStorage = Schema.Struct({
441
- headers: Schema.optional(ConfiguredHeaderMapStorage),
442
- queryParams: Schema.optional(ConfiguredHeaderMapStorage)
443
- });
444
- var SourceConfigStorage = Schema.Struct({
445
- spec: Schema.String,
446
- sourceUrl: Schema.optional(Schema.String),
447
- baseUrl: Schema.optional(Schema.String),
448
- namespace: Schema.optional(Schema.String),
449
- headers: Schema.optional(ConfiguredHeaderMapStorage),
450
- queryParams: Schema.optional(ConfiguredHeaderMapStorage),
451
- specFetchCredentials: Schema.optional(SpecFetchCredentialsStorage),
452
- oauth2: Schema.optional(Schema.Unknown)
453
- });
454
- var SourceStorage = Schema.Struct({
455
- namespace: Schema.String,
456
- scope: Schema.String,
457
- name: Schema.String,
458
- config: SourceConfigStorage
459
- });
460
- var OperationStorage = Schema.Struct({
461
- toolId: Schema.String,
462
- sourceId: Schema.String,
463
- binding: Schema.Unknown
464
- });
465
- var decodeSourceStorage = Schema.decodeUnknownOption(SourceStorage);
466
- var decodeOperationStorage = Schema.decodeUnknownOption(OperationStorage);
467
- var toJsonRecord = (value) => value;
468
- var normalizeStoredOAuth2 = (value) => {
469
- if (value == null) return void 0;
470
- const sourceConfig = typeof value === "string" ? decodeOAuth2SourceConfigJsonOption(value) : decodeOAuth2SourceConfigOption(value);
471
- if (Option2.isSome(sourceConfig)) return sourceConfig.value;
472
- return void 0;
473
- };
474
- var normalizeConfiguredMap = (values) => {
475
- if (!values) return void 0;
476
- const normalized = {};
477
- for (const [name, value] of Object.entries(values)) {
478
- if (typeof value === "string") {
479
- normalized[name] = value;
480
- } else {
481
- normalized[name] = value.prefix != null ? ConfiguredHeaderBinding.make({
482
- kind: "binding",
483
- slot: value.slot,
484
- prefix: value.prefix
485
- }) : ConfiguredHeaderBinding.make({
486
- kind: "binding",
487
- slot: value.slot
488
- });
489
- }
490
- }
491
- return normalized;
492
- };
493
- var encodeSourceConfig = (config) => ({
494
- spec: config.spec,
495
- ...config.sourceUrl ? { sourceUrl: config.sourceUrl } : {},
496
- ...config.baseUrl ? { baseUrl: config.baseUrl } : {},
497
- ...config.namespace ? { namespace: config.namespace } : {},
498
- ...config.headers ? { headers: config.headers } : {},
499
- ...config.queryParams ? { queryParams: config.queryParams } : {},
500
- ...config.specFetchCredentials ? { specFetchCredentials: config.specFetchCredentials } : {},
501
- ...config.oauth2 ? { oauth2: toJsonRecord(encodeOAuth2SourceConfig(config.oauth2)) } : {}
502
- });
503
- var rowToSource = (row) => {
504
- const decoded = decodeSourceStorage(row.data);
505
- if (Option2.isNone(decoded)) return null;
506
- const stored = decoded.value;
507
- const oauth2 = normalizeStoredOAuth2(stored.config.oauth2);
508
- return {
509
- namespace: stored.namespace,
510
- scope: stored.scope,
511
- name: stored.name,
512
- config: {
513
- spec: stored.config.spec,
514
- sourceUrl: stored.config.sourceUrl,
515
- baseUrl: stored.config.baseUrl,
516
- namespace: stored.config.namespace,
517
- headers: normalizeConfiguredMap(stored.config.headers),
518
- queryParams: normalizeConfiguredMap(stored.config.queryParams),
519
- specFetchCredentials: stored.config.specFetchCredentials ? {
520
- headers: normalizeConfiguredMap(stored.config.specFetchCredentials.headers),
521
- queryParams: normalizeConfiguredMap(stored.config.specFetchCredentials.queryParams)
522
- } : void 0,
523
- oauth2
524
- }
525
- };
526
- };
527
- var rowToOperation = (row) => {
528
- const decoded = decodeOperationStorage(row.data);
529
- if (Option2.isNone(decoded)) return null;
530
- const operation = decoded.value;
531
- return {
532
- toolId: operation.toolId,
533
- sourceId: operation.sourceId,
534
- binding: decodeBinding(
535
- typeof operation.binding === "string" ? decodeBindingJson(operation.binding) : operation.binding
536
- )
537
- };
538
- };
539
- var makeDefaultOpenapiStore = ({
540
- pluginStorage
541
- }) => {
542
- const sourceData = (source) => ({
543
- namespace: source.namespace,
544
- scope: source.scope,
545
- name: source.name,
546
- config: encodeSourceConfig(source.config)
547
- });
548
- const operationData = (operation) => ({
549
- toolId: operation.toolId,
550
- sourceId: operation.sourceId,
551
- binding: toJsonRecord(encodeBinding(operation.binding))
552
- });
553
- const listOperationRowsForSourceScope = (sourceId, scope) => pluginStorage.list({
554
- collection: OPERATION_COLLECTION,
555
- keyPrefix: `${sourceId}.`
556
- }).pipe(
557
- Effect2.map(
558
- (rows) => rows.filter(
559
- (row) => String(row.scopeId) === scope && rowToOperation(row)?.sourceId === sourceId
560
- )
561
- )
562
- );
563
- const removeOperationsForSourceScope = (sourceId, scope) => Effect2.gen(function* () {
564
- const rows = yield* listOperationRowsForSourceScope(sourceId, scope);
565
- for (const row of rows) {
566
- yield* pluginStorage.remove({
567
- scope,
568
- collection: OPERATION_COLLECTION,
569
- key: row.key
570
- });
571
- }
572
- });
573
- const deleteSource = (namespace, scope) => Effect2.gen(function* () {
574
- yield* removeOperationsForSourceScope(namespace, scope);
575
- yield* pluginStorage.remove({
576
- scope,
577
- collection: SOURCE_COLLECTION,
578
- key: namespace
579
- });
580
- });
581
- return {
582
- upsertSource: (input, operations) => Effect2.gen(function* () {
583
- yield* deleteSource(input.namespace, input.scope);
584
- yield* pluginStorage.put({
585
- scope: input.scope,
586
- collection: SOURCE_COLLECTION,
587
- key: input.namespace,
588
- data: sourceData(input)
589
- });
590
- for (const operation of operations) {
591
- yield* pluginStorage.put({
592
- scope: input.scope,
593
- collection: OPERATION_COLLECTION,
594
- key: operation.toolId,
595
- data: operationData(operation)
596
- });
597
- }
598
- }),
599
- updateSourceMeta: (namespace, scope, patch) => Effect2.gen(function* () {
600
- const existing = yield* pluginStorage.getAtScope({
601
- scope,
602
- collection: SOURCE_COLLECTION,
603
- key: namespace
604
- });
605
- if (!existing) return;
606
- const source = rowToSource(existing);
607
- if (!source) return;
608
- const next = {
609
- ...source,
610
- name: patch.name?.trim() || source.name,
611
- config: {
612
- ...source.config,
613
- ...patch.baseUrl !== void 0 ? { baseUrl: patch.baseUrl } : {},
614
- ...patch.headers !== void 0 ? { headers: patch.headers } : {},
615
- ...patch.queryParams !== void 0 ? { queryParams: patch.queryParams } : {},
616
- ...patch.specFetchCredentials !== void 0 ? { specFetchCredentials: patch.specFetchCredentials } : {},
617
- ...patch.oauth2 !== void 0 ? { oauth2: patch.oauth2 } : {}
618
- }
619
- };
620
- yield* pluginStorage.put({
621
- scope,
622
- collection: SOURCE_COLLECTION,
623
- key: namespace,
624
- data: sourceData(next)
625
- });
626
- }),
627
- getSource: (namespace, scope) => pluginStorage.getAtScope({ scope, collection: SOURCE_COLLECTION, key: namespace }).pipe(Effect2.map((row) => row ? rowToSource(row) : null)),
628
- listSources: () => pluginStorage.list({ collection: SOURCE_COLLECTION }).pipe(Effect2.map((rows) => rows.map(rowToSource).filter(Predicate.isNotNull))),
629
- getOperationByToolId: (toolId, scope) => pluginStorage.getAtScope({ scope, collection: OPERATION_COLLECTION, key: toolId }).pipe(Effect2.map((row) => row ? rowToOperation(row) : null)),
630
- listOperationsBySource: (sourceId, scope) => listOperationRowsForSourceScope(sourceId, scope).pipe(
631
- Effect2.map((rows) => rows.map(rowToOperation).filter(Predicate.isNotNull))
632
- ),
633
- removeSource: (namespace, scope) => deleteSource(namespace, scope)
634
- };
635
- };
636
-
637
- // src/sdk/plugin.ts
638
- import { Effect as Effect3, Option as Option3, Predicate as Predicate2, Schema as Schema2 } from "effect";
639
- import {
640
- ConnectionId,
641
- CredentialBindingRef,
642
- ScopeId,
643
- SecretId,
644
- SourceDetectionResult,
645
- StorageError,
646
- ToolResult,
647
- authToolFailure,
648
- defaultSourceInstallScopeId,
649
- definePlugin,
650
- tool,
651
- resolveSecretBackedMap
652
- } from "@executor-js/sdk/core";
653
- import {
654
- headersToConfigValues
655
- } from "@executor-js/config";
656
-
657
- // src/sdk/definitions.ts
658
- 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);
659
- var normalizeWord = (value) => value.toLowerCase();
660
- var toCamelCase = (value) => {
661
- const words = splitWords(value).map(normalizeWord);
662
- if (words.length === 0) return "tool";
663
- const [first, ...rest] = words;
664
- return `${first}${rest.map((p) => `${p[0]?.toUpperCase() ?? ""}${p.slice(1)}`).join("")}`;
665
- };
666
- var toPascalCase = (value) => {
667
- const camel = toCamelCase(value);
668
- return `${camel[0]?.toUpperCase() ?? ""}${camel.slice(1)}`;
669
- };
670
- var VERSION_SEGMENT_REGEX = /^v\d+(?:[._-]\d+)?$/i;
671
- var IGNORED_PATH_SEGMENTS = /* @__PURE__ */ new Set(["api"]);
672
- var pathSegmentsFromTemplate = (pathTemplate) => pathTemplate.split("/").map((s) => s.trim()).filter((s) => s.length > 0);
673
- var isPathParameterSegment = (segment) => segment.startsWith("{") && segment.endsWith("}");
674
- var normalizeGroupSegment = (value) => {
675
- const candidate = value?.trim();
676
- if (!candidate) return null;
677
- return toCamelCase(candidate);
678
- };
679
- var deriveVersionSegment = (pathTemplate) => pathSegmentsFromTemplate(pathTemplate).map((s) => s.toLowerCase()).find((s) => VERSION_SEGMENT_REGEX.test(s));
680
- var derivePathGroup = (pathTemplate) => {
681
- for (const segment of pathSegmentsFromTemplate(pathTemplate)) {
682
- const lower = segment.toLowerCase();
683
- if (VERSION_SEGMENT_REGEX.test(lower)) continue;
684
- if (IGNORED_PATH_SEGMENTS.has(lower)) continue;
685
- if (isPathParameterSegment(segment)) continue;
686
- return normalizeGroupSegment(segment) ?? "root";
687
- }
688
- return "root";
689
- };
690
- var splitOperationIdSegments = (value) => value.split(/[/.]+/).map((s) => s.trim()).filter((s) => s.length > 0);
691
- var deriveLeafSeed = (operationId, group) => {
692
- const segments = splitOperationIdSegments(operationId);
693
- if (segments.length > 1) {
694
- const [first, ...rest] = segments;
695
- if ((normalizeGroupSegment(first) ?? first) === group && rest.length > 0) {
696
- return rest.join(" ");
697
- }
698
- }
699
- return operationId;
700
- };
701
- var fallbackLeafSeed = (method, pathTemplate, group) => {
702
- 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);
703
- const segmentSuffix = relevantSegments.map((s) => toPascalCase(s)).join("");
704
- return `${method}${segmentSuffix || "Operation"}`;
705
- };
706
- var deriveLeaf = (operationId, method, pathTemplate, group) => {
707
- const preferred = toCamelCase(deriveLeafSeed(operationId, group));
708
- if (preferred.length > 0 && preferred !== group) return preferred;
709
- return toCamelCase(fallbackLeafSeed(method, pathTemplate, group));
710
- };
711
- var resolveCollisions = (definitions) => {
712
- const staged = definitions.map((d) => ({ ...d }));
713
- const applyFactory = (items, factory) => {
714
- const byPath = /* @__PURE__ */ new Map();
715
- for (const item of items) {
716
- const bucket = byPath.get(item.toolPath) ?? [];
717
- bucket.push(item);
718
- byPath.set(item.toolPath, bucket);
719
- }
720
- for (const bucket of byPath.values()) {
721
- if (bucket.length < 2) continue;
722
- for (const d of bucket) {
723
- d.toolPath = factory(d);
724
- }
725
- }
726
- };
727
- applyFactory(
728
- staged,
729
- (d) => d.versionSegment ? `${d.group}.${d.versionSegment}.${d.leaf}` : d.toolPath
730
- );
731
- applyFactory(staged, (d) => {
732
- const prefix = d.versionSegment ? `${d.group}.${d.versionSegment}` : d.group;
733
- return `${prefix}.${d.leaf}${toPascalCase(d.method)}`;
734
- });
735
- applyFactory(staged, (d) => {
736
- const prefix = d.versionSegment ? `${d.group}.${d.versionSegment}` : d.group;
737
- return `${prefix}.${d.leaf}${toPascalCase(d.method)}${d.operationHash.slice(0, 8)}`;
738
- });
739
- return staged.map((d) => ({
740
- toolPath: d.toolPath,
741
- group: d.group,
742
- leaf: d.leaf,
743
- operationIndex: d.operationIndex,
744
- operation: d.operation
745
- }));
746
- };
747
- var stableHash = (value) => {
748
- const str = JSON.stringify(value, Object.keys(value).sort());
749
- let hash = 0;
750
- for (let i = 0; i < str.length; i++) {
751
- hash = (hash << 5) - hash + str.charCodeAt(i) | 0;
752
- }
753
- return Math.abs(hash).toString(36).padStart(8, "0");
754
- };
755
- var compileToolDefinitions = (operations) => {
756
- const raw = operations.map((op, index) => {
757
- const operationId = op.operationId;
758
- const group = normalizeGroupSegment(op.tags[0]) ?? derivePathGroup(op.pathTemplate);
759
- const leaf = deriveLeaf(operationId, op.method, op.pathTemplate, group);
760
- const versionSegment = deriveVersionSegment(op.pathTemplate);
761
- const operationHash = stableHash({
762
- method: op.method,
763
- path: op.pathTemplate,
764
- operationId
765
- });
766
- return {
767
- toolPath: `${group}.${leaf}`,
768
- group,
769
- leaf,
770
- versionSegment,
771
- method: op.method,
772
- operationHash,
773
- operationIndex: index,
774
- operation: op
775
- };
776
- });
777
- return resolveCollisions(raw).sort((a, b) => a.toolPath.localeCompare(b.toolPath));
778
- };
779
-
780
- // src/sdk/plugin.ts
781
- var STRINGIFIED_BODY_CAP = 1024;
782
- var UpstreamMessageBody = Schema2.Struct({ message: Schema2.String });
783
- var UpstreamErrorMessageBody = Schema2.Struct({ errorMessage: Schema2.String });
784
- var UpstreamNestedErrorBody = Schema2.Struct({ error: UpstreamMessageBody });
785
- var UpstreamErrorsArrayBody = Schema2.Struct({
786
- errors: Schema2.Array(
787
- Schema2.Struct({
788
- detail: Schema2.optional(Schema2.String),
789
- message: Schema2.optional(Schema2.String),
790
- title: Schema2.optional(Schema2.String)
791
- })
792
- )
793
- });
794
- var UpstreamDescriptionBody = Schema2.Struct({
795
- detail: Schema2.optional(Schema2.String),
796
- title: Schema2.optional(Schema2.String),
797
- description: Schema2.optional(Schema2.String)
798
- });
799
- var decodeUpstreamMessageBody = Schema2.decodeUnknownOption(UpstreamMessageBody);
800
- var decodeUpstreamErrorMessageBody = Schema2.decodeUnknownOption(UpstreamErrorMessageBody);
801
- var decodeUpstreamNestedErrorBody = Schema2.decodeUnknownOption(UpstreamNestedErrorBody);
802
- var decodeUpstreamErrorsArrayBody = Schema2.decodeUnknownOption(UpstreamErrorsArrayBody);
803
- var decodeUpstreamDescriptionBody = Schema2.decodeUnknownOption(UpstreamDescriptionBody);
804
- var clampedStringify = (value) => {
805
- let s;
806
- try {
807
- s = JSON.stringify(value);
808
- } catch {
809
- s = String(value);
810
- }
811
- return s.length > STRINGIFIED_BODY_CAP ? `${s.slice(0, STRINGIFIED_BODY_CAP)}\u2026` : s;
812
- };
813
- var firstNonEmpty = (...values) => values.find((value) => value !== void 0 && value.length > 0);
814
- var extractUpstreamMessage = (body, status) => {
815
- if (typeof body === "string") {
816
- return body.length > 0 ? body : `Upstream returned HTTP ${status}`;
817
- }
818
- const nested = Option3.getOrUndefined(decodeUpstreamNestedErrorBody(body));
819
- const messageBody = Option3.getOrUndefined(decodeUpstreamMessageBody(body));
820
- const errorMessageBody = Option3.getOrUndefined(decodeUpstreamErrorMessageBody(body));
821
- const errorsBody = Option3.getOrUndefined(decodeUpstreamErrorsArrayBody(body));
822
- const descriptionBody = Option3.getOrUndefined(decodeUpstreamDescriptionBody(body));
823
- const arrayMessage = errorsBody?.errors.map(
824
- ({ detail, message: upstreamMessage, title }) => firstNonEmpty(detail, upstreamMessage, title)
825
- ).find((message2) => message2 !== void 0);
826
- const message = firstNonEmpty(
827
- nested?.error.message,
828
- messageBody?.message,
829
- errorMessageBody?.errorMessage,
830
- arrayMessage,
831
- descriptionBody?.detail,
832
- descriptionBody?.title,
833
- descriptionBody?.description
834
- );
835
- if (message !== void 0) return message;
836
- if (body !== null && typeof body === "object") {
837
- return clampedStringify(body);
838
- }
839
- return `Upstream returned HTTP ${status}`;
840
- };
841
- var PreviewSpecInputSchema = Schema2.Struct({
842
- spec: Schema2.String,
843
- specFetchCredentials: Schema2.optional(
844
- Schema2.Struct({
845
- headers: Schema2.optional(Schema2.Record(Schema2.String, HeaderValue)),
846
- queryParams: Schema2.optional(Schema2.Record(Schema2.String, HeaderValue))
847
- })
848
- )
849
- });
850
- var StaticPreviewServerVariableSchema = Schema2.Struct({
851
- default: Schema2.String,
852
- enum: Schema2.NullOr(Schema2.Array(Schema2.String)),
853
- description: Schema2.NullOr(Schema2.String)
854
- });
855
- var StaticPreviewServerSchema = Schema2.Struct({
856
- url: Schema2.String,
857
- description: Schema2.NullOr(Schema2.String),
858
- variables: Schema2.NullOr(Schema2.Record(Schema2.String, StaticPreviewServerVariableSchema))
859
- });
860
- var StaticPreviewOAuthAuthorizationCodeFlowSchema = Schema2.Struct({
861
- authorizationUrl: Schema2.String,
862
- tokenUrl: Schema2.String,
863
- refreshUrl: Schema2.NullOr(Schema2.String),
864
- scopes: Schema2.Record(Schema2.String, Schema2.String)
865
- });
866
- var StaticPreviewOAuthClientCredentialsFlowSchema = Schema2.Struct({
867
- tokenUrl: Schema2.String,
868
- refreshUrl: Schema2.NullOr(Schema2.String),
869
- scopes: Schema2.Record(Schema2.String, Schema2.String)
870
- });
871
- var StaticPreviewOAuthFlowsSchema = Schema2.Struct({
872
- authorizationCode: Schema2.NullOr(StaticPreviewOAuthAuthorizationCodeFlowSchema),
873
- clientCredentials: Schema2.NullOr(StaticPreviewOAuthClientCredentialsFlowSchema)
874
- });
875
- var StaticPreviewSecuritySchemeSchema = Schema2.Struct({
876
- name: Schema2.String,
877
- type: Schema2.Literals(["http", "apiKey", "oauth2", "openIdConnect"]),
878
- scheme: Schema2.NullOr(Schema2.String),
879
- bearerFormat: Schema2.NullOr(Schema2.String),
880
- in: Schema2.NullOr(Schema2.Literals(["header", "query", "cookie"])),
881
- headerName: Schema2.NullOr(Schema2.String),
882
- description: Schema2.NullOr(Schema2.String),
883
- flows: Schema2.NullOr(StaticPreviewOAuthFlowsSchema),
884
- openIdConnectUrl: Schema2.NullOr(Schema2.String)
885
- });
886
- var StaticPreviewOAuth2PresetSchema = Schema2.Struct({
887
- label: Schema2.String,
888
- securitySchemeName: Schema2.String,
889
- flow: Schema2.Literals(["authorizationCode", "clientCredentials"]),
890
- authorizationUrl: Schema2.NullOr(Schema2.String),
891
- tokenUrl: Schema2.String,
892
- refreshUrl: Schema2.NullOr(Schema2.String),
893
- scopes: Schema2.Record(Schema2.String, Schema2.String)
894
- });
895
- var StaticPreviewSpecOutputSchema = Schema2.Struct({
896
- title: Schema2.NullOr(Schema2.String),
897
- version: Schema2.NullOr(Schema2.String),
898
- servers: Schema2.Array(StaticPreviewServerSchema),
899
- operationCount: Schema2.Number,
900
- tags: Schema2.Array(Schema2.String),
901
- securitySchemes: Schema2.Array(StaticPreviewSecuritySchemeSchema),
902
- authStrategies: Schema2.Array(Schema2.Struct({ schemes: Schema2.Array(Schema2.String) })),
903
- headerPresets: Schema2.Array(
904
- Schema2.Struct({
905
- label: Schema2.String,
906
- headers: Schema2.Record(Schema2.String, Schema2.NullOr(Schema2.String)),
907
- secretHeaders: Schema2.Array(Schema2.String)
908
- })
909
- ),
910
- oauth2Presets: Schema2.Array(StaticPreviewOAuth2PresetSchema)
911
- });
912
- var OpenApiSpecInputSchema = Schema2.Union([
913
- Schema2.Struct({ kind: Schema2.Literal("url"), url: Schema2.String }),
914
- Schema2.Struct({ kind: Schema2.Literal("blob"), value: Schema2.String })
915
- ]);
916
- var OpenApiSecretShapeInputSchema = Schema2.Struct({
917
- kind: Schema2.Literal("secret"),
918
- prefix: Schema2.optional(Schema2.String)
919
- });
920
- var OpenApiConfiguredValueInputSchema = Schema2.Union([
921
- Schema2.String,
922
- OpenApiSecretShapeInputSchema
923
- ]);
924
- var OpenApiConfigureCredentialInputSchema = Schema2.Union([
925
- Schema2.String,
926
- Schema2.Struct({
927
- kind: Schema2.Literal("text"),
928
- text: Schema2.String,
929
- prefix: Schema2.optional(Schema2.String)
930
- }),
931
- Schema2.Struct({
932
- kind: Schema2.Literal("secret"),
933
- secretId: Schema2.String,
934
- secretScope: Schema2.optional(Schema2.String),
935
- prefix: Schema2.optional(Schema2.String)
936
- }),
937
- Schema2.Struct({
938
- kind: Schema2.Literal("connection"),
939
- connectionId: Schema2.String
940
- })
941
- ]);
942
- var OpenApiConfigureInputSchema = Schema2.Struct({
943
- scope: Schema2.String,
944
- name: Schema2.optional(Schema2.String),
945
- baseUrl: Schema2.optional(Schema2.String),
946
- headers: Schema2.optional(Schema2.Record(Schema2.String, OpenApiConfigureCredentialInputSchema)),
947
- queryParams: Schema2.optional(Schema2.Record(Schema2.String, OpenApiConfigureCredentialInputSchema)),
948
- specFetchCredentials: Schema2.optional(
949
- Schema2.Struct({
950
- headers: Schema2.optional(Schema2.Record(Schema2.String, OpenApiConfigureCredentialInputSchema)),
951
- queryParams: Schema2.optional(
952
- Schema2.Record(Schema2.String, OpenApiConfigureCredentialInputSchema)
953
- )
954
- })
955
- ),
956
- oauth2: Schema2.optional(
957
- Schema2.Struct({
958
- clientId: Schema2.optional(OpenApiConfigureCredentialInputSchema),
959
- clientSecret: Schema2.optional(OpenApiConfigureCredentialInputSchema),
960
- connection: Schema2.optional(OpenApiConfigureCredentialInputSchema)
961
- })
962
- ),
963
- oauth2Source: Schema2.optional(OAuth2SourceConfig)
964
- });
965
- var OpenApiConfigureSourceInputSchema = Schema2.Struct({
966
- source: Schema2.Struct({
967
- id: Schema2.String,
968
- scope: Schema2.String
969
- }),
970
- ...OpenApiConfigureInputSchema.fields
971
- });
972
- var OpenApiOAuthInputSchema = OAuth2SourceConfig;
973
- var AddSourceInputSchema = Schema2.Struct({
974
- spec: OpenApiSpecInputSchema,
975
- name: Schema2.String,
976
- baseUrl: Schema2.String,
977
- namespace: Schema2.String,
978
- headers: Schema2.optional(Schema2.Record(Schema2.String, OpenApiConfiguredValueInputSchema)),
979
- queryParams: Schema2.optional(Schema2.Record(Schema2.String, OpenApiConfiguredValueInputSchema)),
980
- oauth2: Schema2.optional(OpenApiOAuthInputSchema),
981
- specFetchCredentials: Schema2.optional(
982
- Schema2.Struct({
983
- headers: Schema2.optional(Schema2.Record(Schema2.String, OpenApiConfiguredValueInputSchema)),
984
- queryParams: Schema2.optional(Schema2.Record(Schema2.String, OpenApiConfiguredValueInputSchema))
985
- })
986
- )
987
- });
988
- var AddSourceOutputSchema = Schema2.Struct({
989
- sourceId: Schema2.String,
990
- source: Schema2.Struct({
991
- id: Schema2.String,
992
- scope: Schema2.String
993
- }),
994
- toolCount: Schema2.Number
995
- });
996
- var GetSourceInputSchema = Schema2.Struct({
997
- namespace: Schema2.String,
998
- scope: Schema2.String
999
- });
1000
- var GetSourceOutputSchema = Schema2.Struct({
1001
- source: Schema2.NullOr(Schema2.Unknown)
1002
- });
1003
- var PreviewSpecInputStandardSchema = Schema2.toStandardSchemaV1(
1004
- Schema2.toStandardJSONSchemaV1(PreviewSpecInputSchema)
1005
- );
1006
- var PreviewSpecOutputStandardSchema = Schema2.toStandardSchemaV1(
1007
- Schema2.toStandardJSONSchemaV1(StaticPreviewSpecOutputSchema)
1008
- );
1009
- var AddSourceInputStandardSchema = Schema2.toStandardSchemaV1(
1010
- Schema2.toStandardJSONSchemaV1(AddSourceInputSchema)
1011
- );
1012
- var AddSourceOutputStandardSchema = Schema2.toStandardSchemaV1(
1013
- Schema2.toStandardJSONSchemaV1(AddSourceOutputSchema)
1014
- );
1015
- var OpenApiConfigureSourceInputStandardSchema = Schema2.toStandardSchemaV1(
1016
- Schema2.toStandardJSONSchemaV1(OpenApiConfigureSourceInputSchema)
1017
- );
1018
- var OpenApiConfigureSourceOutputStandardSchema = Schema2.toStandardSchemaV1(
1019
- Schema2.toStandardJSONSchemaV1(Schema2.Struct({ result: Schema2.Array(CredentialBindingRef) }))
1020
- );
1021
- var GetSourceInputStandardSchema = Schema2.toStandardSchemaV1(
1022
- Schema2.toStandardJSONSchemaV1(GetSourceInputSchema)
1023
- );
1024
- var GetSourceOutputStandardSchema = Schema2.toStandardSchemaV1(
1025
- Schema2.toStandardJSONSchemaV1(GetSourceOutputSchema)
1026
- );
1027
- var openApiToolFailure = (code, message, details) => ToolResult.fail({
1028
- code,
1029
- message,
1030
- ...details === void 0 ? {} : { details }
1031
- });
1032
- var openApiAuthToolFailure = (failure) => authToolFailure({
1033
- code: failure.code,
1034
- message: failure.message,
1035
- source: { id: failure.sourceId, scope: failure.sourceScope },
1036
- credential: {
1037
- kind: failure.credentialKind,
1038
- ...failure.credentialLabel ? { label: failure.credentialLabel } : {},
1039
- ...failure.slotKey ? { slotKey: failure.slotKey } : {},
1040
- ...failure.secretId ? { secretId: failure.secretId } : {},
1041
- ...failure.connectionId ? { connectionId: failure.connectionId } : {}
1042
- },
1043
- ...failure.status !== void 0 ? { status: failure.status } : {},
1044
- ...failure.details !== void 0 ? {
1045
- upstream: {
1046
- ...failure.status !== void 0 ? { status: failure.status } : {},
1047
- details: failure.details
1048
- }
1049
- } : {},
1050
- recovery: { configureSourceTool: "executor.openapi.configureSource" }
1051
- });
1052
- var staticPreviewOutput = (preview) => ({
1053
- title: Option3.getOrNull(preview.title),
1054
- version: Option3.getOrNull(preview.version),
1055
- servers: preview.servers.map((server) => ({
1056
- url: server.url,
1057
- description: Option3.getOrNull(server.description),
1058
- variables: Option3.getOrNull(server.variables) ? Object.fromEntries(
1059
- Object.entries(Option3.getOrNull(server.variables) ?? {}).map(([name, variable]) => [
1060
- name,
1061
- {
1062
- default: variable.default,
1063
- enum: Option3.getOrNull(variable.enum),
1064
- description: Option3.getOrNull(variable.description)
1065
- }
1066
- ])
1067
- ) : null
1068
- })),
1069
- operationCount: preview.operationCount,
1070
- tags: preview.tags,
1071
- securitySchemes: preview.securitySchemes.map((scheme) => ({
1072
- name: scheme.name,
1073
- type: scheme.type,
1074
- scheme: Option3.getOrNull(scheme.scheme),
1075
- bearerFormat: Option3.getOrNull(scheme.bearerFormat),
1076
- in: Option3.getOrNull(scheme.in),
1077
- headerName: Option3.getOrNull(scheme.headerName),
1078
- description: Option3.getOrNull(scheme.description),
1079
- flows: Option3.isSome(scheme.flows) ? {
1080
- authorizationCode: Option3.isSome(scheme.flows.value.authorizationCode) ? {
1081
- authorizationUrl: scheme.flows.value.authorizationCode.value.authorizationUrl,
1082
- tokenUrl: scheme.flows.value.authorizationCode.value.tokenUrl,
1083
- refreshUrl: Option3.getOrNull(scheme.flows.value.authorizationCode.value.refreshUrl),
1084
- scopes: scheme.flows.value.authorizationCode.value.scopes
1085
- } : null,
1086
- clientCredentials: Option3.isSome(scheme.flows.value.clientCredentials) ? {
1087
- tokenUrl: scheme.flows.value.clientCredentials.value.tokenUrl,
1088
- refreshUrl: Option3.getOrNull(scheme.flows.value.clientCredentials.value.refreshUrl),
1089
- scopes: scheme.flows.value.clientCredentials.value.scopes
1090
- } : null
1091
- } : null,
1092
- openIdConnectUrl: Option3.getOrNull(scheme.openIdConnectUrl)
1093
- })),
1094
- authStrategies: preview.authStrategies,
1095
- headerPresets: preview.headerPresets,
1096
- oauth2Presets: preview.oauth2Presets.map((preset) => ({
1097
- label: preset.label,
1098
- securitySchemeName: preset.securitySchemeName,
1099
- flow: preset.flow,
1100
- authorizationUrl: Option3.getOrNull(preset.authorizationUrl),
1101
- tokenUrl: preset.tokenUrl,
1102
- refreshUrl: Option3.getOrNull(preset.refreshUrl),
1103
- scopes: preset.scopes
1104
- }))
1105
- });
1106
- var resolveStaticScopeInput = (ctx, value) => String(
1107
- ctx.scopes.find((scope) => scope.name === value || String(scope.id) === value)?.id ?? value
1108
- );
1109
- var normalizeOpenApiRefs = (node) => {
1110
- if (node == null || typeof node !== "object") return node;
1111
- if (Array.isArray(node)) {
1112
- let changed2 = false;
1113
- const out = node.map((item) => {
1114
- const n = normalizeOpenApiRefs(item);
1115
- if (n !== item) changed2 = true;
1116
- return n;
1117
- });
1118
- return changed2 ? out : node;
1119
- }
1120
- const obj = node;
1121
- if (typeof obj.$ref === "string") {
1122
- const match = obj.$ref.match(/^#\/components\/schemas\/(.+)$/);
1123
- if (match) return { ...obj, $ref: `#/$defs/${match[1]}` };
1124
- return obj;
1125
- }
1126
- let changed = false;
1127
- const result = {};
1128
- for (const [k, v] of Object.entries(obj)) {
1129
- const n = normalizeOpenApiRefs(v);
1130
- if (n !== v) changed = true;
1131
- result[k] = n;
1132
- }
1133
- return changed ? result : obj;
1134
- };
1135
- var toBinding = (def) => OperationBinding.make({
1136
- method: def.operation.method,
1137
- pathTemplate: def.operation.pathTemplate,
1138
- parameters: [...def.operation.parameters],
1139
- requestBody: def.operation.requestBody
1140
- });
1141
- var descriptionFor = (def) => {
1142
- const op = def.operation;
1143
- return Option3.getOrElse(
1144
- op.description,
1145
- () => Option3.getOrElse(op.summary, () => `${op.method.toUpperCase()} ${op.pathTemplate}`)
1146
- );
1147
- };
1148
- var slotPart = (value) => value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "default";
1149
- var headerSlotFromName = (name) => `header:${slotPart(name)}`;
1150
- var queryParamSlotFromName = (name) => `query_param:${slotPart(name)}`;
1151
- var specFetchHeaderSlotFromName = (name) => `spec_fetch_header:${slotPart(name)}`;
1152
- var specFetchQueryParamSlotFromName = (name) => `spec_fetch_query_param:${slotPart(name)}`;
1153
- var canonicalizeHeaders = (headers) => {
1154
- const nextHeaders = {};
1155
- for (const [name, value] of Object.entries(headers ?? {})) {
1156
- if (typeof value === "string") {
1157
- nextHeaders[name] = value;
1158
- continue;
1159
- }
1160
- if (value.kind === "binding") {
1161
- nextHeaders[name] = value;
1162
- continue;
1163
- }
1164
- const slot = headerSlotFromName(name);
1165
- nextHeaders[name] = ConfiguredHeaderBinding.make({
1166
- kind: "binding",
1167
- slot,
1168
- prefix: value.prefix
1169
- });
1170
- }
1171
- return { headers: nextHeaders };
1172
- };
1173
- var canonicalizeCredentialMap = (values, slotForName) => {
1174
- const nextValues = {};
1175
- for (const [name, value] of Object.entries(values ?? {})) {
1176
- if (typeof value === "string") {
1177
- nextValues[name] = value;
1178
- continue;
1179
- }
1180
- if (value.kind === "binding") {
1181
- nextValues[name] = value;
1182
- continue;
1183
- }
1184
- const slot = slotForName(name);
1185
- nextValues[name] = ConfiguredHeaderBinding.make({
1186
- kind: "binding",
1187
- slot,
1188
- prefix: value.prefix
1189
- });
1190
- }
1191
- return { values: nextValues };
1192
- };
1193
- var canonicalizeSpecFetchCredentials = (credentials) => {
1194
- const headers = canonicalizeCredentialMap(credentials?.headers, specFetchHeaderSlotFromName);
1195
- const queryParams = canonicalizeCredentialMap(
1196
- credentials?.queryParams,
1197
- specFetchQueryParamSlotFromName
1198
- );
1199
- const nextCredentials = Object.keys(headers.values).length === 0 && Object.keys(queryParams.values).length === 0 ? void 0 : {
1200
- ...Object.keys(headers.values).length > 0 ? { headers: headers.values } : {},
1201
- ...Object.keys(queryParams.values).length > 0 ? { queryParams: queryParams.values } : {}
1202
- };
1203
- return {
1204
- credentials: nextCredentials
1205
- };
1206
- };
1207
- var canonicalizeOAuth2 = (oauth2) => {
1208
- if (!oauth2) return {};
1209
- return {
1210
- oauth2
1211
- };
1212
- };
1213
- var configuredValueFromConfigureInput = (slot, input) => {
1214
- if (typeof input === "string") {
1215
- return {
1216
- configured: ConfiguredHeaderBinding.make({ kind: "binding", slot }),
1217
- value: { kind: "text", text: input }
1218
- };
1219
- }
1220
- if (input.kind === "text") {
1221
- return {
1222
- configured: ConfiguredHeaderBinding.make({
1223
- kind: "binding",
1224
- slot,
1225
- prefix: input.prefix
1226
- }),
1227
- value: { kind: "text", text: input.text }
1228
- };
1229
- }
1230
- if (input.kind === "secret") {
1231
- return {
1232
- configured: ConfiguredHeaderBinding.make({
1233
- kind: "binding",
1234
- slot,
1235
- prefix: input.prefix
1236
- }),
1237
- value: {
1238
- kind: "secret",
1239
- secretId: SecretId.make(input.secretId),
1240
- ...input.secretScope ? { secretScopeId: ScopeId.make(input.secretScope) } : {}
1241
- }
1242
- };
1243
- }
1244
- return {
1245
- configured: ConfiguredHeaderBinding.make({ kind: "binding", slot }),
1246
- value: { kind: "connection", connectionId: ConnectionId.make(input.connectionId) }
1247
- };
1248
- };
1249
- var configureMap = (values, slotForName) => {
1250
- const configured = {};
1251
- const bindings = [];
1252
- for (const [name, input] of Object.entries(values ?? {})) {
1253
- const slotKey = slotForName(name);
1254
- const next = configuredValueFromConfigureInput(slotKey, input);
1255
- configured[name] = next.configured;
1256
- bindings.push({ slotKey, value: next.value });
1257
- }
1258
- return { configured, bindings };
1259
- };
1260
- var configureOpenApiSource = (ctx, source, input) => Effect3.gen(function* () {
1261
- const existing = yield* ctx.storage.getSource(source.id, source.scope);
1262
- if (!existing) {
1263
- return yield* new StorageError({
1264
- message: `Cannot configure OpenAPI source "${source.id}" at scope "${source.scope}": source is not visible.`,
1265
- cause: void 0
1266
- });
1267
- }
1268
- const headers = configureMap(input.headers, headerSlotFromName);
1269
- const queryParams = configureMap(input.queryParams, queryParamSlotFromName);
1270
- const specFetchHeaders = configureMap(
1271
- input.specFetchCredentials?.headers,
1272
- specFetchHeaderSlotFromName
1273
- );
1274
- const specFetchQueryParams = configureMap(
1275
- input.specFetchCredentials?.queryParams,
1276
- specFetchQueryParamSlotFromName
1277
- );
1278
- const oauth2 = existing.config.oauth2;
1279
- const oauth2Bindings = [];
1280
- if (oauth2 && input.oauth2?.clientId) {
1281
- oauth2Bindings.push({
1282
- slotKey: oauth2.clientIdSlot,
1283
- value: configuredValueFromConfigureInput(oauth2.clientIdSlot, input.oauth2.clientId).value
1284
- });
1285
- }
1286
- if (oauth2?.clientSecretSlot && input.oauth2?.clientSecret) {
1287
- oauth2Bindings.push({
1288
- slotKey: oauth2.clientSecretSlot,
1289
- value: configuredValueFromConfigureInput(oauth2.clientSecretSlot, input.oauth2.clientSecret).value
1290
- });
1291
- }
1292
- if (oauth2 && input.oauth2?.connection) {
1293
- oauth2Bindings.push({
1294
- slotKey: oauth2.connectionSlot,
1295
- value: configuredValueFromConfigureInput(oauth2.connectionSlot, input.oauth2.connection).value
1296
- });
1297
- }
1298
- const specFetchCredentials = input.specFetchCredentials === void 0 ? existing.config.specFetchCredentials : {
1299
- headers: specFetchHeaders.configured,
1300
- queryParams: specFetchQueryParams.configured
1301
- };
1302
- const affectedPrefixes = [
1303
- ...input.headers !== void 0 ? ["header:"] : [],
1304
- ...input.queryParams !== void 0 ? ["query_param:"] : [],
1305
- ...input.specFetchCredentials?.headers !== void 0 ? ["spec_fetch:header:"] : [],
1306
- ...input.specFetchCredentials?.queryParams !== void 0 ? ["spec_fetch:query_param:"] : [],
1307
- ...input.oauth2 !== void 0 ? ["oauth2:"] : []
1308
- ];
1309
- const bindings = [
1310
- ...headers.bindings,
1311
- ...queryParams.bindings,
1312
- ...specFetchHeaders.bindings,
1313
- ...specFetchQueryParams.bindings,
1314
- ...oauth2Bindings
1315
- ];
1316
- const nextConfiguredValues = (current, next, provided) => {
1317
- if (!provided) return current;
1318
- if (Object.keys(next).length === 0) return {};
1319
- return { ...current ?? {}, ...next };
1320
- };
1321
- return yield* ctx.transaction(
1322
- Effect3.gen(function* () {
1323
- yield* ctx.storage.updateSourceMeta(source.id, source.scope, {
1324
- headers: nextConfiguredValues(
1325
- existing.config.headers,
1326
- headers.configured,
1327
- input.headers !== void 0
1328
- ),
1329
- queryParams: nextConfiguredValues(
1330
- existing.config.queryParams,
1331
- queryParams.configured,
1332
- input.queryParams !== void 0
1333
- ),
1334
- specFetchCredentials
1335
- });
1336
- if (affectedPrefixes.length > 0 || bindings.length > 0) {
1337
- return yield* ctx.credentialBindings.replaceForSource({
1338
- targetScope: ScopeId.make(input.scope),
1339
- pluginId: OPENAPI_PLUGIN_ID,
1340
- sourceId: source.id,
1341
- sourceScope: ScopeId.make(source.scope),
1342
- slotPrefixes: affectedPrefixes,
1343
- bindings
1344
- });
1345
- }
1346
- return [];
1347
- })
1348
- );
1349
- });
1350
- var OPENAPI_PLUGIN_ID = "openapi";
1351
- var scopeRanks = (ctx) => new Map(ctx.scopes.map((scope, index) => [String(scope.id), index]));
1352
- var scopeRank = (ranks, scopeId) => ranks.get(scopeId) ?? Infinity;
1353
- var resolveOpenApiCredentialBinding = (ctx, sourceId, sourceScope, slot) => ctx.credentialBindings.resolveBinding({
1354
- pluginId: OPENAPI_PLUGIN_ID,
1355
- sourceId,
1356
- sourceScope: ScopeId.make(sourceScope),
1357
- slotKey: slot
1358
- });
1359
- var findOuterSource = (ctx, namespace, scope) => Effect3.gen(function* () {
1360
- const ranks = scopeRanks(ctx);
1361
- const baseRank = scopeRank(ranks, scope);
1362
- for (let index = baseRank + 1; index < ctx.scopes.length; index++) {
1363
- const candidateScope = ctx.scopes[index];
1364
- if (!candidateScope) continue;
1365
- const source = yield* ctx.storage.getSource(namespace, candidateScope.id);
1366
- if (source) return source;
1367
- }
1368
- return null;
1369
- });
1370
- var resolveEffectiveSourceConfig = (ctx, base) => Effect3.gen(function* () {
1371
- const fallback = yield* findOuterSource(ctx, base.namespace, base.scope);
1372
- if (!fallback) {
1373
- return {
1374
- config: base.config,
1375
- headersSource: base,
1376
- queryParamsSource: base,
1377
- specFetchCredentialsSource: base,
1378
- oauth2Source: base
1379
- };
1380
- }
1381
- const hasBaseHeaders = Object.keys(base.config.headers ?? {}).length > 0;
1382
- const hasBaseQueryParams = Object.keys(base.config.queryParams ?? {}).length > 0;
1383
- const hasBaseSpecFetchCredentials = base.config.specFetchCredentials !== void 0;
1384
- return {
1385
- config: {
1386
- ...base.config,
1387
- sourceUrl: base.config.sourceUrl ?? fallback.config.sourceUrl,
1388
- baseUrl: fallback.config.baseUrl,
1389
- namespace: base.config.namespace ?? fallback.config.namespace,
1390
- headers: hasBaseHeaders ? base.config.headers : fallback.config.headers,
1391
- queryParams: hasBaseQueryParams ? base.config.queryParams : fallback.config.queryParams,
1392
- specFetchCredentials: base.config.specFetchCredentials ?? fallback.config.specFetchCredentials,
1393
- oauth2: base.config.oauth2 ?? fallback.config.oauth2
1394
- },
1395
- headersSource: hasBaseHeaders ? base : fallback,
1396
- queryParamsSource: hasBaseQueryParams ? base : fallback,
1397
- specFetchCredentialsSource: hasBaseSpecFetchCredentials ? base : fallback,
1398
- oauth2Source: base.config.oauth2 ? base : fallback
1399
- };
1400
- });
1401
- var resolveConfiguredValueMap = (ctx, params) => Effect3.gen(function* () {
1402
- const resolved = {};
1403
- for (const [name, value] of Object.entries(params.values)) {
1404
- if (typeof value === "string") {
1405
- resolved[name] = value;
1406
- continue;
1407
- }
1408
- const binding = yield* resolveOpenApiCredentialBinding(
1409
- ctx,
1410
- params.sourceId,
1411
- params.sourceScope,
1412
- value.slot
1413
- );
1414
- if (binding?.value.kind === "secret") {
1415
- const secretBinding = binding.value;
1416
- const secret = yield* ctx.secrets.getAtScope(secretBinding.secretId, secretBinding.secretScopeId ?? binding.scopeId).pipe(
1417
- Effect3.catchTag(
1418
- "SecretOwnedByConnectionError",
1419
- () => Effect3.fail(
1420
- new OpenApiAuthRequiredError({
1421
- code: "credential_secret_missing",
1422
- sourceId: params.sourceId,
1423
- sourceScope: params.sourceScope,
1424
- credentialKind: "secret",
1425
- credentialLabel: name,
1426
- slotKey: value.slot,
1427
- secretId: String(secretBinding.secretId),
1428
- message: `Secret not found for ${params.missingLabel} "${name}"`
1429
- })
1430
- )
1431
- )
1432
- );
1433
- if (secret === null) {
1434
- return yield* new OpenApiAuthRequiredError({
1435
- code: "credential_secret_missing",
1436
- sourceId: params.sourceId,
1437
- sourceScope: params.sourceScope,
1438
- credentialKind: "secret",
1439
- credentialLabel: name,
1440
- slotKey: value.slot,
1441
- secretId: String(secretBinding.secretId),
1442
- message: `Missing secret "${secretBinding.secretId}" for ${params.missingLabel} "${name}"`
1443
- });
1444
- }
1445
- resolved[name] = value.prefix ? `${value.prefix}${secret}` : secret;
1446
- continue;
1447
- }
1448
- if (binding?.value.kind === "text") {
1449
- resolved[name] = value.prefix ? `${value.prefix}${binding.value.text}` : binding.value.text;
1450
- continue;
1451
- }
1452
- return yield* new OpenApiAuthRequiredError({
1453
- code: "credential_binding_missing",
1454
- sourceId: params.sourceId,
1455
- sourceScope: params.sourceScope,
1456
- credentialKind: "secret",
1457
- credentialLabel: name,
1458
- slotKey: value.slot,
1459
- message: `Missing binding for ${params.missingLabel} "${name}"`
1460
- });
1461
- }
1462
- return resolved;
1463
- });
1464
- var resolveConfiguredHeaders = (ctx, params) => resolveConfiguredValueMap(ctx, {
1465
- sourceId: params.sourceId,
1466
- sourceScope: params.sourceScope,
1467
- values: params.headers,
1468
- missingLabel: "header"
1469
- });
1470
- var resolveSecretBackedValues = (ctx, values) => resolveSecretBackedMap({
1471
- values,
1472
- getSecret: ctx.secrets.get,
1473
- onMissing: (name) => new OpenApiOAuthError({
1474
- message: `Secret not found for "${name}"`
1475
- }),
1476
- onError: (err, name) => Predicate2.isTagged("SecretOwnedByConnectionError")(err) ? new OpenApiOAuthError({
1477
- message: `Secret not found for "${name}"`
1478
- }) : err
1479
- }).pipe(
1480
- Effect3.mapError(
1481
- (err) => Predicate2.isTagged("SecretOwnedByConnectionError")(err) ? new OpenApiOAuthError({ message: "Secret resolution failed" }) : err
1482
- ),
1483
- Effect3.map((resolved) => resolved ?? {})
1484
- );
1485
- var resolveOAuthConnectionId = (ctx, params) => Effect3.gen(function* () {
1486
- const binding = yield* resolveOpenApiCredentialBinding(
1487
- ctx,
1488
- params.sourceId,
1489
- params.sourceScope,
1490
- params.oauth2.connectionSlot
1491
- );
1492
- if (binding?.value.kind === "connection") {
1493
- const connectionId = binding.value.connectionId;
1494
- const connection = yield* ctx.connections.getAtScope(connectionId, binding.scopeId);
1495
- return connection ? { connectionId, scopeId: binding.scopeId } : null;
1496
- }
1497
- return null;
1498
- });
1499
- var resolveSpecFetchInputCredentials = (ctx, credentials) => Effect3.gen(function* () {
1500
- if (!credentials) return void 0;
1501
- return {
1502
- headers: yield* resolveSecretBackedValues(ctx, credentials.headers),
1503
- queryParams: yield* resolveSecretBackedValues(ctx, credentials.queryParams)
1504
- };
1505
- });
1506
- var resolveStoredSpecFetchCredentials = (ctx, params) => Effect3.gen(function* () {
1507
- if (!params.credentials) return void 0;
1508
- return {
1509
- headers: yield* resolveConfiguredValueMap(ctx, {
1510
- sourceId: params.sourceId,
1511
- sourceScope: params.sourceScope,
1512
- values: params.credentials.headers ?? {},
1513
- missingLabel: "spec fetch header"
1514
- }),
1515
- queryParams: yield* resolveConfiguredValueMap(ctx, {
1516
- sourceId: params.sourceId,
1517
- sourceScope: params.sourceScope,
1518
- values: params.credentials.queryParams ?? {},
1519
- missingLabel: "spec fetch query parameter"
1520
- })
1521
- };
1522
- }).pipe(
1523
- Effect3.catchTag(
1524
- "OpenApiAuthRequiredError",
1525
- ({ message }) => Effect3.fail(new OpenApiOAuthError({ message }))
1526
- )
1527
- );
1528
- var toOpenApiSourceConfig = (namespace, config) => {
1529
- const configHeaders = {};
1530
- for (const [name, value] of Object.entries(config.headers ?? {})) {
1531
- if (typeof value === "string") {
1532
- configHeaders[name] = value;
1533
- }
1534
- }
1535
- return {
1536
- kind: "openapi",
1537
- spec: specInputToConfigString(config.spec),
1538
- baseUrl: config.baseUrl,
1539
- namespace,
1540
- headers: headersToConfigValues(
1541
- Object.keys(configHeaders).length > 0 ? configHeaders : void 0
1542
- )
1543
- };
1544
- };
1545
- var specInputToConfigString = (spec) => spec.kind === "url" ? spec.url : spec.value;
1546
- var openApiPlugin = definePlugin((options) => {
1547
- const openApiTransportOutputSchema = (dataSchema) => ({
1548
- type: "object",
1549
- additionalProperties: false,
1550
- required: ["status", "headers", "data"],
1551
- properties: {
1552
- status: { type: "integer" },
1553
- headers: {
1554
- type: "object",
1555
- additionalProperties: { type: "string" }
1556
- },
1557
- data: dataSchema ?? {}
1558
- }
1559
- });
1560
- const rebuildSource = (ctx, input) => Effect3.gen(function* () {
1561
- const doc = yield* parse(input.specText);
1562
- const result = yield* extract(doc);
1563
- const namespace = input.namespace;
1564
- const outerSource = yield* findOuterSource(ctx, namespace, input.scope);
1565
- if (outerSource && input.baseUrl !== void 0 && input.baseUrl.trim() !== "") {
1566
- return yield* new OpenApiOAuthError({
1567
- message: "OpenAPI source shadows inherit the outer source base URL"
1568
- });
1569
- }
1570
- const hoistedDefs = {};
1571
- if (doc.components?.schemas) {
1572
- for (const [k, v] of Object.entries(doc.components.schemas)) {
1573
- hoistedDefs[k] = normalizeOpenApiRefs(v);
1574
- }
1575
- }
1576
- const baseUrl = outerSource ? void 0 : input.baseUrl;
1577
- const canonicalHeaders = canonicalizeHeaders(input.headers);
1578
- const canonicalQueryParams = canonicalizeCredentialMap(
1579
- input.queryParams,
1580
- queryParamSlotFromName
1581
- );
1582
- const canonicalSpecFetchCredentials = canonicalizeSpecFetchCredentials(
1583
- input.specFetchCredentials
1584
- );
1585
- const canonicalOAuth2 = canonicalizeOAuth2(input.oauth2);
1586
- const definitions = compileToolDefinitions(result.operations);
1587
- const sourceName = input.name;
1588
- const sourceConfig = {
1589
- spec: input.specText,
1590
- sourceUrl: input.sourceUrl,
1591
- baseUrl,
1592
- namespace: input.namespace,
1593
- headers: canonicalHeaders.headers,
1594
- queryParams: canonicalQueryParams.values,
1595
- specFetchCredentials: canonicalSpecFetchCredentials.credentials,
1596
- oauth2: canonicalOAuth2.oauth2
1597
- };
1598
- const storedSource = {
1599
- namespace,
1600
- scope: input.scope,
1601
- name: sourceName,
1602
- config: sourceConfig
1603
- };
1604
- const storedOps = definitions.map((def) => ({
1605
- toolId: `${namespace}.${def.toolPath}`,
1606
- sourceId: namespace,
1607
- binding: toBinding(def)
1608
- }));
1609
- yield* ctx.transaction(
1610
- Effect3.gen(function* () {
1611
- yield* ctx.storage.upsertSource(storedSource, storedOps);
1612
- yield* ctx.core.sources.register({
1613
- id: namespace,
1614
- scope: input.scope,
1615
- kind: "openapi",
1616
- name: sourceName,
1617
- url: baseUrl || void 0,
1618
- canRemove: true,
1619
- // `canRefresh` reflects whether we still know the
1620
- // origin URL — sources added from raw spec text have
1621
- // nothing to re-fetch, so refresh stays disabled.
1622
- canRefresh: input.sourceUrl != null,
1623
- canEdit: true,
1624
- tools: definitions.map((def) => ({
1625
- name: def.toolPath,
1626
- description: descriptionFor(def),
1627
- inputSchema: normalizeOpenApiRefs(Option3.getOrUndefined(def.operation.inputSchema)),
1628
- outputSchema: openApiTransportOutputSchema(
1629
- normalizeOpenApiRefs(Option3.getOrUndefined(def.operation.outputSchema))
1630
- )
1631
- }))
1632
- });
1633
- if (Object.keys(hoistedDefs).length > 0) {
1634
- yield* ctx.core.definitions.register({
1635
- sourceId: namespace,
1636
- scope: input.scope,
1637
- definitions: hoistedDefs
1638
- });
1639
- }
1640
- })
1641
- );
1642
- return { sourceId: namespace, toolCount: definitions.length };
1643
- });
1644
- const refreshSourceInternal = (ctx, sourceId, scope) => Effect3.gen(function* () {
1645
- const httpClientLayer = options?.httpClientLayer ?? ctx.httpClientLayer;
1646
- const existing = yield* ctx.storage.getSource(sourceId, scope);
1647
- if (!existing) return;
1648
- const effective = yield* resolveEffectiveSourceConfig(ctx, existing);
1649
- const resolvedConfig = effective.config;
1650
- const sourceUrl = resolvedConfig.sourceUrl;
1651
- if (!sourceUrl) return;
1652
- const credentials = yield* resolveStoredSpecFetchCredentials(ctx, {
1653
- sourceId: existing.namespace,
1654
- sourceScope: effective.specFetchCredentialsSource.scope,
1655
- credentials: resolvedConfig.specFetchCredentials
1656
- });
1657
- const specText = yield* resolveSpecText(sourceUrl, credentials).pipe(
1658
- Effect3.provide(httpClientLayer)
1659
- );
1660
- yield* rebuildSource(ctx, {
1661
- specText,
1662
- scope,
1663
- sourceUrl,
1664
- name: existing.name,
1665
- baseUrl: existing.config.baseUrl,
1666
- namespace: existing.namespace,
1667
- headers: existing.config.headers,
1668
- queryParams: existing.config.queryParams,
1669
- specFetchCredentials: existing.config.specFetchCredentials,
1670
- oauth2: existing.config.oauth2
1671
- });
1672
- });
1673
- return {
1674
- id: "openapi",
1675
- packageName: "@executor-js/plugin-openapi",
1676
- sourcePresets: openApiPresets,
1677
- schema: openapiSchema,
1678
- storage: (deps) => makeDefaultOpenapiStore(deps),
1679
- extension: (ctx) => {
1680
- const httpClientLayer = options?.httpClientLayer ?? ctx.httpClientLayer;
1681
- const addSpecInternal = (config) => Effect3.gen(function* () {
1682
- const specText = config.spec.kind === "url" ? yield* resolveSpecText(config.spec.url).pipe(Effect3.provide(httpClientLayer)) : config.spec.value;
1683
- return yield* rebuildSource(ctx, {
1684
- specText,
1685
- scope: config.scope,
1686
- sourceUrl: config.spec.kind === "url" ? config.spec.url : void 0,
1687
- name: config.name,
1688
- baseUrl: config.baseUrl,
1689
- namespace: config.namespace,
1690
- headers: config.headers,
1691
- queryParams: config.queryParams,
1692
- specFetchCredentials: config.specFetchCredentials,
1693
- oauth2: config.oauth2
1694
- });
1695
- });
1696
- const configFile = options?.configFile;
1697
- return {
1698
- previewSpec: (input) => Effect3.gen(function* () {
1699
- const previewInput = typeof input === "string" ? { spec: input } : input;
1700
- const credentials = yield* resolveSpecFetchInputCredentials(
1701
- ctx,
1702
- previewInput.specFetchCredentials
1703
- );
1704
- const specText = yield* resolveSpecText(previewInput.spec, credentials).pipe(
1705
- Effect3.provide(httpClientLayer)
1706
- );
1707
- return yield* previewSpec(specText).pipe(Effect3.provide(httpClientLayer));
1708
- }),
1709
- addSpec: (config) => Effect3.gen(function* () {
1710
- const result = yield* addSpecInternal(config);
1711
- if (configFile) {
1712
- yield* configFile.upsertSource(toOpenApiSourceConfig(result.sourceId, config));
1713
- }
1714
- return result;
1715
- }),
1716
- removeSpec: (namespace, scope) => Effect3.gen(function* () {
1717
- yield* ctx.transaction(
1718
- Effect3.gen(function* () {
1719
- yield* ctx.credentialBindings.removeForSource({
1720
- pluginId: OPENAPI_PLUGIN_ID,
1721
- sourceId: namespace,
1722
- sourceScope: ScopeId.make(scope)
1723
- });
1724
- yield* ctx.storage.removeSource(namespace, scope);
1725
- yield* ctx.core.sources.unregister({
1726
- id: namespace,
1727
- targetScope: scope
1728
- });
1729
- })
1730
- );
1731
- if (configFile) {
1732
- yield* configFile.removeSource(namespace);
1733
- }
1734
- }),
1735
- getSource: (namespace, scope) => Effect3.gen(function* () {
1736
- const source = yield* ctx.storage.getSource(namespace, scope);
1737
- if (!source) return null;
1738
- const effective = yield* resolveEffectiveSourceConfig(ctx, source);
1739
- return {
1740
- ...source,
1741
- config: effective.config
1742
- };
1743
- }),
1744
- configure: (source, input) => configureOpenApiSource(ctx, source, input)
1745
- };
1746
- },
1747
- sourceConfigure: {
1748
- type: "openapi",
1749
- schema: OpenApiConfigureInputSchema,
1750
- configure: ({ ctx, sourceId, sourceScope, config }) => Effect3.gen(function* () {
1751
- const input = config;
1752
- if (input.name !== void 0 || input.baseUrl !== void 0 || input.oauth2Source !== void 0) {
1753
- if (input.baseUrl !== void 0 && input.baseUrl.trim() !== "") {
1754
- const outerSource = yield* findOuterSource(ctx, sourceId, sourceScope);
1755
- if (outerSource) {
1756
- return yield* new OpenApiOAuthError({
1757
- message: "OpenAPI source shadows inherit the outer source base URL"
1758
- });
1759
- }
1760
- }
1761
- yield* ctx.storage.updateSourceMeta(sourceId, sourceScope, {
1762
- name: input.name?.trim() || void 0,
1763
- baseUrl: input.baseUrl,
1764
- oauth2: input.oauth2Source
1765
- });
1766
- }
1767
- return yield* configureOpenApiSource(ctx, { id: sourceId, scope: sourceScope }, input);
1768
- })
1769
- },
1770
- staticSources: (self) => [
1771
- {
1772
- id: "openapi",
1773
- kind: "executor",
1774
- name: "OpenAPI",
1775
- tools: [
1776
- tool({
1777
- name: "previewSpec",
1778
- description: "Preview an OpenAPI document before adding it as a source. Call this first when the user provides a spec URL/blob so you can inspect servers, auth schemes, operation count, tags, and credential slots before `addSource`. This agent-facing preview intentionally omits the full operations list; use `operationCount` and `tags` for full-size specs. Do not collect API keys or OAuth client secrets in chat; use `executor.coreTools.secrets.create` for those values.",
1779
- inputSchema: PreviewSpecInputStandardSchema,
1780
- outputSchema: PreviewSpecOutputStandardSchema,
1781
- execute: (input) => self.previewSpec(input).pipe(
1782
- Effect3.map((preview) => ToolResult.ok(staticPreviewOutput(preview))),
1783
- Effect3.catchTags({
1784
- OpenApiParseError: ({ message }) => Effect3.succeed(openApiToolFailure("openapi_parse_failed", message)),
1785
- OpenApiExtractionError: ({ message }) => Effect3.succeed(openApiToolFailure("openapi_extraction_failed", message)),
1786
- OpenApiOAuthError: ({ message }) => Effect3.succeed(openApiToolFailure("openapi_oauth_failed", message))
1787
- })
1788
- )
1789
- }),
1790
- tool({
1791
- name: "getSource",
1792
- description: "Inspect an existing OpenAPI source, including effective base URL, configured headers/query params, OAuth settings, and stored credential slots. Use this before repairing an existing source with `openapi.configureSource`, `secrets.create`, or `oauth.start`.",
1793
- inputSchema: GetSourceInputStandardSchema,
1794
- outputSchema: GetSourceOutputStandardSchema,
1795
- execute: (input, { ctx }) => Effect3.map(
1796
- self.getSource(input.namespace, resolveStaticScopeInput(ctx, input.scope)),
1797
- (source) => ToolResult.ok({ source })
1798
- )
1799
- }),
1800
- tool({
1801
- name: "addSource",
1802
- description: "Add an OpenAPI source and register its operations as tools. Executor chooses the source install scope (local scope locally, organization scope in cloud) and returns it as `source`. Recommended flow: call `previewSpec`, choose or confirm namespace/name/baseUrl from the preview (baseUrl is only needed when the spec cannot infer one or the user wants an override), declare credential slots here for sensitive headers/query params, then call `secrets.create` and `openapi.configureSource` with the user's chosen credential scope for per-scope bindings. Use `oauth.start` with `credentialScope` set to the user's chosen personal or organization credential scope for browser OAuth sign-in.",
1803
- annotations: {
1804
- requiresApproval: true,
1805
- approvalDescription: "Add an OpenAPI source"
1806
- },
1807
- inputSchema: AddSourceInputStandardSchema,
1808
- outputSchema: AddSourceOutputStandardSchema,
1809
- execute: (input, { ctx }) => {
1810
- const sourceScope = defaultSourceInstallScopeId(ctx.scopes);
1811
- if (sourceScope === null) {
1812
- return Effect3.succeed(
1813
- openApiToolFailure(
1814
- "source_scope_unavailable",
1815
- "Cannot add an OpenAPI source because this executor has no source install scope."
1816
- )
1817
- );
1818
- }
1819
- return self.addSpec({ ...input, scope: sourceScope }).pipe(
1820
- Effect3.map(
1821
- (result) => ToolResult.ok({
1822
- ...result,
1823
- source: { id: result.sourceId, scope: sourceScope }
1824
- })
1825
- ),
1826
- Effect3.catchTags({
1827
- OpenApiParseError: ({ message }) => Effect3.succeed(openApiToolFailure("openapi_parse_failed", message)),
1828
- OpenApiExtractionError: ({ message }) => Effect3.succeed(openApiToolFailure("openapi_extraction_failed", message)),
1829
- OpenApiOAuthError: ({ message }) => Effect3.succeed(openApiToolFailure("openapi_oauth_failed", message))
1830
- })
1831
- );
1832
- }
1833
- }),
1834
- tool({
1835
- name: "configureSource",
1836
- description: 'Configure an existing OpenAPI source with concrete fields. Use `source` returned by `openapi.addSource` or `sources.list`. The top-level `scope` is the credential target scope for bindings; in cloud, choose the user or organization credential scope deliberately. Pass secret refs as `{kind:"secret", secretId}` and OAuth connections as `{kind:"connection", connectionId}`.',
1837
- annotations: {
1838
- requiresApproval: true,
1839
- approvalDescription: "Configure an OpenAPI source"
1840
- },
1841
- inputSchema: OpenApiConfigureSourceInputStandardSchema,
1842
- outputSchema: OpenApiConfigureSourceOutputStandardSchema,
1843
- execute: (input, { ctx }) => {
1844
- const { source, ...config } = input;
1845
- const sourceScope = resolveStaticScopeInput(ctx, source.scope);
1846
- const targetScope = resolveStaticScopeInput(ctx, config.scope);
1847
- return Effect3.map(
1848
- self.configure(
1849
- { id: source.id, scope: sourceScope },
1850
- { ...config, scope: targetScope }
1851
- ),
1852
- (result) => ToolResult.ok({ result })
1853
- );
1854
- }
1855
- })
1856
- ]
1857
- }
1858
- ],
1859
- invokeTool: ({ ctx, toolRow, args }) => Effect3.gen(function* () {
1860
- const httpClientLayer = options?.httpClientLayer ?? ctx.httpClientLayer;
1861
- const toolScope = toolRow.scope_id;
1862
- const op = yield* ctx.storage.getOperationByToolId(toolRow.id, toolScope);
1863
- if (!op) {
1864
- return yield* new OpenApiExtractionError({
1865
- message: `No OpenAPI operation found for tool "${toolRow.id}"`
1866
- });
1867
- }
1868
- const source = yield* ctx.storage.getSource(op.sourceId, toolScope);
1869
- if (!source) {
1870
- return yield* new OpenApiExtractionError({
1871
- message: `No OpenAPI source found for "${op.sourceId}"`
1872
- });
1873
- }
1874
- const effective = yield* resolveEffectiveSourceConfig(ctx, source);
1875
- const config = effective.config;
1876
- const resolvedHeaders = yield* resolveConfiguredHeaders(ctx, {
1877
- sourceId: op.sourceId,
1878
- sourceScope: effective.headersSource.scope,
1879
- headers: config.headers ?? {}
1880
- });
1881
- const resolvedQueryParams = yield* resolveConfiguredValueMap(ctx, {
1882
- sourceId: op.sourceId,
1883
- sourceScope: effective.queryParamsSource.scope,
1884
- values: config.queryParams ?? {},
1885
- missingLabel: "query parameter"
1886
- });
1887
- if (config.oauth2) {
1888
- const oauth2 = config.oauth2;
1889
- const connection = yield* resolveOAuthConnectionId(ctx, {
1890
- sourceId: op.sourceId,
1891
- sourceScope: effective.oauth2Source.scope,
1892
- oauth2
1893
- });
1894
- if (!connection) {
1895
- return yield* new OpenApiAuthRequiredError({
1896
- code: "oauth_connection_missing",
1897
- sourceId: op.sourceId,
1898
- sourceScope: effective.oauth2Source.scope,
1899
- credentialKind: "connection",
1900
- credentialLabel: oauth2.flow === "clientCredentials" ? "OAuth client connection" : "OAuth sign-in",
1901
- slotKey: oauth2.connectionSlot,
1902
- message: `OAuth configuration for "${op.sourceId}" is missing a connection binding`
1903
- });
1904
- }
1905
- const accessToken = yield* ctx.connections.accessTokenAtScope(connection.connectionId, connection.scopeId).pipe(
1906
- Effect3.catchTags({
1907
- ConnectionReauthRequiredError: ({ message, connectionId }) => Effect3.fail(
1908
- new OpenApiAuthRequiredError({
1909
- code: "oauth_reauth_required",
1910
- sourceId: op.sourceId,
1911
- sourceScope: effective.oauth2Source.scope,
1912
- credentialKind: "oauth",
1913
- credentialLabel: oauth2.flow === "clientCredentials" ? "OAuth client connection" : "OAuth sign-in",
1914
- slotKey: oauth2.connectionSlot,
1915
- connectionId: String(connectionId),
1916
- message: `OAuth connection "${connectionId}" needs re-authentication: ${message}`
1917
- })
1918
- ),
1919
- ConnectionNotFoundError: ({ connectionId }) => Effect3.fail(
1920
- new OpenApiAuthRequiredError({
1921
- code: "oauth_connection_missing",
1922
- sourceId: op.sourceId,
1923
- sourceScope: effective.oauth2Source.scope,
1924
- credentialKind: "connection",
1925
- credentialLabel: oauth2.flow === "clientCredentials" ? "OAuth client connection" : "OAuth sign-in",
1926
- slotKey: oauth2.connectionSlot,
1927
- connectionId: String(connectionId),
1928
- message: `OAuth connection "${connectionId}" was not found for "${op.sourceId}"`
1929
- })
1930
- ),
1931
- ConnectionProviderNotRegisteredError: ({ provider }) => Effect3.fail(
1932
- new OpenApiAuthRequiredError({
1933
- code: "oauth_connection_failed",
1934
- sourceId: op.sourceId,
1935
- sourceScope: effective.oauth2Source.scope,
1936
- credentialKind: "oauth",
1937
- credentialLabel: oauth2.flow === "clientCredentials" ? "OAuth client connection" : "OAuth sign-in",
1938
- slotKey: oauth2.connectionSlot,
1939
- connectionId: connection.connectionId,
1940
- message: `OAuth provider "${provider}" is not registered`
1941
- })
1942
- ),
1943
- ConnectionRefreshNotSupportedError: ({ provider, connectionId }) => Effect3.fail(
1944
- new OpenApiAuthRequiredError({
1945
- code: "oauth_connection_failed",
1946
- sourceId: op.sourceId,
1947
- sourceScope: effective.oauth2Source.scope,
1948
- credentialKind: "oauth",
1949
- credentialLabel: oauth2.flow === "clientCredentials" ? "OAuth client connection" : "OAuth sign-in",
1950
- slotKey: oauth2.connectionSlot,
1951
- connectionId: String(connectionId),
1952
- message: `OAuth provider "${provider}" cannot refresh connection "${connectionId}"`
1953
- })
1954
- ),
1955
- ConnectionRefreshError: ({ message, connectionId }) => Effect3.fail(
1956
- new OpenApiAuthRequiredError({
1957
- code: "oauth_connection_failed",
1958
- sourceId: op.sourceId,
1959
- sourceScope: effective.oauth2Source.scope,
1960
- credentialKind: "oauth",
1961
- credentialLabel: oauth2.flow === "clientCredentials" ? "OAuth client connection" : "OAuth sign-in",
1962
- slotKey: oauth2.connectionSlot,
1963
- connectionId: String(connectionId),
1964
- message: `OAuth connection "${connectionId}" refresh failed: ${message}`
1965
- })
1966
- )
1967
- })
1968
- );
1969
- resolvedHeaders.authorization = `Bearer ${accessToken}`;
1970
- }
1971
- const result = yield* invokeWithLayer(
1972
- op.binding,
1973
- args ?? {},
1974
- config.baseUrl ?? "",
1975
- resolvedHeaders,
1976
- resolvedQueryParams,
1977
- httpClientLayer
1978
- );
1979
- const ok = result.status >= 200 && result.status < 300;
1980
- if (!ok) {
1981
- if (result.status === 401 || result.status === 403) {
1982
- return authToolFailure({
1983
- code: "credential_rejected",
1984
- status: result.status,
1985
- message: `Upstream rejected credentials for "${op.sourceId}" with HTTP ${result.status}. Re-authenticate or update the source credentials before retrying this tool.`,
1986
- source: { id: op.sourceId, scope: toolScope },
1987
- credential: { kind: "upstream", label: "Upstream authorization" },
1988
- upstream: { status: result.status, details: result.error },
1989
- recovery: { configureSourceTool: "executor.openapi.configureSource" }
1990
- });
1991
- }
1992
- return ToolResult.fail({
1993
- code: "upstream_http_error",
1994
- status: result.status,
1995
- message: extractUpstreamMessage(result.error, result.status),
1996
- details: result.error
1997
- });
1998
- }
1999
- return ToolResult.ok({
2000
- status: result.status,
2001
- headers: result.headers,
2002
- data: result.data
2003
- });
2004
- }).pipe(
2005
- Effect3.catchTag(
2006
- "OpenApiAuthRequiredError",
2007
- (error) => Effect3.succeed(openApiAuthToolFailure(error))
2008
- )
2009
- ),
2010
- resolveAnnotations: ({ ctx, sourceId, toolRows }) => Effect3.gen(function* () {
2011
- const scopes = /* @__PURE__ */ new Set();
2012
- for (const row of toolRows) {
2013
- scopes.add(row.scope_id);
2014
- }
2015
- const entries = yield* Effect3.forEach(
2016
- [...scopes],
2017
- (scope) => Effect3.gen(function* () {
2018
- const ops = yield* ctx.storage.listOperationsBySource(sourceId, scope);
2019
- const byId = /* @__PURE__ */ new Map();
2020
- for (const op of ops) byId.set(op.toolId, op.binding);
2021
- return [scope, byId];
2022
- }),
2023
- { concurrency: "unbounded" }
2024
- );
2025
- const byScope = new Map(entries);
2026
- const out = {};
2027
- for (const row of toolRows) {
2028
- const binding = byScope.get(row.scope_id)?.get(row.id);
2029
- if (binding) {
2030
- out[row.id] = annotationsForOperation(binding.method, binding.pathTemplate);
2031
- }
2032
- }
2033
- return out;
2034
- }),
2035
- removeSource: ({ ctx, sourceId, scope }) => Effect3.gen(function* () {
2036
- yield* ctx.transaction(
2037
- Effect3.gen(function* () {
2038
- yield* ctx.credentialBindings.removeForSource({
2039
- pluginId: OPENAPI_PLUGIN_ID,
2040
- sourceId,
2041
- sourceScope: ScopeId.make(scope)
2042
- });
2043
- yield* ctx.storage.removeSource(sourceId, scope);
2044
- })
2045
- );
2046
- if (options?.configFile) {
2047
- yield* options.configFile.removeSource(sourceId);
2048
- }
2049
- }),
2050
- // OpenAPI credential usages are reported by the core `credential_binding`
2051
- // table. Source storage carries only source-owned slot structure.
2052
- usagesForSecret: () => Effect3.succeed([]),
2053
- usagesForConnection: () => Effect3.succeed([]),
2054
- // Re-fetch the spec from its origin URL (captured at addSpec time)
2055
- // and replay the same parse → extract → upsertSource → register
2056
- // path used by addSpec. Sources without a stored URL surface a
2057
- // typed `OpenApiParseError` — the executor only dispatches refresh
2058
- // when `canRefresh: true`, so a raw-text source reaching here
2059
- // means stale UI state, which is worth surfacing to the caller.
2060
- refreshSource: ({ ctx, sourceId, scope }) => refreshSourceInternal(ctx, sourceId, scope),
2061
- detect: ({ ctx, url }) => Effect3.gen(function* () {
2062
- const httpClientLayer = options?.httpClientLayer ?? ctx.httpClientLayer;
2063
- const trimmed = url.trim();
2064
- if (!trimmed) return null;
2065
- const parsed = yield* Effect3.try({
2066
- try: () => new URL(trimmed),
2067
- catch: (error) => error
2068
- }).pipe(Effect3.option);
2069
- if (Option3.isNone(parsed)) return null;
2070
- const specText = yield* resolveSpecText(trimmed).pipe(
2071
- Effect3.provide(httpClientLayer),
2072
- Effect3.catch(() => Effect3.succeed(null))
2073
- );
2074
- if (specText === null) return null;
2075
- const doc = yield* parse(specText).pipe(Effect3.catch(() => Effect3.succeed(null)));
2076
- if (!doc) return null;
2077
- const result = yield* extract(doc).pipe(Effect3.catch(() => Effect3.succeed(null)));
2078
- if (!result) return null;
2079
- const namespace = Option3.getOrElse(result.title, () => "api").toLowerCase().replace(/[^a-z0-9]+/g, "_");
2080
- const name = Option3.getOrElse(result.title, () => namespace);
2081
- return SourceDetectionResult.make({
2082
- kind: "openapi",
2083
- confidence: "high",
2084
- endpoint: trimmed,
2085
- name,
2086
- namespace
2087
- });
2088
- })
2089
- };
2090
- });
2091
-
2092
- export {
2093
- resolveHeaders,
2094
- invoke,
2095
- invokeWithLayer,
2096
- annotationsForOperation,
2097
- openapiSchema,
2098
- makeDefaultOpenapiStore,
2099
- openApiPlugin
2100
- };
2101
- //# sourceMappingURL=chunk-PRVJDE43.js.map