@graphql-tools/delegate 9.0.0-alpha-e2ab84c8.0 → 9.0.0-alpha-25204a2f.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.
- package/README.md +0 -2
- package/cjs/Subschema.js +22 -0
- package/cjs/Transformer.js +45 -0
- package/cjs/applySchemaTransforms.js +11 -0
- package/cjs/checkResultAndHandleErrors.js +77 -0
- package/cjs/createRequest.js +125 -0
- package/cjs/defaultMergedResolver.js +29 -0
- package/cjs/delegateToSchema.js +148 -0
- package/cjs/finalizeGatewayRequest.js +317 -0
- package/cjs/getDocumentMetadata.js +25 -0
- package/cjs/index.js +13 -0
- package/cjs/mergeFields.js +87 -0
- package/cjs/package.json +1 -0
- package/cjs/prepareGatewayDocument.js +311 -0
- package/cjs/resolveExternalValue.js +103 -0
- package/cjs/subschemaConfig.js +31 -0
- package/cjs/symbols.js +6 -0
- package/cjs/types.js +3 -0
- package/esm/Subschema.js +17 -0
- package/esm/Transformer.js +41 -0
- package/esm/applySchemaTransforms.js +7 -0
- package/esm/checkResultAndHandleErrors.js +72 -0
- package/esm/createRequest.js +120 -0
- package/esm/defaultMergedResolver.js +25 -0
- package/esm/delegateToSchema.js +143 -0
- package/esm/finalizeGatewayRequest.js +313 -0
- package/esm/getDocumentMetadata.js +21 -0
- package/esm/index.js +10 -0
- package/esm/mergeFields.js +79 -0
- package/esm/prepareGatewayDocument.js +307 -0
- package/esm/resolveExternalValue.js +99 -0
- package/esm/subschemaConfig.js +26 -0
- package/esm/symbols.js +3 -0
- package/esm/types.js +1 -0
- package/package.json +40 -18
- package/{Subschema.d.ts → typings/Subschema.d.ts} +7 -3
- package/{Transformer.d.ts → typings/Transformer.d.ts} +3 -3
- package/{applySchemaTransforms.d.ts → typings/applySchemaTransforms.d.ts} +2 -2
- package/typings/checkResultAndHandleErrors.d.ts +8 -0
- package/{createRequest.d.ts → typings/createRequest.d.ts} +1 -2
- package/{defaultMergedResolver.d.ts → typings/defaultMergedResolver.d.ts} +2 -4
- package/typings/delegateToSchema.d.ts +6 -0
- package/typings/finalizeGatewayRequest.d.ts +3 -0
- package/{getDocumentMetadata.d.ts → typings/getDocumentMetadata.d.ts} +0 -0
- package/typings/index.d.ts +10 -0
- package/typings/mergeFields.d.ts +8 -0
- package/{prepareGatewayDocument.d.ts → typings/prepareGatewayDocument.d.ts} +0 -0
- package/typings/resolveExternalValue.d.ts +3 -0
- package/{subschemaConfig.d.ts → typings/subschemaConfig.d.ts} +1 -1
- package/typings/symbols.d.ts +3 -0
- package/{types.d.ts → typings/types.d.ts} +21 -40
- package/delegateToSchema.d.ts +0 -9
- package/externalObjects.d.ts +0 -11
- package/externalValues.d.ts +0 -4
- package/finalizeGatewayRequest.d.ts +0 -3
- package/getMergedParent.d.ts +0 -9
- package/index.d.ts +0 -11
- package/index.js +0 -1624
- package/index.mjs +0 -1590
- package/mergeDataAndErrors.d.ts +0 -5
- package/symbols.d.ts +0 -7
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.prepareGatewayDocument = void 0;
|
|
4
|
+
const graphql_1 = require("graphql");
|
|
5
|
+
const utils_1 = require("@graphql-tools/utils");
|
|
6
|
+
const getDocumentMetadata_js_1 = require("./getDocumentMetadata.js");
|
|
7
|
+
function prepareGatewayDocument(originalDocument, transformedSchema, returnType, infoSchema) {
|
|
8
|
+
const wrappedConcreteTypesDocument = wrapConcreteTypes(returnType, transformedSchema, originalDocument);
|
|
9
|
+
if (infoSchema == null) {
|
|
10
|
+
return wrappedConcreteTypesDocument;
|
|
11
|
+
}
|
|
12
|
+
const { possibleTypesMap, reversePossibleTypesMap, interfaceExtensionsMap, fieldNodesByType, fieldNodesByField, dynamicSelectionSetsByField, } = getSchemaMetaData(infoSchema, transformedSchema);
|
|
13
|
+
const { operations, fragments, fragmentNames } = (0, getDocumentMetadata_js_1.getDocumentMetadata)(wrappedConcreteTypesDocument);
|
|
14
|
+
const { expandedFragments, fragmentReplacements } = getExpandedFragments(fragments, fragmentNames, possibleTypesMap);
|
|
15
|
+
const typeInfo = new graphql_1.TypeInfo(transformedSchema);
|
|
16
|
+
const expandedDocument = {
|
|
17
|
+
kind: graphql_1.Kind.DOCUMENT,
|
|
18
|
+
definitions: [...operations, ...fragments, ...expandedFragments],
|
|
19
|
+
};
|
|
20
|
+
const visitorKeyMap = {
|
|
21
|
+
Document: ['definitions'],
|
|
22
|
+
OperationDefinition: ['selectionSet'],
|
|
23
|
+
SelectionSet: ['selections'],
|
|
24
|
+
Field: ['selectionSet'],
|
|
25
|
+
InlineFragment: ['selectionSet'],
|
|
26
|
+
FragmentDefinition: ['selectionSet'],
|
|
27
|
+
};
|
|
28
|
+
return (0, graphql_1.visit)(expandedDocument, (0, graphql_1.visitWithTypeInfo)(typeInfo, {
|
|
29
|
+
[graphql_1.Kind.SELECTION_SET]: node => visitSelectionSet(node, fragmentReplacements, transformedSchema, typeInfo, possibleTypesMap, reversePossibleTypesMap, interfaceExtensionsMap, fieldNodesByType, fieldNodesByField, dynamicSelectionSetsByField),
|
|
30
|
+
}),
|
|
31
|
+
// visitorKeys argument usage a la https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-source-graphql/src/batching/merge-queries.js
|
|
32
|
+
// empty keys cannot be removed only because of typescript errors
|
|
33
|
+
// will hopefully be fixed in future version of graphql-js to be optional
|
|
34
|
+
visitorKeyMap);
|
|
35
|
+
}
|
|
36
|
+
exports.prepareGatewayDocument = prepareGatewayDocument;
|
|
37
|
+
function visitSelectionSet(node, fragmentReplacements, schema, typeInfo, possibleTypesMap, reversePossibleTypesMap, interfaceExtensionsMap, fieldNodesByType, fieldNodesByField, dynamicSelectionSetsByField) {
|
|
38
|
+
var _a, _b;
|
|
39
|
+
const newSelections = new Set();
|
|
40
|
+
const maybeType = typeInfo.getParentType();
|
|
41
|
+
if (maybeType != null) {
|
|
42
|
+
const parentType = (0, graphql_1.getNamedType)(maybeType);
|
|
43
|
+
const parentTypeName = parentType.name;
|
|
44
|
+
const fieldNodes = fieldNodesByType[parentTypeName];
|
|
45
|
+
if (fieldNodes) {
|
|
46
|
+
for (const fieldNode of fieldNodes) {
|
|
47
|
+
newSelections.add(fieldNode);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const interfaceExtensions = interfaceExtensionsMap[parentType.name];
|
|
51
|
+
const interfaceExtensionFields = [];
|
|
52
|
+
for (const selection of node.selections) {
|
|
53
|
+
if (selection.kind === graphql_1.Kind.INLINE_FRAGMENT) {
|
|
54
|
+
if (selection.typeCondition != null) {
|
|
55
|
+
const possibleTypes = possibleTypesMap[selection.typeCondition.name.value];
|
|
56
|
+
if (possibleTypes == null) {
|
|
57
|
+
newSelections.add(selection);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
for (const possibleTypeName of possibleTypes) {
|
|
61
|
+
const maybePossibleType = schema.getType(possibleTypeName);
|
|
62
|
+
if (maybePossibleType != null && (0, utils_1.implementsAbstractType)(schema, parentType, maybePossibleType)) {
|
|
63
|
+
newSelections.add(generateInlineFragment(possibleTypeName, selection.selectionSet));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else if (selection.kind === graphql_1.Kind.FRAGMENT_SPREAD) {
|
|
69
|
+
const fragmentName = selection.name.value;
|
|
70
|
+
if (!fragmentReplacements[fragmentName]) {
|
|
71
|
+
newSelections.add(selection);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
for (const replacement of fragmentReplacements[fragmentName]) {
|
|
75
|
+
const typeName = replacement.typeName;
|
|
76
|
+
const maybeReplacementType = schema.getType(typeName);
|
|
77
|
+
if (maybeReplacementType != null && (0, utils_1.implementsAbstractType)(schema, parentType, maybeType)) {
|
|
78
|
+
newSelections.add({
|
|
79
|
+
kind: graphql_1.Kind.FRAGMENT_SPREAD,
|
|
80
|
+
name: {
|
|
81
|
+
kind: graphql_1.Kind.NAME,
|
|
82
|
+
value: replacement.fragmentName,
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
const fieldName = selection.name.value;
|
|
90
|
+
const fieldNodes = (_a = fieldNodesByField[parentTypeName]) === null || _a === void 0 ? void 0 : _a[fieldName];
|
|
91
|
+
if (fieldNodes != null) {
|
|
92
|
+
for (const fieldNode of fieldNodes) {
|
|
93
|
+
newSelections.add(fieldNode);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const dynamicSelectionSets = (_b = dynamicSelectionSetsByField[parentTypeName]) === null || _b === void 0 ? void 0 : _b[fieldName];
|
|
97
|
+
if (dynamicSelectionSets != null) {
|
|
98
|
+
for (const selectionSetFn of dynamicSelectionSets) {
|
|
99
|
+
const selectionSet = selectionSetFn(selection);
|
|
100
|
+
if (selectionSet != null) {
|
|
101
|
+
for (const selection of selectionSet.selections) {
|
|
102
|
+
newSelections.add(selection);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (interfaceExtensions === null || interfaceExtensions === void 0 ? void 0 : interfaceExtensions[fieldName]) {
|
|
108
|
+
interfaceExtensionFields.push(selection);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
newSelections.add(selection);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (reversePossibleTypesMap[parentType.name]) {
|
|
116
|
+
newSelections.add({
|
|
117
|
+
kind: graphql_1.Kind.FIELD,
|
|
118
|
+
name: {
|
|
119
|
+
kind: graphql_1.Kind.NAME,
|
|
120
|
+
value: '__typename',
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
if (interfaceExtensionFields.length) {
|
|
125
|
+
const possibleTypes = possibleTypesMap[parentType.name];
|
|
126
|
+
if (possibleTypes != null) {
|
|
127
|
+
for (const possibleType of possibleTypes) {
|
|
128
|
+
newSelections.add(generateInlineFragment(possibleType, {
|
|
129
|
+
kind: graphql_1.Kind.SELECTION_SET,
|
|
130
|
+
selections: interfaceExtensionFields,
|
|
131
|
+
}));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
...node,
|
|
137
|
+
selections: Array.from(newSelections),
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
return node;
|
|
141
|
+
}
|
|
142
|
+
function generateInlineFragment(typeName, selectionSet) {
|
|
143
|
+
return {
|
|
144
|
+
kind: graphql_1.Kind.INLINE_FRAGMENT,
|
|
145
|
+
typeCondition: {
|
|
146
|
+
kind: graphql_1.Kind.NAMED_TYPE,
|
|
147
|
+
name: {
|
|
148
|
+
kind: graphql_1.Kind.NAME,
|
|
149
|
+
value: typeName,
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
selectionSet,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
const getSchemaMetaData = (0, utils_1.memoize2)((sourceSchema, targetSchema) => {
|
|
156
|
+
var _a, _b, _c, _d;
|
|
157
|
+
const typeMap = sourceSchema.getTypeMap();
|
|
158
|
+
const targetTypeMap = targetSchema.getTypeMap();
|
|
159
|
+
const possibleTypesMap = Object.create(null);
|
|
160
|
+
const interfaceExtensionsMap = Object.create(null);
|
|
161
|
+
for (const typeName in typeMap) {
|
|
162
|
+
const type = typeMap[typeName];
|
|
163
|
+
if ((0, graphql_1.isAbstractType)(type)) {
|
|
164
|
+
const targetType = targetTypeMap[typeName];
|
|
165
|
+
if ((0, graphql_1.isInterfaceType)(type) && (0, graphql_1.isInterfaceType)(targetType)) {
|
|
166
|
+
const targetTypeFields = targetType.getFields();
|
|
167
|
+
const sourceTypeFields = type.getFields();
|
|
168
|
+
const extensionFields = Object.create(null);
|
|
169
|
+
let isExtensionFieldsEmpty = true;
|
|
170
|
+
for (const fieldName in sourceTypeFields) {
|
|
171
|
+
if (!targetTypeFields[fieldName]) {
|
|
172
|
+
extensionFields[fieldName] = true;
|
|
173
|
+
isExtensionFieldsEmpty = false;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (!isExtensionFieldsEmpty) {
|
|
177
|
+
interfaceExtensionsMap[typeName] = extensionFields;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (interfaceExtensionsMap[typeName] || !(0, graphql_1.isAbstractType)(targetType)) {
|
|
181
|
+
const implementations = sourceSchema.getPossibleTypes(type);
|
|
182
|
+
possibleTypesMap[typeName] = [];
|
|
183
|
+
for (const impl of implementations) {
|
|
184
|
+
if (targetTypeMap[impl.name]) {
|
|
185
|
+
possibleTypesMap[typeName].push(impl.name);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
const stitchingInfo = (_a = sourceSchema.extensions) === null || _a === void 0 ? void 0 : _a['stitchingInfo'];
|
|
192
|
+
return {
|
|
193
|
+
possibleTypesMap,
|
|
194
|
+
reversePossibleTypesMap: reversePossibleTypesMap(possibleTypesMap),
|
|
195
|
+
interfaceExtensionsMap,
|
|
196
|
+
fieldNodesByType: (_b = stitchingInfo === null || stitchingInfo === void 0 ? void 0 : stitchingInfo.fieldNodesByType) !== null && _b !== void 0 ? _b : {},
|
|
197
|
+
fieldNodesByField: (_c = stitchingInfo === null || stitchingInfo === void 0 ? void 0 : stitchingInfo.fieldNodesByField) !== null && _c !== void 0 ? _c : {},
|
|
198
|
+
dynamicSelectionSetsByField: (_d = stitchingInfo === null || stitchingInfo === void 0 ? void 0 : stitchingInfo.dynamicSelectionSetsByField) !== null && _d !== void 0 ? _d : {},
|
|
199
|
+
};
|
|
200
|
+
});
|
|
201
|
+
function reversePossibleTypesMap(possibleTypesMap) {
|
|
202
|
+
const result = Object.create(null);
|
|
203
|
+
for (const typeName in possibleTypesMap) {
|
|
204
|
+
const toTypeNames = possibleTypesMap[typeName];
|
|
205
|
+
for (const toTypeName of toTypeNames) {
|
|
206
|
+
if (!result[toTypeName]) {
|
|
207
|
+
result[toTypeName] = [];
|
|
208
|
+
}
|
|
209
|
+
result[toTypeName].push(typeName);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return result;
|
|
213
|
+
}
|
|
214
|
+
function getExpandedFragments(fragments, fragmentNames, possibleTypesMap) {
|
|
215
|
+
let fragmentCounter = 0;
|
|
216
|
+
function generateFragmentName(typeName) {
|
|
217
|
+
let fragmentName;
|
|
218
|
+
do {
|
|
219
|
+
fragmentName = `_${typeName}_Fragment${fragmentCounter.toString()}`;
|
|
220
|
+
fragmentCounter++;
|
|
221
|
+
} while (fragmentNames.has(fragmentName));
|
|
222
|
+
return fragmentName;
|
|
223
|
+
}
|
|
224
|
+
const expandedFragments = [];
|
|
225
|
+
const fragmentReplacements = Object.create(null);
|
|
226
|
+
for (const fragment of fragments) {
|
|
227
|
+
const possibleTypes = possibleTypesMap[fragment.typeCondition.name.value];
|
|
228
|
+
if (possibleTypes != null) {
|
|
229
|
+
const fragmentName = fragment.name.value;
|
|
230
|
+
fragmentReplacements[fragmentName] = [];
|
|
231
|
+
for (const possibleTypeName of possibleTypes) {
|
|
232
|
+
const name = generateFragmentName(possibleTypeName);
|
|
233
|
+
fragmentNames.add(name);
|
|
234
|
+
expandedFragments.push({
|
|
235
|
+
kind: graphql_1.Kind.FRAGMENT_DEFINITION,
|
|
236
|
+
name: {
|
|
237
|
+
kind: graphql_1.Kind.NAME,
|
|
238
|
+
value: name,
|
|
239
|
+
},
|
|
240
|
+
typeCondition: {
|
|
241
|
+
kind: graphql_1.Kind.NAMED_TYPE,
|
|
242
|
+
name: {
|
|
243
|
+
kind: graphql_1.Kind.NAME,
|
|
244
|
+
value: possibleTypeName,
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
selectionSet: fragment.selectionSet,
|
|
248
|
+
});
|
|
249
|
+
fragmentReplacements[fragmentName].push({
|
|
250
|
+
fragmentName: name,
|
|
251
|
+
typeName: possibleTypeName,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return {
|
|
257
|
+
expandedFragments,
|
|
258
|
+
fragmentReplacements,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
function wrapConcreteTypes(returnType, targetSchema, document) {
|
|
262
|
+
const namedType = (0, graphql_1.getNamedType)(returnType);
|
|
263
|
+
if (!(0, graphql_1.isObjectType)(namedType)) {
|
|
264
|
+
return document;
|
|
265
|
+
}
|
|
266
|
+
const rootTypeNames = (0, utils_1.getRootTypeNames)(targetSchema);
|
|
267
|
+
const typeInfo = new graphql_1.TypeInfo(targetSchema);
|
|
268
|
+
const visitorKeys = {
|
|
269
|
+
Document: ['definitions'],
|
|
270
|
+
OperationDefinition: ['selectionSet'],
|
|
271
|
+
SelectionSet: ['selections'],
|
|
272
|
+
InlineFragment: ['selectionSet'],
|
|
273
|
+
FragmentDefinition: ['selectionSet'],
|
|
274
|
+
};
|
|
275
|
+
return (0, graphql_1.visit)(document, (0, graphql_1.visitWithTypeInfo)(typeInfo, {
|
|
276
|
+
[graphql_1.Kind.FRAGMENT_DEFINITION]: (node) => {
|
|
277
|
+
const typeName = node.typeCondition.name.value;
|
|
278
|
+
if (!rootTypeNames.has(typeName)) {
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
[graphql_1.Kind.FIELD]: (node) => {
|
|
283
|
+
const type = typeInfo.getType();
|
|
284
|
+
if (type != null && (0, graphql_1.isAbstractType)((0, graphql_1.getNamedType)(type))) {
|
|
285
|
+
return {
|
|
286
|
+
...node,
|
|
287
|
+
selectionSet: {
|
|
288
|
+
kind: graphql_1.Kind.SELECTION_SET,
|
|
289
|
+
selections: [
|
|
290
|
+
{
|
|
291
|
+
kind: graphql_1.Kind.INLINE_FRAGMENT,
|
|
292
|
+
typeCondition: {
|
|
293
|
+
kind: graphql_1.Kind.NAMED_TYPE,
|
|
294
|
+
name: {
|
|
295
|
+
kind: graphql_1.Kind.NAME,
|
|
296
|
+
value: namedType.name,
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
selectionSet: node.selectionSet,
|
|
300
|
+
},
|
|
301
|
+
],
|
|
302
|
+
},
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
}),
|
|
307
|
+
// visitorKeys argument usage a la https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-source-graphql/src/batching/merge-queries.js
|
|
308
|
+
// empty keys cannot be removed only because of typescript errors
|
|
309
|
+
// will hopefully be fixed in future version of graphql-js to be optional
|
|
310
|
+
visitorKeys);
|
|
311
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveExternalValue = void 0;
|
|
4
|
+
const graphql_1 = require("graphql");
|
|
5
|
+
const utils_1 = require("@graphql-tools/utils");
|
|
6
|
+
const mergeFields_js_1 = require("./mergeFields.js");
|
|
7
|
+
function resolveExternalValue(result, unpathedErrors, subschema, context, info, returnType = getReturnType(info), skipTypeMerging) {
|
|
8
|
+
const type = (0, graphql_1.getNullableType)(returnType);
|
|
9
|
+
if (result instanceof Error) {
|
|
10
|
+
return result;
|
|
11
|
+
}
|
|
12
|
+
if (result == null) {
|
|
13
|
+
return reportUnpathedErrorsViaNull(unpathedErrors);
|
|
14
|
+
}
|
|
15
|
+
if ('parseValue' in type) {
|
|
16
|
+
return type.parseValue(result);
|
|
17
|
+
}
|
|
18
|
+
else if ((0, graphql_1.isCompositeType)(type)) {
|
|
19
|
+
return resolveExternalObject(type, result, unpathedErrors, subschema, context, info, skipTypeMerging);
|
|
20
|
+
}
|
|
21
|
+
else if ((0, graphql_1.isListType)(type)) {
|
|
22
|
+
return resolveExternalList(type, result, unpathedErrors, subschema, context, info, skipTypeMerging);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.resolveExternalValue = resolveExternalValue;
|
|
26
|
+
function resolveExternalObject(type, object, unpathedErrors, subschema, context, info, skipTypeMerging) {
|
|
27
|
+
var _a;
|
|
28
|
+
// if we have already resolved this object, for example, when the identical object appears twice
|
|
29
|
+
// in a list, see https://github.com/ardatan/graphql-tools/issues/2304
|
|
30
|
+
if (!(0, mergeFields_js_1.isExternalObject)(object)) {
|
|
31
|
+
(0, mergeFields_js_1.annotateExternalObject)(object, unpathedErrors, subschema, Object.create(null));
|
|
32
|
+
}
|
|
33
|
+
if (skipTypeMerging || info == null) {
|
|
34
|
+
return object;
|
|
35
|
+
}
|
|
36
|
+
const stitchingInfo = (_a = info.schema.extensions) === null || _a === void 0 ? void 0 : _a['stitchingInfo'];
|
|
37
|
+
if (stitchingInfo == null) {
|
|
38
|
+
return object;
|
|
39
|
+
}
|
|
40
|
+
const typeName = (0, graphql_1.isAbstractType)(type) ? object.__typename : type.name;
|
|
41
|
+
const mergedTypeInfo = stitchingInfo.mergedTypes[typeName];
|
|
42
|
+
let targetSubschemas;
|
|
43
|
+
// Within the stitching context, delegation to a stitched GraphQLSchema or SubschemaConfig
|
|
44
|
+
// will be redirected to the appropriate Subschema object, from which merge targets can be queried.
|
|
45
|
+
if (mergedTypeInfo != null) {
|
|
46
|
+
targetSubschemas = mergedTypeInfo.targetSubschemas.get(subschema);
|
|
47
|
+
}
|
|
48
|
+
// If there are no merge targets from the subschema, return.
|
|
49
|
+
if (!targetSubschemas || !targetSubschemas.length) {
|
|
50
|
+
return object;
|
|
51
|
+
}
|
|
52
|
+
return (0, mergeFields_js_1.mergeFields)(mergedTypeInfo, object, subschema, context, info);
|
|
53
|
+
}
|
|
54
|
+
function resolveExternalList(type, list, unpathedErrors, subschema, context, info, skipTypeMerging) {
|
|
55
|
+
return list.map(listMember => resolveExternalListMember((0, graphql_1.getNullableType)(type.ofType), listMember, unpathedErrors, subschema, context, info, skipTypeMerging));
|
|
56
|
+
}
|
|
57
|
+
function resolveExternalListMember(type, listMember, unpathedErrors, subschema, context, info, skipTypeMerging) {
|
|
58
|
+
if (listMember instanceof Error) {
|
|
59
|
+
return listMember;
|
|
60
|
+
}
|
|
61
|
+
if (listMember == null) {
|
|
62
|
+
return reportUnpathedErrorsViaNull(unpathedErrors);
|
|
63
|
+
}
|
|
64
|
+
if ('parseValue' in type) {
|
|
65
|
+
return type.parseValue(listMember);
|
|
66
|
+
}
|
|
67
|
+
else if ((0, graphql_1.isCompositeType)(type)) {
|
|
68
|
+
return resolveExternalObject(type, listMember, unpathedErrors, subschema, context, info, skipTypeMerging);
|
|
69
|
+
}
|
|
70
|
+
else if ((0, graphql_1.isListType)(type)) {
|
|
71
|
+
return resolveExternalList(type, listMember, unpathedErrors, subschema, context, info, skipTypeMerging);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const reportedErrors = new WeakMap();
|
|
75
|
+
function reportUnpathedErrorsViaNull(unpathedErrors) {
|
|
76
|
+
if (unpathedErrors.length) {
|
|
77
|
+
const unreportedErrors = [];
|
|
78
|
+
for (const error of unpathedErrors) {
|
|
79
|
+
if (!reportedErrors.has(error)) {
|
|
80
|
+
unreportedErrors.push(error);
|
|
81
|
+
reportedErrors.set(error, true);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (unreportedErrors.length) {
|
|
85
|
+
if (unreportedErrors.length === 1) {
|
|
86
|
+
return unreportedErrors[0];
|
|
87
|
+
}
|
|
88
|
+
const combinedError = new utils_1.AggregateError(unreportedErrors, unreportedErrors.map(error => error.message).join(', \n'));
|
|
89
|
+
// We cast path as any for GraphQL.js 14 compat
|
|
90
|
+
// locatedError path argument must be defined, but it is just forwarded to a constructor that allows a undefined value
|
|
91
|
+
// https://github.com/graphql/graphql-js/blob/b4bff0ba9c15c9d7245dd68556e754c41f263289/src/error/locatedError.js#L25
|
|
92
|
+
// https://github.com/graphql/graphql-js/blob/b4bff0ba9c15c9d7245dd68556e754c41f263289/src/error/GraphQLError.js#L19
|
|
93
|
+
return (0, graphql_1.locatedError)(combinedError, undefined, unreportedErrors[0].path);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
function getReturnType(info) {
|
|
99
|
+
if (info == null) {
|
|
100
|
+
throw new Error(`Return type cannot be inferred without a source schema.`);
|
|
101
|
+
}
|
|
102
|
+
return info.returnType;
|
|
103
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cloneSubschemaConfig = exports.isSubschemaConfig = void 0;
|
|
4
|
+
function isSubschemaConfig(value) {
|
|
5
|
+
return Boolean(value === null || value === void 0 ? void 0 : value.schema);
|
|
6
|
+
}
|
|
7
|
+
exports.isSubschemaConfig = isSubschemaConfig;
|
|
8
|
+
function cloneSubschemaConfig(subschemaConfig) {
|
|
9
|
+
var _a, _b;
|
|
10
|
+
const newSubschemaConfig = {
|
|
11
|
+
...subschemaConfig,
|
|
12
|
+
transforms: subschemaConfig.transforms != null ? [...subschemaConfig.transforms] : undefined,
|
|
13
|
+
};
|
|
14
|
+
if (newSubschemaConfig.merge != null) {
|
|
15
|
+
newSubschemaConfig.merge = { ...subschemaConfig.merge };
|
|
16
|
+
for (const typeName in newSubschemaConfig.merge) {
|
|
17
|
+
const mergedTypeConfig = (newSubschemaConfig.merge[typeName] = { ...((_b = (_a = subschemaConfig.merge) === null || _a === void 0 ? void 0 : _a[typeName]) !== null && _b !== void 0 ? _b : {}) });
|
|
18
|
+
if (mergedTypeConfig.entryPoints != null) {
|
|
19
|
+
mergedTypeConfig.entryPoints = mergedTypeConfig.entryPoints.map(entryPoint => ({ ...entryPoint }));
|
|
20
|
+
}
|
|
21
|
+
if (mergedTypeConfig.fields != null) {
|
|
22
|
+
const fields = (mergedTypeConfig.fields = { ...mergedTypeConfig.fields });
|
|
23
|
+
for (const fieldName in fields) {
|
|
24
|
+
fields[fieldName] = { ...fields[fieldName] };
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return newSubschemaConfig;
|
|
30
|
+
}
|
|
31
|
+
exports.cloneSubschemaConfig = cloneSubschemaConfig;
|
package/cjs/symbols.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FIELD_SUBSCHEMA_MAP_SYMBOL = exports.OBJECT_SUBSCHEMA_SYMBOL = exports.UNPATHED_ERRORS_SYMBOL = void 0;
|
|
4
|
+
exports.UNPATHED_ERRORS_SYMBOL = Symbol('subschemaErrors');
|
|
5
|
+
exports.OBJECT_SUBSCHEMA_SYMBOL = Symbol('initialSubschema');
|
|
6
|
+
exports.FIELD_SUBSCHEMA_MAP_SYMBOL = Symbol('subschemaMap');
|
package/cjs/types.js
ADDED
package/esm/Subschema.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { applySchemaTransforms } from './applySchemaTransforms.js';
|
|
2
|
+
export function isSubschema(value) {
|
|
3
|
+
return Boolean(value.transformedSchema);
|
|
4
|
+
}
|
|
5
|
+
export class Subschema {
|
|
6
|
+
constructor(config) {
|
|
7
|
+
var _a;
|
|
8
|
+
this.schema = config.schema;
|
|
9
|
+
this.executor = config.executor;
|
|
10
|
+
this.batch = config.batch;
|
|
11
|
+
this.batchingOptions = config.batchingOptions;
|
|
12
|
+
this.createProxyingResolver = config.createProxyingResolver;
|
|
13
|
+
this.transforms = (_a = config.transforms) !== null && _a !== void 0 ? _a : [];
|
|
14
|
+
this.transformedSchema = applySchemaTransforms(this.schema, config);
|
|
15
|
+
this.merge = config.merge;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { prepareGatewayDocument } from './prepareGatewayDocument.js';
|
|
2
|
+
import { finalizeGatewayRequest } from './finalizeGatewayRequest.js';
|
|
3
|
+
import { checkResultAndHandleErrors } from './checkResultAndHandleErrors.js';
|
|
4
|
+
export class Transformer {
|
|
5
|
+
constructor(context) {
|
|
6
|
+
this.transformations = [];
|
|
7
|
+
this.delegationContext = context;
|
|
8
|
+
const transforms = context.transforms;
|
|
9
|
+
const delegationTransforms = transforms.slice().reverse();
|
|
10
|
+
for (const transform of delegationTransforms) {
|
|
11
|
+
this.addTransform(transform, {});
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
addTransform(transform, context = {}) {
|
|
15
|
+
this.transformations.push({ transform, context });
|
|
16
|
+
}
|
|
17
|
+
transformRequest(originalRequest) {
|
|
18
|
+
var _a;
|
|
19
|
+
let request = {
|
|
20
|
+
...originalRequest,
|
|
21
|
+
document: prepareGatewayDocument(originalRequest.document, this.delegationContext.transformedSchema, this.delegationContext.returnType, (_a = this.delegationContext.info) === null || _a === void 0 ? void 0 : _a.schema),
|
|
22
|
+
};
|
|
23
|
+
for (const transformation of this.transformations) {
|
|
24
|
+
if (transformation.transform.transformRequest) {
|
|
25
|
+
request = transformation.transform.transformRequest(request, this.delegationContext, transformation.context);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return finalizeGatewayRequest(request, this.delegationContext);
|
|
29
|
+
}
|
|
30
|
+
transformResult(originalResult) {
|
|
31
|
+
let result = originalResult;
|
|
32
|
+
// from right to left
|
|
33
|
+
for (let i = this.transformations.length - 1; i >= 0; i--) {
|
|
34
|
+
const transformation = this.transformations[i];
|
|
35
|
+
if (transformation.transform.transformResult) {
|
|
36
|
+
result = transformation.transform.transformResult(result, this.delegationContext, transformation.context);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return checkResultAndHandleErrors(result, this.delegationContext);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export function applySchemaTransforms(originalWrappingSchema, subschemaConfig) {
|
|
2
|
+
const schemaTransforms = subschemaConfig.transforms;
|
|
3
|
+
if (schemaTransforms == null) {
|
|
4
|
+
return originalWrappingSchema;
|
|
5
|
+
}
|
|
6
|
+
return schemaTransforms.reduce((schema, transform) => transform.transformSchema != null ? transform.transformSchema(schema, subschemaConfig) : schema, originalWrappingSchema);
|
|
7
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { responsePathAsArray, locatedError } from 'graphql';
|
|
2
|
+
import { AggregateError, getResponseKeyFromInfo, relocatedError } from '@graphql-tools/utils';
|
|
3
|
+
import { resolveExternalValue } from './resolveExternalValue.js';
|
|
4
|
+
export function checkResultAndHandleErrors(result, delegationContext) {
|
|
5
|
+
const { context, info, fieldName: responseKey = getResponseKey(info), subschema, returnType = getReturnType(info), skipTypeMerging, onLocatedError, } = delegationContext;
|
|
6
|
+
const { data, unpathedErrors } = mergeDataAndErrors(result.data == null ? undefined : result.data[responseKey], result.errors == null ? [] : result.errors, info != null && info.path ? responsePathAsArray(info.path) : undefined, onLocatedError);
|
|
7
|
+
return resolveExternalValue(data, unpathedErrors, subschema, context, info, returnType, skipTypeMerging);
|
|
8
|
+
}
|
|
9
|
+
export function mergeDataAndErrors(data, errors, path, onLocatedError, index = 1) {
|
|
10
|
+
var _a;
|
|
11
|
+
if (data == null) {
|
|
12
|
+
if (!errors.length) {
|
|
13
|
+
return { data: null, unpathedErrors: [] };
|
|
14
|
+
}
|
|
15
|
+
if (errors.length === 1) {
|
|
16
|
+
const error = onLocatedError ? onLocatedError(errors[0]) : errors[0];
|
|
17
|
+
const newPath = path === undefined ? error.path : !error.path ? path : path.concat(error.path.slice(1));
|
|
18
|
+
return { data: relocatedError(errors[0], newPath), unpathedErrors: [] };
|
|
19
|
+
}
|
|
20
|
+
// We cast path as any for GraphQL.js 14 compat
|
|
21
|
+
// locatedError path argument must be defined, but it is just forwarded to a constructor that allows a undefined value
|
|
22
|
+
// https://github.com/graphql/graphql-js/blob/b4bff0ba9c15c9d7245dd68556e754c41f263289/src/error/locatedError.js#L25
|
|
23
|
+
// https://github.com/graphql/graphql-js/blob/b4bff0ba9c15c9d7245dd68556e754c41f263289/src/error/GraphQLError.js#L19
|
|
24
|
+
const combinedError = new AggregateError(errors, errors.map(error => error.message).join(', \n'));
|
|
25
|
+
const newError = locatedError(combinedError, undefined, path);
|
|
26
|
+
return { data: newError, unpathedErrors: [] };
|
|
27
|
+
}
|
|
28
|
+
if (!errors.length) {
|
|
29
|
+
return { data, unpathedErrors: [] };
|
|
30
|
+
}
|
|
31
|
+
const unpathedErrors = [];
|
|
32
|
+
const errorMap = new Map();
|
|
33
|
+
for (const error of errors) {
|
|
34
|
+
const pathSegment = (_a = error.path) === null || _a === void 0 ? void 0 : _a[index];
|
|
35
|
+
if (pathSegment != null) {
|
|
36
|
+
let pathSegmentErrors = errorMap.get(pathSegment);
|
|
37
|
+
if (pathSegmentErrors === undefined) {
|
|
38
|
+
pathSegmentErrors = [error];
|
|
39
|
+
errorMap.set(pathSegment, pathSegmentErrors);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
pathSegmentErrors.push(error);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
unpathedErrors.push(error);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
for (const [pathSegment, pathSegmentErrors] of errorMap) {
|
|
50
|
+
if (data[pathSegment] !== undefined) {
|
|
51
|
+
const { data: newData, unpathedErrors: newErrors } = mergeDataAndErrors(data[pathSegment], pathSegmentErrors, path, onLocatedError, index + 1);
|
|
52
|
+
data[pathSegment] = newData;
|
|
53
|
+
unpathedErrors.push(...newErrors);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
unpathedErrors.push(...pathSegmentErrors);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return { data, unpathedErrors };
|
|
60
|
+
}
|
|
61
|
+
function getResponseKey(info) {
|
|
62
|
+
if (info == null) {
|
|
63
|
+
throw new Error(`Data cannot be extracted from result without an explicit key or source schema.`);
|
|
64
|
+
}
|
|
65
|
+
return getResponseKeyFromInfo(info);
|
|
66
|
+
}
|
|
67
|
+
function getReturnType(info) {
|
|
68
|
+
if (info == null) {
|
|
69
|
+
throw new Error(`Return type cannot be inferred without a source schema.`);
|
|
70
|
+
}
|
|
71
|
+
return info.returnType;
|
|
72
|
+
}
|