@executor-js/plugin-graphql 1.4.28 → 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 (40) hide show
  1. package/dist/{AddGraphqlSource-3Z3DB4KQ.js → AddGraphqlSource-PBMKSY7Y.js} +29 -18
  2. package/dist/AddGraphqlSource-PBMKSY7Y.js.map +1 -0
  3. package/dist/{EditGraphqlSource-F37RPNKV.js → EditGraphqlSource-AFR4RQHY.js} +107 -91
  4. package/dist/EditGraphqlSource-AFR4RQHY.js.map +1 -0
  5. package/dist/{GraphqlSourceSummary-6EYBXVD2.js → GraphqlSourceSummary-MY4AW37M.js} +4 -4
  6. package/dist/GraphqlSourceSummary-MY4AW37M.js.map +1 -0
  7. package/dist/api/group.d.ts +71 -232
  8. package/dist/api/handlers.d.ts +5 -45
  9. package/dist/api/index.d.ts +76 -404
  10. package/dist/{chunk-PO2TPM5B.js → chunk-7S2FM3ZF.js} +578 -613
  11. package/dist/chunk-7S2FM3ZF.js.map +1 -0
  12. package/dist/chunk-D6E4WAYW.js +51 -0
  13. package/dist/chunk-D6E4WAYW.js.map +1 -0
  14. package/dist/{chunk-445ZPXHU.js → chunk-H422YIM4.js} +15 -34
  15. package/dist/chunk-H422YIM4.js.map +1 -0
  16. package/dist/{chunk-EW4Y3KEX.js → chunk-OYUIHBWZ.js} +23 -80
  17. package/dist/chunk-OYUIHBWZ.js.map +1 -0
  18. package/dist/client.js +7 -47
  19. package/dist/client.js.map +1 -1
  20. package/dist/core.js +3 -8
  21. package/dist/index.js +3 -2
  22. package/dist/react/atoms.d.ts +146 -186
  23. package/dist/react/client.d.ts +70 -231
  24. package/dist/sdk/index.d.ts +2 -2
  25. package/dist/sdk/introspect.d.ts +151 -151
  26. package/dist/sdk/invoke.d.ts +5 -5
  27. package/dist/sdk/plugin.d.ts +74 -228
  28. package/dist/sdk/presets.d.ts +1 -0
  29. package/dist/sdk/store.d.ts +3 -135
  30. package/dist/sdk/types.d.ts +31 -66
  31. package/dist/testing/index.d.ts +20 -2
  32. package/dist/testing.js +77 -29
  33. package/dist/testing.js.map +1 -1
  34. package/package.json +3 -3
  35. package/dist/AddGraphqlSource-3Z3DB4KQ.js.map +0 -1
  36. package/dist/EditGraphqlSource-F37RPNKV.js.map +0 -1
  37. package/dist/GraphqlSourceSummary-6EYBXVD2.js.map +0 -1
  38. package/dist/chunk-445ZPXHU.js.map +0 -1
  39. package/dist/chunk-EW4Y3KEX.js.map +0 -1
  40. package/dist/chunk-PO2TPM5B.js.map +0 -1
@@ -1,22 +1,26 @@
1
+ import {
2
+ graphqlPresets
3
+ } from "./chunk-D6E4WAYW.js";
1
4
  import {
2
5
  ExtractedField,
3
6
  ExtractionResult,
4
7
  GRAPHQL_OAUTH_CONNECTION_SLOT,
5
8
  GraphqlArgument,
9
+ GraphqlConfiguredValueInput,
6
10
  GraphqlCredentialInput,
7
11
  GraphqlExtractionError,
8
12
  GraphqlIntrospectionError,
9
13
  GraphqlInvocationError,
14
+ GraphqlSourceAuth,
10
15
  GraphqlSourceAuthInput,
11
- GraphqlSourceBindingRef,
12
16
  InvocationResult,
13
17
  OperationBinding,
14
18
  graphqlHeaderSlot,
15
19
  graphqlQueryParamSlot
16
- } from "./chunk-445ZPXHU.js";
20
+ } from "./chunk-H422YIM4.js";
17
21
 
18
22
  // src/sdk/introspect.ts
19
- import { Effect, Schema } from "effect";
23
+ import { Effect, Option, Schema } from "effect";
20
24
  import { HttpClient, HttpClientRequest } from "effect/unstable/http";
21
25
  var INTROSPECTION_QUERY = `
22
26
  query IntrospectionQuery {
@@ -90,32 +94,32 @@ var INTROSPECTION_QUERY = `
90
94
  var IntrospectionTypeRefLeaf = Schema.Struct({
91
95
  kind: Schema.String,
92
96
  name: Schema.NullOr(Schema.String),
93
- ofType: Schema.Null
97
+ ofType: Schema.optional(Schema.Null)
94
98
  });
95
99
  var IntrospectionTypeRef5 = Schema.Struct({
96
100
  kind: Schema.String,
97
101
  name: Schema.NullOr(Schema.String),
98
- ofType: Schema.NullOr(IntrospectionTypeRefLeaf)
102
+ ofType: Schema.optional(Schema.NullOr(IntrospectionTypeRefLeaf))
99
103
  });
100
104
  var IntrospectionTypeRef4 = Schema.Struct({
101
105
  kind: Schema.String,
102
106
  name: Schema.NullOr(Schema.String),
103
- ofType: Schema.NullOr(IntrospectionTypeRef5)
107
+ ofType: Schema.optional(Schema.NullOr(IntrospectionTypeRef5))
104
108
  });
105
109
  var IntrospectionTypeRef3 = Schema.Struct({
106
110
  kind: Schema.String,
107
111
  name: Schema.NullOr(Schema.String),
108
- ofType: Schema.NullOr(IntrospectionTypeRef4)
112
+ ofType: Schema.optional(Schema.NullOr(IntrospectionTypeRef4))
109
113
  });
110
114
  var IntrospectionTypeRef2 = Schema.Struct({
111
115
  kind: Schema.String,
112
116
  name: Schema.NullOr(Schema.String),
113
- ofType: Schema.NullOr(IntrospectionTypeRef3)
117
+ ofType: Schema.optional(Schema.NullOr(IntrospectionTypeRef3))
114
118
  });
115
119
  var IntrospectionTypeRefSchema = Schema.Struct({
116
120
  kind: Schema.String,
117
121
  name: Schema.NullOr(Schema.String),
118
- ofType: Schema.NullOr(IntrospectionTypeRef2)
122
+ ofType: Schema.optional(Schema.NullOr(IntrospectionTypeRef2))
119
123
  });
