@graphql-tools/delegate
Version:
A set of utils for faster development of GraphQL tools
4,924 lines • 165 kB
JavaScript
'use strict';
var utils = require('@graphql-tools/utils');
var graphql = require('graphql');
var promiseHelpers = require('@whatwg-node/promise-helpers');
var executor = require('@graphql-tools/executor');
var batchExecute = require('@graphql-tools/batch-execute');
const applySchemaTransforms = utils.memoize2(function applySchemaTransforms2(originalWrappingSchema, subschemaConfig) {
const schemaTransforms = subschemaConfig.transforms;
if (schemaTransforms == null) {
return originalWrappingSchema;
}
return schemaTransforms.reduce(
(schema, transform) => transform.transformSchema?.(schema, subschemaConfig) || schema,
originalWrappingSchema
);
});
function isSubschema(value) {
return Boolean(value.transformedSchema);
}
class Subschema {
name;
schema;
executor;
batch;
batchingOptions;
defer;
createProxyingResolver;
transforms;
_transformedSchema;
merge;
constructor(config) {
this.name = config.name;
this.schema = config.schema;
this.executor = config.executor;
this.batch = config.batch;
this.batchingOptions = config.batchingOptions;
this.defer = config.defer;
this.createProxyingResolver = config.createProxyingResolver;
this.transforms = config.transforms ?? [];
this.merge = config.merge;
}
get transformedSchema() {
if (!this._transformedSchema) {
if (globalThis.process?.env?.["DEBUG"] != null) {
console.warn(
"Transformed schema is not set yet. Returning a dummy one."
);
}
this._transformedSchema = applySchemaTransforms(this.schema, this);
}
return this._transformedSchema;
}
set transformedSchema(value) {
this._transformedSchema = value;
}
}
function getCoercedVariableValues(variableValues) {
if (variableValues == null) {
return void 0;
}
if (Object.hasOwn(variableValues, "coerced") && Object.hasOwn(variableValues, "sources")) {
return variableValues.coerced;
}
return variableValues;
}
function getVariableValues(variableValues) {
if (variableValues != null && Object.hasOwn(variableValues, "coerced") && Object.hasOwn(variableValues, "sources")) {
return variableValues;
}
return {
coerced: variableValues ?? {},
sources: {}
};
}
const prototypePollutingKeys = [
"__proto__",
"constructor",
"prototype"
];
function isPrototypePollutingKey(key) {
return prototypePollutingKeys.includes(key);
}
const leftOverByDelegationPlan = /* @__PURE__ */ new WeakMap();
const PLAN_LEFT_OVER = Symbol("PLAN_LEFT_OVER");
function getPlanLeftOverFromParent(parent) {
if (parent != null && typeof parent === "object") {
return parent[PLAN_LEFT_OVER];
}
return void 0;
}
const UNPATHED_ERRORS_SYMBOL = Symbol.for("subschemaErrors");
const OBJECT_SUBSCHEMA_SYMBOL = Symbol.for("initialSubschema");
const FIELD_SUBSCHEMA_MAP_SYMBOL = Symbol.for("subschemaMap");
const RECEIVER_SYMBOL = Symbol.for("incrementalReceiver");
function isExternalObject(data) {
return data[UNPATHED_ERRORS_SYMBOL] !== void 0;
}
function annotateExternalObject(object, errors, subschema, subschemaMap) {
Object.defineProperties(object, {
[OBJECT_SUBSCHEMA_SYMBOL]: { value: subschema, writable: true },
[FIELD_SUBSCHEMA_MAP_SYMBOL]: { value: subschemaMap, writable: true },
[UNPATHED_ERRORS_SYMBOL]: { value: errors, writable: true }
});
return object;
}
function getSubschema(object, responseKey) {
return object[FIELD_SUBSCHEMA_MAP_SYMBOL]?.[responseKey] ?? object[OBJECT_SUBSCHEMA_SYMBOL];
}
function getUnpathedErrors(object) {
return object[UNPATHED_ERRORS_SYMBOL];
}
const EMPTY_OBJECT = /* @__PURE__ */ Object.create(null);
const getActualFieldNodes = utils.memoize1(function(fieldNode) {
return [fieldNode];
});
function mergeFields(mergedTypeInfo, object, sourceSubschema, context, info, fieldNodes = info.fieldNodes) {
const variableValues = getCoercedVariableValues(info.variableValues);
const delegationMaps = mergedTypeInfo.delegationPlanBuilder(
info.schema,
sourceSubschema,
variableValues != null && Object.keys(variableValues).length > 0 ? variableValues : EMPTY_OBJECT,
info.fragments != null && Object.keys(info.fragments).length > 0 ? info.fragments : EMPTY_OBJECT,
fieldNodes.length === 1 && fieldNodes[0] ? getActualFieldNodes(fieldNodes[0]) : fieldNodes,
context,
info
);
const leftOver = leftOverByDelegationPlan.get(delegationMaps);
if (leftOver) {
object[PLAN_LEFT_OVER] = leftOver;
}
return promiseHelpers.handleMaybePromise(
() => utils.promiseReduce(
delegationMaps,
(_, delegationMap) => executeDelegationStage(
mergedTypeInfo,
delegationMap,
object,
context,
info
),
void 0
),
() => object
);
}
function handleResolverResult(resolverResult, subschema, selectionSet, object, combinedFieldSubschemaMap, info, path, combinedErrors) {
if (resolverResult instanceof Error || resolverResult == null) {
const schema = subschema.transformedSchema || info.schema;
const type = schema.getType(object.__typename);
const { fields } = utils.collectFields(
schema,
info.fragments,
getVariableValues(info.variableValues),
type,
selectionSet
);
const nullResult = {};
for (const [responseKey, fieldNodes] of fields) {
const combinedPath = [...path, responseKey];
if (resolverResult instanceof graphql.GraphQLError) {
if (resolverResult.message.includes(
"Cannot return null for non-nullable field"
)) {
nullResult[responseKey] = null;
} else {
nullResult[responseKey] = utils.relocatedError(
resolverResult,
combinedPath
);
}
} else if (resolverResult instanceof Error) {
nullResult[responseKey] = graphql.locatedError(
resolverResult,
fieldNodes,
combinedPath
);
} else {
nullResult[responseKey] = null;
}
}
resolverResult = nullResult;
} else {
if (resolverResult[UNPATHED_ERRORS_SYMBOL]) {
combinedErrors.push(...resolverResult[UNPATHED_ERRORS_SYMBOL]);
}
}
const objectSubschema = resolverResult[OBJECT_SUBSCHEMA_SYMBOL];
const fieldSubschemaMap = resolverResult[FIELD_SUBSCHEMA_MAP_SYMBOL];
for (const responseKey in resolverResult) {
if (isPrototypePollutingKey(responseKey)) {
continue;
}
const existingPropValue = object[responseKey];
const sourcePropValue = resolverResult[responseKey];
if (responseKey === "__typename" && existingPropValue !== sourcePropValue && graphql.isAbstractType(subschema.transformedSchema.getType(sourcePropValue))) {
continue;
}
if (sourcePropValue != null || existingPropValue == null) {
if (existingPropValue != null && typeof existingPropValue === "object" && !(existingPropValue instanceof Error) && Object.keys(existingPropValue).length > 0) {
if (Array.isArray(existingPropValue) && Array.isArray(sourcePropValue) && existingPropValue.length === sourcePropValue.length) {
object[responseKey] = existingPropValue.map(
(existingElement, index) => sourcePropValue instanceof Error ? existingElement : utils.mergeDeep(
[existingElement, sourcePropValue[index]],
void 0,
true,
true
)
);
} else if (!(sourcePropValue instanceof Error)) {
object[responseKey] = utils.mergeDeep(
[existingPropValue, sourcePropValue],
void 0,
true,
true
);
}
} else {
object[responseKey] = sourcePropValue;
}
}
combinedFieldSubschemaMap[responseKey] = fieldSubschemaMap?.[responseKey] ?? objectSubschema ?? subschema;
}
}
function executeDelegationStage(mergedTypeInfo, delegationMap, object, context, info) {
const combinedErrors = object[UNPATHED_ERRORS_SYMBOL];
const path = utils.pathToArray(info.path);
const combinedFieldSubschemaMap = object[FIELD_SUBSCHEMA_MAP_SYMBOL];
const jobs = [];
for (const [subschema, selectionSet] of delegationMap) {
const schema = subschema.transformedSchema || info.schema;
const type = schema.getType(object.__typename);
const resolver = mergedTypeInfo.resolvers.get(subschema);
if (resolver) {
try {
const resolverResult$ = resolver(
object,
context,
info,
subschema,
selectionSet,
void 0,
type
);
if (promiseHelpers.isPromise(resolverResult$)) {
jobs.push(
resolverResult$.then(
(resolverResult) => handleResolverResult(
resolverResult,
subschema,
selectionSet,
object,
combinedFieldSubschemaMap,
info,
path,
combinedErrors
),
(error) => handleResolverResult(
error,
subschema,
selectionSet,
object,
combinedFieldSubschemaMap,
info,
path,
combinedErrors
)
)
);
} else {
handleResolverResult(
resolverResult$,
subschema,
selectionSet,
object,
combinedFieldSubschemaMap,
info,
path,
combinedErrors
);
}
} catch (error) {
handleResolverResult(
error,
subschema,
selectionSet,
object,
combinedFieldSubschemaMap,
info,
path,
combinedErrors
);
}
}
}
if (jobs.length) {
if (jobs.length === 1) {
return jobs[0];
}
return Promise.all(jobs);
}
}
const CompactFieldSubschemaMap = function CompactFieldSubschemaMap2() {
};
function resolveExternalValue(result, unpathedErrors, subschema, context, info, returnType = getReturnType$1(info), skipTypeMerging) {
const type = graphql.getNullableType(returnType);
if (result instanceof Error) {
return result;
}
if (result == null) {
return reportUnpathedErrorsViaNull(unpathedErrors);
}
if (graphql.isLeafType(type)) {
try {
return type.parseValue(result);
} catch {
return null;
}
} else if (graphql.isCompositeType(type)) {
const resolved = resolveExternalObject(
type,
result,
unpathedErrors,
subschema,
context,
info,
skipTypeMerging
);
if (!promiseHelpers.isPromise(resolved)) {
return validateCompositeResult(resolved, type, info);
}
return promiseHelpers.handleMaybePromise(
() => resolved,
(value) => validateCompositeResult(value, type, info)
);
} else if (graphql.isListType(type)) {
if (Array.isArray(result)) {
return resolveExternalList(
type,
result,
unpathedErrors,
subschema,
context,
info,
skipTypeMerging
);
}
return resolveExternalValue(
result,
unpathedErrors,
subschema,
context,
info,
type.ofType,
skipTypeMerging
);
}
}
function validateCompositeResult(value, type, info) {
if (info && graphql.isAbstractType(type)) {
if (value.__typename != null) {
const resolvedType = info.schema.getType(value.__typename);
if (!resolvedType) return null;
}
return value;
}
return value;
}
function resolveExternalObject(type, object, unpathedErrors, subschema, context, info, skipTypeMerging) {
if (!isExternalObject(object)) {
annotateExternalObject(
object,
unpathedErrors,
subschema,
Object.setPrototypeOf(new CompactFieldSubschemaMap(), null)
);
}
if (skipTypeMerging || info == null) {
return object;
}
const stitchingInfo = info.schema.extensions?.["stitchingInfo"];
if (stitchingInfo == null) {
return object;
}
let mergedTypeInfo;
const possibleTypeNames = [object.__typename, type.name];
for (const possibleTypeName of possibleTypeNames) {
if (possibleTypeName != null && stitchingInfo.mergedTypes[possibleTypeName]?.targetSubschemas?.get(
subschema
)?.length) {
mergedTypeInfo = stitchingInfo.mergedTypes[possibleTypeName];
break;
}
}
if (!mergedTypeInfo) {
for (const possibleTypeName of possibleTypeNames) {
const potentialMergedTypeInfo = stitchingInfo.mergedTypes[possibleTypeName];
if (potentialMergedTypeInfo != null) {
for (const [
sourceSubschema,
targetSubschemas
] of potentialMergedTypeInfo.targetSubschemas) {
if (targetSubschemas.length && sourceSubschema.name != null && sourceSubschema.name === subschema.name) {
subschema = sourceSubschema;
mergedTypeInfo = potentialMergedTypeInfo;
}
}
break;
}
}
}
if (!mergedTypeInfo) {
return object;
}
return mergeFields(
mergedTypeInfo,
object,
subschema,
context,
info
);
}
function resolveExternalList(type, list, unpathedErrors, subschema, context, info, skipTypeMerging) {
return list.map(
(listMember) => resolveExternalValue(
listMember,
unpathedErrors,
subschema,
context,
info,
type.ofType,
skipTypeMerging
)
);
}
const reportedErrors = /* @__PURE__ */ new WeakSet();
function reportUnpathedErrorsViaNull(unpathedErrors) {
if (unpathedErrors.length) {
const unreportedErrors = [];
for (const error of unpathedErrors) {
if (!reportedErrors.has(error)) {
unreportedErrors.push(error);
reportedErrors.add(error);
}
}
if (unreportedErrors.length) {
const unreportedError = unreportedErrors[0];
if (unreportedErrors.length === 1 && unreportedError) {
return graphql.locatedError(
unreportedError,
void 0,
unreportedError.path
);
}
return new AggregateError(
unreportedErrors.map(
(e) => (
// We cast path as any for GraphQL.js 14 compat
// locatedError path argument must be defined, but it is just forwarded to a constructor that allows a undefined value
// https://github.com/graphql/graphql-js/blob/b4bff0ba9c15c9d7245dd68556e754c41f263289/src/error/locatedError.js#L25
// https://github.com/graphql/graphql-js/blob/b4bff0ba9c15c9d7245dd68556e754c41f263289/src/error/GraphQLError.js#L19
graphql.locatedError(e, void 0, unreportedError?.path)
)
),
unreportedErrors.map((error) => error.message).join(", \n")
);
}
}
return null;
}
function getReturnType$1(info) {
if (info == null) {
throw new Error(`Return type cannot be inferred without a source schema.`);
}
return info.returnType;
}
function checkResultAndHandleErrors(result = {
data: null,
errors: []
}, delegationContext) {
const {
context,
info,
fieldName: responseKey = getResponseKey(info),
subschema,
returnType = getReturnType(info),
skipTypeMerging,
onLocatedError
} = delegationContext;
const { data, unpathedErrors } = mergeDataAndErrors(
result.data == null ? void 0 : result.data[responseKey],
result.errors == null ? [] : result.errors,
info != null && info.path ? graphql.responsePathAsArray(info.path) : void 0,
onLocatedError
);
return resolveExternalValue(
data,
unpathedErrors,
subschema,
context,
info,
returnType,
skipTypeMerging
);
}
function mergeDataAndErrors(data, errors, path, onLocatedError, index = 1) {
if (data == null) {
if (!errors.length) {
return { data: null, unpathedErrors: [] };
}
if (errors.length === 1 && errors[0]) {
const error = onLocatedError ? onLocatedError(errors[0]) : errors[0];
const newPath = path === void 0 ? error.path : !error.path ? path : path.concat(error.path.slice(1));
return { data: utils.relocatedError(errors[0], newPath), unpathedErrors: [] };
}
const combinedError = new AggregateError(
errors.map((e) => {
const error = onLocatedError ? onLocatedError(e) : e;
const newPath = path === void 0 ? error.path : !error.path ? path : path.concat(error.path.slice(1));
return utils.relocatedError(error, newPath);
}),
errors.map((error) => error.message).join(",\n")
);
return { data: combinedError, unpathedErrors: [] };
}
if (!errors.length) {
return { data, unpathedErrors: [] };
}
const unpathedErrors = [];
const errorMap = /* @__PURE__ */ new Map();
for (const error of errors) {
const pathSegment = error.path?.[index];
if (pathSegment != null) {
let pathSegmentErrors = errorMap.get(pathSegment);
if (pathSegmentErrors === void 0) {
pathSegmentErrors = [error];
errorMap.set(pathSegment, pathSegmentErrors);
} else {
pathSegmentErrors.push(error);
}
} else {
unpathedErrors.push(error);
}
}
for (const [pathSegment, pathSegmentErrors] of errorMap) {
if (data[pathSegment] !== void 0) {
const { data: newData, unpathedErrors: newErrors } = mergeDataAndErrors(
data[pathSegment],
pathSegmentErrors,
path,
onLocatedError,
index + 1
);
data[pathSegment] = newData;
unpathedErrors.push(...newErrors);
} else {
unpathedErrors.push(...pathSegmentErrors);
}
}
return { data, unpathedErrors };
}
function getResponseKey(info) {
if (info == null) {
throw new Error(
`Data cannot be extracted from result without an explicit key or source schema.`
);
}
return info.fieldNodes[0].alias?.value ?? info.fieldName;
}
function getReturnType(info) {
if (info == null) {
throw new Error(`Return type cannot be inferred without a source schema.`);
}
return info.returnType;
}
function getDocumentMetadata(document) {
const operations = [];
const fragments = [];
const fragmentNames = /* @__PURE__ */ new Set();
for (let i = 0; i < document.definitions.length; i++) {
const def = document.definitions[i];
if (def?.kind === graphql.Kind.FRAGMENT_DEFINITION) {
fragments.push(def);
fragmentNames.add(def.name.value);
} else if (def?.kind === graphql.Kind.OPERATION_DEFINITION) {
operations.push(def);
}
}
return {
operations,
fragments,
fragmentNames
};
}
const getTypeInfo = utils.memoize1(function getTypeInfo2(schema) {
return new graphql.TypeInfo(schema);
});
const getTypeInfoWithType = utils.memoize2(function getTypeInfoWithType2(schema, type) {
return graphql.versionInfo.major < 16 ? new graphql.TypeInfo(schema, void 0, type) : new graphql.TypeInfo(schema, type);
});
const handleOverrideByDelegation = utils.memoize3(
function handleOverrideByDelegation2(info, context, overrideHandler) {
return overrideHandler(context, info);
}
);
function finalizeGatewayDocument(targetSchema, originalDocument, fragments, operations, onOverlappingAliases, delegationContext) {
let usedVariables = [];
let usedFragments = [];
const newOperations = [];
let newFragments = [];
const validFragments = [];
const validFragmentsWithType = /* @__PURE__ */ Object.create(null);
for (const fragment of fragments) {
if (fragment.selectionSet.selections.length === 0) {
continue;
}
const typeName = fragment.typeCondition.name.value;
const type = targetSchema.getType(typeName);
if (type != null) {
validFragments.push(fragment);
validFragmentsWithType[fragment.name.value] = type;
}
}
let fragmentSet = /* @__PURE__ */ Object.create(null);
let selectionCnt = 0;
for (const operation of operations) {
const type = utils.getDefinedRootType(targetSchema, operation.operation);
const {
selectionSet,
usedFragments: operationUsedFragments,
usedVariables: operationUsedVariables
} = finalizeSelectionSet(
targetSchema,
type,
validFragmentsWithType,
operation.selectionSet,
onOverlappingAliases,
delegationContext,
validFragments
);
usedFragments = union(usedFragments, operationUsedFragments);
const {
usedVariables: collectedUsedVariables,
newFragments: collectedNewFragments,
fragmentSet: collectedFragmentSet
} = collectFragmentVariables(
targetSchema,
fragmentSet,
validFragments,
validFragmentsWithType,
usedFragments,
onOverlappingAliases,
delegationContext
);
const operationOrFragmentVariables = union(
operationUsedVariables,
collectedUsedVariables
);
usedVariables = union(usedVariables, operationOrFragmentVariables);
newFragments = collectedNewFragments;
fragmentSet = collectedFragmentSet;
const variableDefinitions = [];
for (const variableName of operationOrFragmentVariables) {
const variableDef = operation.variableDefinitions?.find(
(varDef) => varDef.variable.name.value === variableName
);
if (variableDef != null) {
variableDefinitions.push(variableDef);
}
}
if (operation.operation === "subscription") {
selectionSet.selections = selectionSet.selections.filter(
(selection) => selection.kind !== graphql.Kind.FIELD || selection.name.value !== "__typename"
);
}
if (selectionSet.selections.length === 1 && selectionSet.selections[0] && selectionSet.selections[0].kind === graphql.Kind.FIELD && selectionSet.selections[0].name.value === "__typename") {
continue;
}
selectionCnt += selectionSet.selections.length;
newOperations.push({
kind: graphql.Kind.OPERATION_DEFINITION,
operation: operation.operation,
name: operation.name,
directives: operation.directives,
variableDefinitions,
selectionSet
});
}
if (!newOperations.length || selectionCnt === 0) {
throw utils.createGraphQLError(
"Failed to create a gateway request. The request must contain at least one operation.",
{
extensions: {
[executor.CRITICAL_ERROR]: true
}
}
);
}
const includedFragmentNames = new Set(newFragments.map((f) => f.name.value));
const hasDroppedFragments = includedFragmentNames.size < usedFragments.length;
let newDocument = {
kind: graphql.Kind.DOCUMENT,
definitions: [...newOperations, ...newFragments]
};
const stitchingInfo = delegationContext.info?.schema?.extensions?.["stitchingInfo"];
if (stitchingInfo != null && subschemaHasProvidedSelections(
stitchingInfo,
delegationContext.subschema
)) {
const {
selectionSetsByPath: originalFieldSelectionSetsByPath,
fragments: originalFragmentsByName
} = collectFieldSelectionSetsByPath(originalDocument);
const typeInfo = getTypeInfo(targetSchema);
const pathStack = [];
const inlineFragmentCounterStack = [];
newDocument = graphql.visit(
newDocument,
graphql.visitWithTypeInfo(typeInfo, {
[graphql.Kind.SELECTION_SET]: {
enter() {
inlineFragmentCounterStack.push(/* @__PURE__ */ new Map());
},
leave() {
inlineFragmentCounterStack.pop();
}
},
[graphql.Kind.OPERATION_DEFINITION]: {
enter(node) {
pathStack.push(`op:${node.operation}:${node.name?.value ?? ""}`);
},
leave() {
pathStack.pop();
}
},
[graphql.Kind.FRAGMENT_DEFINITION]: {
enter(node) {
pathStack.push(`frag:${node.name.value}`);
},
leave() {
pathStack.pop();
}
},
[graphql.Kind.INLINE_FRAGMENT]: {
enter(node) {
pathStack.push(
nextInlineFragmentPathSegment(
node,
inlineFragmentCounterStack[inlineFragmentCounterStack.length - 1]
)
);
},
leave() {
pathStack.pop();
}
},
[graphql.Kind.FIELD]: {
enter(fieldNode) {
pathStack.push(fieldNode.alias?.value ?? fieldNode.name.value);
},
leave(fieldNode) {
try {
const parentType = typeInfo.getParentType();
if (!parentType) {
return void 0;
}
const typeConfig = stitchingInfo?.mergedTypes?.[parentType.name];
const providedSelectionsByField = typeConfig?.providedSelectionsByField?.get(
delegationContext.subschema
);
const providedSelection = providedSelectionsByField?.[fieldNode.name.value];
if (!providedSelection) {
return void 0;
}
const originalSelectionSet = lookupOriginalSelectionSet(
pathStack,
fieldNode,
originalFieldSelectionSetsByPath
);
const requestedProvidedSelections = intersectProvidedSelections(
providedSelection.selections,
originalSelectionSet,
originalFragmentsByName
);
if (!requestedProvidedSelections.length) {
return void 0;
}
return {
...fieldNode,
selectionSet: {
kind: graphql.Kind.SELECTION_SET,
selections: [
...requestedProvidedSelections,
...fieldNode.selectionSet?.selections ?? []
]
}
};
} finally {
pathStack.pop();
}
}
}
})
);
}
if (hasDroppedFragments) {
const ops = newDocument.definitions.filter(
(d) => d.kind === graphql.Kind.OPERATION_DEFINITION
);
const frags = newDocument.definitions.filter(
(d) => d.kind === graphql.Kind.FRAGMENT_DEFINITION
);
newDocument = {
kind: graphql.Kind.DOCUMENT,
definitions: [
...removeDeadFragmentSpreads(ops, includedFragmentNames),
...frags
]
};
}
return {
usedVariables,
newDocument
};
}
function finalizeGatewayRequest(originalRequest, delegationContext, onOverlappingAliases) {
let { operations, fragments } = getDocumentMetadata(originalRequest.document);
const { targetSchema } = delegationContext;
const { usedVariables, newDocument } = finalizeGatewayDocument(
targetSchema,
originalRequest.document,
fragments,
operations,
onOverlappingAliases,
delegationContext
);
const newVariables = {};
const outerVariables = getCoercedVariableValues(
delegationContext.info?.variableValues
);
for (const varName of usedVariables) {
const existingVar = originalRequest.variables?.[varName];
const outerVar = outerVariables?.[varName];
if (existingVar != null) {
newVariables[varName] = existingVar;
} else if (outerVar != null) {
newVariables[varName] = outerVar;
}
if (existingVar === null || outerVar === null) {
newVariables[varName] = null;
}
}
return {
...originalRequest,
document: newDocument,
variables: newVariables
};
}
function removeDeadFragmentSpreads(operations, included) {
function cleanSelections(selections) {
const out = [];
for (const sel of selections) {
if (sel.kind === graphql.Kind.FRAGMENT_SPREAD) {
if (included.has(sel.name.value)) {
out.push(sel);
}
} else if ((sel.kind === graphql.Kind.FIELD || sel.kind === graphql.Kind.INLINE_FRAGMENT) && sel.selectionSet) {
const cleaned = cleanSelections(sel.selectionSet.selections);
if (cleaned.length === 0 && sel.kind === graphql.Kind.INLINE_FRAGMENT) {
continue;
}
if (cleaned.length === 0 && sel.kind === graphql.Kind.FIELD) {
continue;
}
out.push(
cleaned === sel.selectionSet.selections ? sel : {
...sel,
selectionSet: {
kind: graphql.Kind.SELECTION_SET,
selections: cleaned
}
}
);
} else {
out.push(sel);
}
}
return out;
}
return operations.map((op) => ({
...op,
selectionSet: {
...op.selectionSet,
selections: cleanSelections(op.selectionSet.selections)
}
}));
}
function isTypeNameField(selection) {
return selection.kind === graphql.Kind.FIELD && !selection.alias && selection.name.value === "__typename";
}
function collectFieldSelectionSetsByPathImpl(document) {
const selectionSetsByPath = /* @__PURE__ */ new Map();
const fragments = /* @__PURE__ */ new Map();
for (const def of document.definitions) {
if (def.kind === graphql.Kind.FRAGMENT_DEFINITION) {
fragments.set(def.name.value, def);
}
}
const pathStack = [];
const inlineFragmentCounterStack = [];
graphql.visit(document, {
[graphql.Kind.SELECTION_SET]: {
enter() {
inlineFragmentCounterStack.push(/* @__PURE__ */ new Map());
},
leave() {
inlineFragmentCounterStack.pop();
}
},
[graphql.Kind.OPERATION_DEFINITION]: {
enter(node) {
pathStack.push(`op:${node.operation}:${node.name?.value ?? ""}`);
},
leave() {
pathStack.pop();
}
},
[graphql.Kind.FRAGMENT_DEFINITION]: {
enter(node) {
pathStack.push(`frag:${node.name.value}`);
},
leave() {
pathStack.pop();
}
},
[graphql.Kind.INLINE_FRAGMENT]: {
enter(node) {
pathStack.push(
nextInlineFragmentPathSegment(
node,
inlineFragmentCounterStack[inlineFragmentCounterStack.length - 1]
)
);
},
leave() {
pathStack.pop();
}
},
[graphql.Kind.FIELD]: {
enter(node) {
pathStack.push(node.alias?.value ?? node.name.value);
if (node.selectionSet) {
selectionSetsByPath.set(pathStack.join(">"), node.selectionSet);
if (node.alias) {
const namePath = [...pathStack.slice(0, -1), node.name.value].join(
">"
);
if (!selectionSetsByPath.has(namePath)) {
selectionSetsByPath.set(namePath, node.selectionSet);
}
}
}
},
leave() {
pathStack.pop();
}
}
});
return { selectionSetsByPath, fragments };
}
const collectFieldSelectionSetsByPath = utils.memoize1(
collectFieldSelectionSetsByPathImpl
);
function nextInlineFragmentPathSegment(node, counter) {
const typeName = node.typeCondition?.name.value ?? "";
if (!counter) {
return `inline:${typeName}:0`;
}
const idx = counter.get(typeName) ?? 0;
counter.set(typeName, idx + 1);
return `inline:${typeName}:${idx}`;
}
function subschemaHasProvidedSelectionsImpl(stitchingInfo, subschema) {
const mergedTypes = stitchingInfo.mergedTypes;
if (!mergedTypes) {
return false;
}
for (const typeConfig of Object.values(mergedTypes)) {
if (typeConfig?.providedSelectionsByField?.has(subschema)) {
return true;
}
}
return false;
}
const subschemaHasProvidedSelections = utils.memoize2(
subschemaHasProvidedSelectionsImpl
);
function lookupOriginalSelectionSet(pathStack, fieldNode, selectionSetsByPath) {
const exact = selectionSetsByPath.get(pathStack.join(">"));
if (exact || !fieldNode.alias) {
return exact;
}
const fallback = [...pathStack.slice(0, -1), fieldNode.name.value].join(">");
return selectionSetsByPath.get(fallback);
}
function intersectProvidedSelections(providedSelections, originalSelectionSet, fragments) {
if (!originalSelectionSet) {
return [];
}
const providedFieldsByName = /* @__PURE__ */ new Map();
const otherProvided = [];
for (const provided of providedSelections) {
if (provided.kind === graphql.Kind.FIELD) {
providedFieldsByName.set(provided.name.value, provided);
} else {
otherProvided.push(provided);
}
}
const result = [];
collectMatchingOriginalSelections(
originalSelectionSet,
providedFieldsByName,
fragments,
/* @__PURE__ */ new Set(),
/* @__PURE__ */ new Set(),
result
);
return [...result, ...otherProvided];
}
function collectMatchingOriginalSelections(selectionSet, providedFieldsByName, fragments, seenFieldNames, seenFragmentNames, result) {
for (const sel of selectionSet.selections) {
if (sel.kind === graphql.Kind.FIELD) {
const provided = providedFieldsByName.get(sel.name.value);
if (!provided) {
continue;
}
const dedupKey = sel.alias?.value ?? sel.name.value;
if (seenFieldNames.has(dedupKey)) {
continue;
}
seenFieldNames.add(dedupKey);
if (provided.selectionSet && sel.selectionSet) {
const nested = intersectProvidedSelections(
provided.selectionSet.selections,
sel.selectionSet,
fragments
);
if (!nested.length) {
continue;
}
result.push({
...sel,
selectionSet: {
kind: graphql.Kind.SELECTION_SET,
selections: nested
}
});
} else {
result.push(sel);
}
} else if (sel.kind === graphql.Kind.INLINE_FRAGMENT && sel.selectionSet) {
const hasDirectives = (sel.directives?.length ?? 0) > 0;
const hasTypeCondition = sel.typeCondition != null;
if (hasDirectives || hasTypeCondition) {
const inner = [];
collectMatchingOriginalSelections(
sel.selectionSet,
providedFieldsByName,
fragments,
/* @__PURE__ */ new Set(),
/* @__PURE__ */ new Set(),
inner
);
if (inner.length === 0) {
continue;
}
result.push({
kind: graphql.Kind.INLINE_FRAGMENT,
typeCondition: sel.typeCondition,
directives: sel.directives,
selectionSet: {
kind: graphql.Kind.SELECTION_SET,
selections: inner
}
});
} else {
collectMatchingOriginalSelections(
sel.selectionSet,
providedFieldsByName,
fragments,
seenFieldNames,
seenFragmentNames,
result
);
}
} else if (sel.kind === graphql.Kind.FRAGMENT_SPREAD) {
const fragmentDef = fragments.get(sel.name.value);
if (!fragmentDef) {
continue;
}
const hasSpreadDirectives = (sel.directives?.length ?? 0) > 0;
const hasFragmentDirectives = (fragmentDef.directives?.length ?? 0) > 0;
if (hasSpreadDirectives || hasFragmentDirectives) {
const inner = [];
collectMatchingOriginalSelections(
fragmentDef.selectionSet,
providedFieldsByName,
fragments,
/* @__PURE__ */ new Set(),
/* @__PURE__ */ new Set(),
inner
);
if (inner.length === 0) {
continue;
}
const combinedDirectives = [
...sel.directives ?? [],
...fragmentDef.directives ?? []
];
result.push({
kind: graphql.Kind.INLINE_FRAGMENT,
typeCondition: fragmentDef.typeCondition,
directives: combinedDirectives.length > 0 ? combinedDirectives : void 0,
selectionSet: {
kind: graphql.Kind.SELECTION_SET,
selections: inner
}
});
} else {
if (seenFragmentNames.has(sel.name.value)) {
continue;
}
seenFragmentNames.add(sel.name.value);
collectMatchingOriginalSelections(
fragmentDef.selectionSet,
providedFieldsByName,
fragments,
seenFieldNames,
seenFragmentNames,
result
);
}
}
}
}
function filterTypenameFields(selections) {
let hasTypeNameField = false;
const filteredSelections = selections.filter((selection) => {
if (isTypeNameField(selection)) {
hasTypeNameField = true;
return false;
}
return true;
});
return {
hasTypeNameField,
selections: filteredSelections
};
}
function collectFragmentVariables(targetSchema, fragmentSet, validFragments, validFragmentsWithType, usedFragments, onOverlappingAliases, delegationContext) {
let remainingFragments = usedFragments.slice();
let usedVariables = [];
const newFragments = [];
while (remainingFragments.length !== 0) {
const nextFragmentName = remainingFragments.pop();
const fragment = validFragments.find(
(fr) => fr.name.value === nextFragmentName
);
if (fragment != null) {
const name = nextFragmentName;
const typeName = fragment.typeCondition.name.value;
const type = targetSchema.getType(typeName);
if (type == null) {
throw new Error(
`Fragment reference type "${typeName}", but the type is not contained within the target schema.`
);
}
const {
selectionSet,
usedFragments: fragmentUsedFragments,
usedVariables: fragmentUsedVariables
} = finalizeSelectionSet(
targetSchema,
type,
validFragmentsWithType,
fragment.selectionSet,
onOverlappingAliases,
delegationContext,
validFragments
);
remainingFragments = union(remainingFragments, fragmentUsedFragments);
usedVariables = union(usedVariables, fragmentUsedVariables);
if (name && !(name in fragmentSet)) {
fragmentSet[name] = true;
if (selectionSet.selections.length > 0) {
newFragments.push({
kind: graphql.Kind.FRAGMENT_DEFINITION,
name: {
kind: graphql.Kind.NAME,
value: name
},
typeCondition: fragment.typeCondition,
selectionSet
});
}
}
}
}
return {
usedVariables,
newFragments,
fragmentSet
};
}
const filteredSelectionSetVisitorKeys = {
SelectionSet: ["selections"],
Field: ["selectionSet"],
InlineFragment: ["selectionSet"],
FragmentDefinition: ["selectionSet"]
};
const variablesVisitorKeys = {
SelectionSet: ["selections"],
Field: ["arguments", "directives", "selectionSet"],
Argument: ["value"],
InlineFragment: ["directives", "selectionSet"],
FragmentSpread: ["directives"],
FragmentDefinition: ["selectionSet"],
ObjectValue: ["fields"],
ObjectField: ["name", "value"],
Directive: ["arguments"],
ListValue: ["values"]
};
function finalizeSelectionSet(schema, type, validFragments, selectionSet, onOverlappingAliases, delegationContext, fragmentDefinitions) {
const usedFragments = [];
const usedVariables = [];
const typeInfo = getTypeInfoWithType(schema, type);
const seenNonNullableMap = /* @__PURE__ */ new WeakMap();
const seenNullableMap = /* @__PURE__ */ new WeakMap();
const filteredSelectionSet = filterSelectionSet(
schema,
typeInfo,
validFragments,
selectionSet,
onOverlappingAliases,
usedFragments,
seenNonNullableMap,
seenNullableMap,
delegationContext,
fragmentDefinitions
);
graphql.visit(
filteredSelectionSet,
{
[graphql.Kind.VARIABLE]: (variableNode) => {
usedVariables.push(variableNode.name.value);
}
},
// visitorKeys argument usage a la https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-source-graphql/src/batching/merge-queries.js
// empty keys cannot be removed only because of typescript errors
// will hopefully be fixed in future version of graphql-js to be optional
variablesVisitorKeys
);
return {
selectionSet: filteredSelectionSet,
usedFragments,
usedVariables
};
}
function filterSelectionSet(schema, typeInfo, validFragments, selectionSet, onOverlappingAliases, usedFragments, seenNonNullableMap, seenNullableMap, delegationContext, fragmentDefinitions) {
const deferredDependencyStack = [];
const forwardDefer = shouldForwardDefer(delegationContext);
const fragmentDefsByName = /* @__PURE__ */ Object.create(null);
if (fragmentDefinitions) {
for (const frag of fragmentDefinitions) {
fragmentDefsByName[frag.name.value] = frag;
}
}
return graphql.visit(
selectionSet,
graphql.visitWithTypeInfo(typeInfo, {
[graphql.Kind.FIELD]: {
enter: (node) => {
const parentType = typeInfo.getParentType();
const field = typeInfo.getFieldDef();
if (delegationContext.context != null && delegationContext.info != null && parentType != null && field != null) {
const parentTypeName = parentType.name;
const overrideHandler = delegationContext.subschemaConfig?.merge?.[parentTypeName]?.fields?.[field.name]?.override;
if (overrideHandler != null) {
const overridden = handleOverrideByDelegation(
delegationContext.info,
delegationContext.context,
overrideHandler
);
if (!overridden) {
return null;
}
}
}
if (graphql.isObjectType(parentType) || graphql.isInterfaceType(parentType)) {
if (!field) {
return null;
}
const args = field.args != null ? field.args : [];
const argsMap = /* @__PURE__ */ Object.create(null);
for (const arg of args) {
argsMap[arg.name] = arg;
}
if (node.arguments != null) {
const newArgs = [];
for (const arg of node.arguments) {
if (arg.name.value in argsMap) {
newArgs.push(arg);
}
}
if (newArgs.length !== node.arguments.length) {
return {
...node,
arguments: newArgs
};
}
}
}
if (graphql.isUnionType(parentType) && typeInfo.getType() == null) {
const possibleTypeNames = [];
const fieldName = node.name.value;
for (const memberType of parentType.getTypes()) {
const memberFields = memberType.getFields();
const possibleField = memberFields[fieldName];
if (possibleField != null) {
const namedType = graphql.getNamedType(possibleField.type);
if (node.selectionSet?.selections?.length && graphql.isLeafType(namedType)) {
continue;
}
if (!node.selectionSet?.selections?.length && graphql.isCompositeType(namedType)) {
continue;
}
possibleTypeNames.push(memberType.name);
}
}
if (possibleTypeNames.length > 0) {
const spreads = possibleTypeNames.map((possibleTypeName) => {
if (!node.selectionSet?.selections) {
return {
kind: graphql.Kind.INLINE_FRAGMENT,
typeCondition: {
kind: graphql.Kind.NAMED_TYPE,
name: {
kind: graphql.Kind.NAME,
value: possibleTypeName
}
},
selectionSet: {
kind: graphql.Kind.SELECTION_SET,
selections: [node]
}
};
}
const possibleType = schema.getType(
possibleTypeName
);
const possibleField = possibleType.getFields()[node.name.value];
if (!possibleField) {
return void 0;
}
const fieldFilteredSelectionSet = filterSelectionSet(
schema,
getTypeInfoWithType(schema, possibleField.type),
validFragments,
node.selectionSet,
onOverlappingAliases,
usedFragments,
seenNonNullableMap,
seenNullableMap,
delegationContext,
fragmentDefinitions
);
if (!fieldFilteredSelectionSet.selections.length) {
return void 0;
}
return {
kind: graphql.Kind.INLINE_FRAGMENT,
typeCondition: {
kind: graphql.Kind.NAMED_TYPE,
name: {
kind: graphql.Kind.NAME,
value: possibleTypeName
}
},
selectionSet: {
kind: graphql.Kind.SELECTION_SET,
selections: [
{
...node,
selectionSet: fieldFilteredSelectionSet
}
]
}
};
});
const nonEmptySpreads = spreads.filter(
(spread) => spread != null
);
if (!nonEmptySpreads.length) {
return void 0;
}
if (nonEmptySpreads.length === 1) {
return nonEmptySpreads[0];
}
return nonEmptySpreads;
}
}
return void 0;
},
leave: (node) => {
const type = typeInfo.getType();
if (type == null) {
return null;
}
const namedType = graphql.getNamedType(type);
if (schema.getType(namedType.name) == null) {
return null;
}
if (graphql.isObjectType(namedType) || graphql.isInterfaceType(namedType)) {
const selections = node.selectionSet != null ? node.selectionSet.selections : null;
if (selections == null || selections.length === 0) {
return null;
}
}
if (!forwardDefer && hasStreamDirective(node.directives) && !isOperationRootType(typeInfo.getParentType(), schema)) {
return {
...node,
directives: node.directives?.filter(
(directive) => directive.name.value !== "stream"
)
};
}
return void 0;
}
},
[graphql.Kind.FRAGMENT_SPREAD]: {
enter: (node) => {
if (hasDeferDirective(node.directives) && !forwardDefer) {
const frag = fragmentDefsByName[node.name.value];
if (!frag?.selectionSet?.selections?.length) {
return null;
}
const dependencyParentType = schema.getType(frag.typeCondition.name.value) ?? typeInfo.getParentType();
const dependencySelections = collectDeferredDependencySelections(
frag.selectionSet.selections,
dependencyParentType,
delegationContext
);
if (dependencySelections.length === 0) {
return null;
}
return {
kind: graphql.Kind.INLINE_FRAGMENT,
typeCondition: frag.typeCondition,
selectionSet: {
kind: graphql.Kind.SELECTION_SET,
selections: dependencySelections
}
};
}
if (!(node.name.value in validFragments)) {
return null;
}
const parentType = typeInfo.getParentType();
const innerType = validFragments[node.name.value];
if (!utils.implementsAbstractType(schema, parentType, innerType)) {
return null;
}
usedFragments.push(node.name.value);
return void 0;
}
},
[graphql.Kind.SELECTION_SET]: {
enter: (node, _key, _parent, _path) => {
const parentType = typeInfo.getParentType();
const { hasTypeNameField, selections } = filterTypenameFields(
node.selections
);
if (hasTypeNameField || parentType != null && graphql.isAbstractType(parentType)) {
selections.unshift({
kind: graphql.Kind.FIELD,
name: {
kind: graphql.Kind.NAME,
value: "__typename"
}
});
}
return {
...node,
selections
};
},
leave: (node) => {
if (node.selections.some((selection) => Array.isArray(selection))) {
return {
...node,
selections: node.selections.flat().filter(Boolean)
};
}
return void 0;
}
},
[graphql.Kind.INLINE_FRAGMENT]: {
enter: (node) => {
if (node.typeCondition != null) {
const parentType = typeInfo.getParentType();
const innerType = schema.getType(node.typeCondition.name.value);
if (graphql.isUnionType(parentType) && parentType.getTypes().some((t) => t.name === innerType?.name)) ; else if (!utils.implementsAbstractType(schema, parentType, innerType)) {
return null;
}
}
if (!forwardDefer && hasDeferDirective(node.directives) && node.selectionSet?.selections) {
const dependencyParentType = (node.typeCondition != null ? schema.getType(node.typeCondition.name.value) : typeInfo.getParentType()) ?? typeInfo.getParentType();
deferredDependencyStack.push(
collectDeferredDependencySelections(
node.selectionSet.selections,
dependencyParentType,
delegationContext
)
);
} else {
deferredDependencyStack.push(null);
}
return void 0;
},
leave: (selection, _key, parent) => {
const snappedDependencies = deferredDependencyStack.pop() ?? null;
if (hasDeferDirective(selection.directives) && !forwardDefer) {
const dependencySelections = snappedDependencies ?? [];
if (dependencySelections.length === 0) {
return null;
}
return {
...selection,
directives: selection.directives?.filter?.(
(directive) => directive.name.value !== "defer"
),
selectionSet: {
kind: graphql.Kind.SELECTION_SET,
selections: dependencySelections
}
};
}
if (!selection.selectionSet?.selections?.length) {
return null;
}
if (Array.isArray(parent)) {
const selectionTypeName = selection.typeCondition?.name.value;
if (selectionTypeName) {
const selectionType = schema.getType(selectionTypeName);
if (selectionType && "getFields" in selectionType) {
const selectionTypeFields = selectionType.getFields();
let seenNonNullable = seenNonNullableMap.get(parent);
if (!seenNonNullable) {
seenNonNullable = /* @__PURE__ */ new Set();
seenNonNullableMap.set(parent, seenNonNullable);
}
let seenNullable = seenNullableMap.get(parent);
if (!seenNullable) {
seenNullable = /* @__PURE__ */ new Set();
seenNullableMap.set(parent, seenNullable);
}
selection = {
...selection,
selectionSet: {
...selection.selectionSet,
selections: selection.selectionSet.selections.map(
(subSelection) => {
if (subSelection.kind === graphql.Kind.FIELD) {
const fieldName = subSelection.name.value;
if (!subSelection.alias) {
const field = selectionTypeFields[fieldName];
if (field) {
let currentNullable;
if (graphql.isNullableType(field.type)) {
seenNullable.add(fieldName);
currentNullable = true;
} else {
seenNonNullable.add(fieldName);
currentNullable = false;
}
if (seenNullable.has(fieldName) && seenNonNullable.has(fieldName)) {
onOverlappingAliases();
return {
...subSelection,
alias: {
kind: graphql.Kind.NAME,
value: currentNullable ? `_nullable_${fieldName}` : `_nonNullable_${fieldName}`
}
};
}
}
}
}
return subSelection;
}
)
}
};
}
}
}
const { selections } = filterTypenameFields(
selection.selectionSet.selections
);
if (selections.length === 0) {
return null;
}
return {
...selection,
selectionSet: {
...selection.selectionSet,
selections
}
};
}
}
}),
// visitorKeys argument usage a la https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-source-graphql/src/batching/merge-queries.js
// empty keys cannot be removed only because of typescript errors
// will hopefully be fixed in future version of graphql-js to be optional
filteredSelectionSetVisitorKeys
);
}
function hasDeferDirective(directives) {
if (directives == null) {
return false;
}
for (let i = 0; i < directives.length; i++) {
if (directives[i].name.value === "defer") {
return true;
}
}
return false;
}
function hasStreamDirective(directives) {
if (directives == null) {
return false;
}
for (let i = 0; i < directives.length; i++) {
if (directives[i].name.value === "stream") {
return true;
}
}
return false;
}
function isOperationRootType(parentType, schema) {
if (parentType == null) {
return false;
}
return parentType === schema.getQueryType() || parentType === schema.getMutationType() || parentType === schema.getSubscriptionType();
}
function shouldForwardDefer(delegationContext) {
const config = delegationContext.subschemaConfig;
return config?.defer === true;
}
function collectDeferredDependencySelections(selections, parentType, delegationContext) {
if (!parentType || !("getFields" in parentType)) {
return [];
}
const stitchingInfo = delegationContext.info?.schema.extensions?.["stitchingInfo"];
const typeConfig = stitchingInfo?.mergedTypes?.[parentType.name];
const parentFields = parentType.getFields();
const dependencies = [];
const seen = /* @__PURE__ */ new Set();
function addDependencyField(fieldName) {
if (seen.has(fieldName) || parentFields[fieldName] == null) {
return;
}
seen.add(fieldName);
dependencies.push({
kind: graphql.Kind.FIELD,
name: { kind: graphql.Kind.NAME, value: fieldName }
});
}
function addDependenciesForMergedField(fieldName) {
if (typeConfig?.fieldSelectionSets) {
for (const fieldMap of typeConfig.fieldSelectionSets.values()) {
const requiredSelectionSet = fieldMap?.[fieldName];
if (!requiredSelectionSet?.selections) {
continue;
}
for (const requiredSelection of requiredSelectionSet.selections) {
if (requiredSelection.kind === graphql.Kind.FIELD) {
addDependencyField(requiredSelection.name.value);
}
}
}
}
const provided = typeConfig?.providedSelectionsByField?.get(
delegationContext.subschema
)?.[fieldName];
if (provided?.selections) {
for (const providedSelection of provided.selections) {
if (providedSelection.kind === graphql.Kind.FIELD) {
addDependencyField(providedSelection.name.value);
}
}
}
}
function walk(nodes) {
for (const node of nodes) {
if (node.kind === graphql.Kind.FIELD) {
const fieldName = node.name.value;
const fieldOnSubschema = parentFields[fieldName] != null;
if (!fieldOnSubschema) {
addDependenciesForMergedField(fieldName);
}
} else if (node.kind === graphql.Kind.INLINE_FRAGMENT && node.selectionSet) {
walk(node.selectionSet.selections);
} else if (node.kind === graphql.Kind.FRAGMENT_SPREAD) {
const fragDef = delegationContext.info?.fragments?.[node.name.value];
if (fragDef?.selectionSet?.selections) {
walk(fragDef.selectionSet.selections);
}
}
}
}
walk(selections);
return dependencies;
}
function union(...arrays) {
const cache = /* @__PURE__ */ Object.create(null);
const result = [];
for (const array of arrays) {
for (const item of array) {
if (!(item in cache)) {
cache[item] = true;
result.push(item);
}
}
}
return result;
}
function prepareGatewayDocument(originalDocument, delegationContext) {
const transformedSchema = delegationContext.transformedSchema;
const returnType = delegationContext.returnType;
const infoSchema = delegationContext.info?.schema;
const wrappedConcreteTypesDocument = wrapConcreteTypes(
returnType,
transformedSchema,
originalDocument
);
if (infoSchema == null) {
return wrappedConcreteTypesDocument;
}
const visitedSelections = /* @__PURE__ */ new WeakSet();
const {
possibleTypesMap,
reversePossibleTypesMap: reversePossibleTypesMap2,
interfaceExtensionsMap,
fieldNodesByType,
fieldNodesByField,
dynamicSelectionSetsByField
} = getSchemaMetaData(infoSchema, transformedSchema);
const { operations, fragments, fragmentNames } = getDocumentMetadata(
wrappedConcreteTypesDocument
);
const { expandedFragments, fragmentReplacements } = getExpandedFragments(
fragments,
fragmentNames,
possibleTypesMap
);
const typeInfo = getTypeInfo(transformedSchema);
const expandedDocument = {
kind: graphql.Kind.DOCUMENT,
definitions: [...operations, ...fragments, ...expandedFragments]
};
const fragmentMap = /* @__PURE__ */ Object.create(null);
for (const fragment of expandedDocument.definitions) {
if (fragment.kind === graphql.Kind.FRAGMENT_DEFINITION) {
fragmentMap[fragment.name.value] = fragment;
}
}
const visitorKeyMap = {
Document: ["definitions"],
OperationDefinition: ["selectionSet"],
SelectionSet: ["selections"],
Field: ["selectionSet"],
InlineFragment: ["selectionSet"],
FragmentDefinition: ["selectionSet"]
};
return graphql.visit(
expandedDocument,
graphql.visitWithTypeInfo(typeInfo, {
[graphql.Kind.SELECTION_SET]: (node) => visitSelectionSet(
node,
fragmentReplacements,
transformedSchema,
typeInfo,
possibleTypesMap,
reversePossibleTypesMap2,
interfaceExtensionsMap,
fieldNodesByType,
fieldNodesByField,
dynamicSelectionSetsByField,
infoSchema,
visitedSelections,
fragmentMap,
delegationContext
)
}),
// visitorKeys argument usage a la https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-source-graphql/src/batching/merge-queries.js
// empty keys cannot be removed only because of typescript errors
// will hopefully be fixed in future version of graphql-js to be optional
visitorKeyMap
);
}
const getExtraPossibleTypesFn = utils.memoize2(function getExtraPossibleTypes(transformedSchema, infoSchema) {
const extraPossiblesTypesMap = /* @__PURE__ */ new Map();
return function getExtraPossibleTypes2(typeName) {
let extraTypesForSubschema = extraPossiblesTypesMap.get(typeName);
if (!extraTypesForSubschema) {
extraTypesForSubschema = /* @__PURE__ */ new Set();
const gatewayType = infoSchema.getType(typeName);
const subschemaType = transformedSchema.getType(typeName);
if (graphql.isAbstractType(gatewayType) && graphql.isAbstractType(subschemaType)) {
const possibleTypes = infoSchema.getPossibleTypes(gatewayType);
const possibleTypesInSubschema = transformedSchema.getPossibleTypes(subschemaType);
for (const possibleType of possibleTypes) {
const possibleTypeInSubschema = transformedSchema.getType(
possibleType.name
);
if (!possibleTypeInSubschema) {
continue;
}
if (possibleTypeInSubschema && possibleTypesInSubschema.some((t) => t.name === possibleType.name)) {
continue;
}
extraTypesForSubschema.add(possibleType.name);
}
}
extraPossiblesTypesMap.set(typeName, extraTypesForSubschema);
}
return extraTypesForSubschema;
};
});
function visitSelectionSet(node, fragmentReplacements, transformedSchema, typeInfo, possibleTypesMap, reversePossibleTypesMap2, interfaceExtensionsMap, fieldNodesByType, fieldNodesByField, dynamicSelectionSetsByField, infoSchema, visitedSelections, fragmentMap, delegationContext) {
const newSelections = /* @__PURE__ */ new Set();
const maybeType = typeInfo.getParentType();
if (maybeType != null) {
const parentType = graphql.getNamedType(maybeType);
if (isSelectionSetSatisfiedBySchema(
transformedSchema,
parentType,
node,
fragmentMap,
infoSchema,
delegationContext
)) {
if (graphql.isAbstractType(delegationContext.returnType)) {
addSelectionNodeToSelections(newSelections, {
kind: graphql.Kind.FIELD,
name: {
kind: graphql.Kind.NAME,
value: "__typename"
}
});
}
for (const selection of node.selections) {
addSelectionNodeToSelections(newSelections, selection);
}
return {
...node,
selections: Array.from(newSelections)
};
}
const parentTypeName = parentType.name;
const fieldNodes = fieldNodesByType[parentTypeName];
if (fieldNodes) {
for (const fieldNode of fieldNodes) {
addSelectionNodeToSelections(newSelections, fieldNode);
}
}
const interfaceExtensions = interfaceExtensionsMap[parentType.name];
const interfaceExtensionFields = [];
for (const selection of node.selections) {
if (selection.kind === graphql.Kind.INLINE_FRAGMENT) {
if (selection.typeCondition != null) {
if (!visitedSelections.has(selection)) {
visitedSelections.add(selection);
const typeName = selection.typeCondition.name.value;
const getExtraPossibleTypes2 = getExtraPossibleTypesFn(
transformedSchema,
infoSchema
);
const extraPossibleTypes = getExtraPossibleTypes2(typeName);
for (const extraPossibleTypeName of extraPossibleTypes) {
addSelectionNodeToSelections(newSelections, {
...selection,
typeCondition: {
kind: graphql.Kind.NAMED_TYPE,
name: {
kind: graphql.Kind.NAME,
value: extraPossibleTypeName
}
}
});
}
const typeInSubschema = transformedSchema.getType(typeName);
if (graphql.isObjectType(typeInSubschema) || graphql.isInterfaceType(typeInSubschema)) {
const fieldMap = typeInSubschema.getFields();
for (const subSelection of selection.selectionSet.selections) {
if (subSelection.kind === graphql.Kind.FIELD) {
const fieldName = subSelection.name.value;
const field = fieldMap[fieldName];
if (!field) {
addSelectionNodeToSelections(newSelections, subSelection);
}
}
}
} else if (!typeInSubschema) {
for (const subSelection of selection.selectionSet.selections) {
addSelectionNodeToSelections(newSelections, subSelection);
}
}
}
const possibleTypes = possibleTypesMap[selection.typeCondition.name.value];
if (possibleTypes == null) {
const fieldNodesForTypeName = fieldNodesByField[parentTypeName]?.["__typename"];
if (fieldNodesForTypeName) {
for (const fieldNode of fieldNodesForTypeName) {
addSelectionNodeToSelections(newSelections, fieldNode);
}
}
addSelectionNodeToSelections(newSelections, selection);
continue;
}
for (const possibleTypeName of possibleTypes) {
const maybePossibleType = transformedSchema.getType(possibleTypeName);
if (maybePossibleType != null && utils.implementsAbstractType(
transformedSchema,
parentType,
maybePossibleType
)) {
addSelectionNodeToSelections(
newSelections,
generateInlineFragment(
possibleTypeName,
selection.selectionSet
)
);
}
}
if (possibleTypes.length === 0) {
addSelectionNodeToSelections(newSelections, selection);
}
} else {
addSelectionNodeToSelections(newSelections, selection);
}
} else if (selection.kind === graphql.Kind.FRAGMENT_SPREAD) {
const fragmentName = selection.name.value;
if (!fragmentReplacements[fragmentName]) {
addSelectionNodeToSelections(newSelections, selection);
continue;
}
for (const replacement of fragmentReplacements[fragmentName]) {
const typeName = replacement.typeName;
const maybeReplacementType = transformedSchema.getType(typeName);
if (maybeReplacementType != null && utils.implementsAbstractType(transformedSchema, parentType, maybeType)) {
addSelectionNodeToSelections(newSelections, {
kind: graphql.Kind.FRAGMENT_SPREAD,
name: {
kind: graphql.Kind.NAME,
value: replacement.fragmentName
}
});
}
}
} else {
const fieldName = selection.name.value;
if (interfaceExtensions?.[fieldName]) {
interfaceExtensionFields.push(selection);
} else {
addSelectionNodeToSelections(newSelections, selection);
}
if (graphql.isAbstractType(parentType)) {
const fieldNodesForTypeName = fieldNodesByField[parentTypeName]?.["__typename"];
if (fieldNodesForTypeName) {
for (const fieldNode of fieldNodesForTypeName) {
addSelectionNodeToSelections(newSelections, fieldNode);
}
}
}
const fieldNodesMapForType = fieldNodesByField[parentTypeName];
if (fieldNodesMapForType) {
addDependenciesNestedly(
selection,
/* @__PURE__ */ new Set(),
fieldNodesMapForType,
newSelections
);
}
const dynamicSelectionSets = dynamicSelectionSetsByField[parentTypeName]?.[fieldName];
if (dynamicSelectionSets != null) {
for (const selectionSetFn of dynamicSelectionSets) {
const selectionSet = selectionSetFn(selection);
if (selectionSet != null) {
for (const selection2 of selectionSet.selections) {
addSelectionNodeToSelections(newSelections, selection2);
}
}
}
}
}
}
if (reversePossibleTypesMap2[parentType.name]) {
addSelectionNodeToSelections(newSelections, {
kind: graphql.Kind.FIELD,
name: {
kind: graphql.Kind.NAME,
value: "__typename"
}
});
}
if (interfaceExtensionFields.length) {
const possibleTypes = possibleTypesMap[parentType.name];
if (possibleTypes != null) {
for (const possibleType of possibleTypes) {
addSelectionNodeToSelections(
newSelections,
generateInlineFragment(possibleType, {
kind: graphql.Kind.SELECTION_SET,
selections: interfaceExtensionFields
})
);
}
}
}
return {
...node,
selections: Array.from(newSelections)
};
}
return node;
}
function isFieldNodeSatisfiedBySelections(fieldNode, existing) {
for (const existingSelection of existing) {
if (existingSelection.kind === graphql.Kind.FIELD && existingSelection.name.value === fieldNode.name.value && existingSelection.alias?.value === fieldNode.alias?.value) {
if (fieldNode.selectionSet && !existingSelection.selectionSet) {
return false;
}
if (fieldNode.selectionSet && existingSelection.selectionSet) {
const satisfied = isSelectionSetSatisfied({
incoming: fieldNode.selectionSet,
existing: existingSelection.selectionSet.selections
});
if (!satisfied) {
return false;
}
}
return true;
}
}
return false;
}
function isSelectionSetSatisfiedBySchema(schema, type, selectionSet, fragmentsMap, infoSchema, delegationContext) {
const namedType = graphql.getNamedType(type);
if (graphql.isLeafType(namedType)) {
return true;
}
const fields = graphql.isObjectType(namedType) || graphql.isInterfaceType(namedType) ? namedType.getFields() : null;
for (const selection of selectionSet.selections) {
if (selection.kind === graphql.Kind.FIELD) {
if (graphql.isAbstractType(namedType)) {
return false;
}
const fieldName = selection.name.value;
if (fieldName === "__typename") {
continue;
}
if (fields) {
const field = fields[fieldName];
if (!field) {
return false;
}
const typeInInfoSchema = infoSchema.getType(namedType.name);
const fieldInInfoSchema = typeInInfoSchema?.getFields?.()?.[fieldName];
const resolverInInfoSchema = fieldInInfoSchema?.resolve;
if (resolverInInfoSchema != null && resolverInInfoSchema.name !== "defaultMergedResolver" && resolverInInfoSchema.name !== "defaultFieldResolver") {
return false;
}
if (delegationContext.info) {
const overrideHandler = delegationContext.subschemaConfig?.merge?.[namedType.name]?.fields?.[field.name]?.override;
if (overrideHandler != null) {
const overridden = handleOverrideByDelegation(
delegationContext.info,
delegationContext.context,
overrideHandler
);
if (!overridden) {
return false;
}
}
}
if (selection.selectionSet) {
const fieldType = graphql.getNamedType(field.type);
const satisfied = isSelectionSetSatisfiedBySchema(
schema,
fieldType,
selection.selectionSet,
fragmentsMap,
infoSchema,
delegationContext
);
if (!satisfied) {
return false;
}
}
} else {
return false;
}
} else if (selection.kind === graphql.Kind.INLINE_FRAGMENT) {
if (selection.typeCondition) {
const typeConditionName = selection.typeCondition.name.value;
const typeCondition = schema.getType(typeConditionName);
if (!typeCondition) {
return false;
}
const satisfied = isSelectionSetSatisfiedBySchema(
schema,
typeCondition,
selection.selectionSet,
fragmentsMap,
infoSchema,
delegationContext
);
if (!satisfied) {
return false;
}
} else {
const satisfied = isSelectionSetSatisfiedBySchema(
schema,
type,
selection.selectionSet,
fragmentsMap,
infoSchema,
delegationContext
);
if (!satisfied) {
return false;
}
}
} else if (selection.kind === graphql.Kind.FRAGMENT_SPREAD) {
const fragmentName = selection.name.value;
const fragment = fragmentsMap[fragmentName];
if (!fragment) {
return false;
}
const typeConditionName = fragment.typeCondition.name.value;
const typeCondition = schema.getType(typeConditionName);
if (!typeCondition) {
return false;
}
const satisfied = isSelectionSetSatisfiedBySchema(
schema,
typeCondition,
fragment.selectionSet,
fragmentsMap,
infoSchema,
delegationContext
);
if (!satisfied) {
return false;
}
}
}
return true;
}
function isSelectionSetSatisfied({
incoming,
existing
}) {
for (const incomingSelection of incoming.selections) {
if (incomingSelection.kind === graphql.Kind.FIELD) {
const existingField = existing.find((selection) => {
return selection.kind === graphql.Kind.FIELD && selection.name.value === incomingSelection.name.value && selection.alias?.value === incomingSelection.alias?.value;
});
if (!existingField) {
return false;
}
if (incomingSelection.selectionSet && !existingField.selectionSet) {
return false;
}
if (incomingSelection.selectionSet && existingField.selectionSet) {
const satisfied = isSelectionSetSatisfied({
incoming: incomingSelection.selectionSet,
existing: existingField.selectionSet.selections
});
if (!satisfied) {
return false;
}
}
} else {
return false;
}
}
return true;
}
function addSelectionNodeToSelections(selections, selectionNode) {
if (selectionNode.kind === graphql.Kind.FIELD && isFieldNodeSatisfiedBySelections(selectionNode, selections)) {
return;
}
selections.add(selectionNode);
}
function addDependenciesNestedly(fieldNode, seenFieldNames, fieldNodesByField, newSelections) {
if (seenFieldNames.has(fieldNode.name.value)) {
return;
}
seenFieldNames.add(fieldNode.name.value);
const fieldNodes = fieldNodesByField[fieldNode.name.value];
if (fieldNodes != null) {
for (const nestedFieldNode of fieldNodes) {
addSelectionNodeToSelections(newSelections, nestedFieldNode);
addDependenciesNestedly(
nestedFieldNode,
seenFieldNames,
fieldNodesByField,
newSelections
);
}
}
}
function generateInlineFragment(typeName, selectionSet) {
return {
kind: graphql.Kind.INLINE_FRAGMENT,
typeCondition: {
kind: graphql.Kind.NAMED_TYPE,
name: {
kind: graphql.Kind.NAME,
value: typeName
}
},
selectionSet
};
}
const getSchemaMetaData = utils.memoize2(
(sourceSchema, targetSchema) => {
const typeMap = sourceSchema.getTypeMap();
const targetTypeMap = targetSchema.getTypeMap();
const possibleTypesMap = /* @__PURE__ */ Object.create(null);
const interfaceExtensionsMap = /* @__PURE__ */ Object.create(null);
for (const typeName in typeMap) {
const type = typeMap[typeName];
if (graphql.isAbstractType(type)) {
const targetType = targetTypeMap[typeName];
if (graphql.isInterfaceType(type) && graphql.isInterfaceType(targetType)) {
const targetTypeFields = targetType.getFields();
const sourceTypeFields = type.getFields();
const extensionFields = /* @__PURE__ */ Object.create(null);
let isExtensionFieldsEmpty = true;
for (const fieldName in sourceTypeFields) {
if (!targetTypeFields[fieldName]) {
extensionFields[fieldName] = true;
isExtensionFieldsEmpty = false;
}
}
if (!isExtensionFieldsEmpty) {
interfaceExtensionsMap[typeName] = extensionFields;
}
}
if (interfaceExtensionsMap[typeName] || !graphql.isAbstractType(targetType)) {
const implementations = sourceSchema.getPossibleTypes(type);
possibleTypesMap[typeName] = [];
for (const impl of implementations) {
if (targetTypeMap[impl.name]) {
possibleTypesMap[typeName].push(impl.name);
}
}
}
}
}
const stitchingInfo = sourceSchema.extensions?.["stitchingInfo"];
return {
possibleTypesMap,
reversePossibleTypesMap: reversePossibleTypesMap(possibleTypesMap),
interfaceExtensionsMap,
fieldNodesByType: stitchingInfo?.fieldNodesByType ?? {},
fieldNodesByField: stitchingInfo?.fieldNodesByField ?? {},
dynamicSelectionSetsByField: stitchingInfo?.dynamicSelectionSetsByField ?? {}
};
}
);
function reversePossibleTypesMap(possibleTypesMap) {
const result = /* @__PURE__ */ Object.create(null);
for (const typeName in possibleTypesMap) {
const toTypeNames = possibleTypesMap[typeName];
if (toTypeNames) {
for (const toTypeName of toTypeNames) {
if (!result[toTypeName]) {
result[toTypeName] = [];
}
result[toTypeName].push(typeName);
}
}
}
return result;
}
function getExpandedFragments(fragments, fragmentNames, possibleTypesMap) {
let fragmentCounter = 0;
function generateFragmentName(typeName) {
let fragmentName;
do {
fragmentName = `_${typeName}_Fragment${fragmentCounter.toString()}`;
fragmentCounter++;
} while (fragmentNames.has(fragmentName));
return fragmentName;
}
const expandedFragments = [];
const fragmentReplacements = /* @__PURE__ */ Object.create(null);
for (const fragment of fragments) {
const possibleTypes = possibleTypesMap[fragment.typeCondition.name.value];
if (possibleTypes != null) {
const fragmentName = fragment.name.value;
fragmentReplacements[fragmentName] = [];
for (const possibleTypeName of possibleTypes) {
const name = generateFragmentName(possibleTypeName);
fragmentNames.add(name);
expandedFragments.push({
kind: graphql.Kind.FRAGMENT_DEFINITION,
name: {
kind: graphql.Kind.NAME,
value: name
},
typeCondition: {
kind: graphql.Kind.NAMED_TYPE,
name: {
kind: graphql.Kind.NAME,
value: possibleTypeName
}
},
selectionSet: fragment.selectionSet
});
fragmentReplacements[fragmentName].push({
fragmentName: name,
typeName: possibleTypeName
});
}
}
}
return {
expandedFragments,
fragmentReplacements
};
}
function wrapConcreteTypes(returnType, targetSchema, document) {
const namedType = graphql.getNamedType(returnType);
if (graphql.isLeafType(namedType)) {
return document;
}
let possibleTypes = graphql.isAbstractType(
namedType
) ? targetSchema.getPossibleTypes(namedType) : [namedType];
if (possibleTypes.length === 0) {
possibleTypes = [namedType];
}
const rootTypeNames = utils.getRootTypeNames(targetSchema);
const typeInfo = getTypeInfo(targetSchema);
const visitorKeys = {
Document: ["definitions"],
OperationDefinition: ["selectionSet"],
SelectionSet: ["selections"],
InlineFragment: ["selectionSet"],
FragmentDefinition: ["selectionSet"]
};
return graphql.visit(
document,
graphql.visitWithTypeInfo(typeInfo, {
[graphql.Kind.FRAGMENT_DEFINITION]: (node) => {
const typeName = node.typeCondition.name.value;
if (!rootTypeNames.has(typeName)) {
return false;
}
return void 0;
},
[graphql.Kind.FIELD]: (node) => {
const fieldType = typeInfo.getType();
if (fieldType) {
const fieldNamedType = graphql.getNamedType(fieldType);
if (graphql.isAbstractType(fieldNamedType) && fieldNamedType.name !== namedType.name && possibleTypes.length > 0) {
return {
...node,
selectionSet: {
kind: graphql.Kind.SELECTION_SET,
selections: possibleTypes.map((possibleType) => ({
kind: graphql.Kind.INLINE_FRAGMENT,
typeCondition: {
kind: graphql.Kind.NAMED_TYPE,
name: {
kind: graphql.Kind.NAME,
value: possibleType.name
}
},
selectionSet: node.selectionSet
}))
}
};
}
}
return void 0;
}
}),
// visitorKeys argument usage a la https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-source-graphql/src/batching/merge-queries.js
// empty keys cannot be removed only because of typescript errors
// will hopefully be fixed in future version of graphql-js to be optional
visitorKeys
);
}
class Transformer {
transformations = [];
delegationContext;
hasOverlappingAliases = false;
constructor(context) {
this.delegationContext = context;
const transforms = context.transforms;
const delegationTransforms = transforms.slice().reverse();
for (const transform of delegationTransforms) {
this.addTransform(transform);
}
}
addTransform(transform, context = {}) {
this.transformations.push({ transform, context });
}
transformRequest(originalRequest) {
let request = {
...originalRequest,
document: prepareGatewayDocument(
originalRequest.document,
this.delegationContext
)
};
for (const transformation of this.transformations) {
if (transformation.transform.transformRequest) {
request = transformation.transform.transformRequest(
request,
this.delegationContext,
transformation.context
);
}
}
return finalizeGatewayRequest(request, this.delegationContext, () => {
this.hasOverlappingAliases = true;
});
}
transformResult(originalResult) {
let result = originalResult;
for (let i = this.transformations.length - 1; i >= 0; i--) {
const transformation = this.transformations[i];
if (transformation?.transform.transformResult) {
result = transformation.transform.transformResult(
result,
this.delegationContext,
transformation.context
);
}
}
if (this.hasOverlappingAliases) {
result = removeOverlappingAliases(result);
}
return checkResultAndHandleErrors(result, this.delegationContext);
}
}
function removeOverlappingAliases(result) {
if (result != null) {
if (Array.isArray(result)) {
return result.map(removeOverlappingAliases);
} else if (typeof result === "object") {
const newResult = {};
for (const key in result) {
if (key.startsWith("_nullable_") || key.startsWith("_nonNullable_")) {
const newKey = key.replace(/^_nullable_/, "").replace(/^_nonNullable_/, "");
newResult[newKey] = removeOverlappingAliases(result[key]);
} else {
newResult[key] = removeOverlappingAliases(result[key]);
}
}
return newResult;
}
}
return result;
}
const asyncHelpers = {
promiseAll: Promise.all.bind(Promise),
track: () => void 0
};
function getGraphQLResolveInfo(info) {
if (info == null || "getAbortSignal" in info && "getAsyncHelpers" in info) {
return info;
}
return Object.assign(info, {
getAbortSignal: () => void 0,
getAsyncHelpers: () => asyncHelpers
});
}
function getDelegatingOperation(parentType, schema) {
if (parentType === schema.getMutationType()) {
return "mutation";
} else if (parentType === schema.getSubscriptionType()) {
return "subscription";
}
return "query";
}
function createRequest({
subgraphName,
fragments,
rootValue,
targetOperationName,
targetOperation,
targetSchema,
targetFieldName,
selectionSet,
fieldNodes,
context,
info,
args
}) {
let newSelectionSet;
if (selectionSet != null) {
newSelectionSet = selectionSet;
} else {
const selections = [];
for (const fieldNode2 of fieldNodes || []) {
if (fieldNode2.selectionSet) {
for (const selection of fieldNode2.selectionSet.selections) {
selections.push(selection);
}
}
}
newSelectionSet = selections.length ? {
kind: graphql.Kind.SELECTION_SET,
selections
} : void 0;
}
const fieldNode = fieldNodes?.[0];
const rootFieldName = targetFieldName ?? fieldNode?.name.value;
if (rootFieldName === void 0) {
throw new Error(
`Either "targetFieldName" or a non empty "fieldNodes" array must be provided.`
);
}
const outerVariableValues = getCoercedVariableValues(info?.variableValues);
const newVariables = outerVariableValues ? { ...outerVariableValues } : {};
const variableDefinitions = info?.operation.variableDefinitions ? [...info.operation.variableDefinitions] : [];
const argNodes = [];
const replacedVariableNames = /* @__PURE__ */ new Set();
if (args != null) {
const rootType = targetSchema != null ? utils.getDefinedRootType(targetSchema, targetOperation) : void 0;
const rootField = rootType?.getFields()[rootFieldName];
const rootFieldArgs = rootField?.args;
for (const argName in args) {
const argValue = args[argName];
const argInstance = rootFieldArgs?.find((arg) => arg.name === argName);
const existingArgNode = fieldNode?.arguments?.find(
(argNode) => argNode.name.value === argName
);
if (existingArgNode && !argInstance) {
argNodes.push(existingArgNode);
continue;
}
if (existingArgNode?.value.kind === graphql.Kind.VARIABLE) {
const varName = existingArgNode.value.name.value;
const varValue = newVariables[varName];
const variableDefinition = variableDefinitions.find(
(definition) => definition.variable.name.value === varName
);
const variableType = variableDefinition && targetSchema ? graphql.typeFromAST(info?.schema ?? targetSchema, variableDefinition.type) : void 0;
if (varValue === argValue && variableType && argInstance && graphql.isTypeSubTypeOf(
info?.schema ?? targetSchema,
variableType,
argInstance.type
)) {
argNodes.push(existingArgNode);
continue;
}
}
if (argInstance) {
const argAst = utils.astFromArg(argInstance, targetSchema);
const varExists = (varName2) => variableDefinitions.some(
(varDef) => varDef.variable.name.value === varName2
) || // It should not conflict with the variable on the gateway request
// Because the gateway request can have a variable that has nothing to do with
// this argument
outerVariableValues?.[varName2] != null;
let varName = argName;
if (varExists(varName)) {
varName = `_${rootFieldName}_${argName}`;
let i = 0;
while (varExists(varName)) {
varName = `_${i++}_${rootFieldName}_${argName}`;
}
}
if (existingArgNode?.value.kind === graphql.Kind.VARIABLE) {
replacedVariableNames.add(existingArgNode.value.name.value);
}
variableDefinitions.push({
kind: graphql.Kind.VARIABLE_DEFINITION,
variable: {
kind: graphql.Kind.VARIABLE,
name: {
kind: graphql.Kind.NAME,
value: varName
}
},
type: argAst.type
});
const varValue = projectArgumentValue(argValue, argInstance.type);
if (varValue !== void 0) {
newVariables[varName] = varValue;
}
argNodes.push({
kind: graphql.Kind.ARGUMENT,
name: {
kind: graphql.Kind.NAME,
value: argName
},
value: {
kind: graphql.Kind.VARIABLE,
name: {
kind: graphql.Kind.NAME,
value: varName
}
}
});
} else {
const valueNode = utils.astFromValueUntyped(argValue);
if (valueNode != null) {
argNodes.push({
kind: graphql.Kind.ARGUMENT,
name: {
kind: graphql.Kind.NAME,
value: argName
},
value: valueNode
});
}
}
}
}
const rootfieldNode = {
kind: graphql.Kind.FIELD,
arguments: argNodes,
name: {
kind: graphql.Kind.NAME,
value: rootFieldName
},
selectionSet: newSelectionSet,
directives: fieldNode?.directives
};
const operationName = targetOperationName ? {
kind: graphql.Kind.NAME,
value: targetOperationName
} : void 0;
const operationDefinition = {
kind: graphql.Kind.OPERATION_DEFINITION,
name: operationName,
operation: targetOperation,
variableDefinitions,
selectionSet: {
kind: graphql.Kind.SELECTION_SET,
selections: [rootfieldNode]
}
};
const definitions = [operationDefinition];
if (fragments != null) {
definitions.push(...fragments);
}
const document = {
kind: graphql.Kind.DOCUMENT,
definitions
};
if (replacedVariableNames.size > 0) {
const usedVariableNames = /* @__PURE__ */ new Set();
graphql.visit(document, {
VariableDefinition: () => false,
Variable: (variableNode) => {
usedVariableNames.add(variableNode.name.value);
}
});
for (const variableName of replacedVariableNames) {
if (!usedVariableNames.has(variableName)) {
const variableIndex = variableDefinitions.findIndex(
(definition) => definition.variable.name.value === variableName
);
if (variableIndex !== -1) {
variableDefinitions.splice(variableIndex, 1);
delete newVariables[variableName];
}
}
}
}
return {
subgraphName,
document,
variables: newVariables,
rootValue,
operationName: targetOperationName,
context,
info: getGraphQLResolveInfo(info),
operationType: targetOperation
};
}
function projectArgumentValue(argValue, argType) {
if (argValue == null) {
return argValue;
}
if (graphql.isNonNullType(argType)) {
return projectArgumentValue(argValue, argType.ofType);
}
if (graphql.isListType(argType)) {
return utils.asArray(argValue).map(
(item) => projectArgumentValue(item, argType.ofType)
);
}
if (graphql.isInputObjectType(argType) && typeof argValue === "object") {
const projectedValue = {};
const fields = argType.getFields();
for (const key in argValue) {
const field = fields[key];
if (field) {
const varValue = projectArgumentValue(argValue[key], field.type);
if (varValue !== void 0) {
projectedValue[key] = varValue;
}
}
}
return projectedValue;
}
if (argType.name === "Boolean") {
return Boolean(argValue);
}
if (argType.name === "Int" || argType.name === "Float") {
return Number(argValue);
}
if (argType.name === "String") {
return String(argValue);
}
return argValue;
}
class IncrementalReceiver {
constructor(delegationContext) {
this.delegationContext = delegationContext;
this.fieldName = delegationContext.fieldName;
const info = delegationContext.info;
this.initialPathLength = info?.path ? graphql.responsePathAsArray(info.path).length : 0;
}
fieldName;
initialPathLength;
waiters = /* @__PURE__ */ new Map();
/** Field waiters keyed by parent object identity (batch-safe). */
fieldWaiters = [];
rootObject = null;
finished = false;
attachTo(value) {
if (value == null || typeof value !== "object") {
return;
}
this.rootObject = value;
attachReceiver(value, this, this.delegationContext);
}
/**
* Continue reading the subgraph stream in the background, merging patches
* into the attached external object and resolving any waiters.
*/
start(iterable) {
void this.consume(iterable).catch(() => {
});
}
/**
* Apply one incremental-delivery chunk (initial data updates and/or patches).
*/
handleChunk(result) {
if (result?.incremental?.length) {
for (const patch of result.incremental) {
this.applyPatch(patch);
}
return;
}
if (result?.data && this.rootObject) {
const rootData = result.data[this.fieldName];
if (rootData != null && typeof rootData === "object") {
this.mergeInto(this.rootObject, [], rootData);
}
}
}
/** Mark the stream finished and release any remaining waiters. */
finish() {
if (this.finished) {
return;
}
this.finished = true;
for (const waiters of this.waiters.values()) {
for (const waiter of waiters) {
waiter.resolve(void 0);
}
}
this.waiters.clear();
for (const { deferred } of this.fieldWaiters) {
deferred.resolve(void 0);
}
this.fieldWaiters.length = 0;
}
async consume(iterable) {
try {
for await (const result of iterable) {
this.handleChunk(result);
if (result?.hasNext === false) {
break;
}
}
this.finish();
} catch (err) {
if (err?.name === "AbortError") {
this.finish();
return;
}
this.fail(err);
}
}
/**
* End the stream and resolve remaining waiters with `err` as a field value
* (GraphQL-tools Error-as-value pattern — not Promise rejection).
*/
fail(err) {
if (this.finished) {
return;
}
this.finished = true;
const error = err instanceof Error ? err : new graphql.GraphQLError(
err == null ? "Incremental stream failed" : String(err)
);
for (const waiters of this.waiters.values()) {
for (const waiter of waiters) {
waiter.resolve(error);
}
}
this.waiters.clear();
for (const { deferred } of this.fieldWaiters) {
deferred.resolve(error);
}
this.fieldWaiters.length = 0;
}
/**
* Wait until `info`'s field is present on the external object (filled by a
* deferred patch) or the stream ends.
*
* Prefer {@link requestField} from `defaultMergedResolver` — path-relative
* waits break when batch-delegate splits a list-of-lists result.
*/
request(info) {
const fullPath = graphql.responsePathAsArray(info.path);
const relPath = fullPath.slice(this.initialPathLength);
return this.waitForPath(relPath);
}
/**
* Wait until `parent[responseKey]` is set by a patch (or the stream ends).
* Uses object identity so it works after batch-delegate splits nested lists.
*/
requestField(parent, responseKey) {
if (Object.prototype.hasOwnProperty.call(parent, responseKey) && parent[responseKey] !== void 0 || this.finished) {
return promiseHelpers.fakePromise(parent[responseKey]);
}
const deferred = promiseHelpers.createDeferredPromise();
this.fieldWaiters.push({ parent, key: responseKey, deferred });
return deferred.promise;
}
/**
* Yield list items as they arrive from subgraph `@stream` patches.
* Used when a nested list is streamed under a non-list delegated field
* (return type is an object, so delegateToSchema cannot use the root-list
* AsyncIterable path).
*/
async *streamList(info) {
const fullPath = graphql.responsePathAsArray(info.path);
const relPath = fullPath.slice(this.initialPathLength);
let index = 0;
while (true) {
const itemPath = appendPath(relPath, index);
if (hasDefinedValue(this.rootObject, itemPath)) {
yield getAtPath(this.rootObject, itemPath);
index++;
continue;
}
if (this.finished) {
const list = getAtPath(this.rootObject, relPath);
if (Array.isArray(list)) {
while (index < list.length) {
if (list[index] !== void 0) {
yield list[index];
}
index++;
}
}
return;
}
const value = await this.waitForPath(itemPath);
if (value === void 0) {
if (this.finished) {
return;
}
continue;
}
yield value;
index++;
}
}
waitForPath(relPath) {
const key = pathKey(relPath);
if (hasDefinedValue(this.rootObject, relPath) || this.finished) {
return promiseHelpers.fakePromise(getAtPath(this.rootObject, relPath));
}
const deferred = promiseHelpers.createDeferredPromise();
let list = this.waiters.get(key);
if (!list) {
list = [];
this.waiters.set(key, list);
}
list.push(deferred);
return deferred.promise;
}
applyPatch(patch) {
if (!this.rootObject) {
return;
}
const rawPath = patch.path ?? [];
const relPath = rawPath.length > 0 && rawPath[0] === this.fieldName ? rawPath.slice(1) : rawPath;
if (patch.items != null) {
const listPath = relPath.slice(0, -1);
const index = relPath[relPath.length - 1];
if (typeof index !== "number") {
return;
}
let parent = getAtPath(this.rootObject, listPath);
if (!Array.isArray(parent)) {
parent = [];
if (listPath.length === 0) {
return;
}
let cursor = this.rootObject;
for (let i = 0; i < listPath.length - 1; i++) {
const segment = listPath[i];
if (cursor[segment] == null || typeof cursor[segment] !== "object") {
cursor[segment] = typeof listPath[i + 1] === "number" ? [] : {};
}
cursor = cursor[segment];
}
cursor[listPath[listPath.length - 1]] = parent;
}
for (let i = 0; i < patch.items.length; i++) {
parent[index + i] = patch.items[i];
this.notify(pathKey(listPath, index + i), patch.items[i]);
}
return;
}
if (patch.data != null && typeof patch.data === "object") {
const data = mapPatchDataWithErrors(patch.data, patch.errors);
this.mergeInto(this.rootObject, relPath, data);
return;
}
if (patch.errors?.length) {
const error = patch.errors[0];
const key = pathKey(relPath);
if (key) {
this.notify(key, error);
}
for (const [waiterKey, waiters] of this.waiters) {
if (waiterKey.startsWith(key ? `${key}.` : "")) {
for (const waiter of waiters) {
waiter.resolve(error);
}
this.waiters.delete(waiterKey);
}
}
}
}
mergeInto(root, relPath, data) {
let target = root;
for (const segment of relPath) {
if (target[segment] == null || typeof target[segment] !== "object") {
target[segment] = typeof segment === "number" ? [] : {};
attachReceiver(target[segment], this, this.delegationContext);
}
target = target[segment];
}
for (const key of Object.keys(data)) {
const value = data[key];
if (Object.prototype.hasOwnProperty.call(target, key)) {
const existing = target[key];
if (existing === void 0) {
target[key] = value;
if (value != null && typeof value === "object") {
attachReceiver(value, this, this.delegationContext);
}
this.notify(pathKey(relPath, key), value);
this.notifyField(target, key, value);
continue;
}
if (existing != null && value != null && typeof existing === "object" && typeof value === "object" && !Array.isArray(existing) && !Array.isArray(value) && !(value instanceof Error)) {
this.mergeInto(root, appendPath(relPath, key), value);
} else if (Array.isArray(existing) && value != null && typeof value === "object" && !(value instanceof Error)) {
const listPath = appendPath(relPath, key);
for (const indexKey of Object.keys(value)) {
const index = Number(indexKey);
const item = value[indexKey];
const existingItem = existing[index];
if (Number.isInteger(index) && item != null && typeof item === "object" && !(item instanceof Error) && existingItem != null && typeof existingItem === "object" && !(existingItem instanceof Error)) {
this.mergeInto(root, appendPath(listPath, index), item);
}
}
}
continue;
}
target[key] = value;
if (value != null && typeof value === "object" && !(value instanceof Error)) {
attachReceiver(value, this, this.delegationContext);
}
this.notify(pathKey(relPath, key), value);
this.notifyField(target, key, value);
}
}
notify(key, value) {
const waiters = this.waiters.get(key);
if (!waiters) {
return;
}
for (const waiter of waiters) {
waiter.resolve(value);
}
this.waiters.delete(key);
}
notifyField(parent, key, value) {
for (let i = this.fieldWaiters.length - 1; i >= 0; i--) {
const waiter = this.fieldWaiters[i];
if (waiter.parent === parent && waiter.key === key) {
waiter.deferred.resolve(value);
this.fieldWaiters.splice(i, 1);
}
}
}
}
function getReceiver(object) {
return object?.[RECEIVER_SYMBOL];
}
function attachReceiver(object, receiver, delegationContext) {
if (object == null || typeof object !== "object") {
return;
}
if (Array.isArray(object)) {
for (let i = 0; i < object.length; i++) {
attachReceiver(object[i], receiver, delegationContext);
}
return;
}
if (object[RECEIVER_SYMBOL] === receiver) {
return;
}
if (!isExternalObject(object)) {
annotateExternalObject(
object,
[],
delegationContext.subschema,
/* @__PURE__ */ Object.create(null)
);
}
Object.defineProperty(object, RECEIVER_SYMBOL, {
value: receiver,
writable: true,
configurable: true
});
const keys = Object.keys(object);
for (let i = 0; i < keys.length; i++) {
const value = object[keys[i]];
if (value != null && typeof value === "object") {
attachReceiver(value, receiver, delegationContext);
}
}
}
function pathKey(path, extra) {
if (extra === void 0) {
return path.length === 0 ? "" : path.join(".");
}
if (path.length === 0) {
return String(extra);
}
return `${path.join(".")}.${extra}`;
}
function appendPath(path, segment) {
if (path.length === 0) {
return [segment];
}
const next = path.slice();
next.push(segment);
return next;
}
function getAtPath(root, path) {
if (root == null) {
return void 0;
}
let current = root;
for (let i = 0; i < path.length; i++) {
if (current == null || typeof current !== "object") {
return void 0;
}
const segment = path[i];
if (!Object.prototype.hasOwnProperty.call(current, segment)) {
return void 0;
}
current = current[segment];
}
return current;
}
function hasDefinedValue(root, path) {
if (root == null) {
return false;
}
if (path.length === 0) {
return true;
}
let current = root;
for (let i = 0; i < path.length; i++) {
if (current == null || typeof current !== "object") {
return false;
}
const segment = path[i];
if (!Object.prototype.hasOwnProperty.call(current, segment)) {
return false;
}
current = current[segment];
}
return current !== void 0;
}
function mapPatchDataWithErrors(data, errors, _relPath) {
if (!errors?.length) {
return data;
}
const mapped = { ...data };
for (const error of errors) {
const key = error.path?.at(-1);
if (key != null && Object.prototype.hasOwnProperty.call(mapped, key) && mapped[key] == null) {
mapped[String(key)] = error;
}
}
return mapped;
}
function resolveSourceFieldName(subschema, typeName, fieldName) {
const transforms = subschema.transforms ?? subschema.transforms;
if (!transforms?.length) {
return fieldName;
}
for (const transform of transforms) {
const mapped = readCompositeFieldMapping(transform, typeName, fieldName);
if (mapped != null) {
return mapped;
}
}
return fieldName;
}
function getHoistFieldMeta(subschema, typeName, fieldName) {
const transforms = subschema.transforms ?? subschema.transforms;
if (!transforms?.length) {
return void 0;
}
for (const transform of transforms) {
const hoist = asHoistLike(transform);
if (hoist && hoist.typeName === typeName && hoist.newFieldName === fieldName) {
return hoist;
}
}
return void 0;
}
function getHoistedFieldTarget(parent, hoist) {
let current = parent;
for (const segment of hoist.pathToField) {
if (current == null || typeof current !== "object") {
return void 0;
}
current = current[segment];
}
if (current == null || typeof current !== "object") {
return void 0;
}
return { parent: current, fieldName: hoist.oldFieldName };
}
function getHoistedSourceType(originalSchema, parentTypeName, hoist) {
let type = (() => {
const t = originalSchema.getType(parentTypeName);
return graphql.isObjectType(t) ? t : void 0;
})();
if (!type) {
return void 0;
}
for (const segment of hoist.pathToField) {
const field = type.getFields()[segment];
if (field == null) {
return void 0;
}
const named = unwrapNamedType(field.type);
if (!graphql.isObjectType(named)) {
return void 0;
}
type = named;
}
return type;
}
function unwrapNamedType(type) {
let current = type;
while (current != null && typeof current === "object" && "ofType" in current && current.ofType) {
current = current.ofType;
}
return current;
}
function readCompositeFieldMapping(transform, typeName, fieldName) {
let current = transform;
for (let i = 0; i < 4 && current; i++) {
const mapped = current.mapping?.[typeName]?.[fieldName];
if (typeof mapped === "string") {
return mapped;
}
current = current.transformer;
}
return void 0;
}
function asHoistLike(transform) {
if (transform && typeof transform.typeName === "string" && typeof transform.newFieldName === "string" && typeof transform.oldFieldName === "string" && Array.isArray(transform.pathToField)) {
return transform;
}
return void 0;
}
function pickInnerFieldOwner(mergedTypeInfo, fieldName, info, context) {
const uniqueOwner = mergedTypeInfo.uniqueFields[fieldName];
if (uniqueOwner != null) {
return uniqueOwner;
}
const candidates = mergedTypeInfo.nonUniqueFields[fieldName];
if (candidates == null || candidates.length === 0) {
return void 0;
}
for (const candidate of candidates) {
const overrideHandler = candidate.merge?.[mergedTypeInfo.typeName]?.fields?.[fieldName]?.override;
if (overrideHandler != null && context != null && handleOverrideByDelegation(info, context, overrideHandler)) {
return candidate;
}
}
return candidates[0];
}
function isMissingFieldValue(parent, responseKey) {
return !Object.prototype.hasOwnProperty.call(parent, responseKey) || parent[responseKey] === void 0;
}
function fieldHasStreamDirective$1(info) {
for (const fieldNode of info.fieldNodes) {
const directives = fieldNode.directives;
if (directives == null) {
continue;
}
for (let i = 0; i < directives.length; i++) {
if (directives[i].name.value === "stream") {
return true;
}
}
}
return false;
}
function defaultMergedResolver(parent, args, context, info) {
if (!parent) {
return null;
}
const responseKey = info.fieldNodes[0].alias?.value ?? info.fieldName;
if (!isExternalObject(parent)) {
return graphql.defaultFieldResolver(parent, args, context, info);
}
const streamReceiver = getReceiver(parent);
if (streamReceiver && fieldHasStreamDirective$1(info)) {
return streamReceiver.streamList(info);
}
if (isMissingFieldValue(parent, responseKey)) {
const receiver = getReceiver(parent);
if (receiver) {
return promiseHelpers.handleMaybePromise(
() => receiver.requestField(parent, responseKey),
(value) => resolveExternalValue(
value,
getUnpathedErrors(parent),
getSubschema(parent, responseKey),
context,
info
)
);
}
const leftOver = getPlanLeftOverFromParent(parent);
if (leftOver) {
let missingFieldNodes = leftOver.missingFieldsParentMap.get(parent);
if (!missingFieldNodes) {
missingFieldNodes = [];
leftOver.missingFieldsParentMap.set(parent, missingFieldNodes);
}
missingFieldNodes.push(
...info.fieldNodes.filter(
(fieldNode) => leftOver.unproxiableFieldNodes.some(
(unproxiableFieldNode) => unproxiableFieldNode === fieldNode
)
)
);
let missingDeferredFields = leftOver.missingFieldsParentDeferredMap.get(parent);
if (!missingDeferredFields) {
missingDeferredFields = /* @__PURE__ */ new Map();
leftOver.missingFieldsParentDeferredMap.set(
parent,
missingDeferredFields
);
}
const deferred = promiseHelpers.createDeferredPromise();
missingDeferredFields.set(responseKey, deferred);
const stitchingInfo2 = info.schema.extensions?.["stitchingInfo"];
const parentTypeName2 = parent?.__typename || info.parentType.name;
leftOverDeferredContext.set(deferred, {
parentTypeName: parentTypeName2,
fieldName: info.fieldName,
responseKey,
path: graphql.responsePathAsArray(info.path),
sourceSubschema: parent[OBJECT_SUBSCHEMA_SYMBOL]
});
const fieldNodesByType = stitchingInfo2?.fieldNodesByField?.[parentTypeName2]?.[info.fieldName];
if (fieldNodesByType?.every((fieldNode) => {
const key = fieldNode.alias?.value ?? fieldNode.name.value;
return !isMissingFieldValue(parent, key);
})) {
handleResult(parent, responseKey, context, info);
} else {
handleLeftOver(parent, context, info, leftOver);
}
return deferred.promise;
}
if (!isMissingFieldValue(parent, info.fieldName)) {
return graphql.defaultFieldResolver(parent, args, context, info);
}
const stitchingInfo = info.schema?.extensions?.["stitchingInfo"];
const parentTypeName = parent.__typename || info.parentType?.name;
const mergedTypeInfo = parentTypeName ? stitchingInfo?.mergedTypes[parentTypeName] : void 0;
const sourceSubschema = parent[OBJECT_SUBSCHEMA_SYMBOL];
if (mergedTypeInfo && sourceSubschema) {
const fieldNode = {
kind: graphql.Kind.FIELD,
name: info.fieldNodes[0]?.name ?? {
kind: graphql.Kind.NAME,
value: info.fieldName
},
selectionSet: {
kind: graphql.Kind.SELECTION_SET,
selections: info.fieldNodes
}
};
return promiseHelpers.handleMaybePromise(
() => mergeFields(mergedTypeInfo, parent, sourceSubschema, context, info, [
fieldNode
]),
() => {
if (!isMissingFieldValue(parent, responseKey)) {
return handleResult(parent, responseKey, context, info);
}
return resolveMissingFieldFromSourceSubschema(
parent,
args,
context,
info,
sourceSubschema,
mergedTypeInfo
);
}
);
}
if (sourceSubschema) {
return resolveMissingFieldFromSourceSubschema(
parent,
args,
context,
info,
sourceSubschema
);
}
return void 0;
}
return handleResult(parent, responseKey, context, info);
}
function resolveMissingFieldFromSourceSubschema(parent, args, context, info, subschema, mergedTypeInfo) {
const responseKey = info.fieldNodes[0].alias?.value ?? info.fieldName;
const typedSubschema = subschema;
const parentTypeName = parent.__typename || info.parentType.name;
const originalSchema = subschema.schema ?? (subschema instanceof graphql.GraphQLSchema ? subschema : void 0);
const planningSchema = typedSubschema.transformedSchema ?? originalSchema ?? void 0;
const typeInSubschema = planningSchema?.getType(parentTypeName);
const fieldInSubschema = graphql.isObjectType(typeInSubschema) && typeInSubschema.getFields()[info.fieldName] != null;
const mergedTypeResolver = fieldInSubschema && mergedTypeInfo?.resolvers?.get(typedSubschema);
if (mergedTypeResolver && graphql.isObjectType(typeInSubschema)) {
const selectionSet = {
kind: graphql.Kind.SELECTION_SET,
selections: info.fieldNodes
};
return promiseHelpers.handleMaybePromise(
() => mergedTypeResolver(
parent,
context,
info,
typedSubschema,
selectionSet,
void 0,
typeInSubschema
),
(resolverResult) => {
handleResolverResult(
resolverResult,
typedSubschema,
selectionSet,
parent,
parent[FIELD_SUBSCHEMA_MAP_SYMBOL] ?? /* @__PURE__ */ Object.create(null),
info,
graphql.responsePathAsArray(info.path).slice(0, -1),
parent[UNPATHED_ERRORS_SYMBOL] ?? []
);
if (!isMissingFieldValue(parent, responseKey)) {
return handleResult(parent, responseKey, context, info);
}
return void 0;
}
);
}
if (originalSchema == null) {
return void 0;
}
const hoist = getHoistFieldMeta(subschema, parentTypeName, info.fieldName);
if (hoist) {
const target = getHoistedFieldTarget(parent, hoist);
const sourceType = getHoistedSourceType(
originalSchema,
// Prefer the original type name when RenameTypes is also present.
resolveOriginalTypeName(originalSchema, parentTypeName, hoist.typeName),
hoist
);
if (target && graphql.isObjectType(sourceType)) {
if (!isMissingFieldValue(target.parent, target.fieldName)) {
const value = applyLeafOutputTransforms(
subschema,
info,
target.parent[target.fieldName]
);
parent[responseKey] = value;
return resolveExternalValue(
value,
getUnpathedErrors(parent),
subschema,
context,
info
);
}
const nestedField = sourceType.getFields()[target.fieldName];
const nestedResolve = nestedField?.resolve;
if (nestedResolve != null && nestedResolve !== graphql.defaultFieldResolver) {
return promiseHelpers.handleMaybePromise(
() => nestedResolve(target.parent, args, context, info),
(value) => {
const mapped = applyLeafOutputTransforms(subschema, info, value);
parent[responseKey] = mapped;
if (parent[FIELD_SUBSCHEMA_MAP_SYMBOL]) {
parent[FIELD_SUBSCHEMA_MAP_SYMBOL][responseKey] = subschema;
}
return resolveExternalValue(
mapped,
getUnpathedErrors(parent),
subschema,
context,
info
);
}
);
}
}
}
const sourceFieldName = resolveSourceFieldName(
subschema,
parentTypeName,
info.fieldName
);
let originalType = originalSchema.getType(parentTypeName);
if (!graphql.isObjectType(originalType)) {
const candidates = Object.values(originalSchema.getTypeMap()).filter(
(t) => graphql.isObjectType(t) && !t.name.startsWith("__") && t.getFields()[sourceFieldName] != null
);
originalType = candidates.length === 1 ? candidates[0] : void 0;
}
if (!graphql.isObjectType(originalType)) {
return void 0;
}
const field = originalType.getFields()[sourceFieldName];
const resolve = field?.resolve;
if (resolve == null || resolve === graphql.defaultFieldResolver) {
return void 0;
}
if (resolve === defaultMergedResolver) {
const innerStitchingInfo = originalSchema.extensions?.["stitchingInfo"];
const innerTypeName = typeof parent.__typename === "string" && parent.__typename || parentTypeName;
const innerMergedTypeInfo = innerStitchingInfo?.mergedTypes[innerTypeName];
const fieldOwner = innerMergedTypeInfo && pickInnerFieldOwner(innerMergedTypeInfo, sourceFieldName, info, context);
const ownerResolver = fieldOwner && innerMergedTypeInfo?.resolvers.get(fieldOwner);
const typeInOwner = fieldOwner && (fieldOwner.transformedSchema.getType(innerTypeName) ?? originalSchema.getType(innerTypeName));
if (ownerResolver && fieldOwner && typeInOwner && graphql.isObjectType(typeInOwner)) {
const selectionSet = {
kind: graphql.Kind.SELECTION_SET,
selections: info.fieldNodes
};
const innerParent = annotateExternalObject(
{ ...parent },
getUnpathedErrors(parent),
fieldOwner,
/* @__PURE__ */ Object.create(null)
);
const innerInfo = { ...info, schema: originalSchema };
return promiseHelpers.handleMaybePromise(
() => ownerResolver(
innerParent,
context,
innerInfo,
fieldOwner,
selectionSet,
void 0,
typeInOwner
),
(resolverResult) => {
handleResolverResult(
resolverResult,
fieldOwner,
selectionSet,
innerParent,
innerParent[FIELD_SUBSCHEMA_MAP_SYMBOL] ?? /* @__PURE__ */ Object.create(null),
innerInfo,
graphql.responsePathAsArray(info.path).slice(0, -1),
innerParent[UNPATHED_ERRORS_SYMBOL] ?? []
);
if (!isMissingFieldValue(innerParent, responseKey)) {
const value = innerParent[responseKey];
parent[responseKey] = value;
if (parent[FIELD_SUBSCHEMA_MAP_SYMBOL]) {
parent[FIELD_SUBSCHEMA_MAP_SYMBOL][responseKey] = subschema;
}
return resolveExternalValue(
value,
getUnpathedErrors(parent),
subschema,
context,
info
);
}
return void 0;
}
);
}
return void 0;
}
return promiseHelpers.handleMaybePromise(
() => resolve(parent, args, context, info),
(value) => {
const mapped = applyLeafOutputTransforms(subschema, info, value);
parent[responseKey] = mapped;
if (parent[FIELD_SUBSCHEMA_MAP_SYMBOL]) {
parent[FIELD_SUBSCHEMA_MAP_SYMBOL][responseKey] = subschema;
}
return resolveExternalValue(
mapped,
getUnpathedErrors(parent),
subschema,
context,
info
);
}
);
}
function applyLeafOutputTransforms(subschema, info, value) {
if (value == null) {
return value;
}
const transforms = subschema.transforms ?? subschema.transforms;
if (!transforms?.length) {
return value;
}
const typeName = graphql.getNamedType(info.returnType)?.name;
if (!typeName) {
return value;
}
let mapped = value;
for (const transform of transforms) {
const visitor = transform.resultVisitorMap?.[typeName];
if (typeof visitor === "function") {
mapped = visitor(mapped);
}
}
return mapped;
}
function resolveOriginalTypeName(originalSchema, gatewayTypeName, fallbackTypeName) {
if (graphql.isObjectType(originalSchema.getType(gatewayTypeName))) {
return gatewayTypeName;
}
if (graphql.isObjectType(originalSchema.getType(fallbackTypeName))) {
return fallbackTypeName;
}
return gatewayTypeName;
}
function handleResult(parent, responseKey, context, info) {
const subschema = getSubschema(parent, responseKey);
const data = parent[responseKey];
const unpathedErrors = getUnpathedErrors(parent);
const resolvedData$ = resolveExternalValue(
data,
unpathedErrors,
subschema,
context,
info
);
const leftOver = getPlanLeftOverFromParent(parent);
if (leftOver) {
const endWork = beginLeftOverWork(leftOver);
return promiseHelpers.handleMaybePromise(
() => resolvedData$,
(resolvedData) => {
parent[responseKey] = resolvedData;
handleLeftOver(parent, context, info, leftOver);
return resolvedData;
},
void 0,
endWork
);
}
return resolvedData$;
}
function handleLeftOver(parent, context, info, leftOver) {
const stitchingInfo = info.schema.extensions?.["stitchingInfo"];
let scheduledWork = false;
if (stitchingInfo) {
for (const possibleSubschema of leftOver.nonProxiableSubschemas) {
const parentTypeName = info.parentType.name;
const selectionSets = /* @__PURE__ */ new Set();
const mainSelectionSet = stitchingInfo.mergedTypes[parentTypeName]?.selectionSets.get(
possibleSubschema
);
if (mainSelectionSet) {
selectionSets.add(mainSelectionSet);
}
for (const fieldNode of leftOver.unproxiableFieldNodes) {
const fieldName = fieldNode.name.value;
const fieldSelectionSet = stitchingInfo.mergedTypes[parentTypeName]?.fieldSelectionSets.get(
possibleSubschema
)?.[fieldName];
if (fieldSelectionSet) {
selectionSets.add(fieldSelectionSet);
}
}
if (selectionSets.size) {
scheduledWork = true;
const selectionSet = {
kind: graphql.Kind.SELECTION_SET,
selections: Array.from(selectionSets).flatMap(
(selectionSet2) => selectionSet2.selections
)
};
const endWork = beginLeftOverWork(leftOver);
promiseHelpers.handleMaybePromise(
() => flattenPromise(parent),
(flattenedParent) => {
handleFlattenedParent(
flattenedParent,
parent,
possibleSubschema,
selectionSet,
leftOver,
stitchingInfo,
parentTypeName,
context,
info
);
},
void 0,
endWork
);
}
}
}
if (!scheduledWork) {
scheduleLeftOverDrain(leftOver);
}
}
function handleFlattenedParent(flattenedParent, leftOverParent, possibleSubschema, selectionSet, leftOver, stitchingInfo, parentTypeName, context, info) {
if (parentSatisfiedSelectionSet(flattenedParent, selectionSet)) {
const missingFieldNodes = leftOver.missingFieldsParentMap.get(leftOverParent);
if (missingFieldNodes) {
const resolver = stitchingInfo.mergedTypes[parentTypeName]?.resolvers.get(
possibleSubschema
);
if (resolver) {
Object.assign(leftOverParent, flattenedParent);
const selectionSet2 = {
kind: graphql.Kind.SELECTION_SET,
selections: missingFieldNodes
};
const endWork = beginLeftOverWork(leftOver);
promiseHelpers.handleMaybePromise(
() => resolver(
leftOverParent,
context,
info,
possibleSubschema,
selectionSet2,
info.parentType,
info.parentType
),
(resolverResult) => {
handleDeferredResolverResult(
resolverResult,
possibleSubschema,
selectionSet2,
leftOverParent,
leftOver,
context,
info
);
},
(error) => handleDeferredResolverFailure(leftOver, leftOverParent, error),
endWork
);
}
}
} else {
for (const selectionNode of selectionSet.selections) {
if (selectionNode.kind === graphql.Kind.FIELD && selectionNode.selectionSet?.selections?.length) {
const responseKey = selectionNode.alias?.value ?? selectionNode.name.value;
const nestedParent = flattenedParent[responseKey];
const nestedSelectionSet = selectionNode.selectionSet;
if (nestedParent != null) {
if (!parentSatisfiedSelectionSet(nestedParent, nestedSelectionSet)) {
async function handleNestedParentItem(nestedParentItem, fieldNode) {
const endWork = beginLeftOverWork(leftOver);
try {
const nestedTypeName = nestedParentItem["__typename"];
const sourceSubschema = getSubschema(
flattenedParent,
responseKey
);
if (sourceSubschema && nestedTypeName) {
const variableValues = getCoercedVariableValues(
info.variableValues
);
const delegationPlan = stitchingInfo.mergedTypes[nestedTypeName]?.delegationPlanBuilder(
info.schema,
sourceSubschema,
variableValues != null && Object.keys(variableValues).length > 0 ? variableValues : EMPTY_OBJECT,
info.fragments != null && Object.keys(info.fragments).length > 0 ? info.fragments : EMPTY_OBJECT,
getActualFieldNodes(fieldNode),
context,
info
);
if (delegationPlan?.length) {
for (const delegationMap of delegationPlan) {
for (const [subschema, selectionSet2] of delegationMap) {
const resolver = stitchingInfo.mergedTypes[nestedTypeName]?.resolvers.get(subschema);
if (resolver) {
const subschemaTypes = stitchingInfo.mergedTypes[nestedTypeName].typeMaps.get(subschema);
const returnType = subschemaTypes[nestedTypeName];
const res = await resolver(
nestedParentItem,
context,
info,
subschema,
selectionSet2,
returnType,
// returnType
info.parentType
);
if (res) {
handleResolverResult(
res,
subschema,
selectionSet2,
nestedParentItem,
nestedParentItem[FIELD_SUBSCHEMA_MAP_SYMBOL] ||= /* @__PURE__ */ new Map(),
info,
graphql.responsePathAsArray(info.path),
nestedParentItem[UNPATHED_ERRORS_SYMBOL] ||= []
);
}
}
}
}
}
if (parentSatisfiedSelectionSet(
nestedParent,
nestedSelectionSet
)) {
handleFlattenedParent(
flattenedParent,
leftOverParent,
possibleSubschema,
selectionSet,
leftOver,
stitchingInfo,
parentTypeName,
context,
info
);
}
}
} finally {
endWork();
}
}
if (Array.isArray(nestedParent)) {
nestedParent.forEach(
(nestedParentItem) => handleNestedParentItem(nestedParentItem, selectionNode)
);
} else {
handleNestedParentItem(nestedParent, selectionNode);
}
}
}
}
}
}
}
function handleDeferredResolverResult(resolverResult, possibleSubschema, selectionSet, leftOverParent, leftOver, context, info) {
handleResolverResult(
resolverResult,
possibleSubschema,
selectionSet,
leftOverParent,
leftOverParent[FIELD_SUBSCHEMA_MAP_SYMBOL],
info,
graphql.responsePathAsArray(info.path),
leftOverParent[UNPATHED_ERRORS_SYMBOL]
);
const deferredFields = leftOver.missingFieldsParentDeferredMap.get(leftOverParent);
if (deferredFields) {
const stitchingInfo = info.schema.extensions?.["stitchingInfo"];
const parentTypeName = leftOverParent?.__typename || info.parentType.name;
const resolvedKeys = /* @__PURE__ */ new Set();
for (const [responseKey, deferred] of deferredFields) {
if (Object.prototype.hasOwnProperty.call(leftOverParent, responseKey)) {
deferred.resolve(
handleResult(leftOverParent, responseKey, context, info)
);
resolvedKeys.add(responseKey);
} else {
const fieldNodesByType = stitchingInfo?.fieldNodesByField?.[parentTypeName]?.[responseKey];
if (fieldNodesByType) {
if (fieldNodesByType.every((fieldNode) => {
const requiredKey = fieldNode.alias?.value ?? fieldNode.name.value;
return Object.prototype.hasOwnProperty.call(
leftOverParent,
requiredKey
);
})) {
const endWork = beginLeftOverWork(leftOver);
setTimeout(() => {
try {
handleLeftOver(leftOverParent, context, info, leftOver);
} finally {
endWork();
}
}, 0);
}
}
}
}
for (const key of resolvedKeys) {
deferredFields.delete(key);
}
if (deferredFields.size === 0) {
leftOver.missingFieldsParentDeferredMap.delete(leftOverParent);
}
}
}
function handleDeferredResolverFailure(leftOver, leftOverParent, error) {
const deferredFields = leftOver.missingFieldsParentDeferredMap.get(leftOverParent);
if (deferredFields) {
for (const [_responseKey, deferred] of deferredFields) {
deferred.reject(error);
}
leftOver.missingFieldsParentDeferredMap.delete(leftOverParent);
}
}
function parentSatisfiedSelectionSet(parent, selectionSet) {
if (Array.isArray(parent)) {
const subschemas2 = /* @__PURE__ */ new Set();
for (const item of parent) {
const satisfied = parentSatisfiedSelectionSet(item, selectionSet);
if (satisfied === void 0) {
return void 0;
}
for (const subschema of satisfied) {
subschemas2.add(subschema);
}
}
return subschemas2;
}
if (parent === null) {
return /* @__PURE__ */ new Set();
}
if (parent === void 0) {
return void 0;
}
const subschemas = /* @__PURE__ */ new Set();
for (const selection of selectionSet.selections) {
if (selection.kind === graphql.Kind.FIELD) {
const responseKey = selection.alias?.value ?? selection.name.value;
if (parent[responseKey] === void 0) {
return void 0;
}
if (isExternalObject(parent)) {
const subschema = getSubschema(parent, responseKey);
if (subschema) {
subschemas.add(subschema);
}
}
if (parent[responseKey] === null) {
continue;
}
if (selection.selectionSet != null) {
const satisfied = parentSatisfiedSelectionSet(
parent[responseKey],
selection.selectionSet
);
if (satisfied === void 0) {
return void 0;
}
for (const subschema of satisfied) {
subschemas.add(subschema);
}
}
} else if (selection.kind === graphql.Kind.INLINE_FRAGMENT) {
const inlineSatisfied = parentSatisfiedSelectionSet(
parent,
selection.selectionSet
);
if (inlineSatisfied === void 0) {
return void 0;
}
for (const subschema of inlineSatisfied) {
subschemas.add(subschema);
}
}
}
return subschemas;
}
function flattenPromise(data) {
if (promiseHelpers.isPromise(data)) {
return data.then(flattenPromise);
}
if (Array.isArray(data)) {
return Promise.all(data.map(flattenPromise));
}
if (data != null && typeof data === "object") {
const jobs = [];
const newData = {};
for (const key in data) {
const keyResult = flattenPromise(data[key]);
if (promiseHelpers.isPromise(keyResult)) {
jobs.push(
keyResult.then((resolvedKeyResult) => {
newData[key] = resolvedKeyResult;
})
);
} else {
newData[key] = keyResult;
}
}
if (OBJECT_SUBSCHEMA_SYMBOL in data) {
newData[OBJECT_SUBSCHEMA_SYMBOL] = data[OBJECT_SUBSCHEMA_SYMBOL];
}
if (FIELD_SUBSCHEMA_MAP_SYMBOL in data) {
newData[FIELD_SUBSCHEMA_MAP_SYMBOL] = data[FIELD_SUBSCHEMA_MAP_SYMBOL];
}
if (UNPATHED_ERRORS_SYMBOL in data) {
newData[UNPATHED_ERRORS_SYMBOL] = data[UNPATHED_ERRORS_SYMBOL];
}
if (jobs.length) {
return Promise.all(jobs).then(() => newData);
}
return newData;
}
return data;
}
const leftOverWorkState = /* @__PURE__ */ new WeakMap();
function getLeftOverWorkState(leftOver) {
let state = leftOverWorkState.get(leftOver);
if (!state) {
state = { pending: 0, drainScheduled: false };
leftOverWorkState.set(leftOver, state);
}
return state;
}
function beginLeftOverWork(leftOver) {
const state = getLeftOverWorkState(leftOver);
state.pending++;
let ended = false;
return () => {
if (ended) {
return;
}
ended = true;
state.pending--;
scheduleLeftOverDrain(leftOver);
};
}
function scheduleLeftOverDrain(leftOver) {
const state = getLeftOverWorkState(leftOver);
if (state.drainScheduled) {
return;
}
state.drainScheduled = true;
queueMicrotask(() => {
state.drainScheduled = false;
if (state.pending > 0) {
return;
}
rejectOrphanedLeftOverDeferreds(leftOver);
});
}
function rejectOrphanedLeftOverDeferreds(leftOver) {
for (const [
parent,
deferredFields
] of leftOver.missingFieldsParentDeferredMap) {
if (!deferredFields.size) {
leftOver.missingFieldsParentDeferredMap.delete(parent);
continue;
}
for (const [responseKey, deferred] of deferredFields) {
const ctx = leftOverDeferredContext.get(deferred);
deferred.reject(
new graphql.GraphQLError(
buildSatisfiabilityErrorMessage(leftOver, responseKey, ctx, parent),
{
extensions: {
code: "SATISFIABILITY_ERROR"
}
}
)
);
leftOverDeferredContext.delete(deferred);
}
deferredFields.clear();
leftOver.missingFieldsParentDeferredMap.delete(parent);
}
}
const leftOverDeferredContext = /* @__PURE__ */ new WeakMap();
function formatSubschemaLabel(subschema, fallback) {
const name = subschema?.name;
if (name) {
return `subschema "${name}"`;
}
return fallback;
}
function printPathAsQuerySelection(path) {
const fields = path.filter((segment) => {
return typeof segment === "string";
});
if (fields.length === 0) {
return "{\n}";
}
const lines = ["{"];
for (let i = 0; i < fields.length; i++) {
const pad = " ".repeat(i + 1);
if (i === fields.length - 1) {
lines.push(`${pad}${fields[i]}`);
} else {
lines.push(`${pad}${fields[i]} {`);
}
}
for (let i = fields.length - 1; i >= 1; i--) {
lines.push(`${" ".repeat(i)}}`);
}
lines.push("}");
return lines.join("\n");
}
function buildSatisfiabilityErrorMessage(leftOver, responseKey, ctx, parent) {
const parentTypeName = ctx?.parentTypeName || (typeof parent?.__typename === "string" ? parent.__typename : "Object");
const fieldName = ctx?.fieldName || responseKey;
const qualifiedField = `${parentTypeName}.${fieldName}`;
const path = ctx?.path?.length ? ctx.path : [responseKey];
const selection = printPathAsQuerySelection(path);
const sourceSubschema = ctx?.sourceSubschema || parent[OBJECT_SUBSCHEMA_SYMBOL];
const sourceLabel = formatSubschemaLabel(
sourceSubschema,
"the current subschema"
);
const reasons = [`- cannot find field "${qualifiedField}".`];
for (const target of leftOver.nonProxiableSubschemas) {
const targetLabel = formatSubschemaLabel(target, "another subschema");
const mergeConfig = target.merge?.[parentTypeName];
const keyFields = mergeConfig?.selectionSet?.trim();
const keyPhrase = keyFields ? `using key fields ${keyFields} of "${parentTypeName}"` : `using key fields of "${parentTypeName}"`;
reasons.push(
`- cannot move to ${targetLabel} ${keyPhrase}; the key field(s) cannot be resolved from ${sourceLabel}.`
);
}
return `The following field cannot be satisfied by the subschemas:
${selection}
because:
- from ${sourceLabel}:
` + reasons.map((reason) => ` ${reason}`).join("\n");
}
function isSubschemaConfig(value) {
return Boolean(value?.schema);
}
function cloneSubschemaConfig(subschemaConfig) {
const newSubschemaConfig = {
...subschemaConfig,
transforms: subschemaConfig.transforms != null ? [...subschemaConfig.transforms] : void 0
};
if (newSubschemaConfig.merge != null) {
newSubschemaConfig.merge = { ...subschemaConfig.merge };
for (const typeName in newSubschemaConfig.merge) {
const mergedTypeConfig = newSubschemaConfig.merge[typeName] = {
...subschemaConfig.merge?.[typeName] ?? {}
};
if (mergedTypeConfig.entryPoints != null) {
mergedTypeConfig.entryPoints = mergedTypeConfig.entryPoints.map(
(entryPoint) => ({
...entryPoint
})
);
}
if (mergedTypeConfig.fields != null) {
const fields = mergedTypeConfig.fields = {
...mergedTypeConfig.fields
};
for (const fieldName in fields) {
fields[fieldName] = { ...fields[fieldName] };
}
}
}
}
return newSubschemaConfig;
}
const getFragmentDefinitions = utils.memoize1(
(info) => {
const fragmentMap = info.fragments;
return Object.values(fragmentMap);
}
);
function delegateToSchema(options) {
const {
info,
schema,
rootValue = schema.rootValue ?? info.rootValue,
operationName = info.operation.name?.value,
operation = getDelegatingOperation(info.parentType, info.schema),
fieldName = info.fieldName,
selectionSet,
fieldNodes = info.fieldNodes,
context,
args
} = options;
let targetSchema;
if (isSubschema(schema)) {
targetSchema = schema.transformedSchema;
} else if (graphql.isSchema(schema)) {
targetSchema = schema;
} else {
const stitchingInfo = info.schema.extensions?.["stitchingInfo"];
const subschema = stitchingInfo?.subschemaMap.get(schema);
if (subschema != null) {
targetSchema = subschema.transformedSchema;
} else {
targetSchema = applySchemaTransforms(schema.schema, schema);
}
}
const fragments = info ? getFragmentDefinitions(info) : void 0;
const targetRootType = operation === "mutation" ? targetSchema.getMutationType() : operation === "subscription" ? targetSchema.getSubscriptionType() : targetSchema.getQueryType();
const request = createRequest({
subgraphName: schema.name,
fragments,
targetSchema: targetRootType?.getFields()[fieldName] == null && isSubschemaConfig(schema) ? schema.schema : targetSchema,
rootValue,
targetOperationName: operationName,
targetOperation: operation,
targetFieldName: fieldName,
selectionSet,
fieldNodes,
context,
info,
args
});
return delegateRequest({
...options,
targetSchema,
request
});
}
function getDelegationReturnType(targetSchema, operation, fieldName) {
const rootType = utils.getDefinedRootType(targetSchema, operation);
const rootFieldType = rootType.getFields()[fieldName];
if (!rootFieldType) {
throw new Error(
`Unable to find field '${fieldName}' in type '${rootType}'.`
);
}
return rootFieldType.type;
}
function delegateRequest(options) {
const delegationContext = getDelegationContext(options);
const transformer = new Transformer(delegationContext);
const processedRequest = transformer.transformRequest(options.request);
if (options.validateRequest) {
validateRequest(delegationContext, processedRequest.document);
}
return promiseHelpers.handleMaybePromise(
() => getExecutor(delegationContext)(processedRequest),
function handleExecutorResult(executorResult) {
if (utils.isAsyncIterable(executorResult)) {
const isQuery = delegationContext.operation === "query";
const isListReturn = graphql.isListType(
graphql.getNullableType(delegationContext.returnType)
);
const isRootStream = isListReturn && fieldHasStreamDirective(delegationContext);
if (isQuery && isRootStream) {
return streamListIterable(executorResult, transformer);
}
if (isQuery && delegationContext.subschemaConfig?.defer) {
return consumeDeferredIterable(
executorResult,
transformer,
delegationContext
);
}
if (isQuery && isListReturn) {
return streamListIterable(executorResult, transformer);
}
return promiseHelpers.mapAsyncIterator(
executorResult,
(result) => transformer.transformResult(result)
);
}
return transformer.transformResult(executorResult);
}
);
}
function getDelegationContext({
request,
schema,
fieldName,
returnType,
info,
args,
transforms = [],
targetSchema: transformedSchema,
skipTypeMerging = false,
onLocatedError
}) {
const operationDefinition = utils.getOperationASTFromRequest(request);
let targetFieldName;
if (fieldName == null) {
targetFieldName = operationDefinition.selectionSet.selections[0].name.value;
} else {
targetFieldName = fieldName;
}
const stitchingInfo = info?.schema.extensions?.["stitchingInfo"];
const subschemaOrSubschemaConfig = stitchingInfo?.subschemaMap.get(schema) ?? schema;
const operation = operationDefinition.operation;
if (isSubschemaConfig(subschemaOrSubschemaConfig)) {
const targetSchema = subschemaOrSubschemaConfig.schema;
return {
subschema: schema,
subschemaConfig: subschemaOrSubschemaConfig,
targetSchema,
operation,
fieldName: targetFieldName,
context: request.context,
info,
returnType: returnType ?? info?.returnType ?? getDelegationReturnType(targetSchema, operation, targetFieldName),
transforms: subschemaOrSubschemaConfig.transforms != null ? subschemaOrSubschemaConfig.transforms.concat(transforms) : transforms,
transformedSchema,
skipTypeMerging,
onLocatedError,
args
};
}
return {
subschema: schema,
subschemaConfig: void 0,
targetSchema: subschemaOrSubschemaConfig,
operation,
fieldName: targetFieldName,
context: request.context,
info,
returnType: returnType ?? info?.returnType ?? getDelegationReturnType(
subschemaOrSubschemaConfig,
operation,
targetFieldName
),
transforms,
transformedSchema: transformedSchema ?? subschemaOrSubschemaConfig,
skipTypeMerging,
onLocatedError,
args
};
}
function validateRequest(delegationContext, document) {
const errors = graphql.validate(delegationContext.targetSchema, document);
if (errors.length > 0) {
if (errors.length > 1) {
const combinedError = new AggregateError(
errors,
errors.map((error2) => error2.message).join(", \n")
);
throw combinedError;
}
const error = errors[0];
if (error) {
throw error.originalError || error;
}
}
}
const GLOBAL_CONTEXT = {};
function getExecutor(delegationContext) {
const { subschemaConfig, targetSchema, context } = delegationContext;
let executor$1 = subschemaConfig?.executor || executor.executorFromSchema(targetSchema);
if (subschemaConfig?.batch) {
const batchingOptions = subschemaConfig?.batchingOptions;
executor$1 = batchExecute.getBatchingExecutor(
context ?? GLOBAL_CONTEXT,
executor$1,
batchingOptions?.dataLoaderOptions,
batchingOptions?.extensionsReducer,
batchingOptions?.defer ?? subschemaConfig.defer
);
}
return executor$1;
}
async function consumeDeferredIterable(executorResult, transformer, delegationContext) {
const iterator = executorResult[Symbol.asyncIterator]();
const receiver = new IncrementalReceiver(delegationContext);
let initialResult;
for (; ; ) {
const step = await iterator.next();
if (step.done) {
receiver.finish();
return null;
}
const data = step.value?.data?.[delegationContext.fieldName];
if (data !== void 0 || step.value?.hasNext === false) {
initialResult = step.value;
break;
}
}
const initialValue = await transformer.transformResult(initialResult);
if (initialValue != null && typeof initialValue === "object") {
receiver.attachTo(initialValue);
if (initialResult?.hasNext !== false) {
receiver.start(
transformDeferredChunks(
{ [Symbol.asyncIterator]: () => iterator },
transformer,
delegationContext,
initialValue
)
);
} else {
receiver.finish();
}
} else {
receiver.finish();
}
return initialValue;
}
async function* streamListIterable(executorResult, transformer) {
let pushedCount = 0;
for await (const result of executorResult) {
if (result.incremental) {
const data = {};
for (const incrementalRes of result.incremental) {
if (incrementalRes.items?.length) {
for (const item of incrementalRes.items) {
setObjectKeyPath(
data,
(incrementalRes.path || []).slice(0, -1),
item
);
}
yield await transformer.transformResult({ data });
}
}
if (result.hasNext === false) {
return;
}
continue;
}
const transformedResult = await transformer.transformResult(result);
if (Array.isArray(transformedResult)) {
for (let i = pushedCount; i < transformedResult.length; i++) {
yield await transformedResult[i];
pushedCount = i + 1;
}
} else {
yield await transformedResult;
}
}
}
function fieldHasStreamDirective(delegationContext) {
const fieldNodes = delegationContext.info?.fieldNodes;
if (fieldNodes == null) {
return false;
}
for (const fieldNode of fieldNodes) {
const directives = fieldNode.directives;
if (directives == null) {
continue;
}
for (let i = 0; i < directives.length; i++) {
if (directives[i].name.value === "stream") {
return true;
}
}
}
return false;
}
async function* transformDeferredChunks(iterable, transformer, delegationContext, initialValue) {
const fieldName = delegationContext.fieldName;
for await (const result of iterable) {
if (result?.incremental?.length) {
const lastPatchIndex = result.incremental.length - 1;
for (const [patchIndex, patch] of result.incremental.entries()) {
const hasNext = patchIndex < lastPatchIndex ? true : result.hasNext;
if (patch.items != null) {
const rewrittenPath = Array.isArray(patch.path) && patch.path.length > 0 ? applyErrorPathTransformers(
patch.path,
delegationContext
) : null;
yield {
incremental: [
rewrittenPath != null ? { ...patch, path: rewrittenPath } : patch
],
hasNext
};
continue;
}
if (patch.data != null && patch.path?.length) {
const rewrittenPath = applyErrorPathTransformers(
patch.path,
delegationContext
);
if (rewrittenPath != null) {
yield {
incremental: [
{
...patch,
path: rewrittenPath
}
],
hasNext
};
continue;
}
const tree = {};
setObjectKeyPath(tree, patch.path, {
...patch.data
});
if (tree[fieldName] != null && typeof tree[fieldName] === "object") {
const typename = resolvePatchTypename(
delegationContext,
initialValue
);
if (typename != null && tree[fieldName]["__typename"] == null) {
tree[fieldName]["__typename"] = typename;
}
}
try {
const transformedValue = await transformer.transformResult({
data: tree,
errors: patch.errors
});
if (transformedValue instanceof Error) {
yield {
incremental: [
{
path: [fieldName],
data: null,
errors: [transformedValue]
}
],
hasNext
};
} else if (transformedValue != null && typeof transformedValue === "object") {
yield {
data: { [fieldName]: transformedValue },
hasNext
};
} else {
yield {
incremental: [patch],
hasNext
};
}
} catch {
yield {
incremental: [patch],
hasNext
};
}
continue;
}
const rewrittenErrorPath = Array.isArray(patch.path) && patch.path.length > 0 ? applyErrorPathTransformers(
patch.path,
delegationContext
) : null;
yield {
incremental: [
rewrittenErrorPath != null ? { ...patch, path: rewrittenErrorPath } : patch
],
hasNext
};
}
} else if (result?.data) {
try {
const transformedValue = await transformer.transformResult(result);
if (transformedValue != null && typeof transformedValue === "object" && !(transformedValue instanceof Error)) {
yield {
data: { [fieldName]: transformedValue },
hasNext: result.hasNext
};
}
} catch {
}
} else if (result?.hasNext === false) {
yield { hasNext: false };
}
}
}
function applyErrorPathTransformers(path, delegationContext) {
const transforms = delegationContext.transforms ?? delegationContext.subschemaConfig?.transforms ?? [];
let next = path.slice();
let matched = false;
for (let i = transforms.length - 1; i >= 0; i--) {
const transform = transforms[i];
if (typeof transform.errorPathTransformer !== "function" || !Array.isArray(transform.path) || transform.path.length === 0) {
continue;
}
const prefix = transform.path;
let prefixMatches = true;
for (let j = 0; j < prefix.length; j++) {
if (next[j] !== prefix[j]) {
prefixMatches = false;
break;
}
}
if (!prefixMatches) {
continue;
}
matched = true;
next = [
...prefix,
...transform.errorPathTransformer(next.slice(prefix.length))
];
}
return matched ? next : null;
}
function resolvePatchTypename(delegationContext, initialValue) {
const transforms = delegationContext.transforms ?? delegationContext.subschemaConfig?.transforms ?? [];
for (const transform of transforms) {
const hoist = transform;
if (typeof hoist.typeName === "string" && typeof hoist.newFieldName === "string" && Array.isArray(hoist.pathToField)) {
return hoist.typeName;
}
}
const fromInitial = initialValue["__typename"];
return typeof fromInitial === "string" ? fromInitial : void 0;
}
function setObjectKeyPath(obj, path, value) {
let current = obj;
for (let i = 0; i < path.length - 1; i++) {
const key = path[i];
if (key == null || key === "__proto__" || key === "constructor" || key === "prototype") {
return;
}
if (current[key] == null) {
current[key] = typeof path[i + 1] === "number" ? [] : {};
}
current = current[key];
}
const lastKey = path[path.length - 1];
if (lastKey == null || lastKey === "__proto__" || lastKey === "constructor" || lastKey === "prototype") {
return;
}
const existingValue = current[lastKey];
current[lastKey] = existingValue ? utils.mergeDeep([existingValue, value]) : value;
}
function extractUnavailableFieldsFromSelectionSet(schema, fieldType, fieldSelectionSet, shouldAdd, fragments = {}) {
if (graphql.isLeafType(fieldType)) {
return [];
}
if (graphql.isUnionType(fieldType)) {
const unavailableSelections2 = [];
for (const type of fieldType.getTypes()) {
const fieldSelectionExcluded = {
...fieldSelectionSet,
selections: fieldSelectionSet.selections.filter(
(selection) => selection.kind === graphql.Kind.INLINE_FRAGMENT ? selection.typeCondition ? selection.typeCondition.name.value === type.name : false : true
)
};
unavailableSelections2.push(
...extractUnavailableFieldsFromSelectionSet(
schema,
type,
fieldSelectionExcluded,
shouldAdd,
fragments
)
);
}
return unavailableSelections2;
}
const subFields = fieldType.getFields();
const unavailableSelections = [];
for (const selection of fieldSelectionSet.selections) {
if (selection.kind === graphql.Kind.FIELD) {
if (selection.name.value === "__typename") {
continue;
}
const fieldName = selection.name.value;
const selectionField = subFields[fieldName];
if (!selectionField) {
if (shouldAdd(fieldType, selection)) {
unavailableSelections.push(selection);
}
} else {
const unavailableSubFields = extractUnavailableFields(
schema,
selectionField,
selection,
shouldAdd,
fragments
);
if (unavailableSubFields.length) {
unavailableSelections.push({
...selection,
selectionSet: {
kind: graphql.Kind.SELECTION_SET,
selections: unavailableSubFields
}
});
}
}
} else if (selection.kind === graphql.Kind.INLINE_FRAGMENT) {
const subFieldName = selection.typeCondition?.name.value || fieldType.name;
const subFieldType = selection.typeCondition && schema.getType(subFieldName) || fieldType;
if (subFieldName === fieldType.name || (graphql.isObjectType(subFieldType) || graphql.isInterfaceType(subFieldType)) && graphql.isAbstractType(fieldType) && schema.isSubType(fieldType, subFieldType)) {
const unavailableFields = extractUnavailableFieldsFromSelectionSet(
schema,
subFieldType,
selection.selectionSet,
shouldAdd,
fragments
);
if (unavailableFields.length) {
unavailableSelections.push({
...selection,
selectionSet: {
kind: graphql.Kind.SELECTION_SET,
selections: unavailableFields
}
});
}
} else if (graphql.isObjectType(subFieldType) || graphql.isInterfaceType(subFieldType)) {
const unavailableSubSelections = [];
const subFieldTypeFields = subFieldType.getFields();
for (const subSelection of selection.selectionSet.selections) {
if (subSelection.kind === graphql.Kind.FIELD) {
const subSelectionFieldName = subSelection.name.value;
if (subSelectionFieldName === "__typename") {
continue;
}
const subSelectionField = subFieldTypeFields[subSelection.name.value];
if (!subSelectionField) {
if (shouldAdd(subFieldType, subSelection)) {
unavailableSubSelections.push(subSelection);
}
}
}
}
if (unavailableSubSelections.length) {
unavailableSelections.push({
...selection,
selectionSet: {
kind: graphql.Kind.SELECTION_SET,
selections: unavailableSubSelections
}
});
}
}
} else if (selection.kind === graphql.Kind.FRAGMENT_SPREAD) {
const fragment = fragments[selection.name.value];
if (fragment) {
const fragmentUnavailableFields = extractUnavailableFieldsFromSelectionSet(
schema,
fieldType,
{
kind: graphql.Kind.SELECTION_SET,
selections: [
{
kind: graphql.Kind.INLINE_FRAGMENT,
typeCondition: {
kind: graphql.Kind.NAMED_TYPE,
name: {
kind: graphql.Kind.NAME,
value: fragment.typeCondition.name.value
}
},
selectionSet: fragment.selectionSet
}
]
},
shouldAdd,
fragments
);
if (fragmentUnavailableFields.length) {
unavailableSelections.push(...fragmentUnavailableFields);
}
}
}
}
return unavailableSelections;
}
function extractUnavailableFields(schema, field, fieldNode, shouldAdd, fragments = {}) {
if (fieldNode.selectionSet) {
const fieldType = graphql.getNamedType(field.type);
return extractUnavailableFieldsFromSelectionSet(
schema,
fieldType,
fieldNode.selectionSet,
shouldAdd,
fragments
);
}
return [];
}
function subtractSelectionSets(selectionSetA, selectionSetB, fragments = {}) {
const newSelections = [];
for (const selectionA of selectionSetA.selections) {
switch (selectionA.kind) {
case graphql.Kind.FIELD: {
const fieldA = selectionA;
const fieldsInOtherSelectionSet = selectionSetB.selections.filter(
(subselectionB) => {
if (subselectionB.kind !== graphql.Kind.FIELD) {
return false;
}
return fieldA.name.value === subselectionB.name.value;
}
);
if (fieldsInOtherSelectionSet.length > 0 && fieldA.selectionSet?.selections?.length) {
const newSubSelection = fieldsInOtherSelectionSet.reduce(
(acc, fieldB) => fieldB.selectionSet ? subtractSelectionSets(acc, fieldB.selectionSet, fragments) : acc,
{
kind: graphql.Kind.SELECTION_SET,
selections: fieldA.selectionSet.selections
}
);
if (newSubSelection.selections.length) {
newSelections.push({
...fieldA,
selectionSet: newSubSelection
});
}
} else if (fieldsInOtherSelectionSet.length === 0) {
newSelections.push(selectionA);
}
break;
}
case graphql.Kind.INLINE_FRAGMENT: {
const inlineFragmentA = selectionA;
const inlineFragmentsFromB = selectionSetB.selections.filter(
(subselectionB) => {
if (subselectionB.kind !== graphql.Kind.INLINE_FRAGMENT) {
return false;
}
const inlineFragmentB = subselectionB;
return inlineFragmentA.typeCondition?.name.value === inlineFragmentB.typeCondition?.name.value;
}
);
if (inlineFragmentsFromB.length > 0) {
const newSubSelection = inlineFragmentsFromB.reduce(
(acc, subselectionB) => subselectionB.selectionSet ? subtractSelectionSets(
acc,
subselectionB.selectionSet,
fragments
) : acc,
{
kind: graphql.Kind.SELECTION_SET,
selections: inlineFragmentA.selectionSet.selections
}
);
if (newSubSelection.selections.length) {
if (newSubSelection.selections.length === 1) {
const onlySelection = newSubSelection.selections[0];
if (onlySelection?.kind === graphql.Kind.FIELD) {
const responseKey = onlySelection.alias?.value || onlySelection.name.value;
if (responseKey === "__typename") {
continue;
}
}
}
newSelections.push({
...inlineFragmentA,
selectionSet: newSubSelection
});
}
} else {
newSelections.push(selectionA);
}
break;
}
case graphql.Kind.FRAGMENT_SPREAD: {
const fragmentSpreadA = selectionA;
const fragment = fragments[fragmentSpreadA.name.value];
if (fragment) {
const newSubSelection = subtractSelectionSets(
fragment.selectionSet,
selectionSetB,
fragments
);
if (newSubSelection.selections.length) {
newSelections.push({
kind: graphql.Kind.INLINE_FRAGMENT,
typeCondition: fragment.typeCondition,
directives: [
...fragment.directives ?? [],
...fragmentSpreadA.directives ?? []
],
selectionSet: newSubSelection
});
}
} else if (!selectionSetB.selections.some(
(subselectionB) => subselectionB.kind === graphql.Kind.FRAGMENT_SPREAD && subselectionB.name.value === fragmentSpreadA.name.value
)) {
newSelections.push(selectionA);
}
break;
}
}
}
return {
kind: graphql.Kind.SELECTION_SET,
selections: newSelections
};
}
Object.defineProperty(exports, "createDeferred", {
enumerable: true,
get: function () { return utils.createDeferred; }
});
Object.defineProperty(exports, "createDefaultExecutor", {
enumerable: true,
get: function () { return executor.executorFromSchema; }
});
exports.EMPTY_OBJECT = EMPTY_OBJECT;
exports.FIELD_SUBSCHEMA_MAP_SYMBOL = FIELD_SUBSCHEMA_MAP_SYMBOL;
exports.IncrementalReceiver = IncrementalReceiver;
exports.OBJECT_SUBSCHEMA_SYMBOL = OBJECT_SUBSCHEMA_SYMBOL;
exports.PLAN_LEFT_OVER = PLAN_LEFT_OVER;
exports.RECEIVER_SYMBOL = RECEIVER_SYMBOL;
exports.Subschema = Subschema;
exports.Transformer = Transformer;
exports.UNPATHED_ERRORS_SYMBOL = UNPATHED_ERRORS_SYMBOL;
exports.annotateExternalObject = annotateExternalObject;
exports.applySchemaTransforms = applySchemaTransforms;
exports.cloneSubschemaConfig = cloneSubschemaConfig;
exports.createRequest = createRequest;
exports.defaultMergedResolver = defaultMergedResolver;
exports.delegateRequest = delegateRequest;
exports.delegateToSchema = delegateToSchema;
exports.extractUnavailableFields = extractUnavailableFields;
exports.extractUnavailableFieldsFromSelectionSet = extractUnavailableFieldsFromSelectionSet;
exports.getActualFieldNodes = getActualFieldNodes;
exports.getCoercedVariableValues = getCoercedVariableValues;
exports.getDelegatingOperation = getDelegatingOperation;
exports.getGraphQLResolveInfo = getGraphQLResolveInfo;
exports.getPlanLeftOverFromParent = getPlanLeftOverFromParent;
exports.getReceiver = getReceiver;
exports.getSubschema = getSubschema;
exports.getTypeInfo = getTypeInfo;
exports.getTypeInfoWithType = getTypeInfoWithType;
exports.getUnpathedErrors = getUnpathedErrors;
exports.getVariableValues = getVariableValues;
exports.handleOverrideByDelegation = handleOverrideByDelegation;
exports.handleResolverResult = handleResolverResult;
exports.isExternalObject = isExternalObject;
exports.isPrototypePollutingKey = isPrototypePollutingKey;
exports.isSubschema = isSubschema;
exports.isSubschemaConfig = isSubschemaConfig;
exports.leftOverByDelegationPlan = leftOverByDelegationPlan;
exports.mergeFields = mergeFields;
exports.resolveExternalValue = resolveExternalValue;
exports.subtractSelectionSets = subtractSelectionSets;