@executor-js/plugin-openapi 1.5.15 → 1.5.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AddOpenApiSource-U7AYB224.js +369 -0
- package/dist/AddOpenApiSource-U7AYB224.js.map +1 -0
- package/dist/{OpenApiAccountsPanel-X5Z5XKRM.js → OpenApiAccountsPanel-GHFHHE6P.js} +15 -39
- package/dist/OpenApiAccountsPanel-GHFHHE6P.js.map +1 -0
- package/dist/{UpdateSpecSection-Z2DEEWZW.js → UpdateSpecSection-PLCBUU4I.js} +4 -4
- package/dist/UpdateSpecSection-PLCBUU4I.js.map +1 -0
- package/dist/api/group.d.ts +0 -21
- package/dist/api/index.d.ts +0 -21
- package/dist/{chunk-ZTOOUP67.js → chunk-3FM2SWM4.js} +542 -580
- package/dist/chunk-3FM2SWM4.js.map +1 -0
- package/dist/chunk-CKBX4SXK.js +95 -0
- package/dist/chunk-CKBX4SXK.js.map +1 -0
- package/dist/{chunk-NJ4Q3VF4.js → chunk-CPPTKUOW.js} +5 -14
- package/dist/chunk-CPPTKUOW.js.map +1 -0
- package/dist/{chunk-O54VFSWE.js → chunk-KVPUDOJZ.js} +18 -4
- package/dist/chunk-KVPUDOJZ.js.map +1 -0
- package/dist/{chunk-PAHWRRS3.js → chunk-QQFCICLX.js} +4 -13
- package/dist/chunk-QQFCICLX.js.map +1 -0
- package/dist/client.js +4 -5
- package/dist/client.js.map +1 -1
- package/dist/core.js +25 -15
- package/dist/core.js.map +1 -1
- package/dist/index.js +4 -5
- package/dist/index.js.map +1 -1
- package/dist/react/atoms.d.ts +0 -22
- package/dist/react/client.d.ts +0 -21
- package/dist/react/index.d.ts +2 -0
- package/dist/sdk/backing.d.ts +54 -0
- package/dist/sdk/config.d.ts +0 -2
- package/dist/sdk/derive-auth.d.ts +5 -3
- package/dist/sdk/index.d.ts +2 -1
- package/dist/sdk/plugin.d.ts +4 -10
- package/dist/sdk/presets.d.ts +0 -1
- package/dist/sdk/preview.d.ts +79 -0
- package/dist/testing/index.d.ts +0 -6
- package/package.json +6 -5
- package/dist/AddOpenApiSource-IRMLVLDK.js +0 -765
- package/dist/AddOpenApiSource-IRMLVLDK.js.map +0 -1
- package/dist/OpenApiAccountsPanel-X5Z5XKRM.js.map +0 -1
- package/dist/UpdateSpecSection-Z2DEEWZW.js.map +0 -1
- package/dist/chunk-MZWZQ24W.js +0 -226
- package/dist/chunk-MZWZQ24W.js.map +0 -1
- package/dist/chunk-NJ4Q3VF4.js.map +0 -1
- package/dist/chunk-O54VFSWE.js.map +0 -1
- package/dist/chunk-PAHWRRS3.js.map +0 -1
- package/dist/chunk-UOLBAX5D.js +0 -712
- package/dist/chunk-UOLBAX5D.js.map +0 -1
- package/dist/chunk-ZTOOUP67.js.map +0 -1
- package/dist/react/GoogleProductPicker.d.ts +0 -9
- package/dist/sdk/google-discovery.d.ts +0 -43
- package/dist/sdk/google-discovery.test.d.ts +0 -1
- package/dist/sdk/google-oauth-batches.d.ts +0 -13
- package/dist/sdk/google-oauth-batches.test.d.ts +0 -1
- package/dist/sdk/google-oauth-scopes.d.ts +0 -3
- package/dist/sdk/google-oauth-scopes.test.d.ts +0 -1
- package/dist/sdk/google-presets.d.ts +0 -16
- package/dist/sdk/google-presets.test.d.ts +0 -1
- package/dist/sdk/google-product-picker-scopes.test.d.ts +0 -1
- /package/dist/sdk/{google-bundle.test.d.ts → store.test.d.ts} +0 -0
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
|
-
convertGoogleDiscoveryBundleToOpenApi,
|
|
3
|
-
convertGoogleDiscoveryToOpenApi,
|
|
4
2
|
deriveAuthenticationTemplateFromPreview,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
isGoogleDiscoveryUrl
|
|
8
|
-
} from "./chunk-UOLBAX5D.js";
|
|
3
|
+
firstBaseUrlForPreview
|
|
4
|
+
} from "./chunk-CKBX4SXK.js";
|
|
9
5
|
import {
|
|
10
6
|
openApiPresets
|
|
11
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-QQFCICLX.js";
|
|
12
8
|
import {
|
|
13
9
|
InvocationResult,
|
|
14
10
|
OpenApiExtractionError,
|
|
@@ -18,11 +14,10 @@ import {
|
|
|
18
14
|
extract,
|
|
19
15
|
normalizeOpenApiAuthInputs,
|
|
20
16
|
parse,
|
|
21
|
-
previewSpec,
|
|
22
17
|
previewSpecText,
|
|
23
18
|
resolveServerUrl,
|
|
24
19
|
resolveSpecText
|
|
25
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-KVPUDOJZ.js";
|
|
26
21
|
|
|
27
22
|
// src/sdk/config.ts
|
|
28
23
|
import { Option, Schema } from "effect";
|
|
@@ -46,8 +41,6 @@ var OpenApiIntegrationConfigSchema = Schema.Struct({
|
|
|
46
41
|
specHash: Schema.optional(Schema.String),
|
|
47
42
|
/** Origin URL the spec was fetched from, when known. Enables refresh. */
|
|
48
43
|
sourceUrl: Schema.optional(Schema.String),
|
|
49
|
-
/** Google Discovery bundle URLs, when the spec came from a Google bundle. */
|
|
50
|
-
googleDiscoveryUrls: Schema.optional(Schema.Array(Schema.String)),
|
|
51
44
|
/** Optional base URL override. */
|
|
52
45
|
baseUrl: Schema.optional(Schema.String),
|
|
53
46
|
/** Static headers applied to every request (no secret material). */
|
|
@@ -73,8 +66,101 @@ var requiredTemplateVariables = (template) => {
|
|
|
73
66
|
return requiredPlacementVariables(template.placements);
|
|
74
67
|
};
|
|
75
68
|
|
|
69
|
+
// src/sdk/store.ts
|
|
70
|
+
import { Effect, Option as Option2, Predicate, Schema as Schema2 } from "effect";
|
|
71
|
+
var OPERATION_COLLECTION = "operation";
|
|
72
|
+
var STORE_OWNER = "org";
|
|
73
|
+
var OPERATION_KEY_VERSION = "op";
|
|
74
|
+
var encodeBinding = Schema2.encodeSync(OperationBinding);
|
|
75
|
+
var decodeBinding = Schema2.decodeUnknownSync(OperationBinding);
|
|
76
|
+
var decodeBindingJson = Schema2.decodeUnknownSync(Schema2.fromJsonString(OperationBinding));
|
|
77
|
+
var toJsonRecord = (value) => value;
|
|
78
|
+
var OperationStorage = Schema2.Struct({
|
|
79
|
+
integration: Schema2.String,
|
|
80
|
+
toolName: Schema2.String,
|
|
81
|
+
binding: Schema2.Unknown
|
|
82
|
+
});
|
|
83
|
+
var decodeOperationStorage = Schema2.decodeUnknownOption(OperationStorage);
|
|
84
|
+
var rowToOperation = (row) => {
|
|
85
|
+
const decoded = decodeOperationStorage(row.data);
|
|
86
|
+
if (Option2.isNone(decoded)) return null;
|
|
87
|
+
const operation = decoded.value;
|
|
88
|
+
return {
|
|
89
|
+
integration: operation.integration,
|
|
90
|
+
toolName: operation.toolName,
|
|
91
|
+
binding: decodeBinding(
|
|
92
|
+
typeof operation.binding === "string" ? decodeBindingJson(operation.binding) : operation.binding
|
|
93
|
+
)
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
var stableKeyHash = (value) => {
|
|
97
|
+
let hash = 0xcbf29ce484222325n;
|
|
98
|
+
const prime = 0x100000001b3n;
|
|
99
|
+
const mask = 0xffffffffffffffffn;
|
|
100
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
101
|
+
hash ^= BigInt(value.charCodeAt(index));
|
|
102
|
+
hash = hash * prime & mask;
|
|
103
|
+
}
|
|
104
|
+
return hash.toString(36).padStart(13, "0");
|
|
105
|
+
};
|
|
106
|
+
var operationKey = (integration, toolName) => `${OPERATION_KEY_VERSION}.${stableKeyHash(integration)}.${stableKeyHash(toolName)}`;
|
|
107
|
+
var legacyOperationKey = (integration, toolName) => `${integration}.${toolName}`;
|
|
108
|
+
var specBlobKey = (specHash) => `spec/${specHash}`;
|
|
109
|
+
var makeDefaultOpenapiStore = ({ pluginStorage, blobs }) => {
|
|
110
|
+
const operationData = (operation) => ({
|
|
111
|
+
integration: operation.integration,
|
|
112
|
+
toolName: operation.toolName,
|
|
113
|
+
binding: toJsonRecord(encodeBinding(operation.binding))
|
|
114
|
+
});
|
|
115
|
+
const listRows = (integration) => pluginStorage.list({ collection: OPERATION_COLLECTION }).pipe(
|
|
116
|
+
Effect.map(
|
|
117
|
+
(rows) => rows.filter((row) => rowToOperation(row)?.integration === integration)
|
|
118
|
+
)
|
|
119
|
+
);
|
|
120
|
+
const removeOperations = (integration) => Effect.gen(function* () {
|
|
121
|
+
const rows = yield* listRows(integration);
|
|
122
|
+
yield* pluginStorage.removeMany({
|
|
123
|
+
owner: STORE_OWNER,
|
|
124
|
+
entries: rows.map((row) => ({ collection: OPERATION_COLLECTION, key: row.key }))
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
return {
|
|
128
|
+
putOperations: (integration, operations) => Effect.gen(function* () {
|
|
129
|
+
yield* removeOperations(integration);
|
|
130
|
+
yield* pluginStorage.putMany({
|
|
131
|
+
owner: STORE_OWNER,
|
|
132
|
+
entries: operations.map((operation) => ({
|
|
133
|
+
collection: OPERATION_COLLECTION,
|
|
134
|
+
key: operationKey(integration, operation.toolName),
|
|
135
|
+
data: operationData(operation)
|
|
136
|
+
}))
|
|
137
|
+
});
|
|
138
|
+
}),
|
|
139
|
+
getOperation: (integration, toolName) => Effect.gen(function* () {
|
|
140
|
+
const row = yield* pluginStorage.get({
|
|
141
|
+
collection: OPERATION_COLLECTION,
|
|
142
|
+
key: operationKey(integration, toolName)
|
|
143
|
+
});
|
|
144
|
+
if (row) return rowToOperation(row);
|
|
145
|
+
const legacyKey = legacyOperationKey(integration, toolName);
|
|
146
|
+
if (legacyKey.length > 255) return null;
|
|
147
|
+
const legacyRow = yield* pluginStorage.get({
|
|
148
|
+
collection: OPERATION_COLLECTION,
|
|
149
|
+
key: legacyKey
|
|
150
|
+
});
|
|
151
|
+
return legacyRow ? rowToOperation(legacyRow) : null;
|
|
152
|
+
}),
|
|
153
|
+
listOperations: (integration) => listRows(integration).pipe(
|
|
154
|
+
Effect.map((rows) => rows.map(rowToOperation).filter(Predicate.isNotNull))
|
|
155
|
+
),
|
|
156
|
+
removeOperations,
|
|
157
|
+
putSpec: (specHash, specText) => blobs.put(specBlobKey(specHash), specText, { owner: STORE_OWNER }),
|
|
158
|
+
getSpec: (specHash) => blobs.get(specBlobKey(specHash))
|
|
159
|
+
};
|
|
160
|
+
};
|
|
161
|
+
|
|
76
162
|
// src/sdk/invoke.ts
|
|
77
|
-
import { Effect, Layer, Option as
|
|
163
|
+
import { Effect as Effect2, Layer, Option as Option3 } from "effect";
|
|
78
164
|
import { HttpClient, HttpClientRequest } from "effect/unstable/http";
|
|
79
165
|
var CONTAINER_KEYS = {
|
|
80
166
|
path: ["path", "pathParams", "params"],
|
|
@@ -107,13 +193,13 @@ var encodeReservedAware = (raw, allowReserved) => {
|
|
|
107
193
|
var queryParamValues = (value, param) => {
|
|
108
194
|
if (value === void 0 || value === null) return [];
|
|
109
195
|
if (!Array.isArray(value)) return [primitiveToString(value)];
|
|
110
|
-
const style =
|
|
111
|
-
const explode =
|
|
196
|
+
const style = Option3.getOrUndefined(param.style) ?? "form";
|
|
197
|
+
const explode = Option3.getOrElse(param.explode, () => true);
|
|
112
198
|
if (explode) return value.map(primitiveToString);
|
|
113
199
|
const separator = style === "spaceDelimited" ? " " : style === "pipeDelimited" ? "|" : ",";
|
|
114
200
|
return [value.map(primitiveToString).join(separator)];
|
|
115
201
|
};
|
|
116
|
-
var resolvePath =
|
|
202
|
+
var resolvePath = Effect2.fn("OpenApi.resolvePath")(function* (pathTemplate, args, parameters) {
|
|
117
203
|
let resolved = pathTemplate;
|
|
118
204
|
for (const param of parameters) {
|
|
119
205
|
if (param.location !== "path") continue;
|
|
@@ -122,14 +208,14 @@ var resolvePath = Effect.fn("OpenApi.resolvePath")(function* (pathTemplate, args
|
|
|
122
208
|
if (param.required) {
|
|
123
209
|
return yield* new OpenApiInvocationError({
|
|
124
210
|
message: `Missing required path parameter: ${param.name}`,
|
|
125
|
-
statusCode:
|
|
211
|
+
statusCode: Option3.none()
|
|
126
212
|
});
|
|
127
213
|
}
|
|
128
214
|
continue;
|
|
129
215
|
}
|
|
130
216
|
const encoded = encodeReservedAware(
|
|
131
217
|
String(value),
|
|
132
|
-
|
|
218
|
+
Option3.getOrElse(param.allowReserved, () => false)
|
|
133
219
|
);
|
|
134
220
|
resolved = resolved.replaceAll(`{${param.name}}`, encoded);
|
|
135
221
|
resolved = resolved.replaceAll(`{+${param.name}}`, encoded);
|
|
@@ -145,7 +231,7 @@ var resolvePath = Effect.fn("OpenApi.resolvePath")(function* (pathTemplate, args
|
|
|
145
231
|
if (unresolved.length > 0) {
|
|
146
232
|
return yield* new OpenApiInvocationError({
|
|
147
233
|
message: `Unresolved path parameters: ${[...new Set(unresolved)].join(", ")}`,
|
|
148
|
-
statusCode:
|
|
234
|
+
statusCode: Option3.none()
|
|
149
235
|
});
|
|
150
236
|
}
|
|
151
237
|
return resolved;
|
|
@@ -250,9 +336,9 @@ var toUint8Array = (value) => {
|
|
|
250
336
|
}
|
|
251
337
|
return null;
|
|
252
338
|
};
|
|
253
|
-
var readHintString = (option, fallback) =>
|
|
254
|
-
var readHintMimeType = (hint, fallback) =>
|
|
255
|
-
var readHintEncoding = (hint) =>
|
|
339
|
+
var readHintString = (option, fallback) => Option3.getOrElse(option, () => fallback);
|
|
340
|
+
var readHintMimeType = (hint, fallback) => Option3.getOrElse(hint.mimeType, () => fallback);
|
|
341
|
+
var readHintEncoding = (hint) => Option3.getOrElse(hint.encoding, () => "base64");
|
|
256
342
|
var fileFromByteField = (body, hint) => {
|
|
257
343
|
if (typeof body !== "object" || body === null || Array.isArray(body)) return null;
|
|
258
344
|
const record = body;
|
|
@@ -260,7 +346,7 @@ var fileFromByteField = (body, hint) => {
|
|
|
260
346
|
const rawData = record[dataField];
|
|
261
347
|
if (typeof rawData !== "string") return null;
|
|
262
348
|
const data = normalizeBase64(rawData, readHintEncoding(hint));
|
|
263
|
-
const sizeField =
|
|
349
|
+
const sizeField = Option3.getOrUndefined(hint.sizeField);
|
|
264
350
|
const byteLength = sizeField && typeof record[sizeField] === "number" ? record[sizeField] : byteLengthFromBase64(data);
|
|
265
351
|
const hintedMimeType = readHintMimeType(hint, "application/octet-stream");
|
|
266
352
|
return {
|
|
@@ -294,9 +380,9 @@ var DEFAULT_FORM_STYLE = {
|
|
|
294
380
|
var resolveStyleExplode = (e) => {
|
|
295
381
|
if (!e) return DEFAULT_FORM_STYLE;
|
|
296
382
|
return {
|
|
297
|
-
style:
|
|
298
|
-
explode:
|
|
299
|
-
allowReserved:
|
|
383
|
+
style: Option3.getOrElse(e.style, () => DEFAULT_FORM_STYLE.style),
|
|
384
|
+
explode: Option3.getOrElse(e.explode, () => DEFAULT_FORM_STYLE.explode),
|
|
385
|
+
allowReserved: Option3.getOrElse(e.allowReserved, () => DEFAULT_FORM_STYLE.allowReserved)
|
|
300
386
|
};
|
|
301
387
|
};
|
|
302
388
|
var encodeFormValue = (v, allowReserved) => {
|
|
@@ -356,7 +442,7 @@ var coerceFormDataRecord = (value, encoding) => {
|
|
|
356
442
|
const out = {};
|
|
357
443
|
for (const [key, raw] of Object.entries(value)) {
|
|
358
444
|
if (raw === void 0 || raw === null) continue;
|
|
359
|
-
const partType = encoding?.[key] ?
|
|
445
|
+
const partType = encoding?.[key] ? Option3.getOrUndefined(encoding[key].contentType) : void 0;
|
|
360
446
|
if (partType) {
|
|
361
447
|
const isJson = partType.startsWith("application/json") || partType.includes("+json");
|
|
362
448
|
const serialized = typeof raw === "string" ? raw : isJson ? JSON.stringify(raw) : typeof raw === "object" ? JSON.stringify(raw) : String(raw);
|
|
@@ -437,9 +523,9 @@ var applyRequestBody = (request, contentType, bodyValue, encoding) => {
|
|
|
437
523
|
if (bytes) return HttpClientRequest.bodyUint8Array(request, bytes, contentType);
|
|
438
524
|
return HttpClientRequest.bodyText(request, JSON.stringify(bodyValue), contentType);
|
|
439
525
|
};
|
|
440
|
-
var invoke =
|
|
526
|
+
var invoke = Effect2.fn("OpenApi.invoke")(function* (operation, args, resolvedHeaders, sourceQueryParams = {}) {
|
|
441
527
|
const client = yield* HttpClient.HttpClient;
|
|
442
|
-
yield*
|
|
528
|
+
yield* Effect2.annotateCurrentSpan({
|
|
443
529
|
"http.method": operation.method.toUpperCase(),
|
|
444
530
|
"http.route": operation.pathTemplate,
|
|
445
531
|
"plugin.openapi.method": operation.method.toUpperCase(),
|
|
@@ -465,50 +551,50 @@ var invoke = Effect.fn("OpenApi.invoke")(function* (operation, args, resolvedHea
|
|
|
465
551
|
if (value === void 0 || value === null) continue;
|
|
466
552
|
request = HttpClientRequest.setHeader(request, param.name, String(value));
|
|
467
553
|
}
|
|
468
|
-
if (
|
|
554
|
+
if (Option3.isSome(operation.requestBody)) {
|
|
469
555
|
const rb = operation.requestBody.value;
|
|
470
556
|
const bodyValue = args.body ?? args.input;
|
|
471
557
|
if (bodyValue !== void 0) {
|
|
472
|
-
const contentsOpt =
|
|
558
|
+
const contentsOpt = Option3.getOrUndefined(rb.contents);
|
|
473
559
|
const requestedCt = typeof args.contentType === "string" ? args.contentType : void 0;
|
|
474
560
|
const selected = contentsOpt && requestedCt ? contentsOpt.find((c) => c.contentType === requestedCt) : void 0;
|
|
475
561
|
const chosenCt = selected?.contentType ?? rb.contentType;
|
|
476
|
-
const chosenEncoding = selected ?
|
|
562
|
+
const chosenEncoding = selected ? Option3.getOrUndefined(selected.encoding) : contentsOpt && contentsOpt[0] ? Option3.getOrUndefined(contentsOpt[0].encoding) : void 0;
|
|
477
563
|
request = applyRequestBody(request, chosenCt, bodyValue, chosenEncoding);
|
|
478
564
|
}
|
|
479
565
|
}
|
|
480
566
|
request = applyHeaders(request, resolvedHeaders);
|
|
481
567
|
const response = yield* client.execute(request).pipe(
|
|
482
|
-
|
|
568
|
+
Effect2.mapError(
|
|
483
569
|
(err) => new OpenApiInvocationError({
|
|
484
570
|
message: "HTTP request failed",
|
|
485
|
-
statusCode:
|
|
571
|
+
statusCode: Option3.none(),
|
|
486
572
|
cause: err
|
|
487
573
|
})
|
|
488
574
|
)
|
|
489
575
|
);
|
|
490
576
|
const status = response.status;
|
|
491
|
-
yield*
|
|
577
|
+
yield* Effect2.annotateCurrentSpan({
|
|
492
578
|
"http.status_code": status
|
|
493
579
|
});
|
|
494
580
|
const responseHeaders = { ...response.headers };
|
|
495
581
|
const contentType = response.headers["content-type"] ?? null;
|
|
496
|
-
const mapBodyError =
|
|
582
|
+
const mapBodyError = Effect2.mapError(
|
|
497
583
|
(err) => new OpenApiInvocationError({
|
|
498
584
|
message: "Failed to read response body",
|
|
499
|
-
statusCode:
|
|
585
|
+
statusCode: Option3.some(status),
|
|
500
586
|
cause: err
|
|
501
587
|
})
|
|
502
588
|
);
|
|
503
|
-
const responseBodyBinding =
|
|
504
|
-
const fileHint = responseBodyBinding ?
|
|
589
|
+
const responseBodyBinding = Option3.getOrUndefined(operation.responseBody);
|
|
590
|
+
const fileHint = responseBodyBinding ? Option3.getOrUndefined(responseBodyBinding.fileHint) : void 0;
|
|
505
591
|
const ok = status >= 200 && status < 300;
|
|
506
592
|
const responseBody = status === 204 ? null : ok && fileHint?.kind === "binaryResponse" ? fileFromBinaryBytes(
|
|
507
593
|
new Uint8Array(yield* response.arrayBuffer.pipe(mapBodyError)),
|
|
508
594
|
fileHint,
|
|
509
595
|
contentType
|
|
510
596
|
) : isJsonContentType(contentType) ? yield* response.json.pipe(
|
|
511
|
-
|
|
597
|
+
Effect2.catch(() => response.text),
|
|
512
598
|
mapBodyError
|
|
513
599
|
) : yield* response.text.pipe(mapBodyError);
|
|
514
600
|
const dataBody = ok && fileHint?.kind === "byteField" ? fileFromByteField(responseBody, fileHint) ?? responseBody : responseBody;
|
|
@@ -530,25 +616,25 @@ var resolveRequestHost = (servers, serverArg, baseUrl) => {
|
|
|
530
616
|
if (value != null && value !== "") overrides[name] = String(value);
|
|
531
617
|
}
|
|
532
618
|
}
|
|
533
|
-
return resolveServerUrl(chosen.url,
|
|
619
|
+
return resolveServerUrl(chosen.url, Option3.getOrUndefined(chosen.variables), overrides);
|
|
534
620
|
};
|
|
535
621
|
var invokeWithLayer = (operation, args, baseUrl, resolvedHeaders, sourceQueryParams, httpClientLayer) => {
|
|
536
622
|
const effectiveBaseUrl = resolveRequestHost(operation.servers ?? [], args.server, baseUrl);
|
|
537
623
|
const clientWithBaseUrl = effectiveBaseUrl ? Layer.effect(
|
|
538
624
|
HttpClient.HttpClient,
|
|
539
|
-
|
|
540
|
-
|
|
625
|
+
Effect2.map(
|
|
626
|
+
Effect2.service(HttpClient.HttpClient),
|
|
541
627
|
HttpClient.mapRequest(HttpClientRequest.prependUrl(effectiveBaseUrl))
|
|
542
628
|
)
|
|
543
629
|
).pipe(Layer.provide(httpClientLayer)) : httpClientLayer;
|
|
544
630
|
return invoke(operation, args, resolvedHeaders, sourceQueryParams).pipe(
|
|
545
|
-
|
|
631
|
+
Effect2.provide(clientWithBaseUrl),
|
|
546
632
|
// `invoke` annotates http.status_code on ITS span (`OpenApi.invoke`,
|
|
547
633
|
// via Effect.fn) — annotateCurrentSpan inside it never reaches this
|
|
548
634
|
// wrapper span. Stamp the status here too so queries against
|
|
549
635
|
// `plugin.openapi.invoke` see the upstream outcome directly.
|
|
550
|
-
|
|
551
|
-
|
|
636
|
+
Effect2.tap((result) => Effect2.annotateCurrentSpan({ "http.status_code": result.status })),
|
|
637
|
+
Effect2.withSpan("plugin.openapi.invoke", {
|
|
552
638
|
attributes: {
|
|
553
639
|
"plugin.openapi.method": operation.method.toUpperCase(),
|
|
554
640
|
"plugin.openapi.path_template": operation.pathTemplate,
|
|
@@ -567,89 +653,13 @@ var annotationsForOperation = (method, pathTemplate) => {
|
|
|
567
653
|
};
|
|
568
654
|
};
|
|
569
655
|
|
|
570
|
-
// src/sdk/
|
|
571
|
-
import { Effect as Effect2, Option as Option3, Predicate, Schema as Schema2 } from "effect";
|
|
572
|
-
var OPERATION_COLLECTION = "operation";
|
|
573
|
-
var STORE_OWNER = "org";
|
|
574
|
-
var encodeBinding = Schema2.encodeSync(OperationBinding);
|
|
575
|
-
var decodeBinding = Schema2.decodeUnknownSync(OperationBinding);
|
|
576
|
-
var decodeBindingJson = Schema2.decodeUnknownSync(Schema2.fromJsonString(OperationBinding));
|
|
577
|
-
var toJsonRecord = (value) => value;
|
|
578
|
-
var OperationStorage = Schema2.Struct({
|
|
579
|
-
integration: Schema2.String,
|
|
580
|
-
toolName: Schema2.String,
|
|
581
|
-
binding: Schema2.Unknown
|
|
582
|
-
});
|
|
583
|
-
var decodeOperationStorage = Schema2.decodeUnknownOption(OperationStorage);
|
|
584
|
-
var rowToOperation = (row) => {
|
|
585
|
-
const decoded = decodeOperationStorage(row.data);
|
|
586
|
-
if (Option3.isNone(decoded)) return null;
|
|
587
|
-
const operation = decoded.value;
|
|
588
|
-
return {
|
|
589
|
-
integration: operation.integration,
|
|
590
|
-
toolName: operation.toolName,
|
|
591
|
-
binding: decodeBinding(
|
|
592
|
-
typeof operation.binding === "string" ? decodeBindingJson(operation.binding) : operation.binding
|
|
593
|
-
)
|
|
594
|
-
};
|
|
595
|
-
};
|
|
596
|
-
var operationKey = (integration, toolName) => `${integration}.${toolName}`;
|
|
597
|
-
var specBlobKey = (specHash) => `spec/${specHash}`;
|
|
598
|
-
var makeDefaultOpenapiStore = ({ pluginStorage, blobs }) => {
|
|
599
|
-
const operationData = (operation) => ({
|
|
600
|
-
integration: operation.integration,
|
|
601
|
-
toolName: operation.toolName,
|
|
602
|
-
binding: toJsonRecord(encodeBinding(operation.binding))
|
|
603
|
-
});
|
|
604
|
-
const listRows = (integration) => pluginStorage.list({ collection: OPERATION_COLLECTION, keyPrefix: `${integration}.` }).pipe(
|
|
605
|
-
Effect2.map(
|
|
606
|
-
(rows) => rows.filter((row) => rowToOperation(row)?.integration === integration)
|
|
607
|
-
)
|
|
608
|
-
);
|
|
609
|
-
const removeOperations = (integration) => Effect2.gen(function* () {
|
|
610
|
-
const rows = yield* listRows(integration);
|
|
611
|
-
yield* pluginStorage.removeMany({
|
|
612
|
-
owner: STORE_OWNER,
|
|
613
|
-
entries: rows.map((row) => ({ collection: OPERATION_COLLECTION, key: row.key }))
|
|
614
|
-
});
|
|
615
|
-
});
|
|
616
|
-
return {
|
|
617
|
-
putOperations: (integration, operations) => Effect2.gen(function* () {
|
|
618
|
-
yield* removeOperations(integration);
|
|
619
|
-
yield* pluginStorage.putMany({
|
|
620
|
-
owner: STORE_OWNER,
|
|
621
|
-
entries: operations.map((operation) => ({
|
|
622
|
-
collection: OPERATION_COLLECTION,
|
|
623
|
-
key: operationKey(integration, operation.toolName),
|
|
624
|
-
data: operationData(operation)
|
|
625
|
-
}))
|
|
626
|
-
});
|
|
627
|
-
}),
|
|
628
|
-
getOperation: (integration, toolName) => pluginStorage.get({ collection: OPERATION_COLLECTION, key: operationKey(integration, toolName) }).pipe(Effect2.map((row) => row ? rowToOperation(row) : null)),
|
|
629
|
-
listOperations: (integration) => listRows(integration).pipe(
|
|
630
|
-
Effect2.map((rows) => rows.map(rowToOperation).filter(Predicate.isNotNull))
|
|
631
|
-
),
|
|
632
|
-
removeOperations,
|
|
633
|
-
putSpec: (specHash, specText) => blobs.put(specBlobKey(specHash), specText, { owner: STORE_OWNER }),
|
|
634
|
-
getSpec: (specHash) => blobs.get(specBlobKey(specHash))
|
|
635
|
-
};
|
|
636
|
-
};
|
|
637
|
-
|
|
638
|
-
// src/sdk/plugin.ts
|
|
656
|
+
// src/sdk/backing.ts
|
|
639
657
|
import { Effect as Effect3, Option as Option5, Schema as Schema3 } from "effect";
|
|
640
658
|
import {
|
|
641
|
-
IntegrationAlreadyExistsError,
|
|
642
|
-
IntegrationDetectionResult,
|
|
643
|
-
IntegrationNotFoundError,
|
|
644
|
-
IntegrationSlug,
|
|
645
|
-
ToolName,
|
|
646
659
|
ToolFileJsonSchema,
|
|
660
|
+
ToolName,
|
|
647
661
|
ToolResult,
|
|
648
|
-
authToolFailure
|
|
649
|
-
definePlugin,
|
|
650
|
-
mergeAuthTemplates,
|
|
651
|
-
sha256Hex,
|
|
652
|
-
tool
|
|
662
|
+
authToolFailure
|
|
653
663
|
} from "@executor-js/sdk/core";
|
|
654
664
|
|
|
655
665
|
// src/sdk/definitions.ts
|
|
@@ -797,8 +807,7 @@ var compileToolDefinitions = (operations) => {
|
|
|
797
807
|
return resolveCollisions(raw).sort((a, b) => a.toolPath.localeCompare(b.toolPath));
|
|
798
808
|
};
|
|
799
809
|
|
|
800
|
-
// src/sdk/
|
|
801
|
-
import { ApiKeyAuthTemplate, describeApiKeyAuthMethod } from "@executor-js/sdk/http-auth";
|
|
810
|
+
// src/sdk/backing.ts
|
|
802
811
|
var STRINGIFIED_BODY_CAP = 1024;
|
|
803
812
|
var UpstreamMessageBody = Schema3.Struct({ message: Schema3.String });
|
|
804
813
|
var UpstreamErrorMessageBody = Schema3.Struct({ errorMessage: Schema3.String });
|
|
@@ -832,7 +841,7 @@ var clampedStringify = (value) => {
|
|
|
832
841
|
return s.length > STRINGIFIED_BODY_CAP ? `${s.slice(0, STRINGIFIED_BODY_CAP)}\u2026` : s;
|
|
833
842
|
};
|
|
834
843
|
var firstNonEmpty = (...values) => values.find((value) => value !== void 0 && value.length > 0);
|
|
835
|
-
var
|
|
844
|
+
var extractOpenApiUpstreamMessage = (body, status) => {
|
|
836
845
|
if (typeof body === "string") {
|
|
837
846
|
return body.length > 0 ? body : `Upstream returned HTTP ${status}`;
|
|
838
847
|
}
|
|
@@ -863,162 +872,353 @@ var extractUpstreamMessage = (body, status) => {
|
|
|
863
872
|
}
|
|
864
873
|
return `Upstream returned HTTP ${status}`;
|
|
865
874
|
};
|
|
866
|
-
var
|
|
867
|
-
|
|
875
|
+
var openApiAuthToolFailure = (failure) => authToolFailure({
|
|
876
|
+
code: failure.code,
|
|
877
|
+
message: failure.message,
|
|
878
|
+
source: { id: failure.integration, scope: failure.owner },
|
|
879
|
+
credential: {
|
|
880
|
+
kind: failure.credentialKind,
|
|
881
|
+
...failure.credentialLabel ? { label: failure.credentialLabel } : {}
|
|
882
|
+
},
|
|
883
|
+
...failure.status !== void 0 ? { status: failure.status } : {},
|
|
884
|
+
...failure.details !== void 0 ? {
|
|
885
|
+
upstream: {
|
|
886
|
+
...failure.status !== void 0 ? { status: failure.status } : {},
|
|
887
|
+
details: failure.details
|
|
888
|
+
}
|
|
889
|
+
} : {}
|
|
890
|
+
});
|
|
891
|
+
var normalizeOpenApiRefs = (node) => {
|
|
892
|
+
if (node == null || typeof node !== "object") return node;
|
|
893
|
+
if (Array.isArray(node)) {
|
|
894
|
+
let changed2 = false;
|
|
895
|
+
const out = node.map((item) => {
|
|
896
|
+
const n = normalizeOpenApiRefs(item);
|
|
897
|
+
if (n !== item) changed2 = true;
|
|
898
|
+
return n;
|
|
899
|
+
});
|
|
900
|
+
return changed2 ? out : node;
|
|
901
|
+
}
|
|
902
|
+
const obj = node;
|
|
903
|
+
if (typeof obj.$ref === "string") {
|
|
904
|
+
const match = obj.$ref.match(/^#\/components\/schemas\/(.+)$/);
|
|
905
|
+
if (match) return { ...obj, $ref: `#/$defs/${match[1]}` };
|
|
906
|
+
return obj;
|
|
907
|
+
}
|
|
908
|
+
let changed = false;
|
|
909
|
+
const result = {};
|
|
910
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
911
|
+
const n = normalizeOpenApiRefs(v);
|
|
912
|
+
if (n !== v) changed = true;
|
|
913
|
+
result[k] = n;
|
|
914
|
+
}
|
|
915
|
+
return changed ? result : obj;
|
|
916
|
+
};
|
|
917
|
+
var toBinding = (def) => OperationBinding.make({
|
|
918
|
+
method: def.operation.method,
|
|
919
|
+
servers: def.operation.servers,
|
|
920
|
+
pathTemplate: def.operation.pathTemplate,
|
|
921
|
+
parameters: [...def.operation.parameters],
|
|
922
|
+
requestBody: def.operation.requestBody,
|
|
923
|
+
responseBody: def.operation.responseBody
|
|
924
|
+
});
|
|
925
|
+
var descriptionFor = (def) => {
|
|
926
|
+
const op = def.operation;
|
|
927
|
+
return Option5.getOrElse(
|
|
928
|
+
op.description,
|
|
929
|
+
() => Option5.getOrElse(op.summary, () => `${op.method.toUpperCase()} ${op.pathTemplate}`)
|
|
930
|
+
);
|
|
931
|
+
};
|
|
932
|
+
var compileOpenApiDocument = (doc) => Effect3.gen(function* () {
|
|
933
|
+
const result = yield* extract(doc);
|
|
934
|
+
const hoistedDefs = {};
|
|
935
|
+
if (doc.components?.schemas) {
|
|
936
|
+
for (const [k, v] of Object.entries(doc.components.schemas)) {
|
|
937
|
+
hoistedDefs[k] = normalizeOpenApiRefs(v);
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
return {
|
|
941
|
+
definitions: compileToolDefinitions(result.operations),
|
|
942
|
+
hoistedDefs,
|
|
943
|
+
title: Option5.getOrUndefined(result.title),
|
|
944
|
+
description: Option5.getOrUndefined(result.description)
|
|
945
|
+
};
|
|
946
|
+
});
|
|
947
|
+
var compileOpenApiSpec = (specText) => Effect3.gen(function* () {
|
|
948
|
+
const doc = yield* parse(specText);
|
|
949
|
+
return yield* compileOpenApiDocument(doc);
|
|
950
|
+
});
|
|
951
|
+
var openApiToolDefsFromCompiled = (compiled) => compiled.definitions.map(
|
|
952
|
+
(def) => ({
|
|
953
|
+
name: ToolName.make(def.toolPath),
|
|
954
|
+
description: descriptionFor(def),
|
|
955
|
+
inputSchema: normalizeOpenApiRefs(Option5.getOrUndefined(def.operation.inputSchema)),
|
|
956
|
+
outputSchema: Option5.match(def.operation.responseBody, {
|
|
957
|
+
onNone: () => normalizeOpenApiRefs(Option5.getOrUndefined(def.operation.outputSchema)),
|
|
958
|
+
onSome: (responseBody) => Option5.isSome(responseBody.fileHint) ? ToolFileJsonSchema : normalizeOpenApiRefs(Option5.getOrUndefined(def.operation.outputSchema))
|
|
959
|
+
}),
|
|
960
|
+
annotations: annotationsForOperation(def.operation.method, def.operation.pathTemplate)
|
|
961
|
+
})
|
|
962
|
+
);
|
|
963
|
+
var openApiStoredOperationsFromCompiled = (integration, compiled) => compiled.definitions.map((def) => ({
|
|
964
|
+
integration,
|
|
965
|
+
toolName: def.toolPath,
|
|
966
|
+
binding: toBinding(def)
|
|
967
|
+
}));
|
|
968
|
+
var loadOpenApiSpecText = (storage, config) => config.specHash != null ? storage.getSpec(config.specHash) : Effect3.succeed(null);
|
|
969
|
+
var resolveOpenApiBackedTools = ({
|
|
970
|
+
config,
|
|
971
|
+
storage
|
|
972
|
+
}) => Effect3.gen(function* () {
|
|
973
|
+
const openApiConfig = decodeOpenApiIntegrationConfig(config);
|
|
974
|
+
if (!openApiConfig) return { tools: [], definitions: {} };
|
|
975
|
+
const specText = yield* loadOpenApiSpecText(storage, openApiConfig);
|
|
976
|
+
if (specText == null) return { tools: [], definitions: {} };
|
|
977
|
+
const compiled = yield* compileOpenApiSpec(specText).pipe(
|
|
978
|
+
Effect3.catch(() => Effect3.succeed(null))
|
|
979
|
+
);
|
|
980
|
+
if (!compiled) return { tools: [], definitions: {} };
|
|
981
|
+
return {
|
|
982
|
+
tools: openApiToolDefsFromCompiled(compiled),
|
|
983
|
+
definitions: compiled.hoistedDefs
|
|
984
|
+
};
|
|
985
|
+
});
|
|
986
|
+
var invokeOpenApiBackedTool = (input) => Effect3.gen(function* () {
|
|
987
|
+
const integration = input.toolRow.integration;
|
|
988
|
+
const config = decodeOpenApiIntegrationConfig(input.credential.config);
|
|
989
|
+
let binding = (yield* input.ctx.storage.getOperation(integration, input.toolRow.name))?.binding;
|
|
990
|
+
if ((!binding || Option5.isNone(binding.responseBody)) && config) {
|
|
991
|
+
const specText = yield* loadOpenApiSpecText(input.ctx.storage, config).pipe(
|
|
992
|
+
Effect3.catch(() => Effect3.succeed(null))
|
|
993
|
+
);
|
|
994
|
+
const compiled = specText == null ? null : yield* compileOpenApiSpec(specText).pipe(Effect3.catch(() => Effect3.succeed(null)));
|
|
995
|
+
binding = compiled ? openApiStoredOperationsFromCompiled(integration, compiled).find(
|
|
996
|
+
(op) => op.toolName === input.toolRow.name
|
|
997
|
+
)?.binding : void 0;
|
|
998
|
+
}
|
|
999
|
+
if (!binding) {
|
|
1000
|
+
return yield* new OpenApiExtractionError({
|
|
1001
|
+
message: `No OpenAPI operation found for tool "${input.toolRow.name}" on "${integration}"`
|
|
1002
|
+
});
|
|
1003
|
+
}
|
|
1004
|
+
const headers = { ...config?.headers ?? {} };
|
|
1005
|
+
const queryParams = {
|
|
1006
|
+
...config?.queryParams ?? {}
|
|
1007
|
+
};
|
|
1008
|
+
const template = (config?.authenticationTemplate ?? []).find(
|
|
1009
|
+
(entry) => String(entry.slug) === String(input.credential.template)
|
|
1010
|
+
);
|
|
1011
|
+
if (template) {
|
|
1012
|
+
const missing = requiredTemplateVariables(template).filter((name) => {
|
|
1013
|
+
const value = input.credential.values[name];
|
|
1014
|
+
return value == null || value === "";
|
|
1015
|
+
});
|
|
1016
|
+
if (missing.length > 0) {
|
|
1017
|
+
return openApiAuthToolFailure({
|
|
1018
|
+
code: template.kind === "oauth2" ? "oauth_connection_missing" : "connection_value_missing",
|
|
1019
|
+
message: `Connection "${input.credential.connection}" for "${integration}" has no resolvable credential value. Re-authenticate or update the connection.`,
|
|
1020
|
+
owner: input.credential.owner,
|
|
1021
|
+
integration,
|
|
1022
|
+
connection: String(input.credential.connection),
|
|
1023
|
+
credentialKind: template.kind === "oauth2" ? "oauth" : "secret"
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
1026
|
+
const rendered = renderAuthTemplate(template, input.credential.values);
|
|
1027
|
+
Object.assign(headers, rendered.headers);
|
|
1028
|
+
Object.assign(queryParams, rendered.queryParams);
|
|
1029
|
+
}
|
|
1030
|
+
const result = yield* invokeWithLayer(
|
|
1031
|
+
binding,
|
|
1032
|
+
input.args ?? {},
|
|
1033
|
+
config?.baseUrl ?? "",
|
|
1034
|
+
headers,
|
|
1035
|
+
queryParams,
|
|
1036
|
+
input.httpClientLayer
|
|
1037
|
+
);
|
|
1038
|
+
const ok = result.status >= 200 && result.status < 300;
|
|
1039
|
+
if (!ok) {
|
|
1040
|
+
if (result.status === 401 || result.status === 403) {
|
|
1041
|
+
return openApiAuthToolFailure({
|
|
1042
|
+
code: "connection_rejected",
|
|
1043
|
+
status: result.status,
|
|
1044
|
+
message: `Upstream rejected credentials for "${integration}" with HTTP ${result.status}. Re-authenticate or update the connection "${input.credential.connection}" before retrying this tool.`,
|
|
1045
|
+
owner: input.credential.owner,
|
|
1046
|
+
integration,
|
|
1047
|
+
connection: String(input.credential.connection),
|
|
1048
|
+
credentialKind: "upstream",
|
|
1049
|
+
credentialLabel: "Upstream authorization",
|
|
1050
|
+
details: result.error
|
|
1051
|
+
});
|
|
1052
|
+
}
|
|
1053
|
+
return ToolResult.fail({
|
|
1054
|
+
code: "upstream_http_error",
|
|
1055
|
+
status: result.status,
|
|
1056
|
+
message: extractOpenApiUpstreamMessage(result.error, result.status),
|
|
1057
|
+
details: result.error
|
|
1058
|
+
});
|
|
1059
|
+
}
|
|
1060
|
+
return ToolResult.ok(result.data, {
|
|
1061
|
+
http: { status: result.status, headers: result.headers }
|
|
1062
|
+
});
|
|
1063
|
+
});
|
|
1064
|
+
var resolveOpenApiBackedAnnotations = (input) => Effect3.gen(function* () {
|
|
1065
|
+
const ops = yield* input.ctx.storage.listOperations(String(input.integration));
|
|
1066
|
+
const byName = /* @__PURE__ */ new Map();
|
|
1067
|
+
for (const op of ops) byName.set(op.toolName, op.binding);
|
|
1068
|
+
const out = {};
|
|
1069
|
+
for (const row of input.toolRows) {
|
|
1070
|
+
const binding = byName.get(row.name);
|
|
1071
|
+
if (binding) {
|
|
1072
|
+
out[row.name] = annotationsForOperation(binding.method, binding.pathTemplate);
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
return out;
|
|
868
1076
|
});
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
1077
|
+
|
|
1078
|
+
// src/sdk/plugin.ts
|
|
1079
|
+
import { Effect as Effect4, Option as Option6, Schema as Schema4 } from "effect";
|
|
1080
|
+
import {
|
|
1081
|
+
IntegrationAlreadyExistsError,
|
|
1082
|
+
IntegrationDetectionResult,
|
|
1083
|
+
IntegrationNotFoundError,
|
|
1084
|
+
IntegrationSlug,
|
|
1085
|
+
ToolResult as ToolResult2,
|
|
1086
|
+
definePlugin,
|
|
1087
|
+
mergeAuthTemplates,
|
|
1088
|
+
sha256Hex,
|
|
1089
|
+
tool
|
|
1090
|
+
} from "@executor-js/sdk/core";
|
|
1091
|
+
import { ApiKeyAuthTemplate, describeApiKeyAuthMethod } from "@executor-js/sdk/http-auth";
|
|
1092
|
+
var PreviewSpecInputSchema = Schema4.Struct({
|
|
1093
|
+
spec: Schema4.String
|
|
1094
|
+
});
|
|
1095
|
+
var StaticPreviewServerVariableSchema = Schema4.Struct({
|
|
1096
|
+
default: Schema4.String,
|
|
1097
|
+
enum: Schema4.NullOr(Schema4.Array(Schema4.String)),
|
|
1098
|
+
description: Schema4.NullOr(Schema4.String)
|
|
873
1099
|
});
|
|
874
|
-
var StaticPreviewServerSchema =
|
|
875
|
-
url:
|
|
876
|
-
description:
|
|
877
|
-
variables:
|
|
1100
|
+
var StaticPreviewServerSchema = Schema4.Struct({
|
|
1101
|
+
url: Schema4.String,
|
|
1102
|
+
description: Schema4.NullOr(Schema4.String),
|
|
1103
|
+
variables: Schema4.NullOr(Schema4.Record(Schema4.String, StaticPreviewServerVariableSchema))
|
|
878
1104
|
});
|
|
879
|
-
var StaticPreviewOAuthAuthorizationCodeFlowSchema =
|
|
880
|
-
authorizationUrl:
|
|
881
|
-
tokenUrl:
|
|
882
|
-
refreshUrl:
|
|
883
|
-
scopes:
|
|
1105
|
+
var StaticPreviewOAuthAuthorizationCodeFlowSchema = Schema4.Struct({
|
|
1106
|
+
authorizationUrl: Schema4.String,
|
|
1107
|
+
tokenUrl: Schema4.String,
|
|
1108
|
+
refreshUrl: Schema4.NullOr(Schema4.String),
|
|
1109
|
+
scopes: Schema4.Record(Schema4.String, Schema4.String)
|
|
884
1110
|
});
|
|
885
|
-
var StaticPreviewOAuthClientCredentialsFlowSchema =
|
|
886
|
-
tokenUrl:
|
|
887
|
-
refreshUrl:
|
|
888
|
-
scopes:
|
|
1111
|
+
var StaticPreviewOAuthClientCredentialsFlowSchema = Schema4.Struct({
|
|
1112
|
+
tokenUrl: Schema4.String,
|
|
1113
|
+
refreshUrl: Schema4.NullOr(Schema4.String),
|
|
1114
|
+
scopes: Schema4.Record(Schema4.String, Schema4.String)
|
|
889
1115
|
});
|
|
890
|
-
var StaticPreviewOAuthFlowsSchema =
|
|
891
|
-
authorizationCode:
|
|
892
|
-
clientCredentials:
|
|
1116
|
+
var StaticPreviewOAuthFlowsSchema = Schema4.Struct({
|
|
1117
|
+
authorizationCode: Schema4.NullOr(StaticPreviewOAuthAuthorizationCodeFlowSchema),
|
|
1118
|
+
clientCredentials: Schema4.NullOr(StaticPreviewOAuthClientCredentialsFlowSchema)
|
|
893
1119
|
});
|
|
894
|
-
var StaticPreviewSecuritySchemeSchema =
|
|
895
|
-
name:
|
|
896
|
-
type:
|
|
897
|
-
scheme:
|
|
898
|
-
bearerFormat:
|
|
899
|
-
in:
|
|
900
|
-
headerName:
|
|
901
|
-
description:
|
|
902
|
-
flows:
|
|
903
|
-
openIdConnectUrl:
|
|
1120
|
+
var StaticPreviewSecuritySchemeSchema = Schema4.Struct({
|
|
1121
|
+
name: Schema4.String,
|
|
1122
|
+
type: Schema4.Literals(["http", "apiKey", "oauth2", "openIdConnect"]),
|
|
1123
|
+
scheme: Schema4.NullOr(Schema4.String),
|
|
1124
|
+
bearerFormat: Schema4.NullOr(Schema4.String),
|
|
1125
|
+
in: Schema4.NullOr(Schema4.Literals(["header", "query", "cookie"])),
|
|
1126
|
+
headerName: Schema4.NullOr(Schema4.String),
|
|
1127
|
+
description: Schema4.NullOr(Schema4.String),
|
|
1128
|
+
flows: Schema4.NullOr(StaticPreviewOAuthFlowsSchema),
|
|
1129
|
+
openIdConnectUrl: Schema4.NullOr(Schema4.String)
|
|
904
1130
|
});
|
|
905
|
-
var StaticPreviewOAuth2PresetSchema =
|
|
906
|
-
label:
|
|
907
|
-
securitySchemeName:
|
|
908
|
-
flow:
|
|
909
|
-
authorizationUrl:
|
|
910
|
-
tokenUrl:
|
|
911
|
-
refreshUrl:
|
|
912
|
-
scopes:
|
|
913
|
-
identityScopes:
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
1131
|
+
var StaticPreviewOAuth2PresetSchema = Schema4.Struct({
|
|
1132
|
+
label: Schema4.String,
|
|
1133
|
+
securitySchemeName: Schema4.String,
|
|
1134
|
+
flow: Schema4.Literals(["authorizationCode", "clientCredentials"]),
|
|
1135
|
+
authorizationUrl: Schema4.NullOr(Schema4.String),
|
|
1136
|
+
tokenUrl: Schema4.String,
|
|
1137
|
+
refreshUrl: Schema4.NullOr(Schema4.String),
|
|
1138
|
+
scopes: Schema4.Record(Schema4.String, Schema4.String),
|
|
1139
|
+
identityScopes: Schema4.Union([
|
|
1140
|
+
Schema4.Literal("auto"),
|
|
1141
|
+
Schema4.Literal(false),
|
|
1142
|
+
Schema4.Array(Schema4.String)
|
|
917
1143
|
])
|
|
918
1144
|
});
|
|
919
|
-
var StaticPreviewSpecOutputSchema =
|
|
920
|
-
title:
|
|
921
|
-
version:
|
|
922
|
-
servers:
|
|
923
|
-
operationCount:
|
|
924
|
-
tags:
|
|
925
|
-
securitySchemes:
|
|
926
|
-
authStrategies:
|
|
927
|
-
headerPresets:
|
|
928
|
-
|
|
929
|
-
label:
|
|
930
|
-
headers:
|
|
931
|
-
secretHeaders:
|
|
1145
|
+
var StaticPreviewSpecOutputSchema = Schema4.Struct({
|
|
1146
|
+
title: Schema4.NullOr(Schema4.String),
|
|
1147
|
+
version: Schema4.NullOr(Schema4.String),
|
|
1148
|
+
servers: Schema4.Array(StaticPreviewServerSchema),
|
|
1149
|
+
operationCount: Schema4.Number,
|
|
1150
|
+
tags: Schema4.Array(Schema4.String),
|
|
1151
|
+
securitySchemes: Schema4.Array(StaticPreviewSecuritySchemeSchema),
|
|
1152
|
+
authStrategies: Schema4.Array(Schema4.Struct({ schemes: Schema4.Array(Schema4.String) })),
|
|
1153
|
+
headerPresets: Schema4.Array(
|
|
1154
|
+
Schema4.Struct({
|
|
1155
|
+
label: Schema4.String,
|
|
1156
|
+
headers: Schema4.Record(Schema4.String, Schema4.NullOr(Schema4.String)),
|
|
1157
|
+
secretHeaders: Schema4.Array(Schema4.String)
|
|
932
1158
|
})
|
|
933
1159
|
),
|
|
934
|
-
oauth2Presets:
|
|
1160
|
+
oauth2Presets: Schema4.Array(StaticPreviewOAuth2PresetSchema)
|
|
935
1161
|
});
|
|
936
|
-
var OpenApiSpecInputSchema =
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
Schema3.Struct({
|
|
940
|
-
kind: Schema3.Literal("googleDiscovery"),
|
|
941
|
-
url: Schema3.String
|
|
942
|
-
}),
|
|
943
|
-
Schema3.Struct({
|
|
944
|
-
kind: Schema3.Literal("googleDiscoveryBundle"),
|
|
945
|
-
urls: Schema3.Array(Schema3.String)
|
|
946
|
-
})
|
|
1162
|
+
var OpenApiSpecInputSchema = Schema4.Union([
|
|
1163
|
+
Schema4.Struct({ kind: Schema4.Literal("url"), url: Schema4.String }),
|
|
1164
|
+
Schema4.Struct({ kind: Schema4.Literal("blob"), value: Schema4.String })
|
|
947
1165
|
]);
|
|
948
|
-
var AuthenticationSchema2 =
|
|
949
|
-
|
|
950
|
-
slug:
|
|
951
|
-
kind:
|
|
952
|
-
authorizationUrl:
|
|
953
|
-
tokenUrl:
|
|
954
|
-
scopes:
|
|
1166
|
+
var AuthenticationSchema2 = Schema4.Union([
|
|
1167
|
+
Schema4.Struct({
|
|
1168
|
+
slug: Schema4.String,
|
|
1169
|
+
kind: Schema4.Literal("oauth2"),
|
|
1170
|
+
authorizationUrl: Schema4.String,
|
|
1171
|
+
tokenUrl: Schema4.String,
|
|
1172
|
+
scopes: Schema4.Array(Schema4.String)
|
|
955
1173
|
}),
|
|
956
|
-
// Credential methods are authored request-shaped
|
|
1174
|
+
// Credential methods are authored request-shaped - the ONE apikey input
|
|
957
1175
|
// dialect: `{ type: "apiKey", headers: { Authorization: ["Bearer ",
|
|
958
1176
|
// variable("token")] }, queryParams: { … } }`.
|
|
959
1177
|
ApiKeyAuthTemplate
|
|
960
1178
|
]);
|
|
961
|
-
var AddSourceInputSchema =
|
|
1179
|
+
var AddSourceInputSchema = Schema4.Struct({
|
|
962
1180
|
spec: OpenApiSpecInputSchema,
|
|
963
|
-
slug:
|
|
964
|
-
description:
|
|
965
|
-
baseUrl:
|
|
966
|
-
headers:
|
|
967
|
-
queryParams:
|
|
968
|
-
authenticationTemplate:
|
|
1181
|
+
slug: Schema4.String,
|
|
1182
|
+
description: Schema4.optional(Schema4.String),
|
|
1183
|
+
baseUrl: Schema4.optional(Schema4.String),
|
|
1184
|
+
headers: Schema4.optional(Schema4.Record(Schema4.String, Schema4.String)),
|
|
1185
|
+
queryParams: Schema4.optional(Schema4.Record(Schema4.String, Schema4.String)),
|
|
1186
|
+
authenticationTemplate: Schema4.optional(Schema4.Array(AuthenticationSchema2))
|
|
969
1187
|
});
|
|
970
|
-
var AddSourceOutputSchema =
|
|
971
|
-
slug:
|
|
972
|
-
toolCount:
|
|
1188
|
+
var AddSourceOutputSchema = Schema4.Struct({
|
|
1189
|
+
slug: Schema4.String,
|
|
1190
|
+
toolCount: Schema4.Number
|
|
973
1191
|
});
|
|
974
|
-
var PreviewSpecInputStandardSchema =
|
|
975
|
-
|
|
1192
|
+
var PreviewSpecInputStandardSchema = Schema4.toStandardSchemaV1(
|
|
1193
|
+
Schema4.toStandardJSONSchemaV1(PreviewSpecInputSchema)
|
|
976
1194
|
);
|
|
977
|
-
var PreviewSpecOutputStandardSchema =
|
|
978
|
-
|
|
1195
|
+
var PreviewSpecOutputStandardSchema = Schema4.toStandardSchemaV1(
|
|
1196
|
+
Schema4.toStandardJSONSchemaV1(StaticPreviewSpecOutputSchema)
|
|
979
1197
|
);
|
|
980
|
-
var AddSourceInputStandardSchema =
|
|
981
|
-
|
|
1198
|
+
var AddSourceInputStandardSchema = Schema4.toStandardSchemaV1(
|
|
1199
|
+
Schema4.toStandardJSONSchemaV1(AddSourceInputSchema)
|
|
982
1200
|
);
|
|
983
|
-
var AddSourceOutputStandardSchema =
|
|
984
|
-
|
|
1201
|
+
var AddSourceOutputStandardSchema = Schema4.toStandardSchemaV1(
|
|
1202
|
+
Schema4.toStandardJSONSchemaV1(AddSourceOutputSchema)
|
|
985
1203
|
);
|
|
986
|
-
var openApiToolFailure = (code, message, details) =>
|
|
1204
|
+
var openApiToolFailure = (code, message, details) => ToolResult2.fail({
|
|
987
1205
|
code,
|
|
988
1206
|
message,
|
|
989
1207
|
...details === void 0 ? {} : { details }
|
|
990
1208
|
});
|
|
991
|
-
var openApiAuthToolFailure = (failure) => authToolFailure({
|
|
992
|
-
// The auth-tool-failure helper's code set is shared with v1; keep the
|
|
993
|
-
// string but reference the connection rather than v1's source/slot.
|
|
994
|
-
code: failure.code,
|
|
995
|
-
message: failure.message,
|
|
996
|
-
source: { id: failure.integration, scope: failure.owner },
|
|
997
|
-
credential: {
|
|
998
|
-
kind: failure.credentialKind,
|
|
999
|
-
...failure.credentialLabel ? { label: failure.credentialLabel } : {}
|
|
1000
|
-
},
|
|
1001
|
-
...failure.status !== void 0 ? { status: failure.status } : {},
|
|
1002
|
-
...failure.details !== void 0 ? {
|
|
1003
|
-
upstream: {
|
|
1004
|
-
...failure.status !== void 0 ? { status: failure.status } : {},
|
|
1005
|
-
details: failure.details
|
|
1006
|
-
}
|
|
1007
|
-
} : {}
|
|
1008
|
-
});
|
|
1009
1209
|
var staticPreviewOutput = (preview) => ({
|
|
1010
|
-
title:
|
|
1011
|
-
version:
|
|
1210
|
+
title: Option6.getOrNull(preview.title),
|
|
1211
|
+
version: Option6.getOrNull(preview.version),
|
|
1012
1212
|
servers: preview.servers.map((server) => ({
|
|
1013
1213
|
url: server.url,
|
|
1014
|
-
description:
|
|
1015
|
-
variables:
|
|
1016
|
-
Object.entries(
|
|
1214
|
+
description: Option6.getOrNull(server.description),
|
|
1215
|
+
variables: Option6.getOrNull(server.variables) ? Object.fromEntries(
|
|
1216
|
+
Object.entries(Option6.getOrNull(server.variables) ?? {}).map(([name, variable]) => [
|
|
1017
1217
|
name,
|
|
1018
1218
|
{
|
|
1019
1219
|
default: variable.default,
|
|
1020
|
-
enum:
|
|
1021
|
-
description:
|
|
1220
|
+
enum: Option6.getOrNull(variable.enum),
|
|
1221
|
+
description: Option6.getOrNull(variable.description)
|
|
1022
1222
|
}
|
|
1023
1223
|
])
|
|
1024
1224
|
) : null
|
|
@@ -1028,25 +1228,25 @@ var staticPreviewOutput = (preview) => ({
|
|
|
1028
1228
|
securitySchemes: preview.securitySchemes.map((scheme) => ({
|
|
1029
1229
|
name: scheme.name,
|
|
1030
1230
|
type: scheme.type,
|
|
1031
|
-
scheme:
|
|
1032
|
-
bearerFormat:
|
|
1033
|
-
in:
|
|
1034
|
-
headerName:
|
|
1035
|
-
description:
|
|
1036
|
-
flows:
|
|
1037
|
-
authorizationCode:
|
|
1231
|
+
scheme: Option6.getOrNull(scheme.scheme),
|
|
1232
|
+
bearerFormat: Option6.getOrNull(scheme.bearerFormat),
|
|
1233
|
+
in: Option6.getOrNull(scheme.in),
|
|
1234
|
+
headerName: Option6.getOrNull(scheme.headerName),
|
|
1235
|
+
description: Option6.getOrNull(scheme.description),
|
|
1236
|
+
flows: Option6.isSome(scheme.flows) ? {
|
|
1237
|
+
authorizationCode: Option6.isSome(scheme.flows.value.authorizationCode) ? {
|
|
1038
1238
|
authorizationUrl: scheme.flows.value.authorizationCode.value.authorizationUrl,
|
|
1039
1239
|
tokenUrl: scheme.flows.value.authorizationCode.value.tokenUrl,
|
|
1040
|
-
refreshUrl:
|
|
1240
|
+
refreshUrl: Option6.getOrNull(scheme.flows.value.authorizationCode.value.refreshUrl),
|
|
1041
1241
|
scopes: scheme.flows.value.authorizationCode.value.scopes
|
|
1042
1242
|
} : null,
|
|
1043
|
-
clientCredentials:
|
|
1243
|
+
clientCredentials: Option6.isSome(scheme.flows.value.clientCredentials) ? {
|
|
1044
1244
|
tokenUrl: scheme.flows.value.clientCredentials.value.tokenUrl,
|
|
1045
|
-
refreshUrl:
|
|
1245
|
+
refreshUrl: Option6.getOrNull(scheme.flows.value.clientCredentials.value.refreshUrl),
|
|
1046
1246
|
scopes: scheme.flows.value.clientCredentials.value.scopes
|
|
1047
1247
|
} : null
|
|
1048
1248
|
} : null,
|
|
1049
|
-
openIdConnectUrl:
|
|
1249
|
+
openIdConnectUrl: Option6.getOrNull(scheme.openIdConnectUrl)
|
|
1050
1250
|
})),
|
|
1051
1251
|
authStrategies: preview.authStrategies,
|
|
1052
1252
|
headerPresets: preview.headerPresets,
|
|
@@ -1054,56 +1254,14 @@ var staticPreviewOutput = (preview) => ({
|
|
|
1054
1254
|
label: preset.label,
|
|
1055
1255
|
securitySchemeName: preset.securitySchemeName,
|
|
1056
1256
|
flow: preset.flow,
|
|
1057
|
-
authorizationUrl:
|
|
1257
|
+
authorizationUrl: Option6.getOrNull(preset.authorizationUrl),
|
|
1058
1258
|
tokenUrl: preset.tokenUrl,
|
|
1059
|
-
refreshUrl:
|
|
1259
|
+
refreshUrl: Option6.getOrNull(preset.refreshUrl),
|
|
1060
1260
|
scopes: preset.scopes,
|
|
1061
1261
|
identityScopes: preset.identityScopes
|
|
1062
1262
|
}))
|
|
1063
1263
|
});
|
|
1064
|
-
var
|
|
1065
|
-
if (node == null || typeof node !== "object") return node;
|
|
1066
|
-
if (Array.isArray(node)) {
|
|
1067
|
-
let changed2 = false;
|
|
1068
|
-
const out = node.map((item) => {
|
|
1069
|
-
const n = normalizeOpenApiRefs(item);
|
|
1070
|
-
if (n !== item) changed2 = true;
|
|
1071
|
-
return n;
|
|
1072
|
-
});
|
|
1073
|
-
return changed2 ? out : node;
|
|
1074
|
-
}
|
|
1075
|
-
const obj = node;
|
|
1076
|
-
if (typeof obj.$ref === "string") {
|
|
1077
|
-
const match = obj.$ref.match(/^#\/components\/schemas\/(.+)$/);
|
|
1078
|
-
if (match) return { ...obj, $ref: `#/$defs/${match[1]}` };
|
|
1079
|
-
return obj;
|
|
1080
|
-
}
|
|
1081
|
-
let changed = false;
|
|
1082
|
-
const result = {};
|
|
1083
|
-
for (const [k, v] of Object.entries(obj)) {
|
|
1084
|
-
const n = normalizeOpenApiRefs(v);
|
|
1085
|
-
if (n !== v) changed = true;
|
|
1086
|
-
result[k] = n;
|
|
1087
|
-
}
|
|
1088
|
-
return changed ? result : obj;
|
|
1089
|
-
};
|
|
1090
|
-
var toBinding = (def) => OperationBinding.make({
|
|
1091
|
-
method: def.operation.method,
|
|
1092
|
-
servers: def.operation.servers,
|
|
1093
|
-
pathTemplate: def.operation.pathTemplate,
|
|
1094
|
-
parameters: [...def.operation.parameters],
|
|
1095
|
-
requestBody: def.operation.requestBody,
|
|
1096
|
-
responseBody: def.operation.responseBody
|
|
1097
|
-
});
|
|
1098
|
-
var descriptionFor = (def) => {
|
|
1099
|
-
const op = def.operation;
|
|
1100
|
-
return Option5.getOrElse(
|
|
1101
|
-
op.description,
|
|
1102
|
-
() => Option5.getOrElse(op.summary, () => `${op.method.toUpperCase()} ${op.pathTemplate}`)
|
|
1103
|
-
);
|
|
1104
|
-
};
|
|
1105
|
-
var specInputToSourceUrl = (spec) => spec.kind === "url" || spec.kind === "googleDiscovery" ? spec.url : void 0;
|
|
1106
|
-
var specInputToGoogleBundle = (spec) => spec.kind === "googleDiscoveryBundle" ? spec.urls : void 0;
|
|
1264
|
+
var specInputToSourceUrl = (spec) => spec.kind === "url" ? spec.url : void 0;
|
|
1107
1265
|
var describeOpenApiAuthMethods = (record) => {
|
|
1108
1266
|
const config = decodeOpenApiIntegrationConfig(record.config);
|
|
1109
1267
|
if (!config) return [];
|
|
@@ -1130,79 +1288,10 @@ var describeOpenApiIntegrationDisplay = (record) => {
|
|
|
1130
1288
|
const config = decodeOpenApiIntegrationConfig(record.config);
|
|
1131
1289
|
return { url: config?.baseUrl ?? config?.sourceUrl };
|
|
1132
1290
|
};
|
|
1133
|
-
var loadSpecText = (storage, config) => config.specHash != null ? storage.getSpec(config.specHash) : Effect3.succeed(null);
|
|
1134
|
-
var compileSpec = (specText) => Effect3.gen(function* () {
|
|
1135
|
-
const doc = yield* parse(specText);
|
|
1136
|
-
const result = yield* extract(doc);
|
|
1137
|
-
const hoistedDefs = {};
|
|
1138
|
-
if (doc.components?.schemas) {
|
|
1139
|
-
for (const [k, v] of Object.entries(doc.components.schemas)) {
|
|
1140
|
-
hoistedDefs[k] = normalizeOpenApiRefs(v);
|
|
1141
|
-
}
|
|
1142
|
-
}
|
|
1143
|
-
return {
|
|
1144
|
-
definitions: compileToolDefinitions(result.operations),
|
|
1145
|
-
hoistedDefs,
|
|
1146
|
-
title: Option5.getOrUndefined(result.title),
|
|
1147
|
-
description: Option5.getOrUndefined(result.description)
|
|
1148
|
-
};
|
|
1149
|
-
});
|
|
1150
|
-
var toolDefsFromCompiled = (compiled) => compiled.definitions.map(
|
|
1151
|
-
(def) => ({
|
|
1152
|
-
name: ToolName.make(def.toolPath),
|
|
1153
|
-
description: descriptionFor(def),
|
|
1154
|
-
inputSchema: normalizeOpenApiRefs(Option5.getOrUndefined(def.operation.inputSchema)),
|
|
1155
|
-
// The output schema is the upstream response body only — transport
|
|
1156
|
-
// status/headers live in the ToolResult `http` side channel, not the
|
|
1157
|
-
// payload (see the invoke handler).
|
|
1158
|
-
outputSchema: Option5.match(def.operation.responseBody, {
|
|
1159
|
-
onNone: () => normalizeOpenApiRefs(Option5.getOrUndefined(def.operation.outputSchema)),
|
|
1160
|
-
onSome: (responseBody) => Option5.isSome(responseBody.fileHint) ? ToolFileJsonSchema : normalizeOpenApiRefs(Option5.getOrUndefined(def.operation.outputSchema))
|
|
1161
|
-
}),
|
|
1162
|
-
annotations: annotationsForOperation(def.operation.method, def.operation.pathTemplate)
|
|
1163
|
-
})
|
|
1164
|
-
);
|
|
1165
|
-
var storedOperationsFromCompiled = (integration, compiled) => compiled.definitions.map((def) => ({
|
|
1166
|
-
integration,
|
|
1167
|
-
toolName: def.toolPath,
|
|
1168
|
-
binding: toBinding(def)
|
|
1169
|
-
}));
|
|
1170
|
-
var fetchGoogleDiscoveryBundleConversion = (urls, httpClientLayer) => Effect3.forEach(
|
|
1171
|
-
urls,
|
|
1172
|
-
(url) => fetchGoogleDiscoveryDocument(url).pipe(
|
|
1173
|
-
Effect3.provide(httpClientLayer),
|
|
1174
|
-
Effect3.map((documentText) => ({ discoveryUrl: url, documentText }))
|
|
1175
|
-
),
|
|
1176
|
-
{ concurrency: 4 }
|
|
1177
|
-
).pipe(Effect3.flatMap((documents) => convertGoogleDiscoveryBundleToOpenApi({ documents })));
|
|
1178
1291
|
var openApiPlugin = definePlugin((options) => {
|
|
1179
|
-
const resolveSpecForInput = (spec, httpClientLayer) =>
|
|
1180
|
-
if (spec.kind === "googleDiscovery") {
|
|
1181
|
-
const conversion = yield* fetchGoogleDiscoveryDocument(spec.url).pipe(
|
|
1182
|
-
Effect3.provide(httpClientLayer),
|
|
1183
|
-
Effect3.flatMap(
|
|
1184
|
-
(documentText) => convertGoogleDiscoveryToOpenApi({
|
|
1185
|
-
discoveryUrl: spec.url,
|
|
1186
|
-
documentText
|
|
1187
|
-
})
|
|
1188
|
-
)
|
|
1189
|
-
);
|
|
1190
|
-
return {
|
|
1191
|
-
specText: conversion.specText,
|
|
1192
|
-
baseUrl: conversion.baseUrl,
|
|
1193
|
-
...conversion.authenticationTemplate ? { authenticationTemplate: conversion.authenticationTemplate } : {}
|
|
1194
|
-
};
|
|
1195
|
-
}
|
|
1196
|
-
if (spec.kind === "googleDiscoveryBundle") {
|
|
1197
|
-
const conversion = yield* fetchGoogleDiscoveryBundleConversion(spec.urls, httpClientLayer);
|
|
1198
|
-
return {
|
|
1199
|
-
specText: conversion.specText,
|
|
1200
|
-
baseUrl: conversion.baseUrl,
|
|
1201
|
-
...conversion.authenticationTemplate ? { authenticationTemplate: conversion.authenticationTemplate } : {}
|
|
1202
|
-
};
|
|
1203
|
-
}
|
|
1292
|
+
const resolveSpecForInput = (spec, httpClientLayer) => Effect4.gen(function* () {
|
|
1204
1293
|
if (spec.kind === "url") {
|
|
1205
|
-
const specText = yield* resolveSpecText(spec.url).pipe(
|
|
1294
|
+
const specText = yield* resolveSpecText(spec.url).pipe(Effect4.provide(httpClientLayer));
|
|
1206
1295
|
return { specText };
|
|
1207
1296
|
}
|
|
1208
1297
|
return { specText: spec.value };
|
|
@@ -1221,12 +1310,12 @@ var openApiPlugin = definePlugin((options) => {
|
|
|
1221
1310
|
storage: (deps) => makeDefaultOpenapiStore(deps),
|
|
1222
1311
|
extension: (ctx) => {
|
|
1223
1312
|
const httpClientLayer = options?.httpClientLayer ?? ctx.httpClientLayer;
|
|
1224
|
-
const addSpec = (config) =>
|
|
1313
|
+
const addSpec = (config) => Effect4.gen(function* () {
|
|
1225
1314
|
const resolved = yield* resolveSpecForInput(config.spec, httpClientLayer);
|
|
1226
|
-
const compiled = yield*
|
|
1227
|
-
const explicitBaseUrl = config.baseUrl
|
|
1315
|
+
const compiled = yield* compileOpenApiSpec(resolved.specText);
|
|
1316
|
+
const explicitBaseUrl = config.baseUrl;
|
|
1228
1317
|
const needsDerivedBaseUrl = explicitBaseUrl == null;
|
|
1229
|
-
const needsDerivedAuth = config.authenticationTemplate == null
|
|
1318
|
+
const needsDerivedAuth = config.authenticationTemplate == null;
|
|
1230
1319
|
const preview = needsDerivedBaseUrl || needsDerivedAuth ? yield* previewSpecText(resolved.specText) : void 0;
|
|
1231
1320
|
const derivedBaseUrl = needsDerivedBaseUrl && preview ? firstBaseUrlForPreview(preview) : void 0;
|
|
1232
1321
|
const effectiveBaseUrl = explicitBaseUrl ?? (derivedBaseUrl || void 0);
|
|
@@ -1240,55 +1329,52 @@ var openApiPlugin = definePlugin((options) => {
|
|
|
1240
1329
|
const integrationConfig = {
|
|
1241
1330
|
specHash,
|
|
1242
1331
|
...specInputToSourceUrl(config.spec) !== void 0 ? { sourceUrl: specInputToSourceUrl(config.spec) } : {},
|
|
1243
|
-
...specInputToGoogleBundle(config.spec) !== void 0 ? { googleDiscoveryUrls: specInputToGoogleBundle(config.spec) } : {},
|
|
1244
1332
|
// baseUrl is an optional override only. The host is otherwise
|
|
1245
1333
|
// resolved per call from the operation's `servers` (extracted from
|
|
1246
1334
|
// the spec), so we never bake a derived base URL into the config.
|
|
1247
1335
|
...config.baseUrl ? { baseUrl: config.baseUrl } : {},
|
|
1248
1336
|
...config.headers ? { headers: config.headers } : {},
|
|
1249
1337
|
...config.queryParams ? { queryParams: config.queryParams } : {},
|
|
1250
|
-
// Prefer the caller's explicit template; otherwise
|
|
1251
|
-
//
|
|
1252
|
-
// path relies on this — it has no preview to detect auth from);
|
|
1253
|
-
// otherwise derive from the spec's declared security schemes.
|
|
1338
|
+
// Prefer the caller's explicit template; otherwise derive from the
|
|
1339
|
+
// spec's declared security schemes.
|
|
1254
1340
|
...config.authenticationTemplate ? {
|
|
1255
1341
|
authenticationTemplate: normalizeOpenApiAuthInputs(config.authenticationTemplate)
|
|
1256
|
-
} :
|
|
1342
|
+
} : derivedAuthenticationTemplate && derivedAuthenticationTemplate.length > 0 ? { authenticationTemplate: derivedAuthenticationTemplate } : {}
|
|
1257
1343
|
};
|
|
1258
1344
|
yield* ctx.storage.putSpec(specHash, resolved.specText);
|
|
1259
1345
|
yield* ctx.transaction(
|
|
1260
|
-
|
|
1346
|
+
Effect4.gen(function* () {
|
|
1261
1347
|
yield* ctx.core.integrations.register({
|
|
1262
1348
|
slug,
|
|
1263
1349
|
name: config.name?.trim() || compiled.title || config.slug,
|
|
1264
1350
|
description: config.description ?? compiled.description ?? compiled.title ?? config.slug,
|
|
1265
1351
|
config: integrationConfig,
|
|
1266
1352
|
canRemove: true,
|
|
1267
|
-
canRefresh: specInputToSourceUrl(config.spec) != null
|
|
1353
|
+
canRefresh: specInputToSourceUrl(config.spec) != null
|
|
1268
1354
|
});
|
|
1269
1355
|
yield* ctx.storage.putOperations(
|
|
1270
1356
|
config.slug,
|
|
1271
|
-
|
|
1357
|
+
openApiStoredOperationsFromCompiled(config.slug, compiled)
|
|
1272
1358
|
);
|
|
1273
1359
|
})
|
|
1274
1360
|
);
|
|
1275
1361
|
return { slug, toolCount: compiled.definitions.length };
|
|
1276
1362
|
});
|
|
1277
|
-
const updateSpec = (rawSlug, input) =>
|
|
1363
|
+
const updateSpec = (rawSlug, input) => Effect4.gen(function* () {
|
|
1278
1364
|
const slug = IntegrationSlug.make(rawSlug);
|
|
1279
1365
|
const record = yield* ctx.core.integrations.get(slug);
|
|
1280
1366
|
const current = record ? decodeOpenApiIntegrationConfig(record.config) : null;
|
|
1281
1367
|
if (!record || !current) {
|
|
1282
1368
|
return yield* new IntegrationNotFoundError({ slug });
|
|
1283
1369
|
}
|
|
1284
|
-
const specInput = input?.spec ?? (current.
|
|
1370
|
+
const specInput = input?.spec ?? (current.sourceUrl ? { kind: "url", url: current.sourceUrl } : null);
|
|
1285
1371
|
if (specInput === null) {
|
|
1286
1372
|
return yield* new OpenApiParseError({
|
|
1287
1373
|
message: "This integration's spec was pasted inline and has no source URL to re-fetch. Provide the updated spec content."
|
|
1288
1374
|
});
|
|
1289
1375
|
}
|
|
1290
1376
|
const resolved = yield* resolveSpecForInput(specInput, httpClientLayer);
|
|
1291
|
-
const compiled = yield*
|
|
1377
|
+
const compiled = yield* compileOpenApiSpec(resolved.specText);
|
|
1292
1378
|
const previousOperations = yield* ctx.storage.listOperations(rawSlug);
|
|
1293
1379
|
const previousNames = new Set(previousOperations.map((op) => op.toolName));
|
|
1294
1380
|
const nextNames = new Set(compiled.definitions.map((def) => def.toolPath));
|
|
@@ -1297,32 +1383,31 @@ var openApiPlugin = definePlugin((options) => {
|
|
|
1297
1383
|
const nextConfig = {
|
|
1298
1384
|
...current,
|
|
1299
1385
|
specHash,
|
|
1300
|
-
...specInputToSourceUrl(specInput) !== void 0 ? { sourceUrl: specInputToSourceUrl(specInput) } : {}
|
|
1301
|
-
...specInputToGoogleBundle(specInput) !== void 0 ? { googleDiscoveryUrls: specInputToGoogleBundle(specInput) } : {}
|
|
1386
|
+
...specInputToSourceUrl(specInput) !== void 0 ? { sourceUrl: specInputToSourceUrl(specInput) } : {}
|
|
1302
1387
|
};
|
|
1303
1388
|
yield* ctx.transaction(
|
|
1304
|
-
|
|
1389
|
+
Effect4.gen(function* () {
|
|
1305
1390
|
yield* ctx.core.integrations.update(slug, {
|
|
1306
1391
|
config: nextConfig
|
|
1307
1392
|
});
|
|
1308
1393
|
yield* ctx.storage.putOperations(
|
|
1309
1394
|
rawSlug,
|
|
1310
|
-
|
|
1395
|
+
openApiStoredOperationsFromCompiled(rawSlug, compiled)
|
|
1311
1396
|
);
|
|
1312
1397
|
})
|
|
1313
1398
|
);
|
|
1314
1399
|
const connections = yield* ctx.connections.list({ integration: slug });
|
|
1315
|
-
yield*
|
|
1400
|
+
yield* Effect4.forEach(
|
|
1316
1401
|
connections,
|
|
1317
1402
|
(connection) => ctx.connections.refresh({
|
|
1318
1403
|
owner: connection.owner,
|
|
1319
1404
|
integration: connection.integration,
|
|
1320
1405
|
name: connection.name
|
|
1321
|
-
}).pipe(
|
|
1406
|
+
}).pipe(Effect4.catchTag("ConnectionNotFoundError", () => Effect4.succeed([]))),
|
|
1322
1407
|
{ discard: true }
|
|
1323
1408
|
).pipe(
|
|
1324
|
-
|
|
1325
|
-
|
|
1409
|
+
Effect4.catchTag("IntegrationNotFoundError", () => Effect4.void),
|
|
1410
|
+
Effect4.withSpan("openapi.plugin.update_spec.refresh_connections", {
|
|
1326
1411
|
attributes: { "openapi.connection_count": connections.length }
|
|
1327
1412
|
})
|
|
1328
1413
|
);
|
|
@@ -1333,35 +1418,28 @@ var openApiPlugin = definePlugin((options) => {
|
|
|
1333
1418
|
removedTools: [...previousNames].filter((name) => !nextNames.has(name)).sort()
|
|
1334
1419
|
};
|
|
1335
1420
|
}).pipe(
|
|
1336
|
-
|
|
1421
|
+
Effect4.withSpan("openapi.plugin.update_spec", {
|
|
1337
1422
|
attributes: { "openapi.integration.slug": rawSlug }
|
|
1338
1423
|
})
|
|
1339
1424
|
);
|
|
1340
1425
|
return {
|
|
1341
|
-
previewSpec: (input) =>
|
|
1426
|
+
previewSpec: (input) => Effect4.gen(function* () {
|
|
1342
1427
|
const previewInput = typeof input === "string" ? { spec: input } : input;
|
|
1343
|
-
const specText =
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
discoveryUrl: previewInput.spec,
|
|
1348
|
-
documentText
|
|
1349
|
-
})
|
|
1350
|
-
),
|
|
1351
|
-
Effect3.map((conversion) => conversion.specText)
|
|
1352
|
-
) : yield* resolveSpecText(previewInput.spec).pipe(Effect3.provide(httpClientLayer));
|
|
1353
|
-
return yield* previewSpec(specText).pipe(Effect3.provide(httpClientLayer));
|
|
1428
|
+
const specText = yield* resolveSpecText(previewInput.spec).pipe(
|
|
1429
|
+
Effect4.provide(httpClientLayer)
|
|
1430
|
+
);
|
|
1431
|
+
return yield* previewSpecText(specText);
|
|
1354
1432
|
}),
|
|
1355
1433
|
addSpec,
|
|
1356
1434
|
updateSpec,
|
|
1357
1435
|
removeSpec: (slug) => ctx.transaction(
|
|
1358
|
-
|
|
1436
|
+
Effect4.gen(function* () {
|
|
1359
1437
|
yield* ctx.storage.removeOperations(slug);
|
|
1360
|
-
yield* ctx.core.integrations.remove(IntegrationSlug.make(slug)).pipe(
|
|
1438
|
+
yield* ctx.core.integrations.remove(IntegrationSlug.make(slug)).pipe(Effect4.catchTag("IntegrationRemovalNotAllowedError", () => Effect4.void));
|
|
1361
1439
|
})
|
|
1362
1440
|
),
|
|
1363
1441
|
getIntegration: (slug) => ctx.core.integrations.get(IntegrationSlug.make(slug)).pipe(
|
|
1364
|
-
|
|
1442
|
+
Effect4.map(
|
|
1365
1443
|
(record) => record ? {
|
|
1366
1444
|
slug: record.slug,
|
|
1367
1445
|
description: record.description,
|
|
@@ -1372,12 +1450,12 @@ var openApiPlugin = definePlugin((options) => {
|
|
|
1372
1450
|
)
|
|
1373
1451
|
),
|
|
1374
1452
|
getConfig: (slug) => ctx.core.integrations.get(IntegrationSlug.make(slug)).pipe(
|
|
1375
|
-
|
|
1453
|
+
Effect4.map(
|
|
1376
1454
|
(record) => record ? decodeOpenApiIntegrationConfig(record.config) : null
|
|
1377
1455
|
)
|
|
1378
1456
|
),
|
|
1379
1457
|
configure: (slug, input) => ctx.transaction(
|
|
1380
|
-
|
|
1458
|
+
Effect4.gen(function* () {
|
|
1381
1459
|
const record = yield* ctx.core.integrations.get(IntegrationSlug.make(slug));
|
|
1382
1460
|
if (!record) return [];
|
|
1383
1461
|
const current = decodeOpenApiIntegrationConfig(record.config);
|
|
@@ -1408,17 +1486,17 @@ var openApiPlugin = definePlugin((options) => {
|
|
|
1408
1486
|
inputSchema: PreviewSpecInputStandardSchema,
|
|
1409
1487
|
outputSchema: PreviewSpecOutputStandardSchema,
|
|
1410
1488
|
execute: (input) => self.previewSpec(input).pipe(
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
OpenApiParseError: ({ message }) =>
|
|
1414
|
-
OpenApiExtractionError: ({ message }) =>
|
|
1415
|
-
OpenApiOAuthError: ({ message }) =>
|
|
1489
|
+
Effect4.map((preview) => ToolResult2.ok(staticPreviewOutput(preview))),
|
|
1490
|
+
Effect4.catchTags({
|
|
1491
|
+
OpenApiParseError: ({ message }) => Effect4.succeed(openApiToolFailure("openapi_parse_failed", message)),
|
|
1492
|
+
OpenApiExtractionError: ({ message }) => Effect4.succeed(openApiToolFailure("openapi_extraction_failed", message)),
|
|
1493
|
+
OpenApiOAuthError: ({ message }) => Effect4.succeed(openApiToolFailure("openapi_oauth_failed", message))
|
|
1416
1494
|
})
|
|
1417
1495
|
)
|
|
1418
1496
|
}),
|
|
1419
1497
|
tool({
|
|
1420
1498
|
name: "addSpec",
|
|
1421
|
-
description: "Add an OpenAPI integration to the catalog and persist its operations as tools. Recommended flow: call `previewSpec`, choose a `slug`, then create a connection for that integration with the user's API key or via `oauth.start`. When `baseUrl` is omitted it defaults to the spec's first server; when `authenticationTemplate` is omitted the auth methods are derived from the spec's declared security schemes (pass an explicit template to override how a credential is applied
|
|
1499
|
+
description: "Add an OpenAPI integration to the catalog and persist its operations as tools. Recommended flow: call `previewSpec`, choose a `slug`, then create a connection for that integration with the user's API key or via `oauth.start`. When `baseUrl` is omitted it defaults to the spec's first server; when `authenticationTemplate` is omitted the auth methods are derived from the spec's declared security schemes (pass an explicit template to override how a credential is applied - apiKey header/query, or oauth bearer - or an empty array for no auth methods).",
|
|
1422
1500
|
annotations: {
|
|
1423
1501
|
requiresApproval: true,
|
|
1424
1502
|
approvalDescription: "Add an OpenAPI integration"
|
|
@@ -1434,17 +1512,17 @@ var openApiPlugin = definePlugin((options) => {
|
|
|
1434
1512
|
queryParams: input.queryParams,
|
|
1435
1513
|
authenticationTemplate: input.authenticationTemplate
|
|
1436
1514
|
}).pipe(
|
|
1437
|
-
|
|
1438
|
-
(result) =>
|
|
1515
|
+
Effect4.map(
|
|
1516
|
+
(result) => ToolResult2.ok({
|
|
1439
1517
|
slug: String(result.slug),
|
|
1440
1518
|
toolCount: result.toolCount
|
|
1441
1519
|
})
|
|
1442
1520
|
),
|
|
1443
|
-
|
|
1444
|
-
OpenApiParseError: ({ message }) =>
|
|
1445
|
-
OpenApiExtractionError: ({ message }) =>
|
|
1446
|
-
OpenApiOAuthError: ({ message }) =>
|
|
1447
|
-
IntegrationAlreadyExistsError: ({ slug }) =>
|
|
1521
|
+
Effect4.catchTags({
|
|
1522
|
+
OpenApiParseError: ({ message }) => Effect4.succeed(openApiToolFailure("openapi_parse_failed", message)),
|
|
1523
|
+
OpenApiExtractionError: ({ message }) => Effect4.succeed(openApiToolFailure("openapi_extraction_failed", message)),
|
|
1524
|
+
OpenApiOAuthError: ({ message }) => Effect4.succeed(openApiToolFailure("openapi_oauth_failed", message)),
|
|
1525
|
+
IntegrationAlreadyExistsError: ({ slug }) => Effect4.succeed(
|
|
1448
1526
|
openApiToolFailure(
|
|
1449
1527
|
"integration_already_exists",
|
|
1450
1528
|
`Integration ${slug} already exists; update it instead of re-adding.`
|
|
@@ -1459,176 +1537,50 @@ var openApiPlugin = definePlugin((options) => {
|
|
|
1459
1537
|
describeAuthMethods: describeOpenApiAuthMethods,
|
|
1460
1538
|
describeIntegrationDisplay: describeOpenApiIntegrationDisplay,
|
|
1461
1539
|
// Produce one tool per spec operation. Spec-derived, identical for every
|
|
1462
|
-
// connection on the integration
|
|
1540
|
+
// connection on the integration - so `getValue` is never called here. The
|
|
1463
1541
|
// operation bindings invokeTool needs are persisted at addSpec time; this
|
|
1464
1542
|
// hook only shapes the per-connection ToolDefs from the spec blob the
|
|
1465
1543
|
// catalog config points at.
|
|
1466
|
-
resolveTools: ({
|
|
1467
|
-
|
|
1468
|
-
storage
|
|
1469
|
-
}) => Effect3.gen(function* () {
|
|
1470
|
-
const openApiConfig = decodeOpenApiIntegrationConfig(config);
|
|
1471
|
-
if (!openApiConfig) return { tools: [], definitions: {} };
|
|
1472
|
-
const specText = yield* loadSpecText(storage, openApiConfig);
|
|
1473
|
-
if (specText == null) return { tools: [], definitions: {} };
|
|
1474
|
-
const compiled = yield* compileSpec(specText).pipe(
|
|
1475
|
-
Effect3.catch(() => Effect3.succeed(null))
|
|
1476
|
-
);
|
|
1477
|
-
if (!compiled) return { tools: [], definitions: {} };
|
|
1478
|
-
return {
|
|
1479
|
-
tools: toolDefsFromCompiled(compiled),
|
|
1480
|
-
definitions: compiled.hoistedDefs
|
|
1481
|
-
};
|
|
1482
|
-
}),
|
|
1483
|
-
invokeTool: ({
|
|
1484
|
-
ctx: invokeCtx,
|
|
1485
|
-
toolRow,
|
|
1486
|
-
credential,
|
|
1487
|
-
args
|
|
1488
|
-
}) => Effect3.gen(function* () {
|
|
1544
|
+
resolveTools: ({ config, storage }) => resolveOpenApiBackedTools({ config, storage }),
|
|
1545
|
+
invokeTool: ({ ctx: invokeCtx, toolRow, credential, args }) => {
|
|
1489
1546
|
const httpClientLayer = options?.httpClientLayer ?? invokeCtx.httpClientLayer;
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
);
|
|
1496
|
-
const compiled = specText == null ? null : yield* compileSpec(specText).pipe(Effect3.catch(() => Effect3.succeed(null)));
|
|
1497
|
-
return compiled ? storedOperationsFromCompiled(integration, compiled).find(
|
|
1498
|
-
(op) => op.toolName === toolRow.name
|
|
1499
|
-
)?.binding : void 0;
|
|
1500
|
-
}) : Effect3.succeed(void 0);
|
|
1501
|
-
let binding = (yield* invokeCtx.storage.getOperation(integration, toolRow.name))?.binding;
|
|
1502
|
-
if ((!binding || Option5.isNone(binding.responseBody)) && config) {
|
|
1503
|
-
binding = (yield* bindingFromSpec) ?? binding;
|
|
1504
|
-
}
|
|
1505
|
-
if (!binding) {
|
|
1506
|
-
return yield* new OpenApiExtractionError({
|
|
1507
|
-
message: `No OpenAPI operation found for tool "${toolRow.name}" on "${integration}"`
|
|
1508
|
-
});
|
|
1509
|
-
}
|
|
1510
|
-
const headers = { ...config?.headers ?? {} };
|
|
1511
|
-
const queryParams = {
|
|
1512
|
-
...config?.queryParams ?? {}
|
|
1513
|
-
};
|
|
1514
|
-
const template = (config?.authenticationTemplate ?? []).find(
|
|
1515
|
-
(entry) => String(entry.slug) === String(credential.template)
|
|
1516
|
-
);
|
|
1517
|
-
if (template) {
|
|
1518
|
-
const missing = requiredTemplateVariables(template).filter((name) => {
|
|
1519
|
-
const value = credential.values[name];
|
|
1520
|
-
return value == null || value === "";
|
|
1521
|
-
});
|
|
1522
|
-
if (missing.length > 0) {
|
|
1523
|
-
return openApiAuthToolFailure({
|
|
1524
|
-
code: template.kind === "oauth2" ? "oauth_connection_missing" : "connection_value_missing",
|
|
1525
|
-
message: `Connection "${credential.connection}" for "${integration}" has no resolvable credential value. Re-authenticate or update the connection.`,
|
|
1526
|
-
owner: credential.owner,
|
|
1527
|
-
integration,
|
|
1528
|
-
connection: String(credential.connection),
|
|
1529
|
-
credentialKind: template.kind === "oauth2" ? "oauth" : "secret"
|
|
1530
|
-
});
|
|
1531
|
-
}
|
|
1532
|
-
const rendered = renderAuthTemplate(template, credential.values);
|
|
1533
|
-
Object.assign(headers, rendered.headers);
|
|
1534
|
-
Object.assign(queryParams, rendered.queryParams);
|
|
1535
|
-
}
|
|
1536
|
-
const result = yield* invokeWithLayer(
|
|
1537
|
-
binding,
|
|
1538
|
-
args ?? {},
|
|
1539
|
-
config?.baseUrl ?? "",
|
|
1540
|
-
headers,
|
|
1541
|
-
queryParams,
|
|
1547
|
+
return invokeOpenApiBackedTool({
|
|
1548
|
+
ctx: invokeCtx,
|
|
1549
|
+
toolRow,
|
|
1550
|
+
credential,
|
|
1551
|
+
args,
|
|
1542
1552
|
httpClientLayer
|
|
1543
|
-
);
|
|
1544
|
-
const ok = result.status >= 200 && result.status < 300;
|
|
1545
|
-
if (!ok) {
|
|
1546
|
-
if (result.status === 401 || result.status === 403) {
|
|
1547
|
-
return openApiAuthToolFailure({
|
|
1548
|
-
code: "connection_rejected",
|
|
1549
|
-
status: result.status,
|
|
1550
|
-
message: `Upstream rejected credentials for "${integration}" with HTTP ${result.status}. Re-authenticate or update the connection "${credential.connection}" before retrying this tool.`,
|
|
1551
|
-
owner: credential.owner,
|
|
1552
|
-
integration,
|
|
1553
|
-
connection: String(credential.connection),
|
|
1554
|
-
credentialKind: "upstream",
|
|
1555
|
-
credentialLabel: "Upstream authorization",
|
|
1556
|
-
details: result.error
|
|
1557
|
-
});
|
|
1558
|
-
}
|
|
1559
|
-
return ToolResult.fail({
|
|
1560
|
-
code: "upstream_http_error",
|
|
1561
|
-
status: result.status,
|
|
1562
|
-
message: extractUpstreamMessage(result.error, result.status),
|
|
1563
|
-
details: result.error
|
|
1564
|
-
});
|
|
1565
|
-
}
|
|
1566
|
-
return ToolResult.ok(result.data, {
|
|
1567
|
-
http: { status: result.status, headers: result.headers }
|
|
1568
1553
|
});
|
|
1569
|
-
}
|
|
1570
|
-
resolveAnnotations: ({
|
|
1554
|
+
},
|
|
1555
|
+
resolveAnnotations: ({ ctx: annotationsCtx, integration, toolRows }) => resolveOpenApiBackedAnnotations({
|
|
1571
1556
|
ctx: annotationsCtx,
|
|
1572
|
-
integration,
|
|
1557
|
+
integration: String(integration),
|
|
1573
1558
|
toolRows
|
|
1574
|
-
}) => Effect3.gen(function* () {
|
|
1575
|
-
const ops = yield* annotationsCtx.storage.listOperations(String(integration));
|
|
1576
|
-
const byName = /* @__PURE__ */ new Map();
|
|
1577
|
-
for (const op of ops) byName.set(op.toolName, op.binding);
|
|
1578
|
-
const out = {};
|
|
1579
|
-
for (const row of toolRows) {
|
|
1580
|
-
const binding = byName.get(row.name);
|
|
1581
|
-
if (binding) {
|
|
1582
|
-
out[row.name] = annotationsForOperation(binding.method, binding.pathTemplate);
|
|
1583
|
-
}
|
|
1584
|
-
}
|
|
1585
|
-
return out;
|
|
1586
1559
|
}),
|
|
1587
|
-
removeConnection: () =>
|
|
1560
|
+
removeConnection: () => Effect4.void,
|
|
1588
1561
|
detect: ({
|
|
1589
1562
|
ctx: detectCtx,
|
|
1590
1563
|
url
|
|
1591
|
-
}) =>
|
|
1564
|
+
}) => Effect4.gen(function* () {
|
|
1592
1565
|
const httpClientLayer = options?.httpClientLayer ?? detectCtx.httpClientLayer;
|
|
1593
1566
|
const trimmed = url.trim();
|
|
1594
1567
|
if (!trimmed) return null;
|
|
1595
|
-
const parsed = yield*
|
|
1568
|
+
const parsed = yield* Effect4.try({
|
|
1596
1569
|
try: () => new URL(trimmed),
|
|
1597
1570
|
catch: (error) => error
|
|
1598
|
-
}).pipe(
|
|
1599
|
-
if (
|
|
1600
|
-
if (isGoogleDiscoveryUrl(trimmed)) {
|
|
1601
|
-
const conversion = yield* fetchGoogleDiscoveryDocument(trimmed).pipe(
|
|
1602
|
-
Effect3.provide(httpClientLayer),
|
|
1603
|
-
Effect3.flatMap(
|
|
1604
|
-
(documentText) => convertGoogleDiscoveryToOpenApi({
|
|
1605
|
-
discoveryUrl: trimmed,
|
|
1606
|
-
documentText
|
|
1607
|
-
})
|
|
1608
|
-
),
|
|
1609
|
-
Effect3.catch(() => Effect3.succeed(null))
|
|
1610
|
-
);
|
|
1611
|
-
if (conversion) {
|
|
1612
|
-
return IntegrationDetectionResult.make({
|
|
1613
|
-
kind: "openapi",
|
|
1614
|
-
confidence: "high",
|
|
1615
|
-
endpoint: trimmed,
|
|
1616
|
-
name: conversion.title,
|
|
1617
|
-
slug: conversion.title.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "") || `google_${conversion.service}`
|
|
1618
|
-
});
|
|
1619
|
-
}
|
|
1620
|
-
}
|
|
1571
|
+
}).pipe(Effect4.option);
|
|
1572
|
+
if (Option6.isNone(parsed)) return null;
|
|
1621
1573
|
const specText = yield* resolveSpecText(trimmed).pipe(
|
|
1622
|
-
|
|
1623
|
-
|
|
1574
|
+
Effect4.provide(httpClientLayer),
|
|
1575
|
+
Effect4.catch(() => Effect4.succeed(null))
|
|
1624
1576
|
);
|
|
1625
1577
|
if (specText === null) return null;
|
|
1626
|
-
const doc = yield* parse(specText).pipe(
|
|
1578
|
+
const doc = yield* parse(specText).pipe(Effect4.catch(() => Effect4.succeed(null)));
|
|
1627
1579
|
if (!doc) return null;
|
|
1628
|
-
const result = yield* extract(doc).pipe(
|
|
1580
|
+
const result = yield* extract(doc).pipe(Effect4.catch(() => Effect4.succeed(null)));
|
|
1629
1581
|
if (!result) return null;
|
|
1630
|
-
const slug =
|
|
1631
|
-
const name =
|
|
1582
|
+
const slug = Option6.getOrElse(result.title, () => "api").toLowerCase().replace(/[^a-z0-9]+/g, "_");
|
|
1583
|
+
const name = Option6.getOrElse(result.title, () => slug);
|
|
1632
1584
|
return IntegrationDetectionResult.make({
|
|
1633
1585
|
kind: "openapi",
|
|
1634
1586
|
confidence: "high",
|
|
@@ -1645,10 +1597,20 @@ export {
|
|
|
1645
1597
|
OpenApiIntegrationConfigSchema,
|
|
1646
1598
|
decodeOpenApiIntegrationConfig,
|
|
1647
1599
|
renderAuthTemplate,
|
|
1600
|
+
makeDefaultOpenapiStore,
|
|
1648
1601
|
invoke,
|
|
1649
1602
|
invokeWithLayer,
|
|
1650
1603
|
annotationsForOperation,
|
|
1651
|
-
|
|
1604
|
+
extractOpenApiUpstreamMessage,
|
|
1605
|
+
normalizeOpenApiRefs,
|
|
1606
|
+
compileOpenApiDocument,
|
|
1607
|
+
compileOpenApiSpec,
|
|
1608
|
+
openApiToolDefsFromCompiled,
|
|
1609
|
+
openApiStoredOperationsFromCompiled,
|
|
1610
|
+
loadOpenApiSpecText,
|
|
1611
|
+
resolveOpenApiBackedTools,
|
|
1612
|
+
invokeOpenApiBackedTool,
|
|
1613
|
+
resolveOpenApiBackedAnnotations,
|
|
1652
1614
|
openApiPlugin
|
|
1653
1615
|
};
|
|
1654
|
-
//# sourceMappingURL=chunk-
|
|
1616
|
+
//# sourceMappingURL=chunk-3FM2SWM4.js.map
|