@executor-js/plugin-openapi 1.4.29 → 1.4.30

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 (45) hide show
  1. package/dist/{AddOpenApiSource-FLMNI742.js → AddOpenApiSource-KSOMPQ2R.js} +4 -4
  2. package/dist/{EditOpenApiSource-I4NIGIIJ.js → EditOpenApiSource-AOA7APR2.js} +301 -192
  3. package/dist/EditOpenApiSource-AOA7APR2.js.map +1 -0
  4. package/dist/{OpenApiSourceSummary-CM46DB4L.js → OpenApiSourceSummary-Y3S6ZBOZ.js} +4 -4
  5. package/dist/OpenApiSourceSummary-Y3S6ZBOZ.js.map +1 -0
  6. package/dist/api/group.d.ts +124 -118
  7. package/dist/api/index.d.ts +148 -369
  8. package/dist/chunk-BB5IAKRG.js +136 -0
  9. package/dist/chunk-BB5IAKRG.js.map +1 -0
  10. package/dist/{chunk-E7PZ2QGD.js → chunk-EOXXE5DG.js} +17 -455
  11. package/dist/chunk-EOXXE5DG.js.map +1 -0
  12. package/dist/{chunk-OZ67JNID.js → chunk-NIKLYJ3X.js} +830 -319
  13. package/dist/chunk-NIKLYJ3X.js.map +1 -0
  14. package/dist/{chunk-TGDT6QCH.js → chunk-YJMXYKYX.js} +178 -117
  15. package/dist/chunk-YJMXYKYX.js.map +1 -0
  16. package/dist/{chunk-GFQUEZUW.js → chunk-ZZBTLFTA.js} +78 -93
  17. package/dist/chunk-ZZBTLFTA.js.map +1 -0
  18. package/dist/client.js +7 -137
  19. package/dist/client.js.map +1 -1
  20. package/dist/core.js +5 -10
  21. package/dist/index.js +3 -2
  22. package/dist/react/atoms.d.ts +83 -223
  23. package/dist/react/client.d.ts +123 -117
  24. package/dist/sdk/credential-status.d.ts +3 -3
  25. package/dist/sdk/extract.d.ts +19 -19
  26. package/dist/sdk/index.d.ts +2 -2
  27. package/dist/sdk/invoke.d.ts +7 -7
  28. package/dist/sdk/parse.d.ts +2 -3
  29. package/dist/sdk/plugin.d.ts +181 -275
  30. package/dist/sdk/preview.d.ts +12 -12
  31. package/dist/sdk/source-contracts.d.ts +55 -0
  32. package/dist/sdk/store.d.ts +6 -269
  33. package/dist/sdk/types.d.ts +16 -65
  34. package/dist/testing/index.d.ts +149 -11
  35. package/dist/testing.js +419 -33
  36. package/dist/testing.js.map +1 -1
  37. package/dist/testing.test.d.ts +1 -0
  38. package/package.json +3 -4
  39. package/dist/EditOpenApiSource-I4NIGIIJ.js.map +0 -1
  40. package/dist/OpenApiSourceSummary-CM46DB4L.js.map +0 -1
  41. package/dist/chunk-E7PZ2QGD.js.map +0 -1
  42. package/dist/chunk-GFQUEZUW.js.map +0 -1
  43. package/dist/chunk-OZ67JNID.js.map +0 -1
  44. package/dist/chunk-TGDT6QCH.js.map +0 -1
  45. /package/dist/{AddOpenApiSource-FLMNI742.js.map → AddOpenApiSource-KSOMPQ2R.js.map} +0 -0
@@ -1,23 +1,20 @@
1
+ import {
2
+ openApiPresets
3
+ } from "./chunk-BB5IAKRG.js";
1
4
  import {
2
5
  ConfiguredHeaderBinding,
3
- ConfiguredHeaderValue,
4
6
  HeaderValue,
5
7
  InvocationResult,
6
8
  OAuth2SourceConfig,
7
- OpenApiCredentialInput,
8
9
  OpenApiExtractionError,
9
10
  OpenApiInvocationError,
10
11
  OpenApiOAuthError,
11
- OpenApiSourceBindingRef,
12
12
  OperationBinding,
13
13
  extract,
14
- makeDefaultOpenapiStore,
15
- openapiSchema,
16
14
  parse,
17
15
  previewSpec,
18
- resolveBaseUrl,
19
16
  resolveSpecText
20
- } from "./chunk-E7PZ2QGD.js";
17
+ } from "./chunk-EOXXE5DG.js";
21
18
 
22
19
  // src/sdk/invoke.ts
23
20
  import { Effect, Layer, Option } from "effect";
@@ -417,13 +414,236 @@ var annotationsForOperation = (method, pathTemplate) => {
417
414
  };
418
415
  };
419
416
 
420
- // src/sdk/plugin.ts
417
+ // src/sdk/store.ts
421
418
  import { Effect as Effect2, Option as Option2, Predicate, Schema } from "effect";
