@executor-js/plugin-openapi 1.5.14 → 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.
Files changed (62) hide show
  1. package/dist/AddOpenApiSource-U7AYB224.js +369 -0
  2. package/dist/AddOpenApiSource-U7AYB224.js.map +1 -0
  3. package/dist/{OpenApiAccountsPanel-Y2RGBSSL.js → OpenApiAccountsPanel-GHFHHE6P.js} +15 -39
  4. package/dist/OpenApiAccountsPanel-GHFHHE6P.js.map +1 -0
  5. package/dist/{UpdateSpecSection-MIZ5GLBM.js → UpdateSpecSection-PLCBUU4I.js} +4 -4
  6. package/dist/UpdateSpecSection-PLCBUU4I.js.map +1 -0
  7. package/dist/api/group.d.ts +0 -21
  8. package/dist/api/index.d.ts +0 -21
  9. package/dist/{chunk-PNOEE3ET.js → chunk-3FM2SWM4.js} +643 -569
  10. package/dist/chunk-3FM2SWM4.js.map +1 -0
  11. package/dist/chunk-CKBX4SXK.js +95 -0
  12. package/dist/chunk-CKBX4SXK.js.map +1 -0
  13. package/dist/{chunk-GS5YN6J4.js → chunk-CPPTKUOW.js} +5 -14
  14. package/dist/chunk-CPPTKUOW.js.map +1 -0
  15. package/dist/{chunk-RFSMGUBJ.js → chunk-KVPUDOJZ.js} +83 -8
  16. package/dist/chunk-KVPUDOJZ.js.map +1 -0
  17. package/dist/{chunk-PAHWRRS3.js → chunk-QQFCICLX.js} +4 -13
  18. package/dist/chunk-QQFCICLX.js.map +1 -0
  19. package/dist/client.js +4 -5
  20. package/dist/client.js.map +1 -1
  21. package/dist/core.js +25 -15
  22. package/dist/core.js.map +1 -1
  23. package/dist/index.js +4 -5
  24. package/dist/index.js.map +1 -1
  25. package/dist/react/atoms.d.ts +0 -22
  26. package/dist/react/client.d.ts +0 -21
  27. package/dist/react/index.d.ts +2 -0
  28. package/dist/sdk/backing.d.ts +54 -0
  29. package/dist/sdk/config.d.ts +0 -2
  30. package/dist/sdk/derive-auth.d.ts +5 -3
  31. package/dist/sdk/extract.d.ts +12 -1
  32. package/dist/sdk/index.d.ts +2 -1
  33. package/dist/sdk/invoke.d.ts +12 -1
  34. package/dist/sdk/plugin.d.ts +4 -10
  35. package/dist/sdk/presets.d.ts +0 -1
  36. package/dist/sdk/preview.d.ts +79 -0
  37. package/dist/sdk/types.d.ts +53 -0
  38. package/dist/testing/index.d.ts +0 -6
  39. package/package.json +6 -5
  40. package/dist/AddOpenApiSource-7TI5XUUY.js +0 -765
  41. package/dist/AddOpenApiSource-7TI5XUUY.js.map +0 -1
  42. package/dist/OpenApiAccountsPanel-Y2RGBSSL.js.map +0 -1
  43. package/dist/UpdateSpecSection-MIZ5GLBM.js.map +0 -1
  44. package/dist/chunk-GS5YN6J4.js.map +0 -1
  45. package/dist/chunk-I2XDCVVM.js +0 -712
  46. package/dist/chunk-I2XDCVVM.js.map +0 -1
  47. package/dist/chunk-MZWZQ24W.js +0 -226
  48. package/dist/chunk-MZWZQ24W.js.map +0 -1
  49. package/dist/chunk-PAHWRRS3.js.map +0 -1
  50. package/dist/chunk-PNOEE3ET.js.map +0 -1
  51. package/dist/chunk-RFSMGUBJ.js.map +0 -1
  52. package/dist/react/GoogleProductPicker.d.ts +0 -9
  53. package/dist/sdk/google-discovery.d.ts +0 -43
  54. package/dist/sdk/google-discovery.test.d.ts +0 -1
  55. package/dist/sdk/google-oauth-batches.d.ts +0 -13
  56. package/dist/sdk/google-oauth-batches.test.d.ts +0 -1
  57. package/dist/sdk/google-oauth-scopes.d.ts +0 -3
  58. package/dist/sdk/google-oauth-scopes.test.d.ts +0 -1
  59. package/dist/sdk/google-presets.d.ts +0 -16
  60. package/dist/sdk/google-presets.test.d.ts +0 -1
  61. package/dist/sdk/google-product-picker-scopes.test.d.ts +0 -1
  62. /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
- fetchGoogleDiscoveryDocument,
6
- firstBaseUrlForPreview,
7
- isGoogleDiscoveryUrl
8
- } from "./chunk-I2XDCVVM.js";
3
+ firstBaseUrlForPreview
4
+ } from "./chunk-CKBX4SXK.js";
9
5
  import {
10
6
  openApiPresets
11
- } from "./chunk-PAHWRRS3.js";
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-RFSMGUBJ.js";
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 Option2 } from "effect";
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 = Option2.getOrUndefined(param.style) ?? "form";
111
- const explode = Option2.getOrElse(param.explode, () => true);
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 = Effect.fn("OpenApi.resolvePath")(function* (pathTemplate, args, parameters) {
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: Option2.none()
211
+ statusCode: Option3.none()
126
212
  });
127
213
  }
128
214
  continue;
129
215
  }
130
216
  const encoded = encodeReservedAware(
131
217
  String(value),
132
- Option2.getOrElse(param.allowReserved, () => false)
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: Option2.none()
234
+ statusCode: Option3.none()
149
235
  });
150
236
  }
151
237
  return resolved;
@@ -172,6 +258,72 @@ var isXmlContentType = (ct) => {
172
258
  };
173
259
  var isTextContentType = (ct) => normalizeContentType(ct).startsWith("text/");
174
260
  var isOctetStream = (ct) => normalizeContentType(ct) === "application/octet-stream";
