@graphql-hive/router-runtime 1.2.5 → 1.3.0-alpha-a990d4c23ad5a2cd3bc5526ee8a987fa39a5ca86

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.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,13 @@
1
1
  # @graphql-hive/router-runtime
2
2
 
3
- ## 1.2.5
3
+ ## 1.3.0-alpha-a990d4c23ad5a2cd3bc5526ee8a987fa39a5ca86
4
+ ### Minor Changes
5
+
6
+
7
+
8
+ - [#2203](https://github.com/graphql-hive/gateway/pull/2203) [`12dfc58`](https://github.com/graphql-hive/gateway/commit/12dfc58cf08fcfb7e47a0a000f36f846701a05e1) Thanks [@ardatan](https://github.com/ardatan)! - EDFS Support for Router Runtime
9
+
10
+
4
11
  ### Patch Changes
5
12
 
6
13
 
package/dist/index.cjs CHANGED
@@ -10,6 +10,219 @@ var graphql = require('graphql');
10
10
  var core = require('@envelop/core');
11
11
  var executor = require('@graphql-tools/executor');
12
12
 
13
+ const getTypeInfo = utils.memoize1(function getTypeInfo2(schema) {
14
+ return new graphql.TypeInfo(schema);
15
+ });
16
+ utils.memoize2(function getTypeInfoWithType2(schema, type) {
17
+ return graphql.versionInfo.major < 16 ? new graphql.TypeInfo(schema, void 0, type) : new graphql.TypeInfo(schema, type);
18
+ });
19
+
20
+ const getPubsubOperationRootFields = utils.memoize1(function(schema) {
21
+ const pubsubOperationFields = /* @__PURE__ */ new Map();
22
+ const subscriptionType = schema.getSubscriptionType();
23
+ if (subscriptionType) {
24
+ const subscriptionFields = subscriptionType.getFields();
25
+ for (const fieldName in subscriptionFields) {
26
+ const fieldDef = subscriptionFields[fieldName];
27
+ if (fieldDef) {
28
+ const pubsubOperations = utils.getDirectiveInExtensions(
29
+ fieldDef,
30
+ "pubsubOperation"
31
+ );
32
+ if (pubsubOperations) {
33
+ for (const { pubsubTopic } of pubsubOperations) {
34
+ pubsubOperationFields.set(fieldDef.name, pubsubTopic);
35
+ }
36
+ }
37
+ }
38
+ }
39
+ }
40
+ return pubsubOperationFields;
41
+ });
42
+ function resolvePubsubOperationRootField(responseKey, topicName, pubsub) {
43
+ return utils.mapAsyncIterator(pubsub.subscribe(topicName), (payload) => ({
44
+ data: {
45
+ [responseKey]: payload
46
+ }
47
+ }));
48
+ }
49
+ function handlePubsubOperationField(supergraphSchema, executionRequest) {
50
+ if (executionRequest.operationType === "subscription") {
51
+ const typeInfo = getTypeInfo(supergraphSchema);
52
+ let responseKey;
53
+ let fieldName;
54
+ let selectionSet;
55
+ let returnType;
56
+ graphql.visit(
57
+ executionRequest.document,
58
+ graphql.visitWithTypeInfo(typeInfo, {
59
+ Field(node) {
60
+ const parentType = typeInfo.getParentType();
61
+ if (parentType === supergraphSchema.getSubscriptionType()) {
62
+ responseKey = node.alias?.value || node.name.value;
63
+ fieldName = node.name.value;
64
+ selectionSet = node.selectionSet;
65
+ const fieldDef = typeInfo.getFieldDef();
66
+ if (fieldDef) {
67
+ returnType = graphql.getNamedType(fieldDef.type);
68
+ }
69
+ return graphql.BREAK;
70
+ }
71
+ return node;
72
+ }
73
+ })
74
+ );
75
+ if (responseKey && fieldName) {
76
+ const pubsubOperationFields = getPubsubOperationRootFields(supergraphSchema);
77
+ const pubsubTopic = pubsubOperationFields.get(fieldName);
78
+ if (pubsubTopic) {
79
+ const pubsub = executionRequest.context?.pubsub;
80
+ if (!pubsub) {
81
+ throw utils.createGraphQLError(
82
+ `You have to configure a PubSub instance in the context to execute subscription operations with @pubsubOperation directive.`
83
+ );
84
+ }
85
+ let newExecutionRequest;
86
+ if (selectionSet && returnType) {
87
+ const newDocument = graphql.parse(
88
+ /* GraphQL */
89
+ `
90
+ query ${executionRequest.operationName}($representations: [_Any!]!) {
91
+ _entities(representations: $representations) {
92
+ __typename
93
+ ... on ${returnType.name} ${graphql.print(selectionSet)}
94
+ }
95
+ }
96
+ `
97
+ );
98
+ newExecutionRequest = {
99
+ ...executionRequest,
100
+ document: newDocument
101
+ };
102
+ }
103
+ return {
104
+ executionResult: resolvePubsubOperationRootField(
105
+ responseKey,
106
+ pubsubTopic,
107
+ pubsub
108
+ ),
109
+ responseKey,
110
+ returnTypeName: returnType?.name,
111
+ newExecutionRequest
112
+ };
113
+ }
114
+ }
115
+ }
116
+ return false;
117
+ }
118
+ const getPubsubPublishVisitor = utils.memoize2(function getPubsubPublishFields(schema, pubsub) {
119
+ const pubsubPublishVisitor = {};
120
+ for (const typeName in schema.getTypeMap()) {
121
+ const type = schema.getType(typeName);
122
+ if (type != null && "getFields" in type) {
123
+ const fields = type.getFields();
124
+ for (const fieldName in fields) {
125
+ const fieldDef = fields[fieldName];
126
+ if (fieldDef) {
127
+ const pubsubPublishes = utils.getDirectiveInExtensions(
128
+ fieldDef,
129
+ "pubsubPublish"
130
+ );
131
+ if (pubsubPublishes) {
132
+ for (const { pubsubTopic } of pubsubPublishes) {
133
+ const typeVisitor = pubsubPublishVisitor[typeName] ||= {};
134
+ typeVisitor[fieldName] = (value) => {
135
+ pubsub.publish(pubsubTopic, value);
136
+ return value;
137
+ };
138
+ }
139
+ }
140
+ }
141
+ }
142
+ }
143
+ }
144
+ if (!Object.keys(pubsubPublishVisitor).length) {
145
+ return false;
146
+ }
147
+ return pubsubPublishVisitor;
148
+ });
149
+ function handleResultWithPubSubPublish(schema, request, result) {
150
+ if (result.data != null && request.context?.pubsub != null) {
151
+ const pubsubPublishVisitor = getPubsubPublishVisitor(
152
+ schema,
153
+ request.context.pubsub
154
+ );
155
+ if (pubsubPublishVisitor) {
156
+ return utils.visitResult(result, request, schema, pubsubPublishVisitor);
157
+ }
158
+ }
159
+ }
160
+
161
+ const queryPlanForExecutionRequestContext = /* @__PURE__ */ new WeakMap();
162
+ function getLazyValue(factory) {
163
+ let _value;
164
+ return function() {
165
+ if (_value == null) {
166
+ _value = factory();
167
+ }
168
+ return _value;
169
+ };
170
+ }
171
+ function getLazyFactory(factory) {
172
+ let _value;
173
+ return function(...args) {
174
+ if (!_value) {
175
+ _value = factory();
176
+ }
177
+ return _value(...args);
178
+ };
179
+ }
180
+ function onSubgraphExecuteWithTransforms(subgraphName, executionRequest, onSubgraphExecute, getSubschema) {
181
+ const subschema = getSubschema(subgraphName);
182
+ if (subschema.transforms?.length) {
183
+ const transforms = subschema.transforms;
184
+ const transformationContext = /* @__PURE__ */ Object.create(null);
185
+ const delegationContext = void 0;
186
+ for (const transform of transforms) {
187
+ if (transform.transformRequest) {
188
+ executionRequest = transform.transformRequest(
189
+ executionRequest,
190
+ delegationContext,
191
+ transformationContext
192
+ );
193
+ }
194
+ }
195
+ return handleMaybePromiseMaybeAsyncIterable(
196
+ () => onSubgraphExecute(subgraphName, executionRequest),
197
+ (executionResult) => {
198
+ for (const transform of transforms.toReversed()) {
199
+ if (transform.transformResult) {
200
+ executionResult = transform.transformResult(
201
+ executionResult,
202
+ delegationContext,
203
+ transformationContext
204
+ );
205
+ }
206
+ }
207
+ return executionResult;
208
+ }
209
+ );
210
+ }
211
+ return onSubgraphExecute(subgraphName, executionRequest);
212
+ }
213
+ function handleMaybePromiseMaybeAsyncIterable(executor, mapper, errorMapper) {
214
+ return promiseHelpers.handleMaybePromise(
215
+ executor,
216
+ (result$) => {
217
+ if (utils.isAsyncIterable(result$)) {
218
+ return promiseHelpers.mapAsyncIterator(result$, mapper, errorMapper);
219
+ }
220
+ return mapper(result$);
221
+ },
222
+ errorMapper
223
+ );
224
+ }
225
+
13
226
  function isEntityRepresentation(obj) {
14
227
  return obj?.__typename != null;
15
228
  }
@@ -28,23 +241,17 @@ function executeQueryPlan({
28
241
  executionRequest,
29
242
  onSubgraphExecute
30
243
  });
31
- function handleResp() {
32
- const executionResult = {};
33
- if (Object.keys(executionContext.data).length > 0) {
34
- executionResult.data = projectDataByOperation(executionContext);
35
- }
36
- if (executionContext.errors.length > 0) {
37
- executionResult.errors = executionContext.errors;
38
- }
39
- return executionResult;
40
- }
41
- return promiseHelpers.handleMaybePromise(
244
+ return handleMaybePromiseMaybeAsyncIterable(
42
245
  () => executePlanNode(node, executionContext),
43
- (res) => {
44
- if (utils.isAsyncIterable(res)) {
45
- return promiseHelpers.mapAsyncIterator(res, handleResp);
246
+ () => {
247
+ const executionResult = {};
248
+ if (Object.keys(executionContext.data).length > 0) {
249
+ executionResult.data = projectDataByOperation(executionContext);
46
250
  }
47
- return handleResp();
251
+ if (executionContext.errors.length > 0) {
252
+ executionResult.errors = executionContext.errors;
253
+ }
254
+ return executionResult;
48
255
  }
49
256
  );
50
257
  }
@@ -465,41 +672,7 @@ function executeBatchFetchPlanNode(batchFetchNode, executionContext, batchContex
465
672
  batchContext,
466
673
  selectedVariables
467
674
  );
468
- const handleBatchResult = (fetchResult) => {
469
- if (utils.isAsyncIterable(fetchResult)) {
470
- return promiseHelpers.mapAsyncIterator(fetchResult, handleBatchResult);
471
- }
472
- if (fetchResult.errors?.length) {
473
- executionContext.errors.push(
474
- ...normalizeBatchFetchErrors(fetchResult.errors, batchContext)
475
- );
476
- }
477
- const responseData = fetchResult.data;
478
- if (!responseData || typeof responseData !== "object") {
479
- return;
480
- }
481
- for (const [aliasName, aliasContext] of batchContext.byAlias.entries()) {
482
- let aliasData = responseData[aliasName];
483
- if (!aliasData) {
484
- continue;
485
- }
486
- if (aliasContext.outputRewrites?.length) {
487
- aliasData = applyOutputRewrites(
488
- aliasData,
489
- aliasContext.outputRewrites,
490
- executionContext.supergraphSchema
491
- );
492
- }
493
- if (Array.isArray(aliasData)) {
494
- applyBatchAliasEntities(
495
- aliasData,
496
- aliasContext
497
- );
498
- }
499
- }
500
- return;
501
- };
502
- return promiseHelpers.handleMaybePromise(
675
+ return handleMaybePromiseMaybeAsyncIterable(
503
676
  () => executionContext.onSubgraphExecute(batchFetchNode.serviceName, {
504
677
  document: getDocumentNodeOfFetchingNode(batchFetchNode),
505
678
  variables: variablesForFetch,
@@ -512,7 +685,42 @@ function executeBatchFetchPlanNode(batchFetchNode, executionContext, batchContex
512
685
  info: executionContext.executionRequest.info,
513
686
  signal: executionContext.executionRequest.signal
514
687
  }),
515
- handleBatchResult
688
+ (fetchResult) => {
689
+ if (fetchResult.errors?.length) {
690
+ executionContext.errors.push(
691
+ ...normalizeBatchFetchErrors(fetchResult.errors, batchContext)
692
+ );
693
+ }
694
+ const responseData = fetchResult.data;
695
+ if (!responseData || typeof responseData !== "object") {
696
+ return;
697
+ }
698
+ for (const [aliasName, aliasContext] of batchContext.byAlias.entries()) {
699
+ let aliasData = responseData[aliasName];
700
+ if (!aliasData) {
701
+ continue;
702
+ }
703
+ if (aliasContext.outputRewrites?.length) {
704
+ aliasData = applyOutputRewrites(
705
+ aliasData,
706
+ aliasContext.outputRewrites,
707
+ executionContext.supergraphSchema
708
+ );
709
+ }
710
+ if (Array.isArray(aliasData)) {
711
+ applyBatchAliasEntities(
712
+ aliasData,
713
+ aliasContext
714
+ );
715
+ }
716
+ }
717
+ return;
718
+ },
719
+ (error) => handleSubgraphExecutionError(
720
+ error,
721
+ executionContext,
722
+ batchFetchNode.serviceName
723
+ )
516
724
  );
517
725
  }
518
726
  function executeFetchPlanNode(fetchNode, executionContext, state) {
@@ -582,53 +790,7 @@ function executeFetchPlanNode(fetchNode, executionContext, state) {
582
790
  variablesForFetch = variablesForFetch ? { ...selectedVariables, ...variablesForFetch } : { ...selectedVariables };
583
791
  }
584
792
  const defaultErrorPath = state?.errorPath ?? state?.flatten?.errorPath ?? getDefaultErrorPath(fetchNode);
585
- const handleFetchResult = (fetchResult) => {
586
- if (utils.isAsyncIterable(fetchResult)) {
587
- return promiseHelpers.mapAsyncIterator(fetchResult, handleFetchResult);
588
- }
589
- if (fetchResult.errors?.length) {
590
- const normalizedErrors = normalizeFetchErrors(fetchResult.errors, {
591
- fetchNode,
592
- state,
593
- defaultPath: defaultErrorPath
594
- });
595
- if (normalizedErrors.length) {
596
- executionContext.errors.push(...normalizedErrors);
597
- }
598
- }
599
- const responseData = fetchNode.outputRewrites ? applyOutputRewrites(
600
- fetchResult.data,
601
- fetchNode.outputRewrites,
602
- executionContext.supergraphSchema
603
- ) : fetchResult.data;
604
- if (!responseData) {
605
- return;
606
- }
607
- if (flattenState && flattenState.entityRefs.length) {
608
- const returnedEntities = responseData._entities;
609
- if (Array.isArray(returnedEntities)) {
610
- mergeFlattenEntities(returnedEntities, flattenState);
611
- }
612
- return;
613
- }
614
- if (representationTargets?.length && responseData._entities) {
615
- const returnedEntities = responseData._entities;
616
- for (let index = 0; index < returnedEntities.length; index++) {
617
- const entity = returnedEntities[index];
618
- const target = representationTargets[index];
619
- if (target && entity) {
620
- Object.assign(target, utils.mergeDeep([target, entity], false, true, true));
621
- }
622
- }
623
- return;
624
- }
625
- Object.assign(
626
- executionContext.data,
627
- utils.mergeDeep([executionContext.data, responseData], false, true, true)
628
- );
629
- return;
630
- };
631
- return promiseHelpers.handleMaybePromise(
793
+ return handleMaybePromiseMaybeAsyncIterable(
632
794
  () => executionContext.onSubgraphExecute(fetchNode.serviceName, {
633
795
  document: getDocumentNodeOfFetchingNode(fetchNode),
634
796
  variables: variablesForFetch,
@@ -641,9 +803,76 @@ function executeFetchPlanNode(fetchNode, executionContext, state) {
641
803
  info: executionContext.executionRequest.info,
642
804
  signal: executionContext.executionRequest.signal
643
805
  }),
644
- handleFetchResult
806
+ (fetchResult) => {
807
+ if (fetchResult.errors?.length) {
808
+ const normalizedErrors = normalizeFetchErrors(fetchResult.errors, {
809
+ fetchNode,
810
+ state,
811
+ defaultPath: defaultErrorPath
812
+ });
813
+ if (normalizedErrors.length) {
814
+ executionContext.errors.push(...normalizedErrors);
815
+ }
816
+ }
817
+ const responseData = fetchNode.outputRewrites ? applyOutputRewrites(
818
+ fetchResult.data,
819
+ fetchNode.outputRewrites,
820
+ executionContext.supergraphSchema
821
+ ) : fetchResult.data;
822
+ if (!responseData) {
823
+ return;
824
+ }
825
+ if (flattenState && flattenState.entityRefs.length) {
826
+ const returnedEntities = responseData._entities;
827
+ if (Array.isArray(returnedEntities)) {
828
+ mergeFlattenEntities(returnedEntities, flattenState);
829
+ }
830
+ return;
831
+ }
832
+ if (representationTargets?.length && responseData._entities) {
833
+ const returnedEntities = responseData._entities;
834
+ for (let index = 0; index < returnedEntities.length; index++) {
835
+ const entity = returnedEntities[index];
836
+ const target = representationTargets[index];
837
+ if (target && entity) {
838
+ Object.assign(
839
+ target,
840
+ utils.mergeDeep([target, entity], false, true, true)
841
+ );
842
+ }
843
+ }
844
+ return;
845
+ }
846
+ Object.assign(
847
+ executionContext.data,
848
+ utils.mergeDeep([executionContext.data, responseData], false, true, true)
849
+ );
850
+ return;
851
+ },
852
+ (error) => handleSubgraphExecutionError(
853
+ error,
854
+ executionContext,
855
+ fetchNode.serviceName,
856
+ defaultErrorPath
857
+ )
645
858
  );
646
859
  }
860
+ function handleSubgraphExecutionError(error, executionContext, serviceName, path) {
861
+ let graphQLError;
862
+ if (error instanceof graphql.GraphQLError) {
863
+ graphQLError = error;
864
+ } else {
865
+ graphQLError = utils.createGraphQLError(error.message, {
866
+ originalError: error,
867
+ extensions: {
868
+ code: "DOWNSTREAM_SERVICE_ERROR",
869
+ serviceName
870
+ },
871
+ path
872
+ });
873
+ }
874
+ executionContext.errors.push(graphQLError);
875
+ }
647
876
  function selectFetchVariables(variableValues, variableUsages) {
648
877
  if (!variableValues || !variableUsages || variableUsages.length === 0) {
649
878
  return void 0;
@@ -1333,20 +1562,12 @@ function projectRequires(requiresSelections, entity, supergraphSchema) {
1333
1562
  return result;
1334
1563
  }
1335
1564
 
1336
- const queryPlanForExecutionRequestContext = /* @__PURE__ */ new WeakMap();
1337
- function getLazyFactory(factory) {
1338
- let _value;
1339
- return function(...args) {
1340
- if (!_value) {
1341
- _value = factory();
1342
- }
1343
- return _value(...args);
1344
- };
1345
- }
1346
-
1347
1565
  async function unifiedGraphHandler(opts) {
1348
1566
  const getSubschema = getLazyFactory(
1349
- () => fusionRuntime.handleFederationSupergraph(opts).getSubschema
1567
+ () => getHandledFederationSupergraph().getSubschema
1568
+ );
1569
+ const getHandledFederationSupergraph = getLazyValue(
1570
+ () => fusionRuntime.handleFederationSupergraph(opts)
1350
1571
  );
1351
1572
  const moduleName = "@graphql-hive/router-query-planner";
1352
1573
  const { QueryPlanner } = await import(moduleName);
@@ -1440,45 +1661,96 @@ async function unifiedGraphHandler(opts) {
1440
1661
  supergraphSchema,
1441
1662
  executionRequest,
1442
1663
  onSubgraphExecute(subgraphName, executionRequest2) {
1443
- const subschema = getSubschema(subgraphName);
1444
- if (subschema.transforms?.length) {
1445
- const transforms = subschema.transforms;
1446
- const transformationContext = /* @__PURE__ */ Object.create(null);
1447
- for (const transform of transforms) {
1448
- if (transform.transformRequest) {
1449
- executionRequest2 = transform.transformRequest(
1450
- executionRequest2,
1451
- void 0,
1452
- transformationContext
1453
- );
1454
- }
1455
- }
1456
- return promiseHelpers.handleMaybePromise(
1457
- () => opts.onSubgraphExecute(subgraphName, executionRequest2),
1664
+ function executeSubgraph(executionRequest3) {
1665
+ return handleMaybePromiseMaybeAsyncIterable(
1666
+ () => onSubgraphExecuteWithTransforms(
1667
+ subgraphName,
1668
+ executionRequest3,
1669
+ opts.onSubgraphExecute,
1670
+ getSubschema
1671
+ ),
1458
1672
  (executionResult) => {
1459
- function handleResult(executionResult2) {
1460
- for (const transform of transforms.toReversed()) {
1461
- if (transform.transformResult) {
1462
- executionResult2 = transform.transformResult(
1463
- executionResult2,
1464
- void 0,
1465
- transformationContext
1466
- );
1467
- }
1468
- }
1469
- return executionResult2;
1470
- }
1471
- if (utils.isAsyncIterable(executionResult)) {
1472
- return promiseHelpers.mapAsyncIterator(
1473
- executionResult,
1474
- (result) => handleResult(result)
1673
+ if (executionRequest3.operationType === "mutation") {
1674
+ handleResultWithPubSubPublish(
1675
+ supergraphSchema,
1676
+ executionRequest3,
1677
+ executionResult
1475
1678
  );
1476
1679
  }
1477
- return handleResult(executionResult);
1680
+ return executionResult;
1478
1681
  }
1479
1682
  );
1480
1683
  }
1481
- return opts.onSubgraphExecute(subgraphName, executionRequest2);
1684
+ const maybeResult = handlePubsubOperationField(
1685
+ supergraphSchema,
1686
+ executionRequest2
1687
+ );
1688
+ if (maybeResult) {
1689
+ const {
1690
+ executionResult,
1691
+ newExecutionRequest,
1692
+ responseKey,
1693
+ returnTypeName
1694
+ } = maybeResult;
1695
+ if (newExecutionRequest) {
1696
+ return promiseHelpers.mapAsyncIterator(
1697
+ executionResult,
1698
+ (executionResult2) => {
1699
+ if (executionResult2.data?.[responseKey] != null) {
1700
+ const representations = utils.asArray(
1701
+ executionResult2.data[responseKey]
1702
+ );
1703
+ if (returnTypeName) {
1704
+ for (const representation of representations) {
1705
+ representation.__typename = returnTypeName;
1706
+ }
1707
+ }
1708
+ return handleMaybePromiseMaybeAsyncIterable(
1709
+ () => executeSubgraph({
1710
+ ...newExecutionRequest,
1711
+ variables: {
1712
+ representations
1713
+ }
1714
+ }),
1715
+ (entitiesResult) => {
1716
+ if (entitiesResult?.data?._entities?.length) {
1717
+ const entities = utils.asArray(
1718
+ entitiesResult.data._entities
1719
+ );
1720
+ for (let i = 0; i < entities.length; i++) {
1721
+ const entity = entities[i];
1722
+ const representation = representations[i];
1723
+ if (entity != null && representation != null) {
1724
+ Object.assign(
1725
+ representation,
1726
+ utils.mergeDeep(
1727
+ [entity, representation],
1728
+ false,
1729
+ true,
1730
+ true
1731
+ )
1732
+ );
1733
+ }
1734
+ }
1735
+ return executionResult2;
1736
+ }
1737
+ if (entitiesResult?.errors?.length) {
1738
+ executionResult2.errors ||= [];
1739
+ executionResult2.errors.push(
1740
+ ...entitiesResult.errors
1741
+ );
1742
+ }
1743
+ return executionResult2;
1744
+ }
1745
+ );
1746
+ }
1747
+ return executionResult2;
1748
+ }
1749
+ );
1750
+ }
1751
+ return executionResult;
1752
+ }
1753
+ return executeSubgraph(executionRequest2);
1482
1754
  },
1483
1755
  queryPlan
1484
1756
  });
package/dist/index.js CHANGED
@@ -2,12 +2,225 @@ import { handleFederationSupergraph } from '@graphql-mesh/fusion-runtime';
2
2
  import { createDefaultExecutor } from '@graphql-mesh/transport-common';
3
3
  import { defaultPrintFn } from '@graphql-tools/executor-common';
4
4
  import { filterInternalFieldsAndTypes, getRngFromEnv } from '@graphql-tools/federation';
5
- import { isAsyncIterable, getOperationASTFromRequest, mergeDeep, memoize1, getOperationASTFromDocument, relocatedError, getDirective } from '@graphql-tools/utils';
6
- import { handleMaybePromise, mapAsyncIterator, isPromise } from '@whatwg-node/promise-helpers';
7
- import { parse, isObjectType, isAbstractType, Kind, isInterfaceType, TypeNameMetaFieldDef, getNamedType, isEnumType, isNonNullType, isOutputType, visit, BREAK } from 'graphql';
5
+ import { memoize1, memoize2, createGraphQLError, visitResult, getDirectiveInExtensions, mapAsyncIterator, isAsyncIterable, getOperationASTFromRequest, getOperationASTFromDocument, mergeDeep, relocatedError, getDirective, asArray } from '@graphql-tools/utils';
6
+ import { handleMaybePromise, mapAsyncIterator as mapAsyncIterator$1, isPromise } from '@whatwg-node/promise-helpers';
7
+ import { TypeInfo, versionInfo, visit, visitWithTypeInfo, getNamedType, BREAK, parse, print, Kind, isObjectType, isInterfaceType, TypeNameMetaFieldDef, isEnumType, isNonNullType, isOutputType, GraphQLError, isAbstractType } from 'graphql';
8
8
  import { documentStringMap } from '@envelop/core';
9
9
  import { getFragmentsFromDocument, getVariableValues } from '@graphql-tools/executor';
10
10
 
11
+ const getTypeInfo = memoize1(function getTypeInfo2(schema) {
12
+ return new TypeInfo(schema);
13
+ });
14
+ memoize2(function getTypeInfoWithType2(schema, type) {
15
+ return versionInfo.major < 16 ? new TypeInfo(schema, void 0, type) : new TypeInfo(schema, type);
16
+ });
17
+
18
+ const getPubsubOperationRootFields = memoize1(function(schema) {
19
+ const pubsubOperationFields = /* @__PURE__ */ new Map();
20
+ const subscriptionType = schema.getSubscriptionType();
21
+ if (subscriptionType) {
22
+ const subscriptionFields = subscriptionType.getFields();
23
+ for (const fieldName in subscriptionFields) {
24
+ const fieldDef = subscriptionFields[fieldName];
25
+ if (fieldDef) {
26
+ const pubsubOperations = getDirectiveInExtensions(
27
+ fieldDef,
28
+ "pubsubOperation"
29
+ );
30
+ if (pubsubOperations) {
31
+ for (const { pubsubTopic } of pubsubOperations) {
32
+ pubsubOperationFields.set(fieldDef.name, pubsubTopic);
33
+ }
34
+ }
35
+ }
36
+ }
37
+ }
38
+ return pubsubOperationFields;
39
+ });
40
+ function resolvePubsubOperationRootField(responseKey, topicName, pubsub) {
41
+ return mapAsyncIterator(pubsub.subscribe(topicName), (payload) => ({
42
+ data: {
43
+ [responseKey]: payload
44
+ }
45
+ }));
46
+ }
47
+ function handlePubsubOperationField(supergraphSchema, executionRequest) {
48
+ if (executionRequest.operationType === "subscription") {
49
+ const typeInfo = getTypeInfo(supergraphSchema);
50
+ let responseKey;
51
+ let fieldName;
52
+ let selectionSet;
53
+ let returnType;
54
+ visit(
55
+ executionRequest.document,
56
+ visitWithTypeInfo(typeInfo, {
57
+ Field(node) {
58
+ const parentType = typeInfo.getParentType();
59
+ if (parentType === supergraphSchema.getSubscriptionType()) {
60
+ responseKey = node.alias?.value || node.name.value;
61
+ fieldName = node.name.value;
62
+ selectionSet = node.selectionSet;
63
+ const fieldDef = typeInfo.getFieldDef();
64
+ if (fieldDef) {
65
+ returnType = getNamedType(fieldDef.type);
66
+ }
67
+ return BREAK;
68
+ }
69
+ return node;
70
+ }
71
+ })
72
+ );
73
+ if (responseKey && fieldName) {
74
+ const pubsubOperationFields = getPubsubOperationRootFields(supergraphSchema);
75
+ const pubsubTopic = pubsubOperationFields.get(fieldName);
76
+ if (pubsubTopic) {
77
+ const pubsub = executionRequest.context?.pubsub;
78
+ if (!pubsub) {
79
+ throw createGraphQLError(
80
+ `You have to configure a PubSub instance in the context to execute subscription operations with @pubsubOperation directive.`
81
+ );
82
+ }
83
+ let newExecutionRequest;
84
+ if (selectionSet && returnType) {
85
+ const newDocument = parse(
86
+ /* GraphQL */
87
+ `
88
+ query ${executionRequest.operationName}($representations: [_Any!]!) {
89
+ _entities(representations: $representations) {
90
+ __typename
91
+ ... on ${returnType.name} ${print(selectionSet)}
92
+ }
93
+ }
94
+ `
95
+ );
96
+ newExecutionRequest = {
97
+ ...executionRequest,
98
+ document: newDocument
99
+ };
100
+ }
101
+ return {
102
+ executionResult: resolvePubsubOperationRootField(
103
+ responseKey,
104
+ pubsubTopic,
105
+ pubsub
106
+ ),
107
+ responseKey,
108
+ returnTypeName: returnType?.name,
109
+ newExecutionRequest
110
+ };
111
+ }
112
+ }
113
+ }
114
+ return false;
115
+ }
116
+ const getPubsubPublishVisitor = memoize2(function getPubsubPublishFields(schema, pubsub) {
117
+ const pubsubPublishVisitor = {};
118
+ for (const typeName in schema.getTypeMap()) {
119
+ const type = schema.getType(typeName);
120
+ if (type != null && "getFields" in type) {
121
+ const fields = type.getFields();
122
+ for (const fieldName in fields) {
123
+ const fieldDef = fields[fieldName];
124
+ if (fieldDef) {
125
+ const pubsubPublishes = getDirectiveInExtensions(
126
+ fieldDef,
127
+ "pubsubPublish"
128
+ );
129
+ if (pubsubPublishes) {
130
+ for (const { pubsubTopic } of pubsubPublishes) {
131
+ const typeVisitor = pubsubPublishVisitor[typeName] ||= {};
132
+ typeVisitor[fieldName] = (value) => {
133
+ pubsub.publish(pubsubTopic, value);
134
+ return value;
135
+ };
136
+ }
137
+ }
138
+ }
139
+ }
140
+ }
141
+ }
142
+ if (!Object.keys(pubsubPublishVisitor).length) {
143
+ return false;
144
+ }
145
+ return pubsubPublishVisitor;
146
+ });
147
+ function handleResultWithPubSubPublish(schema, request, result) {
148
+ if (result.data != null && request.context?.pubsub != null) {
149
+ const pubsubPublishVisitor = getPubsubPublishVisitor(
150
+ schema,
151
+ request.context.pubsub
152
+ );
153
+ if (pubsubPublishVisitor) {
154
+ return visitResult(result, request, schema, pubsubPublishVisitor);
155
+ }
156
+ }
157
+ }
158
+
159
+ const queryPlanForExecutionRequestContext = /* @__PURE__ */ new WeakMap();
160
+ function getLazyValue(factory) {
161
+ let _value;
162
+ return function() {
163
+ if (_value == null) {
164
+ _value = factory();
165
+ }
166
+ return _value;
167
+ };
168
+ }
169
+ function getLazyFactory(factory) {
170
+ let _value;
171
+ return function(...args) {
172
+ if (!_value) {
173
+ _value = factory();
174
+ }
175
+ return _value(...args);
176
+ };
177
+ }
178
+ function onSubgraphExecuteWithTransforms(subgraphName, executionRequest, onSubgraphExecute, getSubschema) {
179
+ const subschema = getSubschema(subgraphName);
180
+ if (subschema.transforms?.length) {
181
+ const transforms = subschema.transforms;
182
+ const transformationContext = /* @__PURE__ */ Object.create(null);
183
+ const delegationContext = void 0;
184
+ for (const transform of transforms) {
185
+ if (transform.transformRequest) {
186
+ executionRequest = transform.transformRequest(
187
+ executionRequest,
188
+ delegationContext,
189
+ transformationContext
190
+ );
191
+ }
192
+ }
193
+ return handleMaybePromiseMaybeAsyncIterable(
194
+ () => onSubgraphExecute(subgraphName, executionRequest),
195
+ (executionResult) => {
196
+ for (const transform of transforms.toReversed()) {
197
+ if (transform.transformResult) {
198
+ executionResult = transform.transformResult(
199
+ executionResult,
200
+ delegationContext,
201
+ transformationContext
202
+ );
203
+ }
204
+ }
205
+ return executionResult;
206
+ }
207
+ );
208
+ }
209
+ return onSubgraphExecute(subgraphName, executionRequest);
210
+ }
211
+ function handleMaybePromiseMaybeAsyncIterable(executor, mapper, errorMapper) {
212
+ return handleMaybePromise(
213
+ executor,
214
+ (result$) => {
215
+ if (isAsyncIterable(result$)) {
216
+ return mapAsyncIterator$1(result$, mapper, errorMapper);
217
+ }
218
+ return mapper(result$);
219
+ },
220
+ errorMapper
221
+ );
222
+ }
223
+
11
224
  function isEntityRepresentation(obj) {
12
225
  return obj?.__typename != null;
13
226
  }
@@ -26,23 +239,17 @@ function executeQueryPlan({
26
239
  executionRequest,
27
240
  onSubgraphExecute
28
241
  });
29
- function handleResp() {
30
- const executionResult = {};
31
- if (Object.keys(executionContext.data).length > 0) {
32
- executionResult.data = projectDataByOperation(executionContext);
33
- }
34
- if (executionContext.errors.length > 0) {
35
- executionResult.errors = executionContext.errors;
36
- }
37
- return executionResult;
38
- }
39
- return handleMaybePromise(
242
+ return handleMaybePromiseMaybeAsyncIterable(
40
243
  () => executePlanNode(node, executionContext),
41
- (res) => {
42
- if (isAsyncIterable(res)) {
43
- return mapAsyncIterator(res, handleResp);
244
+ () => {
245
+ const executionResult = {};
246
+ if (Object.keys(executionContext.data).length > 0) {
247
+ executionResult.data = projectDataByOperation(executionContext);
44
248
  }
45
- return handleResp();
249
+ if (executionContext.errors.length > 0) {
250
+ executionResult.errors = executionContext.errors;
251
+ }
252
+ return executionResult;
46
253
  }
47
254
  );
48
255
  }
@@ -463,41 +670,7 @@ function executeBatchFetchPlanNode(batchFetchNode, executionContext, batchContex
463
670
  batchContext,
464
671
  selectedVariables
465
672
  );
466
- const handleBatchResult = (fetchResult) => {
467
- if (isAsyncIterable(fetchResult)) {
468
- return mapAsyncIterator(fetchResult, handleBatchResult);
469
- }
470
- if (fetchResult.errors?.length) {
471
- executionContext.errors.push(
472
- ...normalizeBatchFetchErrors(fetchResult.errors, batchContext)
473
- );
474
- }
475
- const responseData = fetchResult.data;
476
- if (!responseData || typeof responseData !== "object") {
477
- return;
478
- }
479
- for (const [aliasName, aliasContext] of batchContext.byAlias.entries()) {
480
- let aliasData = responseData[aliasName];
481
- if (!aliasData) {
482
- continue;
483
- }
484
- if (aliasContext.outputRewrites?.length) {
485
- aliasData = applyOutputRewrites(
486
- aliasData,
487
- aliasContext.outputRewrites,
488
- executionContext.supergraphSchema
489
- );
490
- }
491
- if (Array.isArray(aliasData)) {
492
- applyBatchAliasEntities(
493
- aliasData,
494
- aliasContext
495
- );
496
- }
497
- }
498
- return;
499
- };
500
- return handleMaybePromise(
673
+ return handleMaybePromiseMaybeAsyncIterable(
501
674
  () => executionContext.onSubgraphExecute(batchFetchNode.serviceName, {
502
675
  document: getDocumentNodeOfFetchingNode(batchFetchNode),
503
676
  variables: variablesForFetch,
@@ -510,7 +683,42 @@ function executeBatchFetchPlanNode(batchFetchNode, executionContext, batchContex
510
683
  info: executionContext.executionRequest.info,
511
684
  signal: executionContext.executionRequest.signal
512
685
  }),
513
- handleBatchResult
686
+ (fetchResult) => {
687
+ if (fetchResult.errors?.length) {
688
+ executionContext.errors.push(
689
+ ...normalizeBatchFetchErrors(fetchResult.errors, batchContext)
690
+ );
691
+ }
692
+ const responseData = fetchResult.data;
693
+ if (!responseData || typeof responseData !== "object") {
694
+ return;
695
+ }
696
+ for (const [aliasName, aliasContext] of batchContext.byAlias.entries()) {
697
+ let aliasData = responseData[aliasName];
698
+ if (!aliasData) {
699
+ continue;
700
+ }
701
+ if (aliasContext.outputRewrites?.length) {
702
+ aliasData = applyOutputRewrites(
703
+ aliasData,
704
+ aliasContext.outputRewrites,
705
+ executionContext.supergraphSchema
706
+ );
707
+ }
708
+ if (Array.isArray(aliasData)) {
709
+ applyBatchAliasEntities(
710
+ aliasData,
711
+ aliasContext
712
+ );
713
+ }
714
+ }
715
+ return;
716
+ },
717
+ (error) => handleSubgraphExecutionError(
718
+ error,
719
+ executionContext,
720
+ batchFetchNode.serviceName
721
+ )
514
722
  );
515
723
  }
516
724
  function executeFetchPlanNode(fetchNode, executionContext, state) {
@@ -580,53 +788,7 @@ function executeFetchPlanNode(fetchNode, executionContext, state) {
580
788
  variablesForFetch = variablesForFetch ? { ...selectedVariables, ...variablesForFetch } : { ...selectedVariables };
581
789
  }
582
790
  const defaultErrorPath = state?.errorPath ?? state?.flatten?.errorPath ?? getDefaultErrorPath(fetchNode);
583
- const handleFetchResult = (fetchResult) => {
584
- if (isAsyncIterable(fetchResult)) {
585
- return mapAsyncIterator(fetchResult, handleFetchResult);
586
- }
587
- if (fetchResult.errors?.length) {
588
- const normalizedErrors = normalizeFetchErrors(fetchResult.errors, {
589
- fetchNode,
590
- state,
591
- defaultPath: defaultErrorPath
592
- });
593
- if (normalizedErrors.length) {
594
- executionContext.errors.push(...normalizedErrors);
595
- }
596
- }
597
- const responseData = fetchNode.outputRewrites ? applyOutputRewrites(
598
- fetchResult.data,
599
- fetchNode.outputRewrites,
600
- executionContext.supergraphSchema
601
- ) : fetchResult.data;
602
- if (!responseData) {
603
- return;
604
- }
605
- if (flattenState && flattenState.entityRefs.length) {
606
- const returnedEntities = responseData._entities;
607
- if (Array.isArray(returnedEntities)) {
608
- mergeFlattenEntities(returnedEntities, flattenState);
609
- }
610
- return;
611
- }
612
- if (representationTargets?.length && responseData._entities) {
613
- const returnedEntities = responseData._entities;
614
- for (let index = 0; index < returnedEntities.length; index++) {
615
- const entity = returnedEntities[index];
616
- const target = representationTargets[index];
617
- if (target && entity) {
618
- Object.assign(target, mergeDeep([target, entity], false, true, true));
619
- }
620
- }
621
- return;
622
- }
623
- Object.assign(
624
- executionContext.data,
625
- mergeDeep([executionContext.data, responseData], false, true, true)
626
- );
627
- return;
628
- };
629
- return handleMaybePromise(
791
+ return handleMaybePromiseMaybeAsyncIterable(
630
792
  () => executionContext.onSubgraphExecute(fetchNode.serviceName, {
631
793
  document: getDocumentNodeOfFetchingNode(fetchNode),
632
794
  variables: variablesForFetch,
@@ -639,9 +801,76 @@ function executeFetchPlanNode(fetchNode, executionContext, state) {
639
801
  info: executionContext.executionRequest.info,
640
802
  signal: executionContext.executionRequest.signal
641
803
  }),
642
- handleFetchResult
804
+ (fetchResult) => {
805
+ if (fetchResult.errors?.length) {
806
+ const normalizedErrors = normalizeFetchErrors(fetchResult.errors, {
807
+ fetchNode,
808
+ state,
809
+ defaultPath: defaultErrorPath
810
+ });
811
+ if (normalizedErrors.length) {
812
+ executionContext.errors.push(...normalizedErrors);
813
+ }
814
+ }
815
+ const responseData = fetchNode.outputRewrites ? applyOutputRewrites(
816
+ fetchResult.data,
817
+ fetchNode.outputRewrites,
818
+ executionContext.supergraphSchema
819
+ ) : fetchResult.data;
820
+ if (!responseData) {
821
+ return;
822
+ }
823
+ if (flattenState && flattenState.entityRefs.length) {
824
+ const returnedEntities = responseData._entities;
825
+ if (Array.isArray(returnedEntities)) {
826
+ mergeFlattenEntities(returnedEntities, flattenState);
827
+ }
828
+ return;
829
+ }
830
+ if (representationTargets?.length && responseData._entities) {
831
+ const returnedEntities = responseData._entities;
832
+ for (let index = 0; index < returnedEntities.length; index++) {
833
+ const entity = returnedEntities[index];
834
+ const target = representationTargets[index];
835
+ if (target && entity) {
836
+ Object.assign(
837
+ target,
838
+ mergeDeep([target, entity], false, true, true)
839
+ );
840
+ }
841
+ }
842
+ return;
843
+ }
844
+ Object.assign(
845
+ executionContext.data,
846
+ mergeDeep([executionContext.data, responseData], false, true, true)
847
+ );
848
+ return;
849
+ },
850
+ (error) => handleSubgraphExecutionError(
851
+ error,
852
+ executionContext,
853
+ fetchNode.serviceName,
854
+ defaultErrorPath
855
+ )
643
856
  );
644
857
  }
858
+ function handleSubgraphExecutionError(error, executionContext, serviceName, path) {
859
+ let graphQLError;
860
+ if (error instanceof GraphQLError) {
861
+ graphQLError = error;
862
+ } else {
863
+ graphQLError = createGraphQLError(error.message, {
864
+ originalError: error,
865
+ extensions: {
866
+ code: "DOWNSTREAM_SERVICE_ERROR",
867
+ serviceName
868
+ },
869
+ path
870
+ });
871
+ }
872
+ executionContext.errors.push(graphQLError);
873
+ }
645
874
  function selectFetchVariables(variableValues, variableUsages) {
646
875
  if (!variableValues || !variableUsages || variableUsages.length === 0) {
647
876
  return void 0;
@@ -1331,20 +1560,12 @@ function projectRequires(requiresSelections, entity, supergraphSchema) {
1331
1560
  return result;
1332
1561
  }
1333
1562
 
1334
- const queryPlanForExecutionRequestContext = /* @__PURE__ */ new WeakMap();
1335
- function getLazyFactory(factory) {
1336
- let _value;
1337
- return function(...args) {
1338
- if (!_value) {
1339
- _value = factory();
1340
- }
1341
- return _value(...args);
1342
- };
1343
- }
1344
-
1345
1563
  async function unifiedGraphHandler(opts) {
1346
1564
  const getSubschema = getLazyFactory(
1347
- () => handleFederationSupergraph(opts).getSubschema
1565
+ () => getHandledFederationSupergraph().getSubschema
1566
+ );
1567
+ const getHandledFederationSupergraph = getLazyValue(
1568
+ () => handleFederationSupergraph(opts)
1348
1569
  );
1349
1570
  const moduleName = "@graphql-hive/router-query-planner";
1350
1571
  const { QueryPlanner } = await import(moduleName);
@@ -1438,45 +1659,96 @@ async function unifiedGraphHandler(opts) {
1438
1659
  supergraphSchema,
1439
1660
  executionRequest,
1440
1661
  onSubgraphExecute(subgraphName, executionRequest2) {
1441
- const subschema = getSubschema(subgraphName);
1442
- if (subschema.transforms?.length) {
1443
- const transforms = subschema.transforms;
1444
- const transformationContext = /* @__PURE__ */ Object.create(null);
1445
- for (const transform of transforms) {
1446
- if (transform.transformRequest) {
1447
- executionRequest2 = transform.transformRequest(
1448
- executionRequest2,
1449
- void 0,
1450
- transformationContext
1451
- );
1452
- }
1453
- }
1454
- return handleMaybePromise(
1455
- () => opts.onSubgraphExecute(subgraphName, executionRequest2),
1662
+ function executeSubgraph(executionRequest3) {
1663
+ return handleMaybePromiseMaybeAsyncIterable(
1664
+ () => onSubgraphExecuteWithTransforms(
1665
+ subgraphName,
1666
+ executionRequest3,
1667
+ opts.onSubgraphExecute,
1668
+ getSubschema
1669
+ ),
1456
1670
  (executionResult) => {
1457
- function handleResult(executionResult2) {
1458
- for (const transform of transforms.toReversed()) {
1459
- if (transform.transformResult) {
1460
- executionResult2 = transform.transformResult(
1461
- executionResult2,
1462
- void 0,
1463
- transformationContext
1464
- );
1465
- }
1466
- }
1467
- return executionResult2;
1468
- }
1469
- if (isAsyncIterable(executionResult)) {
1470
- return mapAsyncIterator(
1471
- executionResult,
1472
- (result) => handleResult(result)
1671
+ if (executionRequest3.operationType === "mutation") {
1672
+ handleResultWithPubSubPublish(
1673
+ supergraphSchema,
1674
+ executionRequest3,
1675
+ executionResult
1473
1676
  );
1474
1677
  }
1475
- return handleResult(executionResult);
1678
+ return executionResult;
1476
1679
  }
1477
1680
  );
1478
1681
  }
1479
- return opts.onSubgraphExecute(subgraphName, executionRequest2);
1682
+ const maybeResult = handlePubsubOperationField(
1683
+ supergraphSchema,
1684
+ executionRequest2
1685
+ );
1686
+ if (maybeResult) {
1687
+ const {
1688
+ executionResult,
1689
+ newExecutionRequest,
1690
+ responseKey,
1691
+ returnTypeName
1692
+ } = maybeResult;
1693
+ if (newExecutionRequest) {
1694
+ return mapAsyncIterator$1(
1695
+ executionResult,
1696
+ (executionResult2) => {
1697
+ if (executionResult2.data?.[responseKey] != null) {
1698
+ const representations = asArray(
1699
+ executionResult2.data[responseKey]
1700
+ );
1701
+ if (returnTypeName) {
1702
+ for (const representation of representations) {
1703
+ representation.__typename = returnTypeName;
1704
+ }
1705
+ }
1706
+ return handleMaybePromiseMaybeAsyncIterable(
1707
+ () => executeSubgraph({
1708
+ ...newExecutionRequest,
1709
+ variables: {
1710
+ representations
1711
+ }
1712
+ }),
1713
+ (entitiesResult) => {
1714
+ if (entitiesResult?.data?._entities?.length) {
1715
+ const entities = asArray(
1716
+ entitiesResult.data._entities
1717
+ );
1718
+ for (let i = 0; i < entities.length; i++) {
1719
+ const entity = entities[i];
1720
+ const representation = representations[i];
1721
+ if (entity != null && representation != null) {
1722
+ Object.assign(
1723
+ representation,
1724
+ mergeDeep(
1725
+ [entity, representation],
1726
+ false,
1727
+ true,
1728
+ true
1729
+ )
1730
+ );
1731
+ }
1732
+ }
1733
+ return executionResult2;
1734
+ }
1735
+ if (entitiesResult?.errors?.length) {
1736
+ executionResult2.errors ||= [];
1737
+ executionResult2.errors.push(
1738
+ ...entitiesResult.errors
1739
+ );
1740
+ }
1741
+ return executionResult2;
1742
+ }
1743
+ );
1744
+ }
1745
+ return executionResult2;
1746
+ }
1747
+ );
1748
+ }
1749
+ return executionResult;
1750
+ }
1751
+ return executeSubgraph(executionRequest2);
1480
1752
  },
1481
1753
  queryPlan
1482
1754
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphql-hive/router-runtime",
3
- "version": "1.2.5",
3
+ "version": "1.3.0-alpha-a990d4c23ad5a2cd3bc5526ee8a987fa39a5ca86",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",