120
124
  var IntrospectionInputValueSchema = Schema.Struct({
121
125
  name: Schema.String,
@@ -155,10 +159,51 @@ var IntrospectionResponseSchema = Schema.Struct({
155
159
  data: Schema.optional(IntrospectionResultSchema),
156
160
  errors: Schema.optional(Schema.Array(Schema.Unknown))
157
161
  });
162
+ var UpstreamErrorResponseSchema = Schema.Struct({
163
+ message: Schema.optional(Schema.String),
164
+ errors: Schema.optional(
165
+ Schema.Array(
166
+ Schema.Struct({
167
+ message: Schema.optional(Schema.String)
168
+ })
169
+ )
170
+ )
171
+ });
158
172
  var IntrospectionJsonSchema = Schema.Union([
159
173
  Schema.Struct({ data: IntrospectionResultSchema }),
160
174
  IntrospectionResultSchema
161
175
  ]);
176
+ var JsonTextSchema = Schema.fromJsonString(Schema.Unknown);
177
+ var decodeUpstreamErrorResponse = Schema.decodeUnknownOption(UpstreamErrorResponseSchema);
178
+ var firstUpstreamErrorMessage = (value) => {
179
+ const decoded = decodeUpstreamErrorResponse(value);
180
+ return Option.match(decoded, {
181
+ onNone: () => null,
182
+ onSome: (response) => {
183
+ if (response.message) return response.message;
184
+ for (const entry of response.errors ?? []) {
185
+ const message = entry.message;
186
+ if (message) return message;
187
+ }
188
+ return null;
189
+ }
190
+ });
191
+ };
192
+ var redactUpstreamBody = (body) => body.replaceAll(
193
+ /("(?:access_token|refresh_token|id_token|client_secret|token|authorization)"\s*:\s*")[^"]*(")/gi,
194
+ "$1[redacted]$2"
195
+ ).replaceAll(
196
+ /((?:access_token|refresh_token|id_token|client_secret|token|authorization)=)[^&\s]*/gi,
197
+ "$1[redacted]"
198
+ ).replaceAll(
199
+ /((?:authorization|access-token|refresh-token|id-token|client-secret|token)\s*:\s*)(?:bearer\s+)?[^\s,;]+/gi,
200
+ "$1[redacted]"
201
+ );
202
+ var upstreamTextMessage = (body) => {
203
+ const text = redactUpstreamBody(body.replaceAll(/\s+/g, " ").trim());
204
+ if (text.length === 0) return null;
205
+ return text.length > 500 ? `${text.slice(0, 500)}...` : text;
206
+ };
162
207
  var introspect = Effect.fn("GraphQL.introspect")(function* (endpoint, headers, queryParams) {
163
208
  const client = yield* HttpClient.HttpClient;
164
209
  const requestEndpoint = queryParams && Object.keys(queryParams).length > 0 ? (() => {
@@ -170,6 +215,8 @@ var introspect = Effect.fn("GraphQL.introspect")(function* (endpoint, headers, q
170
215
  })() : endpoint;
171
216
  let request = HttpClientRequest.post(requestEndpoint).pipe(
172
217
  HttpClientRequest.setHeader("Content-Type", "application/json"),
218
+ HttpClientRequest.setHeader("Accept", "application/json"),
219
+ HttpClientRequest.setHeader("User-Agent", "executor-graphql"),
173
220
  HttpClientRequest.bodyJsonUnsafe({
174
221
  query: INTROSPECTION_QUERY
175
222
  })
@@ -188,8 +235,15 @@ var introspect = Effect.fn("GraphQL.introspect")(function* (endpoint, headers, q
188
235
  )
189
236
  );
190
237
  if (response.status !== 200) {
238
+ const responseText = yield* response.text.pipe(Effect.catch(() => Effect.succeed("")));
239
+ const raw2 = responseText ? yield* Schema.decodeUnknownEffect(JsonTextSchema)(responseText).pipe(
240
+ Effect.catch(() => Effect.succeed(null))
241
+ ) : null;
242
+ const upstreamMessage = upstreamTextMessage(
243
+ (raw2 === null ? null : firstUpstreamErrorMessage(raw2)) ?? responseText
244
+ );
191
245
  return yield* new GraphqlIntrospectionError({
192
- message: `Introspection failed with status ${response.status}`
246
+ message: upstreamMessage ? `Introspection failed with status ${response.status}: ${upstreamMessage}` : `Introspection failed with status ${response.status}`
193
247
  });
194
248
  }
195
249
  const raw = yield* response.json.pipe(
@@ -208,8 +262,9 @@ var introspect = Effect.fn("GraphQL.introspect")(function* (endpoint, headers, q
208
262
  )
209
263
  );
210
264
  if (json.errors && Array.isArray(json.errors) && json.errors.length > 0) {
265
+ const upstreamMessage = firstUpstreamErrorMessage(json);
211
266
  return yield* new GraphqlIntrospectionError({
212
- message: `Introspection returned ${json.errors.length} error(s)`
267
+ message: upstreamMessage ? `Introspection returned ${json.errors.length} error(s): ${upstreamMessage}` : `Introspection returned ${json.errors.length} error(s)`
213
268
  });
214
269
  }
215
270
  if (!json.data?.__schema) {
@@ -229,7 +284,7 @@ var parseIntrospectionJson = (text) => Schema.decodeUnknownEffect(Schema.fromJso
229
284
  );
230
285
 
231
286
  // src/sdk/extract.ts
232
- import { Effect as Effect2, Match, Option } from "effect";
287
+ import { Effect as Effect2, Match, Option as Option2 } from "effect";
233
288
  var unwrapTypeName = (ref) => {
234
289
  if (ref.name) return ref.name;
235
290
  if (ref.ofType) return unwrapTypeName(ref.ofType);
@@ -296,7 +351,7 @@ var typeRefToJsonSchema = (ref, types) => Match.value(ref.kind).pipe(
296
351
  () => ({ type: "object" })
297
352
  ),
298
353
  Match.option,
299
- Option.getOrElse(() => ({}))
354
+ Option2.getOrElse(() => ({}))
300
355
  );
301
356
  var scalarToJsonSchema = (name) => Match.value(name).pipe(
302
357
  Match.whenOr("String", "ID", () => ({ type: "string" })),
@@ -304,7 +359,7 @@ var scalarToJsonSchema = (name) => Match.value(name).pipe(
304
359
  Match.when("Float", () => ({ type: "number" })),
305
360
  Match.when("Boolean", () => ({ type: "boolean" })),
306
361
  Match.option,
307
- Option.getOrElse(
362
+ Option2.getOrElse(
308
363
  () => ({ type: "string", description: `Custom scalar: ${name}` })
309
364
  )
310
365
  );
@@ -333,7 +388,7 @@ var formatTypeRef = (ref) => Match.value(ref.kind).pipe(
333
388
  Match.when("NON_NULL", () => ref.ofType ? `${formatTypeRef(ref.ofType)}!` : "Unknown!"),
334
389
  Match.when("LIST", () => ref.ofType ? `[${formatTypeRef(ref.ofType)}]` : "[Unknown]"),
335
390
  Match.option,
336
- Option.getOrElse(() => ref.name ?? "Unknown")
391
+ Option2.getOrElse(() => ref.name ?? "Unknown")
337
392
  );
338
393
  var extractFields = (_schema, kind, typeName, types) => {
339
394
  if (!typeName) return [];
@@ -345,16 +400,16 @@ var extractFields = (_schema, kind, typeName, types) => {
345
400
  name: arg.name,
346
401
  typeName: formatTypeRef(arg.type),
347
402
  required: isNonNull(arg.type),
348
- description: arg.description ? Option.some(arg.description) : Option.none()
403
+ description: arg.description ? Option2.some(arg.description) : Option2.none()
349
404
  })
350
405
  );
351
406
  const inputSchema = buildInputSchema(field.args, types);
352
407
  return ExtractedField.make({
353
408
  fieldName: field.name,
354
409
  kind,
355
- description: field.description ? Option.some(field.description) : Option.none(),
410
+ description: field.description ? Option2.some(field.description) : Option2.none(),
356
411
  arguments: args,
357
- inputSchema: inputSchema ? Option.some(inputSchema) : Option.none(),
412
+ inputSchema: inputSchema ? Option2.some(inputSchema) : Option2.none(),
358
413
  returnTypeName: unwrapTypeName(field.type)
359
414
  });
360
415
  });
@@ -371,7 +426,7 @@ var extract = (introspection) => Effect2.try({
371
426
  const mutationFields = extractFields(schema, "mutation", schema.mutationType?.name, typeMap);
372
427
  return {
373
428
  result: ExtractionResult.make({
374
- schemaName: Option.none(),
429
+ schemaName: Option2.none(),
375
430
  fields: [...queryFields, ...mutationFields]
376
431
  }),
377
432
  definitions
@@ -383,7 +438,7 @@ var extract = (introspection) => Effect2.try({
383
438
  });
384
439
 
385
440
  // src/sdk/invoke.ts
386
- import { Effect as Effect3, Option as Option2 } from "effect";
441
+ import { Effect as Effect3, Option as Option3 } from "effect";
387
442
  import { HttpClient as HttpClient2, HttpClientRequest as HttpClientRequest2 } from "effect/unstable/http";
388
443
  import { resolveSecretBackedMap } from "@executor-js/sdk/core";
389
444
  var resolveHeaders = (headers, secrets) => {
@@ -398,7 +453,7 @@ var resolveHeaders = (headers, secrets) => {
398
453
  missing: "drop",
399
454
  onMissing: (name) => new GraphqlInvocationError({
400
455
  message: `Missing secret for header "${name}"`,
401
- statusCode: Option2.none()
456
+ statusCode: Option3.none()
402
457
  })
403
458
  }).pipe(
404
459
  Effect3.catch(() => Effect3.succeed(void 0)),
@@ -467,7 +522,7 @@ var invoke = Effect3.fn("GraphQL.invoke")(function* (operation, args, endpoint,
467
522
  Effect3.mapError(
468
523
  (err) => new GraphqlInvocationError({
469
524
  message: "GraphQL request failed",
470
- statusCode: Option2.none(),
525
+ statusCode: Option3.none(),
471
526
  cause: err
472
527
  })
473
528
  )
@@ -500,378 +555,291 @@ var invokeWithLayer = (operation, args, endpoint, resolvedHeaders, resolvedQuery
500
555
  );
501
556
 
502
557
  // src/sdk/store.ts
503
- import { Effect as Effect4, Schema as Schema2 } from "effect";
558
+ import { Effect as Effect4, Option as Option4, Predicate, Schema as Schema2 } from "effect";
504
559
  import {
505
- ConfiguredCredentialBinding,
506
- defineSchema
560
+ ConfiguredCredentialBinding
507
561
  } from "@executor-js/sdk/core";
508
- var graphqlSchema = defineSchema({
509
- graphql_source: {
510
- fields: {
511
- id: { type: "string", required: true },
512
- scope_id: { type: "string", required: true, index: true },
513
- name: { type: "string", required: true },
514
- endpoint: { type: "string", required: true },
515
- auth_kind: {
516
- type: ["none", "oauth2"],
517
- required: true,
518
- defaultValue: "none"
519
- },
520
- auth_connection_slot: {
521
- type: "string",
522
- required: false
523
- }
524
- }
525
- },
526
- graphql_source_header: {
527
- fields: {
528
- id: { type: "string", required: true },
529
- scope_id: { type: "string", required: true, index: true },
530
- source_id: { type: "string", required: true, index: true },
531
- name: { type: "string", required: true },
532
- kind: {
533
- type: ["text", "binding"],
534
- required: true
535
- },
536
- text_value: { type: "string", required: false },
537
- slot_key: { type: "string", required: false },
538
- prefix: { type: "string", required: false }
539
- }
540
- },
541
- graphql_source_query_param: {
542
- fields: {
543
- id: { type: "string", required: true },
544
- scope_id: { type: "string", required: true, index: true },
545
- source_id: { type: "string", required: true, index: true },
546
- name: { type: "string", required: true },
547
- kind: {
548
- type: ["text", "binding"],
549
- required: true
550
- },
551
- text_value: { type: "string", required: false },
552
- slot_key: { type: "string", required: false },
553
- prefix: { type: "string", required: false }
554
- }
555
- },
556
- graphql_operation: {
557
- fields: {
558
- id: { type: "string", required: true },
559
- scope_id: { type: "string", required: true, index: true },
560
- source_id: { type: "string", required: true, index: true },
561
- binding: { type: "json", required: true }
562
- }
563
- }
564
- });
562
+ var graphqlSchema = {};
563
+ var SOURCE_COLLECTION = "source";
564
+ var OPERATION_COLLECTION = "operation";
565
565
  var OperationBindingFromJsonString = Schema2.fromJsonString(OperationBinding);
566
566
  var decodeOperationBindingFromJsonString = Schema2.decodeUnknownSync(
567
567
  OperationBindingFromJsonString
568
568
  );
569
569
  var decodeOperationBinding = Schema2.decodeUnknownSync(OperationBinding);
570
+ var encodeBinding = Schema2.encodeSync(OperationBinding);
570
571
  var decodeBinding = (value) => {
571
- if (typeof value === "string") {
572
- return decodeOperationBindingFromJsonString(value);
573
- }
572
+ if (typeof value === "string") return decodeOperationBindingFromJsonString(value);
574
573
  return decodeOperationBinding(value);
575
574
  };
576
- var encodeBinding = Schema2.encodeSync(OperationBinding);
577
575
  var toJsonRecord = (value) => value;
578
- var SourceRow = Schema2.Struct({
579
- id: Schema2.String,
580
- scope_id: Schema2.String,
581
- name: Schema2.String,
582
- endpoint: Schema2.String,
583
- auth_kind: Schema2.Literals(["none", "oauth2"]),
584
- auth_connection_slot: Schema2.NullOr(Schema2.String).pipe(Schema2.optionalKey)
576
+ var OptionalNullableString = Schema2.optional(Schema2.NullOr(Schema2.String));
577
+ var ConfiguredCredentialBindingStorage = Schema2.Struct({
578
+ kind: Schema2.Literal("binding"),
579
+ slot: Schema2.String,
580
+ prefix: OptionalNullableString
585
581
  });
586
- var ChildValueRow = Schema2.Struct({
582
+ var ConfiguredCredentialValueStorage = Schema2.Union([
583
+ Schema2.String,
584
+ ConfiguredCredentialBindingStorage
585
+ ]);
586
+ var CredentialMapStorage = Schema2.Record(Schema2.String, ConfiguredCredentialValueStorage);
587
+ var SourceStorage = Schema2.Struct({
588
+ namespace: Schema2.String,
589
+ scope: Schema2.String,
587
590
  name: Schema2.String,
588
- kind: Schema2.Literals(["text", "binding"]),
589
- text_value: Schema2.NullOr(Schema2.String).pipe(Schema2.optionalKey),
590
- slot_key: Schema2.NullOr(Schema2.String).pipe(Schema2.optionalKey),
591
- prefix: Schema2.NullOr(Schema2.String).pipe(Schema2.optionalKey)
591
+ endpoint: Schema2.String,
592
+ headers: Schema2.optional(CredentialMapStorage),
593
+ queryParams: Schema2.optional(CredentialMapStorage),
594
+ auth: GraphqlSourceAuth
592
595
  });
593
- var OperationRow = Schema2.Struct({
594
- id: Schema2.String,
595
- source_id: Schema2.String,
596
+ var OperationStorage = Schema2.Struct({
597
+ toolId: Schema2.String,
598
+ sourceId: Schema2.String,
596
599
  binding: Schema2.Unknown
597
600
  });
598
- var decodeSourceRow = Schema2.decodeUnknownSync(SourceRow);
599
- var decodeChildValueRow = Schema2.decodeUnknownSync(ChildValueRow);
600
- var decodeOperationRow = Schema2.decodeUnknownSync(OperationRow);
601
- var rowsToValueMap = (rows) => {
602
- const out = {};
603
- for (const rawRow of rows) {
604
- const row = decodeChildValueRow(rawRow);
605
- const name = row.name;
606
- if (row.kind === "binding" && typeof row.slot_key === "string") {
607
- out[name] = typeof row.prefix === "string" ? ConfiguredCredentialBinding.make({
608
- kind: "binding",
609
- slot: row.slot_key,
610
- prefix: row.prefix
611
- }) : ConfiguredCredentialBinding.make({
612
- kind: "binding",
613
- slot: row.slot_key
614
- });
615
- } else if (row.kind === "text" && typeof row.text_value === "string") {
616
- out[name] = row.text_value;
601
+ var decodeSourceStorage = Schema2.decodeUnknownOption(SourceStorage);
602
+ var decodeOperationStorage = Schema2.decodeUnknownOption(OperationStorage);
603
+ var normalizeCredentialMap = (values) => {
604
+ if (!values) return {};
605
+ const normalized = {};
606
+ for (const [name, value] of Object.entries(values)) {
607
+ if (typeof value === "string") {
608
+ normalized[name] = value;
609
+ continue;
617
610
  }
611
+ normalized[name] = value.prefix != null ? ConfiguredCredentialBinding.make({
612
+ kind: "binding",
613
+ slot: value.slot,
614
+ prefix: value.prefix
615
+ }) : ConfiguredCredentialBinding.make({
616
+ kind: "binding",
617
+ slot: value.slot
618
+ });
618
619
  }
619
- return out;
620
+ return normalized;
620
621
  };
621
- var valueToChildRow = (sourceId, scope, name, value) => {
622
- const id = JSON.stringify([sourceId, name]);
623
- if (typeof value === "string") {
624
- return {
625
- id,
626
- scope_id: scope,
627
- source_id: sourceId,
628
- name,
629
- kind: "text",
630
- text_value: value
631
- };
632
- }
622
+ var sourceData = (source) => ({
623
+ namespace: source.namespace,
624
+ scope: source.scope,
625
+ name: source.name,
626
+ endpoint: source.endpoint,
627
+ headers: source.headers,
628
+ queryParams: source.queryParams,
629
+ auth: source.auth
630
+ });
631
+ var operationData = (operation) => ({
632
+ toolId: operation.toolId,
633
+ sourceId: operation.sourceId,
634
+ binding: toJsonRecord(encodeBinding(operation.binding))
635
+ });
636
+ var rowToSource = (row) => {
637
+ const decoded = decodeSourceStorage(row.data);
638
+ if (Option4.isNone(decoded)) return null;
639
+ const source = decoded.value;
633
640
  return {
634
- id,
635
- scope_id: scope,
636
- source_id: sourceId,
637
- name,
638
- kind: "binding",
639
- slot_key: value.slot,
640
- prefix: value.prefix
641
+ namespace: source.namespace,
642
+ scope: source.scope,
643
+ name: source.name,
644
+ endpoint: source.endpoint,
645
+ headers: normalizeCredentialMap(source.headers),
646
+ queryParams: normalizeCredentialMap(source.queryParams),
647
+ auth: source.auth
641
648
  };
642
649
  };
643
- var rowToAuth = (row) => {
644
- if (row.auth_kind === "oauth2" && typeof row.auth_connection_slot === "string") {
645
- return { kind: "oauth2", connectionSlot: row.auth_connection_slot };
646
- }
647
- return { kind: "none" };
650
+ var rowToOperation = (row) => {
651
+ const decoded = decodeOperationStorage(row.data);
652
+ if (Option4.isNone(decoded)) return null;
653
+ const operation = decoded.value;
654
+ return {
655
+ toolId: operation.toolId,
656
+ sourceId: operation.sourceId,
657
+ binding: decodeBinding(operation.binding)
658
+ };
648
659
  };
649
660
  var makeDefaultGraphqlStore = ({
650
- adapter: db
661
+ pluginStorage
651
662
  }) => {
652
- const loadHeaders = (sourceId, scope) => db.findMany({
653
- model: "graphql_source_header",
654
- where: [
655
- { field: "source_id", value: sourceId },
656
- { field: "scope_id", value: scope }
657
- ]
658
- }).pipe(Effect4.map(rowsToValueMap));
659
- const loadQueryParams = (sourceId, scope) => db.findMany({
660
- model: "graphql_source_query_param",
661
- where: [
662
- { field: "source_id", value: sourceId },
663
- { field: "scope_id", value: scope }
664
- ]
665
- }).pipe(Effect4.map(rowsToValueMap));
666
- const rowToSourceWithChildren = (row) => Effect4.gen(function* () {
667
- const source = decodeSourceRow(row);
668
- const sourceId = source.id;
669
- const scope = source.scope_id;
670
- const headers = yield* loadHeaders(sourceId, scope);
671
- const queryParams = yield* loadQueryParams(sourceId, scope);
672
- return {
673
- namespace: sourceId,
674
- scope,
675
- name: source.name,
676
- endpoint: source.endpoint,
677
- headers,
678
- queryParams,
679
- auth: rowToAuth(source)
680
- };
681
- });
682
- const rowToOperation = (row) => {
683
- const operation = decodeOperationRow(row);
684
- return {
685
- toolId: operation.id,
686
- sourceId: operation.source_id,
687
- binding: decodeBinding(operation.binding)
688
- };
689
- };
690
- const replaceChildren = (model, sourceId, scope, values) => Effect4.gen(function* () {
691
- yield* db.deleteMany({
692
- model,
693
- where: [
694
- { field: "source_id", value: sourceId },
695
- { field: "scope_id", value: scope }
696
- ]
697
- });
698
- const entries = Object.entries(values);
699
- if (entries.length === 0) return;
700
- yield* db.createMany({
701
- model,
702
- data: entries.map(([name, value]) => valueToChildRow(sourceId, scope, name, value)),
703
- forceAllowId: true
704
- });
663
+ const listOperationRowsForSourceScope = (sourceId, scope) => pluginStorage.list({
664
+ collection: OPERATION_COLLECTION,
665
+ keyPrefix: `${sourceId}.`
666
+ }).pipe(
667
+ Effect4.map(
668
+ (rows) => rows.filter((row) => {
669
+ if (String(row.scopeId) !== scope) return false;
670
+ return rowToOperation(row)?.sourceId === sourceId;
671
+ })
672
+ )
673
+ );
674
+ const removeOperationsForSourceScope = (sourceId, scope) => Effect4.gen(function* () {
675
+ const rows = yield* listOperationRowsForSourceScope(sourceId, scope);
676
+ for (const row of rows) {
677
+ yield* pluginStorage.remove({
678
+ scope,
679
+ collection: OPERATION_COLLECTION,
680
+ key: row.key
681
+ });
682
+ }
705
683
  });
706
684
  const deleteSource = (namespace, scope) => Effect4.gen(function* () {
707
- yield* db.deleteMany({
708
- model: "graphql_operation",
709
- where: [
710
- { field: "source_id", value: namespace },
711
- { field: "scope_id", value: scope }
712
- ]
713
- });
714
- yield* db.deleteMany({
715
- model: "graphql_source_header",
716
- where: [
717
- { field: "source_id", value: namespace },
718
- { field: "scope_id", value: scope }
719
- ]
720
- });
721
- yield* db.deleteMany({
722
- model: "graphql_source_query_param",
723
- where: [
724
- { field: "source_id", value: namespace },
725
- { field: "scope_id", value: scope }
726
- ]
727
- });
728
- yield* db.delete({
729
- model: "graphql_source",
730
- where: [
731
- { field: "id", value: namespace },
732
- { field: "scope_id", value: scope }
733
- ]
685
+ yield* removeOperationsForSourceScope(namespace, scope);
686
+ yield* pluginStorage.remove({
687
+ scope,
688
+ collection: SOURCE_COLLECTION,
689
+ key: namespace
734
690
  });
735
691
  });
736
692
  return {
737
693
  upsertSource: (input, operations) => Effect4.gen(function* () {
738
694
  yield* deleteSource(input.namespace, input.scope);
739
- yield* db.create({
740
- model: "graphql_source",
741
- data: {
742
- id: input.namespace,
743
- scope_id: input.scope,
744
- name: input.name,
745
- endpoint: input.endpoint,
746
- auth_kind: input.auth.kind,
747
- auth_connection_slot: input.auth.kind === "oauth2" ? input.auth.connectionSlot : void 0
748
- },
749
- forceAllowId: true
695
+ yield* pluginStorage.put({
696
+ scope: input.scope,
697
+ collection: SOURCE_COLLECTION,
698
+ key: input.namespace,
699
+ data: sourceData(input)
750
700
  });
751
- yield* replaceChildren(
752
- "graphql_source_header",
753
- input.namespace,
754
- input.scope,
755
- input.headers
756
- );
757
- yield* replaceChildren(
758
- "graphql_source_query_param",
759
- input.namespace,
760
- input.scope,
761
- input.queryParams
762
- );
763
- if (operations.length > 0) {
764
- yield* db.createMany({
765
- model: "graphql_operation",
766
- data: operations.map((op) => ({
767
- id: op.toolId,
768
- scope_id: input.scope,
769
- source_id: op.sourceId,
770
- binding: toJsonRecord(encodeBinding(op.binding))
771
- })),
772
- forceAllowId: true
701
+ for (const operation of operations) {
702
+ yield* pluginStorage.put({
703
+ scope: input.scope,
704
+ collection: OPERATION_COLLECTION,
705
+ key: operation.toolId,
706
+ data: operationData(operation)
773
707
  });
774
708
  }
775
709
  }),
776
710
  updateSourceMeta: (namespace, scope, patch) => Effect4.gen(function* () {
777
- const existing = yield* db.findOne({
778
- model: "graphql_source",
779
- where: [
780
- { field: "id", value: namespace },
781
- { field: "scope_id", value: scope }
782
- ]
711
+ const existing = yield* pluginStorage.getAtScope({
712
+ scope,
713
+ collection: SOURCE_COLLECTION,
714
+ key: namespace
783
715
  });
784
716
  if (!existing) return;
785
- const update = {};
786
- if (patch.name !== void 0) update.name = patch.name;
787
- if (patch.endpoint !== void 0) update.endpoint = patch.endpoint;
788
- if (patch.auth !== void 0) {
789
- update.auth_kind = patch.auth.kind;
790
- update.auth_connection_slot = patch.auth.kind === "oauth2" ? patch.auth.connectionSlot : null;
791
- }
792
- if (Object.keys(update).length > 0) {
793
- yield* db.update({
794
- model: "graphql_source",
795
- where: [
796
- { field: "id", value: namespace },
797
- { field: "scope_id", value: scope }
798
- ],
799
- update
800
- });
801
- }
802
- if (patch.headers !== void 0) {
803
- yield* replaceChildren("graphql_source_header", namespace, scope, patch.headers);
804
- }
805
- if (patch.queryParams !== void 0) {
806
- yield* replaceChildren("graphql_source_query_param", namespace, scope, patch.queryParams);
807
- }
808
- }),
809
- getSource: (namespace, scope) => Effect4.gen(function* () {
810
- const row = yield* db.findOne({
811
- model: "graphql_source",
812
- where: [
813
- { field: "id", value: namespace },
814
- { field: "scope_id", value: scope }
815
- ]
816
- });
817
- if (!row) return null;
818
- return yield* rowToSourceWithChildren(row);
819
- }),
820
- listSources: () => Effect4.gen(function* () {
821
- const rows = yield* db.findMany({ model: "graphql_source" });
822
- return yield* Effect4.forEach(rows, rowToSourceWithChildren, {
823
- concurrency: "unbounded"
717
+ const source = rowToSource(existing);
718
+ if (!source) return;
719
+ yield* pluginStorage.put({
720
+ scope,
721
+ collection: SOURCE_COLLECTION,
722
+ key: namespace,
723
+ data: sourceData({
724
+ ...source,
725
+ name: patch.name ?? source.name,
726
+ endpoint: patch.endpoint ?? source.endpoint,
727
+ headers: patch.headers ?? source.headers,
728
+ queryParams: patch.queryParams ?? source.queryParams,
729
+ auth: patch.auth ?? source.auth
730
+ })
824
731
  });
825
732
  }),
826
- getOperationByToolId: (toolId, scope) => db.findOne({
827
- model: "graphql_operation",
828
- where: [
829
- { field: "id", value: toolId },
830
- { field: "scope_id", value: scope }
831
- ]
832
- }).pipe(Effect4.map((row) => row ? rowToOperation(row) : null)),
833
- listOperationsBySource: (sourceId, scope) => db.findMany({
834
- model: "graphql_operation",
835
- where: [
836
- { field: "source_id", value: sourceId },
837
- { field: "scope_id", value: scope }
838
- ]
839
- }).pipe(Effect4.map((rows) => rows.map(rowToOperation))),
733
+ getSource: (namespace, scope) => pluginStorage.getAtScope({ scope, collection: SOURCE_COLLECTION, key: namespace }).pipe(Effect4.map((row) => row ? rowToSource(row) : null)),
734
+ listSources: () => pluginStorage.list({ collection: SOURCE_COLLECTION }).pipe(Effect4.map((rows) => rows.map(rowToSource).filter(Predicate.isNotNull))),
735
+ getOperationByToolId: (toolId, scope) => pluginStorage.getAtScope({ scope, collection: OPERATION_COLLECTION, key: toolId }).pipe(Effect4.map((row) => row ? rowToOperation(row) : null)),
736
+ listOperationsBySource: (sourceId, scope) => listOperationRowsForSourceScope(sourceId, scope).pipe(
737
+ Effect4.map((rows) => rows.map(rowToOperation).filter(Predicate.isNotNull))
738
+ ),
840
739
  removeSource: (namespace, scope) => deleteSource(namespace, scope)
841
740
  };
842
741
  };
843
742
 
844
743
  // src/sdk/plugin.ts
845
- import { Effect as Effect5, Match as Match2, Option as Option3, Schema as Schema3 } from "effect";
744
+ import { Effect as Effect5, Match as Match2, Option as Option5, Schema as Schema3 } from "effect";
846
745
  import {
847
- ConnectionId,
848
- ConfiguredCredentialBinding as ConfiguredCredentialBinding2,
849
746
  definePlugin,
850
747
  tool,
748
+ defaultSourceInstallScopeId,
851
749
  ScopeId,
852
- SecretId,
853
750
  SourceDetectionResult,
854
- StorageError
751
+ StorageError,
752
+ ToolResult
855
753
  } from "@executor-js/sdk/core";
754
+ import {
755
+ compileHttpNamedCredentialMap,
756
+ OAuth2SourceConfig,
757
+ httpCredentialInputToBindingValue
758
+ } from "@executor-js/sdk/http-source";
856
759
  import {
857
760
  headersToConfigValues
858
761
  } from "@executor-js/config";
859
- var StaticAddSourceInputSchema = Schema3.Struct({
762
+ var GraphqlErrorBody = Schema3.Struct({ message: Schema3.String });
763
+ var GraphqlErrorsBody = Schema3.Array(Schema3.Unknown);
764
+ var decodeGraphqlErrorBody = Schema3.decodeUnknownOption(GraphqlErrorBody);
765
+ var decodeGraphqlErrorsBody = Schema3.decodeUnknownOption(GraphqlErrorsBody);
766
+ var decodeGraphqlErrors = (errors) => Option5.getOrUndefined(decodeGraphqlErrorsBody(errors));
767
+ var extractGraphqlErrorMessage = (errors) => errors.map((error) => Option5.getOrUndefined(decodeGraphqlErrorBody(error))?.message).find((message) => message !== void 0 && message.length > 0);
768
+ var GraphqlInitialCredentialsInputSchema = Schema3.Struct({
860
769
  scope: Schema3.String,
770
+ headers: Schema3.optional(Schema3.Record(Schema3.String, GraphqlCredentialInput)),
771
+ queryParams: Schema3.optional(Schema3.Record(Schema3.String, GraphqlCredentialInput)),
772
+ auth: Schema3.optional(GraphqlSourceAuthInput)
773
+ });
774
+ var StaticAddSourceInputSchema = Schema3.Struct({
861
775
  endpoint: Schema3.String,
862
- name: Schema3.optional(Schema3.String),
776
+ name: Schema3.String,
863
777
  introspectionJson: Schema3.optional(Schema3.String),
864
- namespace: Schema3.optional(Schema3.String),
778
+ namespace: Schema3.String,
779
+ headers: Schema3.optional(Schema3.Record(Schema3.String, GraphqlConfiguredValueInput)),
780
+ queryParams: Schema3.optional(Schema3.Record(Schema3.String, GraphqlConfiguredValueInput)),
781
+ oauth2: Schema3.optional(OAuth2SourceConfig),
782
+ credentials: Schema3.optional(GraphqlInitialCredentialsInputSchema)
783
+ });
784
+ var SourceConfigureInputSchema = Schema3.Struct({
785
+ name: Schema3.optional(Schema3.String),
786
+ endpoint: Schema3.optional(Schema3.String),
865
787
  headers: Schema3.optional(Schema3.Record(Schema3.String, GraphqlCredentialInput)),
866
788
  queryParams: Schema3.optional(Schema3.Record(Schema3.String, GraphqlCredentialInput)),
867
- credentialTargetScope: Schema3.optional(Schema3.String),
868
789
  auth: Schema3.optional(GraphqlSourceAuthInput)
869
790
  });
791
+ var StaticConfigureSourceInputSchema = Schema3.Struct({
792
+ source: Schema3.Struct({
793
+ id: Schema3.String,
794
+ scope: Schema3.String
795
+ }),
796
+ scope: Schema3.String,
797
+ ...SourceConfigureInputSchema.fields
798
+ });
799
+ var StaticConfigureSourceOutputSchema = Schema3.Struct({
800
+ configured: Schema3.Boolean
801
+ });
802
+ var StaticGetSourceInputSchema = Schema3.Struct({
803
+ namespace: Schema3.String,
804
+ scope: Schema3.String
805
+ });
806
+ var StaticGetSourceOutputSchema = Schema3.Struct({
807
+ source: Schema3.NullOr(Schema3.Unknown)
808
+ });
870
809
  var StaticAddSourceInputStandardSchema = Schema3.toStandardSchemaV1(
871
810
  Schema3.toStandardJSONSchemaV1(StaticAddSourceInputSchema)
872
811
  );
873
812
  var StaticAddSourceOutputStandardSchema = Schema3.toStandardSchemaV1(
874
- Schema3.toStandardJSONSchemaV1(Schema3.Struct({ toolCount: Schema3.Number }))
813
+ Schema3.toStandardJSONSchemaV1(
814
+ Schema3.Struct({
815
+ namespace: Schema3.String,
816
+ source: Schema3.Struct({
817
+ id: Schema3.String,
818
+ scope: Schema3.String
819
+ }),
820
+ toolCount: Schema3.Number
821
+ })
822
+ )
823
+ );
824
+ var StaticGetSourceInputStandardSchema = Schema3.toStandardSchemaV1(
825
+ Schema3.toStandardJSONSchemaV1(StaticGetSourceInputSchema)
826
+ );
827
+ var StaticGetSourceOutputStandardSchema = Schema3.toStandardSchemaV1(
828
+ Schema3.toStandardJSONSchemaV1(StaticGetSourceOutputSchema)
829
+ );
830
+ var StaticConfigureSourceInputStandardSchema = Schema3.toStandardSchemaV1(
831
+ Schema3.toStandardJSONSchemaV1(StaticConfigureSourceInputSchema)
832
+ );
833
+ var StaticConfigureSourceOutputStandardSchema = Schema3.toStandardSchemaV1(
834
+ Schema3.toStandardJSONSchemaV1(StaticConfigureSourceOutputSchema)
835
+ );
836
+ var graphqlToolFailure = (code, message, details) => ToolResult.fail({
837
+ code,
838
+ message,
839
+ ...details === void 0 ? {} : { details }
840
+ });
841
+ var resolveStaticScopeInput = (ctx, value) => String(
842
+ ctx.scopes.find((scope) => scope.name === value || String(scope.id) === value)?.id ?? value
875
843
  );
876
844
  var urlMatchesToken = (url, token) => {
877
845
  const re = new RegExp(`(?:^|[^a-z0-9])${token}(?:$|[^a-z0-9])`, "i");
@@ -889,7 +857,7 @@ var formatTypeRef2 = (ref) => Match2.value(ref.kind).pipe(
889
857
  Match2.when("NON_NULL", () => ref.ofType ? `${formatTypeRef2(ref.ofType)}!` : "Unknown!"),
890
858
  Match2.when("LIST", () => ref.ofType ? `[${formatTypeRef2(ref.ofType)}]` : "[Unknown]"),
891
859
  Match2.option,
892
- Option3.getOrElse(() => ref.name ?? "Unknown")
860
+ Option5.getOrElse(() => ref.name ?? "Unknown")
893
861
  );
894
862
  var unwrapTypeName2 = (ref) => {
895
863
  if (ref.name) return ref.name;
@@ -945,7 +913,7 @@ var prepareOperations = (fields, introspection) => {
945
913
  return fields.map((extracted) => {
946
914
  const prefix = extracted.kind === "mutation" ? "mutation" : "query";
947
915
  const toolPath = `${prefix}.${extracted.fieldName}`;
948
- const description = Option3.getOrElse(
916
+ const description = Option5.getOrElse(
949
917
  extracted.description,
950
918
  () => `GraphQL ${extracted.kind}: ${extracted.fieldName} -> ${extracted.returnTypeName}`
951
919
  );
@@ -961,7 +929,7 @@ var prepareOperations = (fields, introspection) => {
961
929
  return {
962
930
  toolPath,
963
931
  description,
964
- inputSchema: Option3.getOrUndefined(extracted.inputSchema),
932
+ inputSchema: Option5.getOrUndefined(extracted.inputSchema),
965
933
  binding
966
934
  };
967
935
  });
@@ -993,26 +961,6 @@ var toGraphqlConfigEntry = (namespace, config) => {
993
961
  var GRAPHQL_PLUGIN_ID = "graphql";
994
962
  var scopeRanks = (ctx) => new Map(ctx.scopes.map((scope, index) => [String(scope.id), index]));
995
963
  var scopeRank = (ranks, scopeId) => ranks.get(scopeId) ?? Infinity;
996
- var coreBindingToGraphqlBinding = (binding) => GraphqlSourceBindingRef.make({
997
- sourceId: binding.sourceId,
998
- sourceScopeId: binding.sourceScopeId,
999
- scopeId: binding.scopeId,
1000
- slot: binding.slotKey,
1001
- value: binding.value,
1002
- createdAt: binding.createdAt,
1003
- updatedAt: binding.updatedAt
1004
- });
1005
- var listGraphqlSourceBindings = (ctx, sourceId, sourceScope) => Effect5.gen(function* () {
1006
- const ranks = scopeRanks(ctx);
1007
- const sourceSourceRank = scopeRank(ranks, sourceScope);
1008
- if (sourceSourceRank === Infinity) return [];
1009
- const bindings = yield* ctx.credentialBindings.listForSource({
1010
- pluginId: GRAPHQL_PLUGIN_ID,
1011
- sourceId,
1012
- sourceScope: ScopeId.make(sourceScope)
1013
- });
1014
- return bindings.filter((binding) => scopeRank(ranks, binding.scopeId) <= sourceSourceRank).map(coreBindingToGraphqlBinding);
1015
- });
1016
964
  var resolveGraphqlSourceBinding = (ctx, sourceId, sourceScope, slot) => Effect5.gen(function* () {
1017
965
  const ranks = scopeRanks(ctx);
1018
966
  const sourceSourceRank = scopeRank(ranks, sourceScope);
@@ -1025,7 +973,7 @@ var resolveGraphqlSourceBinding = (ctx, sourceId, sourceScope, slot) => Effect5.
1025
973
  const binding = bindings.filter(
1026
974
  (candidate) => candidate.slotKey === slot && scopeRank(ranks, candidate.scopeId) <= sourceSourceRank
1027
975
  ).sort((a, b) => scopeRank(ranks, a.scopeId) - scopeRank(ranks, b.scopeId))[0];
1028
- return binding ? coreBindingToGraphqlBinding(binding) : null;
976
+ return binding ?? null;
1029
977
  });
1030
978
  var validateGraphqlBindingTarget = (ctx, input) => Effect5.gen(function* () {
1031
979
  const ranks = scopeRanks(ctx);
@@ -1051,70 +999,93 @@ var validateGraphqlBindingTarget = (ctx, input) => Effect5.gen(function* () {
1051
999
  });
1052
1000
  }
1053
1001
  });
1054
- var bindingTargetScope = (targetScope, bindings) => {
1055
- if (bindings.length === 0) return Effect5.succeed(void 0);
1056
- if (targetScope) return Effect5.succeed(targetScope);
1057
- return Effect5.fail(
1058
- new GraphqlIntrospectionError({
1059
- message: "credentialTargetScope is required when adding direct GraphQL credentials"
1060
- })
1061
- );
1062
- };
1063
- var targetScopeForBinding = (fallbackTargetScope, binding) => {
1064
- const targetScope = binding.targetScope ?? fallbackTargetScope;
1065
- if (targetScope) return Effect5.succeed(targetScope);
1066
- return Effect5.fail(
1067
- new GraphqlIntrospectionError({
1068
- message: "credentialTargetScope is required when adding direct GraphQL credentials"
1069
- })
1070
- );
1071
- };
1072
- var canonicalizeCredentialMap = (values, slotForName) => {
1073
- const nextValues = {};
1074
- const bindings = [];
1002
+ var canonicalizeCredentialMap = compileHttpNamedCredentialMap;
1003
+ var canonicalizeConfiguredValueMap = (values, slotForName) => {
1004
+ const next = {};
1075
1005
  for (const [name, value] of Object.entries(values ?? {})) {
1076
1006
  if (typeof value === "string") {
1077
- nextValues[name] = value;
1007
+ next[name] = value;
1078
1008
  continue;
1079
1009
  }
1080
- if ("kind" in value) {
1081
- nextValues[name] = value;
1082
- continue;
1083
- }
1084
- const slot = slotForName(name);
1085
- nextValues[name] = ConfiguredCredentialBinding2.make({
1010
+ next[name] = {
1086
1011
  kind: "binding",
1087
- slot,
1012
+ slot: slotForName(name),
1088
1013
  prefix: value.prefix
1089
- });
1090
- bindings.push({
1091
- slot,
1092
- targetScope: "targetScope" in value ? value.targetScope : void 0,
1093
- value: {
1094
- kind: "secret",
1095
- secretId: SecretId.make(value.secretId),
1096
- ..."secretScopeId" in value && value.secretScopeId ? { secretScopeId: value.secretScopeId } : {}
1097
- }
1098
- });
1014
+ };
1015
+ }
1016
+ return next;
1017
+ };
1018
+ var resolveConfiguredValueMap = (values) => {
1019
+ if (!values) return void 0;
1020
+ const resolved = {};
1021
+ for (const [name, value] of Object.entries(values)) {
1022
+ if (typeof value === "string") resolved[name] = value;
1099
1023
  }
1100
- return { values: nextValues, bindings };
1024
+ return Object.keys(resolved).length > 0 ? resolved : void 0;
1101
1025
  };
1026
+ var authFromOAuth2Source = (oauth2) => oauth2 ? { kind: "oauth2", connectionSlot: oauth2.connectionSlot } : { kind: "none" };
1102
1027
  var canonicalizeAuth = (auth) => {
1103
- if (!auth || auth.kind === "none") return { auth: { kind: "none" }, bindings: [] };
1104
- if ("connectionSlot" in auth) return { auth, bindings: [] };
1028
+ if (!auth || "kind" in auth || !auth.oauth2) return { auth: { kind: "none" }, bindings: [] };
1029
+ const connection = auth.oauth2.connection;
1105
1030
  return {
1106
1031
  auth: { kind: "oauth2", connectionSlot: GRAPHQL_OAUTH_CONNECTION_SLOT },
1107
- bindings: [
1032
+ bindings: connection ? [
1108
1033
  {
1109
1034
  slot: GRAPHQL_OAUTH_CONNECTION_SLOT,
1110
- value: {
1111
- kind: "connection",
1112
- connectionId: ConnectionId.make(auth.connectionId)
1113
- }
1035
+ value: httpCredentialInputToBindingValue(connection)
1114
1036
  }
1115
- ]
1037
+ ] : []
1116
1038
  };
1117
1039
  };
1040
+ var resolveInitialCredentialValueMap = (ctx, values, bindings, targetScope) => Effect5.gen(function* () {
1041
+ const bySlot = new Map(bindings.map((binding) => [binding.slot, binding.value]));
1042
+ const resolved = {};
1043
+ for (const [name, value] of Object.entries(values)) {
1044
+ if (typeof value === "string") {
1045
+ resolved[name] = value;
1046
+ continue;
1047
+ }
1048
+ const binding = bySlot.get(value.slot);
1049
+ if (binding?.kind === "secret") {
1050
+ const secret = yield* ctx.secrets.getAtScope(binding.secretId, binding.secretScopeId ?? ScopeId.make(targetScope)).pipe(
1051
+ Effect5.catchTag(
1052
+ "SecretOwnedByConnectionError",
1053
+ () => Effect5.fail(
1054
+ new GraphqlIntrospectionError({
1055
+ message: `Secret not found for ${name}`
1056
+ })
1057
+ )
1058
+ )
1059
+ );
1060
+ if (secret === null) {
1061
+ return yield* new GraphqlIntrospectionError({
1062
+ message: `Missing secret "${binding.secretId}" for ${name}`
1063
+ });
1064
+ }
1065
+ resolved[name] = value.prefix ? `${value.prefix}${secret}` : secret;
1066
+ continue;
1067
+ }
1068
+ if (binding?.kind === "text") {
1069
+ resolved[name] = value.prefix ? `${value.prefix}${binding.text}` : binding.text;
1070
+ }
1071
+ }
1072
+ return Object.keys(resolved).length > 0 ? resolved : void 0;
1073
+ });
1074
+ var resolveInitialOAuthHeaders = (ctx, bindings, targetScope) => Effect5.gen(function* () {
1075
+ const connection = bindings.find(
1076
+ (binding) => binding.slot === GRAPHQL_OAUTH_CONNECTION_SLOT && binding.value.kind === "connection"
1077
+ );
1078
+ if (!connection || connection.value.kind !== "connection") return void 0;
1079
+ const connectionId = connection.value.connectionId;
1080
+ const accessToken = yield* ctx.connections.accessTokenAtScope(connectionId, ScopeId.make(targetScope)).pipe(
1081
+ Effect5.mapError(
1082
+ ({ message }) => new GraphqlIntrospectionError({
1083
+ message: `Failed to resolve OAuth connection "${connectionId}": ${message}`
1084
+ })
1085
+ )
1086
+ );
1087
+ return { Authorization: `Bearer ${accessToken}` };
1088
+ });
1118
1089
  var resolveGraphqlBindingValueMap = (ctx, values, params) => Effect5.gen(function* () {
1119
1090
  if (!values) return void 0;
1120
1091
  const resolved = {};
@@ -1169,7 +1140,7 @@ var resolveGraphqlStoredOAuthHeader = (ctx, sourceId, sourceScope, auth) => Effe
1169
1140
  if (binding?.value.kind !== "connection") {
1170
1141
  return yield* new GraphqlInvocationError({
1171
1142
  message: `Missing OAuth connection binding for GraphQL source "${sourceId}"`,
1172
- statusCode: Option3.none()
1143
+ statusCode: Option5.none()
1173
1144
  });
1174
1145
  }
1175
1146
  const accessToken = yield* ctx.connections.accessTokenAtScope(
@@ -1179,127 +1150,61 @@ var resolveGraphqlStoredOAuthHeader = (ctx, sourceId, sourceScope, auth) => Effe
1179
1150
  return { Authorization: `Bearer ${accessToken}` };
1180
1151
  });
1181
1152
  var makeGraphqlExtension = (ctx, httpClientLayer, configFile) => {
1182
- const resolveCredentialInputMap = (values, params) => Effect5.gen(function* () {
1183
- if (!values) return void 0;
1184
- const resolved = {};
1185
- for (const [name, value] of Object.entries(values)) {
1186
- if (typeof value === "string") {
1187
- resolved[name] = value;
1188
- continue;
1189
- }
1190
- if ("kind" in value) {
1191
- const slotResolved = yield* resolveGraphqlBindingValueMap(
1192
- ctx,
1193
- { [name]: value },
1194
- {
1195
- sourceId: params.sourceId,
1196
- sourceScope: params.sourceScope,
1197
- missingLabel: params.missingLabel,
1198
- makeError: params.makeError
1199
- }
1200
- );
1201
- if (slotResolved?.[name] !== void 0) resolved[name] = slotResolved[name];
1202
- continue;
1203
- }
1204
- const secretScope = "secretScopeId" in value ? value.secretScopeId ?? value.targetScope : params.targetScope ?? params.sourceScope;
1205
- const secret = yield* ctx.secrets.getAtScope(SecretId.make(value.secretId), secretScope).pipe(
1206
- Effect5.catchTag(
1207
- "SecretOwnedByConnectionError",
1208
- () => Effect5.fail(
1209
- params.makeError(`Secret not found for ${params.missingLabel} "${name}"`)
1210
- )
1211
- )
1212
- );
1213
- if (secret === null) {
1214
- return yield* Effect5.fail(
1215
- params.makeError(
1216
- `Missing secret "${value.secretId}" for ${params.missingLabel} "${name}"`
1217
- )
1218
- );
1219
- }
1220
- resolved[name] = value.prefix ? `${value.prefix}${secret}` : secret;
1221
- }
1222
- return Object.keys(resolved).length > 0 ? resolved : void 0;
1223
- });
1224
- const resolveOAuthInputHeader = (sourceId, sourceScope, targetScope, auth) => Effect5.gen(function* () {
1225
- if (!auth || auth.kind === "none") return void 0;
1226
- const connection = "connectionId" in auth ? { id: auth.connectionId, scope: targetScope ?? sourceScope } : yield* Effect5.gen(function* () {
1227
- const binding = yield* resolveGraphqlSourceBinding(
1228
- ctx,
1229
- sourceId,
1230
- sourceScope,
1231
- auth.connectionSlot
1232
- );
1233
- return binding?.value.kind === "connection" ? { id: binding.value.connectionId, scope: binding.scopeId } : null;
1234
- });
1235
- if (connection === null) {
1236
- return yield* new GraphqlIntrospectionError({
1237
- message: `Missing OAuth connection binding for "${sourceId}"`
1238
- });
1239
- }
1240
- const accessToken = yield* ctx.connections.accessTokenAtScope(connection.id, connection.scope).pipe(
1241
- Effect5.mapError(
1242
- () => new GraphqlIntrospectionError({
1243
- message: `Failed to resolve OAuth connection "${connection.id}"`
1244
- })
1245
- )
1246
- );
1247
- return { Authorization: `Bearer ${accessToken}` };
1248
- });
1249
1153
  const addSourceInternal = (config) => ctx.transaction(
1250
1154
  Effect5.gen(function* () {
1251
- const namespace = config.namespace ?? namespaceFromEndpoint(config.endpoint);
1252
- const canonicalHeaders = canonicalizeCredentialMap(config.headers, graphqlHeaderSlot);
1253
- const canonicalQueryParams = canonicalizeCredentialMap(
1155
+ const namespace = config.namespace;
1156
+ const canonicalHeaders = canonicalizeConfiguredValueMap(config.headers, graphqlHeaderSlot);
1157
+ const canonicalQueryParams = canonicalizeConfiguredValueMap(
1254
1158
  config.queryParams,
1255
1159
  graphqlQueryParamSlot
1256
1160
  );
1257
- const canonicalAuth = canonicalizeAuth(config.auth);
1258
- const directBindings = [
1259
- ...canonicalHeaders.bindings,
1260
- ...canonicalQueryParams.bindings,
1261
- ...canonicalAuth.bindings
1161
+ const initialHeaders = config.credentials?.headers !== void 0 ? canonicalizeCredentialMap(config.credentials.headers, graphqlHeaderSlot) : null;
1162
+ const initialQueryParams = config.credentials?.queryParams !== void 0 ? canonicalizeCredentialMap(config.credentials.queryParams, graphqlQueryParamSlot) : null;
1163
+ const initialAuth = config.credentials?.auth !== void 0 ? canonicalizeAuth(config.credentials.auth) : null;
1164
+ const auth = config.oauth2 ? authFromOAuth2Source(config.oauth2) : initialAuth?.auth ?? { kind: "none" };
1165
+ const initialBindings = [
1166
+ ...initialHeaders?.bindings ?? [],
1167
+ ...initialQueryParams?.bindings ?? [],
1168
+ ...initialAuth?.bindings ?? []
1262
1169
  ];
1263
- for (const binding of directBindings) {
1264
- const bindingTargetScope2 = yield* targetScopeForBinding(
1265
- config.credentialTargetScope,
1266
- binding
1267
- );
1170
+ const initialScope = config.credentials?.scope;
1171
+ if (initialScope && initialBindings.length > 0) {
1268
1172
  yield* validateGraphqlBindingTarget(ctx, {
1269
1173
  sourceId: namespace,
1270
1174
  sourceScope: config.scope,
1271
- targetScope: bindingTargetScope2
1175
+ targetScope: initialScope
1272
1176
  });
1273
1177
  }
1274
- const targetScope = directBindings[0] !== void 0 ? yield* targetScopeForBinding(config.credentialTargetScope, directBindings[0]) : void 0;
1275
1178
  let introspectionResult;
1276
1179
  if (config.introspectionJson) {
1277
1180
  introspectionResult = yield* parseIntrospectionJson(config.introspectionJson);
1278
1181
  } else {
1279
- const resolvedHeaders = yield* resolveCredentialInputMap(config.headers, {
1280
- sourceId: namespace,
1281
- sourceScope: config.scope,
1282
- targetScope,
1283
- missingLabel: "header",
1284
- makeError: (message) => new GraphqlIntrospectionError({ message })
1285
- });
1286
- const oauthHeader = yield* resolveOAuthInputHeader(
1287
- namespace,
1288
- config.scope,
1289
- targetScope,
1290
- config.auth
1291
- );
1292
- const resolvedQueryParams = yield* resolveCredentialInputMap(config.queryParams, {
1293
- sourceId: namespace,
1294
- sourceScope: config.scope,
1295
- targetScope,
1296
- missingLabel: "query parameter",
1297
- makeError: (message) => new GraphqlIntrospectionError({ message })
1298
- });
1182
+ const resolvedInitialHeaders = initialHeaders && initialScope ? yield* resolveInitialCredentialValueMap(
1183
+ ctx,
1184
+ canonicalHeaders,
1185
+ initialHeaders.bindings,
1186
+ initialScope
1187
+ ) : void 0;
1188
+ const resolvedOAuthHeaders = initialAuth && initialScope ? yield* resolveInitialOAuthHeaders(ctx, initialAuth.bindings, initialScope) : void 0;
1189
+ const resolvedHeaders = {
1190
+ ...resolveConfiguredValueMap(config.headers) ?? {},
1191
+ ...resolvedInitialHeaders ?? {},
1192
+ ...resolvedOAuthHeaders ?? {}
1193
+ };
1194
+ const resolvedInitialQueryParams = initialQueryParams && initialScope ? yield* resolveInitialCredentialValueMap(
1195
+ ctx,
1196
+ canonicalQueryParams,
1197
+ initialQueryParams.bindings,
1198
+ initialScope
1199
+ ) : void 0;
1200
+ const resolvedQueryParams = {
1201
+ ...resolveConfiguredValueMap(config.queryParams) ?? {},
1202
+ ...resolvedInitialQueryParams ?? {}
1203
+ };
1299
1204
  introspectionResult = yield* introspect(
1300
1205
  config.endpoint,
1301
- { ...resolvedHeaders ?? {}, ...oauthHeader ?? {} },
1302
- resolvedQueryParams
1206
+ Object.keys(resolvedHeaders).length > 0 ? resolvedHeaders : void 0,
1207
+ Object.keys(resolvedQueryParams).length > 0 ? resolvedQueryParams : void 0
1303
1208
  ).pipe(Effect5.provide(httpClientLayer));
1304
1209
  }
1305
1210
  const { result, definitions } = yield* extract(introspectionResult);
@@ -1310,9 +1215,9 @@ var makeGraphqlExtension = (ctx, httpClientLayer, configFile) => {
1310
1215
  scope: config.scope,
1311
1216
  name: displayName,
1312
1217
  endpoint: config.endpoint,
1313
- headers: canonicalHeaders.values,
1314
- queryParams: canonicalQueryParams.values,
1315
- auth: canonicalAuth.auth
1218
+ headers: canonicalHeaders,
1219
+ queryParams: canonicalQueryParams,
1220
+ auth
1316
1221
  };
1317
1222
  const storedOps = prepared.map((p) => ({
1318
1223
  toolId: `${namespace}.${p.toolPath}`,
@@ -1335,6 +1240,23 @@ var makeGraphqlExtension = (ctx, httpClientLayer, configFile) => {
1335
1240
  inputSchema: p.inputSchema
1336
1241
  }))
1337
1242
  });
1243
+ if (initialScope && initialBindings.length > 0) {
1244
+ yield* ctx.credentialBindings.replaceForSource({
1245
+ targetScope: ScopeId.make(initialScope),
1246
+ pluginId: GRAPHQL_PLUGIN_ID,
1247
+ sourceId: namespace,
1248
+ sourceScope: ScopeId.make(config.scope),
1249
+ slotPrefixes: [
1250
+ ...config.credentials?.headers !== void 0 ? ["header:"] : [],
1251
+ ...config.credentials?.queryParams !== void 0 ? ["query_param:"] : [],
1252
+ ...config.credentials?.auth !== void 0 ? ["auth:"] : []
1253
+ ],
1254
+ bindings: initialBindings.map((binding) => ({
1255
+ slotKey: binding.slot,
1256
+ value: binding.value
1257
+ }))
1258
+ });
1259
+ }
1338
1260
  if (Object.keys(definitions).length > 0) {
1339
1261
  yield* ctx.core.definitions.register({
1340
1262
  sourceId: namespace,
@@ -1342,25 +1264,57 @@ var makeGraphqlExtension = (ctx, httpClientLayer, configFile) => {
1342
1264
  definitions
1343
1265
  });
1344
1266
  }
1345
- if (directBindings.length > 0) {
1346
- for (const binding of directBindings) {
1347
- const bindingTargetScope2 = yield* targetScopeForBinding(
1348
- config.credentialTargetScope,
1349
- binding
1350
- );
1351
- yield* ctx.credentialBindings.set({
1352
- targetScope: ScopeId.make(bindingTargetScope2),
1267
+ return { toolCount: prepared.length, namespace };
1268
+ })
1269
+ );
1270
+ const configureSource = (namespace, scope, targetScope, input) => Effect5.gen(function* () {
1271
+ const existing = yield* ctx.storage.getSource(namespace, scope);
1272
+ if (!existing) return;
1273
+ const canonicalHeaders = input.headers !== void 0 ? canonicalizeCredentialMap(input.headers, graphqlHeaderSlot) : null;
1274
+ const canonicalQueryParams = input.queryParams !== void 0 ? canonicalizeCredentialMap(input.queryParams, graphqlQueryParamSlot) : null;
1275
+ const canonicalAuth = input.auth !== void 0 ? canonicalizeAuth(input.auth) : null;
1276
+ const directBindings = [
1277
+ ...canonicalHeaders?.bindings ?? [],
1278
+ ...canonicalQueryParams?.bindings ?? [],
1279
+ ...canonicalAuth?.bindings ?? []
1280
+ ];
1281
+ if (directBindings.length > 0) {
1282
+ yield* validateGraphqlBindingTarget(ctx, {
1283
+ sourceId: namespace,
1284
+ sourceScope: scope,
1285
+ targetScope
1286
+ });
1287
+ }
1288
+ const affectedPrefixes = [
1289
+ ...input.headers !== void 0 ? ["header:"] : [],
1290
+ ...input.queryParams !== void 0 ? ["query_param:"] : [],
1291
+ ...input.auth !== void 0 ? ["auth:"] : []
1292
+ ];
1293
+ yield* ctx.transaction(
1294
+ Effect5.gen(function* () {
1295
+ yield* ctx.storage.updateSourceMeta(namespace, scope, {
1296
+ name: input.name?.trim() || void 0,
1297
+ endpoint: input.endpoint,
1298
+ headers: canonicalHeaders?.values,
1299
+ queryParams: canonicalQueryParams?.values,
1300
+ auth: canonicalAuth?.auth
1301
+ });
1302
+ if (affectedPrefixes.length > 0 || directBindings.length > 0) {
1303
+ yield* ctx.credentialBindings.replaceForSource({
1304
+ targetScope: ScopeId.make(targetScope),
1353
1305
  pluginId: GRAPHQL_PLUGIN_ID,
1354
1306
  sourceId: namespace,
1355
- sourceScope: ScopeId.make(config.scope),
1356
- slotKey: binding.slot,
1357
- value: binding.value
1307
+ sourceScope: ScopeId.make(scope),
1308
+ slotPrefixes: affectedPrefixes,
1309
+ bindings: directBindings.map((binding) => ({
1310
+ slotKey: binding.slot,
1311
+ value: binding.value
1312
+ }))
1358
1313
  });
1359
1314
  }
1360
- }
1361
- return { toolCount: prepared.length, namespace };
1362
- })
1363
- );
1315
+ })
1316
+ );
1317
+ });
1364
1318
  return {
1365
1319
  addSource: (config) => addSourceInternal(config).pipe(
1366
1320
  Effect5.tap(
@@ -1384,93 +1338,15 @@ var makeGraphqlExtension = (ctx, httpClientLayer, configFile) => {
1384
1338
  }
1385
1339
  }),
1386
1340
  getSource: (namespace, scope) => ctx.storage.getSource(namespace, scope),
1387
- updateSource: (namespace, scope, input) => Effect5.gen(function* () {
1388
- const existing = yield* ctx.storage.getSource(namespace, scope);
1389
- if (!existing) return;
1390
- const canonicalHeaders = input.headers !== void 0 ? canonicalizeCredentialMap(input.headers, graphqlHeaderSlot) : null;
1391
- const canonicalQueryParams = input.queryParams !== void 0 ? canonicalizeCredentialMap(input.queryParams, graphqlQueryParamSlot) : null;
1392
- const canonicalAuth = input.auth !== void 0 ? canonicalizeAuth(input.auth) : null;
1393
- const directBindings = [
1394
- ...canonicalHeaders?.bindings ?? [],
1395
- ...canonicalQueryParams?.bindings ?? [],
1396
- ...canonicalAuth?.bindings ?? []
1397
- ];
1398
- const targetScope = yield* bindingTargetScope(input.credentialTargetScope, directBindings);
1399
- if (targetScope) {
1400
- yield* validateGraphqlBindingTarget(ctx, {
1401
- sourceId: namespace,
1402
- sourceScope: scope,
1403
- targetScope
1404
- });
1405
- }
1406
- const affectedPrefixes = [
1407
- ...input.headers !== void 0 ? ["header:"] : [],
1408
- ...input.queryParams !== void 0 ? ["query_param:"] : [],
1409
- ...input.auth !== void 0 ? ["auth:"] : []
1410
- ];
1411
- const replacementTargetScope = targetScope ?? input.credentialTargetScope ?? scope;
1412
- yield* ctx.transaction(
1413
- Effect5.gen(function* () {
1414
- yield* ctx.storage.updateSourceMeta(namespace, scope, {
1415
- name: input.name?.trim() || void 0,
1416
- endpoint: input.endpoint,
1417
- headers: canonicalHeaders?.values,
1418
- queryParams: canonicalQueryParams?.values,
1419
- auth: canonicalAuth?.auth
1420
- });
1421
- if (affectedPrefixes.length > 0 || directBindings.length > 0) {
1422
- yield* ctx.credentialBindings.replaceForSource({
1423
- targetScope: ScopeId.make(replacementTargetScope),
1424
- pluginId: GRAPHQL_PLUGIN_ID,
1425
- sourceId: namespace,
1426
- sourceScope: ScopeId.make(scope),
1427
- slotPrefixes: affectedPrefixes,
1428
- bindings: directBindings.map((binding) => ({
1429
- slotKey: binding.slot,
1430
- value: binding.value
1431
- }))
1432
- });
1433
- }
1434
- })
1435
- );
1436
- }),
1437
- listSourceBindings: (sourceId, sourceScope) => listGraphqlSourceBindings(ctx, sourceId, sourceScope),
1438
- setSourceBinding: (input) => Effect5.gen(function* () {
1439
- yield* validateGraphqlBindingTarget(ctx, {
1440
- sourceId: input.sourceId,
1441
- sourceScope: input.sourceScope,
1442
- targetScope: input.scope
1443
- });
1444
- const binding = yield* ctx.credentialBindings.set({
1445
- targetScope: input.scope,
1446
- pluginId: GRAPHQL_PLUGIN_ID,
1447
- sourceId: input.sourceId,
1448
- sourceScope: input.sourceScope,
1449
- slotKey: input.slot,
1450
- value: input.value
1451
- });
1452
- return coreBindingToGraphqlBinding(binding);
1453
- }),
1454
- removeSourceBinding: (sourceId, sourceScope, slot, scope) => Effect5.gen(function* () {
1455
- yield* validateGraphqlBindingTarget(ctx, {
1456
- sourceId,
1457
- sourceScope,
1458
- targetScope: scope
1459
- });
1460
- yield* ctx.credentialBindings.remove({
1461
- targetScope: ScopeId.make(scope),
1462
- pluginId: GRAPHQL_PLUGIN_ID,
1463
- sourceId,
1464
- sourceScope: ScopeId.make(sourceScope),
1465
- slotKey: slot
1466
- });
1467
- })
1341
+ configureSource,
1342
+ configure: (source, input) => configureSource(source.id, source.scope, input.scope, input)
1468
1343
  };
1469
1344
  };
1470
1345
  var graphqlPlugin = definePlugin((options) => {
1471
1346
  return {
1472
1347
  id: "graphql",
1473
1348
  packageName: "@executor-js/plugin-graphql",
1349
+ sourcePresets: graphqlPresets,
1474
1350
  schema: graphqlSchema,
1475
1351
  storage: (deps) => makeDefaultGraphqlStore(deps),
1476
1352
  extension: (ctx) => makeGraphqlExtension(
@@ -1478,22 +1354,90 @@ var graphqlPlugin = definePlugin((options) => {
1478
1354
  options?.httpClientLayer ?? ctx.httpClientLayer,
1479
1355
  options?.configFile
1480
1356
  ),
1357
+ sourceConfigure: {
1358
+ type: "graphql",
1359
+ schema: SourceConfigureInputSchema,
1360
+ configure: ({ ctx, sourceId, sourceScope, targetScope, config }) => makeGraphqlExtension(
1361
+ ctx,
1362
+ options?.httpClientLayer ?? ctx.httpClientLayer,
1363
+ options?.configFile
1364
+ ).configureSource(
1365
+ sourceId,
1366
+ sourceScope,
1367
+ targetScope,
1368
+ config
1369
+ )
1370
+ },
1481
1371
  staticSources: (self) => [
1482
1372
  {
1483
1373
  id: "graphql",
1484
1374
  kind: "executor",
1485
1375
  name: "GraphQL",
1486
1376
  tools: [
1377
+ tool({
1378
+ name: "getSource",
1379
+ description: "Inspect an existing GraphQL source, including endpoint, auth mode, configured headers/query params, and credential slots. Use this before repairing an existing source with `graphql.configureSource`, `secrets.create`, or `oauth.start`.",
1380
+ inputSchema: StaticGetSourceInputStandardSchema,
1381
+ outputSchema: StaticGetSourceOutputStandardSchema,
1382
+ execute: (input, { ctx }) => Effect5.map(
1383
+ self.getSource(input.namespace, resolveStaticScopeInput(ctx, input.scope)),
1384
+ (source) => ToolResult.ok({ source })
1385
+ )
1386
+ }),
1487
1387
  tool({
1488
1388
  name: "addSource",
1489
- description: "Add a GraphQL endpoint and register its operations as tools",
1389
+ description: "Add a GraphQL endpoint and register its operations as tools. Executor chooses the source install scope (local scope locally, organization scope in cloud) and returns it as `source`. For API keys or bearer tokens, first call `executor.coreTools.secrets.create` at the user's chosen credential scope and pass secret refs through `credentials`. For OAuth, start the browser flow with `executor.coreTools.oauth.start` using `credentialScope` set to the user's chosen personal or organization credential scope, verify completion with `connections.list`, then bind the connection through `credentials` or `graphql.configureSource`.",
1490
1390
  annotations: {
1491
1391
  requiresApproval: true,
1492
1392
  approvalDescription: "Add a GraphQL source"
1493
1393
  },
1494
1394
  inputSchema: StaticAddSourceInputStandardSchema,
1495
1395
  outputSchema: StaticAddSourceOutputStandardSchema,
1496
- execute: (input) => self.addSource(input)
1396
+ execute: (input, { ctx }) => {
1397
+ const sourceScope = defaultSourceInstallScopeId(ctx.scopes);
1398
+ if (sourceScope === null) {
1399
+ return Effect5.succeed(
1400
+ graphqlToolFailure(
1401
+ "source_scope_unavailable",
1402
+ "Cannot add a GraphQL source because this executor has no source install scope."
1403
+ )
1404
+ );
1405
+ }
1406
+ return self.addSource({ ...input, scope: sourceScope }).pipe(
1407
+ Effect5.map(
1408
+ (result) => ToolResult.ok({
1409
+ ...result,
1410
+ source: { id: result.namespace, scope: sourceScope }
1411
+ })
1412
+ ),
1413
+ Effect5.catchTags({
1414
+ GraphqlIntrospectionError: ({ message }) => Effect5.succeed(graphqlToolFailure("graphql_introspection_failed", message)),
1415
+ GraphqlExtractionError: ({ message }) => Effect5.succeed(graphqlToolFailure("graphql_extraction_failed", message))
1416
+ })
1417
+ );
1418
+ }
1419
+ }),
1420
+ tool({
1421
+ name: "configureSource",
1422
+ description: 'Configure an existing GraphQL source with concrete fields. Use `source` returned by `graphql.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}`.',
1423
+ annotations: {
1424
+ requiresApproval: true,
1425
+ approvalDescription: "Configure a GraphQL source"
1426
+ },
1427
+ inputSchema: StaticConfigureSourceInputStandardSchema,
1428
+ outputSchema: StaticConfigureSourceOutputStandardSchema,
1429
+ execute: (input, { ctx }) => {
1430
+ const { source, ...config } = input;
1431
+ const sourceScope = resolveStaticScopeInput(ctx, source.scope);
1432
+ const targetScope = resolveStaticScopeInput(ctx, config.scope);
1433
+ return Effect5.as(
1434
+ self.configure(
1435
+ { id: source.id, scope: sourceScope },
1436
+ { ...config, scope: targetScope }
1437
+ ),
1438
+ ToolResult.ok({ configured: true })
1439
+ );
1440
+ }
1497
1441
  })
1498
1442
  ]
1499
1443
  }
@@ -1505,27 +1449,27 @@ var graphqlPlugin = definePlugin((options) => {
1505
1449
  if (!op) {
1506
1450
  return yield* new GraphqlInvocationError({
1507
1451
  message: `No GraphQL operation found for tool "${toolRow.id}"`,
1508
- statusCode: Option3.none()
1452
+ statusCode: Option5.none()
1509
1453
  });
1510
1454
  }
1511
1455
  const source = yield* ctx.storage.getSource(op.sourceId, toolScope);
1512
1456
  if (!source) {
1513
1457
  return yield* new GraphqlInvocationError({
1514
1458
  message: `No GraphQL source found for "${op.sourceId}"`,
1515
- statusCode: Option3.none()
1459
+ statusCode: Option5.none()
1516
1460
  });
1517
1461
  }
1518
1462
  const resolvedHeaders = (yield* resolveGraphqlBindingValueMap(ctx, source.headers, {
1519
1463
  sourceId: source.namespace,
1520
1464
  sourceScope: source.scope,
1521
1465
  missingLabel: "header",
1522
- makeError: (message) => new GraphqlInvocationError({ message, statusCode: Option3.none() })
1466
+ makeError: (message) => new GraphqlInvocationError({ message, statusCode: Option5.none() })
1523
1467
  })) ?? {};
1524
1468
  const resolvedQueryParams = (yield* resolveGraphqlBindingValueMap(ctx, source.queryParams, {
1525
1469
  sourceId: source.namespace,
1526
1470
  sourceScope: source.scope,
1527
1471
  missingLabel: "query parameter",
1528
- makeError: (message) => new GraphqlInvocationError({ message, statusCode: Option3.none() })
1472
+ makeError: (message) => new GraphqlInvocationError({ message, statusCode: Option5.none() })
1529
1473
  })) ?? {};
1530
1474
  const oauthHeader = yield* resolveGraphqlStoredOAuthHeader(
1531
1475
  ctx,
@@ -1542,7 +1486,28 @@ var graphqlPlugin = definePlugin((options) => {
1542
1486
  resolvedQueryParams,
1543
1487
  httpClientLayer
1544
1488
  );
1545
- return result;
1489
+ const errors = decodeGraphqlErrors(result.errors);
1490
+ if (errors !== void 0 && errors.length > 0) {
1491
+ const firstMessage = extractGraphqlErrorMessage(errors);
1492
+ return ToolResult.fail({
1493
+ code: "graphql_errors",
1494
+ message: firstMessage !== void 0 ? firstMessage : "GraphQL request returned errors",
1495
+ details: { errors }
1496
+ });
1497
+ }
1498
+ if (result.status < 200 || result.status >= 300) {
1499
+ return ToolResult.fail({
1500
+ code: "graphql_http_error",
1501
+ status: result.status,
1502
+ message: `GraphQL request failed with HTTP ${result.status}`,
1503
+ details: {
1504
+ status: result.status,
1505
+ data: result.data,
1506
+ errors: result.errors
1507
+ }
1508
+ });
1509
+ }
1510
+ return ToolResult.ok(result.data);
1546
1511
  }),
1547
1512
  resolveAnnotations: ({ ctx, sourceId, toolRows }) => Effect5.gen(function* () {
1548
1513
  const scopes = /* @__PURE__ */ new Set();
@@ -1592,7 +1557,7 @@ var graphqlPlugin = definePlugin((options) => {
1592
1557
  try: () => new URL(trimmed),
1593
1558
  catch: (cause) => cause
1594
1559
  }).pipe(Effect5.option);
1595
- if (Option3.isNone(parsed)) return null;
1560
+ if (Option5.isNone(parsed)) return null;
1596
1561
  const ok = yield* introspect(trimmed).pipe(
1597
1562
  Effect5.provide(httpClientLayer),
1598
1563
  Effect5.map(() => true),
@@ -1633,4 +1598,4 @@ export {
1633
1598
  makeDefaultGraphqlStore,
1634
1599
  graphqlPlugin
1635
1600
  };
1636
- //# sourceMappingURL=chunk-PO2TPM5B.js.map
1601
+ //# sourceMappingURL=chunk-7S2FM3ZF.js.map