261
+ var bytesToBase64 = (bytes) => {
262
+ let binary = "";
263
+ const chunkSize = 32768;
264
+ for (let i = 0; i < bytes.length; i += chunkSize) {
265
+ binary += String.fromCharCode(...bytes.subarray(i, i + chunkSize));
266
+ }
267
+ return btoa(binary);
268
+ };
269
+ var normalizeBase64 = (value, encoding) => {
270
+ const compact = value.replace(/\s/g, "");
271
+ const alphabet = encoding === "base64url" ? compact.replace(/-/g, "+").replace(/_/g, "/") : compact;
272
+ const remainder = alphabet.length % 4;
273
+ return remainder === 0 ? alphabet : `${alphabet}${"=".repeat(4 - remainder)}`;
274
+ };
275
+ var byteLengthFromBase64 = (base64) => {
276
+ const compact = base64.replace(/\s/g, "");
277
+ const padding = compact.endsWith("==") ? 2 : compact.endsWith("=") ? 1 : 0;
278
+ return Math.max(0, Math.floor(compact.length * 3 / 4) - padding);
279
+ };
280
+ var isGenericMimeType = (mimeType) => normalizeContentType(mimeType) === "application/octet-stream";
281
+ var startsWithBytes = (bytes, prefix) => prefix.every((byte, index) => bytes[index] === byte);
282
+ var isLikelyUtf8Text = (bytes) => {
283
+ if (bytes.length === 0) return false;
284
+ let text;
285
+ try {
286
+ text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
287
+ } catch {
288
+ return false;
289
+ }
290
+ let suspicious = 0;
291
+ for (let index = 0; index < text.length; index += 1) {
292
+ const code = text.charCodeAt(index);
293
+ const allowedControl = code === 9 || code === 10 || code === 12 || code === 13;
294
+ if (code === 0) return false;
295
+ if (code < 32 && !allowedControl) suspicious += 1;
296
+ }
297
+ return suspicious / Math.max(1, text.length) <= 0.02;
298
+ };
299
+ var sniffMimeType = (bytes) => {
300
+ if (startsWithBytes(bytes, [255, 216, 255])) return "image/jpeg";
301
+ if (startsWithBytes(bytes, [137, 80, 78, 71, 13, 10, 26, 10])) {
302
+ return "image/png";
303
+ }
304
+ if (startsWithBytes(bytes, [71, 73, 70, 56, 55, 97]) || startsWithBytes(bytes, [71, 73, 70, 56, 57, 97])) {
305
+ return "image/gif";
306
+ }
307
+ if (startsWithBytes(bytes, [82, 73, 70, 70]) && bytes[8] === 87 && bytes[9] === 69 && bytes[10] === 66 && bytes[11] === 80) {
308
+ return "image/webp";
309
+ }
310
+ if (startsWithBytes(bytes, [37, 80, 68, 70, 45])) return "application/pdf";
311
+ if (startsWithBytes(bytes, [80, 75, 3, 4]) || startsWithBytes(bytes, [80, 75, 5, 6]) || startsWithBytes(bytes, [80, 75, 7, 8])) {
312
+ return "application/zip";
313
+ }
314
+ if (isLikelyUtf8Text(bytes)) return "text/plain";
315
+ return null;
316
+ };
317
+ var bytesFromBase64Prefix = (base64) => {
318
+ const prefix = base64.slice(0, Math.min(base64.length, 64));
319
+ const binary = atob(prefix);
320
+ const bytes = new Uint8Array(binary.length);
321
+ for (let index = 0; index < binary.length; index += 1) {
322
+ bytes[index] = binary.charCodeAt(index);
323
+ }
324
+ return bytes;
325
+ };
326
+ var sniffMimeTypeFromBase64 = (base64) => sniffMimeType(bytesFromBase64Prefix(base64));
175
327
  var toUint8Array = (value) => {
176
328
  if (value instanceof Uint8Array) return value;
177
329
  if (value instanceof ArrayBuffer) return new Uint8Array(value);
@@ -184,6 +336,37 @@ var toUint8Array = (value) => {
184
336
  }
185
337
  return null;
186
338
  };
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");
342
+ var fileFromByteField = (body, hint) => {
343
+ if (typeof body !== "object" || body === null || Array.isArray(body)) return null;
344
+ const record = body;
345
+ const dataField = readHintString(hint.dataField, "data");
346
+ const rawData = record[dataField];
347
+ if (typeof rawData !== "string") return null;
348
+ const data = normalizeBase64(rawData, readHintEncoding(hint));
349
+ const sizeField = Option3.getOrUndefined(hint.sizeField);
350
+ const byteLength = sizeField && typeof record[sizeField] === "number" ? record[sizeField] : byteLengthFromBase64(data);
351
+ const hintedMimeType = readHintMimeType(hint, "application/octet-stream");
352
+ return {
353
+ _tag: "ToolFile",
354
+ mimeType: isGenericMimeType(hintedMimeType) ? sniffMimeTypeFromBase64(data) ?? hintedMimeType : hintedMimeType,
355
+ encoding: "base64",
356
+ data,
357
+ byteLength
358
+ };
359
+ };
360
+ var fileFromBinaryBytes = (bytes, hint, contentType) => {
361
+ const hintedMimeType = contentType ?? readHintMimeType(hint, "application/octet-stream");
362
+ return {
363
+ _tag: "ToolFile",
364
+ mimeType: isGenericMimeType(hintedMimeType) ? sniffMimeType(bytes) ?? hintedMimeType : hintedMimeType,
365
+ encoding: "base64",
366
+ data: bytesToBase64(bytes),
367
+ byteLength: bytes.byteLength
368
+ };
369
+ };
187
370
  var toArrayBuffer = (bytes) => {
188
371
  const copy = new ArrayBuffer(bytes.byteLength);
189
372
  new Uint8Array(copy).set(bytes);
@@ -197,9 +380,9 @@ var DEFAULT_FORM_STYLE = {
197
380
  var resolveStyleExplode = (e) => {
198
381
  if (!e) return DEFAULT_FORM_STYLE;
199
382
  return {
200
- style: Option2.getOrElse(e.style, () => DEFAULT_FORM_STYLE.style),
201
- explode: Option2.getOrElse(e.explode, () => DEFAULT_FORM_STYLE.explode),
202
- allowReserved: Option2.getOrElse(e.allowReserved, () => DEFAULT_FORM_STYLE.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)
203
386
  };
204
387
  };
205
388
  var encodeFormValue = (v, allowReserved) => {
@@ -259,7 +442,7 @@ var coerceFormDataRecord = (value, encoding) => {
259
442
  const out = {};
260
443
  for (const [key, raw] of Object.entries(value)) {
261
444
  if (raw === void 0 || raw === null) continue;
262
- const partType = encoding?.[key] ? Option2.getOrUndefined(encoding[key].contentType) : void 0;
445
+ const partType = encoding?.[key] ? Option3.getOrUndefined(encoding[key].contentType) : void 0;
263
446
  if (partType) {
264
447
  const isJson = partType.startsWith("application/json") || partType.includes("+json");
265
448
  const serialized = typeof raw === "string" ? raw : isJson ? JSON.stringify(raw) : typeof raw === "object" ? JSON.stringify(raw) : String(raw);
@@ -340,9 +523,9 @@ var applyRequestBody = (request, contentType, bodyValue, encoding) => {
340
523
  if (bytes) return HttpClientRequest.bodyUint8Array(request, bytes, contentType);
341
524
  return HttpClientRequest.bodyText(request, JSON.stringify(bodyValue), contentType);
342
525
  };
343
- var invoke = Effect.fn("OpenApi.invoke")(function* (operation, args, resolvedHeaders, sourceQueryParams = {}) {
526
+ var invoke = Effect2.fn("OpenApi.invoke")(function* (operation, args, resolvedHeaders, sourceQueryParams = {}) {
344
527
  const client = yield* HttpClient.HttpClient;
345
- yield* Effect.annotateCurrentSpan({
528
+ yield* Effect2.annotateCurrentSpan({
346
529
  "http.method": operation.method.toUpperCase(),
347
530
  "http.route": operation.pathTemplate,
348
531
  "plugin.openapi.method": operation.method.toUpperCase(),
@@ -368,50 +551,57 @@ var invoke = Effect.fn("OpenApi.invoke")(function* (operation, args, resolvedHea
368
551
  if (value === void 0 || value === null) continue;
369
552
  request = HttpClientRequest.setHeader(request, param.name, String(value));
370
553
  }
371
- if (Option2.isSome(operation.requestBody)) {
554
+ if (Option3.isSome(operation.requestBody)) {
372
555
  const rb = operation.requestBody.value;
373
556
  const bodyValue = args.body ?? args.input;
374
557
  if (bodyValue !== void 0) {
375
- const contentsOpt = Option2.getOrUndefined(rb.contents);
558
+ const contentsOpt = Option3.getOrUndefined(rb.contents);
376
559
  const requestedCt = typeof args.contentType === "string" ? args.contentType : void 0;
377
560
  const selected = contentsOpt && requestedCt ? contentsOpt.find((c) => c.contentType === requestedCt) : void 0;
378
561
  const chosenCt = selected?.contentType ?? rb.contentType;
379
- const chosenEncoding = selected ? Option2.getOrUndefined(selected.encoding) : contentsOpt && contentsOpt[0] ? Option2.getOrUndefined(contentsOpt[0].encoding) : void 0;
562
+ const chosenEncoding = selected ? Option3.getOrUndefined(selected.encoding) : contentsOpt && contentsOpt[0] ? Option3.getOrUndefined(contentsOpt[0].encoding) : void 0;
380
563
  request = applyRequestBody(request, chosenCt, bodyValue, chosenEncoding);
381
564
  }
382
565
  }
383
566
  request = applyHeaders(request, resolvedHeaders);
384
567
  const response = yield* client.execute(request).pipe(
385
- Effect.mapError(
568
+ Effect2.mapError(
386
569
  (err) => new OpenApiInvocationError({
387
570
  message: "HTTP request failed",
388
- statusCode: Option2.none(),
571
+ statusCode: Option3.none(),
389
572
  cause: err
390
573
  })
391
574
  )
392
575
  );
393
576
  const status = response.status;
394
- yield* Effect.annotateCurrentSpan({
577
+ yield* Effect2.annotateCurrentSpan({
395
578
  "http.status_code": status
396
579
  });
397
580
  const responseHeaders = { ...response.headers };
398
581
  const contentType = response.headers["content-type"] ?? null;
399
- const mapBodyError = Effect.mapError(
582
+ const mapBodyError = Effect2.mapError(
400
583
  (err) => new OpenApiInvocationError({
401
584
  message: "Failed to read response body",
402
- statusCode: Option2.some(status),
585
+ statusCode: Option3.some(status),
403
586
  cause: err
404
587
  })
405
588
  );
406
- const responseBody = status === 204 ? null : isJsonContentType(contentType) ? yield* response.json.pipe(
407
- Effect.catch(() => response.text),
589
+ const responseBodyBinding = Option3.getOrUndefined(operation.responseBody);
590
+ const fileHint = responseBodyBinding ? Option3.getOrUndefined(responseBodyBinding.fileHint) : void 0;
591
+ const ok = status >= 200 && status < 300;
592
+ const responseBody = status === 204 ? null : ok && fileHint?.kind === "binaryResponse" ? fileFromBinaryBytes(
593
+ new Uint8Array(yield* response.arrayBuffer.pipe(mapBodyError)),
594
+ fileHint,
595
+ contentType
596
+ ) : isJsonContentType(contentType) ? yield* response.json.pipe(
597
+ Effect2.catch(() => response.text),
408
598
  mapBodyError
409
599
  ) : yield* response.text.pipe(mapBodyError);
410
- const ok = status >= 200 && status < 300;
600
+ const dataBody = ok && fileHint?.kind === "byteField" ? fileFromByteField(responseBody, fileHint) ?? responseBody : responseBody;
411
601
  return InvocationResult.make({
412
602
  status,
413
603
  headers: responseHeaders,
414
- data: ok ? responseBody : null,
604
+ data: ok ? dataBody : null,
415
605
  error: ok ? null : responseBody
416
606
  });
417
607
  });
@@ -426,25 +616,25 @@ var resolveRequestHost = (servers, serverArg, baseUrl) => {
426
616
  if (value != null && value !== "") overrides[name] = String(value);
427
617
  }
428
618
  }
429
- return resolveServerUrl(chosen.url, Option2.getOrUndefined(chosen.variables), overrides);
619
+ return resolveServerUrl(chosen.url, Option3.getOrUndefined(chosen.variables), overrides);
430
620
  };
431
621
  var invokeWithLayer = (operation, args, baseUrl, resolvedHeaders, sourceQueryParams, httpClientLayer) => {
432
622
  const effectiveBaseUrl = resolveRequestHost(operation.servers ?? [], args.server, baseUrl);
433
623
  const clientWithBaseUrl = effectiveBaseUrl ? Layer.effect(
434
624
  HttpClient.HttpClient,
435
- Effect.map(
436
- Effect.service(HttpClient.HttpClient),
625
+ Effect2.map(
626
+ Effect2.service(HttpClient.HttpClient),
437
627
  HttpClient.mapRequest(HttpClientRequest.prependUrl(effectiveBaseUrl))
438
628
  )
439
629
  ).pipe(Layer.provide(httpClientLayer)) : httpClientLayer;
440
630
  return invoke(operation, args, resolvedHeaders, sourceQueryParams).pipe(
441
- Effect.provide(clientWithBaseUrl),
631
+ Effect2.provide(clientWithBaseUrl),
442
632
  // `invoke` annotates http.status_code on ITS span (`OpenApi.invoke`,
443
633
  // via Effect.fn) — annotateCurrentSpan inside it never reaches this
444
634
  // wrapper span. Stamp the status here too so queries against
445
635
  // `plugin.openapi.invoke` see the upstream outcome directly.
446
- Effect.tap((result) => Effect.annotateCurrentSpan({ "http.status_code": result.status })),
447
- Effect.withSpan("plugin.openapi.invoke", {
636
+ Effect2.tap((result) => Effect2.annotateCurrentSpan({ "http.status_code": result.status })),
637
+ Effect2.withSpan("plugin.openapi.invoke", {
448
638
  attributes: {
449
639
  "plugin.openapi.method": operation.method.toUpperCase(),
450
640
  "plugin.openapi.path_template": operation.pathTemplate,
@@ -463,88 +653,13 @@ var annotationsForOperation = (method, pathTemplate) => {
463
653
  };
464
654
  };
465
655
 
466
- // src/sdk/store.ts
467
- import { Effect as Effect2, Option as Option3, Predicate, Schema as Schema2 } from "effect";
468
- var OPERATION_COLLECTION = "operation";
469
- var STORE_OWNER = "org";
470
- var encodeBinding = Schema2.encodeSync(OperationBinding);
471
- var decodeBinding = Schema2.decodeUnknownSync(OperationBinding);
472
- var decodeBindingJson = Schema2.decodeUnknownSync(Schema2.fromJsonString(OperationBinding));
473
- var toJsonRecord = (value) => value;
474
- var OperationStorage = Schema2.Struct({
475
- integration: Schema2.String,
476
- toolName: Schema2.String,
477
- binding: Schema2.Unknown
478
- });
479
- var decodeOperationStorage = Schema2.decodeUnknownOption(OperationStorage);
480
- var rowToOperation = (row) => {
481
- const decoded = decodeOperationStorage(row.data);
482
- if (Option3.isNone(decoded)) return null;
483
- const operation = decoded.value;
484
- return {
485
- integration: operation.integration,
486
- toolName: operation.toolName,
487
- binding: decodeBinding(
488
- typeof operation.binding === "string" ? decodeBindingJson(operation.binding) : operation.binding
489
- )
490
- };
491
- };
492
- var operationKey = (integration, toolName) => `${integration}.${toolName}`;
493
- var specBlobKey = (specHash) => `spec/${specHash}`;
494
- var makeDefaultOpenapiStore = ({ pluginStorage, blobs }) => {
495
- const operationData = (operation) => ({
496
- integration: operation.integration,
497
- toolName: operation.toolName,
498
- binding: toJsonRecord(encodeBinding(operation.binding))
499
- });
500
- const listRows = (integration) => pluginStorage.list({ collection: OPERATION_COLLECTION, keyPrefix: `${integration}.` }).pipe(
501
- Effect2.map(
502
- (rows) => rows.filter((row) => rowToOperation(row)?.integration === integration)
503
- )
504
- );
505
- const removeOperations = (integration) => Effect2.gen(function* () {
506
- const rows = yield* listRows(integration);
507
- yield* pluginStorage.removeMany({
508
- owner: STORE_OWNER,
509
- entries: rows.map((row) => ({ collection: OPERATION_COLLECTION, key: row.key }))
510
- });
511
- });
512
- return {
513
- putOperations: (integration, operations) => Effect2.gen(function* () {
514
- yield* removeOperations(integration);
515
- yield* pluginStorage.putMany({
516
- owner: STORE_OWNER,
517
- entries: operations.map((operation) => ({
518
- collection: OPERATION_COLLECTION,
519
- key: operationKey(integration, operation.toolName),
520
- data: operationData(operation)
521
- }))
522
- });
523
- }),
524
- getOperation: (integration, toolName) => pluginStorage.get({ collection: OPERATION_COLLECTION, key: operationKey(integration, toolName) }).pipe(Effect2.map((row) => row ? rowToOperation(row) : null)),
525
- listOperations: (integration) => listRows(integration).pipe(
526
- Effect2.map((rows) => rows.map(rowToOperation).filter(Predicate.isNotNull))
527
- ),
528
- removeOperations,
529
- putSpec: (specHash, specText) => blobs.put(specBlobKey(specHash), specText, { owner: STORE_OWNER }),
530
- getSpec: (specHash) => blobs.get(specBlobKey(specHash))
531
- };
532
- };
533
-
534
- // src/sdk/plugin.ts
656
+ // src/sdk/backing.ts
535
657
  import { Effect as Effect3, Option as Option5, Schema as Schema3 } from "effect";
536
658
  import {
537
- IntegrationAlreadyExistsError,
538
- IntegrationDetectionResult,
539
- IntegrationNotFoundError,
540
- IntegrationSlug,
659
+ ToolFileJsonSchema,
541
660
  ToolName,
542
661
  ToolResult,
543
- authToolFailure,
544
- definePlugin,
545
- mergeAuthTemplates,
546
- sha256Hex,
547
- tool
662
+ authToolFailure
548
663
  } from "@executor-js/sdk/core";
549
664
 
550
665
  // src/sdk/definitions.ts
@@ -692,8 +807,7 @@ var compileToolDefinitions = (operations) => {
692
807
  return resolveCollisions(raw).sort((a, b) => a.toolPath.localeCompare(b.toolPath));
693
808
  };
694
809
 
695
- // src/sdk/plugin.ts
696
- import { ApiKeyAuthTemplate, describeApiKeyAuthMethod } from "@executor-js/sdk/http-auth";
810
+ // src/sdk/backing.ts
697
811
  var STRINGIFIED_BODY_CAP = 1024;
698
812
  var UpstreamMessageBody = Schema3.Struct({ message: Schema3.String });
699
813
  var UpstreamErrorMessageBody = Schema3.Struct({ errorMessage: Schema3.String });
@@ -727,7 +841,7 @@ var clampedStringify = (value) => {
727
841
  return s.length > STRINGIFIED_BODY_CAP ? `${s.slice(0, STRINGIFIED_BODY_CAP)}\u2026` : s;
728
842
  };
729
843
  var firstNonEmpty = (...values) => values.find((value) => value !== void 0 && value.length > 0);
730
- var extractUpstreamMessage = (body, status) => {
844
+ var extractOpenApiUpstreamMessage = (body, status) => {
731
845
  if (typeof body === "string") {
732
846
  return body.length > 0 ? body : `Upstream returned HTTP ${status}`;
733
847
  }
@@ -758,162 +872,353 @@ var extractUpstreamMessage = (body, status) => {
758
872
  }
759
873
  return `Upstream returned HTTP ${status}`;
760
874
  };
761
- var PreviewSpecInputSchema = Schema3.Struct({
762
- spec: Schema3.String
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
763
924
  });
764
- var StaticPreviewServerVariableSchema = Schema3.Struct({
765
- default: Schema3.String,
766
- enum: Schema3.NullOr(Schema3.Array(Schema3.String)),
767
- description: Schema3.NullOr(Schema3.String)
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
+ };
768
946
  });
769
- var StaticPreviewServerSchema = Schema3.Struct({
770
- url: Schema3.String,
771
- description: Schema3.NullOr(Schema3.String),
772
- variables: Schema3.NullOr(Schema3.Record(Schema3.String, StaticPreviewServerVariableSchema))
947
+ var compileOpenApiSpec = (specText) => Effect3.gen(function* () {
948
+ const doc = yield* parse(specText);
949
+ return yield* compileOpenApiDocument(doc);
773
950
  });
774
- var StaticPreviewOAuthAuthorizationCodeFlowSchema = Schema3.Struct({
775
- authorizationUrl: Schema3.String,
776
- tokenUrl: Schema3.String,
777
- refreshUrl: Schema3.NullOr(Schema3.String),
778
- scopes: Schema3.Record(Schema3.String, Schema3.String)
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
+ };
779
985
  });
780
- var StaticPreviewOAuthClientCredentialsFlowSchema = Schema3.Struct({
781
- tokenUrl: Schema3.String,
782
- refreshUrl: Schema3.NullOr(Schema3.String),
783
- scopes: Schema3.Record(Schema3.String, Schema3.String)
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;
1076
+ });
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)
1099
+ });
1100
+ var StaticPreviewServerSchema = Schema4.Struct({
1101
+ url: Schema4.String,
1102
+ description: Schema4.NullOr(Schema4.String),
1103
+ variables: Schema4.NullOr(Schema4.Record(Schema4.String, StaticPreviewServerVariableSchema))
784
1104
  });
785
- var StaticPreviewOAuthFlowsSchema = Schema3.Struct({
786
- authorizationCode: Schema3.NullOr(StaticPreviewOAuthAuthorizationCodeFlowSchema),
787
- clientCredentials: Schema3.NullOr(StaticPreviewOAuthClientCredentialsFlowSchema)
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)
788
1110
  });
789
- var StaticPreviewSecuritySchemeSchema = Schema3.Struct({
790
- name: Schema3.String,
791
- type: Schema3.Literals(["http", "apiKey", "oauth2", "openIdConnect"]),
792
- scheme: Schema3.NullOr(Schema3.String),
793
- bearerFormat: Schema3.NullOr(Schema3.String),
794
- in: Schema3.NullOr(Schema3.Literals(["header", "query", "cookie"])),
795
- headerName: Schema3.NullOr(Schema3.String),
796
- description: Schema3.NullOr(Schema3.String),
797
- flows: Schema3.NullOr(StaticPreviewOAuthFlowsSchema),
798
- openIdConnectUrl: Schema3.NullOr(Schema3.String)
1111
+ var StaticPreviewOAuthClientCredentialsFlowSchema = Schema4.Struct({
1112
+ tokenUrl: Schema4.String,
1113
+ refreshUrl: Schema4.NullOr(Schema4.String),
1114
+ scopes: Schema4.Record(Schema4.String, Schema4.String)
799
1115
  });
800
- var StaticPreviewOAuth2PresetSchema = Schema3.Struct({
801
- label: Schema3.String,
802
- securitySchemeName: Schema3.String,
803
- flow: Schema3.Literals(["authorizationCode", "clientCredentials"]),
804
- authorizationUrl: Schema3.NullOr(Schema3.String),
805
- tokenUrl: Schema3.String,
806
- refreshUrl: Schema3.NullOr(Schema3.String),
807
- scopes: Schema3.Record(Schema3.String, Schema3.String),
808
- identityScopes: Schema3.Union([
809
- Schema3.Literal("auto"),
810
- Schema3.Literal(false),
811
- Schema3.Array(Schema3.String)
1116
+ var StaticPreviewOAuthFlowsSchema = Schema4.Struct({
1117
+ authorizationCode: Schema4.NullOr(StaticPreviewOAuthAuthorizationCodeFlowSchema),
1118
+ clientCredentials: Schema4.NullOr(StaticPreviewOAuthClientCredentialsFlowSchema)
1119
+ });
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)
1130
+ });
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)
812
1143
  ])
813
1144
  });
814
- var StaticPreviewSpecOutputSchema = Schema3.Struct({
815
- title: Schema3.NullOr(Schema3.String),
816
- version: Schema3.NullOr(Schema3.String),
817
- servers: Schema3.Array(StaticPreviewServerSchema),
818
- operationCount: Schema3.Number,
819
- tags: Schema3.Array(Schema3.String),
820
- securitySchemes: Schema3.Array(StaticPreviewSecuritySchemeSchema),
821
- authStrategies: Schema3.Array(Schema3.Struct({ schemes: Schema3.Array(Schema3.String) })),
822
- headerPresets: Schema3.Array(
823
- Schema3.Struct({
824
- label: Schema3.String,
825
- headers: Schema3.Record(Schema3.String, Schema3.NullOr(Schema3.String)),
826
- secretHeaders: Schema3.Array(Schema3.String)
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)
827
1158
  })
828
1159
  ),
829
- oauth2Presets: Schema3.Array(StaticPreviewOAuth2PresetSchema)
1160
+ oauth2Presets: Schema4.Array(StaticPreviewOAuth2PresetSchema)
830
1161
  });
831
- var OpenApiSpecInputSchema = Schema3.Union([
832
- Schema3.Struct({ kind: Schema3.Literal("url"), url: Schema3.String }),
833
- Schema3.Struct({ kind: Schema3.Literal("blob"), value: Schema3.String }),
834
- Schema3.Struct({
835
- kind: Schema3.Literal("googleDiscovery"),
836
- url: Schema3.String
837
- }),
838
- Schema3.Struct({
839
- kind: Schema3.Literal("googleDiscoveryBundle"),
840
- urls: Schema3.Array(Schema3.String)
841
- })
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 })
842
1165
  ]);
843
- var AuthenticationSchema2 = Schema3.Union([
844
- Schema3.Struct({
845
- slug: Schema3.String,
846
- kind: Schema3.Literal("oauth2"),
847
- authorizationUrl: Schema3.String,
848
- tokenUrl: Schema3.String,
849
- scopes: Schema3.Array(Schema3.String)
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)
850
1173
  }),
851
- // Credential methods are authored request-shaped the ONE apikey input
1174
+ // Credential methods are authored request-shaped - the ONE apikey input
852
1175
  // dialect: `{ type: "apiKey", headers: { Authorization: ["Bearer ",
853
1176
  // variable("token")] }, queryParams: { … } }`.
854
1177
  ApiKeyAuthTemplate
855
1178
  ]);
856
- var AddSourceInputSchema = Schema3.Struct({
1179
+ var AddSourceInputSchema = Schema4.Struct({
857
1180
  spec: OpenApiSpecInputSchema,
858
- slug: Schema3.String,
859
- description: Schema3.optional(Schema3.String),
860
- baseUrl: Schema3.optional(Schema3.String),
861
- headers: Schema3.optional(Schema3.Record(Schema3.String, Schema3.String)),
862
- queryParams: Schema3.optional(Schema3.Record(Schema3.String, Schema3.String)),
863
- authenticationTemplate: Schema3.optional(Schema3.Array(AuthenticationSchema2))
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))
864
1187
  });
865
- var AddSourceOutputSchema = Schema3.Struct({
866
- slug: Schema3.String,
867
- toolCount: Schema3.Number
1188
+ var AddSourceOutputSchema = Schema4.Struct({
1189
+ slug: Schema4.String,
1190
+ toolCount: Schema4.Number
868
1191
  });
869
- var PreviewSpecInputStandardSchema = Schema3.toStandardSchemaV1(
870
- Schema3.toStandardJSONSchemaV1(PreviewSpecInputSchema)
1192
+ var PreviewSpecInputStandardSchema = Schema4.toStandardSchemaV1(
1193
+ Schema4.toStandardJSONSchemaV1(PreviewSpecInputSchema)
871
1194
  );
872
- var PreviewSpecOutputStandardSchema = Schema3.toStandardSchemaV1(
873
- Schema3.toStandardJSONSchemaV1(StaticPreviewSpecOutputSchema)
1195
+ var PreviewSpecOutputStandardSchema = Schema4.toStandardSchemaV1(
1196
+ Schema4.toStandardJSONSchemaV1(StaticPreviewSpecOutputSchema)
874
1197
  );
875
- var AddSourceInputStandardSchema = Schema3.toStandardSchemaV1(
876
- Schema3.toStandardJSONSchemaV1(AddSourceInputSchema)
1198
+ var AddSourceInputStandardSchema = Schema4.toStandardSchemaV1(
1199
+ Schema4.toStandardJSONSchemaV1(AddSourceInputSchema)
877
1200
  );
878
- var AddSourceOutputStandardSchema = Schema3.toStandardSchemaV1(
879
- Schema3.toStandardJSONSchemaV1(AddSourceOutputSchema)
1201
+ var AddSourceOutputStandardSchema = Schema4.toStandardSchemaV1(
1202
+ Schema4.toStandardJSONSchemaV1(AddSourceOutputSchema)
880
1203
  );
881
- var openApiToolFailure = (code, message, details) => ToolResult.fail({
1204
+ var openApiToolFailure = (code, message, details) => ToolResult2.fail({
882
1205
  code,
883
1206
  message,
884
1207
  ...details === void 0 ? {} : { details }
885
1208
  });
886
- var openApiAuthToolFailure = (failure) => authToolFailure({
887
- // The auth-tool-failure helper's code set is shared with v1; keep the
888
- // string but reference the connection rather than v1's source/slot.
889
- code: failure.code,
890
- message: failure.message,
891
- source: { id: failure.integration, scope: failure.owner },
892
- credential: {
893
- kind: failure.credentialKind,
894
- ...failure.credentialLabel ? { label: failure.credentialLabel } : {}
895
- },
896
- ...failure.status !== void 0 ? { status: failure.status } : {},
897
- ...failure.details !== void 0 ? {
898
- upstream: {
899
- ...failure.status !== void 0 ? { status: failure.status } : {},
900
- details: failure.details
901
- }
902
- } : {}
903
- });
904
1209
  var staticPreviewOutput = (preview) => ({
905
- title: Option5.getOrNull(preview.title),
906
- version: Option5.getOrNull(preview.version),
1210
+ title: Option6.getOrNull(preview.title),
1211
+ version: Option6.getOrNull(preview.version),
907
1212
  servers: preview.servers.map((server) => ({
908
1213
  url: server.url,
909
- description: Option5.getOrNull(server.description),
910
- variables: Option5.getOrNull(server.variables) ? Object.fromEntries(
911
- Object.entries(Option5.getOrNull(server.variables) ?? {}).map(([name, variable]) => [
1214
+ description: Option6.getOrNull(server.description),
1215
+ variables: Option6.getOrNull(server.variables) ? Object.fromEntries(
1216
+ Object.entries(Option6.getOrNull(server.variables) ?? {}).map(([name, variable]) => [
912
1217
  name,
913
1218
  {
914
1219
  default: variable.default,
915
- enum: Option5.getOrNull(variable.enum),
916
- description: Option5.getOrNull(variable.description)
1220
+ enum: Option6.getOrNull(variable.enum),
1221
+ description: Option6.getOrNull(variable.description)
917
1222
  }
918
1223
  ])
919
1224
  ) : null
@@ -923,25 +1228,25 @@ var staticPreviewOutput = (preview) => ({
923
1228
  securitySchemes: preview.securitySchemes.map((scheme) => ({
924
1229
  name: scheme.name,
925
1230
  type: scheme.type,
926
- scheme: Option5.getOrNull(scheme.scheme),
927
- bearerFormat: Option5.getOrNull(scheme.bearerFormat),
928
- in: Option5.getOrNull(scheme.in),
929
- headerName: Option5.getOrNull(scheme.headerName),
930
- description: Option5.getOrNull(scheme.description),
931
- flows: Option5.isSome(scheme.flows) ? {
932
- authorizationCode: Option5.isSome(scheme.flows.value.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) ? {
933
1238
  authorizationUrl: scheme.flows.value.authorizationCode.value.authorizationUrl,
934
1239
  tokenUrl: scheme.flows.value.authorizationCode.value.tokenUrl,
935
- refreshUrl: Option5.getOrNull(scheme.flows.value.authorizationCode.value.refreshUrl),
1240
+ refreshUrl: Option6.getOrNull(scheme.flows.value.authorizationCode.value.refreshUrl),
936
1241
  scopes: scheme.flows.value.authorizationCode.value.scopes
937
1242
  } : null,
938
- clientCredentials: Option5.isSome(scheme.flows.value.clientCredentials) ? {
1243
+ clientCredentials: Option6.isSome(scheme.flows.value.clientCredentials) ? {
939
1244
  tokenUrl: scheme.flows.value.clientCredentials.value.tokenUrl,
940
- refreshUrl: Option5.getOrNull(scheme.flows.value.clientCredentials.value.refreshUrl),
1245
+ refreshUrl: Option6.getOrNull(scheme.flows.value.clientCredentials.value.refreshUrl),
941
1246
  scopes: scheme.flows.value.clientCredentials.value.scopes
942
1247
  } : null
943
1248
  } : null,
944
- openIdConnectUrl: Option5.getOrNull(scheme.openIdConnectUrl)
1249
+ openIdConnectUrl: Option6.getOrNull(scheme.openIdConnectUrl)
945
1250
  })),
946
1251
  authStrategies: preview.authStrategies,
947
1252
  headerPresets: preview.headerPresets,
@@ -949,55 +1254,14 @@ var staticPreviewOutput = (preview) => ({
949
1254
  label: preset.label,
950
1255
  securitySchemeName: preset.securitySchemeName,
951
1256
  flow: preset.flow,
952
- authorizationUrl: Option5.getOrNull(preset.authorizationUrl),
1257
+ authorizationUrl: Option6.getOrNull(preset.authorizationUrl),
953
1258
  tokenUrl: preset.tokenUrl,
954
- refreshUrl: Option5.getOrNull(preset.refreshUrl),
1259
+ refreshUrl: Option6.getOrNull(preset.refreshUrl),
955
1260
  scopes: preset.scopes,
956
1261
  identityScopes: preset.identityScopes
957
1262
  }))
958
1263
  });
959
- var normalizeOpenApiRefs = (node) => {
960
- if (node == null || typeof node !== "object") return node;
961
- if (Array.isArray(node)) {
962
- let changed2 = false;
963
- const out = node.map((item) => {
964
- const n = normalizeOpenApiRefs(item);
965
- if (n !== item) changed2 = true;
966
- return n;
967
- });
968
- return changed2 ? out : node;
969
- }
970
- const obj = node;
971
- if (typeof obj.$ref === "string") {
972
- const match = obj.$ref.match(/^#\/components\/schemas\/(.+)$/);
973
- if (match) return { ...obj, $ref: `#/$defs/${match[1]}` };
974
- return obj;
975
- }
976
- let changed = false;
977
- const result = {};
978
- for (const [k, v] of Object.entries(obj)) {
979
- const n = normalizeOpenApiRefs(v);
980
- if (n !== v) changed = true;
981
- result[k] = n;
982
- }
983
- return changed ? result : obj;
984
- };
985
- var toBinding = (def) => OperationBinding.make({
986
- method: def.operation.method,
987
- servers: def.operation.servers,
988
- pathTemplate: def.operation.pathTemplate,
989
- parameters: [...def.operation.parameters],
990
- requestBody: def.operation.requestBody
991
- });
992
- var descriptionFor = (def) => {
993
- const op = def.operation;
994
- return Option5.getOrElse(
995
- op.description,
996
- () => Option5.getOrElse(op.summary, () => `${op.method.toUpperCase()} ${op.pathTemplate}`)
997
- );
998
- };
999
- var specInputToSourceUrl = (spec) => spec.kind === "url" || spec.kind === "googleDiscovery" ? spec.url : void 0;
1000
- var specInputToGoogleBundle = (spec) => spec.kind === "googleDiscoveryBundle" ? spec.urls : void 0;
1264
+ var specInputToSourceUrl = (spec) => spec.kind === "url" ? spec.url : void 0;
1001
1265
  var describeOpenApiAuthMethods = (record) => {
1002
1266
  const config = decodeOpenApiIntegrationConfig(record.config);
1003
1267
  if (!config) return [];
@@ -1024,76 +1288,10 @@ var describeOpenApiIntegrationDisplay = (record) => {
1024
1288
  const config = decodeOpenApiIntegrationConfig(record.config);
1025
1289
  return { url: config?.baseUrl ?? config?.sourceUrl };
1026
1290
  };
1027
- var loadSpecText = (storage, config) => config.specHash != null ? storage.getSpec(config.specHash) : Effect3.succeed(null);
1028
- var compileSpec = (specText) => Effect3.gen(function* () {
1029
- const doc = yield* parse(specText);
1030
- const result = yield* extract(doc);
1031
- const hoistedDefs = {};
1032
- if (doc.components?.schemas) {
1033
- for (const [k, v] of Object.entries(doc.components.schemas)) {
1034
- hoistedDefs[k] = normalizeOpenApiRefs(v);
1035
- }
1036
- }
1037
- return {
1038
- definitions: compileToolDefinitions(result.operations),
1039
- hoistedDefs,
1040
- title: Option5.getOrUndefined(result.title),
1041
- description: Option5.getOrUndefined(result.description)
1042
- };
1043
- });
1044
- var toolDefsFromCompiled = (compiled) => compiled.definitions.map(
1045
- (def) => ({
1046
- name: ToolName.make(def.toolPath),
1047
- description: descriptionFor(def),
1048
- inputSchema: normalizeOpenApiRefs(Option5.getOrUndefined(def.operation.inputSchema)),
1049
- // The output schema is the upstream response body only — transport
1050
- // status/headers live in the ToolResult `http` side channel, not the
1051
- // payload (see the invoke handler).
1052
- outputSchema: normalizeOpenApiRefs(Option5.getOrUndefined(def.operation.outputSchema)),
1053
- annotations: annotationsForOperation(def.operation.method, def.operation.pathTemplate)
1054
- })
1055
- );
1056
- var storedOperationsFromCompiled = (integration, compiled) => compiled.definitions.map((def) => ({
1057
- integration,
1058
- toolName: def.toolPath,
1059
- binding: toBinding(def)
1060
- }));
1061
- var fetchGoogleDiscoveryBundleConversion = (urls, httpClientLayer) => Effect3.forEach(
1062
- urls,
1063
- (url) => fetchGoogleDiscoveryDocument(url).pipe(
1064
- Effect3.provide(httpClientLayer),
1065
- Effect3.map((documentText) => ({ discoveryUrl: url, documentText }))
1066
- ),
1067
- { concurrency: 4 }
1068
- ).pipe(Effect3.flatMap((documents) => convertGoogleDiscoveryBundleToOpenApi({ documents })));
1069
1291
  var openApiPlugin = definePlugin((options) => {
1070
- const resolveSpecForInput = (spec, httpClientLayer) => Effect3.gen(function* () {
1071
- if (spec.kind === "googleDiscovery") {
1072
- const conversion = yield* fetchGoogleDiscoveryDocument(spec.url).pipe(
1073
- Effect3.provide(httpClientLayer),
1074
- Effect3.flatMap(
1075
- (documentText) => convertGoogleDiscoveryToOpenApi({
1076
- discoveryUrl: spec.url,
1077
- documentText
1078
- })
1079
- )
1080
- );
1081
- return {
1082
- specText: conversion.specText,
1083
- baseUrl: conversion.baseUrl,
1084
- ...conversion.authenticationTemplate ? { authenticationTemplate: conversion.authenticationTemplate } : {}
1085
- };
1086
- }
1087
- if (spec.kind === "googleDiscoveryBundle") {
1088
- const conversion = yield* fetchGoogleDiscoveryBundleConversion(spec.urls, httpClientLayer);
1089
- return {
1090
- specText: conversion.specText,
1091
- baseUrl: conversion.baseUrl,
1092
- ...conversion.authenticationTemplate ? { authenticationTemplate: conversion.authenticationTemplate } : {}
1093
- };
1094
- }
1292
+ const resolveSpecForInput = (spec, httpClientLayer) => Effect4.gen(function* () {
1095
1293
  if (spec.kind === "url") {
1096
- const specText = yield* resolveSpecText(spec.url).pipe(Effect3.provide(httpClientLayer));
1294
+ const specText = yield* resolveSpecText(spec.url).pipe(Effect4.provide(httpClientLayer));
1097
1295
  return { specText };
1098
1296
  }
1099
1297
  return { specText: spec.value };
@@ -1112,12 +1310,12 @@ var openApiPlugin = definePlugin((options) => {
1112
1310
  storage: (deps) => makeDefaultOpenapiStore(deps),
1113
1311
  extension: (ctx) => {
1114
1312
  const httpClientLayer = options?.httpClientLayer ?? ctx.httpClientLayer;
1115
- const addSpec = (config) => Effect3.gen(function* () {
1313
+ const addSpec = (config) => Effect4.gen(function* () {
1116
1314
  const resolved = yield* resolveSpecForInput(config.spec, httpClientLayer);
1117
- const compiled = yield* compileSpec(resolved.specText);
1118
- const explicitBaseUrl = config.baseUrl ?? resolved.baseUrl;
1315
+ const compiled = yield* compileOpenApiSpec(resolved.specText);
1316
+ const explicitBaseUrl = config.baseUrl;
1119
1317
  const needsDerivedBaseUrl = explicitBaseUrl == null;
1120
- const needsDerivedAuth = config.authenticationTemplate == null && resolved.authenticationTemplate == null;
1318
+ const needsDerivedAuth = config.authenticationTemplate == null;
1121
1319
  const preview = needsDerivedBaseUrl || needsDerivedAuth ? yield* previewSpecText(resolved.specText) : void 0;
1122
1320
  const derivedBaseUrl = needsDerivedBaseUrl && preview ? firstBaseUrlForPreview(preview) : void 0;
1123
1321
  const effectiveBaseUrl = explicitBaseUrl ?? (derivedBaseUrl || void 0);
@@ -1131,55 +1329,52 @@ var openApiPlugin = definePlugin((options) => {
1131
1329
  const integrationConfig = {
1132
1330
  specHash,
1133
1331
  ...specInputToSourceUrl(config.spec) !== void 0 ? { sourceUrl: specInputToSourceUrl(config.spec) } : {},
1134
- ...specInputToGoogleBundle(config.spec) !== void 0 ? { googleDiscoveryUrls: specInputToGoogleBundle(config.spec) } : {},
1135
1332
  // baseUrl is an optional override only. The host is otherwise
1136
1333
  // resolved per call from the operation's `servers` (extracted from
1137
1334
  // the spec), so we never bake a derived base URL into the config.
1138
1335
  ...config.baseUrl ? { baseUrl: config.baseUrl } : {},
1139
1336
  ...config.headers ? { headers: config.headers } : {},
1140
1337
  ...config.queryParams ? { queryParams: config.queryParams } : {},
1141
- // Prefer the caller's explicit template; otherwise adopt the one the
1142
- // Google Discovery converter derived from the spec (the bundle add
1143
- // path relies on this — it has no preview to detect auth from);
1144
- // 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.
1145
1340
  ...config.authenticationTemplate ? {
1146
1341
  authenticationTemplate: normalizeOpenApiAuthInputs(config.authenticationTemplate)
1147
- } : resolved.authenticationTemplate ? { authenticationTemplate: resolved.authenticationTemplate } : derivedAuthenticationTemplate && derivedAuthenticationTemplate.length > 0 ? { authenticationTemplate: derivedAuthenticationTemplate } : {}
1342
+ } : derivedAuthenticationTemplate && derivedAuthenticationTemplate.length > 0 ? { authenticationTemplate: derivedAuthenticationTemplate } : {}
1148
1343
  };
1149
1344
  yield* ctx.storage.putSpec(specHash, resolved.specText);
1150
1345
  yield* ctx.transaction(
1151
- Effect3.gen(function* () {
1346
+ Effect4.gen(function* () {
1152
1347
  yield* ctx.core.integrations.register({
1153
1348
  slug,
1154
1349
  name: config.name?.trim() || compiled.title || config.slug,
1155
1350
  description: config.description ?? compiled.description ?? compiled.title ?? config.slug,
1156
1351
  config: integrationConfig,
1157
1352
  canRemove: true,
1158
- canRefresh: specInputToSourceUrl(config.spec) != null || specInputToGoogleBundle(config.spec) != null
1353
+ canRefresh: specInputToSourceUrl(config.spec) != null
1159
1354
  });
1160
1355
  yield* ctx.storage.putOperations(
1161
1356
  config.slug,
1162
- storedOperationsFromCompiled(config.slug, compiled)
1357
+ openApiStoredOperationsFromCompiled(config.slug, compiled)
1163
1358
  );
1164
1359
  })
1165
1360
  );
1166
1361
  return { slug, toolCount: compiled.definitions.length };
1167
1362
  });
1168
- const updateSpec = (rawSlug, input) => Effect3.gen(function* () {
1363
+ const updateSpec = (rawSlug, input) => Effect4.gen(function* () {
1169
1364
  const slug = IntegrationSlug.make(rawSlug);
1170
1365
  const record = yield* ctx.core.integrations.get(slug);
1171
1366
  const current = record ? decodeOpenApiIntegrationConfig(record.config) : null;
1172
1367
  if (!record || !current) {
1173
1368
  return yield* new IntegrationNotFoundError({ slug });
1174
1369
  }
1175
- const specInput = input?.spec ?? (current.googleDiscoveryUrls ? { kind: "googleDiscoveryBundle", urls: current.googleDiscoveryUrls } : current.sourceUrl ? isGoogleDiscoveryUrl(current.sourceUrl) ? { kind: "googleDiscovery", url: current.sourceUrl } : { kind: "url", url: current.sourceUrl } : null);
1370
+ const specInput = input?.spec ?? (current.sourceUrl ? { kind: "url", url: current.sourceUrl } : null);
1176
1371
  if (specInput === null) {
1177
1372
  return yield* new OpenApiParseError({
1178
1373
  message: "This integration's spec was pasted inline and has no source URL to re-fetch. Provide the updated spec content."
1179
1374
  });
1180
1375
  }
1181
1376
  const resolved = yield* resolveSpecForInput(specInput, httpClientLayer);
1182
- const compiled = yield* compileSpec(resolved.specText);
1377
+ const compiled = yield* compileOpenApiSpec(resolved.specText);
1183
1378
  const previousOperations = yield* ctx.storage.listOperations(rawSlug);
1184
1379
  const previousNames = new Set(previousOperations.map((op) => op.toolName));
1185
1380
  const nextNames = new Set(compiled.definitions.map((def) => def.toolPath));
@@ -1188,32 +1383,31 @@ var openApiPlugin = definePlugin((options) => {
1188
1383
  const nextConfig = {
1189
1384
  ...current,
1190
1385
  specHash,
1191
- ...specInputToSourceUrl(specInput) !== void 0 ? { sourceUrl: specInputToSourceUrl(specInput) } : {},
1192
- ...specInputToGoogleBundle(specInput) !== void 0 ? { googleDiscoveryUrls: specInputToGoogleBundle(specInput) } : {}
1386
+ ...specInputToSourceUrl(specInput) !== void 0 ? { sourceUrl: specInputToSourceUrl(specInput) } : {}
1193
1387
  };
1194
1388
  yield* ctx.transaction(
1195
- Effect3.gen(function* () {
1389
+ Effect4.gen(function* () {
1196
1390
  yield* ctx.core.integrations.update(slug, {
1197
1391
  config: nextConfig
1198
1392
  });
1199
1393
  yield* ctx.storage.putOperations(
1200
1394
  rawSlug,
1201
- storedOperationsFromCompiled(rawSlug, compiled)
1395
+ openApiStoredOperationsFromCompiled(rawSlug, compiled)
1202
1396
  );
1203
1397
  })
1204
1398
  );
1205
1399
  const connections = yield* ctx.connections.list({ integration: slug });
1206
- yield* Effect3.forEach(
1400
+ yield* Effect4.forEach(
1207
1401
  connections,
1208
1402
  (connection) => ctx.connections.refresh({
1209
1403
  owner: connection.owner,
1210
1404
  integration: connection.integration,
1211
1405
  name: connection.name
1212
- }).pipe(Effect3.catchTag("ConnectionNotFoundError", () => Effect3.succeed([]))),
1406
+ }).pipe(Effect4.catchTag("ConnectionNotFoundError", () => Effect4.succeed([]))),
1213
1407
  { discard: true }
1214
1408
  ).pipe(
1215
- Effect3.catchTag("IntegrationNotFoundError", () => Effect3.void),
1216
- Effect3.withSpan("openapi.plugin.update_spec.refresh_connections", {
1409
+ Effect4.catchTag("IntegrationNotFoundError", () => Effect4.void),
1410
+ Effect4.withSpan("openapi.plugin.update_spec.refresh_connections", {
1217
1411
  attributes: { "openapi.connection_count": connections.length }
1218
1412
  })
1219
1413
  );
@@ -1224,35 +1418,28 @@ var openApiPlugin = definePlugin((options) => {
1224
1418
  removedTools: [...previousNames].filter((name) => !nextNames.has(name)).sort()
1225
1419
  };
1226
1420
  }).pipe(
1227
- Effect3.withSpan("openapi.plugin.update_spec", {
1421
+ Effect4.withSpan("openapi.plugin.update_spec", {
1228
1422
  attributes: { "openapi.integration.slug": rawSlug }
1229
1423
  })
1230
1424
  );
1231
1425
  return {
1232
- previewSpec: (input) => Effect3.gen(function* () {
1426
+ previewSpec: (input) => Effect4.gen(function* () {
1233
1427
  const previewInput = typeof input === "string" ? { spec: input } : input;
1234
- const specText = isGoogleDiscoveryUrl(previewInput.spec) ? yield* fetchGoogleDiscoveryDocument(previewInput.spec).pipe(
1235
- Effect3.provide(httpClientLayer),
1236
- Effect3.flatMap(
1237
- (documentText) => convertGoogleDiscoveryToOpenApi({
1238
- discoveryUrl: previewInput.spec,
1239
- documentText
1240
- })
1241
- ),
1242
- Effect3.map((conversion) => conversion.specText)
1243
- ) : yield* resolveSpecText(previewInput.spec).pipe(Effect3.provide(httpClientLayer));
1244
- 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);
1245
1432
  }),
1246
1433
  addSpec,
1247
1434
  updateSpec,
1248
1435
  removeSpec: (slug) => ctx.transaction(
1249
- Effect3.gen(function* () {
1436
+ Effect4.gen(function* () {
1250
1437
  yield* ctx.storage.removeOperations(slug);
1251
- yield* ctx.core.integrations.remove(IntegrationSlug.make(slug)).pipe(Effect3.catchTag("IntegrationRemovalNotAllowedError", () => Effect3.void));
1438
+ yield* ctx.core.integrations.remove(IntegrationSlug.make(slug)).pipe(Effect4.catchTag("IntegrationRemovalNotAllowedError", () => Effect4.void));
1252
1439
  })
1253
1440
  ),
1254
1441
  getIntegration: (slug) => ctx.core.integrations.get(IntegrationSlug.make(slug)).pipe(
1255
- Effect3.map(
1442
+ Effect4.map(
1256
1443
  (record) => record ? {
1257
1444
  slug: record.slug,
1258
1445
  description: record.description,
@@ -1263,12 +1450,12 @@ var openApiPlugin = definePlugin((options) => {
1263
1450
  )
1264
1451
  ),
1265
1452
  getConfig: (slug) => ctx.core.integrations.get(IntegrationSlug.make(slug)).pipe(
1266
- Effect3.map(
1453
+ Effect4.map(
1267
1454
  (record) => record ? decodeOpenApiIntegrationConfig(record.config) : null
1268
1455
  )
1269
1456
  ),
1270
1457
  configure: (slug, input) => ctx.transaction(
1271
- Effect3.gen(function* () {
1458
+ Effect4.gen(function* () {
1272
1459
  const record = yield* ctx.core.integrations.get(IntegrationSlug.make(slug));
1273
1460
  if (!record) return [];
1274
1461
  const current = decodeOpenApiIntegrationConfig(record.config);
@@ -1299,17 +1486,17 @@ var openApiPlugin = definePlugin((options) => {
1299
1486
  inputSchema: PreviewSpecInputStandardSchema,
1300
1487
  outputSchema: PreviewSpecOutputStandardSchema,
1301
1488
  execute: (input) => self.previewSpec(input).pipe(
1302
- Effect3.map((preview) => ToolResult.ok(staticPreviewOutput(preview))),
1303
- Effect3.catchTags({
1304
- OpenApiParseError: ({ message }) => Effect3.succeed(openApiToolFailure("openapi_parse_failed", message)),
1305
- OpenApiExtractionError: ({ message }) => Effect3.succeed(openApiToolFailure("openapi_extraction_failed", message)),
1306
- OpenApiOAuthError: ({ message }) => Effect3.succeed(openApiToolFailure("openapi_oauth_failed", 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))
1307
1494
  })
1308
1495
  )
1309
1496
  }),
1310
1497
  tool({
1311
1498
  name: "addSpec",
1312
- 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 \u2014 apiKey header/query, or oauth bearer \u2014 or an empty array for no auth methods).",
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).",
1313
1500
  annotations: {
1314
1501
  requiresApproval: true,
1315
1502
  approvalDescription: "Add an OpenAPI integration"
@@ -1325,17 +1512,17 @@ var openApiPlugin = definePlugin((options) => {
1325
1512
  queryParams: input.queryParams,
1326
1513
  authenticationTemplate: input.authenticationTemplate
1327
1514
  }).pipe(
1328
- Effect3.map(
1329
- (result) => ToolResult.ok({
1515
+ Effect4.map(
1516
+ (result) => ToolResult2.ok({
1330
1517
  slug: String(result.slug),
1331
1518
  toolCount: result.toolCount
1332
1519
  })
1333
1520
  ),
1334
- Effect3.catchTags({
1335
- OpenApiParseError: ({ message }) => Effect3.succeed(openApiToolFailure("openapi_parse_failed", message)),
1336
- OpenApiExtractionError: ({ message }) => Effect3.succeed(openApiToolFailure("openapi_extraction_failed", message)),
1337
- OpenApiOAuthError: ({ message }) => Effect3.succeed(openApiToolFailure("openapi_oauth_failed", message)),
1338
- IntegrationAlreadyExistsError: ({ slug }) => Effect3.succeed(
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(
1339
1526
  openApiToolFailure(
1340
1527
  "integration_already_exists",
1341
1528
  `Integration ${slug} already exists; update it instead of re-adding.`
@@ -1350,173 +1537,50 @@ var openApiPlugin = definePlugin((options) => {
1350
1537
  describeAuthMethods: describeOpenApiAuthMethods,
1351
1538
  describeIntegrationDisplay: describeOpenApiIntegrationDisplay,
1352
1539
  // Produce one tool per spec operation. Spec-derived, identical for every
1353
- // connection on the integration so `getValue` is never called here. The
1540
+ // connection on the integration - so `getValue` is never called here. The
1354
1541
  // operation bindings invokeTool needs are persisted at addSpec time; this
1355
1542
  // hook only shapes the per-connection ToolDefs from the spec blob the
1356
1543
  // catalog config points at.
1357
- resolveTools: ({
1358
- config,
1359
- storage
1360
- }) => Effect3.gen(function* () {
1361
- const openApiConfig = decodeOpenApiIntegrationConfig(config);
1362
- if (!openApiConfig) return { tools: [], definitions: {} };
1363
- const specText = yield* loadSpecText(storage, openApiConfig);
1364
- if (specText == null) return { tools: [], definitions: {} };
1365
- const compiled = yield* compileSpec(specText).pipe(
1366
- Effect3.catch(() => Effect3.succeed(null))
1367
- );
1368
- if (!compiled) return { tools: [], definitions: {} };
1369
- return {
1370
- tools: toolDefsFromCompiled(compiled),
1371
- definitions: compiled.hoistedDefs
1372
- };
1373
- }),
1374
- invokeTool: ({
1375
- ctx: invokeCtx,
1376
- toolRow,
1377
- credential,
1378
- args
1379
- }) => Effect3.gen(function* () {
1544
+ resolveTools: ({ config, storage }) => resolveOpenApiBackedTools({ config, storage }),
1545
+ invokeTool: ({ ctx: invokeCtx, toolRow, credential, args }) => {
1380
1546
  const httpClientLayer = options?.httpClientLayer ?? invokeCtx.httpClientLayer;
1381
- const integration = toolRow.integration;
1382
- const config = decodeOpenApiIntegrationConfig(credential.config);
1383
- let binding = (yield* invokeCtx.storage.getOperation(integration, toolRow.name))?.binding;
1384
- if (!binding && config) {
1385
- const specText = yield* loadSpecText(invokeCtx.storage, config).pipe(
1386
- Effect3.catch(() => Effect3.succeed(null))
1387
- );
1388
- const compiled = specText == null ? null : yield* compileSpec(specText).pipe(Effect3.catch(() => Effect3.succeed(null)));
1389
- binding = compiled ? storedOperationsFromCompiled(integration, compiled).find(
1390
- (op) => op.toolName === toolRow.name
1391
- )?.binding : void 0;
1392
- }
1393
- if (!binding) {
1394
- return yield* new OpenApiExtractionError({
1395
- message: `No OpenAPI operation found for tool "${toolRow.name}" on "${integration}"`
1396
- });
1397
- }
1398
- const headers = { ...config?.headers ?? {} };
1399
- const queryParams = {
1400
- ...config?.queryParams ?? {}
1401
- };
1402
- const template = (config?.authenticationTemplate ?? []).find(
1403
- (entry) => String(entry.slug) === String(credential.template)
1404
- );
1405
- if (template) {
1406
- const missing = requiredTemplateVariables(template).filter((name) => {
1407
- const value = credential.values[name];
1408
- return value == null || value === "";
1409
- });
1410
- if (missing.length > 0) {
1411
- return openApiAuthToolFailure({
1412
- code: template.kind === "oauth2" ? "oauth_connection_missing" : "connection_value_missing",
1413
- message: `Connection "${credential.connection}" for "${integration}" has no resolvable credential value. Re-authenticate or update the connection.`,
1414
- owner: credential.owner,
1415
- integration,
1416
- connection: String(credential.connection),
1417
- credentialKind: template.kind === "oauth2" ? "oauth" : "secret"
1418
- });
1419
- }
1420
- const rendered = renderAuthTemplate(template, credential.values);
1421
- Object.assign(headers, rendered.headers);
1422
- Object.assign(queryParams, rendered.queryParams);
1423
- }
1424
- const result = yield* invokeWithLayer(
1425
- binding,
1426
- args ?? {},
1427
- config?.baseUrl ?? "",
1428
- headers,
1429
- queryParams,
1547
+ return invokeOpenApiBackedTool({
1548
+ ctx: invokeCtx,
1549
+ toolRow,
1550
+ credential,
1551
+ args,
1430
1552
  httpClientLayer
1431
- );
1432
- const ok = result.status >= 200 && result.status < 300;
1433
- if (!ok) {
1434
- if (result.status === 401 || result.status === 403) {
1435
- return openApiAuthToolFailure({
1436
- code: "connection_rejected",
1437
- status: result.status,
1438
- message: `Upstream rejected credentials for "${integration}" with HTTP ${result.status}. Re-authenticate or update the connection "${credential.connection}" before retrying this tool.`,
1439
- owner: credential.owner,
1440
- integration,
1441
- connection: String(credential.connection),
1442
- credentialKind: "upstream",
1443
- credentialLabel: "Upstream authorization",
1444
- details: result.error
1445
- });
1446
- }
1447
- return ToolResult.fail({
1448
- code: "upstream_http_error",
1449
- status: result.status,
1450
- message: extractUpstreamMessage(result.error, result.status),
1451
- details: result.error
1452
- });
1453
- }
1454
- return ToolResult.ok(result.data, {
1455
- http: { status: result.status, headers: result.headers }
1456
1553
  });
1457
- }),
1458
- resolveAnnotations: ({
1554
+ },
1555
+ resolveAnnotations: ({ ctx: annotationsCtx, integration, toolRows }) => resolveOpenApiBackedAnnotations({
1459
1556
  ctx: annotationsCtx,
1460
- integration,
1557
+ integration: String(integration),
1461
1558
  toolRows
1462
- }) => Effect3.gen(function* () {
1463
- const ops = yield* annotationsCtx.storage.listOperations(String(integration));
1464
- const byName = /* @__PURE__ */ new Map();
1465
- for (const op of ops) byName.set(op.toolName, op.binding);
1466
- const out = {};
1467
- for (const row of toolRows) {
1468
- const binding = byName.get(row.name);
1469
- if (binding) {
1470
- out[row.name] = annotationsForOperation(binding.method, binding.pathTemplate);
1471
- }
1472
- }
1473
- return out;
1474
1559
  }),
1475
- removeConnection: () => Effect3.void,
1560
+ removeConnection: () => Effect4.void,
1476
1561
  detect: ({
1477
1562
  ctx: detectCtx,
1478
1563
  url
1479
- }) => Effect3.gen(function* () {
1564
+ }) => Effect4.gen(function* () {
1480
1565
  const httpClientLayer = options?.httpClientLayer ?? detectCtx.httpClientLayer;
1481
1566
  const trimmed = url.trim();
1482
1567
  if (!trimmed) return null;
1483
- const parsed = yield* Effect3.try({
1568
+ const parsed = yield* Effect4.try({
1484
1569
  try: () => new URL(trimmed),
1485
1570
  catch: (error) => error
1486
- }).pipe(Effect3.option);
1487
- if (Option5.isNone(parsed)) return null;
1488
- if (isGoogleDiscoveryUrl(trimmed)) {
1489
- const conversion = yield* fetchGoogleDiscoveryDocument(trimmed).pipe(
1490
- Effect3.provide(httpClientLayer),
1491
- Effect3.flatMap(
1492
- (documentText) => convertGoogleDiscoveryToOpenApi({
1493
- discoveryUrl: trimmed,
1494
- documentText
1495
- })
1496
- ),
1497
- Effect3.catch(() => Effect3.succeed(null))
1498
- );
1499
- if (conversion) {
1500
- return IntegrationDetectionResult.make({
1501
- kind: "openapi",
1502
- confidence: "high",
1503
- endpoint: trimmed,
1504
- name: conversion.title,
1505
- slug: conversion.title.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "") || `google_${conversion.service}`
1506
- });
1507
- }
1508
- }
1571
+ }).pipe(Effect4.option);
1572
+ if (Option6.isNone(parsed)) return null;
1509
1573
  const specText = yield* resolveSpecText(trimmed).pipe(
1510
- Effect3.provide(httpClientLayer),
1511
- Effect3.catch(() => Effect3.succeed(null))
1574
+ Effect4.provide(httpClientLayer),
1575
+ Effect4.catch(() => Effect4.succeed(null))
1512
1576
  );
1513
1577
  if (specText === null) return null;
1514
- const doc = yield* parse(specText).pipe(Effect3.catch(() => Effect3.succeed(null)));
1578
+ const doc = yield* parse(specText).pipe(Effect4.catch(() => Effect4.succeed(null)));
1515
1579
  if (!doc) return null;
1516
- const result = yield* extract(doc).pipe(Effect3.catch(() => Effect3.succeed(null)));
1580
+ const result = yield* extract(doc).pipe(Effect4.catch(() => Effect4.succeed(null)));
1517
1581
  if (!result) return null;
1518
- const slug = Option5.getOrElse(result.title, () => "api").toLowerCase().replace(/[^a-z0-9]+/g, "_");
1519
- const name = Option5.getOrElse(result.title, () => slug);
1582
+ const slug = Option6.getOrElse(result.title, () => "api").toLowerCase().replace(/[^a-z0-9]+/g, "_");
1583
+ const name = Option6.getOrElse(result.title, () => slug);
1520
1584
  return IntegrationDetectionResult.make({
1521
1585
  kind: "openapi",
1522
1586
  confidence: "high",
@@ -1533,10 +1597,20 @@ export {
1533
1597
  OpenApiIntegrationConfigSchema,
1534
1598
  decodeOpenApiIntegrationConfig,
1535
1599
  renderAuthTemplate,
1600
+ makeDefaultOpenapiStore,
1536
1601
  invoke,
1537
1602
  invokeWithLayer,
1538
1603
  annotationsForOperation,
1539
- makeDefaultOpenapiStore,
1604
+ extractOpenApiUpstreamMessage,
1605
+ normalizeOpenApiRefs,
1606
+ compileOpenApiDocument,
1607
+ compileOpenApiSpec,
1608
+ openApiToolDefsFromCompiled,
1609
+ openApiStoredOperationsFromCompiled,
1610
+ loadOpenApiSpecText,
1611
+ resolveOpenApiBackedTools,
1612
+ invokeOpenApiBackedTool,
1613
+ resolveOpenApiBackedAnnotations,
1540
1614
  openApiPlugin
1541
1615
  };
1542
- //# sourceMappingURL=chunk-PNOEE3ET.js.map
1616
+ //# sourceMappingURL=chunk-3FM2SWM4.js.map