@executor-js/plugin-openapi 0.1.0 → 0.2.1

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 (38) hide show
  1. package/dist/AddOpenApiSource-EV3NJHLA.js +19 -0
  2. package/dist/AddOpenApiSource-EV3NJHLA.js.map +1 -0
  3. package/dist/EditOpenApiSource-J7NXCVT5.js +665 -0
  4. package/dist/EditOpenApiSource-J7NXCVT5.js.map +1 -0
  5. package/dist/OpenApiSourceSummary-K5WZD5NR.js +122 -0
  6. package/dist/OpenApiSourceSummary-K5WZD5NR.js.map +1 -0
  7. package/dist/api/group.d.ts +79 -10
  8. package/dist/api/index.d.ts +384 -0
  9. package/dist/chunk-2BXVRXGL.js +1345 -0
  10. package/dist/chunk-2BXVRXGL.js.map +1 -0
  11. package/dist/chunk-E4QUTDQ2.js +1120 -0
  12. package/dist/chunk-E4QUTDQ2.js.map +1 -0
  13. package/dist/chunk-LBTK5F65.js +216 -0
  14. package/dist/chunk-LBTK5F65.js.map +1 -0
  15. package/dist/chunk-TRD7KSKA.js +1444 -0
  16. package/dist/chunk-TRD7KSKA.js.map +1 -0
  17. package/dist/client.js +165 -0
  18. package/dist/client.js.map +1 -0
  19. package/dist/core.js +8 -10
  20. package/dist/index.js +2 -1
  21. package/dist/react/AddOpenApiSource.d.ts +1 -1
  22. package/dist/react/OpenApiSourceDetailsFields.d.ts +18 -0
  23. package/dist/react/atoms.d.ts +158 -13
  24. package/dist/react/client.d.ts +84 -15
  25. package/dist/sdk/index.d.ts +1 -1
  26. package/dist/sdk/openapi-utils.d.ts +4 -3
  27. package/dist/sdk/parse.d.ts +1 -1
  28. package/dist/sdk/parse.test.d.ts +1 -0
  29. package/dist/sdk/plugin.d.ts +136 -125
  30. package/dist/sdk/store.d.ts +132 -47
  31. package/dist/sdk/types.d.ts +19 -44
  32. package/dist/sdk/usage-scope-isolation.test.d.ts +1 -0
  33. package/dist/testing/index.d.ts +34 -0
  34. package/dist/testing.js +56 -0
  35. package/dist/testing.js.map +1 -0
  36. package/package.json +16 -4
  37. package/dist/chunk-RBE3CVB4.js +0 -2837
  38. package/dist/chunk-RBE3CVB4.js.map +0 -1
