@executor-js/plugin-openapi 0.0.1-beta.5 → 0.0.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.
@@ -14,9 +14,7 @@ var OpenApiExtractionError = class extends Schema.TaggedError()(
14
14
  }
15
15
  ) {
16
16
  };
17
- var OpenApiInvocationError = class extends Data.TaggedError(
18
- "OpenApiInvocationError"
19
- ) {
17
+ var OpenApiInvocationError = class extends Data.TaggedError("OpenApiInvocationError") {
20
18
  };
21
19
 
22
20
  // src/sdk/parse.ts
@@ -25,11 +23,15 @@ import { Effect } from "effect";
25
23
  import YAML from "yaml";
26
24
  var parse = Effect.fn("OpenApi.parse")(function* (input) {
27
25
  const api = yield* Effect.tryPromise({
28
- try: () => {
29
- if (input.startsWith("http://") || input.startsWith("https://")) {
30
- return SwaggerParser.bundle(input);
26
+ try: async () => {
27
+ const source = input.startsWith("http://") || input.startsWith("https://") ? input : parseTextToObject(input);
28
+ try {
29
+ return await SwaggerParser.bundle(source);
30
+ } catch {
31
+ const parsed = await SwaggerParser.parse(source);
32
+ resolveRefsInPlace(parsed);
33
+ return parsed;
31
34
  }
32
- return SwaggerParser.bundle(parseTextToObject(input));
33
35
  },
34
36
  catch: (error) => new OpenApiParseError({
35
37
  message: `Failed to parse OpenAPI document: ${error instanceof Error ? error.message : String(error)}`
@@ -59,6 +61,67 @@ var parseTextToObject = (text) => {
59
61
  }
60
62
  return parsed;
61
63
  };
64
+ var resolveRefsInPlace = (doc) => {
65
+ const lookup = (pointer) => {
66
+ if (!pointer.startsWith("#/")) return void 0;
67
+ const parts = pointer.slice(2).split("/");
68
+ let current = doc;
69
+ for (const part of parts) {
70
+ if (typeof current !== "object" || current === null) return void 0;
71
+ current = current[part];
72
+ }
73
+ return current;
74
+ };
75
+ const resolving = /* @__PURE__ */ new Set();
76
+ const resolveRef = (pointer) => {
77
+ if (resolving.has(pointer)) return void 0;
78
+ const target = lookup(pointer);
79
+ if (!target) return void 0;
80
+ resolving.add(pointer);
81
+ const cloned = deepClone(target);
82
+ walk(cloned);
83
+ resolving.delete(pointer);
84
+ return cloned;
85
+ };
86
+ const deepClone = (obj) => {
87
+ if (!obj || typeof obj !== "object") return obj;
88
+ if (Array.isArray(obj)) return obj.map(deepClone);
89
+ const result = {};
90
+ for (const [k, v] of Object.entries(obj)) {
91
+ result[k] = deepClone(v);
92
+ }
93
+ return result;
94
+ };
95
+ const walk = (obj) => {
96
+ if (!obj || typeof obj !== "object") return;
97
+ if (Array.isArray(obj)) {
98
+ for (let i = 0; i < obj.length; i++) {
99
+ const item = obj[i];
100
+ if (isRef(item)) {
101
+ const resolved = resolveRef(item.$ref);
102
+ if (resolved) obj[i] = resolved;
103
+ else obj[i] = { description: `Unresolved: ${item.$ref}` };
104
+ } else {
105
+ walk(item);
106
+ }
107
+ }
108
+ return;
109
+ }
110
+ const record = obj;
111
+ for (const [k, v] of Object.entries(record)) {
112
+ if (k === "$ref") continue;
113
+ if (isRef(v)) {
114
+ const resolved = resolveRef(v.$ref);
115
+ if (resolved) record[k] = resolved;
116
+ else record[k] = { description: `Unresolved: ${v.$ref}` };
117
+ } else {
118
+ walk(v);
119
+ }
120
+ }
121
+ };
122
+ walk(doc);
123
+ };
124
+ var isRef = (v) => typeof v === "object" && v !== null && "$ref" in v && typeof v.$ref === "string";
62
125
 
63
126
  // src/sdk/openapi-utils.ts
64
127
  import { Option } from "effect";
@@ -69,7 +132,7 @@ var DocResolver = class {
69
132
  doc;
70
133
  /** Resolve a value that might be a $ref, returning the resolved object */
71
134
  resolve(value) {
72
- if (isRef(value)) {
135
+ if (isRef2(value)) {
73
136
  const resolved = this.resolvePointer(value.$ref);
74
137
  return resolved;
75
138
  }
@@ -86,7 +149,7 @@ var DocResolver = class {
86
149
  return current;
87
150
  }
88
151
  };
89
- var isRef = (value) => typeof value === "object" && value !== null && "$ref" in value;
152
+ var isRef2 = (value) => typeof value === "object" && value !== null && "$ref" in value;
90
153
  var resolveBaseUrl = (servers) => {
91
154
  const server = servers[0];
92
155
  if (!server) return "";
@@ -119,9 +182,7 @@ var HttpMethod = Schema2.Literal(
119
182
  "trace"
120
183
  );
121
184
  var ParameterLocation = Schema2.Literal("path", "query", "header", "cookie");
122
- var OperationParameter = class extends Schema2.Class(
123
- "OperationParameter"
124
- )({
185
+ var OperationParameter = class extends Schema2.Class("OperationParameter")({
125
186
  name: Schema2.String,
126
187
  location: ParameterLocation,
127
188
  required: Schema2.Boolean,
@@ -140,9 +201,7 @@ var OperationRequestBody = class extends Schema2.Class(
140
201
  schema: Schema2.optionalWith(Schema2.Unknown, { as: "Option" })
141
202
  }) {
142
203
  };
143
- var ExtractedOperation = class extends Schema2.Class(
144
- "ExtractedOperation"
145
- )({
204
+ var ExtractedOperation = class extends Schema2.Class("ExtractedOperation")({
146
205
  operationId: OperationId,
147
206
  method: HttpMethod,
148
207
  pathTemplate: Schema2.String,
@@ -158,24 +217,19 @@ var ExtractedOperation = class extends Schema2.Class(
158
217
  };
159
218
  var ServerInfo = class extends Schema2.Class("ServerInfo")({
160
219
  url: Schema2.String,
161
- variables: Schema2.optionalWith(
162
- Schema2.Record({ key: Schema2.String, value: Schema2.String }),
163
- { as: "Option" }
164
- )
220
+ variables: Schema2.optionalWith(Schema2.Record({ key: Schema2.String, value: Schema2.String }), {
221
+ as: "Option"
222
+ })
165
223
  }) {
166
224
  };
167
- var ExtractionResult = class extends Schema2.Class(
168
- "ExtractionResult"
169
- )({
225
+ var ExtractionResult = class extends Schema2.Class("ExtractionResult")({
170
226
  title: Schema2.optionalWith(Schema2.String, { as: "Option" }),
171
227
  version: Schema2.optionalWith(Schema2.String, { as: "Option" }),
172
228
  servers: Schema2.Array(ServerInfo),
173
229
  operations: Schema2.Array(ExtractedOperation)
174
230
  }) {
175
231
  };
176
- var OperationBinding = class extends Schema2.Class(
177
- "OperationBinding"
178
- )({
232
+ var OperationBinding = class extends Schema2.Class("OperationBinding")({
179
233
  method: HttpMethod,
180
234
  pathTemplate: Schema2.String,
181
235
  parameters: Schema2.Array(OperationParameter),
@@ -189,20 +243,15 @@ var HeaderValue = Schema2.Union(
189
243
  prefix: Schema2.optional(Schema2.String)
190
244
  })
191
245
  );
192
- var InvocationConfig = class extends Schema2.Class(
193
- "InvocationConfig"
194
- )({
246
+ var InvocationConfig = class extends Schema2.Class("InvocationConfig")({
195
247
  baseUrl: Schema2.String,
196
248
  /** Headers applied to every request. Values can reference secrets. */
197
- headers: Schema2.optionalWith(
198
- Schema2.Record({ key: Schema2.String, value: HeaderValue }),
199
- { default: () => ({}) }
200
- )
249
+ headers: Schema2.optionalWith(Schema2.Record({ key: Schema2.String, value: HeaderValue }), {
250
+ default: () => ({})
251
+ })
201
252
  }) {
202
253
  };
203
- var InvocationResult = class extends Schema2.Class(
204
- "InvocationResult"
205
- )({
254
+ var InvocationResult = class extends Schema2.Class("InvocationResult")({
206
255
  status: Schema2.Number,
207
256
  headers: Schema2.Record({ key: Schema2.String, value: Schema2.String }),
208
257
  data: Schema2.NullOr(Schema2.Unknown),
@@ -243,9 +292,7 @@ var extractParameters = (pathItem, operation, r) => {
243
292
  schema: Option2.fromNullable(p.schema),
244
293
  style: Option2.fromNullable(p.style),
245
294
  explode: Option2.fromNullable(p.explode),
246
- allowReserved: Option2.fromNullable(
247
- "allowReserved" in p ? p.allowReserved : void 0
248
- ),
295
+ allowReserved: Option2.fromNullable("allowReserved" in p ? p.allowReserved : void 0),
249
296
  description: Option2.fromNullable(p.description)
250
297
  })
251
298
  );
@@ -296,10 +343,7 @@ var buildInputSchema = (parameters, requestBody) => {
296
343
  additionalProperties: false
297
344
  };
298
345
  };
299
- var deriveOperationId = (method, pathTemplate, operation) => operation.operationId ?? (`${method}_${pathTemplate.replace(/[^a-zA-Z0-9]+/g, "_")}`.replace(
300
- /^_+|_+$/g,
301
- ""
302
- ) || `${method}_operation`);
346
+ var deriveOperationId = (method, pathTemplate, operation) => operation.operationId ?? (`${method}_${pathTemplate.replace(/[^a-zA-Z0-9]+/g, "_")}`.replace(/^_+|_+$/g, "") || `${method}_operation`);
303
347
  var extractServers = (doc) => (doc.servers ?? []).flatMap((server) => {
304
348
  if (!server.url) return [];
305
349
  const vars = server.variables ? Object.fromEntries(
@@ -337,9 +381,7 @@ var extract = Effect2.fn("OpenApi.extract")(function* (doc) {
337
381
  const tags = (operation.tags ?? []).filter((t) => t.trim().length > 0);
338
382
  operations.push(
339
383
  new ExtractedOperation({
340
- operationId: OperationId.make(
341
- deriveOperationId(method, pathTemplate, operation)
342
- ),
384
+ operationId: OperationId.make(deriveOperationId(method, pathTemplate, operation)),
343
385
  method,
344
386
  pathTemplate,
345
387
  summary: Option2.fromNullable(operation.summary),
@@ -364,14 +406,11 @@ var extract = Effect2.fn("OpenApi.extract")(function* (doc) {
364
406
 
365
407
  // src/sdk/invoke.ts
366
408
  import { Effect as Effect3, Layer, Option as Option3 } from "effect";
367
- import {
368
- HttpClient,
369
- HttpClientRequest
370
- } from "@effect/platform";
409
+ import { HttpClient, HttpClientRequest } from "@effect/platform";
371
410
  import {
372
411
  ToolInvocationResult,
373
412
  ToolInvocationError
374
- } from "@executor-js/sdk/core";
413
+ } from "@executor-js/sdk";
375
414
  var CONTAINER_KEYS = {
376
415
  path: ["path", "pathParams", "params"],
377
416
  query: ["query", "queryParams", "params"],
@@ -404,19 +443,13 @@ var resolvePath = Effect3.fn("OpenApi.resolvePath")(function* (pathTemplate, arg
404
443
  }
405
444
  continue;
406
445
  }
407
- resolved = resolved.replaceAll(
408
- `{${param.name}}`,
409
- encodeURIComponent(String(value))
410
- );
446
+ resolved = resolved.replaceAll(`{${param.name}}`, encodeURIComponent(String(value)));
411
447
  }
412
448
  const remaining = [...resolved.matchAll(/\{([^{}]+)\}/g)].map((m) => m[1]).filter((v) => typeof v === "string");
413
449
  for (const name of remaining) {
414
450
  const value = args[name];
415
451
  if (value !== void 0 && value !== null) {
416
- resolved = resolved.replaceAll(
417
- `{${name}}`,
418
- encodeURIComponent(String(value))
419
- );
452
+ resolved = resolved.replaceAll(`{${name}}`, encodeURIComponent(String(value)));
420
453
  }
421
454
  }
422
455
  const unresolved = [...resolved.matchAll(/\{([^{}]+)\}/g)].map((m) => m[1]).filter((v) => typeof v === "string");
@@ -462,32 +495,20 @@ var isJsonContentType = (ct) => {
462
495
  };
463
496
  var invoke = Effect3.fn("OpenApi.invoke")(function* (operation, args, config, resolvedHeaders) {
464
497
  const client = yield* HttpClient.HttpClient;
465
- const resolvedPath = yield* resolvePath(
466
- operation.pathTemplate,
467
- args,
468
- operation.parameters
469
- );
498
+ const resolvedPath = yield* resolvePath(operation.pathTemplate, args, operation.parameters);
470
499
  const path = resolvedPath.startsWith("/") ? resolvedPath : `/${resolvedPath}`;
471
500
  let request = HttpClientRequest.make(operation.method.toUpperCase())(path);
472
501
  for (const param of operation.parameters) {
473
502
  if (param.location !== "query") continue;
474
503
  const value = readParamValue(args, param);
475
504
  if (value === void 0 || value === null) continue;
476
- request = HttpClientRequest.setUrlParam(
477
- request,
478
- param.name,
479
- String(value)
480
- );
505
+ request = HttpClientRequest.setUrlParam(request, param.name, String(value));
481
506
  }
482
507
  for (const param of operation.parameters) {
483
508
  if (param.location !== "header") continue;
484
509
  const value = readParamValue(args, param);
485
510
  if (value === void 0 || value === null) continue;
486
- request = HttpClientRequest.setHeader(
487
- request,
488
- param.name,
489
- String(value)
490
- );
511
+ request = HttpClientRequest.setHeader(request, param.name, String(value));
491
512
  }
492
513
  if (Option3.isSome(operation.requestBody)) {
493
514
  const rb = operation.requestBody.value;
@@ -513,9 +534,7 @@ var invoke = Effect3.fn("OpenApi.invoke")(function* (operation, args, config, re
513
534
  const status = response.status;
514
535
  const responseHeaders = { ...response.headers };
515
536
  const contentType = response.headers["content-type"] ?? null;
516
- const responseBody = status === 204 ? null : isJsonContentType(contentType) ? yield* response.json.pipe(
517
- Effect3.catchAll(() => response.text)
518
- ) : yield* response.text;
537
+ const responseBody = status === 204 ? null : isJsonContentType(contentType) ? yield* response.json.pipe(Effect3.catchAll(() => response.text)) : yield* response.text;
519
538
  const ok = status >= 200 && status < 300;
520
539
  return new InvocationResult({
521
540
  status,
@@ -547,20 +566,23 @@ var makeOpenApiInvoker = (opts) => ({
547
566
  cause: void 0
548
567
  });
549
568
  }
550
- const { binding, config } = entry;
569
+ const source = yield* opts.operationStore.getSource(entry.namespace);
570
+ if (!source) {
571
+ return yield* new ToolInvocationError({
572
+ toolId,
573
+ message: `No source found for namespace "${entry.namespace}"`,
574
+ cause: void 0
575
+ });
576
+ }
577
+ const { binding } = entry;
578
+ const { invocationConfig: config } = source;
551
579
  const baseUrl = config.baseUrl;
552
- const resolvedHeaders = yield* resolveHeaders(
553
- config.headers,
554
- opts.secrets,
555
- opts.scopeId
556
- );
580
+ const resolvedHeaders = yield* resolveHeaders(config.headers, opts.secrets, opts.scopeId);
557
581
  const clientWithBaseUrl = baseUrl ? Layer.effect(
558
582
  HttpClient.HttpClient,
559
583
  Effect3.map(
560
584
  HttpClient.HttpClient,
561
- HttpClient.mapRequest(
562
- HttpClientRequest.prependUrl(baseUrl)
563
- )
585
+ HttpClient.mapRequest(HttpClientRequest.prependUrl(baseUrl))
564
586
  )
565
587
  ).pipe(Layer.provide(opts.httpClientLayer)) : opts.httpClientLayer;
566
588
  const result = yield* invoke(
@@ -591,51 +613,80 @@ var makeOpenApiInvoker = (opts) => ({
591
613
  });
592
614
 
593
615
  // src/sdk/kv-operation-store.ts
594
- import { Effect as Effect4, Schema as Schema3 } from "effect";
595
- import { scopeKv, makeInMemoryScopedKv } from "@executor-js/sdk/core";
596
- var StoredEntry = class extends Schema3.Class("StoredEntry")({
597
- namespace: Schema3.String,
598
- binding: OperationBinding,
599
- config: InvocationConfig
600
- }) {
601
- };
602
- var encodeEntry = Schema3.encodeSync(Schema3.parseJson(StoredEntry));
603
- var decodeEntry = Schema3.decodeUnknownSync(Schema3.parseJson(StoredEntry));
604
- var StoredSourceSchema = Schema3.Struct({
616
+ import { Effect as Effect4, Schema as Schema4 } from "effect";
617
+ import { scopeKv, makeInMemoryScopedKv } from "@executor-js/sdk";
618
+
619
+ // src/sdk/stored-source.ts
620
+ import { Schema as Schema3 } from "effect";
621
+ var StoredSourceSchema = class extends Schema3.Class("OpenApiStoredSource")({
605
622
  namespace: Schema3.String,
606
623
  name: Schema3.String,
607
624
  config: Schema3.Struct({
608
625
  spec: Schema3.String,
609
626
  baseUrl: Schema3.optional(Schema3.String),
610
627
  namespace: Schema3.optional(Schema3.String),
611
- headers: Schema3.optional(
612
- Schema3.Record({ key: Schema3.String, value: HeaderValue })
613
- )
614
- })
615
- });
616
- var encodeSource = Schema3.encodeSync(Schema3.parseJson(StoredSourceSchema));
617
- var decodeSource = Schema3.decodeUnknownSync(Schema3.parseJson(StoredSourceSchema));
628
+ headers: Schema3.optional(Schema3.Record({ key: Schema3.String, value: HeaderValue }))
629
+ }),
630
+ // TODO(migration): make required once all rows have been migrated to
631
+ // carry invocationConfig. Left optional for decode compat with rows
632
+ // written before the source-level invocationConfig refactor.
633
+ invocationConfig: Schema3.optional(InvocationConfig)
634
+ }) {
635
+ };
636
+
637
+ // src/sdk/kv-operation-store.ts
638
+ var StoredEntry = class extends Schema4.Class("StoredEntry")({
639
+ namespace: Schema4.String,
640
+ binding: OperationBinding
641
+ }) {
642
+ };
643
+ var encodeEntry = Schema4.encodeSync(Schema4.parseJson(StoredEntry));
644
+ var decodeEntry = Schema4.decodeUnknownSync(Schema4.parseJson(StoredEntry));
645
+ var LegacyStoredEntry = class extends Schema4.Class("LegacyStoredEntry")({
646
+ namespace: Schema4.String,
647
+ binding: OperationBinding,
648
+ config: Schema4.optional(InvocationConfig)
649
+ }) {
650
+ };
651
+ var decodeLegacyEntry = Schema4.decodeUnknownSync(Schema4.parseJson(LegacyStoredEntry));
652
+ var encodeSource = Schema4.encodeSync(Schema4.parseJson(StoredSourceSchema));
653
+ var decodeSource = Schema4.decodeUnknownSync(Schema4.parseJson(StoredSourceSchema));
618
654
  var makeStore = (bindings, sources) => {
619
655
  const withKvTransaction = (kv, effect) => kv.withTransaction?.(effect) ?? effect;
656
+ const rehydrateInvocationConfig = (source) => Effect4.gen(function* () {
657
+ if (source.invocationConfig) return source;
658
+ let recovered = null;
659
+ const entries = yield* bindings.list();
660
+ for (const e of entries) {
661
+ const legacy = decodeLegacyEntry(e.value);
662
+ if (legacy.namespace === source.namespace && legacy.config) {
663
+ recovered = legacy.config;
664
+ break;
665
+ }
666
+ }
667
+ const invocationConfig = recovered ?? new InvocationConfig({
668
+ baseUrl: source.config.baseUrl ?? "",
669
+ headers: source.config.headers ?? {}
670
+ });
671
+ return { ...source, invocationConfig };
672
+ });
620
673
  return {
621
674
  get: (toolId) => Effect4.gen(function* () {
622
675
  const raw = yield* bindings.get(toolId);
623
676
  if (!raw) return null;
624
677
  const entry = decodeEntry(raw);
625
- return { binding: entry.binding, config: entry.config };
678
+ return { binding: entry.binding, namespace: entry.namespace };
626
679
  }),
627
680
  put: (entries) => withKvTransaction(
628
681
  bindings,
629
- Effect4.forEach(
630
- entries,
631
- ({ toolId, namespace, binding, config }) => bindings.set(
632
- toolId,
633
- encodeEntry(new StoredEntry({ namespace, binding, config }))
634
- ),
635
- { discard: true }
682
+ bindings.set(
683
+ entries.map(({ toolId, namespace, binding }) => ({
684
+ key: toolId,
685
+ value: encodeEntry(new StoredEntry({ namespace, binding }))
686
+ }))
636
687
  )
637
688
  ),
638
- remove: (toolId) => bindings.delete(toolId).pipe(Effect4.asVoid),
689
+ remove: (toolId) => bindings.delete([toolId]).pipe(Effect4.asVoid),
639
690
  listByNamespace: (namespace) => Effect4.gen(function* () {
640
691
  const entries = yield* bindings.list();
641
692
  const ids = [];
@@ -650,73 +701,98 @@ var makeStore = (bindings, sources) => {
650
701
  const ids = [];
651
702
  for (const e of entries) {
652
703
  const entry = decodeEntry(e.value);
653
- if (entry.namespace === namespace) {
654
- ids.push(e.key);
655
- yield* bindings.delete(e.key);
656
- }
704
+ if (entry.namespace === namespace) ids.push(e.key);
657
705
  }
706
+ if (ids.length > 0) yield* bindings.delete(ids);
658
707
  return ids;
659
708
  }),
660
- putSource: (source) => sources.set(source.namespace, encodeSource(source)),
661
- removeSource: (namespace) => sources.delete(namespace).pipe(Effect4.asVoid),
709
+ putSource: (source) => sources.set([{ key: source.namespace, value: encodeSource(source) }]),
710
+ removeSource: (namespace) => sources.delete([namespace]).pipe(Effect4.asVoid),
662
711
  listSources: () => Effect4.gen(function* () {
663
712
  const entries = yield* sources.list();
664
- return entries.map((e) => decodeSource(e.value));
713
+ const out = [];
714
+ for (const e of entries) {
715
+ const raw = decodeSource(e.value);
716
+ out.push(
717
+ raw.invocationConfig ? raw : yield* rehydrateInvocationConfig(raw)
718
+ );
719
+ }
720
+ return out;
721
+ }),
722
+ getSource: (namespace) => Effect4.gen(function* () {
723
+ const raw = yield* sources.get(namespace);
724
+ if (!raw) return null;
725
+ const source = decodeSource(raw);
726
+ if (source.invocationConfig) return source;
727
+ const healed = yield* rehydrateInvocationConfig(source);
728
+ yield* sources.set([{ key: namespace, value: encodeSource(healed) }]);
729
+ return healed;
730
+ }),
731
+ getSourceConfig: (namespace) => Effect4.gen(function* () {
732
+ const raw = yield* sources.get(namespace);
733
+ if (!raw) return null;
734
+ const source = decodeSource(raw);
735
+ return source.config;
665
736
  })
666
737
  };
667
738
  };
668
- var makeKvOperationStore = (kv, namespace) => makeStore(
669
- scopeKv(kv, `${namespace}.bindings`),
670
- scopeKv(kv, `${namespace}.sources`)
671
- );
672
- var makeInMemoryOperationStore = () => makeStore(
673
- makeInMemoryScopedKv(),
674
- makeInMemoryScopedKv()
675
- );
739
+ var makeKvOperationStore = (kv, namespace) => makeStore(scopeKv(kv, `${namespace}.bindings`), scopeKv(kv, `${namespace}.sources`));
740
+ var makeInMemoryOperationStore = () => makeStore(makeInMemoryScopedKv(), makeInMemoryScopedKv());
676
741
 
677
742
  // src/sdk/preview.ts
678
743
  import { Effect as Effect5, Option as Option4 } from "effect";
679
- import { Schema as Schema4 } from "effect";
680
- var SecurityScheme = class extends Schema4.Class("SecurityScheme")({
744
+ import { Schema as Schema5 } from "effect";
745
+ var SecurityScheme = class extends Schema5.Class("SecurityScheme")({
681
746
  /** Key name in components.securitySchemes (e.g. "api_token") */
682
- name: Schema4.String,
747
+ name: Schema5.String,
683
748
  /** OpenAPI security scheme type */
684
- type: Schema4.Literal("http", "apiKey", "oauth2", "openIdConnect"),
749
+ type: Schema5.Literal("http", "apiKey", "oauth2", "openIdConnect"),
685
750
  /** For type: "http" — e.g. "bearer", "basic" */
686
- scheme: Schema4.optionalWith(Schema4.String, { as: "Option" }),
751
+ scheme: Schema5.optionalWith(Schema5.String, { as: "Option" }),
687
752
  /** For type: "apiKey" — where the key goes */
688
- in: Schema4.optionalWith(Schema4.Literal("header", "query", "cookie"), { as: "Option" }),
753
+ in: Schema5.optionalWith(Schema5.Literal("header", "query", "cookie"), { as: "Option" }),
689
754
  /** For type: "apiKey" — the header/query/cookie name */
690
- headerName: Schema4.optionalWith(Schema4.String, { as: "Option" }),
691
- description: Schema4.optionalWith(Schema4.String, { as: "Option" })
755
+ headerName: Schema5.optionalWith(Schema5.String, { as: "Option" }),
756
+ description: Schema5.optionalWith(Schema5.String, { as: "Option" })
692
757
  }) {
693
758
  };
694
- var AuthStrategy = class extends Schema4.Class("AuthStrategy")({
759
+ var AuthStrategy = class extends Schema5.Class("AuthStrategy")({
695
760
  /** The security schemes required together for this strategy */
696
- schemes: Schema4.Array(Schema4.String)
761
+ schemes: Schema5.Array(Schema5.String)
697
762
  }) {
698
763
  };
699
- var HeaderPreset = class extends Schema4.Class("HeaderPreset")({
764
+ var HeaderPreset = class extends Schema5.Class("HeaderPreset")({
700
765
  /** Human-readable label for the UI (e.g. "Bearer Token", "API Key + Email") */
701
- label: Schema4.String,
766
+ label: Schema5.String,
702
767
  /** Headers this strategy needs. Value is null when the user must provide it. */
703
- headers: Schema4.Record({ key: Schema4.String, value: Schema4.NullOr(Schema4.String) }),
768
+ headers: Schema5.Record({ key: Schema5.String, value: Schema5.NullOr(Schema5.String) }),
704
769
  /** Which headers should be stored as secrets */
705
- secretHeaders: Schema4.Array(Schema4.String)
770
+ secretHeaders: Schema5.Array(Schema5.String)
771
+ }) {
772
+ };
773
+ var PreviewOperation = class extends Schema5.Class("PreviewOperation")({
774
+ operationId: Schema5.String,
775
+ method: HttpMethod,
776
+ path: Schema5.String,
777
+ summary: Schema5.optionalWith(Schema5.String, { as: "Option" }),
778
+ tags: Schema5.Array(Schema5.String),
779
+ deprecated: Schema5.Boolean
706
780
  }) {
707
781
  };
708
- var SpecPreview = class extends Schema4.Class("SpecPreview")({
709
- title: Schema4.optionalWith(Schema4.String, { as: "Option" }),
710
- version: Schema4.optionalWith(Schema4.String, { as: "Option" }),
782
+ var SpecPreview = class extends Schema5.Class("SpecPreview")({
783
+ title: Schema5.optionalWith(Schema5.String, { as: "Option" }),
784
+ version: Schema5.optionalWith(Schema5.String, { as: "Option" }),
711
785
  /** Reuses ServerInfo from extraction */
712
- servers: Schema4.Array(Schema4.Unknown),
713
- operationCount: Schema4.Number,
714
- tags: Schema4.Array(Schema4.String),
715
- securitySchemes: Schema4.Array(SecurityScheme),
786
+ servers: Schema5.Array(Schema5.Unknown),
787
+ operationCount: Schema5.Number,
788
+ /** Lightweight operation list for the add-source UI */
789
+ operations: Schema5.Array(PreviewOperation),
790
+ tags: Schema5.Array(Schema5.String),
791
+ securitySchemes: Schema5.Array(SecurityScheme),
716
792
  /** Valid auth strategies (each is a set of schemes used together) */
717
- authStrategies: Schema4.Array(AuthStrategy),
793
+ authStrategies: Schema5.Array(AuthStrategy),
718
794
  /** Pre-built header presets derived from auth strategies */
719
- headerPresets: Schema4.Array(HeaderPreset)
795
+ headerPresets: Schema5.Array(HeaderPreset)
720
796
  }) {
721
797
  };
722
798
  var extractSecuritySchemes = (rawSchemes) => Object.entries(rawSchemes).flatMap(([name, schemeOrRef]) => {
@@ -730,9 +806,7 @@ var extractSecuritySchemes = (rawSchemes) => Object.entries(rawSchemes).flatMap(
730
806
  name,
731
807
  type,
732
808
  scheme: Option4.fromNullable(scheme.scheme),
733
- in: Option4.fromNullable(
734
- scheme.in
735
- ),
809
+ in: Option4.fromNullable(scheme.in),
736
810
  headerName: Option4.fromNullable(scheme.name),
737
811
  description: Option4.fromNullable(scheme.description)
738
812
  })
@@ -767,13 +841,9 @@ var buildHeaderPresets = (schemes, strategies) => {
767
841
  }
768
842
  }
769
843
  if (Object.keys(headers).length === 0 && resolved.length > 0) {
770
- return [
771
- new HeaderPreset({ label: labelParts.join(" + "), headers: {}, secretHeaders: [] })
772
- ];
844
+ return [new HeaderPreset({ label: labelParts.join(" + "), headers: {}, secretHeaders: [] })];
773
845
  }
774
- return [
775
- new HeaderPreset({ label: labelParts.join(" + "), headers, secretHeaders })
776
- ];
846
+ return [new HeaderPreset({ label: labelParts.join(" + "), headers, secretHeaders })];
777
847
  });
778
848
  };
779
849
  var collectTags = (result) => {
@@ -786,9 +856,7 @@ var collectTags = (result) => {
786
856
  var previewSpec = Effect5.fn("OpenApi.previewSpec")(function* (specText) {
787
857
  const doc = yield* parse(specText);
788
858
  const result = yield* extract(doc);
789
- const securitySchemes = extractSecuritySchemes(
790
- doc.components?.securitySchemes ?? {}
791
- );
859
+ const securitySchemes = extractSecuritySchemes(doc.components?.securitySchemes ?? {});
792
860
  const rawSecurity = doc.security ?? [];
793
861
  const authStrategies = rawSecurity.map(
794
862
  (entry) => new AuthStrategy({ schemes: Object.keys(entry) })
@@ -798,6 +866,16 @@ var previewSpec = Effect5.fn("OpenApi.previewSpec")(function* (specText) {
798
866
  version: result.version,
799
867
  servers: result.servers,
800
868
  operationCount: result.operations.length,
869
+ operations: result.operations.map(
870
+ (op) => new PreviewOperation({
871
+ operationId: op.operationId,
872
+ method: op.method,
873
+ path: op.pathTemplate,
874
+ summary: op.summary,
875
+ tags: op.tags,
876
+ deprecated: op.deprecated
877
+ })
878
+ ),
801
879
  tags: collectTags(result),
802
880
  securitySchemes,
803
881
  authStrategies,
@@ -806,7 +884,7 @@ var previewSpec = Effect5.fn("OpenApi.previewSpec")(function* (specText) {
806
884
  });
807
885
 
808
886
  // src/sdk/plugin.ts
809
- import { Effect as Effect6, Option as Option5, Schema as Schema5 } from "effect";
887
+ import { Effect as Effect6, Option as Option5, Schema as Schema6 } from "effect";
810
888
  import { FetchHttpClient } from "@effect/platform";
811
889
  import {
812
890
  Source,
@@ -815,7 +893,7 @@ import {
815
893
  registerRuntimeTools,
816
894
  runtimeTool,
817
895
  ToolId
818
- } from "@executor-js/sdk/core";
896
+ } from "@executor-js/sdk";
819
897
 
820
898
  // src/sdk/definitions.ts
821
899
  var splitWords = (value) => value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z0-9]+)/g, "$1 $2").replace(/[^a-zA-Z0-9]+/g, " ").trim().split(/\s+/).filter((part) => part.length > 0);
@@ -937,26 +1015,22 @@ var compileToolDefinitions = (operations) => {
937
1015
  operation: op
938
1016
  };
939
1017
  });
940
- return resolveCollisions(raw).sort(
941
- (a, b) => a.toolPath.localeCompare(b.toolPath)
942
- );
1018
+ return resolveCollisions(raw).sort((a, b) => a.toolPath.localeCompare(b.toolPath));
943
1019
  };
944
1020
 
945
1021
  // src/sdk/plugin.ts
946
- var PreviewSpecInputSchema = Schema5.Struct({
947
- spec: Schema5.String
1022
+ var PreviewSpecInputSchema = Schema6.Struct({
1023
+ spec: Schema6.String
948
1024
  });
949
- var AddSourceInputSchema = Schema5.Struct({
950
- spec: Schema5.String,
951
- baseUrl: Schema5.optional(Schema5.String),
952
- namespace: Schema5.optional(Schema5.String),
953
- headers: Schema5.optional(
954
- Schema5.Record({ key: Schema5.String, value: HeaderValue })
955
- )
1025
+ var AddSourceInputSchema = Schema6.Struct({
1026
+ spec: Schema6.String,
1027
+ baseUrl: Schema6.optional(Schema6.String),
1028
+ namespace: Schema6.optional(Schema6.String),
1029
+ headers: Schema6.optional(Schema6.Record({ key: Schema6.String, value: HeaderValue }))
956
1030
  });
957
- var AddSourceOutputSchema = Schema5.Struct({
958
- sourceId: Schema5.String,
959
- toolCount: Schema5.Number
1031
+ var AddSourceOutputSchema = Schema6.Struct({
1032
+ sourceId: Schema6.String,
1033
+ toolCount: Schema6.Number
960
1034
  });
961
1035
  var normalizeOpenApiRefs = (node) => {
962
1036
  if (node == null || typeof node !== "object") return node;
@@ -988,10 +1062,7 @@ var toRegistration = (def, namespace) => {
988
1062
  const op = def.operation;
989
1063
  const description = Option5.getOrElse(
990
1064
  op.description,
991
- () => Option5.getOrElse(
992
- op.summary,
993
- () => `${op.method.toUpperCase()} ${op.pathTemplate}`
994
- )
1065
+ () => Option5.getOrElse(op.summary, () => `${op.method.toUpperCase()} ${op.pathTemplate}`)
995
1066
  );
996
1067
  return {
997
1068
  id: ToolId.make(`${namespace}.${def.toolPath}`),
@@ -1033,9 +1104,11 @@ var openApiPlugin = (options) => {
1033
1104
  id: s.namespace,
1034
1105
  name: s.name,
1035
1106
  kind: "openapi",
1107
+ url: s.config.baseUrl,
1036
1108
  runtime: false,
1037
1109
  canRemove: true,
1038
- canRefresh: false
1110
+ canRefresh: false,
1111
+ canEdit: true
1039
1112
  })
1040
1113
  )
1041
1114
  )
@@ -1050,13 +1123,9 @@ var openApiPlugin = (options) => {
1050
1123
  if (!trimmed) return null;
1051
1124
  const parsed = yield* Effect6.try(() => new URL(trimmed)).pipe(Effect6.option);
1052
1125
  if (parsed._tag === "None") return null;
1053
- const doc = yield* parse(trimmed).pipe(
1054
- Effect6.catchAll(() => Effect6.succeed(null))
1055
- );
1126
+ const doc = yield* parse(trimmed).pipe(Effect6.catchAll(() => Effect6.succeed(null)));
1056
1127
  if (!doc) return null;
1057
- const result = yield* extract(doc).pipe(
1058
- Effect6.catchAll(() => Effect6.succeed(null))
1059
- );
1128
+ const result = yield* extract(doc).pipe(Effect6.catchAll(() => Effect6.succeed(null)));
1060
1129
  if (!result) return null;
1061
1130
  const namespace = Option5.getOrElse(result.title, () => "api").toLowerCase().replace(/[^a-z0-9]+/g, "_");
1062
1131
  const name = Option5.getOrElse(result.title, () => namespace);
@@ -1086,19 +1155,16 @@ var openApiPlugin = (options) => {
1086
1155
  headers: config.headers ?? {}
1087
1156
  });
1088
1157
  const definitions = compileToolDefinitions(result.operations);
1089
- const registrations = definitions.map(
1090
- (def) => toRegistration(def, namespace)
1091
- );
1158
+ const registrations = definitions.map((def) => toRegistration(def, namespace));
1092
1159
  yield* operationStore.put(
1093
1160
  definitions.map((def) => ({
1094
1161
  toolId: ToolId.make(`${namespace}.${def.toolPath}`),
1095
1162
  namespace,
1096
- binding: toBinding(def),
1097
- config: invocationConfig
1163
+ binding: toBinding(def)
1098
1164
  }))
1099
1165
  );
1100
1166
  yield* ctx.tools.register(registrations);
1101
- const sourceName = Option5.getOrElse(result.title, () => namespace);
1167
+ const sourceName = config.name ?? Option5.getOrElse(result.title, () => namespace);
1102
1168
  yield* operationStore.putSource({
1103
1169
  namespace,
1104
1170
  name: sourceName,
@@ -1107,7 +1173,8 @@ var openApiPlugin = (options) => {
1107
1173
  baseUrl: config.baseUrl,
1108
1174
  namespace: config.namespace,
1109
1175
  headers: config.headers
1110
- }
1176
+ },
1177
+ invocationConfig
1111
1178
  });
1112
1179
  return { sourceId: namespace, toolCount: registrations.length };
1113
1180
  });
@@ -1142,15 +1209,33 @@ var openApiPlugin = (options) => {
1142
1209
  return {
1143
1210
  extension: {
1144
1211
  previewSpec: (specText) => previewSpec(specText),
1145
- addSpec: (config) => addSpecInternal(config).pipe(
1146
- Effect6.map(({ toolCount }) => ({ toolCount }))
1147
- ),
1212
+ addSpec: (config) => addSpecInternal(config).pipe(Effect6.map(({ toolCount }) => ({ toolCount }))),
1148
1213
  removeSpec: (namespace) => Effect6.gen(function* () {
1149
1214
  const toolIds = yield* operationStore.removeByNamespace(namespace);
1150
1215
  if (toolIds.length > 0) {
1151
1216
  yield* ctx.tools.unregister(toolIds);
1152
1217
  }
1153
1218
  yield* operationStore.removeSource(namespace);
1219
+ }),
1220
+ getSource: (namespace) => operationStore.getSource(namespace),
1221
+ updateSource: (namespace, input) => Effect6.gen(function* () {
1222
+ const existing = yield* operationStore.getSource(namespace);
1223
+ if (!existing) return;
1224
+ const updatedConfig = {
1225
+ ...existing.config,
1226
+ ...input.baseUrl !== void 0 ? { baseUrl: input.baseUrl } : {},
1227
+ ...input.headers !== void 0 ? { headers: input.headers } : {}
1228
+ };
1229
+ const newInvocationConfig = new InvocationConfig({
1230
+ baseUrl: updatedConfig.baseUrl ?? existing.invocationConfig.baseUrl,
1231
+ headers: updatedConfig.headers ?? {}
1232
+ });
1233
+ yield* operationStore.putSource({
1234
+ namespace,
1235
+ name: input.name?.trim() || existing.name,
1236
+ config: updatedConfig,
1237
+ invocationConfig: newInvocationConfig
1238
+ });
1154
1239
  })
1155
1240
  },
1156
1241
  close: () => runtimeTools.close()
@@ -1186,8 +1271,9 @@ export {
1186
1271
  SecurityScheme,
1187
1272
  AuthStrategy,
1188
1273
  HeaderPreset,
1274
+ PreviewOperation,
1189
1275
  SpecPreview,
1190
1276
  previewSpec,
1191
1277
  openApiPlugin
1192
1278
  };
1193
- //# sourceMappingURL=chunk-C57CSNPZ.js.map
1279
+ //# sourceMappingURL=chunk-KPGROAQO.js.map