@executor-js/plugin-graphql 1.4.33 → 1.5.0

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 (54) hide show
  1. package/dist/AddGraphqlSource-P3D3UXRJ.js +179 -0
  2. package/dist/AddGraphqlSource-P3D3UXRJ.js.map +1 -0
  3. package/dist/EditGraphqlSource-FVF67CTP.js +38 -0
  4. package/dist/EditGraphqlSource-FVF67CTP.js.map +1 -0
  5. package/dist/GraphqlAccountsPanel-GBNFHLFH.js +9 -0
  6. package/dist/GraphqlAccountsPanel-GBNFHLFH.js.map +1 -0
  7. package/dist/api/group.d.ts +108 -119
  8. package/dist/api/handlers.d.ts +9 -7
  9. package/dist/api/index.d.ts +117 -104
  10. package/dist/chunk-2Y3J3CVO.js +191 -0
  11. package/dist/chunk-2Y3J3CVO.js.map +1 -0
  12. package/dist/chunk-ADQTI2OK.js +1309 -0
  13. package/dist/chunk-ADQTI2OK.js.map +1 -0
  14. package/dist/{chunk-UIAHATHP.js → chunk-N5GJE7R6.js} +42 -58
  15. package/dist/chunk-N5GJE7R6.js.map +1 -0
  16. package/dist/chunk-VCYDSSIK.js +79 -0
  17. package/dist/chunk-VCYDSSIK.js.map +1 -0
  18. package/dist/client.js +7 -7
  19. package/dist/client.js.map +1 -1
  20. package/dist/core.js +20 -28
  21. package/dist/index.js +2 -2
  22. package/dist/react/AddGraphqlSource.d.ts +1 -1
  23. package/dist/react/EditGraphqlSource.d.ts +2 -2
  24. package/dist/react/GraphqlAccountsPanel.d.ts +6 -0
  25. package/dist/react/GraphqlSignInButton.d.ts +6 -2
  26. package/dist/react/GraphqlSourceFields.d.ts +2 -2
  27. package/dist/react/atoms.d.ts +95 -205
  28. package/dist/react/auth-method-config.d.ts +9 -0
  29. package/dist/react/client.d.ts +108 -97
  30. package/dist/react/defaults.d.ts +16 -2
  31. package/dist/react/index.d.ts +2 -2
  32. package/dist/react/source-plugin.d.ts +2 -2
  33. package/dist/sdk/errors.d.ts +8 -6
  34. package/dist/sdk/index.d.ts +5 -5
  35. package/dist/sdk/introspect.d.ts +1 -1
  36. package/dist/sdk/invoke.d.ts +1 -4
  37. package/dist/sdk/plugin.d.ts +94 -104
  38. package/dist/sdk/store.d.ts +11 -28
  39. package/dist/sdk/types.d.ts +110 -72
  40. package/package.json +5 -4
  41. package/dist/AddGraphqlSource-CJCUUYNM.js +0 -250
  42. package/dist/AddGraphqlSource-CJCUUYNM.js.map +0 -1
  43. package/dist/EditGraphqlSource-YLTPUYW4.js +0 -267
  44. package/dist/EditGraphqlSource-YLTPUYW4.js.map +0 -1
  45. package/dist/GraphqlSourceSummary-YWJX6ONU.js +0 -70
  46. package/dist/GraphqlSourceSummary-YWJX6ONU.js.map +0 -1
  47. package/dist/chunk-2252RTCE.js +0 -1730
  48. package/dist/chunk-2252RTCE.js.map +0 -1
  49. package/dist/chunk-D3FN3ZDA.js +0 -125
  50. package/dist/chunk-D3FN3ZDA.js.map +0 -1
  51. package/dist/chunk-M4SJY6CB.js +0 -45
  52. package/dist/chunk-M4SJY6CB.js.map +0 -1
  53. package/dist/chunk-UIAHATHP.js.map +0 -1
  54. package/dist/react/GraphqlSourceSummary.d.ts +0 -5