@@ -0,0 +1,1345 @@
1
+ // src/sdk/errors.ts
2
+ import { Data, Schema } from "effect";
3
+ var OpenApiParseError = class extends Schema.TaggedErrorClass()(
4
+ "OpenApiParseError",
5
+ {
6
+ message: Schema.String
7
+ },
8
+ { httpApiStatus: 400 }
9
+ ) {
10
+ };
11
+ var OpenApiExtractionError = class extends Schema.TaggedErrorClass()(
12
+ "OpenApiExtractionError",
13
+ {
14
+ message: Schema.String
15
+ },
16
+ { httpApiStatus: 400 }
17
+ ) {
18
+ };
19
+ var OpenApiInvocationError = class extends Data.TaggedError("OpenApiInvocationError") {
20
+ };
21
+ var OpenApiOAuthError = class extends Schema.TaggedErrorClass()(
22
+ "OpenApiOAuthError",
23
+ {
24
+ message: Schema.String
25
+ },
26
+ { httpApiStatus: 400 }
27
+ ) {
28
+ };
29
+
30
+ // src/sdk/parse.ts
31
+ import { Duration, Effect, Schema as Schema2 } from "effect";
32
+ import { HttpClient, HttpClientRequest } from "effect/unstable/http";
33
+ import YAML from "yaml";
34
+ var OpenApiExtractionErrorFromParse = class extends OpenApiExtractionError {
35
+ };
36
+ var fetchSpecText = Effect.fn("OpenApi.fetchSpecText")(function* (url, credentials) {
37
+ const client = yield* HttpClient.HttpClient;
38
+ const requestUrl = new URL(url);
39
+ for (const [name, value] of Object.entries(credentials?.queryParams ?? {})) {
40
+ requestUrl.searchParams.set(name, value);
41
+ }
42
+ let request = HttpClientRequest.get(requestUrl.toString()).pipe(
43
+ HttpClientRequest.setHeader("Accept", "application/json, application/yaml, text/yaml, */*")
44
+ );
45
+ for (const [name, value] of Object.entries(credentials?.headers ?? {})) {
46
+ request = HttpClientRequest.setHeader(request, name, value);
47
+ }
48
+ const response = yield* client.execute(request).pipe(
49
+ Effect.timeout(Duration.seconds(60)),
50
+ Effect.mapError(
51
+ (_cause) => new OpenApiParseError({
52
+ message: "Failed to fetch OpenAPI document"
53
+ })
54
+ )
55
+ );
56
+ if (response.status < 200 || response.status >= 300) {
57
+ return yield* new OpenApiParseError({
58
+ message: `Failed to fetch OpenAPI document: HTTP ${response.status}`
59
+ });
60
+ }
61
+ return yield* response.text.pipe(
62
+ Effect.mapError(
63
+ (_cause) => new OpenApiParseError({
64
+ message: "Failed to read OpenAPI document body"
65
+ })
66
+ )
67
+ );
68
+ });
69
+ var resolveSpecText = (input, credentials) => input.startsWith("http://") || input.startsWith("https://") ? fetchSpecText(input, credentials) : Effect.succeed(input);
70
+ var parse = Effect.fn("OpenApi.parse")(function* (text) {
71
+ const api = yield* parseTextToObject(text);
72
+ if (!isOpenApi3(api)) {
73
+ return yield* new OpenApiExtractionErrorFromParse({
74
+ message: "Only OpenAPI 3.x documents are supported. Swagger 2.x documents should be converted first."
75
+ });
76
+ }
77
+ return api;
78
+ });
79
+ var isOpenApi3 = (doc) => "openapi" in doc && typeof doc.openapi === "string" && doc.openapi.startsWith("3.");
80
+ var parseTextToObject = (text) => Effect.gen(function* () {
81
+ const trimmed = text.trim();
82
+ if (trimmed.length === 0) {
83
+ return yield* new OpenApiParseError({
84
+ message: "OpenAPI document is empty"
85
+ });
86
+ }
87
+ const parsed = yield* parseJsonLike(trimmed).pipe(
88
+ Effect.mapError(
89
+ () => new OpenApiParseError({
90
+ message: "Failed to parse OpenAPI document"
91
+ })
92
+ )
93
+ );
94
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
95
+ return yield* new OpenApiParseError({
96
+ message: "OpenAPI document must parse to an object"
97
+ });
98
+ }
99
+ return parsed;
100
+ });
101
+ var parseJsonText = Schema2.decodeUnknownEffect(Schema2.fromJsonString(Schema2.Unknown));
102
+ var parseJsonLike = (text) => {
103
+ const parseYaml = Effect.try({
104
+ try: () => YAML.parse(text),
105
+ catch: () => "YamlParseFailed"
106
+ });
107
+ if (!text.startsWith("{") && !text.startsWith("[")) return parseYaml;
108
+ return parseJsonText(text).pipe(Effect.catch(() => parseYaml));
109
+ };
110
+
111
+ // src/sdk/openapi-utils.ts
112
+ import { Option } from "effect";
113
+ var DocResolver = class {
114
+ constructor(doc) {
115
+ this.doc = doc;
116
+ }
117
+ doc;
118
+ /** Resolve a value that might be a $ref, returning the resolved object */
119
+ resolve(value) {
120
+ if (isRef(value)) {
121
+ const resolved = this.resolvePointer(value.$ref);
122
+ return resolved;
123
+ }
124
+ return value;
125
+ }
126
+ resolvePointer(ref) {
127
+ if (!ref.startsWith("#/")) return null;
128
+ const segments = ref.slice(2).split("/");
129
+ let current = this.doc;
130
+ for (const segment of segments) {
131
+ if (typeof current !== "object" || current === null) return null;
132
+ current = current[segment];
133
+ }
134
+ return current;
135
+ }
136
+ };
137
+ var isRef = (value) => typeof value === "object" && value !== null && "$ref" in value;
138
+ var substituteUrlVariables = (url, values) => {
139
+ let out = url;
140
+ for (const [name, value] of Object.entries(values)) {
141
+ out = out.replaceAll(`{${name}}`, value);
142
+ }
143
+ return out;
144
+ };
145
+ var OPENAPI_MAX_SERVER_VARIABLE_OPTIONS = 64;
146
+ var expandServerUrlOptions = (server, limit = OPENAPI_MAX_SERVER_VARIABLE_OPTIONS) => {
147
+ if (!Option.isSome(server.variables)) return [server.url];
148
+ let urls = [server.url];
149
+ for (const [name, variable] of Object.entries(server.variables.value)) {
150
+ const enumValues = typeof variable === "string" ? [] : Option.getOrElse(variable.enum, () => []);
151
+ const values = enumValues.length > 0 ? enumValues : [typeof variable === "string" ? variable : variable.default];
152
+ const next = [];
153
+ for (const url of urls) {
154
+ for (const value of values) {
155
+ next.push(url.replaceAll(`{${name}}`, value));
156
+ if (next.length >= limit) return next;
157
+ }
158
+ }
159
+ urls = next;
160
+ }
161
+ return urls;
162
+ };
163
+ var resolveBaseUrl = (servers) => {
164
+ const server = servers[0];
165
+ if (!server) return "";
166
+ if (!Option.isSome(server.variables)) return server.url;
167
+ const values = {};
168
+ for (const [name, v] of Object.entries(server.variables.value)) {
169
+ values[name] = typeof v === "string" ? v : v.default;
170
+ }
171
+ return substituteUrlVariables(server.url, values);
172
+ };
173
+ var declaredContents = (content) => {
174
+ if (!content) return [];
175
+ return Object.entries(content).map(([mediaType, media]) => ({ mediaType, media }));
176
+ };
177
+ var preferredContent = (content) => {
178
+ const first = declaredContents(content)[0];
179
+ return first ? first : void 0;
180
+ };
181
+ var preferredResponseContent = (content) => {
182
+ if (!content) return void 0;
183
+ const entries = Object.entries(content);
184
+ const pick = entries.find(([mt]) => mt === "application/json") ?? entries.find(([mt]) => mt.toLowerCase().includes("+json")) ?? entries.find(([mt]) => mt.toLowerCase().includes("json")) ?? entries[0];
185
+ return pick ? { mediaType: pick[0], media: pick[1] } : void 0;
186
+ };
187
+
188
+ // src/sdk/types.ts
189
+ import { Schema as Schema3 } from "effect";
190
+ import {
191
+ ConnectionId,
192
+ ScopeId,
193
+ ScopedSecretCredentialInput,
194
+ SecretBackedValue,
195
+ SecretId
196
+ } from "@executor-js/sdk/core";
197
+ var OperationId = Schema3.String.pipe(Schema3.brand("OperationId"));
198
+ var HttpMethod = Schema3.Literals([
199
+ "get",
200
+ "put",
201
+ "post",
202
+ "delete",
203
+ "patch",
204
+ "head",
205
+ "options",
206
+ "trace"
207
+ ]);
208
+ var ParameterLocation = Schema3.Literals(["path", "query", "header", "cookie"]);
209
+ var OperationParameter = class extends Schema3.Class("OperationParameter")({
210
+ name: Schema3.String,
211
+ location: ParameterLocation,
212
+ required: Schema3.Boolean,
213
+ schema: Schema3.OptionFromOptional(Schema3.Unknown),
214
+ style: Schema3.OptionFromOptional(Schema3.String),
215
+ explode: Schema3.OptionFromOptional(Schema3.Boolean),
216
+ allowReserved: Schema3.OptionFromOptional(Schema3.Boolean),
217
+ description: Schema3.OptionFromOptional(Schema3.String)
218
+ }) {
219
+ };
220
+ var EncodingObject = class extends Schema3.Class("EncodingObject")({
221
+ contentType: Schema3.OptionFromOptional(Schema3.String),
222
+ style: Schema3.OptionFromOptional(Schema3.String),
223
+ explode: Schema3.OptionFromOptional(Schema3.Boolean),
224
+ allowReserved: Schema3.OptionFromOptional(Schema3.Boolean)
225
+ }) {
226
+ };
227
+ var MediaBinding = class extends Schema3.Class("MediaBinding")({
228
+ contentType: Schema3.String,
229
+ schema: Schema3.OptionFromOptional(Schema3.Unknown),
230
+ encoding: Schema3.OptionFromOptional(Schema3.Record(Schema3.String, EncodingObject))
231
+ }) {
232
+ };
233
+ var OperationRequestBody = class extends Schema3.Class(
234
+ "OperationRequestBody"
235
+ )({
236
+ required: Schema3.Boolean,
237
+ /** Default media type — first declared in spec order (not JSON-first).
238
+ * Used when the caller does not override via the tool's `contentType` arg. */
239
+ contentType: Schema3.String,
240
+ /** Schema of the default media type. Kept for backward compat with stored
241
+ * bindings from before `contents` was added. */
242
+ schema: Schema3.OptionFromOptional(Schema3.Unknown),
243
+ /** All declared media types in spec order. Populated by `extract.ts`
244
+ * going forward; older persisted bindings may have this unset and will
245
+ * fall back to `{contentType, schema}`. */
246
+ contents: Schema3.OptionFromOptional(Schema3.Array(MediaBinding))
247
+ }) {
248
+ };
249
+ var ExtractedOperation = class extends Schema3.Class("ExtractedOperation")({
250
+ operationId: OperationId,
251
+ method: HttpMethod,
252
+ pathTemplate: Schema3.String,
253
+ summary: Schema3.OptionFromOptional(Schema3.String),
254
+ description: Schema3.OptionFromOptional(Schema3.String),
255
+ tags: Schema3.Array(Schema3.String),
256
+ parameters: Schema3.Array(OperationParameter),
257
+ requestBody: Schema3.OptionFromOptional(OperationRequestBody),
258
+ inputSchema: Schema3.OptionFromOptional(Schema3.Unknown),
259
+ outputSchema: Schema3.OptionFromOptional(Schema3.Unknown),
260
+ deprecated: Schema3.Boolean
261
+ }) {
262
+ };
263
+ var ServerVariable = class extends Schema3.Class("ServerVariable")({
264
+ default: Schema3.String,
265
+ enum: Schema3.OptionFromOptional(Schema3.Array(Schema3.String)),
266
+ description: Schema3.OptionFromOptional(Schema3.String)
267
+ }) {
268
+ };
269
+ var ServerInfo = class extends Schema3.Class("ServerInfo")({
270
+ url: Schema3.String,
271
+ description: Schema3.OptionFromOptional(Schema3.String),
272
+ variables: Schema3.OptionFromOptional(Schema3.Record(Schema3.String, ServerVariable))
273
+ }) {
274
+ };
275
+ var ExtractionResult = class extends Schema3.Class("ExtractionResult")({
276
+ title: Schema3.OptionFromOptional(Schema3.String),
277
+ version: Schema3.OptionFromOptional(Schema3.String),
278
+ servers: Schema3.Array(ServerInfo),
279
+ operations: Schema3.Array(ExtractedOperation)
280
+ }) {
281
+ };
282
+ var OperationBinding = class extends Schema3.Class("OperationBinding")({
283
+ method: HttpMethod,
284
+ pathTemplate: Schema3.String,
285
+ parameters: Schema3.Array(OperationParameter),
286
+ requestBody: Schema3.OptionFromOptional(OperationRequestBody)
287
+ }) {
288
+ };
289
+ var HeaderValue = SecretBackedValue;
290
+ var ConfiguredHeaderBinding = class extends Schema3.Class(
291
+ "OpenApiConfiguredHeaderBinding"
292
+ )({
293
+ kind: Schema3.Literal("binding"),
294
+ slot: Schema3.String,
295
+ prefix: Schema3.optional(Schema3.String)
296
+ }) {
297
+ };
298
+ var ConfiguredHeaderValue = Schema3.Union([Schema3.String, ConfiguredHeaderBinding]);
299
+ var OpenApiCredentialInput = Schema3.Union([
300
+ ScopedSecretCredentialInput,
301
+ HeaderValue,
302
+ ConfiguredHeaderValue
303
+ ]);
304
+ var OpenApiSourceBindingValue = Schema3.Union([
305
+ Schema3.Struct({
306
+ kind: Schema3.Literal("secret"),
307
+ secretId: SecretId,
308
+ secretScopeId: Schema3.optional(ScopeId)
309
+ }),
310
+ Schema3.Struct({
311
+ kind: Schema3.Literal("connection"),
312
+ connectionId: ConnectionId
313
+ }),
314
+ Schema3.Struct({
315
+ kind: Schema3.Literal("text"),
316
+ text: Schema3.String
317
+ })
318
+ ]);
319
+ var OpenApiSourceBindingInputSchema = Schema3.Struct({
320
+ sourceId: Schema3.String,
321
+ sourceScope: ScopeId,
322
+ scope: ScopeId,
323
+ slot: Schema3.String,
324
+ value: OpenApiSourceBindingValue
325
+ });
326
+ var OpenApiSourceBindingInput = class extends Schema3.Class(
327
+ "OpenApiSourceBindingInput"
328
+ )(OpenApiSourceBindingInputSchema.fields) {
329
+ };
330
+ var OpenApiSourceBindingRef = class extends Schema3.Class(
331
+ "OpenApiSourceBindingRef"
332
+ )({
333
+ sourceId: Schema3.String,
334
+ sourceScopeId: ScopeId,
335
+ scopeId: ScopeId,
336
+ slot: Schema3.String,
337
+ value: OpenApiSourceBindingValue,
338
+ createdAt: Schema3.Date,
339
+ updatedAt: Schema3.Date
340
+ }) {
341
+ };
342
+ var OAuth2Flow = Schema3.Literals(["authorizationCode", "clientCredentials"]);
343
+ var OAuth2SourceConfigSchema = Schema3.Struct({
344
+ kind: Schema3.Literal("oauth2"),
345
+ securitySchemeName: Schema3.String,
346
+ flow: OAuth2Flow,
347
+ tokenUrl: Schema3.String,
348
+ authorizationUrl: Schema3.NullOr(Schema3.String),
349
+ issuerUrl: Schema3.optional(Schema3.NullOr(Schema3.String)),
350
+ clientIdSlot: Schema3.String,
351
+ clientSecretSlot: Schema3.NullOr(Schema3.String),
352
+ connectionSlot: Schema3.String,
353
+ scopes: Schema3.Array(Schema3.String)
354
+ });
355
+ var OAuth2SourceConfig = class extends Schema3.Class(
356
+ "OpenApiOAuth2SourceConfig"
357
+ )(OAuth2SourceConfigSchema.fields) {
358
+ };
359
+ var InvocationResult = class extends Schema3.Class("InvocationResult")({
360
+ status: Schema3.Number,
361
+ headers: Schema3.Record(Schema3.String, Schema3.String),
362
+ data: Schema3.NullOr(Schema3.Unknown),
363
+ error: Schema3.NullOr(Schema3.Unknown)
364
+ }) {
365
+ };
366
+
367
+ // src/sdk/extract.ts
368
+ import { Effect as Effect2, Option as Option2 } from "effect";
369
+ var HTTP_METHODS = [
370
+ "get",
371
+ "put",
372
+ "post",
373
+ "delete",
374
+ "patch",
375
+ "head",
376
+ "options",
377
+ "trace"
378
+ ];
379
+ var VALID_PARAM_LOCATIONS = /* @__PURE__ */ new Set(["path", "query", "header", "cookie"]);
380
+ var extractParameters = (pathItem, operation, r) => {
381
+ const merged = /* @__PURE__ */ new Map();
382
+ for (const raw of pathItem.parameters ?? []) {
383
+ const p = r.resolve(raw);
384
+ if (!p) continue;
385
+ merged.set(`${p.in}:${p.name}`, p);
386
+ }
387
+ for (const raw of operation.parameters ?? []) {
388
+ const p = r.resolve(raw);
389
+ if (!p) continue;
390
+ merged.set(`${p.in}:${p.name}`, p);
391
+ }
392
+ return [...merged.values()].filter((p) => VALID_PARAM_LOCATIONS.has(p.in)).map(
393
+ (p) => new OperationParameter({
394
+ name: p.name,
395
+ location: p.in,
396
+ required: p.in === "path" ? true : p.required === true,
397
+ schema: Option2.fromNullishOr(p.schema),
398
+ style: Option2.fromNullishOr(p.style),
399
+ explode: Option2.fromNullishOr(p.explode),
400
+ allowReserved: Option2.fromNullishOr("allowReserved" in p ? p.allowReserved : void 0),
401
+ description: Option2.fromNullishOr(p.description)
402
+ })
403
+ );
404
+ };
405
+ var buildEncodingRecord = (encoding) => {
406
+ if (!encoding) return void 0;
407
+ const out = {};
408
+ for (const [prop, raw] of Object.entries(encoding)) {
409
+ if (typeof raw !== "object" || raw === null) continue;
410
+ const e = raw;
411
+ out[prop] = new EncodingObject({
412
+ contentType: Option2.fromNullishOr(e.contentType),
413
+ style: Option2.fromNullishOr(e.style),
414
+ explode: Option2.fromNullishOr(e.explode),
415
+ allowReserved: Option2.fromNullishOr(e.allowReserved)
416
+ });
417
+ }
418
+ return Object.keys(out).length > 0 ? out : void 0;
419
+ };
420
+ var extractRequestBody = (operation, r) => {
421
+ if (!operation.requestBody) return void 0;
422
+ const body = r.resolve(operation.requestBody);
423
+ if (!body) return void 0;
424
+ const contents = declaredContents(body.content).map(
425
+ ({ mediaType, media }) => new MediaBinding({
426
+ contentType: mediaType,
427
+ schema: Option2.fromNullishOr(media.schema),
428
+ encoding: Option2.fromNullishOr(
429
+ buildEncodingRecord(media.encoding)
430
+ )
431
+ })
432
+ );
433
+ if (contents.length === 0) return void 0;
434
+ const defaultContent = contents[0];
435
+ return new OperationRequestBody({
436
+ required: body.required === true,
437
+ contentType: defaultContent.contentType,
438
+ schema: defaultContent.schema,
439
+ contents: Option2.some(contents)
440
+ });
441
+ };
442
+ var extractOutputSchema = (operation, r) => {
443
+ if (!operation.responses) return void 0;
444
+ const entries = Object.entries(operation.responses);
445
+ const preferred = [
446
+ ...entries.filter(([s]) => /^2\d\d$/.test(s)).sort(([a], [b]) => a.localeCompare(b)),
447
+ ...entries.filter(([s]) => s === "default")
448
+ ];
449
+ for (const [, ref] of preferred) {
450
+ const resp = r.resolve(ref);
451
+ if (!resp) continue;
452
+ const content = preferredResponseContent(resp.content);
453
+ if (content?.media.schema) return content.media.schema;
454
+ }
455
+ return void 0;
456
+ };
457
+ var buildInputSchema = (parameters, requestBody) => {
458
+ const properties = {};
459
+ const required = [];
460
+ for (const param of parameters) {
461
+ properties[param.name] = Option2.getOrElse(param.schema, () => ({ type: "string" }));
462
+ if (param.required) required.push(param.name);
463
+ }
464
+ if (requestBody) {
465
+ properties.body = Option2.getOrElse(requestBody.schema, () => ({ type: "object" }));
466
+ if (requestBody.required) required.push("body");
467
+ const contents = Option2.getOrUndefined(requestBody.contents);
468
+ if (contents && contents.length > 1) {
469
+ properties.contentType = {
470
+ type: "string",
471
+ enum: contents.map((c) => c.contentType),
472
+ default: requestBody.contentType,
473
+ description: "Content-Type for the request body. Declared media types for this operation, in spec order."
474
+ };
475
+ }
476
+ }
477
+ if (Object.keys(properties).length === 0) return void 0;
478
+ return {
479
+ type: "object",
480
+ properties,
481
+ ...required.length > 0 ? { required } : {},
482
+ additionalProperties: false
483
+ };
484
+ };
485
+ var deriveOperationId = (method, pathTemplate, operation) => operation.operationId ?? (`${method}_${pathTemplate.replace(/[^a-zA-Z0-9]+/g, "_")}`.replace(/^_+|_+$/g, "") || `${method}_operation`);
486
+ var extractServers = (doc) => (doc.servers ?? []).flatMap((server) => {
487
+ if (!server.url) return [];
488
+ const vars = server.variables ? Object.fromEntries(
489
+ Object.entries(server.variables).flatMap(([name, v]) => {
490
+ if (v.default === void 0 || v.default === null) return [];
491
+ const enumValues = Array.isArray(v.enum) ? v.enum.filter((x) => typeof x === "string") : void 0;
492
+ return [
493
+ [
494
+ name,
495
+ new ServerVariable({
496
+ default: String(v.default),
497
+ enum: enumValues && enumValues.length > 0 ? Option2.some(enumValues) : Option2.none(),
498
+ description: Option2.fromNullishOr(v.description)
499
+ })
500
+ ]
501
+ ];
502
+ })
503
+ ) : void 0;
504
+ return [
505
+ new ServerInfo({
506
+ url: server.url,
507
+ description: Option2.fromNullishOr(server.description),
508
+ variables: vars && Object.keys(vars).length > 0 ? Option2.some(vars) : Option2.none()
509
+ })
510
+ ];
511
+ });
512
+ var extract = Effect2.fn("OpenApi.extract")(function* (doc) {
513
+ const paths = doc.paths;
514
+ if (!paths) {
515
+ return yield* new OpenApiExtractionError({
516
+ message: "OpenAPI document has no paths defined"
517
+ });
518
+ }
519
+ const r = new DocResolver(doc);
520
+ const operations = [];
521
+ for (const [pathTemplate, pathItem] of Object.entries(paths).sort(
522
+ ([a], [b]) => a.localeCompare(b)
523
+ )) {
524
+ if (!pathItem) continue;
525
+ for (const method of HTTP_METHODS) {
526
+ const operation = pathItem[method];
527
+ if (!operation) continue;
528
+ const parameters = extractParameters(pathItem, operation, r);
529
+ const requestBody = extractRequestBody(operation, r);
530
+ const inputSchema = buildInputSchema(parameters, requestBody);
531
+ const outputSchema = extractOutputSchema(operation, r);
532
+ const tags = (operation.tags ?? []).filter((t) => t.trim().length > 0);
533
+ operations.push(
534
+ new ExtractedOperation({
535
+ operationId: OperationId.make(deriveOperationId(method, pathTemplate, operation)),
536
+ method,
537
+ pathTemplate,
538
+ summary: Option2.fromNullishOr(operation.summary),
539
+ description: Option2.fromNullishOr(operation.description),
540
+ tags,
541
+ parameters,
542
+ requestBody: Option2.fromNullishOr(requestBody),
543
+ inputSchema: Option2.fromNullishOr(inputSchema),
544
+ outputSchema: Option2.fromNullishOr(outputSchema),
545
+ deprecated: operation.deprecated === true
546
+ })
547
+ );
548
+ }
549
+ }
550
+ return new ExtractionResult({
551
+ title: Option2.fromNullishOr(doc.info?.title),
552
+ version: Option2.fromNullishOr(doc.info?.version),
553
+ servers: extractServers(doc),
554
+ operations
555
+ });
556
+ });
557
+
558
+ // src/sdk/preview.ts
559
+ import { Effect as Effect3, Option as Option3 } from "effect";
560
+ import { Schema as Schema4 } from "effect";
561
+ var OAuth2Scopes = Schema4.Record(Schema4.String, Schema4.String);
562
+ var SecuritySchemeType = Schema4.Literals(["http", "apiKey", "oauth2", "openIdConnect"]);
563
+ var decodeSecuritySchemeType = Schema4.decodeUnknownOption(SecuritySchemeType);
564
+ var OAuth2AuthorizationCodeFlow = class extends Schema4.Class(
565
+ "OAuth2AuthorizationCodeFlow"
566
+ )({
567
+ authorizationUrl: Schema4.String,
568
+ tokenUrl: Schema4.String,
569
+ refreshUrl: Schema4.OptionFromOptional(Schema4.String),
570
+ scopes: OAuth2Scopes
571
+ }) {
572
+ };
573
+ var OAuth2ClientCredentialsFlow = class extends Schema4.Class(
574
+ "OAuth2ClientCredentialsFlow"
575
+ )({
576
+ tokenUrl: Schema4.String,
577
+ refreshUrl: Schema4.OptionFromOptional(Schema4.String),
578
+ scopes: OAuth2Scopes
579
+ }) {
580
+ };
581
+ var OAuth2Flows = class extends Schema4.Class("OAuth2Flows")({
582
+ authorizationCode: Schema4.OptionFromOptional(OAuth2AuthorizationCodeFlow),
583
+ clientCredentials: Schema4.OptionFromOptional(OAuth2ClientCredentialsFlow)
584
+ }) {
585
+ };
586
+ var SecurityScheme = class extends Schema4.Class("SecurityScheme")({
587
+ /** Key name in components.securitySchemes (e.g. "api_token") */
588
+ name: Schema4.String,
589
+ /** OpenAPI security scheme type */
590
+ type: SecuritySchemeType,
591
+ /** For type: "http" — e.g. "bearer", "basic" */
592
+ scheme: Schema4.OptionFromOptional(Schema4.String),
593
+ /** For type: "http" with scheme "bearer" — e.g. "JWT" */
594
+ bearerFormat: Schema4.OptionFromOptional(Schema4.String),
595
+ /** For type: "apiKey" — where the key goes */
596
+ in: Schema4.OptionFromOptional(Schema4.Literals(["header", "query", "cookie"])),
597
+ /** For type: "apiKey" — the header/query/cookie name */
598
+ headerName: Schema4.OptionFromOptional(Schema4.String),
599
+ description: Schema4.OptionFromOptional(Schema4.String),
600
+ /** For type: "oauth2" — declared flows (authorizationCode / clientCredentials only; implicit and password are deprecated). */
601
+ flows: Schema4.OptionFromOptional(OAuth2Flows),
602
+ /** For type: "openIdConnect" — the discovery URL. */
603
+ openIdConnectUrl: Schema4.OptionFromOptional(Schema4.String)
604
+ }) {
605
+ };
606
+ var AuthStrategy = class extends Schema4.Class("AuthStrategy")({
607
+ /** The security schemes required together for this strategy */
608
+ schemes: Schema4.Array(Schema4.String)
609
+ }) {
610
+ };
611
+ var HeaderPreset = class extends Schema4.Class("HeaderPreset")({
612
+ /** Human-readable label for the UI (e.g. "Bearer Token", "API Key + Email") */
613
+ label: Schema4.String,
614
+ /** Headers this strategy needs. Value is null when the user must provide it. */
615
+ headers: Schema4.Record(Schema4.String, Schema4.NullOr(Schema4.String)),
616
+ /** Which headers should be stored as secrets */
617
+ secretHeaders: Schema4.Array(Schema4.String)
618
+ }) {
619
+ };
620
+ var OAuth2Preset = class extends Schema4.Class("OAuth2Preset")({
621
+ /** Human-readable label for the UI (e.g. "OAuth2 (Authorization Code) — oauth_app") */
622
+ label: Schema4.String,
623
+ /** The source security scheme this preset came from (components.securitySchemes key). */
624
+ securitySchemeName: Schema4.String,
625
+ /** Which OAuth2 flow this preset uses. */
626
+ flow: Schema4.Literals(["authorizationCode", "clientCredentials"]),
627
+ /** For authorizationCode: user-agent redirect URL (from the spec). */
628
+ authorizationUrl: Schema4.OptionFromOptional(Schema4.String),
629
+ /** Token endpoint to exchange the code / refresh. */
630
+ tokenUrl: Schema4.String,
631
+ /** Optional refresh endpoint if the spec declares one separately. */
632
+ refreshUrl: Schema4.OptionFromOptional(Schema4.String),
633
+ /** Declared scopes for this flow: `{ scope: description }`. */
634
+ scopes: Schema4.Record(Schema4.String, Schema4.String)
635
+ }) {
636
+ };
637
+ var PreviewOperation = class extends Schema4.Class("PreviewOperation")({
638
+ operationId: Schema4.String,
639
+ method: HttpMethod,
640
+ path: Schema4.String,
641
+ summary: Schema4.OptionFromOptional(Schema4.String),
642
+ tags: Schema4.Array(Schema4.String),
643
+ deprecated: Schema4.Boolean
644
+ }) {
645
+ };
646
+ var SpecPreview = class extends Schema4.Class("SpecPreview")({
647
+ title: Schema4.OptionFromOptional(Schema4.String),
648
+ version: Schema4.OptionFromOptional(Schema4.String),
649
+ /** Reuses ServerInfo from extraction */
650
+ servers: Schema4.Array(ServerInfo),
651
+ operationCount: Schema4.Number,
652
+ /** Lightweight operation list for the add-source UI */
653
+ operations: Schema4.Array(PreviewOperation),
654
+ tags: Schema4.Array(Schema4.String),
655
+ securitySchemes: Schema4.Array(SecurityScheme),
656
+ /** Valid auth strategies (each is a set of schemes used together) */
657
+ authStrategies: Schema4.Array(AuthStrategy),
658
+ /** Pre-built header presets derived from auth strategies */
659
+ headerPresets: Schema4.Array(HeaderPreset),
660
+ /** OAuth2 presets — one per (oauth2 scheme × supported flow) combination */
661
+ oauth2Presets: Schema4.Array(OAuth2Preset)
662
+ }) {
663
+ };
664
+ var stringRecord = (value) => {
665
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
666
+ const out = {};
667
+ for (const [k, v] of Object.entries(value)) {
668
+ if (typeof v === "string") out[k] = v;
669
+ }
670
+ return out;
671
+ };
672
+ var extractFlows = (rawFlows) => {
673
+ if (!rawFlows || typeof rawFlows !== "object") return Option3.none();
674
+ const flows = rawFlows;
675
+ const parseFlow = (key) => flows[key];
676
+ let authorizationCode = Option3.none();
677
+ const authCodeRaw = parseFlow("authorizationCode");
678
+ if (authCodeRaw && typeof authCodeRaw === "object") {
679
+ const f = authCodeRaw;
680
+ const authUrl = typeof f.authorizationUrl === "string" ? f.authorizationUrl : null;
681
+ const tokenUrl = typeof f.tokenUrl === "string" ? f.tokenUrl : null;
682
+ if (authUrl && tokenUrl) {
683
+ authorizationCode = Option3.some(
684
+ new OAuth2AuthorizationCodeFlow({
685
+ authorizationUrl: authUrl,
686
+ tokenUrl,
687
+ refreshUrl: Option3.fromNullishOr(
688
+ typeof f.refreshUrl === "string" ? f.refreshUrl : void 0
689
+ ),
690
+ scopes: stringRecord(f.scopes)
691
+ })
692
+ );
693
+ }
694
+ }
695
+ let clientCredentials = Option3.none();
696
+ const ccRaw = parseFlow("clientCredentials");
697
+ if (ccRaw && typeof ccRaw === "object") {
698
+ const f = ccRaw;
699
+ const tokenUrl = typeof f.tokenUrl === "string" ? f.tokenUrl : null;
700
+ if (tokenUrl) {
701
+ clientCredentials = Option3.some(
702
+ new OAuth2ClientCredentialsFlow({
703
+ tokenUrl,
704
+ refreshUrl: Option3.fromNullishOr(
705
+ typeof f.refreshUrl === "string" ? f.refreshUrl : void 0
706
+ ),
707
+ scopes: stringRecord(f.scopes)
708
+ })
709
+ );
710
+ }
711
+ }
712
+ if (Option3.isNone(authorizationCode) && Option3.isNone(clientCredentials)) {
713
+ return Option3.none();
714
+ }
715
+ return Option3.some(new OAuth2Flows({ authorizationCode, clientCredentials }));
716
+ };
717
+ var extractSecuritySchemes = (rawSchemes, resolver) => Object.entries(rawSchemes).flatMap(([name, schemeOrRef]) => {
718
+ if (!schemeOrRef || typeof schemeOrRef !== "object") return [];
719
+ const resolved = resolver.resolve(
720
+ schemeOrRef
721
+ );
722
+ if (!resolved || typeof resolved !== "object") return [];
723
+ const scheme = resolved;
724
+ const type = decodeSecuritySchemeType(scheme.type);
725
+ if (Option3.isNone(type)) return [];
726
+ const schemeType = type.value;
727
+ return [
728
+ new SecurityScheme({
729
+ name,
730
+ type: schemeType,
731
+ scheme: Option3.fromNullishOr(scheme.scheme),
732
+ bearerFormat: Option3.fromNullishOr(scheme.bearerFormat),
733
+ in: Option3.fromNullishOr(scheme.in),
734
+ headerName: Option3.fromNullishOr(scheme.name),
735
+ description: Option3.fromNullishOr(scheme.description),
736
+ flows: schemeType === "oauth2" ? extractFlows(scheme.flows) : Option3.none(),
737
+ openIdConnectUrl: Option3.fromNullishOr(scheme.openIdConnectUrl)
738
+ })
739
+ ];
740
+ });
741
+ var buildHeaderPresets = (schemes, strategies) => {
742
+ const schemeMap = new Map(schemes.map((s) => [s.name, s]));
743
+ return strategies.flatMap((strategy) => {
744
+ const resolved = strategy.schemes.map((name) => schemeMap.get(name)).filter((s) => s !== void 0);
745
+ if (resolved.length === 0) return [];
746
+ const headers = {};
747
+ const secretHeaders = [];
748
+ const labelParts = [];
749
+ for (const scheme of resolved) {
750
+ if (scheme.type === "http" && Option3.getOrElse(scheme.scheme, () => "") === "bearer") {
751
+ headers["Authorization"] = null;
752
+ secretHeaders.push("Authorization");
753
+ labelParts.push("Bearer Token");
754
+ } else if (scheme.type === "http" && Option3.getOrElse(scheme.scheme, () => "") === "basic") {
755
+ headers["Authorization"] = null;
756
+ secretHeaders.push("Authorization");
757
+ labelParts.push("Basic Auth");
758
+ } else if (scheme.type === "apiKey" && Option3.getOrElse(scheme.in, () => "") === "header") {
759
+ const headerName = Option3.getOrElse(scheme.headerName, () => scheme.name);
760
+ headers[headerName] = null;
761
+ secretHeaders.push(headerName);
762
+ labelParts.push(scheme.name);
763
+ } else if (scheme.type === "apiKey") {
764
+ labelParts.push(`${scheme.name} (${Option3.getOrElse(scheme.in, () => "unknown")})`);
765
+ } else if (scheme.type === "oauth2" || scheme.type === "openIdConnect") {
766
+ return [];
767
+ } else {
768
+ labelParts.push(scheme.name);
769
+ }
770
+ }
771
+ if (Object.keys(headers).length === 0 && resolved.length > 0) {
772
+ return [
773
+ new HeaderPreset({
774
+ label: labelParts.join(" + "),
775
+ headers: {},
776
+ secretHeaders: []
777
+ })
778
+ ];
779
+ }
780
+ return [
781
+ new HeaderPreset({
782
+ label: labelParts.join(" + "),
783
+ headers,
784
+ secretHeaders
785
+ })
786
+ ];
787
+ });
788
+ };
789
+ var buildOAuth2Presets = (schemes) => {
790
+ const presets = [];
791
+ for (const scheme of schemes) {
792
+ if (scheme.type !== "oauth2") continue;
793
+ if (Option3.isNone(scheme.flows)) continue;
794
+ const flows = scheme.flows.value;
795
+ if (Option3.isSome(flows.authorizationCode)) {
796
+ const flow = flows.authorizationCode.value;
797
+ presets.push(
798
+ new OAuth2Preset({
799
+ label: `OAuth2 Authorization Code \xB7 ${scheme.name}`,
800
+ securitySchemeName: scheme.name,
801
+ flow: "authorizationCode",
802
+ authorizationUrl: Option3.some(flow.authorizationUrl),
803
+ tokenUrl: flow.tokenUrl,
804
+ refreshUrl: flow.refreshUrl,
805
+ scopes: flow.scopes
806
+ })
807
+ );
808
+ }
809
+ if (Option3.isSome(flows.clientCredentials)) {
810
+ const flow = flows.clientCredentials.value;
811
+ presets.push(
812
+ new OAuth2Preset({
813
+ label: `OAuth2 Client Credentials \xB7 ${scheme.name}`,
814
+ securitySchemeName: scheme.name,
815
+ flow: "clientCredentials",
816
+ authorizationUrl: Option3.none(),
817
+ tokenUrl: flow.tokenUrl,
818
+ refreshUrl: flow.refreshUrl,
819
+ scopes: flow.scopes
820
+ })
821
+ );
822
+ }
823
+ }
824
+ return presets;
825
+ };
826
+ var collectTags = (result) => {
827
+ const tagSet = /* @__PURE__ */ new Set();
828
+ for (const op of result.operations) {
829
+ for (const tag of op.tags) tagSet.add(tag);
830
+ }
831
+ return [...tagSet].sort();
832
+ };
833
+ var previewSpec = Effect3.fn("OpenApi.previewSpec")(function* (input) {
834
+ const specText = yield* resolveSpecText(input);
835
+ const doc = yield* parse(specText);
836
+ const result = yield* extract(doc);
837
+ const resolver = new DocResolver(doc);
838
+ const securitySchemes = extractSecuritySchemes(doc.components?.securitySchemes ?? {}, resolver);
839
+ const rawSecurity = doc.security ?? [];
840
+ const declaredStrategies = rawSecurity.map(
841
+ (entry) => new AuthStrategy({ schemes: Object.keys(entry) })
842
+ );
843
+ const authStrategies = declaredStrategies.length > 0 ? declaredStrategies : securitySchemes.map((scheme) => new AuthStrategy({ schemes: [scheme.name] }));
844
+ return new SpecPreview({
845
+ title: result.title,
846
+ version: result.version,
847
+ servers: result.servers,
848
+ operationCount: result.operations.length,
849
+ operations: result.operations.map(
850
+ (op) => new PreviewOperation({
851
+ operationId: op.operationId,
852
+ method: op.method,
853
+ path: op.pathTemplate,
854
+ summary: op.summary,
855
+ tags: op.tags,
856
+ deprecated: op.deprecated
857
+ })
858
+ ),
859
+ tags: collectTags(result),
860
+ securitySchemes,
861
+ authStrategies,
862
+ headerPresets: buildHeaderPresets(securitySchemes, authStrategies),
863
+ oauth2Presets: buildOAuth2Presets(securitySchemes)
864
+ });
865
+ });
866
+
867
+ // src/sdk/store.ts
868
+ import { Effect as Effect4, Option as Option4, Schema as Schema5 } from "effect";
869
+ import { defineSchema } from "@executor-js/sdk/core";
870
+ var openapiSchema = defineSchema({
871
+ openapi_source: {
872
+ fields: {
873
+ id: { type: "string", required: true },
874
+ scope_id: { type: "string", required: true, index: true },
875
+ name: { type: "string", required: true },
876
+ spec: { type: "string", required: true },
877
+ // Origin URL the spec was fetched from. Set when `addSpec` was
878
+ // invoked with an http(s) URL; null when the caller passed raw
879
+ // spec text. Drives `canRefresh` on the core source row and
880
+ // is the address re-fetched on `refreshSource`.
881
+ source_url: { type: "string", required: false },
882
+ base_url: { type: "string", required: false },
883
+ // OAuth2 stays JSON because it is one typed source-owned config object
884
+ // carrying slot names, not concrete secret/connection ids.
885
+ oauth2: { type: "json", required: false }
886
+ }
887
+ },
888
+ openapi_operation: {
889
+ fields: {
890
+ id: { type: "string", required: true },
891
+ scope_id: { type: "string", required: true, index: true },
892
+ source_id: { type: "string", required: true, index: true },
893
+ binding: { type: "json", required: true }
894
+ }
895
+ },
896
+ openapi_source_header: {
897
+ fields: {
898
+ id: { type: "string", required: true },
899
+ scope_id: { type: "string", required: true, index: true },
900
+ source_id: { type: "string", required: true, index: true },
901
+ name: { type: "string", required: true },
902
+ kind: { type: ["text", "binding"], required: true },
903
+ text_value: { type: "string", required: false },
904
+ slot_key: { type: "string", required: false },
905
+ prefix: { type: "string", required: false }
906
+ }
907
+ },
908
+ openapi_source_query_param: {
909
+ fields: {
910
+ id: { type: "string", required: true },
911
+ scope_id: { type: "string", required: true, index: true },
912
+ source_id: { type: "string", required: true, index: true },
913
+ name: { type: "string", required: true },
914
+ kind: { type: ["text", "binding"], required: true },
915
+ text_value: { type: "string", required: false },
916
+ slot_key: { type: "string", required: false },
917
+ prefix: { type: "string", required: false }
918
+ }
919
+ },
920
+ openapi_source_spec_fetch_header: {
921
+ fields: {
922
+ id: { type: "string", required: true },
923
+ scope_id: { type: "string", required: true, index: true },
924
+ source_id: { type: "string", required: true, index: true },
925
+ name: { type: "string", required: true },
926
+ kind: { type: ["text", "binding"], required: true },
927
+ text_value: { type: "string", required: false },
928
+ slot_key: { type: "string", required: false },
929
+ prefix: { type: "string", required: false }
930
+ }
931
+ },
932
+ openapi_source_spec_fetch_query_param: {
933
+ fields: {
934
+ id: { type: "string", required: true },
935
+ scope_id: { type: "string", required: true, index: true },
936
+ source_id: { type: "string", required: true, index: true },
937
+ name: { type: "string", required: true },
938
+ kind: { type: ["text", "binding"], required: true },
939
+ text_value: { type: "string", required: false },
940
+ slot_key: { type: "string", required: false },
941
+ prefix: { type: "string", required: false }
942
+ }
943
+ }
944
+ });
945
+ var StoredSourceSchema = class extends Schema5.Class("OpenApiStoredSource")({
946
+ namespace: Schema5.String,
947
+ scope: Schema5.String,
948
+ name: Schema5.String,
949
+ config: Schema5.Struct({
950
+ spec: Schema5.String,
951
+ sourceUrl: Schema5.optional(Schema5.String),
952
+ baseUrl: Schema5.optional(Schema5.String),
953
+ namespace: Schema5.optional(Schema5.String),
954
+ headers: Schema5.optional(Schema5.Record(Schema5.String, ConfiguredHeaderValue)),
955
+ queryParams: Schema5.optional(Schema5.Record(Schema5.String, ConfiguredHeaderValue)),
956
+ specFetchCredentials: Schema5.optional(
957
+ Schema5.Struct({
958
+ headers: Schema5.optional(Schema5.Record(Schema5.String, ConfiguredHeaderValue)),
959
+ queryParams: Schema5.optional(Schema5.Record(Schema5.String, ConfiguredHeaderValue))
960
+ })
961
+ ),
962
+ // Canonical source-owned OAuth config. Concrete client credentials
963
+ // and connection ids live in OpenAPI-owned scoped binding rows.
964
+ oauth2: Schema5.optional(OAuth2SourceConfig)
965
+ })
966
+ }) {
967
+ };
968
+ var encodeBinding = Schema5.encodeSync(OperationBinding);
969
+ var decodeBinding = Schema5.decodeUnknownSync(OperationBinding);
970
+ var decodeBindingJson = Schema5.decodeUnknownSync(Schema5.fromJsonString(OperationBinding));
971
+ var decodeOAuth2SourceConfigOption = Schema5.decodeUnknownOption(OAuth2SourceConfig);
972
+ var decodeOAuth2SourceConfigJsonOption = Schema5.decodeUnknownOption(
973
+ Schema5.fromJsonString(OAuth2SourceConfig)
974
+ );
975
+ var encodeOAuth2SourceConfig = Schema5.encodeSync(OAuth2SourceConfig);
976
+ var NullableString = Schema5.NullOr(Schema5.String);
977
+ var OptionalNullableString = Schema5.optional(NullableString);
978
+ var ChildStorageRow = Schema5.Struct({
979
+ name: Schema5.String,
980
+ kind: Schema5.Literals(["text", "binding"]),
981
+ text_value: OptionalNullableString,
982
+ slot_key: OptionalNullableString,
983
+ prefix: OptionalNullableString
984
+ });
985
+ var decodeChildStorageRowOption = Schema5.decodeUnknownOption(ChildStorageRow);
986
+ var SourceStorageRow = Schema5.Struct({
987
+ id: Schema5.String,
988
+ scope_id: Schema5.String,
989
+ name: Schema5.String,
990
+ spec: Schema5.String,
991
+ source_url: OptionalNullableString,
992
+ base_url: OptionalNullableString,
993
+ oauth2: Schema5.optional(Schema5.Unknown)
994
+ });
995
+ var decodeSourceStorageRow = Schema5.decodeUnknownSync(SourceStorageRow);
996
+ var OperationStorageRow = Schema5.Struct({
997
+ id: Schema5.String,
998
+ source_id: Schema5.String,
999
+ binding: Schema5.Unknown
1000
+ });
1001
+ var decodeOperationStorageRow = Schema5.decodeUnknownSync(OperationStorageRow);
1002
+ var valueMapToChildRows = (sourceId, scope, values) => {
1003
+ if (!values) return [];
1004
+ return Object.entries(values).map(([name, value]) => {
1005
+ const id = JSON.stringify([sourceId, name]);
1006
+ if (typeof value === "string") {
1007
+ return {
1008
+ id,
1009
+ scope_id: scope,
1010
+ source_id: sourceId,
1011
+ name,
1012
+ kind: "text",
1013
+ text_value: value
1014
+ };
1015
+ }
1016
+ return {
1017
+ id,
1018
+ scope_id: scope,
1019
+ source_id: sourceId,
1020
+ name,
1021
+ kind: "binding",
1022
+ slot_key: value.slot,
1023
+ prefix: value.prefix
1024
+ };
1025
+ });
1026
+ };
1027
+ var childRowsToValueMap = (rows) => {
1028
+ const out = {};
1029
+ for (const row of rows) {
1030
+ const decoded = decodeChildStorageRowOption(row);
1031
+ if (Option4.isSome(decoded)) {
1032
+ const child = decoded.value;
1033
+ if (child.kind === "binding" && child.slot_key != null) {
1034
+ out[child.name] = child.prefix != null ? new ConfiguredHeaderBinding({
1035
+ kind: "binding",
1036
+ slot: child.slot_key,
1037
+ prefix: child.prefix
1038
+ }) : new ConfiguredHeaderBinding({
1039
+ kind: "binding",
1040
+ slot: child.slot_key
1041
+ });
1042
+ } else if (child.kind === "text" && child.text_value != null) {
1043
+ out[child.name] = child.text_value;
1044
+ }
1045
+ }
1046
+ }
1047
+ return out;
1048
+ };
1049
+ var toJsonRecord = (value) => value;
1050
+ var slugifySlotPart = (value) => value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "default";
1051
+ var headerBindingSlot = (headerName) => `header:${slugifySlotPart(headerName)}`;
1052
+ var queryParamBindingSlot = (name) => `query_param:${slugifySlotPart(name)}`;
1053
+ var oauth2ClientIdSlot = (securitySchemeName) => `oauth2:${slugifySlotPart(securitySchemeName)}:client-id`;
1054
+ var oauth2ClientSecretSlot = (securitySchemeName) => `oauth2:${slugifySlotPart(securitySchemeName)}:client-secret`;
1055
+ var oauth2ConnectionSlot = (securitySchemeName) => `oauth2:${slugifySlotPart(securitySchemeName)}:connection`;
1056
+ var normalizeStoredOAuth2 = (value) => {
1057
+ if (value == null) return void 0;
1058
+ const sourceConfig = typeof value === "string" ? decodeOAuth2SourceConfigJsonOption(value) : decodeOAuth2SourceConfigOption(value);
1059
+ if (Option4.isSome(sourceConfig)) {
1060
+ return sourceConfig.value;
1061
+ }
1062
+ return void 0;
1063
+ };
1064
+ var makeDefaultOpenapiStore = ({ adapter }) => {
1065
+ const loadChildValueMap = (model, sourceId, scope) => adapter.findMany({
1066
+ model,
1067
+ where: [
1068
+ { field: "source_id", value: sourceId },
1069
+ { field: "scope_id", value: scope }
1070
+ ]
1071
+ }).pipe(Effect4.map(childRowsToValueMap));
1072
+ const rowToSource = (row) => Effect4.gen(function* () {
1073
+ const sourceRow = decodeSourceStorageRow(row);
1074
+ const sourceId = sourceRow.id;
1075
+ const scope = sourceRow.scope_id;
1076
+ const oauth2 = normalizeStoredOAuth2(sourceRow.oauth2);
1077
+ const headers = yield* loadChildValueMap("openapi_source_header", sourceId, scope);
1078
+ const queryParams = yield* loadChildValueMap("openapi_source_query_param", sourceId, scope);
1079
+ const specFetchHeaders = yield* loadChildValueMap(
1080
+ "openapi_source_spec_fetch_header",
1081
+ sourceId,
1082
+ scope
1083
+ );
1084
+ const specFetchQueryParams = yield* loadChildValueMap(
1085
+ "openapi_source_spec_fetch_query_param",
1086
+ sourceId,
1087
+ scope
1088
+ );
1089
+ const specFetchCredentials = Object.keys(specFetchHeaders).length === 0 && Object.keys(specFetchQueryParams).length === 0 ? void 0 : {
1090
+ ...Object.keys(specFetchHeaders).length > 0 ? { headers: specFetchHeaders } : {},
1091
+ ...Object.keys(specFetchQueryParams).length > 0 ? { queryParams: specFetchQueryParams } : {}
1092
+ };
1093
+ return {
1094
+ namespace: sourceId,
1095
+ scope,
1096
+ name: sourceRow.name,
1097
+ config: {
1098
+ spec: sourceRow.spec,
1099
+ sourceUrl: sourceRow.source_url ?? void 0,
1100
+ baseUrl: sourceRow.base_url ?? void 0,
1101
+ headers,
1102
+ queryParams,
1103
+ specFetchCredentials,
1104
+ oauth2
1105
+ }
1106
+ };
1107
+ });
1108
+ const rowToOperation = (row) => {
1109
+ const operationRow = decodeOperationStorageRow(row);
1110
+ return {
1111
+ toolId: operationRow.id,
1112
+ sourceId: operationRow.source_id,
1113
+ binding: decodeBinding(
1114
+ typeof operationRow.binding === "string" ? decodeBindingJson(operationRow.binding) : operationRow.binding
1115
+ )
1116
+ };
1117
+ };
1118
+ const replaceChildRows = (model, sourceId, scope, values) => Effect4.gen(function* () {
1119
+ yield* adapter.deleteMany({
1120
+ model,
1121
+ where: [
1122
+ { field: "source_id", value: sourceId },
1123
+ { field: "scope_id", value: scope }
1124
+ ]
1125
+ });
1126
+ const rows = valueMapToChildRows(sourceId, scope, values);
1127
+ if (rows.length === 0) return;
1128
+ yield* adapter.createMany({
1129
+ model,
1130
+ data: rows,
1131
+ forceAllowId: true
1132
+ });
1133
+ });
1134
+ const deleteSource = (namespace, scope) => Effect4.gen(function* () {
1135
+ yield* adapter.deleteMany({
1136
+ model: "openapi_operation",
1137
+ where: [
1138
+ { field: "source_id", value: namespace },
1139
+ { field: "scope_id", value: scope }
1140
+ ]
1141
+ });
1142
+ for (const model of [
1143
+ "openapi_source_header",
1144
+ "openapi_source_query_param",
1145
+ "openapi_source_spec_fetch_header",
1146
+ "openapi_source_spec_fetch_query_param"
1147
+ ]) {
1148
+ yield* adapter.deleteMany({
1149
+ model,
1150
+ where: [
1151
+ { field: "source_id", value: namespace },
1152
+ { field: "scope_id", value: scope }
1153
+ ]
1154
+ });
1155
+ }
1156
+ yield* adapter.delete({
1157
+ model: "openapi_source",
1158
+ where: [
1159
+ { field: "id", value: namespace },
1160
+ { field: "scope_id", value: scope }
1161
+ ]
1162
+ });
1163
+ });
1164
+ return {
1165
+ upsertSource: (input, operations) => Effect4.gen(function* () {
1166
+ yield* deleteSource(input.namespace, input.scope);
1167
+ yield* adapter.create({
1168
+ model: "openapi_source",
1169
+ data: {
1170
+ id: input.namespace,
1171
+ scope_id: input.scope,
1172
+ name: input.name,
1173
+ spec: input.config.spec,
1174
+ source_url: input.config.sourceUrl ?? void 0,
1175
+ base_url: input.config.baseUrl ?? void 0,
1176
+ oauth2: input.config.oauth2 ? toJsonRecord(encodeOAuth2SourceConfig(input.config.oauth2)) : void 0
1177
+ },
1178
+ forceAllowId: true
1179
+ });
1180
+ yield* replaceChildRows(
1181
+ "openapi_source_header",
1182
+ input.namespace,
1183
+ input.scope,
1184
+ input.config.headers
1185
+ );
1186
+ yield* replaceChildRows(
1187
+ "openapi_source_query_param",
1188
+ input.namespace,
1189
+ input.scope,
1190
+ input.config.queryParams
1191
+ );
1192
+ yield* replaceChildRows(
1193
+ "openapi_source_spec_fetch_header",
1194
+ input.namespace,
1195
+ input.scope,
1196
+ input.config.specFetchCredentials?.headers
1197
+ );
1198
+ yield* replaceChildRows(
1199
+ "openapi_source_spec_fetch_query_param",
1200
+ input.namespace,
1201
+ input.scope,
1202
+ input.config.specFetchCredentials?.queryParams
1203
+ );
1204
+ if (operations.length > 0) {
1205
+ yield* adapter.createMany({
1206
+ model: "openapi_operation",
1207
+ data: operations.map((op) => ({
1208
+ id: op.toolId,
1209
+ scope_id: input.scope,
1210
+ source_id: op.sourceId,
1211
+ binding: toJsonRecord(encodeBinding(op.binding))
1212
+ })),
1213
+ forceAllowId: true
1214
+ });
1215
+ }
1216
+ }),
1217
+ updateSourceMeta: (namespace, scope, patch) => Effect4.gen(function* () {
1218
+ const existingRow = yield* adapter.findOne({
1219
+ model: "openapi_source",
1220
+ where: [
1221
+ { field: "id", value: namespace },
1222
+ { field: "scope_id", value: scope }
1223
+ ]
1224
+ });
1225
+ if (!existingRow) return;
1226
+ const existing = yield* rowToSource(existingRow);
1227
+ const nextName = patch.name?.trim() || existing.name;
1228
+ const nextBaseUrl = patch.baseUrl !== void 0 ? patch.baseUrl : existing.config.baseUrl;
1229
+ const nextOAuth2 = patch.oauth2 !== void 0 ? patch.oauth2 : existing.config.oauth2;
1230
+ yield* adapter.update({
1231
+ model: "openapi_source",
1232
+ where: [
1233
+ { field: "id", value: namespace },
1234
+ { field: "scope_id", value: scope }
1235
+ ],
1236
+ update: {
1237
+ name: nextName,
1238
+ base_url: nextBaseUrl ?? void 0,
1239
+ oauth2: nextOAuth2 ? toJsonRecord(encodeOAuth2SourceConfig(nextOAuth2)) : void 0
1240
+ }
1241
+ });
1242
+ if (patch.headers !== void 0) {
1243
+ yield* replaceChildRows("openapi_source_header", namespace, scope, patch.headers);
1244
+ }
1245
+ if (patch.queryParams !== void 0) {
1246
+ yield* replaceChildRows(
1247
+ "openapi_source_query_param",
1248
+ namespace,
1249
+ scope,
1250
+ patch.queryParams
1251
+ );
1252
+ }
1253
+ }),
1254
+ getSource: (namespace, scope) => Effect4.gen(function* () {
1255
+ const row = yield* adapter.findOne({
1256
+ model: "openapi_source",
1257
+ where: [
1258
+ { field: "id", value: namespace },
1259
+ { field: "scope_id", value: scope }
1260
+ ]
1261
+ });
1262
+ if (!row) return null;
1263
+ return yield* rowToSource(row);
1264
+ }),
1265
+ listSources: () => Effect4.gen(function* () {
1266
+ const rows = yield* adapter.findMany({ model: "openapi_source" });
1267
+ return yield* Effect4.forEach(rows, rowToSource, {
1268
+ concurrency: "unbounded"
1269
+ });
1270
+ }),
1271
+ getOperationByToolId: (toolId, scope) => adapter.findOne({
1272
+ model: "openapi_operation",
1273
+ where: [
1274
+ { field: "id", value: toolId },
1275
+ { field: "scope_id", value: scope }
1276
+ ]
1277
+ }).pipe(Effect4.map((row) => row ? rowToOperation(row) : null)),
1278
+ listOperationsBySource: (sourceId, scope) => adapter.findMany({
1279
+ model: "openapi_operation",
1280
+ where: [
1281
+ { field: "source_id", value: sourceId },
1282
+ { field: "scope_id", value: scope }
1283
+ ]
1284
+ }).pipe(Effect4.map((rows) => rows.map(rowToOperation))),
1285
+ removeSource: (namespace, scope) => deleteSource(namespace, scope)
1286
+ };
1287
+ };
1288
+
1289
+ export {
1290
+ OpenApiParseError,
1291
+ OpenApiExtractionError,
1292
+ OpenApiInvocationError,
1293
+ OpenApiOAuthError,
1294
+ fetchSpecText,
1295
+ resolveSpecText,
1296
+ parse,
1297
+ DocResolver,
1298
+ substituteUrlVariables,
1299
+ expandServerUrlOptions,
1300
+ resolveBaseUrl,
1301
+ preferredContent,
1302
+ OperationId,
1303
+ HttpMethod,
1304
+ ParameterLocation,
1305
+ OperationParameter,
1306
+ EncodingObject,
1307
+ MediaBinding,
1308
+ OperationRequestBody,
1309
+ ExtractedOperation,
1310
+ ServerVariable,
1311
+ ServerInfo,
1312
+ ExtractionResult,
1313
+ OperationBinding,
1314
+ HeaderValue,
1315
+ ConfiguredHeaderBinding,
1316
+ ConfiguredHeaderValue,
1317
+ OpenApiCredentialInput,
1318
+ OpenApiSourceBindingValue,
1319
+ OpenApiSourceBindingInputSchema,
1320
+ OpenApiSourceBindingInput,
1321
+ OpenApiSourceBindingRef,
1322
+ OAuth2SourceConfigSchema,
1323
+ OAuth2SourceConfig,
1324
+ InvocationResult,
1325
+ extract,
1326
+ OAuth2AuthorizationCodeFlow,
1327
+ OAuth2ClientCredentialsFlow,
1328
+ OAuth2Flows,
1329
+ SecurityScheme,
1330
+ AuthStrategy,
1331
+ HeaderPreset,
1332
+ OAuth2Preset,
1333
+ PreviewOperation,
1334
+ SpecPreview,
1335
+ previewSpec,
1336
+ openapiSchema,
1337
+ StoredSourceSchema,
1338
+ headerBindingSlot,
1339
+ queryParamBindingSlot,
1340
+ oauth2ClientIdSlot,
1341
+ oauth2ClientSecretSlot,
1342
+ oauth2ConnectionSlot,
1343
+ makeDefaultOpenapiStore
1344
+ };
1345
+ //# sourceMappingURL=chunk-2BXVRXGL.js.map