419
+ var openapiSchema = {};
420
+ var SOURCE_COLLECTION = "source";
421
+ var OPERATION_COLLECTION = "operation";
422
+ var encodeBinding = Schema.encodeSync(OperationBinding);
423
+ var decodeBinding = Schema.decodeUnknownSync(OperationBinding);
424
+ var decodeBindingJson = Schema.decodeUnknownSync(Schema.fromJsonString(OperationBinding));
425
+ var decodeOAuth2SourceConfigOption = Schema.decodeUnknownOption(OAuth2SourceConfig);
426
+ var decodeOAuth2SourceConfigJsonOption = Schema.decodeUnknownOption(
427
+ Schema.fromJsonString(OAuth2SourceConfig)
428
+ );
429
+ var encodeOAuth2SourceConfig = Schema.encodeSync(OAuth2SourceConfig);
430
+ var NullableString = Schema.NullOr(Schema.String);
431
+ var OptionalNullableString = Schema.optional(NullableString);
432
+ var ConfiguredHeaderBindingStorage = Schema.Struct({
433
+ kind: Schema.Literal("binding"),
434
+ slot: Schema.String,
435
+ prefix: OptionalNullableString
436
+ });
437
+ var ConfiguredHeaderValueStorage = Schema.Union([Schema.String, ConfiguredHeaderBindingStorage]);
438
+ var ConfiguredHeaderMapStorage = Schema.Record(Schema.String, ConfiguredHeaderValueStorage);
439
+ var SpecFetchCredentialsStorage = Schema.Struct({
440
+ headers: Schema.optional(ConfiguredHeaderMapStorage),
441
+ queryParams: Schema.optional(ConfiguredHeaderMapStorage)
442
+ });
443
+ var SourceConfigStorage = Schema.Struct({
444
+ spec: Schema.String,
445
+ sourceUrl: Schema.optional(Schema.String),
446
+ baseUrl: Schema.optional(Schema.String),
447
+ namespace: Schema.optional(Schema.String),
448
+ headers: Schema.optional(ConfiguredHeaderMapStorage),
449
+ queryParams: Schema.optional(ConfiguredHeaderMapStorage),
450
+ specFetchCredentials: Schema.optional(SpecFetchCredentialsStorage),
451
+ oauth2: Schema.optional(Schema.Unknown)
452
+ });
453
+ var SourceStorage = Schema.Struct({
454
+ namespace: Schema.String,
455
+ scope: Schema.String,
456
+ name: Schema.String,
457
+ config: SourceConfigStorage
458
+ });
459
+ var OperationStorage = Schema.Struct({
460
+ toolId: Schema.String,
461
+ sourceId: Schema.String,
462
+ binding: Schema.Unknown
463
+ });
464
+ var decodeSourceStorage = Schema.decodeUnknownOption(SourceStorage);
465
+ var decodeOperationStorage = Schema.decodeUnknownOption(OperationStorage);
466
+ var toJsonRecord = (value) => value;
467
+ var normalizeStoredOAuth2 = (value) => {
468
+ if (value == null) return void 0;
469
+ const sourceConfig = typeof value === "string" ? decodeOAuth2SourceConfigJsonOption(value) : decodeOAuth2SourceConfigOption(value);
470
+ if (Option2.isSome(sourceConfig)) return sourceConfig.value;
471
+ return void 0;
472
+ };
473
+ var normalizeConfiguredMap = (values) => {
474
+ if (!values) return void 0;
475
+ const normalized = {};
476
+ for (const [name, value] of Object.entries(values)) {
477
+ if (typeof value === "string") {
478
+ normalized[name] = value;
479
+ } else {
480
+ normalized[name] = value.prefix != null ? ConfiguredHeaderBinding.make({
481
+ kind: "binding",
482
+ slot: value.slot,
483
+ prefix: value.prefix
484
+ }) : ConfiguredHeaderBinding.make({
485
+ kind: "binding",
486
+ slot: value.slot
487
+ });
488
+ }
489
+ }
490
+ return normalized;
491
+ };
492
+ var encodeSourceConfig = (config) => ({
493
+ spec: config.spec,
494
+ ...config.sourceUrl ? { sourceUrl: config.sourceUrl } : {},
495
+ ...config.baseUrl ? { baseUrl: config.baseUrl } : {},
496
+ ...config.namespace ? { namespace: config.namespace } : {},
497
+ ...config.headers ? { headers: config.headers } : {},
498
+ ...config.queryParams ? { queryParams: config.queryParams } : {},
499
+ ...config.specFetchCredentials ? { specFetchCredentials: config.specFetchCredentials } : {},
500
+ ...config.oauth2 ? { oauth2: toJsonRecord(encodeOAuth2SourceConfig(config.oauth2)) } : {}
501
+ });
502
+ var rowToSource = (row) => {
503
+ const decoded = decodeSourceStorage(row.data);
504
+ if (Option2.isNone(decoded)) return null;
505
+ const stored = decoded.value;
506
+ const oauth2 = normalizeStoredOAuth2(stored.config.oauth2);
507
+ return {
508
+ namespace: stored.namespace,
509
+ scope: stored.scope,
510
+ name: stored.name,
511
+ config: {
512
+ spec: stored.config.spec,
513
+ sourceUrl: stored.config.sourceUrl,
514
+ baseUrl: stored.config.baseUrl,
515
+ namespace: stored.config.namespace,
516
+ headers: normalizeConfiguredMap(stored.config.headers),
517
+ queryParams: normalizeConfiguredMap(stored.config.queryParams),
518
+ specFetchCredentials: stored.config.specFetchCredentials ? {
519
+ headers: normalizeConfiguredMap(stored.config.specFetchCredentials.headers),
520
+ queryParams: normalizeConfiguredMap(stored.config.specFetchCredentials.queryParams)
521
+ } : void 0,
522
+ oauth2
523
+ }
524
+ };
525
+ };
526
+ var rowToOperation = (row) => {
527
+ const decoded = decodeOperationStorage(row.data);
528
+ if (Option2.isNone(decoded)) return null;
529
+ const operation = decoded.value;
530
+ return {
531
+ toolId: operation.toolId,
532
+ sourceId: operation.sourceId,
533
+ binding: decodeBinding(
534
+ typeof operation.binding === "string" ? decodeBindingJson(operation.binding) : operation.binding
535
+ )
536
+ };
537
+ };
538
+ var makeDefaultOpenapiStore = ({
539
+ pluginStorage
540
+ }) => {
541
+ const sourceData = (source) => ({
542
+ namespace: source.namespace,
543
+ scope: source.scope,
544
+ name: source.name,
545
+ config: encodeSourceConfig(source.config)
546
+ });
547
+ const operationData = (operation) => ({
548
+ toolId: operation.toolId,
549
+ sourceId: operation.sourceId,
550
+ binding: toJsonRecord(encodeBinding(operation.binding))
551
+ });
552
+ const listOperationRowsForSourceScope = (sourceId, scope) => pluginStorage.list({
553
+ collection: OPERATION_COLLECTION,
554
+ keyPrefix: `${sourceId}.`
555
+ }).pipe(
556
+ Effect2.map(
557
+ (rows) => rows.filter(
558
+ (row) => String(row.scopeId) === scope && rowToOperation(row)?.sourceId === sourceId
559
+ )
560
+ )
561
+ );
562
+ const removeOperationsForSourceScope = (sourceId, scope) => Effect2.gen(function* () {
563
+ const rows = yield* listOperationRowsForSourceScope(sourceId, scope);
564
+ for (const row of rows) {
565
+ yield* pluginStorage.remove({
566
+ scope,
567
+ collection: OPERATION_COLLECTION,
568
+ key: row.key
569
+ });
570
+ }
571
+ });
572
+ const deleteSource = (namespace, scope) => Effect2.gen(function* () {
573
+ yield* removeOperationsForSourceScope(namespace, scope);
574
+ yield* pluginStorage.remove({
575
+ scope,
576
+ collection: SOURCE_COLLECTION,
577
+ key: namespace
578
+ });
579
+ });
580
+ return {
581
+ upsertSource: (input, operations) => Effect2.gen(function* () {
582
+ yield* deleteSource(input.namespace, input.scope);
583
+ yield* pluginStorage.put({
584
+ scope: input.scope,
585
+ collection: SOURCE_COLLECTION,
586
+ key: input.namespace,
587
+ data: sourceData(input)
588
+ });
589
+ for (const operation of operations) {
590
+ yield* pluginStorage.put({
591
+ scope: input.scope,
592
+ collection: OPERATION_COLLECTION,
593
+ key: operation.toolId,
594
+ data: operationData(operation)
595
+ });
596
+ }
597
+ }),
598
+ updateSourceMeta: (namespace, scope, patch) => Effect2.gen(function* () {
599
+ const existing = yield* pluginStorage.getAtScope({
600
+ scope,
601
+ collection: SOURCE_COLLECTION,
602
+ key: namespace
603
+ });
604
+ if (!existing) return;
605
+ const source = rowToSource(existing);
606
+ if (!source) return;
607
+ const next = {
608
+ ...source,
609
+ name: patch.name?.trim() || source.name,
610
+ config: {
611
+ ...source.config,
612
+ ...patch.baseUrl !== void 0 ? { baseUrl: patch.baseUrl } : {},
613
+ ...patch.headers !== void 0 ? { headers: patch.headers } : {},
614
+ ...patch.queryParams !== void 0 ? { queryParams: patch.queryParams } : {},
615
+ ...patch.specFetchCredentials !== void 0 ? { specFetchCredentials: patch.specFetchCredentials } : {},
616
+ ...patch.oauth2 !== void 0 ? { oauth2: patch.oauth2 } : {}
617
+ }
618
+ };
619
+ yield* pluginStorage.put({
620
+ scope,
621
+ collection: SOURCE_COLLECTION,
622
+ key: namespace,
623
+ data: sourceData(next)
624
+ });
625
+ }),
626
+ getSource: (namespace, scope) => pluginStorage.getAtScope({ scope, collection: SOURCE_COLLECTION, key: namespace }).pipe(Effect2.map((row) => row ? rowToSource(row) : null)),
627
+ listSources: () => pluginStorage.list({ collection: SOURCE_COLLECTION }).pipe(Effect2.map((rows) => rows.map(rowToSource).filter(Predicate.isNotNull))),
628
+ getOperationByToolId: (toolId, scope) => pluginStorage.getAtScope({ scope, collection: OPERATION_COLLECTION, key: toolId }).pipe(Effect2.map((row) => row ? rowToOperation(row) : null)),
629
+ listOperationsBySource: (sourceId, scope) => listOperationRowsForSourceScope(sourceId, scope).pipe(
630
+ Effect2.map((rows) => rows.map(rowToOperation).filter(Predicate.isNotNull))
631
+ ),
632
+ removeSource: (namespace, scope) => deleteSource(namespace, scope)
633
+ };
634
+ };
635
+
636
+ // src/sdk/plugin.ts
637
+ import { Effect as Effect3, Option as Option3, Predicate as Predicate2, Schema as Schema2 } from "effect";
422
638
  import {
639
+ ConnectionId,
640
+ CredentialBindingRef,
423
641
  ScopeId,
424
642
  SecretId,
425
643
  SourceDetectionResult,
426
644
  StorageError,
645
+ ToolResult,
646
+ defaultSourceInstallScopeId,
427
647
  definePlugin,
428
648
  tool,
429
649
  resolveSecretBackedMap
@@ -556,46 +776,313 @@ var compileToolDefinitions = (operations) => {
556
776
  };
557
777
 
558
778
  // src/sdk/plugin.ts
559
- var PreviewSpecInputSchema = Schema.Struct({
560
- spec: Schema.String,
561
- specFetchCredentials: Schema.optional(
562
- Schema.Struct({
563
- headers: Schema.optional(Schema.Record(Schema.String, HeaderValue)),
564
- queryParams: Schema.optional(Schema.Record(Schema.String, HeaderValue))
779
+ var STRINGIFIED_BODY_CAP = 1024;
780
+ var UpstreamMessageBody = Schema2.Struct({ message: Schema2.String });
781
+ var UpstreamErrorMessageBody = Schema2.Struct({ errorMessage: Schema2.String });
782
+ var UpstreamNestedErrorBody = Schema2.Struct({ error: UpstreamMessageBody });
783
+ var UpstreamErrorsArrayBody = Schema2.Struct({
784
+ errors: Schema2.Array(
785
+ Schema2.Struct({
786
+ detail: Schema2.optional(Schema2.String),
787
+ message: Schema2.optional(Schema2.String),
788
+ title: Schema2.optional(Schema2.String)
789
+ })
790
+ )
791
+ });
792
+ var UpstreamDescriptionBody = Schema2.Struct({
793
+ detail: Schema2.optional(Schema2.String),
794
+ title: Schema2.optional(Schema2.String),
795
+ description: Schema2.optional(Schema2.String)
796
+ });
797
+ var decodeUpstreamMessageBody = Schema2.decodeUnknownOption(UpstreamMessageBody);
798
+ var decodeUpstreamErrorMessageBody = Schema2.decodeUnknownOption(UpstreamErrorMessageBody);
799
+ var decodeUpstreamNestedErrorBody = Schema2.decodeUnknownOption(UpstreamNestedErrorBody);
800
+ var decodeUpstreamErrorsArrayBody = Schema2.decodeUnknownOption(UpstreamErrorsArrayBody);
801
+ var decodeUpstreamDescriptionBody = Schema2.decodeUnknownOption(UpstreamDescriptionBody);
802
+ var clampedStringify = (value) => {
803
+ let s;
804
+ try {
805
+ s = JSON.stringify(value);
806
+ } catch {
807
+ s = String(value);
808
+ }
809
+ return s.length > STRINGIFIED_BODY_CAP ? `${s.slice(0, STRINGIFIED_BODY_CAP)}\u2026` : s;
810
+ };
811
+ var firstNonEmpty = (...values) => values.find((value) => value !== void 0 && value.length > 0);
812
+ var extractUpstreamMessage = (body, status) => {
813
+ if (typeof body === "string") {
814
+ return body.length > 0 ? body : `Upstream returned HTTP ${status}`;
815
+ }
816
+ const nested = Option3.getOrUndefined(decodeUpstreamNestedErrorBody(body));
817
+ const messageBody = Option3.getOrUndefined(decodeUpstreamMessageBody(body));
818
+ const errorMessageBody = Option3.getOrUndefined(decodeUpstreamErrorMessageBody(body));
819
+ const errorsBody = Option3.getOrUndefined(decodeUpstreamErrorsArrayBody(body));
820
+ const descriptionBody = Option3.getOrUndefined(decodeUpstreamDescriptionBody(body));
821
+ const arrayMessage = errorsBody?.errors.map(
822
+ ({ detail, message: upstreamMessage, title }) => firstNonEmpty(detail, upstreamMessage, title)
823
+ ).find((message2) => message2 !== void 0);
824
+ const message = firstNonEmpty(
825
+ nested?.error.message,
826
+ messageBody?.message,
827
+ errorMessageBody?.errorMessage,
828
+ arrayMessage,
829
+ descriptionBody?.detail,
830
+ descriptionBody?.title,
831
+ descriptionBody?.description
832
+ );
833
+ if (message !== void 0) return message;
834
+ if (body !== null && typeof body === "object") {
835
+ return clampedStringify(body);
836
+ }
837
+ return `Upstream returned HTTP ${status}`;
838
+ };
839
+ var PreviewSpecInputSchema = Schema2.Struct({
840
+ spec: Schema2.String,
841
+ specFetchCredentials: Schema2.optional(
842
+ Schema2.Struct({
843
+ headers: Schema2.optional(Schema2.Record(Schema2.String, HeaderValue)),
844
+ queryParams: Schema2.optional(Schema2.Record(Schema2.String, HeaderValue))
565
845
  })
566
846
  )
567
847
  });
568
- var OpenApiHeaderInputSchema = Schema.Union([HeaderValue, ConfiguredHeaderValue]);
848
+ var StaticPreviewServerVariableSchema = Schema2.Struct({
849
+ default: Schema2.String,
850
+ enum: Schema2.NullOr(Schema2.Array(Schema2.String)),
851
+ description: Schema2.NullOr(Schema2.String)
852
+ });
853
+ var StaticPreviewServerSchema = Schema2.Struct({
854
+ url: Schema2.String,
855
+ description: Schema2.NullOr(Schema2.String),
856
+ variables: Schema2.NullOr(Schema2.Record(Schema2.String, StaticPreviewServerVariableSchema))
857
+ });
858
+ var StaticPreviewOAuthAuthorizationCodeFlowSchema = Schema2.Struct({
859
+ authorizationUrl: Schema2.String,
860
+ tokenUrl: Schema2.String,
861
+ refreshUrl: Schema2.NullOr(Schema2.String),
862
+ scopes: Schema2.Record(Schema2.String, Schema2.String)
863
+ });
864
+ var StaticPreviewOAuthClientCredentialsFlowSchema = Schema2.Struct({
865
+ tokenUrl: Schema2.String,
866
+ refreshUrl: Schema2.NullOr(Schema2.String),
867
+ scopes: Schema2.Record(Schema2.String, Schema2.String)
868
+ });
869
+ var StaticPreviewOAuthFlowsSchema = Schema2.Struct({
870
+ authorizationCode: Schema2.NullOr(StaticPreviewOAuthAuthorizationCodeFlowSchema),
871
+ clientCredentials: Schema2.NullOr(StaticPreviewOAuthClientCredentialsFlowSchema)
872
+ });
873
+ var StaticPreviewSecuritySchemeSchema = Schema2.Struct({
874
+ name: Schema2.String,
875
+ type: Schema2.Literals(["http", "apiKey", "oauth2", "openIdConnect"]),
876
+ scheme: Schema2.NullOr(Schema2.String),
877
+ bearerFormat: Schema2.NullOr(Schema2.String),
878
+ in: Schema2.NullOr(Schema2.Literals(["header", "query", "cookie"])),
879
+ headerName: Schema2.NullOr(Schema2.String),
880
+ description: Schema2.NullOr(Schema2.String),
881
+ flows: Schema2.NullOr(StaticPreviewOAuthFlowsSchema),
882
+ openIdConnectUrl: Schema2.NullOr(Schema2.String)
883
+ });
884
+ var StaticPreviewOAuth2PresetSchema = Schema2.Struct({
885
+ label: Schema2.String,
886
+ securitySchemeName: Schema2.String,
887
+ flow: Schema2.Literals(["authorizationCode", "clientCredentials"]),
888
+ authorizationUrl: Schema2.NullOr(Schema2.String),
889
+ tokenUrl: Schema2.String,
890
+ refreshUrl: Schema2.NullOr(Schema2.String),
891
+ scopes: Schema2.Record(Schema2.String, Schema2.String)
892
+ });
893
+ var StaticPreviewSpecOutputSchema = Schema2.Struct({
894
+ title: Schema2.NullOr(Schema2.String),
895
+ version: Schema2.NullOr(Schema2.String),
896
+ servers: Schema2.Array(StaticPreviewServerSchema),
897
+ operationCount: Schema2.Number,
898
+ tags: Schema2.Array(Schema2.String),
899
+ securitySchemes: Schema2.Array(StaticPreviewSecuritySchemeSchema),
900
+ authStrategies: Schema2.Array(Schema2.Struct({ schemes: Schema2.Array(Schema2.String) })),
901
+ headerPresets: Schema2.Array(
902
+ Schema2.Struct({
903
+ label: Schema2.String,
904
+ headers: Schema2.Record(Schema2.String, Schema2.NullOr(Schema2.String)),
905
+ secretHeaders: Schema2.Array(Schema2.String)
906
+ })
907
+ ),
908
+ oauth2Presets: Schema2.Array(StaticPreviewOAuth2PresetSchema)
909
+ });
910
+ var OpenApiSpecInputSchema = Schema2.Union([
911
+ Schema2.Struct({ kind: Schema2.Literal("url"), url: Schema2.String }),
912
+ Schema2.Struct({ kind: Schema2.Literal("blob"), value: Schema2.String })
913
+ ]);
914
+ var OpenApiSecretShapeInputSchema = Schema2.Struct({
915
+ kind: Schema2.Literal("secret"),
916
+ prefix: Schema2.optional(Schema2.String)
917
+ });
918
+ var OpenApiConfiguredValueInputSchema = Schema2.Union([
919
+ Schema2.String,
920
+ OpenApiSecretShapeInputSchema
921
+ ]);
922
+ var OpenApiConfigureCredentialInputSchema = Schema2.Union([
923
+ Schema2.String,
924
+ Schema2.Struct({
925
+ kind: Schema2.Literal("text"),
926
+ text: Schema2.String,
927
+ prefix: Schema2.optional(Schema2.String)
928
+ }),
929
+ Schema2.Struct({
930
+ kind: Schema2.Literal("secret"),
931
+ secretId: Schema2.String,
932
+ secretScope: Schema2.optional(Schema2.String),
933
+ prefix: Schema2.optional(Schema2.String)
934
+ }),
935
+ Schema2.Struct({
936
+ kind: Schema2.Literal("connection"),
937
+ connectionId: Schema2.String
938
+ })
939
+ ]);
940
+ var OpenApiConfigureInputSchema = Schema2.Struct({
941
+ scope: Schema2.String,
942
+ name: Schema2.optional(Schema2.String),
943
+ baseUrl: Schema2.optional(Schema2.String),
944
+ headers: Schema2.optional(Schema2.Record(Schema2.String, OpenApiConfigureCredentialInputSchema)),
945
+ queryParams: Schema2.optional(Schema2.Record(Schema2.String, OpenApiConfigureCredentialInputSchema)),
946
+ specFetchCredentials: Schema2.optional(
947
+ Schema2.Struct({
948
+ headers: Schema2.optional(Schema2.Record(Schema2.String, OpenApiConfigureCredentialInputSchema)),
949
+ queryParams: Schema2.optional(
950
+ Schema2.Record(Schema2.String, OpenApiConfigureCredentialInputSchema)
951
+ )
952
+ })
953
+ ),
954
+ oauth2: Schema2.optional(
955
+ Schema2.Struct({
956
+ clientId: Schema2.optional(OpenApiConfigureCredentialInputSchema),
957
+ clientSecret: Schema2.optional(OpenApiConfigureCredentialInputSchema),
958
+ connection: Schema2.optional(OpenApiConfigureCredentialInputSchema)
959
+ })
960
+ ),
961
+ oauth2Source: Schema2.optional(OAuth2SourceConfig)
962
+ });
963
+ var OpenApiConfigureSourceInputSchema = Schema2.Struct({
964
+ source: Schema2.Struct({
965
+ id: Schema2.String,
966
+ scope: Schema2.String
967
+ }),
968
+ ...OpenApiConfigureInputSchema.fields
969
+ });
569
970
  var OpenApiOAuthInputSchema = OAuth2SourceConfig;
570
- var AddSourceInputSchema = Schema.Struct({
571
- scope: Schema.String,
572
- spec: Schema.String,
573
- name: Schema.optional(Schema.String),
574
- baseUrl: Schema.optional(Schema.String),
575
- namespace: Schema.optional(Schema.String),
576
- headers: Schema.optional(Schema.Record(Schema.String, OpenApiHeaderInputSchema)),
577
- queryParams: Schema.optional(Schema.Record(Schema.String, OpenApiCredentialInput)),
578
- oauth2: Schema.optional(OpenApiOAuthInputSchema),
579
- credentialTargetScope: Schema.optional(Schema.String),
580
- specFetchCredentials: Schema.optional(
581
- Schema.Struct({
582
- headers: Schema.optional(Schema.Record(Schema.String, HeaderValue)),
583
- queryParams: Schema.optional(Schema.Record(Schema.String, HeaderValue))
971
+ var AddSourceInputSchema = Schema2.Struct({
972
+ spec: OpenApiSpecInputSchema,
973
+ name: Schema2.String,
974
+ baseUrl: Schema2.String,
975
+ namespace: Schema2.String,
976
+ headers: Schema2.optional(Schema2.Record(Schema2.String, OpenApiConfiguredValueInputSchema)),
977
+ queryParams: Schema2.optional(Schema2.Record(Schema2.String, OpenApiConfiguredValueInputSchema)),
978
+ oauth2: Schema2.optional(OpenApiOAuthInputSchema),
979
+ specFetchCredentials: Schema2.optional(
980
+ Schema2.Struct({
981
+ headers: Schema2.optional(Schema2.Record(Schema2.String, OpenApiConfiguredValueInputSchema)),
982
+ queryParams: Schema2.optional(Schema2.Record(Schema2.String, OpenApiConfiguredValueInputSchema))
584
983
  })
585
984
  )
586
985
  });
587
- var AddSourceOutputSchema = Schema.Struct({
588
- sourceId: Schema.String,
589
- toolCount: Schema.Number
986
+ var AddSourceOutputSchema = Schema2.Struct({
987
+ sourceId: Schema2.String,
988
+ source: Schema2.Struct({
989
+ id: Schema2.String,
990
+ scope: Schema2.String
991
+ }),
992
+ toolCount: Schema2.Number
993
+ });
994
+ var GetSourceInputSchema = Schema2.Struct({
995
+ namespace: Schema2.String,
996
+ scope: Schema2.String
590
997
  });
591
- var PreviewSpecInputStandardSchema = Schema.toStandardSchemaV1(
592
- Schema.toStandardJSONSchemaV1(PreviewSpecInputSchema)
998
+ var GetSourceOutputSchema = Schema2.Struct({
999
+ source: Schema2.NullOr(Schema2.Unknown)
1000
+ });
1001
+ var PreviewSpecInputStandardSchema = Schema2.toStandardSchemaV1(
1002
+ Schema2.toStandardJSONSchemaV1(PreviewSpecInputSchema)
1003
+ );
1004
+ var PreviewSpecOutputStandardSchema = Schema2.toStandardSchemaV1(
1005
+ Schema2.toStandardJSONSchemaV1(StaticPreviewSpecOutputSchema)
1006
+ );
1007
+ var AddSourceInputStandardSchema = Schema2.toStandardSchemaV1(
1008
+ Schema2.toStandardJSONSchemaV1(AddSourceInputSchema)
1009
+ );
1010
+ var AddSourceOutputStandardSchema = Schema2.toStandardSchemaV1(
1011
+ Schema2.toStandardJSONSchemaV1(AddSourceOutputSchema)
593
1012
  );
594
- var AddSourceInputStandardSchema = Schema.toStandardSchemaV1(
595
- Schema.toStandardJSONSchemaV1(AddSourceInputSchema)
1013
+ var OpenApiConfigureSourceInputStandardSchema = Schema2.toStandardSchemaV1(
1014
+ Schema2.toStandardJSONSchemaV1(OpenApiConfigureSourceInputSchema)
596
1015
  );
597
- var AddSourceOutputStandardSchema = Schema.toStandardSchemaV1(
598
- Schema.toStandardJSONSchemaV1(AddSourceOutputSchema)
1016
+ var OpenApiConfigureSourceOutputStandardSchema = Schema2.toStandardSchemaV1(
1017
+ Schema2.toStandardJSONSchemaV1(Schema2.Struct({ result: Schema2.Array(CredentialBindingRef) }))
1018
+ );
1019
+ var GetSourceInputStandardSchema = Schema2.toStandardSchemaV1(
1020
+ Schema2.toStandardJSONSchemaV1(GetSourceInputSchema)
1021
+ );
1022
+ var GetSourceOutputStandardSchema = Schema2.toStandardSchemaV1(
1023
+ Schema2.toStandardJSONSchemaV1(GetSourceOutputSchema)
1024
+ );
1025
+ var openApiToolFailure = (code, message, details) => ToolResult.fail({
1026
+ code,
1027
+ message,
1028
+ ...details === void 0 ? {} : { details }
1029
+ });
1030
+ var staticPreviewOutput = (preview) => ({
1031
+ title: Option3.getOrNull(preview.title),
1032
+ version: Option3.getOrNull(preview.version),
1033
+ servers: preview.servers.map((server) => ({
1034
+ url: server.url,
1035
+ description: Option3.getOrNull(server.description),
1036
+ variables: Option3.getOrNull(server.variables) ? Object.fromEntries(
1037
+ Object.entries(Option3.getOrNull(server.variables) ?? {}).map(([name, variable]) => [
1038
+ name,
1039
+ {
1040
+ default: variable.default,
1041
+ enum: Option3.getOrNull(variable.enum),
1042
+ description: Option3.getOrNull(variable.description)
1043
+ }
1044
+ ])
1045
+ ) : null
1046
+ })),
1047
+ operationCount: preview.operationCount,
1048
+ tags: preview.tags,
1049
+ securitySchemes: preview.securitySchemes.map((scheme) => ({
1050
+ name: scheme.name,
1051
+ type: scheme.type,
1052
+ scheme: Option3.getOrNull(scheme.scheme),
1053
+ bearerFormat: Option3.getOrNull(scheme.bearerFormat),
1054
+ in: Option3.getOrNull(scheme.in),
1055
+ headerName: Option3.getOrNull(scheme.headerName),
1056
+ description: Option3.getOrNull(scheme.description),
1057
+ flows: Option3.isSome(scheme.flows) ? {
1058
+ authorizationCode: Option3.isSome(scheme.flows.value.authorizationCode) ? {
1059
+ authorizationUrl: scheme.flows.value.authorizationCode.value.authorizationUrl,
1060
+ tokenUrl: scheme.flows.value.authorizationCode.value.tokenUrl,
1061
+ refreshUrl: Option3.getOrNull(scheme.flows.value.authorizationCode.value.refreshUrl),
1062
+ scopes: scheme.flows.value.authorizationCode.value.scopes
1063
+ } : null,
1064
+ clientCredentials: Option3.isSome(scheme.flows.value.clientCredentials) ? {
1065
+ tokenUrl: scheme.flows.value.clientCredentials.value.tokenUrl,
1066
+ refreshUrl: Option3.getOrNull(scheme.flows.value.clientCredentials.value.refreshUrl),
1067
+ scopes: scheme.flows.value.clientCredentials.value.scopes
1068
+ } : null
1069
+ } : null,
1070
+ openIdConnectUrl: Option3.getOrNull(scheme.openIdConnectUrl)
1071
+ })),
1072
+ authStrategies: preview.authStrategies,
1073
+ headerPresets: preview.headerPresets,
1074
+ oauth2Presets: preview.oauth2Presets.map((preset) => ({
1075
+ label: preset.label,
1076
+ securitySchemeName: preset.securitySchemeName,
1077
+ flow: preset.flow,
1078
+ authorizationUrl: Option3.getOrNull(preset.authorizationUrl),
1079
+ tokenUrl: preset.tokenUrl,
1080
+ refreshUrl: Option3.getOrNull(preset.refreshUrl),
1081
+ scopes: preset.scopes
1082
+ }))
1083
+ });
1084
+ var resolveStaticScopeInput = (ctx, value) => String(
1085
+ ctx.scopes.find((scope) => scope.name === value || String(scope.id) === value)?.id ?? value
599
1086
  );
600
1087
  var normalizeOpenApiRefs = (node) => {
601
1088
  if (node == null || typeof node !== "object") return node;
@@ -631,9 +1118,9 @@ var toBinding = (def) => OperationBinding.make({
631
1118
  });
632
1119
  var descriptionFor = (def) => {
633
1120
  const op = def.operation;
634
- return Option2.getOrElse(
1121
+ return Option3.getOrElse(
635
1122
  op.description,
636
- () => Option2.getOrElse(op.summary, () => `${op.method.toUpperCase()} ${op.pathTemplate}`)
1123
+ () => Option3.getOrElse(op.summary, () => `${op.method.toUpperCase()} ${op.pathTemplate}`)
637
1124
  );
638
1125
  };
639
1126
  var slotPart = (value) => value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "default";
@@ -643,13 +1130,12 @@ var specFetchHeaderSlotFromName = (name) => `spec_fetch_header:${slotPart(name)}
643
1130
  var specFetchQueryParamSlotFromName = (name) => `spec_fetch_query_param:${slotPart(name)}`;
644
1131
  var canonicalizeHeaders = (headers) => {
645
1132
  const nextHeaders = {};
646
- const bindings = [];
647
1133
  for (const [name, value] of Object.entries(headers ?? {})) {
648
1134
  if (typeof value === "string") {
649
1135
  nextHeaders[name] = value;
650
1136
  continue;
651
1137
  }
652
- if ("kind" in value) {
1138
+ if (value.kind === "binding") {
653
1139
  nextHeaders[name] = value;
654
1140
  continue;
655
1141
  }
@@ -659,27 +1145,17 @@ var canonicalizeHeaders = (headers) => {
659
1145
  slot,
660
1146
  prefix: value.prefix
661
1147
  });
662
- bindings.push({
663
- slot,
664
- targetScope: "targetScope" in value ? value.targetScope : void 0,
665
- value: {
666
- kind: "secret",
667
- secretId: SecretId.make(value.secretId),
668
- ..."secretScopeId" in value && value.secretScopeId ? { secretScopeId: value.secretScopeId } : {}
669
- }
670
- });
671
1148
  }
672
- return { headers: nextHeaders, bindings };
1149
+ return { headers: nextHeaders };
673
1150
  };
674
1151
  var canonicalizeCredentialMap = (values, slotForName) => {
675
1152
  const nextValues = {};
676
- const bindings = [];
677
1153
  for (const [name, value] of Object.entries(values ?? {})) {
678
1154
  if (typeof value === "string") {
679
1155
  nextValues[name] = value;
680
1156
  continue;
681
1157
  }
682
- if ("kind" in value) {
1158
+ if (value.kind === "binding") {
683
1159
  nextValues[name] = value;
684
1160
  continue;
685
1161
  }
@@ -689,17 +1165,8 @@ var canonicalizeCredentialMap = (values, slotForName) => {
689
1165
  slot,
690
1166
  prefix: value.prefix
691
1167
  });
692
- bindings.push({
693
- slot,
694
- targetScope: "targetScope" in value ? value.targetScope : void 0,
695
- value: {
696
- kind: "secret",
697
- secretId: SecretId.make(value.secretId),
698
- ..."secretScopeId" in value && value.secretScopeId ? { secretScopeId: value.secretScopeId } : {}
699
- }
700
- });
701
1168
  }
702
- return { values: nextValues, bindings };
1169
+ return { values: nextValues };
703
1170
  };
704
1171
  var canonicalizeSpecFetchCredentials = (credentials) => {
705
1172
  const headers = canonicalizeCredentialMap(credentials?.headers, specFetchHeaderSlotFromName);
@@ -712,88 +1179,162 @@ var canonicalizeSpecFetchCredentials = (credentials) => {
712
1179
  ...Object.keys(queryParams.values).length > 0 ? { queryParams: queryParams.values } : {}
713
1180
  };
714
1181
  return {
715
- credentials: nextCredentials,
716
- bindings: [...headers.bindings, ...queryParams.bindings]
1182
+ credentials: nextCredentials
717
1183
  };
718
1184
  };
719
1185
  var canonicalizeOAuth2 = (oauth2) => {
720
- if (!oauth2) return { bindings: [] };
1186
+ if (!oauth2) return {};
721
1187
  return {
722
- oauth2,
723
- bindings: []
1188
+ oauth2
724
1189
  };
725
1190
  };
726
- var OPENAPI_PLUGIN_ID = "openapi";
727
- var scopeRanks = (ctx) => new Map(ctx.scopes.map((scope, index) => [String(scope.id), index]));
728
- var scopeRank = (ranks, scopeId) => ranks.get(scopeId) ?? Infinity;
729
- var coreBindingToOpenApiBinding = (binding) => OpenApiSourceBindingRef.make({
730
- sourceId: binding.sourceId,
731
- sourceScopeId: binding.sourceScopeId,
732
- scopeId: binding.scopeId,
733
- slot: binding.slotKey,
734
- value: binding.value,
735
- createdAt: binding.createdAt,
736
- updatedAt: binding.updatedAt
737
- });
738
- var listOpenApiSourceBindings = (ctx, sourceId, sourceScope) => Effect2.gen(function* () {
739
- const ranks = scopeRanks(ctx);
740
- const sourceSourceRank = scopeRank(ranks, sourceScope);
741
- if (sourceSourceRank === Infinity) return [];
742
- const bindings = yield* ctx.credentialBindings.listForSource({
743
- pluginId: OPENAPI_PLUGIN_ID,
744
- sourceId,
745
- sourceScope: ScopeId.make(sourceScope)
746
- });
747
- return bindings.filter((binding) => scopeRank(ranks, binding.scopeId) <= sourceSourceRank).map(coreBindingToOpenApiBinding);
748
- });
749
- var resolveOpenApiSourceBinding = (ctx, sourceId, sourceScope, slot) => Effect2.gen(function* () {
750
- const ranks = scopeRanks(ctx);
751
- const sourceSourceRank = scopeRank(ranks, sourceScope);
752
- if (sourceSourceRank === Infinity) return null;
753
- const bindings = yield* ctx.credentialBindings.listForSource({
754
- pluginId: OPENAPI_PLUGIN_ID,
755
- sourceId,
756
- sourceScope: ScopeId.make(sourceScope)
757
- });
758
- const binding = bindings.filter(
759
- (candidate) => candidate.slotKey === slot && scopeRank(ranks, candidate.scopeId) <= sourceSourceRank
760
- ).sort((a, b) => scopeRank(ranks, a.scopeId) - scopeRank(ranks, b.scopeId))[0];
761
- return binding ? coreBindingToOpenApiBinding(binding) : null;
762
- });
763
- var validateOpenApiBindingTarget = (ctx, input) => Effect2.gen(function* () {
764
- const ranks = scopeRanks(ctx);
765
- const sourceSourceRank = scopeRank(ranks, input.sourceScope);
766
- const targetRank = scopeRank(ranks, input.targetScope);
767
- const scopeList = `[${ctx.scopes.map((s) => s.id).join(", ")}]`;
768
- if (sourceSourceRank === Infinity) {
1191
+ var configuredValueFromConfigureInput = (slot, input) => {
1192
+ if (typeof input === "string") {
1193
+ return {
1194
+ configured: ConfiguredHeaderBinding.make({ kind: "binding", slot }),
1195
+ value: { kind: "text", text: input }
1196
+ };
1197
+ }
1198
+ if (input.kind === "text") {
1199
+ return {
1200
+ configured: ConfiguredHeaderBinding.make({
1201
+ kind: "binding",
1202
+ slot,
1203
+ prefix: input.prefix
1204
+ }),
1205
+ value: { kind: "text", text: input.text }
1206
+ };
1207
+ }
1208
+ if (input.kind === "secret") {
1209
+ return {
1210
+ configured: ConfiguredHeaderBinding.make({
1211
+ kind: "binding",
1212
+ slot,
1213
+ prefix: input.prefix
1214
+ }),
1215
+ value: {
1216
+ kind: "secret",
1217
+ secretId: SecretId.make(input.secretId),
1218
+ ...input.secretScope ? { secretScopeId: ScopeId.make(input.secretScope) } : {}
1219
+ }
1220
+ };
1221
+ }
1222
+ return {
1223
+ configured: ConfiguredHeaderBinding.make({ kind: "binding", slot }),
1224
+ value: { kind: "connection", connectionId: ConnectionId.make(input.connectionId) }
1225
+ };
1226
+ };
1227
+ var configureMap = (values, slotForName) => {
1228
+ const configured = {};
1229
+ const bindings = [];
1230
+ for (const [name, input] of Object.entries(values ?? {})) {
1231
+ const slotKey = slotForName(name);
1232
+ const next = configuredValueFromConfigureInput(slotKey, input);
1233
+ configured[name] = next.configured;
1234
+ bindings.push({ slotKey, value: next.value });
1235
+ }
1236
+ return { configured, bindings };
1237
+ };
1238
+ var configureOpenApiSource = (ctx, source, input) => Effect3.gen(function* () {
1239
+ const existing = yield* ctx.storage.getSource(source.id, source.scope);
1240
+ if (!existing) {
769
1241
  return yield* new StorageError({
770
- message: `OpenAPI source binding references source scope "${input.sourceScope}" which is not in the executor's scope stack ${scopeList}.`,
1242
+ message: `Cannot configure OpenAPI source "${source.id}" at scope "${source.scope}": source is not visible.`,
771
1243
  cause: void 0
772
1244
  });
773
1245
  }
774
- if (targetRank === Infinity) {
775
- return yield* new StorageError({
776
- message: `OpenAPI source binding targets scope "${input.targetScope}" which is not in the executor's scope stack ${scopeList}.`,
777
- cause: void 0
1246
+ const headers = configureMap(input.headers, headerSlotFromName);
1247
+ const queryParams = configureMap(input.queryParams, queryParamSlotFromName);
1248
+ const specFetchHeaders = configureMap(
1249
+ input.specFetchCredentials?.headers,
1250
+ specFetchHeaderSlotFromName
1251
+ );
1252
+ const specFetchQueryParams = configureMap(
1253
+ input.specFetchCredentials?.queryParams,
1254
+ specFetchQueryParamSlotFromName
1255
+ );
1256
+ const oauth2 = existing.config.oauth2;
1257
+ const oauth2Bindings = [];
1258
+ if (oauth2 && input.oauth2?.clientId) {
1259
+ oauth2Bindings.push({
1260
+ slotKey: oauth2.clientIdSlot,
1261
+ value: configuredValueFromConfigureInput(oauth2.clientIdSlot, input.oauth2.clientId).value
778
1262
  });
779
1263
  }
780
- if (targetRank > sourceSourceRank) {
781
- return yield* new StorageError({
782
- message: `OpenAPI source bindings for "${input.sourceId}" cannot be written at outer scope "${input.targetScope}" because the base source lives at "${input.sourceScope}"`,
783
- cause: void 0
1264
+ if (oauth2?.clientSecretSlot && input.oauth2?.clientSecret) {
1265
+ oauth2Bindings.push({
1266
+ slotKey: oauth2.clientSecretSlot,
1267
+ value: configuredValueFromConfigureInput(oauth2.clientSecretSlot, input.oauth2.clientSecret).value
784
1268
  });
785
1269
  }
786
- });
787
- var targetScopeForBinding = (fallbackTargetScope, binding) => {
788
- const targetScope = binding.targetScope ?? fallbackTargetScope;
789
- if (targetScope) return Effect2.succeed(targetScope);
790
- return Effect2.fail(
791
- new OpenApiOAuthError({
792
- message: "credentialTargetScope is required when adding direct OpenAPI credentials"
1270
+ if (oauth2 && input.oauth2?.connection) {
1271
+ oauth2Bindings.push({
1272
+ slotKey: oauth2.connectionSlot,
1273
+ value: configuredValueFromConfigureInput(oauth2.connectionSlot, input.oauth2.connection).value
1274
+ });
1275
+ }
1276
+ const specFetchCredentials = input.specFetchCredentials === void 0 ? existing.config.specFetchCredentials : {
1277
+ headers: specFetchHeaders.configured,
1278
+ queryParams: specFetchQueryParams.configured
1279
+ };
1280
+ const affectedPrefixes = [
1281
+ ...input.headers !== void 0 ? ["header:"] : [],
1282
+ ...input.queryParams !== void 0 ? ["query_param:"] : [],
1283
+ ...input.specFetchCredentials?.headers !== void 0 ? ["spec_fetch:header:"] : [],
1284
+ ...input.specFetchCredentials?.queryParams !== void 0 ? ["spec_fetch:query_param:"] : [],
1285
+ ...input.oauth2 !== void 0 ? ["oauth2:"] : []
1286
+ ];
1287
+ const bindings = [
1288
+ ...headers.bindings,
1289
+ ...queryParams.bindings,
1290
+ ...specFetchHeaders.bindings,
1291
+ ...specFetchQueryParams.bindings,
1292
+ ...oauth2Bindings
1293
+ ];
1294
+ const nextConfiguredValues = (current, next, provided) => {
1295
+ if (!provided) return current;
1296
+ if (Object.keys(next).length === 0) return {};
1297
+ return { ...current ?? {}, ...next };
1298
+ };
1299
+ return yield* ctx.transaction(
1300
+ Effect3.gen(function* () {
1301
+ yield* ctx.storage.updateSourceMeta(source.id, source.scope, {
1302
+ headers: nextConfiguredValues(
1303
+ existing.config.headers,
1304
+ headers.configured,
1305
+ input.headers !== void 0
1306
+ ),
1307
+ queryParams: nextConfiguredValues(
1308
+ existing.config.queryParams,
1309
+ queryParams.configured,
1310
+ input.queryParams !== void 0
1311
+ ),
1312
+ specFetchCredentials
1313
+ });
1314
+ if (affectedPrefixes.length > 0 || bindings.length > 0) {
1315
+ return yield* ctx.credentialBindings.replaceForSource({
1316
+ targetScope: ScopeId.make(input.scope),
1317
+ pluginId: OPENAPI_PLUGIN_ID,
1318
+ sourceId: source.id,
1319
+ sourceScope: ScopeId.make(source.scope),
1320
+ slotPrefixes: affectedPrefixes,
1321
+ bindings
1322
+ });
1323
+ }
1324
+ return [];
793
1325
  })
794
1326
  );
795
- };
796
- var findOuterSource = (ctx, namespace, scope) => Effect2.gen(function* () {
1327
+ });
1328
+ var OPENAPI_PLUGIN_ID = "openapi";
1329
+ var scopeRanks = (ctx) => new Map(ctx.scopes.map((scope, index) => [String(scope.id), index]));
1330
+ var scopeRank = (ranks, scopeId) => ranks.get(scopeId) ?? Infinity;
1331
+ var resolveOpenApiCredentialBinding = (ctx, sourceId, sourceScope, slot) => ctx.credentialBindings.resolveBinding({
1332
+ pluginId: OPENAPI_PLUGIN_ID,
1333
+ sourceId,
1334
+ sourceScope: ScopeId.make(sourceScope),
1335
+ slotKey: slot
1336
+ });
1337
+ var findOuterSource = (ctx, namespace, scope) => Effect3.gen(function* () {
797
1338
  const ranks = scopeRanks(ctx);
798
1339
  const baseRank = scopeRank(ranks, scope);
799
1340
  for (let index = baseRank + 1; index < ctx.scopes.length; index++) {
@@ -804,7 +1345,7 @@ var findOuterSource = (ctx, namespace, scope) => Effect2.gen(function* () {
804
1345
  }
805
1346
  return null;
806
1347
  });
807
- var resolveEffectiveSourceConfig = (ctx, base) => Effect2.gen(function* () {
1348
+ var resolveEffectiveSourceConfig = (ctx, base) => Effect3.gen(function* () {
808
1349
  const fallback = yield* findOuterSource(ctx, base.namespace, base.scope);
809
1350
  if (!fallback) {
810
1351
  return {
@@ -835,14 +1376,14 @@ var resolveEffectiveSourceConfig = (ctx, base) => Effect2.gen(function* () {
835
1376
  oauth2Source: base.config.oauth2 ? base : fallback
836
1377
  };
837
1378
  });
838
- var resolveConfiguredValueMap = (ctx, params) => Effect2.gen(function* () {
1379
+ var resolveConfiguredValueMap = (ctx, params) => Effect3.gen(function* () {
839
1380
  const resolved = {};
840
1381
  for (const [name, value] of Object.entries(params.values)) {
841
1382
  if (typeof value === "string") {
842
1383
  resolved[name] = value;
843
1384
  continue;
844
1385
  }
845
- const binding = yield* resolveOpenApiSourceBinding(
1386
+ const binding = yield* resolveOpenApiCredentialBinding(
846
1387
  ctx,
847
1388
  params.sourceId,
848
1389
  params.sourceScope,
@@ -850,9 +1391,9 @@ var resolveConfiguredValueMap = (ctx, params) => Effect2.gen(function* () {
850
1391
  );
851
1392
  if (binding?.value.kind === "secret") {
852
1393
  const secret = yield* ctx.secrets.getAtScope(binding.value.secretId, binding.value.secretScopeId ?? binding.scopeId).pipe(
853
- Effect2.catchTag(
1394
+ Effect3.catchTag(
854
1395
  "SecretOwnedByConnectionError",
855
- () => Effect2.fail(
1396
+ () => Effect3.fail(
856
1397
  new OpenApiOAuthError({
857
1398
  message: `Secret not found for header "${name}"`
858
1399
  })
@@ -889,17 +1430,17 @@ var resolveSecretBackedValues = (ctx, values) => resolveSecretBackedMap({
889
1430
  onMissing: (name) => new OpenApiOAuthError({
890
1431
  message: `Secret not found for "${name}"`
891
1432
  }),
892
- onError: (err, name) => Predicate.isTagged("SecretOwnedByConnectionError")(err) ? new OpenApiOAuthError({
1433
+ onError: (err, name) => Predicate2.isTagged("SecretOwnedByConnectionError")(err) ? new OpenApiOAuthError({
893
1434
  message: `Secret not found for "${name}"`
894
1435
  }) : err
895
1436
  }).pipe(
896
- Effect2.mapError(
897
- (err) => Predicate.isTagged("SecretOwnedByConnectionError")(err) ? new OpenApiOAuthError({ message: "Secret resolution failed" }) : err
1437
+ Effect3.mapError(
1438
+ (err) => Predicate2.isTagged("SecretOwnedByConnectionError")(err) ? new OpenApiOAuthError({ message: "Secret resolution failed" }) : err
898
1439
  ),
899
- Effect2.map((resolved) => resolved ?? {})
1440
+ Effect3.map((resolved) => resolved ?? {})
900
1441
  );
901
- var resolveOAuthConnectionId = (ctx, params) => Effect2.gen(function* () {
902
- const binding = yield* resolveOpenApiSourceBinding(
1442
+ var resolveOAuthConnectionId = (ctx, params) => Effect3.gen(function* () {
1443
+ const binding = yield* resolveOpenApiCredentialBinding(
903
1444
  ctx,
904
1445
  params.sourceId,
905
1446
  params.sourceScope,
@@ -912,14 +1453,14 @@ var resolveOAuthConnectionId = (ctx, params) => Effect2.gen(function* () {
912
1453
  }
913
1454
  return null;
914
1455
  });
915
- var resolveSpecFetchInputCredentials = (ctx, credentials) => Effect2.gen(function* () {
1456
+ var resolveSpecFetchInputCredentials = (ctx, credentials) => Effect3.gen(function* () {
916
1457
  if (!credentials) return void 0;
917
1458
  return {
918
1459
  headers: yield* resolveSecretBackedValues(ctx, credentials.headers),
919
1460
  queryParams: yield* resolveSecretBackedValues(ctx, credentials.queryParams)
920
1461
  };
921
1462
  });
922
- var resolveStoredSpecFetchCredentials = (ctx, params) => Effect2.gen(function* () {
1463
+ var resolveStoredSpecFetchCredentials = (ctx, params) => Effect3.gen(function* () {
923
1464
  if (!params.credentials) return void 0;
924
1465
  return {
925
1466
  headers: yield* resolveConfiguredValueMap(ctx, {
@@ -939,13 +1480,13 @@ var resolveStoredSpecFetchCredentials = (ctx, params) => Effect2.gen(function* (
939
1480
  var toOpenApiSourceConfig = (namespace, config) => {
940
1481
  const configHeaders = {};
941
1482
  for (const [name, value] of Object.entries(config.headers ?? {})) {
942
- if (typeof value === "string" || !("kind" in value)) {
1483
+ if (typeof value === "string") {
943
1484
  configHeaders[name] = value;
944
1485
  }
945
1486
  }
946
1487
  return {
947
1488
  kind: "openapi",
948
- spec: config.spec,
1489
+ spec: specInputToConfigString(config.spec),
949
1490
  baseUrl: config.baseUrl,
950
1491
  namespace,
951
1492
  headers: headersToConfigValues(
@@ -953,12 +1494,12 @@ var toOpenApiSourceConfig = (namespace, config) => {
953
1494
  )
954
1495
  };
955
1496
  };
956
- var isHttpUrl = (s) => s.startsWith("http://") || s.startsWith("https://");
1497
+ var specInputToConfigString = (spec) => spec.kind === "url" ? spec.url : spec.value;
957
1498
  var openApiPlugin = definePlugin((options) => {
958
- const rebuildSource = (ctx, input) => Effect2.gen(function* () {
1499
+ const rebuildSource = (ctx, input) => Effect3.gen(function* () {
959
1500
  const doc = yield* parse(input.specText);
960
1501
  const result = yield* extract(doc);
961
- const namespace = input.namespace ?? Option2.getOrElse(result.title, () => "api").toLowerCase().replace(/[^a-z0-9]+/g, "_");
1502
+ const namespace = input.namespace;
962
1503
  const outerSource = yield* findOuterSource(ctx, namespace, input.scope);
963
1504
  if (outerSource && input.baseUrl !== void 0 && input.baseUrl.trim() !== "") {
964
1505
  return yield* new OpenApiOAuthError({
@@ -971,7 +1512,7 @@ var openApiPlugin = definePlugin((options) => {
971
1512
  hoistedDefs[k] = normalizeOpenApiRefs(v);
972
1513
  }
973
1514
  }
974
- const baseUrl = outerSource ? void 0 : input.baseUrl ?? resolveBaseUrl(result.servers);
1515
+ const baseUrl = outerSource ? void 0 : input.baseUrl;
975
1516
  const canonicalHeaders = canonicalizeHeaders(input.headers);
976
1517
  const canonicalQueryParams = canonicalizeCredentialMap(
977
1518
  input.queryParams,
@@ -981,25 +1522,8 @@ var openApiPlugin = definePlugin((options) => {
981
1522
  input.specFetchCredentials
982
1523
  );
983
1524
  const canonicalOAuth2 = canonicalizeOAuth2(input.oauth2);
984
- const directBindings = [
985
- ...canonicalHeaders.bindings,
986
- ...canonicalQueryParams.bindings,
987
- ...canonicalSpecFetchCredentials.bindings,
988
- ...canonicalOAuth2.bindings
989
- ];
990
- for (const binding of directBindings) {
991
- const bindingTargetScope = yield* targetScopeForBinding(
992
- input.credentialTargetScope,
993
- binding
994
- );
995
- yield* validateOpenApiBindingTarget(ctx, {
996
- sourceId: namespace,
997
- sourceScope: input.scope,
998
- targetScope: bindingTargetScope
999
- });
1000
- }
1001
1525
  const definitions = compileToolDefinitions(result.operations);
1002
- const sourceName = input.name ?? Option2.getOrElse(result.title, () => namespace);
1526
+ const sourceName = input.name;
1003
1527
  const sourceConfig = {
1004
1528
  spec: input.specText,
1005
1529
  sourceUrl: input.sourceUrl,
@@ -1022,7 +1546,7 @@ var openApiPlugin = definePlugin((options) => {
1022
1546
  binding: toBinding(def)
1023
1547
  }));
1024
1548
  yield* ctx.transaction(
1025
- Effect2.gen(function* () {
1549
+ Effect3.gen(function* () {
1026
1550
  yield* ctx.storage.upsertSource(storedSource, storedOps);
1027
1551
  yield* ctx.core.sources.register({
1028
1552
  id: namespace,
@@ -1039,26 +1563,10 @@ var openApiPlugin = definePlugin((options) => {
1039
1563
  tools: definitions.map((def) => ({
1040
1564
  name: def.toolPath,
1041
1565
  description: descriptionFor(def),
1042
- inputSchema: normalizeOpenApiRefs(Option2.getOrUndefined(def.operation.inputSchema)),
1043
- outputSchema: normalizeOpenApiRefs(Option2.getOrUndefined(def.operation.outputSchema))
1566
+ inputSchema: normalizeOpenApiRefs(Option3.getOrUndefined(def.operation.inputSchema)),
1567
+ outputSchema: normalizeOpenApiRefs(Option3.getOrUndefined(def.operation.outputSchema))
1044
1568
  }))
1045
1569
  });
1046
- if (directBindings.length > 0) {
1047
- for (const binding of directBindings) {
1048
- const bindingTargetScope = yield* targetScopeForBinding(
1049
- input.credentialTargetScope,
1050
- binding
1051
- );
1052
- yield* ctx.credentialBindings.set({
1053
- targetScope: ScopeId.make(bindingTargetScope),
1054
- pluginId: OPENAPI_PLUGIN_ID,
1055
- sourceId: namespace,
1056
- sourceScope: ScopeId.make(input.scope),
1057
- slotKey: binding.slot,
1058
- value: binding.value
1059
- });
1060
- }
1061
- }
1062
1570
  if (Object.keys(hoistedDefs).length > 0) {
1063
1571
  yield* ctx.core.definitions.register({
1064
1572
  sourceId: namespace,
@@ -1070,7 +1578,7 @@ var openApiPlugin = definePlugin((options) => {
1070
1578
  );
1071
1579
  return { sourceId: namespace, toolCount: definitions.length };
1072
1580
  });
1073
- const refreshSourceInternal = (ctx, sourceId, scope) => Effect2.gen(function* () {
1581
+ const refreshSourceInternal = (ctx, sourceId, scope) => Effect3.gen(function* () {
1074
1582
  const httpClientLayer = options?.httpClientLayer ?? ctx.httpClientLayer;
1075
1583
  const existing = yield* ctx.storage.getSource(sourceId, scope);
1076
1584
  if (!existing) return;
@@ -1084,78 +1592,67 @@ var openApiPlugin = definePlugin((options) => {
1084
1592
  credentials: resolvedConfig.specFetchCredentials
1085
1593
  });
1086
1594
  const specText = yield* resolveSpecText(sourceUrl, credentials).pipe(
1087
- Effect2.provide(httpClientLayer)
1595
+ Effect3.provide(httpClientLayer)
1088
1596
  );
1089
1597
  yield* rebuildSource(ctx, {
1090
1598
  specText,
1091
1599
  scope,
1092
1600
  sourceUrl,
1093
1601
  name: existing.name,
1094
- baseUrl: resolvedConfig.baseUrl,
1602
+ baseUrl: existing.config.baseUrl,
1095
1603
  namespace: existing.namespace,
1096
1604
  headers: existing.config.headers,
1097
1605
  queryParams: existing.config.queryParams,
1098
1606
  specFetchCredentials: existing.config.specFetchCredentials,
1099
- oauth2: existing.config.oauth2,
1100
- credentialTargetScope: scope
1607
+ oauth2: existing.config.oauth2
1101
1608
  });
1102
1609
  });
1103
1610
  return {
1104
1611
  id: "openapi",
1105
1612
  packageName: "@executor-js/plugin-openapi",
1613
+ sourcePresets: openApiPresets,
1106
1614
  schema: openapiSchema,
1107
1615
  storage: (deps) => makeDefaultOpenapiStore(deps),
1108
1616
  extension: (ctx) => {
1109
1617
  const httpClientLayer = options?.httpClientLayer ?? ctx.httpClientLayer;
1110
- const addSpecInternal = (config) => Effect2.gen(function* () {
1111
- const credentials = yield* resolveSpecFetchInputCredentials(
1112
- ctx,
1113
- config.specFetchCredentials
1114
- );
1115
- const specText = yield* resolveSpecText(config.spec, credentials).pipe(
1116
- Effect2.provide(httpClientLayer)
1117
- );
1618
+ const addSpecInternal = (config) => Effect3.gen(function* () {
1619
+ const specText = config.spec.kind === "url" ? yield* resolveSpecText(config.spec.url).pipe(Effect3.provide(httpClientLayer)) : config.spec.value;
1118
1620
  return yield* rebuildSource(ctx, {
1119
1621
  specText,
1120
1622
  scope: config.scope,
1121
- sourceUrl: isHttpUrl(config.spec) ? config.spec : void 0,
1623
+ sourceUrl: config.spec.kind === "url" ? config.spec.url : void 0,
1122
1624
  name: config.name,
1123
1625
  baseUrl: config.baseUrl,
1124
1626
  namespace: config.namespace,
1125
1627
  headers: config.headers,
1126
1628
  queryParams: config.queryParams,
1127
1629
  specFetchCredentials: config.specFetchCredentials,
1128
- oauth2: config.oauth2,
1129
- // Default to the source's own scope. refreshSource and editSource
1130
- // do the same; without this, config-sync's addSpec — which never
1131
- // passes the field — fails with "credentialTargetScope is
1132
- // required" the moment the jsonc declares any header secret.
1133
- credentialTargetScope: config.credentialTargetScope ?? config.scope
1630
+ oauth2: config.oauth2
1134
1631
  });
1135
1632
  });
1136
1633
  const configFile = options?.configFile;
1137
1634
  return {
1138
- previewSpec: (input) => Effect2.gen(function* () {
1635
+ previewSpec: (input) => Effect3.gen(function* () {
1139
1636
  const previewInput = typeof input === "string" ? { spec: input } : input;
1140
1637
  const credentials = yield* resolveSpecFetchInputCredentials(
1141
1638
  ctx,
1142
1639
  previewInput.specFetchCredentials
1143
1640
  );
1144
1641
  const specText = yield* resolveSpecText(previewInput.spec, credentials).pipe(
1145
- Effect2.provide(httpClientLayer)
1642
+ Effect3.provide(httpClientLayer)
1146
1643
  );
1147
- return yield* previewSpec(specText).pipe(Effect2.provide(httpClientLayer));
1644
+ return yield* previewSpec(specText).pipe(Effect3.provide(httpClientLayer));
1148
1645
  }),
1149
- addSpec: (config) => Effect2.gen(function* () {
1646
+ addSpec: (config) => Effect3.gen(function* () {
1150
1647
  const result = yield* addSpecInternal(config);
1151
1648
  if (configFile) {
1152
1649
  yield* configFile.upsertSource(toOpenApiSourceConfig(result.sourceId, config));
1153
1650
  }
1154
1651
  return result;
1155
1652
  }),
1156
- removeSpec: (namespace, scope) => Effect2.gen(function* () {
1653
+ removeSpec: (namespace, scope) => Effect3.gen(function* () {
1157
1654
  yield* ctx.transaction(
1158
- Effect2.gen(function* () {
1655
+ Effect3.gen(function* () {
1159
1656
  yield* ctx.credentialBindings.removeForSource({
1160
1657
  pluginId: OPENAPI_PLUGIN_ID,
1161
1658
  sourceId: namespace,
@@ -1172,7 +1669,7 @@ var openApiPlugin = definePlugin((options) => {
1172
1669
  yield* configFile.removeSource(namespace);
1173
1670
  }
1174
1671
  }),
1175
- getSource: (namespace, scope) => Effect2.gen(function* () {
1672
+ getSource: (namespace, scope) => Effect3.gen(function* () {
1176
1673
  const source = yield* ctx.storage.getSource(namespace, scope);
1177
1674
  if (!source) return null;
1178
1675
  const effective = yield* resolveEffectiveSourceConfig(ctx, source);
@@ -1181,95 +1678,31 @@ var openApiPlugin = definePlugin((options) => {
1181
1678
  config: effective.config
1182
1679
  };
1183
1680
  }),
1184
- updateSource: (namespace, scope, input) => Effect2.gen(function* () {
1185
- const existing = yield* ctx.storage.getSource(namespace, scope);
1186
- if (!existing) return;
1187
- const canonicalHeaders = input.headers !== void 0 ? canonicalizeHeaders(input.headers) : null;
1188
- const canonicalOAuth2 = input.oauth2 !== void 0 ? canonicalizeOAuth2(input.oauth2) : null;
1189
- const canonicalQueryParams = input.queryParams !== void 0 ? canonicalizeCredentialMap(input.queryParams, queryParamSlotFromName) : null;
1190
- const directBindings = [
1191
- ...canonicalHeaders?.bindings ?? [],
1192
- ...canonicalQueryParams?.bindings ?? [],
1193
- ...canonicalOAuth2?.bindings ?? []
1194
- ];
1195
- const affectedPrefixes = [
1196
- ...input.headers !== void 0 ? ["header:"] : [],
1197
- ...input.queryParams !== void 0 ? ["query_param:"] : [],
1198
- ...input.oauth2 !== void 0 ? ["oauth2:"] : []
1199
- ];
1200
- const targetScope = input.credentialTargetScope ?? scope;
1681
+ configure: (source, input) => configureOpenApiSource(ctx, source, input)
1682
+ };
1683
+ },
1684
+ sourceConfigure: {
1685
+ type: "openapi",
1686
+ schema: OpenApiConfigureInputSchema,
1687
+ configure: ({ ctx, sourceId, sourceScope, config }) => Effect3.gen(function* () {
1688
+ const input = config;
1689
+ if (input.name !== void 0 || input.baseUrl !== void 0 || input.oauth2Source !== void 0) {
1201
1690
  if (input.baseUrl !== void 0 && input.baseUrl.trim() !== "") {
1202
- const outerSource = yield* findOuterSource(ctx, namespace, scope);
1691
+ const outerSource = yield* findOuterSource(ctx, sourceId, sourceScope);
1203
1692
  if (outerSource) {
1204
1693
  return yield* new OpenApiOAuthError({
1205
1694
  message: "OpenAPI source shadows inherit the outer source base URL"
1206
1695
  });
1207
1696
  }
1208
1697
  }
1209
- if (affectedPrefixes.length > 0 || directBindings.length > 0) {
1210
- yield* validateOpenApiBindingTarget(ctx, {
1211
- sourceId: namespace,
1212
- sourceScope: scope,
1213
- targetScope
1214
- });
1215
- }
1216
- yield* ctx.transaction(
1217
- Effect2.gen(function* () {
1218
- yield* ctx.storage.updateSourceMeta(namespace, scope, {
1219
- name: input.name?.trim() || void 0,
1220
- baseUrl: input.baseUrl,
1221
- headers: canonicalHeaders?.headers,
1222
- queryParams: canonicalQueryParams?.values,
1223
- oauth2: canonicalOAuth2?.oauth2
1224
- });
1225
- if (affectedPrefixes.length > 0 || directBindings.length > 0) {
1226
- yield* ctx.credentialBindings.replaceForSource({
1227
- targetScope: ScopeId.make(targetScope),
1228
- pluginId: OPENAPI_PLUGIN_ID,
1229
- sourceId: namespace,
1230
- sourceScope: ScopeId.make(scope),
1231
- slotPrefixes: affectedPrefixes,
1232
- bindings: directBindings.map((binding) => ({
1233
- slotKey: binding.slot,
1234
- value: binding.value
1235
- }))
1236
- });
1237
- }
1238
- })
1239
- );
1240
- }),
1241
- listSourceBindings: (sourceId, sourceScope) => listOpenApiSourceBindings(ctx, sourceId, sourceScope),
1242
- setSourceBinding: (input) => Effect2.gen(function* () {
1243
- yield* validateOpenApiBindingTarget(ctx, {
1244
- sourceId: input.sourceId,
1245
- sourceScope: input.sourceScope,
1246
- targetScope: input.scope
1247
- });
1248
- const binding = yield* ctx.credentialBindings.set({
1249
- targetScope: input.scope,
1250
- pluginId: OPENAPI_PLUGIN_ID,
1251
- sourceId: input.sourceId,
1252
- sourceScope: input.sourceScope,
1253
- slotKey: input.slot,
1254
- value: input.value
1255
- });
1256
- return coreBindingToOpenApiBinding(binding);
1257
- }),
1258
- removeSourceBinding: (sourceId, sourceScope, slot, scope) => Effect2.gen(function* () {
1259
- yield* validateOpenApiBindingTarget(ctx, {
1260
- sourceId,
1261
- sourceScope,
1262
- targetScope: scope
1698
+ yield* ctx.storage.updateSourceMeta(sourceId, sourceScope, {
1699
+ name: input.name?.trim() || void 0,
1700
+ baseUrl: input.baseUrl,
1701
+ oauth2: input.oauth2Source
1263
1702
  });
1264
- yield* ctx.credentialBindings.remove({
1265
- targetScope: ScopeId.make(scope),
1266
- pluginId: OPENAPI_PLUGIN_ID,
1267
- sourceId,
1268
- sourceScope: ScopeId.make(sourceScope),
1269
- slotKey: slot
1270
- });
1271
- })
1272
- };
1703
+ }
1704
+ return yield* configureOpenApiSource(ctx, { id: sourceId, scope: sourceScope }, input);
1705
+ })
1273
1706
  },
1274
1707
  staticSources: (self) => [
1275
1708
  {
@@ -1279,25 +1712,88 @@ var openApiPlugin = definePlugin((options) => {
1279
1712
  tools: [
1280
1713
  tool({
1281
1714
  name: "previewSpec",
1282
- description: "Preview an OpenAPI document before adding it as a source",
1715
+ description: "Preview an OpenAPI document before adding it as a source. Call this first when the user provides a spec URL/blob so you can inspect servers, auth schemes, operation count, tags, and credential slots before `addSource`. This agent-facing preview intentionally omits the full operations list; use `operationCount` and `tags` for full-size specs. Do not collect API keys or OAuth client secrets in chat; use `executor.coreTools.secrets.create` for those values.",
1283
1716
  inputSchema: PreviewSpecInputStandardSchema,
1284
- execute: (input) => self.previewSpec(input)
1717
+ outputSchema: PreviewSpecOutputStandardSchema,
1718
+ execute: (input) => self.previewSpec(input).pipe(
1719
+ Effect3.map((preview) => ToolResult.ok(staticPreviewOutput(preview))),
1720
+ Effect3.catchTags({
1721
+ OpenApiParseError: ({ message }) => Effect3.succeed(openApiToolFailure("openapi_parse_failed", message)),
1722
+ OpenApiExtractionError: ({ message }) => Effect3.succeed(openApiToolFailure("openapi_extraction_failed", message)),
1723
+ OpenApiOAuthError: ({ message }) => Effect3.succeed(openApiToolFailure("openapi_oauth_failed", message))
1724
+ })
1725
+ )
1726
+ }),
1727
+ tool({
1728
+ name: "getSource",
1729
+ description: "Inspect an existing OpenAPI source, including effective base URL, configured headers/query params, OAuth settings, and stored credential slots. Use this before repairing an existing source with `openapi.configureSource`, `secrets.create`, or `oauth.start`.",
1730
+ inputSchema: GetSourceInputStandardSchema,
1731
+ outputSchema: GetSourceOutputStandardSchema,
1732
+ execute: (input, { ctx }) => Effect3.map(
1733
+ self.getSource(input.namespace, resolveStaticScopeInput(ctx, input.scope)),
1734
+ (source) => ToolResult.ok({ source })
1735
+ )
1285
1736
  }),
1286
1737
  tool({
1287
1738
  name: "addSource",
1288
- description: "Add an OpenAPI source and register its operations as tools",
1739
+ description: "Add an OpenAPI source and register its operations as tools. Executor chooses the source install scope (local scope locally, organization scope in cloud) and returns it as `source`. Recommended flow: call `previewSpec`, choose or confirm namespace/name/baseUrl from the preview (baseUrl is only needed when the spec cannot infer one or the user wants an override), declare credential slots here for sensitive headers/query params, then call `secrets.create` and `openapi.configureSource` with the user's chosen credential scope for per-scope bindings. Use `oauth.start` with `credentialScope` set to the user's chosen personal or organization credential scope for browser OAuth sign-in.",
1289
1740
  annotations: {
1290
1741
  requiresApproval: true,
1291
1742
  approvalDescription: "Add an OpenAPI source"
1292
1743
  },
1293
1744
  inputSchema: AddSourceInputStandardSchema,
1294
1745
  outputSchema: AddSourceOutputStandardSchema,
1295
- execute: (input) => self.addSpec(input)
1746
+ execute: (input, { ctx }) => {
1747
+ const sourceScope = defaultSourceInstallScopeId(ctx.scopes);
1748
+ if (sourceScope === null) {
1749
+ return Effect3.succeed(
1750
+ openApiToolFailure(
1751
+ "source_scope_unavailable",
1752
+ "Cannot add an OpenAPI source because this executor has no source install scope."
1753
+ )
1754
+ );
1755
+ }
1756
+ return self.addSpec({ ...input, scope: sourceScope }).pipe(
1757
+ Effect3.map(
1758
+ (result) => ToolResult.ok({
1759
+ ...result,
1760
+ source: { id: result.sourceId, scope: sourceScope }
1761
+ })
1762
+ ),
1763
+ Effect3.catchTags({
1764
+ OpenApiParseError: ({ message }) => Effect3.succeed(openApiToolFailure("openapi_parse_failed", message)),
1765
+ OpenApiExtractionError: ({ message }) => Effect3.succeed(openApiToolFailure("openapi_extraction_failed", message)),
1766
+ OpenApiOAuthError: ({ message }) => Effect3.succeed(openApiToolFailure("openapi_oauth_failed", message))
1767
+ })
1768
+ );
1769
+ }
1770
+ }),
1771
+ tool({
1772
+ name: "configureSource",
1773
+ description: 'Configure an existing OpenAPI source with concrete fields. Use `source` returned by `openapi.addSource` or `sources.list`. The top-level `scope` is the credential target scope for bindings; in cloud, choose the user or organization credential scope deliberately. Pass secret refs as `{kind:"secret", secretId}` and OAuth connections as `{kind:"connection", connectionId}`.',
1774
+ annotations: {
1775
+ requiresApproval: true,
1776
+ approvalDescription: "Configure an OpenAPI source"
1777
+ },
1778
+ inputSchema: OpenApiConfigureSourceInputStandardSchema,
1779
+ outputSchema: OpenApiConfigureSourceOutputStandardSchema,
1780
+ execute: (input, { ctx }) => {
1781
+ const { source, ...config } = input;
1782
+ const sourceScope = resolveStaticScopeInput(ctx, source.scope);
1783
+ const targetScope = resolveStaticScopeInput(ctx, config.scope);
1784
+ return Effect3.map(
1785
+ self.configure(
1786
+ { id: source.id, scope: sourceScope },
1787
+ { ...config, scope: targetScope }
1788
+ ),
1789
+ (result) => ToolResult.ok({ result })
1790
+ );
1791
+ }
1296
1792
  })
1297
1793
  ]
1298
1794
  }
1299
1795
  ],
1300
- invokeTool: ({ ctx, toolRow, args }) => Effect2.gen(function* () {
1796
+ invokeTool: ({ ctx, toolRow, args }) => Effect3.gen(function* () {
1301
1797
  const httpClientLayer = options?.httpClientLayer ?? ctx.httpClientLayer;
1302
1798
  const toolScope = toolRow.scope_id;
1303
1799
  const op = yield* ctx.storage.getOperationByToolId(toolRow.id, toolScope);
@@ -1337,7 +1833,7 @@ var openApiPlugin = definePlugin((options) => {
1337
1833
  });
1338
1834
  }
1339
1835
  const accessToken = yield* ctx.connections.accessTokenAtScope(connection.connectionId, connection.scopeId).pipe(
1340
- Effect2.mapError(
1836
+ Effect3.mapError(
1341
1837
  () => new OpenApiOAuthError({
1342
1838
  message: "OAuth connection resolution failed"
1343
1839
  })
@@ -1353,16 +1849,29 @@ var openApiPlugin = definePlugin((options) => {
1353
1849
  resolvedQueryParams,
1354
1850
  httpClientLayer
1355
1851
  );
1356
- return result;
1852
+ const ok = result.status >= 200 && result.status < 300;
1853
+ if (!ok) {
1854
+ return ToolResult.fail({
1855
+ code: "upstream_http_error",
1856
+ status: result.status,
1857
+ message: extractUpstreamMessage(result.error, result.status),
1858
+ details: result.error
1859
+ });
1860
+ }
1861
+ return ToolResult.ok({
1862
+ status: result.status,
1863
+ headers: result.headers,
1864
+ data: result.data
1865
+ });
1357
1866
  }),
1358
- resolveAnnotations: ({ ctx, sourceId, toolRows }) => Effect2.gen(function* () {
1867
+ resolveAnnotations: ({ ctx, sourceId, toolRows }) => Effect3.gen(function* () {
1359
1868
  const scopes = /* @__PURE__ */ new Set();
1360
1869
  for (const row of toolRows) {
1361
1870
  scopes.add(row.scope_id);
1362
1871
  }
1363
- const entries = yield* Effect2.forEach(
1872
+ const entries = yield* Effect3.forEach(
1364
1873
  [...scopes],
1365
- (scope) => Effect2.gen(function* () {
1874
+ (scope) => Effect3.gen(function* () {
1366
1875
  const ops = yield* ctx.storage.listOperationsBySource(sourceId, scope);
1367
1876
  const byId = /* @__PURE__ */ new Map();
1368
1877
  for (const op of ops) byId.set(op.toolId, op.binding);
@@ -1380,9 +1889,9 @@ var openApiPlugin = definePlugin((options) => {
1380
1889
  }
1381
1890
  return out;
1382
1891
  }),
1383
- removeSource: ({ ctx, sourceId, scope }) => Effect2.gen(function* () {
1892
+ removeSource: ({ ctx, sourceId, scope }) => Effect3.gen(function* () {
1384
1893
  yield* ctx.transaction(
1385
- Effect2.gen(function* () {
1894
+ Effect3.gen(function* () {
1386
1895
  yield* ctx.credentialBindings.removeForSource({
1387
1896
  pluginId: OPENAPI_PLUGIN_ID,
1388
1897
  sourceId,
@@ -1397,8 +1906,8 @@ var openApiPlugin = definePlugin((options) => {
1397
1906
  }),
1398
1907
  // OpenAPI credential usages are reported by the core `credential_binding`
1399
1908
  // table. Source storage carries only source-owned slot structure.
1400
- usagesForSecret: () => Effect2.succeed([]),
1401
- usagesForConnection: () => Effect2.succeed([]),
1909
+ usagesForSecret: () => Effect3.succeed([]),
1910
+ usagesForConnection: () => Effect3.succeed([]),
1402
1911
  // Re-fetch the spec from its origin URL (captured at addSpec time)
1403
1912
  // and replay the same parse → extract → upsertSource → register
1404
1913
  // path used by addSpec. Sources without a stored URL surface a
@@ -1406,26 +1915,26 @@ var openApiPlugin = definePlugin((options) => {
1406
1915
  // when `canRefresh: true`, so a raw-text source reaching here
1407
1916
  // means stale UI state, which is worth surfacing to the caller.
1408
1917
  refreshSource: ({ ctx, sourceId, scope }) => refreshSourceInternal(ctx, sourceId, scope),
1409
- detect: ({ ctx, url }) => Effect2.gen(function* () {
1918
+ detect: ({ ctx, url }) => Effect3.gen(function* () {
1410
1919
  const httpClientLayer = options?.httpClientLayer ?? ctx.httpClientLayer;
1411
1920
  const trimmed = url.trim();
1412
1921
  if (!trimmed) return null;
1413
- const parsed = yield* Effect2.try({
1922
+ const parsed = yield* Effect3.try({
1414
1923
  try: () => new URL(trimmed),
1415
1924
  catch: (error) => error
1416
- }).pipe(Effect2.option);
1417
- if (Option2.isNone(parsed)) return null;
1925
+ }).pipe(Effect3.option);
1926
+ if (Option3.isNone(parsed)) return null;
1418
1927
  const specText = yield* resolveSpecText(trimmed).pipe(
1419
- Effect2.provide(httpClientLayer),
1420
- Effect2.catch(() => Effect2.succeed(null))
1928
+ Effect3.provide(httpClientLayer),
1929
+ Effect3.catch(() => Effect3.succeed(null))
1421
1930
  );
1422
1931
  if (specText === null) return null;
1423
- const doc = yield* parse(specText).pipe(Effect2.catch(() => Effect2.succeed(null)));
1932
+ const doc = yield* parse(specText).pipe(Effect3.catch(() => Effect3.succeed(null)));
1424
1933
  if (!doc) return null;
1425
- const result = yield* extract(doc).pipe(Effect2.catch(() => Effect2.succeed(null)));
1934
+ const result = yield* extract(doc).pipe(Effect3.catch(() => Effect3.succeed(null)));
1426
1935
  if (!result) return null;
1427
- const namespace = Option2.getOrElse(result.title, () => "api").toLowerCase().replace(/[^a-z0-9]+/g, "_");
1428
- const name = Option2.getOrElse(result.title, () => namespace);
1936
+ const namespace = Option3.getOrElse(result.title, () => "api").toLowerCase().replace(/[^a-z0-9]+/g, "_");
1937
+ const name = Option3.getOrElse(result.title, () => namespace);
1429
1938
  return SourceDetectionResult.make({
1430
1939
  kind: "openapi",
1431
1940
  confidence: "high",
@@ -1442,6 +1951,8 @@ export {
1442
1951
  invoke,
1443
1952
  invokeWithLayer,
1444
1953
  annotationsForOperation,
1954
+ openapiSchema,
1955
+ makeDefaultOpenapiStore,
1445
1956
  openApiPlugin
1446
1957
  };
1447
- //# sourceMappingURL=chunk-OZ67JNID.js.map
1958
+ //# sourceMappingURL=chunk-NIKLYJ3X.js.map