@executor-js/plugin-openapi 1.5.15 → 1.5.17
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-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/{chunk-ZTOOUP67.js → chunk-UEKOP6NZ.js} +544 -580
- package/dist/chunk-UEKOP6NZ.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-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 → request-user-agent.test.d.ts} +0 -0
- /package/dist/sdk/{google-discovery.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,11 +231,12 @@ 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;
|
|
152
238
|
});
|
|
239
|
+
var DEFAULT_USER_AGENT = "executor";
|
|
153
240
|
var applyHeaders = (request, headers) => {
|
|
154
241
|
let req = request;
|
|
155
242
|
for (const [name, value] of Object.entries(headers)) {
|
|
@@ -250,9 +337,9 @@ var toUint8Array = (value) => {
|
|
|
250
337
|
}
|
|
251
338
|
return null;
|
|
252
339
|
};
|
|
253
|
-
var readHintString = (option, fallback) =>
|
|
254
|
-
var readHintMimeType = (hint, fallback) =>
|
|
255
|
-
var readHintEncoding = (hint) =>
|
|
340
|
+
var readHintString = (option, fallback) => Option3.getOrElse(option, () => fallback);
|
|
341
|
+
var readHintMimeType = (hint, fallback) => Option3.getOrElse(hint.mimeType, () => fallback);
|
|
342
|
+
var readHintEncoding = (hint) => Option3.getOrElse(hint.encoding, () => "base64");
|
|
256
343
|
var fileFromByteField = (body, hint) => {
|
|
257
344
|
if (typeof body !== "object" || body === null || Array.isArray(body)) return null;
|
|
258
345
|
const record = body;
|
|
@@ -260,7 +347,7 @@ var fileFromByteField = (body, hint) => {
|
|
|
260
347
|
const rawData = record[dataField];
|
|
261
348
|
if (typeof rawData !== "string") return null;
|
|
262
349
|
const data = normalizeBase64(rawData, readHintEncoding(hint));
|
|
263
|
-
const sizeField =
|
|
350
|
+
const sizeField = Option3.getOrUndefined(hint.sizeField);
|
|
264
351
|
const byteLength = sizeField && typeof record[sizeField] === "number" ? record[sizeField] : byteLengthFromBase64(data);
|
|
265
352
|
const hintedMimeType = readHintMimeType(hint, "application/octet-stream");
|
|
266
353
|
return {
|
|
@@ -294,9 +381,9 @@ var DEFAULT_FORM_STYLE = {
|
|
|
294
381
|
var resolveStyleExplode = (e) => {
|
|
295
382
|
if (!e) return DEFAULT_FORM_STYLE;
|
|
296
383
|
return {
|
|
297
|
-
style:
|
|
298
|
-
explode:
|
|
299
|
-
allowReserved:
|
|
384
|
+
style: Option3.getOrElse(e.style, () => DEFAULT_FORM_STYLE.style),
|
|
385
|
+
explode: Option3.getOrElse(e.explode, () => DEFAULT_FORM_STYLE.explode),
|
|
386
|
+
allowReserved: Option3.getOrElse(e.allowReserved, () => DEFAULT_FORM_STYLE.allowReserved)
|
|
300
387
|
};
|
|
301
388
|
};
|
|
302
389
|
var encodeFormValue = (v, allowReserved) => {
|
|
@@ -356,7 +443,7 @@ var coerceFormDataRecord = (value, encoding) => {
|
|
|
356
443
|
const out = {};
|
|
357
444
|
for (const [key, raw] of Object.entries(value)) {
|
|
358
445
|
if (raw === void 0 || raw === null) continue;
|
|
359
|
-
const partType = encoding?.[key] ?
|
|
446
|
+
const partType = encoding?.[key] ? Option3.getOrUndefined(encoding[key].contentType) : void 0;
|
|
360
447
|
if (partType) {
|
|
361
448
|
const isJson = partType.startsWith("application/json") || partType.includes("+json");
|
|
362
449
|
const serialized = typeof raw === "string" ? raw : isJson ? JSON.stringify(raw) : typeof raw === "object" ? JSON.stringify(raw) : String(raw);
|
|
@@ -437,9 +524,9 @@ var applyRequestBody = (request, contentType, bodyValue, encoding) => {
|
|
|
437
524
|
if (bytes) return HttpClientRequest.bodyUint8Array(request, bytes, contentType);
|
|
438
525
|
return HttpClientRequest.bodyText(request, JSON.stringify(bodyValue), contentType);
|
|
439
526
|
};
|
|
440
|
-
var invoke =
|
|
527
|
+
var invoke = Effect2.fn("OpenApi.invoke")(function* (operation, args, resolvedHeaders, sourceQueryParams = {}) {
|
|
441
528
|
const client = yield* HttpClient.HttpClient;
|
|
442
|
-
yield*
|
|
529
|
+
yield* Effect2.annotateCurrentSpan({
|
|
443
530
|
"http.method": operation.method.toUpperCase(),
|
|
444
531
|
"http.route": operation.pathTemplate,
|
|
445
532
|
"plugin.openapi.method": operation.method.toUpperCase(),
|
|
@@ -449,6 +536,7 @@ var invoke = Effect.fn("OpenApi.invoke")(function* (operation, args, resolvedHea
|
|
|
449
536
|
const resolvedPath = yield* resolvePath(operation.pathTemplate, args, operation.parameters);
|
|
450
537
|
const path = resolvedPath.startsWith("/") ? resolvedPath : `/${resolvedPath}`;
|
|
451
538
|
let request = HttpClientRequest.make(operation.method.toUpperCase())(path);
|
|
539
|
+
request = HttpClientRequest.setHeader(request, "User-Agent", DEFAULT_USER_AGENT);
|
|
452
540
|
for (const [name, value] of Object.entries(sourceQueryParams)) {
|
|
453
541
|
request = HttpClientRequest.setUrlParam(request, name, value);
|
|
454
542
|
}
|
|
@@ -465,50 +553,50 @@ var invoke = Effect.fn("OpenApi.invoke")(function* (operation, args, resolvedHea
|
|
|
465
553
|
if (value === void 0 || value === null) continue;
|
|
466
554
|
request = HttpClientRequest.setHeader(request, param.name, String(value));
|
|
467
555
|
}
|
|
468
|
-
if (
|
|
556
|
+
if (Option3.isSome(operation.requestBody)) {
|
|
469
557
|
const rb = operation.requestBody.value;
|
|
470
558
|
const bodyValue = args.body ?? args.input;
|
|
471
559
|
if (bodyValue !== void 0) {
|
|
472
|
-
const contentsOpt =
|
|
560
|
+
const contentsOpt = Option3.getOrUndefined(rb.contents);
|
|
473
561
|
const requestedCt = typeof args.contentType === "string" ? args.contentType : void 0;
|
|
474
562
|
const selected = contentsOpt && requestedCt ? contentsOpt.find((c) => c.contentType === requestedCt) : void 0;
|
|
475
563
|
const chosenCt = selected?.contentType ?? rb.contentType;
|
|
476
|
-
const chosenEncoding = selected ?
|
|
564
|
+
const chosenEncoding = selected ? Option3.getOrUndefined(selected.encoding) : contentsOpt && contentsOpt[0] ? Option3.getOrUndefined(contentsOpt[0].encoding) : void 0;
|
|
477
565
|
request = applyRequestBody(request, chosenCt, bodyValue, chosenEncoding);
|
|
478
566
|
}
|
|
479
567
|
}
|
|
480
568
|
request = applyHeaders(request, resolvedHeaders);
|
|
481
569
|
const response = yield* client.execute(request).pipe(
|
|
482
|
-
|
|
570
|
+
Effect2.mapError(
|
|
483
571
|
(err) => new OpenApiInvocationError({
|
|
484
572
|
message: "HTTP request failed",
|
|
485
|
-
statusCode:
|
|
573
|
+
statusCode: Option3.none(),
|
|
486
574
|
cause: err
|
|
487
575
|
})
|
|
488
576
|
)
|
|
489
577
|
);
|
|
490
578
|
const status = response.status;
|
|
491
|
-
yield*
|
|
579
|
+
yield* Effect2.annotateCurrentSpan({
|
|
492
580
|
"http.status_code": status
|
|
493
581
|
});
|
|
494
582
|
const responseHeaders = { ...response.headers };
|
|
495
583
|
const contentType = response.headers["content-type"] ?? null;
|
|
496
|
-
const mapBodyError =
|
|
584
|
+
const mapBodyError = Effect2.mapError(
|
|
497
585
|
(err) => new OpenApiInvocationError({
|
|
498
586
|
message: "Failed to read response body",
|
|
499
|
-
statusCode:
|
|
587
|
+
statusCode: Option3.some(status),
|
|
500
588
|
cause: err
|
|
501
589
|
})
|
|
502
590
|
);
|
|
503
|
-
const responseBodyBinding =
|
|
504
|
-
const fileHint = responseBodyBinding ?
|
|
591
|
+
const responseBodyBinding = Option3.getOrUndefined(operation.responseBody);
|
|
592
|
+
const fileHint = responseBodyBinding ? Option3.getOrUndefined(responseBodyBinding.fileHint) : void 0;
|
|
505
593
|
const ok = status >= 200 && status < 300;
|
|
506
594
|
const responseBody = status === 204 ? null : ok && fileHint?.kind === "binaryResponse" ? fileFromBinaryBytes(
|
|
507
595
|
new Uint8Array(yield* response.arrayBuffer.pipe(mapBodyError)),
|
|
508
596
|
fileHint,
|
|
509
597
|
contentType
|
|
510
598
|
) : isJsonContentType(contentType) ? yield* response.json.pipe(
|
|
511
|
-
|
|
599
|
+
Effect2.catch(() => response.text),
|
|
512
600
|
mapBodyError
|
|
513
601
|
) : yield* response.text.pipe(mapBodyError);
|
|
514
602
|
const dataBody = ok && fileHint?.kind === "byteField" ? fileFromByteField(responseBody, fileHint) ?? responseBody : responseBody;
|
|
@@ -530,25 +618,25 @@ var resolveRequestHost = (servers, serverArg, baseUrl) => {
|
|
|
530
618
|
if (value != null && value !== "") overrides[name] = String(value);
|
|
531
619
|
}
|
|
532
620
|
}
|
|
533
|
-
return resolveServerUrl(chosen.url,
|
|
621
|
+
return resolveServerUrl(chosen.url, Option3.getOrUndefined(chosen.variables), overrides);
|
|
534
622
|
};
|
|
535
623
|
var invokeWithLayer = (operation, args, baseUrl, resolvedHeaders, sourceQueryParams, httpClientLayer) => {
|
|
536
624
|
const effectiveBaseUrl = resolveRequestHost(operation.servers ?? [], args.server, baseUrl);
|
|
537
625
|
const clientWithBaseUrl = effectiveBaseUrl ? Layer.effect(
|
|
538
626
|
HttpClient.HttpClient,
|
|
539
|
-
|
|
540
|
-
|
|
627
|
+
Effect2.map(
|
|
628
|
+
Effect2.service(HttpClient.HttpClient),
|
|
541
629
|
HttpClient.mapRequest(HttpClientRequest.prependUrl(effectiveBaseUrl))
|
|
542
630
|
)
|
|
543
631
|
).pipe(Layer.provide(httpClientLayer)) : httpClientLayer;
|
|
544
632
|
return invoke(operation, args, resolvedHeaders, sourceQueryParams).pipe(
|
|
545
|
-
|
|
633
|
+
Effect2.provide(clientWithBaseUrl),
|
|
546
634
|
// `invoke` annotates http.status_code on ITS span (`OpenApi.invoke`,
|
|
547
635
|
// via Effect.fn) — annotateCurrentSpan inside it never reaches this
|
|
548
636
|
// wrapper span. Stamp the status here too so queries against
|
|
549
637
|
// `plugin.openapi.invoke` see the upstream outcome directly.
|
|
550
|
-
|
|
551
|
-
|
|
638
|
+
Effect2.tap((result) => Effect2.annotateCurrentSpan({ "http.status_code": result.status })),
|
|
639
|
+
Effect2.withSpan("plugin.openapi.invoke", {
|
|
552
640
|
attributes: {
|
|
553
641
|
"plugin.openapi.method": operation.method.toUpperCase(),
|
|
554
642
|
"plugin.openapi.path_template": operation.pathTemplate,
|
|
@@ -567,89 +655,13 @@ var annotationsForOperation = (method, pathTemplate) => {
|
|
|
567
655
|
};
|
|
568
656
|
};
|
|
569
657
|
|
|
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
|
|
658
|
+
// src/sdk/backing.ts
|
|
639
659
|
import { Effect as Effect3, Option as Option5, Schema as Schema3 } from "effect";
|
|
640
660
|
import {
|
|
641
|
-
IntegrationAlreadyExistsError,
|
|
642
|
-
IntegrationDetectionResult,
|
|
643
|
-
IntegrationNotFoundError,
|
|
644
|
-
IntegrationSlug,
|
|
645
|
-
ToolName,
|
|
646
661
|
ToolFileJsonSchema,
|
|
662
|
+
ToolName,
|
|
647
663
|
ToolResult,
|
|
648
|
-
authToolFailure
|
|
649
|
-
definePlugin,
|
|
650
|
-
mergeAuthTemplates,
|
|
651
|
-
sha256Hex,
|
|
652
|
-
tool
|
|
664
|
+
authToolFailure
|
|
653
665
|
} from "@executor-js/sdk/core";
|
|
654
666
|
|
|
655
667
|
// src/sdk/definitions.ts
|
|
@@ -797,8 +809,7 @@ var compileToolDefinitions = (operations) => {
|
|
|
797
809
|
return resolveCollisions(raw).sort((a, b) => a.toolPath.localeCompare(b.toolPath));
|
|
798
810
|
};
|
|
799
811
|
|
|
800
|
-
// src/sdk/
|
|
801
|
-
import { ApiKeyAuthTemplate, describeApiKeyAuthMethod } from "@executor-js/sdk/http-auth";
|
|
812
|
+
// src/sdk/backing.ts
|
|
802
813
|
var STRINGIFIED_BODY_CAP = 1024;
|
|
803
814
|
var UpstreamMessageBody = Schema3.Struct({ message: Schema3.String });
|
|
804
815
|
var UpstreamErrorMessageBody = Schema3.Struct({ errorMessage: Schema3.String });
|
|
@@ -832,7 +843,7 @@ var clampedStringify = (value) => {
|
|
|
832
843
|
return s.length > STRINGIFIED_BODY_CAP ? `${s.slice(0, STRINGIFIED_BODY_CAP)}\u2026` : s;
|
|
833
844
|
};
|
|
834
845
|
var firstNonEmpty = (...values) => values.find((value) => value !== void 0 && value.length > 0);
|
|
835
|
-
var
|
|
846
|
+
var extractOpenApiUpstreamMessage = (body, status) => {
|
|
836
847
|
if (typeof body === "string") {
|
|
837
848
|
return body.length > 0 ? body : `Upstream returned HTTP ${status}`;
|
|
838
849
|
}
|
|
@@ -863,162 +874,353 @@ var extractUpstreamMessage = (body, status) => {
|
|
|
863
874
|
}
|
|
864
875
|
return `Upstream returned HTTP ${status}`;
|
|
865
876
|
};
|
|
866
|
-
var
|
|
867
|
-
|
|
877
|
+
var openApiAuthToolFailure = (failure) => authToolFailure({
|
|
878
|
+
code: failure.code,
|
|
879
|
+
message: failure.message,
|
|
880
|
+
source: { id: failure.integration, scope: failure.owner },
|
|
881
|
+
credential: {
|
|
882
|
+
kind: failure.credentialKind,
|
|
883
|
+
...failure.credentialLabel ? { label: failure.credentialLabel } : {}
|
|
884
|
+
},
|
|
885
|
+
...failure.status !== void 0 ? { status: failure.status } : {},
|
|
886
|
+
...failure.details !== void 0 ? {
|
|
887
|
+
upstream: {
|
|
888
|
+
...failure.status !== void 0 ? { status: failure.status } : {},
|
|
889
|
+
details: failure.details
|
|
890
|
+
}
|
|
891
|
+
} : {}
|
|
892
|
+
});
|
|
893
|
+
var normalizeOpenApiRefs = (node) => {
|
|
894
|
+
if (node == null || typeof node !== "object") return node;
|
|
895
|
+
if (Array.isArray(node)) {
|
|
896
|
+
let changed2 = false;
|
|
897
|
+
const out = node.map((item) => {
|
|
898
|
+
const n = normalizeOpenApiRefs(item);
|
|
899
|
+
if (n !== item) changed2 = true;
|
|
900
|
+
return n;
|
|
901
|
+
});
|
|
902
|
+
return changed2 ? out : node;
|
|
903
|
+
}
|
|
904
|
+
const obj = node;
|
|
905
|
+
if (typeof obj.$ref === "string") {
|
|
906
|
+
const match = obj.$ref.match(/^#\/components\/schemas\/(.+)$/);
|
|
907
|
+
if (match) return { ...obj, $ref: `#/$defs/${match[1]}` };
|
|
908
|
+
return obj;
|
|
909
|
+
}
|
|
910
|
+
let changed = false;
|
|
911
|
+
const result = {};
|
|
912
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
913
|
+
const n = normalizeOpenApiRefs(v);
|
|
914
|
+
if (n !== v) changed = true;
|
|
915
|
+
result[k] = n;
|
|
916
|
+
}
|
|
917
|
+
return changed ? result : obj;
|
|
918
|
+
};
|
|
919
|
+
var toBinding = (def) => OperationBinding.make({
|
|
920
|
+
method: def.operation.method,
|
|
921
|
+
servers: def.operation.servers,
|
|
922
|
+
pathTemplate: def.operation.pathTemplate,
|
|
923
|
+
parameters: [...def.operation.parameters],
|
|
924
|
+
requestBody: def.operation.requestBody,
|
|
925
|
+
responseBody: def.operation.responseBody
|
|
926
|
+
});
|
|
927
|
+
var descriptionFor = (def) => {
|
|
928
|
+
const op = def.operation;
|
|
929
|
+
return Option5.getOrElse(
|
|
930
|
+
op.description,
|
|
931
|
+
() => Option5.getOrElse(op.summary, () => `${op.method.toUpperCase()} ${op.pathTemplate}`)
|
|
932
|
+
);
|
|
933
|
+
};
|
|
934
|
+
var compileOpenApiDocument = (doc) => Effect3.gen(function* () {
|
|
935
|
+
const result = yield* extract(doc);
|
|
936
|
+
const hoistedDefs = {};
|
|
937
|
+
if (doc.components?.schemas) {
|
|
938
|
+
for (const [k, v] of Object.entries(doc.components.schemas)) {
|
|
939
|
+
hoistedDefs[k] = normalizeOpenApiRefs(v);
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
return {
|
|
943
|
+
definitions: compileToolDefinitions(result.operations),
|
|
944
|
+
hoistedDefs,
|
|
945
|
+
title: Option5.getOrUndefined(result.title),
|
|
946
|
+
description: Option5.getOrUndefined(result.description)
|
|
947
|
+
};
|
|
948
|
+
});
|
|
949
|
+
var compileOpenApiSpec = (specText) => Effect3.gen(function* () {
|
|
950
|
+
const doc = yield* parse(specText);
|
|
951
|
+
return yield* compileOpenApiDocument(doc);
|
|
952
|
+
});
|
|
953
|
+
var openApiToolDefsFromCompiled = (compiled) => compiled.definitions.map(
|
|
954
|
+
(def) => ({
|
|
955
|
+
name: ToolName.make(def.toolPath),
|
|
956
|
+
description: descriptionFor(def),
|
|
957
|
+
inputSchema: normalizeOpenApiRefs(Option5.getOrUndefined(def.operation.inputSchema)),
|
|
958
|
+
outputSchema: Option5.match(def.operation.responseBody, {
|
|
959
|
+
onNone: () => normalizeOpenApiRefs(Option5.getOrUndefined(def.operation.outputSchema)),
|
|
960
|
+
onSome: (responseBody) => Option5.isSome(responseBody.fileHint) ? ToolFileJsonSchema : normalizeOpenApiRefs(Option5.getOrUndefined(def.operation.outputSchema))
|
|
961
|
+
}),
|
|
962
|
+
annotations: annotationsForOperation(def.operation.method, def.operation.pathTemplate)
|
|
963
|
+
})
|
|
964
|
+
);
|
|
965
|
+
var openApiStoredOperationsFromCompiled = (integration, compiled) => compiled.definitions.map((def) => ({
|
|
966
|
+
integration,
|
|
967
|
+
toolName: def.toolPath,
|
|
968
|
+
binding: toBinding(def)
|
|
969
|
+
}));
|
|
970
|
+
var loadOpenApiSpecText = (storage, config) => config.specHash != null ? storage.getSpec(config.specHash) : Effect3.succeed(null);
|
|
971
|
+
var resolveOpenApiBackedTools = ({
|
|
972
|
+
config,
|
|
973
|
+
storage
|
|
974
|
+
}) => Effect3.gen(function* () {
|
|
975
|
+
const openApiConfig = decodeOpenApiIntegrationConfig(config);
|
|
976
|
+
if (!openApiConfig) return { tools: [], definitions: {} };
|
|
977
|
+
const specText = yield* loadOpenApiSpecText(storage, openApiConfig);
|
|
978
|
+
if (specText == null) return { tools: [], definitions: {} };
|
|
979
|
+
const compiled = yield* compileOpenApiSpec(specText).pipe(
|
|
980
|
+
Effect3.catch(() => Effect3.succeed(null))
|
|
981
|
+
);
|
|
982
|
+
if (!compiled) return { tools: [], definitions: {} };
|
|
983
|
+
return {
|
|
984
|
+
tools: openApiToolDefsFromCompiled(compiled),
|
|
985
|
+
definitions: compiled.hoistedDefs
|
|
986
|
+
};
|
|
987
|
+
});
|
|
988
|
+
var invokeOpenApiBackedTool = (input) => Effect3.gen(function* () {
|
|
989
|
+
const integration = input.toolRow.integration;
|
|
990
|
+
const config = decodeOpenApiIntegrationConfig(input.credential.config);
|
|
991
|
+
let binding = (yield* input.ctx.storage.getOperation(integration, input.toolRow.name))?.binding;
|
|
992
|
+
if ((!binding || Option5.isNone(binding.responseBody)) && config) {
|
|
993
|
+
const specText = yield* loadOpenApiSpecText(input.ctx.storage, config).pipe(
|
|
994
|
+
Effect3.catch(() => Effect3.succeed(null))
|
|
995
|
+
);
|
|
996
|
+
const compiled = specText == null ? null : yield* compileOpenApiSpec(specText).pipe(Effect3.catch(() => Effect3.succeed(null)));
|
|
997
|
+
binding = compiled ? openApiStoredOperationsFromCompiled(integration, compiled).find(
|
|
998
|
+
(op) => op.toolName === input.toolRow.name
|
|
999
|
+
)?.binding : void 0;
|
|
1000
|
+
}
|
|
1001
|
+
if (!binding) {
|
|
1002
|
+
return yield* new OpenApiExtractionError({
|
|
1003
|
+
message: `No OpenAPI operation found for tool "${input.toolRow.name}" on "${integration}"`
|
|
1004
|
+
});
|
|
1005
|
+
}
|
|
1006
|
+
const headers = { ...config?.headers ?? {} };
|
|
1007
|
+
const queryParams = {
|
|
1008
|
+
...config?.queryParams ?? {}
|
|
1009
|
+
};
|
|
1010
|
+
const template = (config?.authenticationTemplate ?? []).find(
|
|
1011
|
+
(entry) => String(entry.slug) === String(input.credential.template)
|
|
1012
|
+
);
|
|
1013
|
+
if (template) {
|
|
1014
|
+
const missing = requiredTemplateVariables(template).filter((name) => {
|
|
1015
|
+
const value = input.credential.values[name];
|
|
1016
|
+
return value == null || value === "";
|
|
1017
|
+
});
|
|
1018
|
+
if (missing.length > 0) {
|
|
1019
|
+
return openApiAuthToolFailure({
|
|
1020
|
+
code: template.kind === "oauth2" ? "oauth_connection_missing" : "connection_value_missing",
|
|
1021
|
+
message: `Connection "${input.credential.connection}" for "${integration}" has no resolvable credential value. Re-authenticate or update the connection.`,
|
|
1022
|
+
owner: input.credential.owner,
|
|
1023
|
+
integration,
|
|
1024
|
+
connection: String(input.credential.connection),
|
|
1025
|
+
credentialKind: template.kind === "oauth2" ? "oauth" : "secret"
|
|
1026
|
+
});
|
|
1027
|
+
}
|
|
1028
|
+
const rendered = renderAuthTemplate(template, input.credential.values);
|
|
1029
|
+
Object.assign(headers, rendered.headers);
|
|
1030
|
+
Object.assign(queryParams, rendered.queryParams);
|
|
1031
|
+
}
|
|
1032
|
+
const result = yield* invokeWithLayer(
|
|
1033
|
+
binding,
|
|
1034
|
+
input.args ?? {},
|
|
1035
|
+
config?.baseUrl ?? "",
|
|
1036
|
+
headers,
|
|
1037
|
+
queryParams,
|
|
1038
|
+
input.httpClientLayer
|
|
1039
|
+
);
|
|
1040
|
+
const ok = result.status >= 200 && result.status < 300;
|
|
1041
|
+
if (!ok) {
|
|
1042
|
+
if (result.status === 401 || result.status === 403) {
|
|
1043
|
+
return openApiAuthToolFailure({
|
|
1044
|
+
code: "connection_rejected",
|
|
1045
|
+
status: result.status,
|
|
1046
|
+
message: `Upstream rejected credentials for "${integration}" with HTTP ${result.status}. Re-authenticate or update the connection "${input.credential.connection}" before retrying this tool.`,
|
|
1047
|
+
owner: input.credential.owner,
|
|
1048
|
+
integration,
|
|
1049
|
+
connection: String(input.credential.connection),
|
|
1050
|
+
credentialKind: "upstream",
|
|
1051
|
+
credentialLabel: "Upstream authorization",
|
|
1052
|
+
details: result.error
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
1055
|
+
return ToolResult.fail({
|
|
1056
|
+
code: "upstream_http_error",
|
|
1057
|
+
status: result.status,
|
|
1058
|
+
message: extractOpenApiUpstreamMessage(result.error, result.status),
|
|
1059
|
+
details: result.error
|
|
1060
|
+
});
|
|
1061
|
+
}
|
|
1062
|
+
return ToolResult.ok(result.data, {
|
|
1063
|
+
http: { status: result.status, headers: result.headers }
|
|
1064
|
+
});
|
|
1065
|
+
});
|
|
1066
|
+
var resolveOpenApiBackedAnnotations = (input) => Effect3.gen(function* () {
|
|
1067
|
+
const ops = yield* input.ctx.storage.listOperations(String(input.integration));
|
|
1068
|
+
const byName = /* @__PURE__ */ new Map();
|
|
1069
|
+
for (const op of ops) byName.set(op.toolName, op.binding);
|
|
1070
|
+
const out = {};
|
|
1071
|
+
for (const row of input.toolRows) {
|
|
1072
|
+
const binding = byName.get(row.name);
|
|
1073
|
+
if (binding) {
|
|
1074
|
+
out[row.name] = annotationsForOperation(binding.method, binding.pathTemplate);
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
return out;
|
|
868
1078
|
});
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
1079
|
+
|
|
1080
|
+
// src/sdk/plugin.ts
|
|
1081
|
+
import { Effect as Effect4, Option as Option6, Schema as Schema4 } from "effect";
|
|
1082
|
+
import {
|
|
1083
|
+
IntegrationAlreadyExistsError,
|
|
1084
|
+
IntegrationDetectionResult,
|
|
1085
|
+
IntegrationNotFoundError,
|
|
1086
|
+
IntegrationSlug,
|
|
1087
|
+
ToolResult as ToolResult2,
|
|
1088
|
+
definePlugin,
|
|
1089
|
+
mergeAuthTemplates,
|
|
1090
|
+
sha256Hex,
|
|
1091
|
+
tool
|
|
1092
|
+
} from "@executor-js/sdk/core";
|
|
1093
|
+
import { ApiKeyAuthTemplate, describeApiKeyAuthMethod } from "@executor-js/sdk/http-auth";
|
|
1094
|
+
var PreviewSpecInputSchema = Schema4.Struct({
|
|
1095
|
+
spec: Schema4.String
|
|
1096
|
+
});
|
|
1097
|
+
var StaticPreviewServerVariableSchema = Schema4.Struct({
|
|
1098
|
+
default: Schema4.String,
|
|
1099
|
+
enum: Schema4.NullOr(Schema4.Array(Schema4.String)),
|
|
1100
|
+
description: Schema4.NullOr(Schema4.String)
|
|
873
1101
|
});
|
|
874
|
-
var StaticPreviewServerSchema =
|
|
875
|
-
url:
|
|
876
|
-
description:
|
|
877
|
-
variables:
|
|
1102
|
+
var StaticPreviewServerSchema = Schema4.Struct({
|
|
1103
|
+
url: Schema4.String,
|
|
1104
|
+
description: Schema4.NullOr(Schema4.String),
|
|
1105
|
+
variables: Schema4.NullOr(Schema4.Record(Schema4.String, StaticPreviewServerVariableSchema))
|
|
878
1106
|
});
|
|
879
|
-
var StaticPreviewOAuthAuthorizationCodeFlowSchema =
|
|
880
|
-
authorizationUrl:
|
|
881
|
-
tokenUrl:
|
|
882
|
-
refreshUrl:
|
|
883
|
-
scopes:
|
|
1107
|
+
var StaticPreviewOAuthAuthorizationCodeFlowSchema = Schema4.Struct({
|
|
1108
|
+
authorizationUrl: Schema4.String,
|
|
1109
|
+
tokenUrl: Schema4.String,
|
|
1110
|
+
refreshUrl: Schema4.NullOr(Schema4.String),
|
|
1111
|
+
scopes: Schema4.Record(Schema4.String, Schema4.String)
|
|
884
1112
|
});
|
|
885
|
-
var StaticPreviewOAuthClientCredentialsFlowSchema =
|
|
886
|
-
tokenUrl:
|
|
887
|
-
refreshUrl:
|
|
888
|
-
scopes:
|
|
1113
|
+
var StaticPreviewOAuthClientCredentialsFlowSchema = Schema4.Struct({
|
|
1114
|
+
tokenUrl: Schema4.String,
|
|
1115
|
+
refreshUrl: Schema4.NullOr(Schema4.String),
|
|
1116
|
+
scopes: Schema4.Record(Schema4.String, Schema4.String)
|
|
889
1117
|
});
|
|
890
|
-
var StaticPreviewOAuthFlowsSchema =
|
|
891
|
-
authorizationCode:
|
|
892
|
-
clientCredentials:
|
|
1118
|
+
var StaticPreviewOAuthFlowsSchema = Schema4.Struct({
|
|
1119
|
+
authorizationCode: Schema4.NullOr(StaticPreviewOAuthAuthorizationCodeFlowSchema),
|
|
1120
|
+
clientCredentials: Schema4.NullOr(StaticPreviewOAuthClientCredentialsFlowSchema)
|
|
893
1121
|
});
|
|
894
|
-
var StaticPreviewSecuritySchemeSchema =
|
|
895
|
-
name:
|
|
896
|
-
type:
|
|
897
|
-
scheme:
|
|
898
|
-
bearerFormat:
|
|
899
|
-
in:
|
|
900
|
-
headerName:
|
|
901
|
-
description:
|
|
902
|
-
flows:
|
|
903
|
-
openIdConnectUrl:
|
|
1122
|
+
var StaticPreviewSecuritySchemeSchema = Schema4.Struct({
|
|
1123
|
+
name: Schema4.String,
|
|
1124
|
+
type: Schema4.Literals(["http", "apiKey", "oauth2", "openIdConnect"]),
|
|
1125
|
+
scheme: Schema4.NullOr(Schema4.String),
|
|
1126
|
+
bearerFormat: Schema4.NullOr(Schema4.String),
|
|
1127
|
+
in: Schema4.NullOr(Schema4.Literals(["header", "query", "cookie"])),
|
|
1128
|
+
headerName: Schema4.NullOr(Schema4.String),
|
|
1129
|
+
description: Schema4.NullOr(Schema4.String),
|
|
1130
|
+
flows: Schema4.NullOr(StaticPreviewOAuthFlowsSchema),
|
|
1131
|
+
openIdConnectUrl: Schema4.NullOr(Schema4.String)
|
|
904
1132
|
});
|
|
905
|
-
var StaticPreviewOAuth2PresetSchema =
|
|
906
|
-
label:
|
|
907
|
-
securitySchemeName:
|
|
908
|
-
flow:
|
|
909
|
-
authorizationUrl:
|
|
910
|
-
tokenUrl:
|
|
911
|
-
refreshUrl:
|
|
912
|
-
scopes:
|
|
913
|
-
identityScopes:
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
1133
|
+
var StaticPreviewOAuth2PresetSchema = Schema4.Struct({
|
|
1134
|
+
label: Schema4.String,
|
|
1135
|
+
securitySchemeName: Schema4.String,
|
|
1136
|
+
flow: Schema4.Literals(["authorizationCode", "clientCredentials"]),
|
|
1137
|
+
authorizationUrl: Schema4.NullOr(Schema4.String),
|
|
1138
|
+
tokenUrl: Schema4.String,
|
|
1139
|
+
refreshUrl: Schema4.NullOr(Schema4.String),
|
|
1140
|
+
scopes: Schema4.Record(Schema4.String, Schema4.String),
|
|
1141
|
+
identityScopes: Schema4.Union([
|
|
1142
|
+
Schema4.Literal("auto"),
|
|
1143
|
+
Schema4.Literal(false),
|
|
1144
|
+
Schema4.Array(Schema4.String)
|
|
917
1145
|
])
|
|
918
1146
|
});
|
|
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:
|
|
1147
|
+
var StaticPreviewSpecOutputSchema = Schema4.Struct({
|
|
1148
|
+
title: Schema4.NullOr(Schema4.String),
|
|
1149
|
+
version: Schema4.NullOr(Schema4.String),
|
|
1150
|
+
servers: Schema4.Array(StaticPreviewServerSchema),
|
|
1151
|
+
operationCount: Schema4.Number,
|
|
1152
|
+
tags: Schema4.Array(Schema4.String),
|
|
1153
|
+
securitySchemes: Schema4.Array(StaticPreviewSecuritySchemeSchema),
|
|
1154
|
+
authStrategies: Schema4.Array(Schema4.Struct({ schemes: Schema4.Array(Schema4.String) })),
|
|
1155
|
+
headerPresets: Schema4.Array(
|
|
1156
|
+
Schema4.Struct({
|
|
1157
|
+
label: Schema4.String,
|
|
1158
|
+
headers: Schema4.Record(Schema4.String, Schema4.NullOr(Schema4.String)),
|
|
1159
|
+
secretHeaders: Schema4.Array(Schema4.String)
|
|
932
1160
|
})
|
|
933
1161
|
),
|
|
934
|
-
oauth2Presets:
|
|
1162
|
+
oauth2Presets: Schema4.Array(StaticPreviewOAuth2PresetSchema)
|
|
935
1163
|
});
|
|
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
|
-
})
|
|
1164
|
+
var OpenApiSpecInputSchema = Schema4.Union([
|
|
1165
|
+
Schema4.Struct({ kind: Schema4.Literal("url"), url: Schema4.String }),
|
|
1166
|
+
Schema4.Struct({ kind: Schema4.Literal("blob"), value: Schema4.String })
|
|
947
1167
|
]);
|
|
948
|
-
var AuthenticationSchema2 =
|
|
949
|
-
|
|
950
|
-
slug:
|
|
951
|
-
kind:
|
|
952
|
-
authorizationUrl:
|
|
953
|
-
tokenUrl:
|
|
954
|
-
scopes:
|
|
1168
|
+
var AuthenticationSchema2 = Schema4.Union([
|
|
1169
|
+
Schema4.Struct({
|
|
1170
|
+
slug: Schema4.String,
|
|
1171
|
+
kind: Schema4.Literal("oauth2"),
|
|
1172
|
+
authorizationUrl: Schema4.String,
|
|
1173
|
+
tokenUrl: Schema4.String,
|
|
1174
|
+
scopes: Schema4.Array(Schema4.String)
|
|
955
1175
|
}),
|
|
956
|
-
// Credential methods are authored request-shaped
|
|
1176
|
+
// Credential methods are authored request-shaped - the ONE apikey input
|
|
957
1177
|
// dialect: `{ type: "apiKey", headers: { Authorization: ["Bearer ",
|
|
958
1178
|
// variable("token")] }, queryParams: { … } }`.
|
|
959
1179
|
ApiKeyAuthTemplate
|
|
960
1180
|
]);
|
|
961
|
-
var AddSourceInputSchema =
|
|
1181
|
+
var AddSourceInputSchema = Schema4.Struct({
|
|
962
1182
|
spec: OpenApiSpecInputSchema,
|
|
963
|
-
slug:
|
|
964
|
-
description:
|
|
965
|
-
baseUrl:
|
|
966
|
-
headers:
|
|
967
|
-
queryParams:
|
|
968
|
-
authenticationTemplate:
|
|
1183
|
+
slug: Schema4.String,
|
|
1184
|
+
description: Schema4.optional(Schema4.String),
|
|
1185
|
+
baseUrl: Schema4.optional(Schema4.String),
|
|
1186
|
+
headers: Schema4.optional(Schema4.Record(Schema4.String, Schema4.String)),
|
|
1187
|
+
queryParams: Schema4.optional(Schema4.Record(Schema4.String, Schema4.String)),
|
|
1188
|
+
authenticationTemplate: Schema4.optional(Schema4.Array(AuthenticationSchema2))
|
|
969
1189
|
});
|
|
970
|
-
var AddSourceOutputSchema =
|
|
971
|
-
slug:
|
|
972
|
-
toolCount:
|
|
1190
|
+
var AddSourceOutputSchema = Schema4.Struct({
|
|
1191
|
+
slug: Schema4.String,
|
|
1192
|
+
toolCount: Schema4.Number
|
|
973
1193
|
});
|
|
974
|
-
var PreviewSpecInputStandardSchema =
|
|
975
|
-
|
|
1194
|
+
var PreviewSpecInputStandardSchema = Schema4.toStandardSchemaV1(
|
|
1195
|
+
Schema4.toStandardJSONSchemaV1(PreviewSpecInputSchema)
|
|
976
1196
|
);
|
|
977
|
-
var PreviewSpecOutputStandardSchema =
|
|
978
|
-
|
|
1197
|
+
var PreviewSpecOutputStandardSchema = Schema4.toStandardSchemaV1(
|
|
1198
|
+
Schema4.toStandardJSONSchemaV1(StaticPreviewSpecOutputSchema)
|
|
979
1199
|
);
|
|
980
|
-
var AddSourceInputStandardSchema =
|
|
981
|
-
|
|
1200
|
+
var AddSourceInputStandardSchema = Schema4.toStandardSchemaV1(
|
|
1201
|
+
Schema4.toStandardJSONSchemaV1(AddSourceInputSchema)
|
|
982
1202
|
);
|
|
983
|
-
var AddSourceOutputStandardSchema =
|
|
984
|
-
|
|
1203
|
+
var AddSourceOutputStandardSchema = Schema4.toStandardSchemaV1(
|
|
1204
|
+
Schema4.toStandardJSONSchemaV1(AddSourceOutputSchema)
|
|
985
1205
|
);
|
|
986
|
-
var openApiToolFailure = (code, message, details) =>
|
|
1206
|
+
var openApiToolFailure = (code, message, details) => ToolResult2.fail({
|
|
987
1207
|
code,
|
|
988
1208
|
message,
|
|
989
1209
|
...details === void 0 ? {} : { details }
|
|
990
1210
|
});
|
|
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
1211
|
var staticPreviewOutput = (preview) => ({
|
|
1010
|
-
title:
|
|
1011
|
-
version:
|
|
1212
|
+
title: Option6.getOrNull(preview.title),
|
|
1213
|
+
version: Option6.getOrNull(preview.version),
|
|
1012
1214
|
servers: preview.servers.map((server) => ({
|
|
1013
1215
|
url: server.url,
|
|
1014
|
-
description:
|
|
1015
|
-
variables:
|
|
1016
|
-
Object.entries(
|
|
1216
|
+
description: Option6.getOrNull(server.description),
|
|
1217
|
+
variables: Option6.getOrNull(server.variables) ? Object.fromEntries(
|
|
1218
|
+
Object.entries(Option6.getOrNull(server.variables) ?? {}).map(([name, variable]) => [
|
|
1017
1219
|
name,
|
|
1018
1220
|
{
|
|
1019
1221
|
default: variable.default,
|
|
1020
|
-
enum:
|
|
1021
|
-
description:
|
|
1222
|
+
enum: Option6.getOrNull(variable.enum),
|
|
1223
|
+
description: Option6.getOrNull(variable.description)
|
|
1022
1224
|
}
|
|
1023
1225
|
])
|
|
1024
1226
|
) : null
|
|
@@ -1028,25 +1230,25 @@ var staticPreviewOutput = (preview) => ({
|
|
|
1028
1230
|
securitySchemes: preview.securitySchemes.map((scheme) => ({
|
|
1029
1231
|
name: scheme.name,
|
|
1030
1232
|
type: scheme.type,
|
|
1031
|
-
scheme:
|
|
1032
|
-
bearerFormat:
|
|
1033
|
-
in:
|
|
1034
|
-
headerName:
|
|
1035
|
-
description:
|
|
1036
|
-
flows:
|
|
1037
|
-
authorizationCode:
|
|
1233
|
+
scheme: Option6.getOrNull(scheme.scheme),
|
|
1234
|
+
bearerFormat: Option6.getOrNull(scheme.bearerFormat),
|
|
1235
|
+
in: Option6.getOrNull(scheme.in),
|
|
1236
|
+
headerName: Option6.getOrNull(scheme.headerName),
|
|
1237
|
+
description: Option6.getOrNull(scheme.description),
|
|
1238
|
+
flows: Option6.isSome(scheme.flows) ? {
|
|
1239
|
+
authorizationCode: Option6.isSome(scheme.flows.value.authorizationCode) ? {
|
|
1038
1240
|
authorizationUrl: scheme.flows.value.authorizationCode.value.authorizationUrl,
|
|
1039
1241
|
tokenUrl: scheme.flows.value.authorizationCode.value.tokenUrl,
|
|
1040
|
-
refreshUrl:
|
|
1242
|
+
refreshUrl: Option6.getOrNull(scheme.flows.value.authorizationCode.value.refreshUrl),
|
|
1041
1243
|
scopes: scheme.flows.value.authorizationCode.value.scopes
|
|
1042
1244
|
} : null,
|
|
1043
|
-
clientCredentials:
|
|
1245
|
+
clientCredentials: Option6.isSome(scheme.flows.value.clientCredentials) ? {
|
|
1044
1246
|
tokenUrl: scheme.flows.value.clientCredentials.value.tokenUrl,
|
|
1045
|
-
refreshUrl:
|
|
1247
|
+
refreshUrl: Option6.getOrNull(scheme.flows.value.clientCredentials.value.refreshUrl),
|
|
1046
1248
|
scopes: scheme.flows.value.clientCredentials.value.scopes
|
|
1047
1249
|
} : null
|
|
1048
1250
|
} : null,
|
|
1049
|
-
openIdConnectUrl:
|
|
1251
|
+
openIdConnectUrl: Option6.getOrNull(scheme.openIdConnectUrl)
|
|
1050
1252
|
})),
|
|
1051
1253
|
authStrategies: preview.authStrategies,
|
|
1052
1254
|
headerPresets: preview.headerPresets,
|
|
@@ -1054,56 +1256,14 @@ var staticPreviewOutput = (preview) => ({
|
|
|
1054
1256
|
label: preset.label,
|
|
1055
1257
|
securitySchemeName: preset.securitySchemeName,
|
|
1056
1258
|
flow: preset.flow,
|
|
1057
|
-
authorizationUrl:
|
|
1259
|
+
authorizationUrl: Option6.getOrNull(preset.authorizationUrl),
|
|
1058
1260
|
tokenUrl: preset.tokenUrl,
|
|
1059
|
-
refreshUrl:
|
|
1261
|
+
refreshUrl: Option6.getOrNull(preset.refreshUrl),
|
|
1060
1262
|
scopes: preset.scopes,
|
|
1061
1263
|
identityScopes: preset.identityScopes
|
|
1062
1264
|
}))
|
|
1063
1265
|
});
|
|
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;
|
|
1266
|
+
var specInputToSourceUrl = (spec) => spec.kind === "url" ? spec.url : void 0;
|
|
1107
1267
|
var describeOpenApiAuthMethods = (record) => {
|
|
1108
1268
|
const config = decodeOpenApiIntegrationConfig(record.config);
|
|
1109
1269
|
if (!config) return [];
|
|
@@ -1130,79 +1290,10 @@ var describeOpenApiIntegrationDisplay = (record) => {
|
|
|
1130
1290
|
const config = decodeOpenApiIntegrationConfig(record.config);
|
|
1131
1291
|
return { url: config?.baseUrl ?? config?.sourceUrl };
|
|
1132
1292
|
};
|
|
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
1293
|
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
|
-
}
|
|
1294
|
+
const resolveSpecForInput = (spec, httpClientLayer) => Effect4.gen(function* () {
|
|
1204
1295
|
if (spec.kind === "url") {
|
|
1205
|
-
const specText = yield* resolveSpecText(spec.url).pipe(
|
|
1296
|
+
const specText = yield* resolveSpecText(spec.url).pipe(Effect4.provide(httpClientLayer));
|
|
1206
1297
|
return { specText };
|
|
1207
1298
|
}
|
|
1208
1299
|
return { specText: spec.value };
|
|
@@ -1221,12 +1312,12 @@ var openApiPlugin = definePlugin((options) => {
|
|
|
1221
1312
|
storage: (deps) => makeDefaultOpenapiStore(deps),
|
|
1222
1313
|
extension: (ctx) => {
|
|
1223
1314
|
const httpClientLayer = options?.httpClientLayer ?? ctx.httpClientLayer;
|
|
1224
|
-
const addSpec = (config) =>
|
|
1315
|
+
const addSpec = (config) => Effect4.gen(function* () {
|
|
1225
1316
|
const resolved = yield* resolveSpecForInput(config.spec, httpClientLayer);
|
|
1226
|
-
const compiled = yield*
|
|
1227
|
-
const explicitBaseUrl = config.baseUrl
|
|
1317
|
+
const compiled = yield* compileOpenApiSpec(resolved.specText);
|
|
1318
|
+
const explicitBaseUrl = config.baseUrl;
|
|
1228
1319
|
const needsDerivedBaseUrl = explicitBaseUrl == null;
|
|
1229
|
-
const needsDerivedAuth = config.authenticationTemplate == null
|
|
1320
|
+
const needsDerivedAuth = config.authenticationTemplate == null;
|
|
1230
1321
|
const preview = needsDerivedBaseUrl || needsDerivedAuth ? yield* previewSpecText(resolved.specText) : void 0;
|
|
1231
1322
|
const derivedBaseUrl = needsDerivedBaseUrl && preview ? firstBaseUrlForPreview(preview) : void 0;
|
|
1232
1323
|
const effectiveBaseUrl = explicitBaseUrl ?? (derivedBaseUrl || void 0);
|
|
@@ -1240,55 +1331,52 @@ var openApiPlugin = definePlugin((options) => {
|
|
|
1240
1331
|
const integrationConfig = {
|
|
1241
1332
|
specHash,
|
|
1242
1333
|
...specInputToSourceUrl(config.spec) !== void 0 ? { sourceUrl: specInputToSourceUrl(config.spec) } : {},
|
|
1243
|
-
...specInputToGoogleBundle(config.spec) !== void 0 ? { googleDiscoveryUrls: specInputToGoogleBundle(config.spec) } : {},
|
|
1244
1334
|
// baseUrl is an optional override only. The host is otherwise
|
|
1245
1335
|
// resolved per call from the operation's `servers` (extracted from
|
|
1246
1336
|
// the spec), so we never bake a derived base URL into the config.
|
|
1247
1337
|
...config.baseUrl ? { baseUrl: config.baseUrl } : {},
|
|
1248
1338
|
...config.headers ? { headers: config.headers } : {},
|
|
1249
1339
|
...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.
|
|
1340
|
+
// Prefer the caller's explicit template; otherwise derive from the
|
|
1341
|
+
// spec's declared security schemes.
|
|
1254
1342
|
...config.authenticationTemplate ? {
|
|
1255
1343
|
authenticationTemplate: normalizeOpenApiAuthInputs(config.authenticationTemplate)
|
|
1256
|
-
} :
|
|
1344
|
+
} : derivedAuthenticationTemplate && derivedAuthenticationTemplate.length > 0 ? { authenticationTemplate: derivedAuthenticationTemplate } : {}
|
|
1257
1345
|
};
|
|
1258
1346
|
yield* ctx.storage.putSpec(specHash, resolved.specText);
|
|
1259
1347
|
yield* ctx.transaction(
|
|
1260
|
-
|
|
1348
|
+
Effect4.gen(function* () {
|
|
1261
1349
|
yield* ctx.core.integrations.register({
|
|
1262
1350
|
slug,
|
|
1263
1351
|
name: config.name?.trim() || compiled.title || config.slug,
|
|
1264
1352
|
description: config.description ?? compiled.description ?? compiled.title ?? config.slug,
|
|
1265
1353
|
config: integrationConfig,
|
|
1266
1354
|
canRemove: true,
|
|
1267
|
-
canRefresh: specInputToSourceUrl(config.spec) != null
|
|
1355
|
+
canRefresh: specInputToSourceUrl(config.spec) != null
|
|
1268
1356
|
});
|
|
1269
1357
|
yield* ctx.storage.putOperations(
|
|
1270
1358
|
config.slug,
|
|
1271
|
-
|
|
1359
|
+
openApiStoredOperationsFromCompiled(config.slug, compiled)
|
|
1272
1360
|
);
|
|
1273
1361
|
})
|
|
1274
1362
|
);
|
|
1275
1363
|
return { slug, toolCount: compiled.definitions.length };
|
|
1276
1364
|
});
|
|
1277
|
-
const updateSpec = (rawSlug, input) =>
|
|
1365
|
+
const updateSpec = (rawSlug, input) => Effect4.gen(function* () {
|
|
1278
1366
|
const slug = IntegrationSlug.make(rawSlug);
|
|
1279
1367
|
const record = yield* ctx.core.integrations.get(slug);
|
|
1280
1368
|
const current = record ? decodeOpenApiIntegrationConfig(record.config) : null;
|
|
1281
1369
|
if (!record || !current) {
|
|
1282
1370
|
return yield* new IntegrationNotFoundError({ slug });
|
|
1283
1371
|
}
|
|
1284
|
-
const specInput = input?.spec ?? (current.
|
|
1372
|
+
const specInput = input?.spec ?? (current.sourceUrl ? { kind: "url", url: current.sourceUrl } : null);
|
|
1285
1373
|
if (specInput === null) {
|
|
1286
1374
|
return yield* new OpenApiParseError({
|
|
1287
1375
|
message: "This integration's spec was pasted inline and has no source URL to re-fetch. Provide the updated spec content."
|
|
1288
1376
|
});
|
|
1289
1377
|
}
|
|
1290
1378
|
const resolved = yield* resolveSpecForInput(specInput, httpClientLayer);
|
|
1291
|
-
const compiled = yield*
|
|
1379
|
+
const compiled = yield* compileOpenApiSpec(resolved.specText);
|
|
1292
1380
|
const previousOperations = yield* ctx.storage.listOperations(rawSlug);
|
|
1293
1381
|
const previousNames = new Set(previousOperations.map((op) => op.toolName));
|
|
1294
1382
|
const nextNames = new Set(compiled.definitions.map((def) => def.toolPath));
|
|
@@ -1297,32 +1385,31 @@ var openApiPlugin = definePlugin((options) => {
|
|
|
1297
1385
|
const nextConfig = {
|
|
1298
1386
|
...current,
|
|
1299
1387
|
specHash,
|
|
1300
|
-
...specInputToSourceUrl(specInput) !== void 0 ? { sourceUrl: specInputToSourceUrl(specInput) } : {}
|
|
1301
|
-
...specInputToGoogleBundle(specInput) !== void 0 ? { googleDiscoveryUrls: specInputToGoogleBundle(specInput) } : {}
|
|
1388
|
+
...specInputToSourceUrl(specInput) !== void 0 ? { sourceUrl: specInputToSourceUrl(specInput) } : {}
|
|
1302
1389
|
};
|
|
1303
1390
|
yield* ctx.transaction(
|
|
1304
|
-
|
|
1391
|
+
Effect4.gen(function* () {
|
|
1305
1392
|
yield* ctx.core.integrations.update(slug, {
|
|
1306
1393
|
config: nextConfig
|
|
1307
1394
|
});
|
|
1308
1395
|
yield* ctx.storage.putOperations(
|
|
1309
1396
|
rawSlug,
|
|
1310
|
-
|
|
1397
|
+
openApiStoredOperationsFromCompiled(rawSlug, compiled)
|
|
1311
1398
|
);
|
|
1312
1399
|
})
|
|
1313
1400
|
);
|
|
1314
1401
|
const connections = yield* ctx.connections.list({ integration: slug });
|
|
1315
|
-
yield*
|
|
1402
|
+
yield* Effect4.forEach(
|
|
1316
1403
|
connections,
|
|
1317
1404
|
(connection) => ctx.connections.refresh({
|
|
1318
1405
|
owner: connection.owner,
|
|
1319
1406
|
integration: connection.integration,
|
|
1320
1407
|
name: connection.name
|
|
1321
|
-
}).pipe(
|
|
1408
|
+
}).pipe(Effect4.catchTag("ConnectionNotFoundError", () => Effect4.succeed([]))),
|
|
1322
1409
|
{ discard: true }
|
|
1323
1410
|
).pipe(
|
|
1324
|
-
|
|
1325
|
-
|
|
1411
|
+
Effect4.catchTag("IntegrationNotFoundError", () => Effect4.void),
|
|
1412
|
+
Effect4.withSpan("openapi.plugin.update_spec.refresh_connections", {
|
|
1326
1413
|
attributes: { "openapi.connection_count": connections.length }
|
|
1327
1414
|
})
|
|
1328
1415
|
);
|
|
@@ -1333,35 +1420,28 @@ var openApiPlugin = definePlugin((options) => {
|
|
|
1333
1420
|
removedTools: [...previousNames].filter((name) => !nextNames.has(name)).sort()
|
|
1334
1421
|
};
|
|
1335
1422
|
}).pipe(
|
|
1336
|
-
|
|
1423
|
+
Effect4.withSpan("openapi.plugin.update_spec", {
|
|
1337
1424
|
attributes: { "openapi.integration.slug": rawSlug }
|
|
1338
1425
|
})
|
|
1339
1426
|
);
|
|
1340
1427
|
return {
|
|
1341
|
-
previewSpec: (input) =>
|
|
1428
|
+
previewSpec: (input) => Effect4.gen(function* () {
|
|
1342
1429
|
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));
|
|
1430
|
+
const specText = yield* resolveSpecText(previewInput.spec).pipe(
|
|
1431
|
+
Effect4.provide(httpClientLayer)
|
|
1432
|
+
);
|
|
1433
|
+
return yield* previewSpecText(specText);
|
|
1354
1434
|
}),
|
|
1355
1435
|
addSpec,
|
|
1356
1436
|
updateSpec,
|
|
1357
1437
|
removeSpec: (slug) => ctx.transaction(
|
|
1358
|
-
|
|
1438
|
+
Effect4.gen(function* () {
|
|
1359
1439
|
yield* ctx.storage.removeOperations(slug);
|
|
1360
|
-
yield* ctx.core.integrations.remove(IntegrationSlug.make(slug)).pipe(
|
|
1440
|
+
yield* ctx.core.integrations.remove(IntegrationSlug.make(slug)).pipe(Effect4.catchTag("IntegrationRemovalNotAllowedError", () => Effect4.void));
|
|
1361
1441
|
})
|
|
1362
1442
|
),
|
|
1363
1443
|
getIntegration: (slug) => ctx.core.integrations.get(IntegrationSlug.make(slug)).pipe(
|
|
1364
|
-
|
|
1444
|
+
Effect4.map(
|
|
1365
1445
|
(record) => record ? {
|
|
1366
1446
|
slug: record.slug,
|
|
1367
1447
|
description: record.description,
|
|
@@ -1372,12 +1452,12 @@ var openApiPlugin = definePlugin((options) => {
|
|
|
1372
1452
|
)
|
|
1373
1453
|
),
|
|
1374
1454
|
getConfig: (slug) => ctx.core.integrations.get(IntegrationSlug.make(slug)).pipe(
|
|
1375
|
-
|
|
1455
|
+
Effect4.map(
|
|
1376
1456
|
(record) => record ? decodeOpenApiIntegrationConfig(record.config) : null
|
|
1377
1457
|
)
|
|
1378
1458
|
),
|
|
1379
1459
|
configure: (slug, input) => ctx.transaction(
|
|
1380
|
-
|
|
1460
|
+
Effect4.gen(function* () {
|
|
1381
1461
|
const record = yield* ctx.core.integrations.get(IntegrationSlug.make(slug));
|
|
1382
1462
|
if (!record) return [];
|
|
1383
1463
|
const current = decodeOpenApiIntegrationConfig(record.config);
|
|
@@ -1408,17 +1488,17 @@ var openApiPlugin = definePlugin((options) => {
|
|
|
1408
1488
|
inputSchema: PreviewSpecInputStandardSchema,
|
|
1409
1489
|
outputSchema: PreviewSpecOutputStandardSchema,
|
|
1410
1490
|
execute: (input) => self.previewSpec(input).pipe(
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
OpenApiParseError: ({ message }) =>
|
|
1414
|
-
OpenApiExtractionError: ({ message }) =>
|
|
1415
|
-
OpenApiOAuthError: ({ message }) =>
|
|
1491
|
+
Effect4.map((preview) => ToolResult2.ok(staticPreviewOutput(preview))),
|
|
1492
|
+
Effect4.catchTags({
|
|
1493
|
+
OpenApiParseError: ({ message }) => Effect4.succeed(openApiToolFailure("openapi_parse_failed", message)),
|
|
1494
|
+
OpenApiExtractionError: ({ message }) => Effect4.succeed(openApiToolFailure("openapi_extraction_failed", message)),
|
|
1495
|
+
OpenApiOAuthError: ({ message }) => Effect4.succeed(openApiToolFailure("openapi_oauth_failed", message))
|
|
1416
1496
|
})
|
|
1417
1497
|
)
|
|
1418
1498
|
}),
|
|
1419
1499
|
tool({
|
|
1420
1500
|
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
|
|
1501
|
+
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
1502
|
annotations: {
|
|
1423
1503
|
requiresApproval: true,
|
|
1424
1504
|
approvalDescription: "Add an OpenAPI integration"
|
|
@@ -1434,17 +1514,17 @@ var openApiPlugin = definePlugin((options) => {
|
|
|
1434
1514
|
queryParams: input.queryParams,
|
|
1435
1515
|
authenticationTemplate: input.authenticationTemplate
|
|
1436
1516
|
}).pipe(
|
|
1437
|
-
|
|
1438
|
-
(result) =>
|
|
1517
|
+
Effect4.map(
|
|
1518
|
+
(result) => ToolResult2.ok({
|
|
1439
1519
|
slug: String(result.slug),
|
|
1440
1520
|
toolCount: result.toolCount
|
|
1441
1521
|
})
|
|
1442
1522
|
),
|
|
1443
|
-
|
|
1444
|
-
OpenApiParseError: ({ message }) =>
|
|
1445
|
-
OpenApiExtractionError: ({ message }) =>
|
|
1446
|
-
OpenApiOAuthError: ({ message }) =>
|
|
1447
|
-
IntegrationAlreadyExistsError: ({ slug }) =>
|
|
1523
|
+
Effect4.catchTags({
|
|
1524
|
+
OpenApiParseError: ({ message }) => Effect4.succeed(openApiToolFailure("openapi_parse_failed", message)),
|
|
1525
|
+
OpenApiExtractionError: ({ message }) => Effect4.succeed(openApiToolFailure("openapi_extraction_failed", message)),
|
|
1526
|
+
OpenApiOAuthError: ({ message }) => Effect4.succeed(openApiToolFailure("openapi_oauth_failed", message)),
|
|
1527
|
+
IntegrationAlreadyExistsError: ({ slug }) => Effect4.succeed(
|
|
1448
1528
|
openApiToolFailure(
|
|
1449
1529
|
"integration_already_exists",
|
|
1450
1530
|
`Integration ${slug} already exists; update it instead of re-adding.`
|
|
@@ -1459,176 +1539,50 @@ var openApiPlugin = definePlugin((options) => {
|
|
|
1459
1539
|
describeAuthMethods: describeOpenApiAuthMethods,
|
|
1460
1540
|
describeIntegrationDisplay: describeOpenApiIntegrationDisplay,
|
|
1461
1541
|
// Produce one tool per spec operation. Spec-derived, identical for every
|
|
1462
|
-
// connection on the integration
|
|
1542
|
+
// connection on the integration - so `getValue` is never called here. The
|
|
1463
1543
|
// operation bindings invokeTool needs are persisted at addSpec time; this
|
|
1464
1544
|
// hook only shapes the per-connection ToolDefs from the spec blob the
|
|
1465
1545
|
// 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* () {
|
|
1546
|
+
resolveTools: ({ config, storage }) => resolveOpenApiBackedTools({ config, storage }),
|
|
1547
|
+
invokeTool: ({ ctx: invokeCtx, toolRow, credential, args }) => {
|
|
1489
1548
|
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,
|
|
1549
|
+
return invokeOpenApiBackedTool({
|
|
1550
|
+
ctx: invokeCtx,
|
|
1551
|
+
toolRow,
|
|
1552
|
+
credential,
|
|
1553
|
+
args,
|
|
1542
1554
|
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
1555
|
});
|
|
1569
|
-
}
|
|
1570
|
-
resolveAnnotations: ({
|
|
1556
|
+
},
|
|
1557
|
+
resolveAnnotations: ({ ctx: annotationsCtx, integration, toolRows }) => resolveOpenApiBackedAnnotations({
|
|
1571
1558
|
ctx: annotationsCtx,
|
|
1572
|
-
integration,
|
|
1559
|
+
integration: String(integration),
|
|
1573
1560
|
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
1561
|
}),
|
|
1587
|
-
removeConnection: () =>
|
|
1562
|
+
removeConnection: () => Effect4.void,
|
|
1588
1563
|
detect: ({
|
|
1589
1564
|
ctx: detectCtx,
|
|
1590
1565
|
url
|
|
1591
|
-
}) =>
|
|
1566
|
+
}) => Effect4.gen(function* () {
|
|
1592
1567
|
const httpClientLayer = options?.httpClientLayer ?? detectCtx.httpClientLayer;
|
|
1593
1568
|
const trimmed = url.trim();
|
|
1594
1569
|
if (!trimmed) return null;
|
|
1595
|
-
const parsed = yield*
|
|
1570
|
+
const parsed = yield* Effect4.try({
|
|
1596
1571
|
try: () => new URL(trimmed),
|
|
1597
1572
|
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
|
-
}
|
|
1573
|
+
}).pipe(Effect4.option);
|
|
1574
|
+
if (Option6.isNone(parsed)) return null;
|
|
1621
1575
|
const specText = yield* resolveSpecText(trimmed).pipe(
|
|
1622
|
-
|
|
1623
|
-
|
|
1576
|
+
Effect4.provide(httpClientLayer),
|
|
1577
|
+
Effect4.catch(() => Effect4.succeed(null))
|
|
1624
1578
|
);
|
|
1625
1579
|
if (specText === null) return null;
|
|
1626
|
-
const doc = yield* parse(specText).pipe(
|
|
1580
|
+
const doc = yield* parse(specText).pipe(Effect4.catch(() => Effect4.succeed(null)));
|
|
1627
1581
|
if (!doc) return null;
|
|
1628
|
-
const result = yield* extract(doc).pipe(
|
|
1582
|
+
const result = yield* extract(doc).pipe(Effect4.catch(() => Effect4.succeed(null)));
|
|
1629
1583
|
if (!result) return null;
|
|
1630
|
-
const slug =
|
|
1631
|
-
const name =
|
|
1584
|
+
const slug = Option6.getOrElse(result.title, () => "api").toLowerCase().replace(/[^a-z0-9]+/g, "_");
|
|
1585
|
+
const name = Option6.getOrElse(result.title, () => slug);
|
|
1632
1586
|
return IntegrationDetectionResult.make({
|
|
1633
1587
|
kind: "openapi",
|
|
1634
1588
|
confidence: "high",
|
|
@@ -1645,10 +1599,20 @@ export {
|
|
|
1645
1599
|
OpenApiIntegrationConfigSchema,
|
|
1646
1600
|
decodeOpenApiIntegrationConfig,
|
|
1647
1601
|
renderAuthTemplate,
|
|
1602
|
+
makeDefaultOpenapiStore,
|
|
1648
1603
|
invoke,
|
|
1649
1604
|
invokeWithLayer,
|
|
1650
1605
|
annotationsForOperation,
|
|
1651
|
-
|
|
1606
|
+
extractOpenApiUpstreamMessage,
|
|
1607
|
+
normalizeOpenApiRefs,
|
|
1608
|
+
compileOpenApiDocument,
|
|
1609
|
+
compileOpenApiSpec,
|
|
1610
|
+
openApiToolDefsFromCompiled,
|
|
1611
|
+
openApiStoredOperationsFromCompiled,
|
|
1612
|
+
loadOpenApiSpecText,
|
|
1613
|
+
resolveOpenApiBackedTools,
|
|
1614
|
+
invokeOpenApiBackedTool,
|
|
1615
|
+
resolveOpenApiBackedAnnotations,
|
|
1652
1616
|
openApiPlugin
|
|
1653
1617
|
};
|
|
1654
|
-
//# sourceMappingURL=chunk-
|
|
1618
|
+
//# sourceMappingURL=chunk-UEKOP6NZ.js.map
|