@@ -1,1730 +0,0 @@
1
- import {
2
- graphqlPresets
3
- } from "./chunk-D6E4WAYW.js";
4
- import {
5
- ExtractedField,
6
- ExtractionResult,
7
- GRAPHQL_OAUTH_CONNECTION_SLOT,
8
- GraphqlArgument,
9
- GraphqlAuthRequiredError,
10
- GraphqlConfiguredValueInput,
11
- GraphqlCredentialInput,
12
- GraphqlExtractionError,
13
- GraphqlIntrospectionError,
14
- GraphqlInvocationError,
15
- GraphqlSourceAuth,
16
- GraphqlSourceAuthInput,
17
- InvocationResult,
18
- OperationBinding,
19
- graphqlHeaderSlot,
20
- graphqlQueryParamSlot
21
- } from "./chunk-UIAHATHP.js";
22
-
23
- // src/sdk/introspect.ts
24
- import { Effect, Option, Schema } from "effect";
25
- import { HttpClient, HttpClientRequest } from "effect/unstable/http";
26
- var INTROSPECTION_QUERY = `
27
- query IntrospectionQuery {
28
- __schema {
29
- queryType { name }
30
- mutationType { name }
31
- types {
32
- kind
33
- name
34
- description
35
- fields(includeDeprecated: false) {
36
- name
37
- description
38
- args {
39
- name
40
- description
41
- type {
42
- ...TypeRef
43
- }
44
- defaultValue
45
- }
46
- type {
47
- ...TypeRef
48
- }
49
- }
50
- inputFields {
51
- name
52
- description
53
- type {
54
- ...TypeRef
55
- }
56
- defaultValue
57
- }
58
- enumValues(includeDeprecated: false) {
59
- name
60
- description
61
- }
62
- }
63
- }
64
- }
65
-
66
- fragment TypeRef on __Type {
67
- kind
68
- name
69
- ofType {
70
- kind
71
- name
72
- ofType {
73
- kind
74
- name
75
- ofType {
76
- kind
77
- name
78
- ofType {
79
- kind
80
- name
81
- ofType {
82
- kind
83
- name
84
- ofType {
85
- kind
86
- name
87
- }
88
- }
89
- }
90
- }
91
- }
92
- }
93
- }
94
- `;
95
- var IntrospectionTypeRefLeaf = Schema.Struct({
96
- kind: Schema.String,
97
- name: Schema.NullOr(Schema.String),
98
- ofType: Schema.optional(Schema.Null)
99
- });
100
- var IntrospectionTypeRef5 = Schema.Struct({
101
- kind: Schema.String,
102
- name: Schema.NullOr(Schema.String),
103
- ofType: Schema.optional(Schema.NullOr(IntrospectionTypeRefLeaf))
104
- });
105
- var IntrospectionTypeRef4 = Schema.Struct({
106
- kind: Schema.String,
107
- name: Schema.NullOr(Schema.String),
108
- ofType: Schema.optional(Schema.NullOr(IntrospectionTypeRef5))
109
- });
110
- var IntrospectionTypeRef3 = Schema.Struct({
111
- kind: Schema.String,
112
- name: Schema.NullOr(Schema.String),
113
- ofType: Schema.optional(Schema.NullOr(IntrospectionTypeRef4))
114
- });
115
- var IntrospectionTypeRef2 = Schema.Struct({
116
- kind: Schema.String,
117
- name: Schema.NullOr(Schema.String),
118
- ofType: Schema.optional(Schema.NullOr(IntrospectionTypeRef3))
119
- });
120
- var IntrospectionTypeRefSchema = Schema.Struct({
121
- kind: Schema.String,
122
- name: Schema.NullOr(Schema.String),
123
- ofType: Schema.optional(Schema.NullOr(IntrospectionTypeRef2))
124
- });
125
- var IntrospectionInputValueSchema = Schema.Struct({
126
- name: Schema.String,
127
- description: Schema.NullOr(Schema.String),
128
- type: IntrospectionTypeRefSchema,
129
- defaultValue: Schema.NullOr(Schema.String)
130
- });
131
- var IntrospectionFieldSchema = Schema.Struct({
132
- name: Schema.String,
133
- description: Schema.NullOr(Schema.String),
134
- args: Schema.Array(IntrospectionInputValueSchema),
135
- type: IntrospectionTypeRefSchema
136
- });
137
- var IntrospectionTypeSchema = Schema.Struct({
138
- kind: Schema.String,
139
- name: Schema.String,
140
- description: Schema.NullOr(Schema.String),
141
- fields: Schema.NullOr(Schema.Array(IntrospectionFieldSchema)),
142
- inputFields: Schema.NullOr(Schema.Array(IntrospectionInputValueSchema)),
143
- enumValues: Schema.NullOr(
144
- Schema.Array(
145
- Schema.Struct({
146
- name: Schema.String,
147
- description: Schema.NullOr(Schema.String)
148
- })
149
- )
150
- )
151
- });
152
- var IntrospectionResultSchema = Schema.Struct({
153
- __schema: Schema.Struct({
154
- queryType: Schema.NullOr(Schema.Struct({ name: Schema.String })),
155
- mutationType: Schema.NullOr(Schema.Struct({ name: Schema.String })),
156
- types: Schema.Array(IntrospectionTypeSchema)
157
- })
158
- });
159
- var IntrospectionResponseSchema = Schema.Struct({
160
- data: Schema.optional(IntrospectionResultSchema),
161
- errors: Schema.optional(Schema.Array(Schema.Unknown))
162
- });
163
- var UpstreamErrorResponseSchema = Schema.Struct({
164
- message: Schema.optional(Schema.String),
165
- errors: Schema.optional(
166
- Schema.Array(
167
- Schema.Struct({
168
- message: Schema.optional(Schema.String)
169
- })
170
- )
171
- )
172
- });
173
- var IntrospectionJsonSchema = Schema.Union([
174
- Schema.Struct({ data: IntrospectionResultSchema }),
175
- IntrospectionResultSchema
176
- ]);
177
- var JsonTextSchema = Schema.fromJsonString(Schema.Unknown);
178
- var decodeUpstreamErrorResponse = Schema.decodeUnknownOption(UpstreamErrorResponseSchema);
179
- var firstUpstreamErrorMessage = (value) => {
180
- const decoded = decodeUpstreamErrorResponse(value);
181
- return Option.match(decoded, {
182
- onNone: () => null,
183
- onSome: (response) => {
184
- if (response.message) return response.message;
185
- for (const entry of response.errors ?? []) {
186
- const message = entry.message;
187
- if (message) return message;
188
- }
189
- return null;
190
- }
191
- });
192
- };
193
- var redactUpstreamBody = (body) => body.replaceAll(
194
- /("(?:access_token|refresh_token|id_token|client_secret|token|authorization)"\s*:\s*")[^"]*(")/gi,
195
- "$1[redacted]$2"
196
- ).replaceAll(
197
- /((?:access_token|refresh_token|id_token|client_secret|token|authorization)=)[^&\s]*/gi,
198
- "$1[redacted]"
199
- ).replaceAll(
200
- /((?:authorization|access-token|refresh-token|id-token|client-secret|token)\s*:\s*)(?:bearer\s+)?[^\s,;]+/gi,
201
- "$1[redacted]"
202
- );
203
- var upstreamTextMessage = (body) => {
204
- const text = redactUpstreamBody(body.replaceAll(/\s+/g, " ").trim());
205
- if (text.length === 0) return null;
206
- return text.length > 500 ? `${text.slice(0, 500)}...` : text;
207
- };
208
- var introspect = Effect.fn("GraphQL.introspect")(function* (endpoint, headers, queryParams) {
209
- const client = yield* HttpClient.HttpClient;
210
- const requestEndpoint = queryParams && Object.keys(queryParams).length > 0 ? (() => {
211
- const url = new URL(endpoint);
212
- for (const [name, value] of Object.entries(queryParams)) {
213
- url.searchParams.set(name, value);
214
- }
215
- return url.toString();
216
- })() : endpoint;
217
- let request = HttpClientRequest.post(requestEndpoint).pipe(
218
- HttpClientRequest.setHeader("Content-Type", "application/json"),
219
- HttpClientRequest.setHeader("Accept", "application/json"),
220
- HttpClientRequest.setHeader("User-Agent", "executor-graphql"),
221
- HttpClientRequest.bodyJsonUnsafe({
222
- query: INTROSPECTION_QUERY
223
- })
224
- );
225
- if (headers) {
226
- for (const [k, v] of Object.entries(headers)) {
227
- request = HttpClientRequest.setHeader(request, k, v);
228
- }
229
- }
230
- const response = yield* client.execute(request).pipe(
231
- Effect.tapCause((cause) => Effect.logError("graphql introspection request failed", cause)),
232
- Effect.mapError(
233
- () => new GraphqlIntrospectionError({
234
- message: "Failed to reach GraphQL endpoint"
235
- })
236
- )
237
- );
238
- if (response.status !== 200) {
239
- const responseText = yield* response.text.pipe(Effect.catch(() => Effect.succeed("")));
240
- const raw2 = responseText ? yield* Schema.decodeUnknownEffect(JsonTextSchema)(responseText).pipe(
241
- Effect.catch(() => Effect.succeed(null))
242
- ) : null;
243
- const upstreamMessage = upstreamTextMessage(
244
- (raw2 === null ? null : firstUpstreamErrorMessage(raw2)) ?? responseText
245
- );
246
- return yield* new GraphqlIntrospectionError({
247
- message: upstreamMessage ? `Introspection failed with status ${response.status}: ${upstreamMessage}` : `Introspection failed with status ${response.status}`
248
- });
249
- }
250
- const raw = yield* response.json.pipe(
251
- Effect.tapCause((cause) => Effect.logError("graphql introspection JSON parse failed", cause)),
252
- Effect.mapError(
253
- () => new GraphqlIntrospectionError({
254
- message: `Failed to parse introspection response as JSON`
255
- })
256
- )
257
- );
258
- const json = yield* Schema.decodeUnknownEffect(IntrospectionResponseSchema)(raw).pipe(
259
- Effect.mapError(
260
- () => new GraphqlIntrospectionError({
261
- message: "Introspection response has an invalid shape"
262
- })
263
- )
264
- );
265
- if (json.errors && Array.isArray(json.errors) && json.errors.length > 0) {
266
- const upstreamMessage = firstUpstreamErrorMessage(json);
267
- return yield* new GraphqlIntrospectionError({
268
- message: upstreamMessage ? `Introspection returned ${json.errors.length} error(s): ${upstreamMessage}` : `Introspection returned ${json.errors.length} error(s)`
269
- });
270
- }
271
- if (!json.data?.__schema) {
272
- return yield* new GraphqlIntrospectionError({
273
- message: "Introspection response missing __schema"
274
- });
275
- }
276
- return json.data;
277
- });
278
- var parseIntrospectionJson = (text) => Schema.decodeUnknownEffect(Schema.fromJsonString(IntrospectionJsonSchema))(text).pipe(
279
- Effect.map((parsed) => "data" in parsed ? parsed.data : parsed),
280
- Effect.mapError(
281
- () => new GraphqlIntrospectionError({
282
- message: "Failed to parse introspection JSON"
283
- })
284
- )
285
- );
286
-
287
- // src/sdk/extract.ts
288
- import { Effect as Effect2, Match, Option as Option2 } from "effect";
289
- var unwrapTypeName = (ref) => {
290
- if (ref.name) return ref.name;
291
- if (ref.ofType) return unwrapTypeName(ref.ofType);
292
- return "Unknown";
293
- };
294
- var isNonNull = (ref) => ref.kind === "NON_NULL";
295
- var buildDefinitions = (types) => {
296
- const defs = {};
297
- for (const [name, type] of types) {
298
- if (name.startsWith("__")) continue;
299
- if (type.kind === "INPUT_OBJECT" && type.inputFields) {
300
- const properties = {};
301
- const required = [];
302
- for (const field of type.inputFields) {
303
- const schema = typeRefToJsonSchema(field.type, types);
304
- if (field.description) {
305
- schema.description = field.description;
306
- }
307
- properties[field.name] = schema;
308
- if (isNonNull(field.type)) {
309
- required.push(field.name);
310
- }
311
- }
312
- const def = { type: "object", properties };
313
- if (required.length > 0) def.required = required;
314
- if (type.description) def.description = type.description;
315
- defs[name] = def;
316
- }
317
- if (type.kind === "ENUM" && type.enumValues) {
318
- defs[name] = {
319
- type: "string",
320
- enum: type.enumValues.map((v) => v.name),
321
- ...type.description ? { description: type.description } : {}
322
- };
323
- }
324
- }
325
- return defs;
326
- };
327
- var typeRefToJsonSchema = (ref, types) => Match.value(ref.kind).pipe(
328
- Match.when(
329
- "NON_NULL",
330
- () => ref.ofType ? typeRefToJsonSchema(ref.ofType, types) : {}
331
- ),
332
- Match.when(
333
- "LIST",
334
- () => ({
335
- type: "array",
336
- items: ref.ofType ? typeRefToJsonSchema(ref.ofType, types) : {}
337
- })
338
- ),
339
- Match.when("SCALAR", () => scalarToJsonSchema(ref.name ?? "String")),
340
- Match.when(
341
- "ENUM",
342
- () => ref.name ? { $ref: `#/$defs/${ref.name}` } : { type: "string" }
343
- ),
344
- Match.when(
345
- "INPUT_OBJECT",
346
- () => ref.name ? { $ref: `#/$defs/${ref.name}` } : { type: "object" }
347
- ),
348
- Match.whenOr(
349
- "OBJECT",
350
- "INTERFACE",
351
- "UNION",
352
- () => ({ type: "object" })
353
- ),
354
- Match.option,
355
- Option2.getOrElse(() => ({}))
356
- );
357
- var scalarToJsonSchema = (name) => Match.value(name).pipe(
358
- Match.whenOr("String", "ID", () => ({ type: "string" })),
359
- Match.when("Int", () => ({ type: "integer" })),
360
- Match.when("Float", () => ({ type: "number" })),
361
- Match.when("Boolean", () => ({ type: "boolean" })),
362
- Match.option,
363
- Option2.getOrElse(
364
- () => ({ type: "string", description: `Custom scalar: ${name}` })
365
- )
366
- );
367
- var buildInputSchema = (args, types) => {
368
- if (args.length === 0) return void 0;
369
- const properties = {};
370
- const required = [];
371
- for (const arg of args) {
372
- const schema = typeRefToJsonSchema(arg.type, types);
373
- if (arg.description) {
374
- schema.description = arg.description;
375
- }
376
- properties[arg.name] = schema;
377
- if (isNonNull(arg.type)) {
378
- required.push(arg.name);
379
- }
380
- }
381
- const inputSchema = {
382
- type: "object",
383
- properties
384
- };
385
- if (required.length > 0) inputSchema.required = required;
386
- return inputSchema;
387
- };
388
- var formatTypeRef = (ref) => Match.value(ref.kind).pipe(
389
- Match.when("NON_NULL", () => ref.ofType ? `${formatTypeRef(ref.ofType)}!` : "Unknown!"),
390
- Match.when("LIST", () => ref.ofType ? `[${formatTypeRef(ref.ofType)}]` : "[Unknown]"),
391
- Match.option,
392
- Option2.getOrElse(() => ref.name ?? "Unknown")
393
- );
394
- var extractFields = (_schema, kind, typeName, types) => {
395
- if (!typeName) return [];
396
- const type = types.get(typeName);
397
- if (!type?.fields) return [];
398
- return type.fields.filter((f) => !f.name.startsWith("__")).map((field) => {
399
- const args = field.args.map(
400
- (arg) => GraphqlArgument.make({
401
- name: arg.name,
402
- typeName: formatTypeRef(arg.type),
403
- required: isNonNull(arg.type),
404
- description: arg.description ? Option2.some(arg.description) : Option2.none()
405
- })
406
- );
407
- const inputSchema = buildInputSchema(field.args, types);
408
- return ExtractedField.make({
409
- fieldName: field.name,
410
- kind,
411
- description: field.description ? Option2.some(field.description) : Option2.none(),
412
- arguments: args,
413
- inputSchema: inputSchema ? Option2.some(inputSchema) : Option2.none(),
414
- returnTypeName: unwrapTypeName(field.type)
415
- });
416
- });
417
- };
418
- var extract = (introspection) => Effect2.try({
419
- try: () => {
420
- const schema = introspection.__schema;
421
- const typeMap = /* @__PURE__ */ new Map();
422
- for (const t of schema.types) {
423
- typeMap.set(t.name, t);
424
- }
425
- const definitions = buildDefinitions(typeMap);
426
- const queryFields = extractFields(schema, "query", schema.queryType?.name, typeMap);
427
- const mutationFields = extractFields(schema, "mutation", schema.mutationType?.name, typeMap);
428
- return {
429
- result: ExtractionResult.make({
430
- schemaName: Option2.none(),
431
- fields: [...queryFields, ...mutationFields]
432
- }),
433
- definitions
434
- };
435
- },
436
- catch: () => new GraphqlExtractionError({
437
- message: "Failed to extract GraphQL schema"
438
- })
439
- });
440
-
441
- // src/sdk/invoke.ts
442
- import { Effect as Effect3, Option as Option3 } from "effect";
443
- import { HttpClient as HttpClient2, HttpClientRequest as HttpClientRequest2 } from "effect/unstable/http";
444
- import { resolveSecretBackedMap } from "@executor-js/sdk/core";
445
- var resolveHeaders = (headers, secrets) => {
446
- const entries = Object.entries(headers);
447
- const secretCount = entries.reduce(
448
- (acc, [, value]) => typeof value === "string" ? acc : acc + 1,
449
- 0
450
- );
451
- return resolveSecretBackedMap({
452
- values: headers,
453
- getSecret: (secretId) => secrets.get(secretId).pipe(Effect3.catch(() => Effect3.succeed(null))),
454
- missing: "drop",
455
- onMissing: (name) => new GraphqlInvocationError({
456
- message: `Missing secret for header "${name}"`,
457
- statusCode: Option3.none()
458
- })
459
- }).pipe(
460
- Effect3.catch(() => Effect3.succeed(void 0)),
461
- Effect3.map((resolved) => resolved ?? {}),
462
- Effect3.withSpan("plugin.graphql.secret.resolve", {
463
- attributes: {
464
- "plugin.graphql.headers.total": entries.length,
465
- "plugin.graphql.headers.secret_count": secretCount
466
- }
467
- })
468
- );
469
- };
470
- var endpointWithQueryParams = (endpoint, queryParams) => {
471
- if (Object.keys(queryParams).length === 0) return endpoint;
472
- const url = new URL(endpoint);
473
- for (const [name, value] of Object.entries(queryParams)) {
474
- url.searchParams.set(name, value);
475
- }
476
- return url.toString();
477
- };
478
- var endpointForTelemetry = (endpoint) => {
479
- if (!URL.canParse(endpoint)) return endpoint;
480
- const url = new URL(endpoint);
481
- url.search = "";
482
- url.hash = "";
483
- return url.toString();
484
- };
485
- var isJsonContentType = (ct) => {
486
- if (!ct) return false;
487
- const normalized = ct.split(";")[0]?.trim().toLowerCase() ?? "";
488
- return normalized === "application/json" || normalized.includes("+json") || normalized.includes("json");
489
- };
490
- var invoke = Effect3.fn("GraphQL.invoke")(function* (operation, args, endpoint, resolvedHeaders, resolvedQueryParams = {}) {
491
- const client = yield* HttpClient2.HttpClient;
492
- const requestEndpoint = endpointWithQueryParams(endpoint, resolvedQueryParams);
493
- const telemetryEndpoint = endpointForTelemetry(endpoint);
494
- yield* Effect3.annotateCurrentSpan({
495
- "http.method": "POST",
496
- "http.url": telemetryEndpoint,
497
- "plugin.graphql.endpoint": telemetryEndpoint,
498
- "plugin.graphql.operation_kind": operation.kind,
499
- "plugin.graphql.field_name": operation.fieldName,
500
- "plugin.graphql.headers.resolved_count": Object.keys(resolvedHeaders).length,
501
- "plugin.graphql.query_params.resolved_count": Object.keys(resolvedQueryParams).length
502
- });
503
- const variables = {};
504
- for (const varName of operation.variableNames) {
505
- if (args[varName] !== void 0) {
506
- variables[varName] = args[varName];
507
- }
508
- }
509
- if (typeof args.variables === "object" && args.variables !== null) {
510
- Object.assign(variables, args.variables);
511
- }
512
- let request = HttpClientRequest2.post(requestEndpoint).pipe(
513
- HttpClientRequest2.setHeader("Content-Type", "application/json"),
514
- HttpClientRequest2.bodyJsonUnsafe({
515
- query: operation.operationString,
516
- variables: Object.keys(variables).length > 0 ? variables : void 0
517
- })
518
- );
519
- for (const [name, value] of Object.entries(resolvedHeaders)) {
520
- request = HttpClientRequest2.setHeader(request, name, value);
521
- }
522
- const response = yield* client.execute(request).pipe(
523
- Effect3.mapError(
524
- (err) => new GraphqlInvocationError({
525
- message: "GraphQL request failed",
526
- statusCode: Option3.none(),
527
- cause: err
528
- })
529
- )
530
- );
531
- const status = response.status;
532
- const contentType = response.headers["content-type"] ?? null;
533
- const body = isJsonContentType(contentType) ? yield* response.json.pipe(Effect3.catch(() => response.text)) : yield* response.text;
534
- const gqlBody = body;
535
- const hasErrors = Array.isArray(gqlBody?.errors) && gqlBody.errors.length > 0;
536
- yield* Effect3.annotateCurrentSpan({
537
- "http.status_code": status,
538
- "plugin.graphql.has_errors": hasErrors,
539
- "plugin.graphql.error_count": hasErrors ? gqlBody.errors.length : 0
540
- });
541
- return InvocationResult.make({
542
- status,
543
- data: gqlBody?.data ?? null,
544
- errors: hasErrors ? gqlBody.errors : null
545
- });
546
- });
547
- var invokeWithLayer = (operation, args, endpoint, resolvedHeaders, resolvedQueryParams, httpClientLayer) => invoke(operation, args, endpoint, resolvedHeaders, resolvedQueryParams).pipe(
548
- Effect3.provide(httpClientLayer),
549
- Effect3.withSpan("plugin.graphql.invoke", {
550
- attributes: {
551
- "plugin.graphql.endpoint": endpointForTelemetry(endpoint),
552
- "plugin.graphql.operation_kind": operation.kind,
553
- "plugin.graphql.field_name": operation.fieldName
554
- }
555
- })
556
- );
557
-
558
- // src/sdk/store.ts
559
- import { Effect as Effect4, Option as Option4, Predicate, Schema as Schema2 } from "effect";
560
- import {
561
- ConfiguredCredentialBinding
562
- } from "@executor-js/sdk/core";
563
- var graphqlSchema = {};
564
- var SOURCE_COLLECTION = "source";
565
- var OPERATION_COLLECTION = "operation";
566
- var OperationBindingFromJsonString = Schema2.fromJsonString(OperationBinding);
567
- var decodeOperationBindingFromJsonString = Schema2.decodeUnknownSync(
568
- OperationBindingFromJsonString
569
- );
570
- var decodeOperationBinding = Schema2.decodeUnknownSync(OperationBinding);
571
- var encodeBinding = Schema2.encodeSync(OperationBinding);
572
- var decodeBinding = (value) => {
573
- if (typeof value === "string") return decodeOperationBindingFromJsonString(value);
574
- return decodeOperationBinding(value);
575
- };
576
- var toJsonRecord = (value) => value;
577
- var OptionalNullableString = Schema2.optional(Schema2.NullOr(Schema2.String));
578
- var ConfiguredCredentialBindingStorage = Schema2.Struct({
579
- kind: Schema2.Literal("binding"),
580
- slot: Schema2.String,
581
- prefix: OptionalNullableString
582
- });
583
- var ConfiguredCredentialValueStorage = Schema2.Union([
584
- Schema2.String,
585
- ConfiguredCredentialBindingStorage
586
- ]);
587
- var CredentialMapStorage = Schema2.Record(Schema2.String, ConfiguredCredentialValueStorage);
588
- var SourceStorage = Schema2.Struct({
589
- namespace: Schema2.String,
590
- scope: Schema2.String,
591
- name: Schema2.String,
592
- endpoint: Schema2.String,
593
- headers: Schema2.optional(CredentialMapStorage),
594
- queryParams: Schema2.optional(CredentialMapStorage),
595
- auth: GraphqlSourceAuth
596
- });
597
- var OperationStorage = Schema2.Struct({
598
- toolId: Schema2.String,
599
- sourceId: Schema2.String,
600
- binding: Schema2.Unknown
601
- });
602
- var decodeSourceStorage = Schema2.decodeUnknownOption(SourceStorage);
603
- var decodeOperationStorage = Schema2.decodeUnknownOption(OperationStorage);
604
- var normalizeCredentialMap = (values) => {
605
- if (!values) return {};
606
- const normalized = {};
607
- for (const [name, value] of Object.entries(values)) {
608
- if (typeof value === "string") {
609
- normalized[name] = value;
610
- continue;
611
- }
612
- normalized[name] = value.prefix != null ? ConfiguredCredentialBinding.make({
613
- kind: "binding",
614
- slot: value.slot,
615
- prefix: value.prefix
616
- }) : ConfiguredCredentialBinding.make({
617
- kind: "binding",
618
- slot: value.slot
619
- });
620
- }
621
- return normalized;
622
- };
623
- var sourceData = (source) => ({
624
- namespace: source.namespace,
625
- scope: source.scope,
626
- name: source.name,
627
- endpoint: source.endpoint,
628
- headers: source.headers,
629
- queryParams: source.queryParams,
630
- auth: source.auth
631
- });
632
- var operationData = (operation) => ({
633
- toolId: operation.toolId,
634
- sourceId: operation.sourceId,
635
- binding: toJsonRecord(encodeBinding(operation.binding))
636
- });
637
- var rowToSource = (row) => {
638
- const decoded = decodeSourceStorage(row.data);
639
- if (Option4.isNone(decoded)) return null;
640
- const source = decoded.value;
641
- return {
642
- namespace: source.namespace,
643
- scope: source.scope,
644
- name: source.name,
645
- endpoint: source.endpoint,
646
- headers: normalizeCredentialMap(source.headers),
647
- queryParams: normalizeCredentialMap(source.queryParams),
648
- auth: source.auth
649
- };
650
- };
651
- var rowToOperation = (row) => {
652
- const decoded = decodeOperationStorage(row.data);
653
- if (Option4.isNone(decoded)) return null;
654
- const operation = decoded.value;
655
- return {
656
- toolId: operation.toolId,
657
- sourceId: operation.sourceId,
658
- binding: decodeBinding(operation.binding)
659
- };
660
- };
661
- var makeDefaultGraphqlStore = ({
662
- pluginStorage
663
- }) => {
664
- const listOperationRowsForSourceScope = (sourceId, scope) => pluginStorage.list({
665
- collection: OPERATION_COLLECTION,
666
- keyPrefix: `${sourceId}.`
667
- }).pipe(
668
- Effect4.map(
669
- (rows) => rows.filter((row) => {
670
- if (String(row.scopeId) !== scope) return false;
671
- return rowToOperation(row)?.sourceId === sourceId;
672
- })
673
- )
674
- );
675
- const removeOperationsForSourceScope = (sourceId, scope) => Effect4.gen(function* () {
676
- const rows = yield* listOperationRowsForSourceScope(sourceId, scope);
677
- for (const row of rows) {
678
- yield* pluginStorage.remove({
679
- scope,
680
- collection: OPERATION_COLLECTION,
681
- key: row.key
682
- });
683
- }
684
- });
685
- const deleteSource = (namespace, scope) => Effect4.gen(function* () {
686
- yield* removeOperationsForSourceScope(namespace, scope);
687
- yield* pluginStorage.remove({
688
- scope,
689
- collection: SOURCE_COLLECTION,
690
- key: namespace
691
- });
692
- });
693
- return {
694
- upsertSource: (input, operations) => Effect4.gen(function* () {
695
- yield* deleteSource(input.namespace, input.scope);
696
- yield* pluginStorage.put({
697
- scope: input.scope,
698
- collection: SOURCE_COLLECTION,
699
- key: input.namespace,
700
- data: sourceData(input)
701
- });
702
- for (const operation of operations) {
703
- yield* pluginStorage.put({
704
- scope: input.scope,
705
- collection: OPERATION_COLLECTION,
706
- key: operation.toolId,
707
- data: operationData(operation)
708
- });
709
- }
710
- }),
711
- updateSourceMeta: (namespace, scope, patch) => Effect4.gen(function* () {
712
- const existing = yield* pluginStorage.getAtScope({
713
- scope,
714
- collection: SOURCE_COLLECTION,
715
- key: namespace
716
- });
717
- if (!existing) return;
718
- const source = rowToSource(existing);
719
- if (!source) return;
720
- yield* pluginStorage.put({
721
- scope,
722
- collection: SOURCE_COLLECTION,
723
- key: namespace,
724
- data: sourceData({
725
- ...source,
726
- name: patch.name ?? source.name,
727
- endpoint: patch.endpoint ?? source.endpoint,
728
- headers: patch.headers ?? source.headers,
729
- queryParams: patch.queryParams ?? source.queryParams,
730
- auth: patch.auth ?? source.auth
731
- })
732
- });
733
- }),
734
- getSource: (namespace, scope) => pluginStorage.getAtScope({ scope, collection: SOURCE_COLLECTION, key: namespace }).pipe(Effect4.map((row) => row ? rowToSource(row) : null)),
735
- listSources: () => pluginStorage.list({ collection: SOURCE_COLLECTION }).pipe(Effect4.map((rows) => rows.map(rowToSource).filter(Predicate.isNotNull))),
736
- getOperationByToolId: (toolId, scope) => pluginStorage.getAtScope({ scope, collection: OPERATION_COLLECTION, key: toolId }).pipe(Effect4.map((row) => row ? rowToOperation(row) : null)),
737
- listOperationsBySource: (sourceId, scope) => listOperationRowsForSourceScope(sourceId, scope).pipe(
738
- Effect4.map((rows) => rows.map(rowToOperation).filter(Predicate.isNotNull))
739
- ),
740
- removeSource: (namespace, scope) => deleteSource(namespace, scope)
741
- };
742
- };
743
-
744
- // src/sdk/plugin.ts
745
- import { Effect as Effect5, Match as Match2, Option as Option5, Schema as Schema3 } from "effect";
746
- import {
747
- definePlugin,
748
- tool,
749
- defaultSourceInstallScopeId,
750
- ScopeId,
751
- SourceDetectionResult,
752
- StorageError,
753
- ToolResult,
754
- authToolFailure
755
- } from "@executor-js/sdk/core";
756
- import {
757
- compileHttpNamedCredentialMap,
758
- OAuth2SourceConfig,
759
- httpCredentialInputToBindingValue
760
- } from "@executor-js/sdk/http-source";
761
- import {
762
- headersToConfigValues
763
- } from "@executor-js/config";
764
- var GraphqlErrorBody = Schema3.Struct({ message: Schema3.String });
765
- var GraphqlErrorsBody = Schema3.Array(Schema3.Unknown);
766
- var decodeGraphqlErrorBody = Schema3.decodeUnknownOption(GraphqlErrorBody);
767
- var decodeGraphqlErrorsBody = Schema3.decodeUnknownOption(GraphqlErrorsBody);
768
- var decodeGraphqlErrors = (errors) => Option5.getOrUndefined(decodeGraphqlErrorsBody(errors));
769
- var extractGraphqlErrorMessage = (errors) => errors.map((error) => Option5.getOrUndefined(decodeGraphqlErrorBody(error))?.message).find((message) => message !== void 0 && message.length > 0);
770
- var GraphqlInitialCredentialsInputSchema = Schema3.Struct({
771
- scope: Schema3.String,
772
- headers: Schema3.optional(Schema3.Record(Schema3.String, GraphqlCredentialInput)),
773
- queryParams: Schema3.optional(Schema3.Record(Schema3.String, GraphqlCredentialInput)),
774
- auth: Schema3.optional(GraphqlSourceAuthInput)
775
- });
776
- var StaticAddSourceInputSchema = Schema3.Struct({
777
- endpoint: Schema3.String,
778
- name: Schema3.String,
779
- introspectionJson: Schema3.optional(Schema3.String),
780
- namespace: Schema3.String,
781
- headers: Schema3.optional(Schema3.Record(Schema3.String, GraphqlConfiguredValueInput)),
782
- queryParams: Schema3.optional(Schema3.Record(Schema3.String, GraphqlConfiguredValueInput)),
783
- oauth2: Schema3.optional(OAuth2SourceConfig),
784
- credentials: Schema3.optional(GraphqlInitialCredentialsInputSchema)
785
- });
786
- var SourceConfigureInputSchema = Schema3.Struct({
787
- name: Schema3.optional(Schema3.String),
788
- endpoint: Schema3.optional(Schema3.String),
789
- headers: Schema3.optional(Schema3.Record(Schema3.String, GraphqlCredentialInput)),
790
- queryParams: Schema3.optional(Schema3.Record(Schema3.String, GraphqlCredentialInput)),
791
- auth: Schema3.optional(GraphqlSourceAuthInput)
792
- });
793
- var StaticConfigureSourceInputSchema = Schema3.Struct({
794
- source: Schema3.Struct({
795
- id: Schema3.String,
796
- scope: Schema3.String
797
- }),
798
- scope: Schema3.String,
799
- ...SourceConfigureInputSchema.fields
800
- });
801
- var StaticConfigureSourceOutputSchema = Schema3.Struct({
802
- configured: Schema3.Boolean
803
- });
804
- var StaticGetSourceInputSchema = Schema3.Struct({
805
- namespace: Schema3.String,
806
- scope: Schema3.String
807
- });
808
- var StaticGetSourceOutputSchema = Schema3.Struct({
809
- source: Schema3.NullOr(Schema3.Unknown)
810
- });
811
- var StaticAddSourceInputStandardSchema = Schema3.toStandardSchemaV1(
812
- Schema3.toStandardJSONSchemaV1(StaticAddSourceInputSchema)
813
- );
814
- var StaticAddSourceOutputStandardSchema = Schema3.toStandardSchemaV1(
815
- Schema3.toStandardJSONSchemaV1(
816
- Schema3.Struct({
817
- namespace: Schema3.String,
818
- source: Schema3.Struct({
819
- id: Schema3.String,
820
- scope: Schema3.String
821
- }),
822
- toolCount: Schema3.Number
823
- })
824
- )
825
- );
826
- var StaticGetSourceInputStandardSchema = Schema3.toStandardSchemaV1(
827
- Schema3.toStandardJSONSchemaV1(StaticGetSourceInputSchema)
828
- );
829
- var StaticGetSourceOutputStandardSchema = Schema3.toStandardSchemaV1(
830
- Schema3.toStandardJSONSchemaV1(StaticGetSourceOutputSchema)
831
- );
832
- var StaticConfigureSourceInputStandardSchema = Schema3.toStandardSchemaV1(
833
- Schema3.toStandardJSONSchemaV1(StaticConfigureSourceInputSchema)
834
- );
835
- var StaticConfigureSourceOutputStandardSchema = Schema3.toStandardSchemaV1(
836
- Schema3.toStandardJSONSchemaV1(StaticConfigureSourceOutputSchema)
837
- );
838
- var graphqlToolFailure = (code, message, details) => ToolResult.fail({
839
- code,
840
- message,
841
- ...details === void 0 ? {} : { details }
842
- });
843
- var graphqlAuthToolFailure = (failure) => authToolFailure({
844
- code: failure.code,
845
- message: failure.message,
846
- source: { id: failure.sourceId, scope: failure.sourceScope },
847
- credential: {
848
- kind: failure.credentialKind,
849
- ...failure.credentialLabel ? { label: failure.credentialLabel } : {},
850
- ...failure.slotKey ? { slotKey: failure.slotKey } : {},
851
- ...failure.secretId ? { secretId: failure.secretId } : {},
852
- ...failure.connectionId ? { connectionId: failure.connectionId } : {}
853
- },
854
- ...failure.status !== void 0 ? { status: failure.status } : {},
855
- ...failure.details !== void 0 ? {
856
- upstream: {
857
- ...failure.status !== void 0 ? { status: failure.status } : {},
858
- details: failure.details
859
- }
860
- } : {},
861
- recovery: { configureSourceTool: "executor.graphql.configureSource" }
862
- });
863
- var resolveStaticScopeInput = (ctx, value) => String(
864
- ctx.scopes.find((scope) => scope.name === value || String(scope.id) === value)?.id ?? value
865
- );
866
- var urlMatchesToken = (url, token) => {
867
- const re = new RegExp(`(?:^|[^a-z0-9])${token}(?:$|[^a-z0-9])`, "i");
868
- return re.test(url.hostname) || re.test(url.pathname);
869
- };
870
- var namespaceFromEndpoint = (endpoint) => {
871
- try {
872
- const url = new URL(endpoint);
873
- return url.hostname.replace(/[^a-z0-9]+/gi, "_").toLowerCase();
874
- } catch {
875
- return "graphql";
876
- }
877
- };
878
- var formatTypeRef2 = (ref) => Match2.value(ref.kind).pipe(
879
- Match2.when("NON_NULL", () => ref.ofType ? `${formatTypeRef2(ref.ofType)}!` : "Unknown!"),
880
- Match2.when("LIST", () => ref.ofType ? `[${formatTypeRef2(ref.ofType)}]` : "[Unknown]"),
881
- Match2.option,
882
- Option5.getOrElse(() => ref.name ?? "Unknown")
883
- );
884
- var unwrapTypeName2 = (ref) => {
885
- if (ref.name) return ref.name;
886
- if (ref.ofType) return unwrapTypeName2(ref.ofType);
887
- return "Unknown";
888
- };
889
- var buildSelectionSet = (ref, types, depth, seen) => {
890
- if (depth > 2) return "";
891
- const leafName = unwrapTypeName2(ref);
892
- if (seen.has(leafName)) return "";
893
- const objectType = types.get(leafName);
894
- if (!objectType?.fields) return "";
895
- const kind = objectType.kind;
896
- if (kind === "SCALAR" || kind === "ENUM") return "";
897
- seen.add(leafName);
898
- const subFields = objectType.fields.filter((f) => !f.name.startsWith("__")).slice(0, 12).map((f) => {
899
- const sub = buildSelectionSet(f.type, types, depth + 1, seen);
900
- return sub ? `${f.name} ${sub}` : f.name;
901
- });
902
- seen.delete(leafName);
903
- return subFields.length > 0 ? `{ ${subFields.join(" ")} }` : "";
904
- };
905
- var buildOperationStringForField = (kind, field, types) => {
906
- const opType = kind === "query" ? "query" : "mutation";
907
- const varDefs = field.args.map((arg) => {
908
- const typeName = formatTypeRef2(arg.type);
909
- return `$${arg.name}: ${typeName}`;
910
- });
911
- const argPasses = field.args.map((arg) => `${arg.name}: $${arg.name}`);
912
- const selectionSet = buildSelectionSet(field.type, types, 0, /* @__PURE__ */ new Set());
913
- const varDefsStr = varDefs.length > 0 ? `(${varDefs.join(", ")})` : "";
914
- const argPassStr = argPasses.length > 0 ? `(${argPasses.join(", ")})` : "";
915
- return `${opType}${varDefsStr} { ${field.name}${argPassStr}${selectionSet ? ` ${selectionSet}` : ""} }`;
916
- };
917
- var prepareOperations = (fields, introspection) => {
918
- const typeMap = /* @__PURE__ */ new Map();
919
- for (const t of introspection.__schema.types) {
920
- typeMap.set(t.name, t);
921
- }
922
- const fieldMap = /* @__PURE__ */ new Map();
923
- const schema = introspection.__schema;
924
- for (const rootKind of ["query", "mutation"]) {
925
- const typeName = rootKind === "query" ? schema.queryType?.name : schema.mutationType?.name;
926
- if (!typeName) continue;
927
- const rootType = typeMap.get(typeName);
928
- if (!rootType?.fields) continue;
929
- for (const f of rootType.fields) {
930
- if (!f.name.startsWith("__")) {
931
- fieldMap.set(`${rootKind}.${f.name}`, { kind: rootKind, field: f });
932
- }
933
- }
934
- }
935
- return fields.map((extracted) => {
936
- const prefix = extracted.kind === "mutation" ? "mutation" : "query";
937
- const toolPath = `${prefix}.${extracted.fieldName}`;
938
- const description = Option5.getOrElse(
939
- extracted.description,
940
- () => `GraphQL ${extracted.kind}: ${extracted.fieldName} -> ${extracted.returnTypeName}`
941
- );
942
- const key = `${extracted.kind}.${extracted.fieldName}`;
943
- const entry = fieldMap.get(key);
944
- const operationString = entry ? buildOperationStringForField(entry.kind, entry.field, typeMap) : `${extracted.kind} { ${extracted.fieldName} }`;
945
- const binding = OperationBinding.make({
946
- kind: extracted.kind,
947
- fieldName: extracted.fieldName,
948
- operationString,
949
- variableNames: extracted.arguments.map((a) => a.name)
950
- });
951
- return {
952
- toolPath,
953
- description,
954
- inputSchema: Option5.getOrUndefined(extracted.inputSchema),
955
- binding
956
- };
957
- });
958
- };
959
- var annotationsFor = (binding) => {
960
- if (binding.kind === "mutation") {
961
- return {
962
- requiresApproval: true,
963
- approvalDescription: `mutation ${binding.fieldName}`
964
- };
965
- }
966
- return {};
967
- };
968
- var toGraphqlConfigEntry = (namespace, config) => {
969
- const headers = {};
970
- for (const [name, value] of Object.entries(config.headers ?? {})) {
971
- if (typeof value === "string" || !("kind" in value)) {
972
- headers[name] = value;
973
- }
974
- }
975
- return {
976
- kind: "graphql",
977
- endpoint: config.endpoint,
978
- introspectionJson: config.introspectionJson,
979
- namespace,
980
- headers: headersToConfigValues(Object.keys(headers).length > 0 ? headers : void 0)
981
- };
982
- };
983
- var GRAPHQL_PLUGIN_ID = "graphql";
984
- var scopeRanks = (ctx) => new Map(ctx.scopes.map((scope, index) => [String(scope.id), index]));
985
- var scopeRank = (ranks, scopeId) => ranks.get(scopeId) ?? Infinity;
986
- var resolveGraphqlSourceBinding = (ctx, sourceId, sourceScope, slot) => Effect5.gen(function* () {
987
- const ranks = scopeRanks(ctx);
988
- const sourceSourceRank = scopeRank(ranks, sourceScope);
989
- if (sourceSourceRank === Infinity) return null;
990
- const bindings = yield* ctx.credentialBindings.listForSource({
991
- pluginId: GRAPHQL_PLUGIN_ID,
992
- sourceId,
993
- sourceScope: ScopeId.make(sourceScope)
994
- });
995
- const binding = bindings.filter(
996
- (candidate) => candidate.slotKey === slot && scopeRank(ranks, candidate.scopeId) <= sourceSourceRank
997
- ).sort((a, b) => scopeRank(ranks, a.scopeId) - scopeRank(ranks, b.scopeId))[0];
998
- return binding ?? null;
999
- });
1000
- var validateGraphqlBindingTarget = (ctx, input) => Effect5.gen(function* () {
1001
- const ranks = scopeRanks(ctx);
1002
- const sourceSourceRank = scopeRank(ranks, input.sourceScope);
1003
- const targetRank = scopeRank(ranks, input.targetScope);
1004
- const scopeList = `[${ctx.scopes.map((s) => s.id).join(", ")}]`;
1005
- if (sourceSourceRank === Infinity) {
1006
- return yield* new StorageError({
1007
- message: `GraphQL source binding references source scope "${input.sourceScope}" which is not in the executor's scope stack ${scopeList}.`,
1008
- cause: void 0
1009
- });
1010
- }
1011
- if (targetRank === Infinity) {
1012
- return yield* new StorageError({
1013
- message: `GraphQL source binding targets scope "${input.targetScope}" which is not in the executor's scope stack ${scopeList}.`,
1014
- cause: void 0
1015
- });
1016
- }
1017
- if (targetRank > sourceSourceRank) {
1018
- return yield* new StorageError({
1019
- message: `GraphQL source bindings for "${input.sourceId}" cannot be written at outer scope "${input.targetScope}" because the base source lives at "${input.sourceScope}"`,
1020
- cause: void 0
1021
- });
1022
- }
1023
- });
1024
- var canonicalizeCredentialMap = compileHttpNamedCredentialMap;
1025
- var canonicalizeConfiguredValueMap = (values, slotForName) => {
1026
- const next = {};
1027
- for (const [name, value] of Object.entries(values ?? {})) {
1028
- if (typeof value === "string") {
1029
- next[name] = value;
1030
- continue;
1031
- }
1032
- next[name] = {
1033
- kind: "binding",
1034
- slot: slotForName(name),
1035
- prefix: value.prefix
1036
- };
1037
- }
1038
- return next;
1039
- };
1040
- var resolveConfiguredValueMap = (values) => {
1041
- if (!values) return void 0;
1042
- const resolved = {};
1043
- for (const [name, value] of Object.entries(values)) {
1044
- if (typeof value === "string") resolved[name] = value;
1045
- }
1046
- return Object.keys(resolved).length > 0 ? resolved : void 0;
1047
- };
1048
- var authFromOAuth2Source = (oauth2) => oauth2 ? { kind: "oauth2", connectionSlot: oauth2.connectionSlot } : { kind: "none" };
1049
- var canonicalizeAuth = (auth) => {
1050
- if (!auth || "kind" in auth || !auth.oauth2) return { auth: { kind: "none" }, bindings: [] };
1051
- const connection = auth.oauth2.connection;
1052
- return {
1053
- auth: { kind: "oauth2", connectionSlot: GRAPHQL_OAUTH_CONNECTION_SLOT },
1054
- bindings: connection ? [
1055
- {
1056
- slot: GRAPHQL_OAUTH_CONNECTION_SLOT,
1057
- value: httpCredentialInputToBindingValue(connection)
1058
- }
1059
- ] : []
1060
- };
1061
- };
1062
- var resolveInitialCredentialValueMap = (ctx, values, bindings, targetScope) => Effect5.gen(function* () {
1063
- const bySlot = new Map(bindings.map((binding) => [binding.slot, binding.value]));
1064
- const resolved = {};
1065
- for (const [name, value] of Object.entries(values)) {
1066
- if (typeof value === "string") {
1067
- resolved[name] = value;
1068
- continue;
1069
- }
1070
- const binding = bySlot.get(value.slot);
1071
- if (binding?.kind === "secret") {
1072
- const secret = yield* ctx.secrets.getAtScope(binding.secretId, binding.secretScopeId ?? ScopeId.make(targetScope)).pipe(
1073
- Effect5.catchTag(
1074
- "SecretOwnedByConnectionError",
1075
- () => Effect5.fail(
1076
- new GraphqlIntrospectionError({
1077
- message: `Secret not found for ${name}`
1078
- })
1079
- )
1080
- )
1081
- );
1082
- if (secret === null) {
1083
- return yield* new GraphqlIntrospectionError({
1084
- message: `Missing secret "${binding.secretId}" for ${name}`
1085
- });
1086
- }
1087
- resolved[name] = value.prefix ? `${value.prefix}${secret}` : secret;
1088
- continue;
1089
- }
1090
- if (binding?.kind === "text") {
1091
- resolved[name] = value.prefix ? `${value.prefix}${binding.text}` : binding.text;
1092
- }
1093
- }
1094
- return Object.keys(resolved).length > 0 ? resolved : void 0;
1095
- });
1096
- var resolveInitialOAuthHeaders = (ctx, bindings, targetScope) => Effect5.gen(function* () {
1097
- const connection = bindings.find(
1098
- (binding) => binding.slot === GRAPHQL_OAUTH_CONNECTION_SLOT && binding.value.kind === "connection"
1099
- );
1100
- if (!connection || connection.value.kind !== "connection") return void 0;
1101
- const connectionId = connection.value.connectionId;
1102
- const accessToken = yield* ctx.connections.accessTokenAtScope(connectionId, ScopeId.make(targetScope)).pipe(
1103
- Effect5.mapError(
1104
- ({ message }) => new GraphqlIntrospectionError({
1105
- message: `Failed to resolve OAuth connection "${connectionId}": ${message}`
1106
- })
1107
- )
1108
- );
1109
- return { Authorization: `Bearer ${accessToken}` };
1110
- });
1111
- var resolveGraphqlBindingValueMap = (ctx, values, params) => Effect5.gen(function* () {
1112
- if (!values) return void 0;
1113
- const resolved = {};
1114
- for (const [name, value] of Object.entries(values)) {
1115
- if (typeof value === "string") {
1116
- resolved[name] = value;
1117
- continue;
1118
- }
1119
- const binding = yield* resolveGraphqlSourceBinding(
1120
- ctx,
1121
- params.sourceId,
1122
- params.sourceScope,
1123
- value.slot
1124
- );
1125
- if (binding?.value.kind === "secret") {
1126
- const secretBinding = binding.value;
1127
- const secret = yield* ctx.secrets.getAtScope(secretBinding.secretId, binding.scopeId).pipe(
1128
- Effect5.catchTag(
1129
- "SecretOwnedByConnectionError",
1130
- () => Effect5.fail(
1131
- new GraphqlAuthRequiredError({
1132
- code: "credential_secret_missing",
1133
- sourceId: params.sourceId,
1134
- sourceScope: params.sourceScope,
1135
- credentialKind: "secret",
1136
- credentialLabel: name,
1137
- slotKey: value.slot,
1138
- secretId: String(secretBinding.secretId),
1139
- message: `Secret not found for ${params.missingLabel} "${name}"`
1140
- })
1141
- )
1142
- )
1143
- );
1144
- if (secret === null) {
1145
- return yield* new GraphqlAuthRequiredError({
1146
- code: "credential_secret_missing",
1147
- sourceId: params.sourceId,
1148
- sourceScope: params.sourceScope,
1149
- credentialKind: "secret",
1150
- credentialLabel: name,
1151
- slotKey: value.slot,
1152
- secretId: String(secretBinding.secretId),
1153
- message: `Missing secret "${secretBinding.secretId}" for ${params.missingLabel} "${name}"`
1154
- });
1155
- }
1156
- resolved[name] = value.prefix ? `${value.prefix}${secret}` : secret;
1157
- continue;
1158
- }
1159
- if (binding?.value.kind === "text") {
1160
- resolved[name] = value.prefix ? `${value.prefix}${binding.value.text}` : binding.value.text;
1161
- continue;
1162
- }
1163
- return yield* new GraphqlAuthRequiredError({
1164
- code: "credential_binding_missing",
1165
- sourceId: params.sourceId,
1166
- sourceScope: params.sourceScope,
1167
- credentialKind: "secret",
1168
- credentialLabel: name,
1169
- slotKey: value.slot,
1170
- message: `Missing binding for ${params.missingLabel} "${name}"`
1171
- });
1172
- }
1173
- return Object.keys(resolved).length > 0 ? resolved : void 0;
1174
- });
1175
- var resolveGraphqlStoredOAuthHeader = (ctx, sourceId, sourceScope, auth) => Effect5.gen(function* () {
1176
- if (!auth || auth.kind === "none") return void 0;
1177
- const binding = yield* resolveGraphqlSourceBinding(
1178
- ctx,
1179
- sourceId,
1180
- sourceScope,
1181
- auth.connectionSlot
1182
- );
1183
- if (binding?.value.kind !== "connection") {
1184
- return yield* new GraphqlAuthRequiredError({
1185
- code: "oauth_connection_missing",
1186
- sourceId,
1187
- sourceScope,
1188
- credentialKind: "connection",
1189
- credentialLabel: "OAuth sign-in",
1190
- slotKey: auth.connectionSlot,
1191
- message: `Missing OAuth connection binding for GraphQL source "${sourceId}"`
1192
- });
1193
- }
1194
- const connectionId = binding.value.connectionId;
1195
- const accessToken = yield* ctx.connections.accessTokenAtScope(connectionId, binding.scopeId).pipe(
1196
- Effect5.catchTags({
1197
- ConnectionReauthRequiredError: ({ message, connectionId: connectionId2 }) => Effect5.fail(
1198
- new GraphqlAuthRequiredError({
1199
- code: "oauth_reauth_required",
1200
- sourceId,
1201
- sourceScope,
1202
- credentialKind: "oauth",
1203
- credentialLabel: "OAuth sign-in",
1204
- slotKey: auth.connectionSlot,
1205
- connectionId: String(connectionId2),
1206
- message: `OAuth connection "${connectionId2}" needs re-authentication: ${message}`
1207
- })
1208
- ),
1209
- ConnectionNotFoundError: ({ connectionId: connectionId2 }) => Effect5.fail(
1210
- new GraphqlAuthRequiredError({
1211
- code: "oauth_connection_missing",
1212
- sourceId,
1213
- sourceScope,
1214
- credentialKind: "connection",
1215
- credentialLabel: "OAuth sign-in",
1216
- slotKey: auth.connectionSlot,
1217
- connectionId: String(connectionId2),
1218
- message: `OAuth connection "${connectionId2}" was not found for GraphQL source "${sourceId}"`
1219
- })
1220
- ),
1221
- ConnectionProviderNotRegisteredError: ({ provider }) => Effect5.fail(
1222
- new GraphqlAuthRequiredError({
1223
- code: "oauth_connection_failed",
1224
- sourceId,
1225
- sourceScope,
1226
- credentialKind: "oauth",
1227
- credentialLabel: "OAuth sign-in",
1228
- slotKey: auth.connectionSlot,
1229
- connectionId: String(connectionId),
1230
- message: `OAuth provider "${provider}" is not registered`
1231
- })
1232
- ),
1233
- ConnectionRefreshNotSupportedError: ({ provider, connectionId: connectionId2 }) => Effect5.fail(
1234
- new GraphqlAuthRequiredError({
1235
- code: "oauth_connection_failed",
1236
- sourceId,
1237
- sourceScope,
1238
- credentialKind: "oauth",
1239
- credentialLabel: "OAuth sign-in",
1240
- slotKey: auth.connectionSlot,
1241
- connectionId: String(connectionId2),
1242
- message: `OAuth provider "${provider}" cannot refresh connection "${connectionId2}"`
1243
- })
1244
- ),
1245
- ConnectionRefreshError: ({ message, connectionId: connectionId2 }) => Effect5.fail(
1246
- new GraphqlAuthRequiredError({
1247
- code: "oauth_connection_failed",
1248
- sourceId,
1249
- sourceScope,
1250
- credentialKind: "oauth",
1251
- credentialLabel: "OAuth sign-in",
1252
- slotKey: auth.connectionSlot,
1253
- connectionId: String(connectionId2),
1254
- message: `OAuth connection "${connectionId2}" refresh failed: ${message}`
1255
- })
1256
- )
1257
- })
1258
- );
1259
- return { Authorization: `Bearer ${accessToken}` };
1260
- });
1261
- var makeGraphqlExtension = (ctx, httpClientLayer, configFile) => {
1262
- const addSourceInternal = (config) => ctx.transaction(
1263
- Effect5.gen(function* () {
1264
- const namespace = config.namespace;
1265
- const canonicalHeaders = canonicalizeConfiguredValueMap(config.headers, graphqlHeaderSlot);
1266
- const canonicalQueryParams = canonicalizeConfiguredValueMap(
1267
- config.queryParams,
1268
- graphqlQueryParamSlot
1269
- );
1270
- const initialHeaders = config.credentials?.headers !== void 0 ? canonicalizeCredentialMap(config.credentials.headers, graphqlHeaderSlot) : null;
1271
- const initialQueryParams = config.credentials?.queryParams !== void 0 ? canonicalizeCredentialMap(config.credentials.queryParams, graphqlQueryParamSlot) : null;
1272
- const initialAuth = config.credentials?.auth !== void 0 ? canonicalizeAuth(config.credentials.auth) : null;
1273
- const auth = config.oauth2 ? authFromOAuth2Source(config.oauth2) : initialAuth?.auth ?? { kind: "none" };
1274
- const initialBindings = [
1275
- ...initialHeaders?.bindings ?? [],
1276
- ...initialQueryParams?.bindings ?? [],
1277
- ...initialAuth?.bindings ?? []
1278
- ];
1279
- const initialScope = config.credentials?.scope;
1280
- if (initialScope && initialBindings.length > 0) {
1281
- yield* validateGraphqlBindingTarget(ctx, {
1282
- sourceId: namespace,
1283
- sourceScope: config.scope,
1284
- targetScope: initialScope
1285
- });
1286
- }
1287
- let introspectionResult;
1288
- if (config.introspectionJson) {
1289
- introspectionResult = yield* parseIntrospectionJson(config.introspectionJson);
1290
- } else {
1291
- const resolvedInitialHeaders = initialHeaders && initialScope ? yield* resolveInitialCredentialValueMap(
1292
- ctx,
1293
- canonicalHeaders,
1294
- initialHeaders.bindings,
1295
- initialScope
1296
- ) : void 0;
1297
- const resolvedOAuthHeaders = initialAuth && initialScope ? yield* resolveInitialOAuthHeaders(ctx, initialAuth.bindings, initialScope) : void 0;
1298
- const resolvedHeaders = {
1299
- ...resolveConfiguredValueMap(config.headers) ?? {},
1300
- ...resolvedInitialHeaders ?? {},
1301
- ...resolvedOAuthHeaders ?? {}
1302
- };
1303
- const resolvedInitialQueryParams = initialQueryParams && initialScope ? yield* resolveInitialCredentialValueMap(
1304
- ctx,
1305
- canonicalQueryParams,
1306
- initialQueryParams.bindings,
1307
- initialScope
1308
- ) : void 0;
1309
- const resolvedQueryParams = {
1310
- ...resolveConfiguredValueMap(config.queryParams) ?? {},
1311
- ...resolvedInitialQueryParams ?? {}
1312
- };
1313
- introspectionResult = yield* introspect(
1314
- config.endpoint,
1315
- Object.keys(resolvedHeaders).length > 0 ? resolvedHeaders : void 0,
1316
- Object.keys(resolvedQueryParams).length > 0 ? resolvedQueryParams : void 0
1317
- ).pipe(Effect5.provide(httpClientLayer));
1318
- }
1319
- const { result, definitions } = yield* extract(introspectionResult);
1320
- const prepared = prepareOperations(result.fields, introspectionResult);
1321
- const displayName = config.name?.trim() || namespace;
1322
- const storedSource = {
1323
- namespace,
1324
- scope: config.scope,
1325
- name: displayName,
1326
- endpoint: config.endpoint,
1327
- headers: canonicalHeaders,
1328
- queryParams: canonicalQueryParams,
1329
- auth
1330
- };
1331
- const storedOps = prepared.map((p) => ({
1332
- toolId: `${namespace}.${p.toolPath}`,
1333
- sourceId: namespace,
1334
- binding: p.binding
1335
- }));
1336
- yield* ctx.storage.upsertSource(storedSource, storedOps);
1337
- yield* ctx.core.sources.register({
1338
- id: namespace,
1339
- scope: config.scope,
1340
- kind: "graphql",
1341
- name: displayName,
1342
- url: config.endpoint,
1343
- canRemove: true,
1344
- canRefresh: false,
1345
- canEdit: true,
1346
- tools: prepared.map((p) => ({
1347
- name: p.toolPath,
1348
- description: p.description,
1349
- inputSchema: p.inputSchema
1350
- }))
1351
- });
1352
- if (initialScope && initialBindings.length > 0) {
1353
- yield* ctx.credentialBindings.replaceForSource({
1354
- targetScope: ScopeId.make(initialScope),
1355
- pluginId: GRAPHQL_PLUGIN_ID,
1356
- sourceId: namespace,
1357
- sourceScope: ScopeId.make(config.scope),
1358
- slotPrefixes: [
1359
- ...config.credentials?.headers !== void 0 ? ["header:"] : [],
1360
- ...config.credentials?.queryParams !== void 0 ? ["query_param:"] : [],
1361
- ...config.credentials?.auth !== void 0 ? ["auth:"] : []
1362
- ],
1363
- bindings: initialBindings.map((binding) => ({
1364
- slotKey: binding.slot,
1365
- value: binding.value
1366
- }))
1367
- });
1368
- }
1369
- if (Object.keys(definitions).length > 0) {
1370
- yield* ctx.core.definitions.register({
1371
- sourceId: namespace,
1372
- scope: config.scope,
1373
- definitions
1374
- });
1375
- }
1376
- return { toolCount: prepared.length, namespace };
1377
- })
1378
- );
1379
- const configureSource = (namespace, scope, targetScope, input) => Effect5.gen(function* () {
1380
- const existing = yield* ctx.storage.getSource(namespace, scope);
1381
- if (!existing) return;
1382
- const canonicalHeaders = input.headers !== void 0 ? canonicalizeCredentialMap(input.headers, graphqlHeaderSlot) : null;
1383
- const canonicalQueryParams = input.queryParams !== void 0 ? canonicalizeCredentialMap(input.queryParams, graphqlQueryParamSlot) : null;
1384
- const canonicalAuth = input.auth !== void 0 ? canonicalizeAuth(input.auth) : null;
1385
- const directBindings = [
1386
- ...canonicalHeaders?.bindings ?? [],
1387
- ...canonicalQueryParams?.bindings ?? [],
1388
- ...canonicalAuth?.bindings ?? []
1389
- ];
1390
- if (directBindings.length > 0) {
1391
- yield* validateGraphqlBindingTarget(ctx, {
1392
- sourceId: namespace,
1393
- sourceScope: scope,
1394
- targetScope
1395
- });
1396
- }
1397
- const affectedPrefixes = [
1398
- ...input.headers !== void 0 ? ["header:"] : [],
1399
- ...input.queryParams !== void 0 ? ["query_param:"] : [],
1400
- ...input.auth !== void 0 ? ["auth:"] : []
1401
- ];
1402
- yield* ctx.transaction(
1403
- Effect5.gen(function* () {
1404
- yield* ctx.storage.updateSourceMeta(namespace, scope, {
1405
- name: input.name?.trim() || void 0,
1406
- endpoint: input.endpoint,
1407
- headers: canonicalHeaders?.values,
1408
- queryParams: canonicalQueryParams?.values,
1409
- auth: canonicalAuth?.auth
1410
- });
1411
- if (affectedPrefixes.length > 0 || directBindings.length > 0) {
1412
- yield* ctx.credentialBindings.replaceForSource({
1413
- targetScope: ScopeId.make(targetScope),
1414
- pluginId: GRAPHQL_PLUGIN_ID,
1415
- sourceId: namespace,
1416
- sourceScope: ScopeId.make(scope),
1417
- slotPrefixes: affectedPrefixes,
1418
- bindings: directBindings.map((binding) => ({
1419
- slotKey: binding.slot,
1420
- value: binding.value
1421
- }))
1422
- });
1423
- }
1424
- })
1425
- );
1426
- });
1427
- return {
1428
- addSource: (config) => addSourceInternal(config).pipe(
1429
- Effect5.tap(
1430
- (result) => configFile ? configFile.upsertSource(toGraphqlConfigEntry(result.namespace, config)) : Effect5.void
1431
- )
1432
- ),
1433
- removeSource: (namespace, scope) => Effect5.gen(function* () {
1434
- yield* ctx.transaction(
1435
- Effect5.gen(function* () {
1436
- yield* ctx.credentialBindings.removeForSource({
1437
- pluginId: GRAPHQL_PLUGIN_ID,
1438
- sourceId: namespace,
1439
- sourceScope: ScopeId.make(scope)
1440
- });
1441
- yield* ctx.storage.removeSource(namespace, scope);
1442
- yield* ctx.core.sources.unregister({ id: namespace, targetScope: scope });
1443
- })
1444
- );
1445
- if (configFile) {
1446
- yield* configFile.removeSource(namespace);
1447
- }
1448
- }),
1449
- getSource: (namespace, scope) => ctx.storage.getSource(namespace, scope),
1450
- configureSource,
1451
- configure: (source, input) => configureSource(source.id, source.scope, input.scope, input)
1452
- };
1453
- };
1454
- var graphqlPlugin = definePlugin((options) => {
1455
- return {
1456
- id: "graphql",
1457
- packageName: "@executor-js/plugin-graphql",
1458
- sourcePresets: graphqlPresets,
1459
- schema: graphqlSchema,
1460
- storage: (deps) => makeDefaultGraphqlStore(deps),
1461
- extension: (ctx) => makeGraphqlExtension(
1462
- ctx,
1463
- options?.httpClientLayer ?? ctx.httpClientLayer,
1464
- options?.configFile
1465
- ),
1466
- sourceConfigure: {
1467
- type: "graphql",
1468
- schema: SourceConfigureInputSchema,
1469
- configure: ({ ctx, sourceId, sourceScope, targetScope, config }) => makeGraphqlExtension(
1470
- ctx,
1471
- options?.httpClientLayer ?? ctx.httpClientLayer,
1472
- options?.configFile
1473
- ).configureSource(
1474
- sourceId,
1475
- sourceScope,
1476
- targetScope,
1477
- config
1478
- )
1479
- },
1480
- staticSources: (self) => [
1481
- {
1482
- id: "graphql",
1483
- kind: "executor",
1484
- name: "GraphQL",
1485
- tools: [
1486
- tool({
1487
- name: "getSource",
1488
- 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`.",
1489
- inputSchema: StaticGetSourceInputStandardSchema,
1490
- outputSchema: StaticGetSourceOutputStandardSchema,
1491
- execute: (input, { ctx }) => Effect5.map(
1492
- self.getSource(input.namespace, resolveStaticScopeInput(ctx, input.scope)),
1493
- (source) => ToolResult.ok({ source })
1494
- )
1495
- }),
1496
- tool({
1497
- name: "addSource",
1498
- 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`.",
1499
- annotations: {
1500
- requiresApproval: true,
1501
- approvalDescription: "Add a GraphQL source"
1502
- },
1503
- inputSchema: StaticAddSourceInputStandardSchema,
1504
- outputSchema: StaticAddSourceOutputStandardSchema,
1505
- execute: (input, { ctx }) => {
1506
- const sourceScope = defaultSourceInstallScopeId(ctx.scopes);
1507
- if (sourceScope === null) {
1508
- return Effect5.succeed(
1509
- graphqlToolFailure(
1510
- "source_scope_unavailable",
1511
- "Cannot add a GraphQL source because this executor has no source install scope."
1512
- )
1513
- );
1514
- }
1515
- return self.addSource({ ...input, scope: sourceScope }).pipe(
1516
- Effect5.map(
1517
- (result) => ToolResult.ok({
1518
- ...result,
1519
- source: { id: result.namespace, scope: sourceScope }
1520
- })
1521
- ),
1522
- Effect5.catchTags({
1523
- GraphqlIntrospectionError: ({ message }) => Effect5.succeed(graphqlToolFailure("graphql_introspection_failed", message)),
1524
- GraphqlExtractionError: ({ message }) => Effect5.succeed(graphqlToolFailure("graphql_extraction_failed", message))
1525
- })
1526
- );
1527
- }
1528
- }),
1529
- tool({
1530
- name: "configureSource",
1531
- 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}`.',
1532
- annotations: {
1533
- requiresApproval: true,
1534
- approvalDescription: "Configure a GraphQL source"
1535
- },
1536
- inputSchema: StaticConfigureSourceInputStandardSchema,
1537
- outputSchema: StaticConfigureSourceOutputStandardSchema,
1538
- execute: (input, { ctx }) => {
1539
- const { source, ...config } = input;
1540
- const sourceScope = resolveStaticScopeInput(ctx, source.scope);
1541
- const targetScope = resolveStaticScopeInput(ctx, config.scope);
1542
- return Effect5.as(
1543
- self.configure(
1544
- { id: source.id, scope: sourceScope },
1545
- { ...config, scope: targetScope }
1546
- ),
1547
- ToolResult.ok({ configured: true })
1548
- );
1549
- }
1550
- })
1551
- ]
1552
- }
1553
- ],
1554
- invokeTool: ({ ctx, toolRow, args }) => Effect5.gen(function* () {
1555
- const httpClientLayer = options?.httpClientLayer ?? ctx.httpClientLayer;
1556
- const toolScope = toolRow.scope_id;
1557
- const op = yield* ctx.storage.getOperationByToolId(toolRow.id, toolScope);
1558
- if (!op) {
1559
- return yield* new GraphqlInvocationError({
1560
- message: `No GraphQL operation found for tool "${toolRow.id}"`,
1561
- statusCode: Option5.none()
1562
- });
1563
- }
1564
- const source = yield* ctx.storage.getSource(op.sourceId, toolScope);
1565
- if (!source) {
1566
- return yield* new GraphqlInvocationError({
1567
- message: `No GraphQL source found for "${op.sourceId}"`,
1568
- statusCode: Option5.none()
1569
- });
1570
- }
1571
- const resolvedHeaders = (yield* resolveGraphqlBindingValueMap(ctx, source.headers, {
1572
- sourceId: source.namespace,
1573
- sourceScope: source.scope,
1574
- missingLabel: "header"
1575
- })) ?? {};
1576
- const resolvedQueryParams = (yield* resolveGraphqlBindingValueMap(ctx, source.queryParams, {
1577
- sourceId: source.namespace,
1578
- sourceScope: source.scope,
1579
- missingLabel: "query parameter"
1580
- })) ?? {};
1581
- const oauthHeader = yield* resolveGraphqlStoredOAuthHeader(
1582
- ctx,
1583
- source.namespace,
1584
- source.scope,
1585
- source.auth
1586
- );
1587
- Object.assign(resolvedHeaders, oauthHeader ?? {});
1588
- const result = yield* invokeWithLayer(
1589
- op.binding,
1590
- args ?? {},
1591
- source.endpoint,
1592
- resolvedHeaders,
1593
- resolvedQueryParams,
1594
- httpClientLayer
1595
- );
1596
- const errors = decodeGraphqlErrors(result.errors);
1597
- if (errors !== void 0 && errors.length > 0) {
1598
- const firstMessage = extractGraphqlErrorMessage(errors);
1599
- return ToolResult.fail({
1600
- code: "graphql_errors",
1601
- message: firstMessage !== void 0 ? firstMessage : "GraphQL request returned errors",
1602
- details: { errors }
1603
- });
1604
- }
1605
- if (result.status < 200 || result.status >= 300) {
1606
- if (result.status === 401 || result.status === 403) {
1607
- return authToolFailure({
1608
- code: "credential_rejected",
1609
- status: result.status,
1610
- message: `Upstream rejected credentials for GraphQL source "${source.namespace}" with HTTP ${result.status}. Re-authenticate or update the source credentials before retrying this tool.`,
1611
- source: { id: source.namespace, scope: source.scope },
1612
- credential: { kind: "upstream", label: "Upstream authorization" },
1613
- upstream: {
1614
- status: result.status,
1615
- details: {
1616
- data: result.data,
1617
- errors: result.errors
1618
- }
1619
- },
1620
- recovery: { configureSourceTool: "executor.graphql.configureSource" }
1621
- });
1622
- }
1623
- return ToolResult.fail({
1624
- code: "graphql_http_error",
1625
- status: result.status,
1626
- message: `GraphQL request failed with HTTP ${result.status}`,
1627
- details: {
1628
- status: result.status,
1629
- data: result.data,
1630
- errors: result.errors
1631
- }
1632
- });
1633
- }
1634
- return ToolResult.ok(result.data);
1635
- }).pipe(
1636
- Effect5.catchTag(
1637
- "GraphqlAuthRequiredError",
1638
- (error) => Effect5.succeed(graphqlAuthToolFailure(error))
1639
- )
1640
- ),
1641
- resolveAnnotations: ({ ctx, sourceId, toolRows }) => Effect5.gen(function* () {
1642
- const scopes = /* @__PURE__ */ new Set();
1643
- for (const row of toolRows) {
1644
- scopes.add(row.scope_id);
1645
- }
1646
- const entries = yield* Effect5.forEach(
1647
- [...scopes],
1648
- (scope) => Effect5.gen(function* () {
1649
- const ops = yield* ctx.storage.listOperationsBySource(sourceId, scope);
1650
- const byId = /* @__PURE__ */ new Map();
1651
- for (const op of ops) byId.set(op.toolId, op.binding);
1652
- return [scope, byId];
1653
- }),
1654
- { concurrency: "unbounded" }
1655
- );
1656
- const byScope = new Map(entries);
1657
- const out = {};
1658
- for (const row of toolRows) {
1659
- const binding = byScope.get(row.scope_id)?.get(row.id);
1660
- if (binding) out[row.id] = annotationsFor(binding);
1661
- }
1662
- return out;
1663
- }),
1664
- removeSource: ({ ctx, sourceId, scope }) => Effect5.gen(function* () {
1665
- yield* ctx.transaction(
1666
- Effect5.gen(function* () {
1667
- yield* ctx.credentialBindings.removeForSource({
1668
- pluginId: GRAPHQL_PLUGIN_ID,
1669
- sourceId,
1670
- sourceScope: ScopeId.make(scope)
1671
- });
1672
- yield* ctx.storage.removeSource(sourceId, scope);
1673
- })
1674
- );
1675
- if (options?.configFile) {
1676
- yield* options.configFile.removeSource(sourceId);
1677
- }
1678
- }),
1679
- usagesForSecret: () => Effect5.succeed([]),
1680
- usagesForConnection: () => Effect5.succeed([]),
1681
- detect: ({ ctx, url }) => Effect5.gen(function* () {
1682
- const httpClientLayer = options?.httpClientLayer ?? ctx.httpClientLayer;
1683
- const trimmed = url.trim();
1684
- if (!trimmed) return null;
1685
- const parsed = yield* Effect5.try({
1686
- try: () => new URL(trimmed),
1687
- catch: (cause) => cause
1688
- }).pipe(Effect5.option);
1689
- if (Option5.isNone(parsed)) return null;
1690
- const ok = yield* introspect(trimmed).pipe(
1691
- Effect5.provide(httpClientLayer),
1692
- Effect5.map(() => true),
1693
- Effect5.catch(() => Effect5.succeed(false))
1694
- );
1695
- const name = namespaceFromEndpoint(trimmed);
1696
- if (ok) {
1697
- return SourceDetectionResult.make({
1698
- kind: "graphql",
1699
- confidence: "high",
1700
- endpoint: trimmed,
1701
- name,
1702
- namespace: name
1703
- });
1704
- }
1705
- if (urlMatchesToken(parsed.value, "graphql")) {
1706
- return SourceDetectionResult.make({
1707
- kind: "graphql",
1708
- confidence: "low",
1709
- endpoint: trimmed,
1710
- name,
1711
- namespace: name
1712
- });
1713
- }
1714
- return null;
1715
- })
1716
- };
1717
- });
1718
-
1719
- export {
1720
- introspect,
1721
- parseIntrospectionJson,
1722
- extract,
1723
- resolveHeaders,
1724
- invoke,
1725
- invokeWithLayer,
1726
- graphqlSchema,
1727
- makeDefaultGraphqlStore,
1728
- graphqlPlugin
1729
- };
1730
- //# sourceMappingURL=chunk-2252RTCE.js.map