@graphql-hive/router-runtime
Version:
1,620 lines (1,618 loc) • 64.3 kB
JavaScript
import { handleFederationSupergraph } from '@graphql-mesh/fusion-runtime';
import { createDefaultExecutor } from '@graphql-mesh/transport-common';
import { defaultPrintFn } from '@graphql-tools/executor-common';
import { filterInternalFieldsAndTypes, getRngFromEnv } from '@graphql-tools/federation';
import { isAsyncIterable, getOperationASTFromRequest, memoize1, getOperationASTFromDocument, relocatedError, mergeDeep, getDirective } from '@graphql-tools/utils';
import { handleMaybePromise, mapAsyncIterator, isPromise } from '@whatwg-node/promise-helpers';
import { parse, isObjectType, isAbstractType, Kind, isInterfaceType, isOutputType, TypeNameMetaFieldDef, getNamedType, isEnumType, isNonNullType, visit, BREAK } from 'graphql';
import { documentStringMap } from '@envelop/core';
import { getVariableValues, getFragmentsFromDocument } from '@graphql-tools/executor';
function isEntityRepresentation(obj) {
return obj?.__typename != null;
}
function executeQueryPlan({
queryPlan,
executionRequest,
onSubgraphExecute,
supergraphSchema
}) {
const node = queryPlan.node;
if (!node) {
throw new Error("Query plan has no root node.");
}
const executionContext = createQueryPlanExecutionContext({
supergraphSchema,
executionRequest,
onSubgraphExecute
});
function handleResp() {
const executionResult = {};
if (hasOwnProperties(executionContext.data)) {
executionResult.data = projectDataByOperation(executionContext);
}
if (executionContext.errors.length > 0) {
executionResult.errors = executionContext.errors;
}
return executionResult;
}
return handleMaybePromise(
() => executePlanNode(node, executionContext),
(res) => {
if (isAsyncIterable(res)) {
return mapAsyncIterator(res, handleResp);
}
return handleResp();
}
);
}
const globalEmpty = {};
const projectionArtifactsByDocument = /* @__PURE__ */ new WeakMap();
const compiledRequiresCache = /* @__PURE__ */ new WeakMap();
function createQueryPlanExecutionContext({
supergraphSchema,
executionRequest,
onSubgraphExecute
}) {
const { operation, fragments, compiledProjection } = getOrCreateCompiledProjectionArtifacts(executionRequest);
let variableValues = executionRequest.variables;
if (operation.variableDefinitions) {
const variableValuesResult = getVariableValues(
supergraphSchema,
operation.variableDefinitions,
variableValues || globalEmpty
);
if (variableValuesResult.errors?.length) {
if (variableValuesResult.errors.length === 1) {
throw variableValuesResult.errors[0];
}
if (variableValuesResult.errors.length > 1) {
throw new AggregateError(
variableValuesResult.errors,
"Variable parsing error"
);
}
}
if (variableValuesResult.coerced) {
variableValues = variableValuesResult.coerced;
}
}
return {
supergraphSchema,
operation,
fragments,
variableValues,
data: {},
errors: [],
onSubgraphExecute,
executionRequest,
compiledProjection,
projectionRuntimeCache: {
fieldMetaByParentType: /* @__PURE__ */ new WeakMap(),
inaccessibleByObjectType: /* @__PURE__ */ new WeakMap(),
enumProjectionValueByType: /* @__PURE__ */ new WeakMap(),
entityTypeConditionResult: /* @__PURE__ */ new Map()
}
};
}
function normalizeFlattenNodePath(path) {
const normalized = [];
for (const segment of path) {
if (segment === "@") {
normalized.push({ kind: "List" });
continue;
} else if ("Field" in segment) {
normalized.push({ kind: "Field", name: segment.Field });
} else if ("TypeCondition" in segment) {
normalized.push({ kind: "Cast", typeCondition: segment.TypeCondition });
} else {
throw new Error(
`Unsupported flatten path segment received from query planner: ${JSON.stringify(segment)}`
);
}
}
return normalized;
}
function collectFlattenEntities(source, pathSegments, supergraphSchema) {
const entities = [];
const activePath = [];
traverseFlattenPath(
source,
pathSegments,
0,
supergraphSchema,
activePath,
(value, path) => {
if (Array.isArray(value)) {
for (let index = 0; index < value.length; index++) {
const item = value[index];
if (item && typeof item === "object") {
path.push(index);
entities.push({
entity: item,
path: path.slice()
});
path.pop();
}
}
return;
}
if (value && typeof value === "object") {
entities.push({
entity: value,
path: path.slice()
});
}
}
);
return entities;
}
function traverseFlattenPath(current, pathSegments, pathIndex, supergraphSchema, path, callback) {
if (current == null) {
return;
}
const segment = pathSegments[pathIndex];
if (!segment) {
callback(current, path);
return;
}
switch (segment.kind) {
case "Field": {
if (Array.isArray(current)) {
for (const item of current) {
traverseFlattenPath(
item,
pathSegments,
pathIndex,
supergraphSchema,
path,
callback
);
}
return;
}
if (typeof current === "object") {
path.push(segment.name);
const next = current[segment.name];
traverseFlattenPath(
next,
pathSegments,
pathIndex + 1,
supergraphSchema,
path,
callback
);
path.pop();
}
return;
}
case "List": {
if (Array.isArray(current)) {
for (let index = 0; index < current.length; index++) {
path.push(index);
traverseFlattenPath(
current[index],
pathSegments,
pathIndex + 1,
supergraphSchema,
path,
callback
);
path.pop();
}
}
return;
}
case "Cast": {
if (Array.isArray(current)) {
for (const item of current) {
traverseFlattenPath(
item,
pathSegments,
pathIndex,
supergraphSchema,
path,
callback
);
}
return;
}
if (typeof current === "object") {
const value = current;
const candidateTypenames = typeof value.__typename === "string" ? [value.__typename] : segment.typeCondition;
if (candidateTypenames.some(
(typeName) => entitySatisfiesTypeCondition(
supergraphSchema,
typeName,
segment.typeCondition
)
)) {
traverseFlattenPath(
current,
pathSegments,
pathIndex + 1,
supergraphSchema,
path,
callback
);
}
}
}
}
}
function prepareFlattenContext(flattenNode, executionContext) {
if (!flattenNode.node || flattenNode.node.kind !== "Fetch") {
return null;
}
const fetchNode = flattenNode.node;
const requires = fetchNode.requires;
if (!requires || requires.length === 0) {
return null;
}
const pathSegments = normalizeFlattenNodePath(flattenNode.path);
const entityLocations = collectFlattenEntities(
executionContext.data,
pathSegments,
executionContext.supergraphSchema
);
if (entityLocations.length === 0) {
return null;
}
const entityRefs = [];
const entityPaths = [];
const representationOrder = [];
const dedupedRepresentations = [];
const hashToEntry = /* @__PURE__ */ new Map();
for (const location of entityLocations) {
const entityRef = location.entity;
if (!isEntityRepresentation(entityRef)) {
continue;
}
let representation = projectRequires(
requires,
entityRef,
executionContext.supergraphSchema
);
if (!representation || Array.isArray(representation)) {
continue;
}
representation.__typename ??= entityRef.__typename;
if (fetchNode.inputRewrites?.length) {
representation = applyInputRewrites(
representation,
fetchNode.inputRewrites,
executionContext.supergraphSchema
);
}
const hashKey = stableStringify(representation);
let bucket = hashToEntry.get(hashKey);
let dedupIndex;
if (!bucket) {
dedupIndex = dedupedRepresentations.length;
const canonical = canonicalEncodeEntity(representation);
hashToEntry.set(hashKey, [[canonical, dedupIndex]]);
dedupedRepresentations.push(representation);
} else {
const canonical = canonicalEncodeEntity(representation);
const existing = findInBucket(bucket, canonical);
if (existing !== void 0) {
dedupIndex = existing;
} else {
dedupIndex = dedupedRepresentations.length;
bucket.push([canonical, dedupIndex]);
dedupedRepresentations.push(representation);
}
}
entityRefs.push(entityRef);
entityPaths.push(location.path);
representationOrder.push(dedupIndex);
}
if (dedupedRepresentations.length === 0) {
return null;
}
let errorPath;
for (const segment of pathSegments) {
if (segment.kind === "Field") {
(errorPath ??= []).push(segment.name);
}
}
return {
entityRefs,
dedupedRepresentations,
entityPaths,
representationOrder,
errorPath
};
}
function prepareBatchFetchContext(batchFetchNode, executionContext) {
const byAlias = /* @__PURE__ */ new Map();
const representationsByVariableName = /* @__PURE__ */ new Map();
for (const alias of batchFetchNode.entityBatch.aliases) {
const requires = alias.requires;
if (!requires || requires.length === 0) {
continue;
}
const pathStates = [];
const entityPathsByRepresentationIndex = /* @__PURE__ */ new Map();
const representationsVariableName = alias.representationsVariableName;
let variableBatchState = representationsByVariableName.get(
representationsVariableName
);
if (!variableBatchState) {
variableBatchState = {
representations: [],
identityToEntityIndex: /* @__PURE__ */ new Map()
};
representationsByVariableName.set(
representationsVariableName,
variableBatchState
);
}
const ensuredVariableBatchState = variableBatchState;
for (const path of alias.paths) {
const normalizedPath = normalizeFlattenNodePath(path);
const entityLocations = collectFlattenEntities(
executionContext.data,
normalizedPath,
executionContext.supergraphSchema
);
const entityRefs = [];
const entityPaths = [];
const representationIndexByTarget = [];
for (const location of entityLocations) {
const entityRef = location.entity;
if (!isEntityRepresentation(entityRef)) {
continue;
}
let representation = projectRequires(
requires,
entityRef,
executionContext.supergraphSchema
);
if (!representation || Array.isArray(representation)) {
continue;
}
representation.__typename ??= entityRef.__typename;
if (alias.inputRewrites?.length) {
representation = applyInputRewrites(
representation,
alias.inputRewrites,
executionContext.supergraphSchema
);
}
const hashKey = stableStringify(representation);
let bucket = ensuredVariableBatchState.identityToEntityIndex.get(hashKey);
let dedupIndex;
if (!bucket) {
dedupIndex = ensuredVariableBatchState.representations.length;
const canonical = canonicalEncodeEntity(representation);
ensuredVariableBatchState.identityToEntityIndex.set(hashKey, [
[canonical, dedupIndex]
]);
ensuredVariableBatchState.representations.push(representation);
} else {
const canonical = canonicalEncodeEntity(representation);
const existing = findInBucket(bucket, canonical);
if (existing !== void 0) {
dedupIndex = existing;
} else {
dedupIndex = ensuredVariableBatchState.representations.length;
bucket.push([canonical, dedupIndex]);
ensuredVariableBatchState.representations.push(representation);
}
}
entityRefs.push(entityRef);
entityPaths.push(location.path);
representationIndexByTarget.push(dedupIndex);
let pathsForRepresentation = entityPathsByRepresentationIndex.get(dedupIndex);
if (!pathsForRepresentation) {
pathsForRepresentation = [];
entityPathsByRepresentationIndex.set(
dedupIndex,
pathsForRepresentation
);
}
pathsForRepresentation.push(location.path);
}
pathStates.push({
entityRefs,
entityPaths,
representationIndexByTarget
});
}
byAlias.set(alias.alias, {
alias: alias.alias,
pathStates,
entityPathsByRepresentationIndex,
outputRewrites: alias.outputRewrites
});
}
let hasRepresentations = false;
for (const state of representationsByVariableName.values()) {
if (state.representations.length > 0) {
hasRepresentations = true;
break;
}
}
if (!hasRepresentations) {
return null;
}
return {
byAlias,
representationsByVariableName
};
}
function buildBatchFetchVariables(batchContext, selectedVariables) {
let variablesForFetch;
if (selectedVariables) {
variablesForFetch = { ...selectedVariables };
}
for (const [
variableName,
state
] of batchContext.representationsByVariableName.entries()) {
if (!state.representations.length) {
continue;
}
const targetVariables = variablesForFetch ?? /* @__PURE__ */ Object.create(null);
if (!variablesForFetch) {
variablesForFetch = targetVariables;
}
targetVariables[variableName] = state.representations;
}
return variablesForFetch;
}
function applyBatchAliasEntities(returnedEntities, aliasContext) {
for (const pathContext of aliasContext.pathStates) {
const { entityRefs, representationIndexByTarget } = pathContext;
for (let index = 0; index < entityRefs.length; index++) {
const target = entityRefs[index];
const dedupIndex = representationIndexByTarget[index];
if (dedupIndex == null) {
continue;
}
const entity = returnedEntities[dedupIndex];
if (!target || !entity) {
continue;
}
mergeEntityPayload(target, entity);
}
}
}
function normalizeBatchFetchErrors(errors, batchContext) {
if (!errors.length) {
return [];
}
const relocated = [];
for (const error of errors) {
const errorPath = error.path;
if (!errorPath || errorPath.length === 0) {
relocated.push(error);
continue;
}
const aliasName = errorPath[0];
if (typeof aliasName !== "string") {
relocated.push(error);
continue;
}
const aliasContext = batchContext.byAlias.get(aliasName);
if (!aliasContext) {
relocated.push(error);
continue;
}
const entityIndex = errorPath[1];
if (typeof entityIndex !== "number") {
relocated.push(error);
continue;
}
const mappedPaths = aliasContext.entityPathsByRepresentationIndex.get(entityIndex);
if (!mappedPaths?.length) {
relocated.push(error);
continue;
}
const tailStart = 2;
const tailLen = errorPath.length - tailStart;
for (const mappedPath of mappedPaths) {
const newPath = new Array(mappedPath.length + tailLen);
let i = 0;
for (let j = 0; j < mappedPath.length; j++) {
newPath[i++] = mappedPath[j];
}
for (let j = tailStart; j < errorPath.length; j++) {
newPath[i++] = errorPath[j];
}
relocated.push(relocatedError(error, newPath));
}
}
return relocated;
}
function executeBatchFetchPlanNode(batchFetchNode, executionContext, batchContext) {
const selectedVariables = selectFetchVariables(
executionContext.variableValues,
batchFetchNode.variableUsages
);
const variablesForFetch = buildBatchFetchVariables(
batchContext,
selectedVariables
);
const handleBatchResult = (fetchResult) => {
if (isAsyncIterable(fetchResult)) {
return mapAsyncIterator(fetchResult, handleBatchResult);
}
if (fetchResult.errors?.length) {
executionContext.errors.push(
...normalizeBatchFetchErrors(fetchResult.errors, batchContext)
);
}
const responseData = fetchResult.data;
if (!responseData || typeof responseData !== "object") {
return;
}
for (const [aliasName, aliasContext] of batchContext.byAlias.entries()) {
let aliasData = responseData[aliasName];
if (!aliasData) {
continue;
}
if (aliasContext.outputRewrites?.length) {
aliasData = applyOutputRewrites(
aliasData,
aliasContext.outputRewrites,
executionContext.supergraphSchema
);
}
if (Array.isArray(aliasData)) {
applyBatchAliasEntities(
aliasData,
aliasContext
);
}
}
return;
};
return handleMaybePromise(
() => executionContext.onSubgraphExecute(batchFetchNode.serviceName, {
document: getDocumentNodeOfFetchingNode(batchFetchNode),
variables: variablesForFetch,
operationType: batchFetchNode.operationKind ?? executionContext.operation.operation,
operationName: batchFetchNode.operationName,
extensions: executionContext.executionRequest.extensions,
rootValue: executionContext.executionRequest.rootValue,
context: executionContext.executionRequest.context,
subgraphName: batchFetchNode.serviceName,
info: executionContext.executionRequest.info,
signal: executionContext.executionRequest.signal
}),
handleBatchResult
);
}
function executeFetchPlanNode(fetchNode, executionContext, state) {
const flattenState = state?.flatten;
let representationTargets = flattenState?.entityRefs ?? state?.representations;
let preparedRepresentations;
if (flattenState) {
if (!flattenState.dedupedRepresentations.length) {
return;
}
preparedRepresentations = flattenState.dedupedRepresentations;
} else if (representationTargets?.length) {
const requires = fetchNode.requires;
const nextTargets = [];
const payloads = [];
for (const entity of representationTargets) {
if (requires) {
let satisfies = false;
for (const requiresNode of requires) {
if (entity && entitySatisfiesTypeCondition(
executionContext.supergraphSchema,
entity.__typename,
requiresNode.kind === "InlineFragment" ? requiresNode.typeCondition : void 0
)) {
satisfies = true;
break;
}
}
if (!satisfies) {
continue;
}
}
let projection = requires ? projectRequires(
requires,
entity,
executionContext.supergraphSchema
) : entity;
if (!projection || Array.isArray(projection)) {
continue;
}
projection.__typename ??= entity.__typename;
if (fetchNode.inputRewrites?.length) {
projection = applyInputRewrites(
projection,
fetchNode.inputRewrites,
executionContext.supergraphSchema
);
}
payloads.push(projection);
nextTargets.push(entity);
}
if (!payloads.length) {
return;
}
representationTargets = nextTargets;
preparedRepresentations = payloads;
}
const selectedVariables = selectFetchVariables(
executionContext.variableValues,
fetchNode.variableUsages
);
let variablesForFetch;
if (preparedRepresentations?.length) {
variablesForFetch = {
representations: preparedRepresentations
};
}
if (selectedVariables) {
variablesForFetch = variablesForFetch ? { ...selectedVariables, ...variablesForFetch } : { ...selectedVariables };
}
const defaultErrorPath = state?.errorPath ?? state?.flatten?.errorPath ?? getDefaultErrorPath(fetchNode);
const handleFetchResult = (fetchResult) => {
if (isAsyncIterable(fetchResult)) {
return mapAsyncIterator(fetchResult, handleFetchResult);
}
if (fetchResult.errors?.length) {
const normalizedErrors = normalizeFetchErrors(fetchResult.errors, {
fetchNode,
state,
defaultPath: defaultErrorPath
});
if (normalizedErrors.length) {
executionContext.errors.push(...normalizedErrors);
}
}
const responseData = fetchNode.outputRewrites ? applyOutputRewrites(
fetchResult.data,
fetchNode.outputRewrites,
executionContext.supergraphSchema
) : fetchResult.data;
if (!responseData) {
return;
}
if (flattenState && flattenState.entityRefs.length) {
const returnedEntities = responseData._entities;
if (Array.isArray(returnedEntities)) {
mergeFlattenEntities(returnedEntities, flattenState);
}
return;
}
if (representationTargets?.length && responseData._entities) {
const returnedEntities = responseData._entities;
for (let index = 0; index < returnedEntities.length; index++) {
const entity = returnedEntities[index];
const target = representationTargets[index];
if (target && entity) {
mergeEntityPayload(target, entity);
}
}
return;
}
mergeEntityPayload(executionContext.data, responseData);
return;
};
return handleMaybePromise(
() => executionContext.onSubgraphExecute(fetchNode.serviceName, {
document: getDocumentNodeOfFetchingNode(fetchNode),
variables: variablesForFetch,
operationType: fetchNode.operationKind ?? executionContext.operation.operation,
operationName: fetchNode.operationName,
extensions: executionContext.executionRequest.extensions,
rootValue: executionContext.executionRequest.rootValue,
context: executionContext.executionRequest.context,
subgraphName: fetchNode.serviceName,
info: executionContext.executionRequest.info,
signal: executionContext.executionRequest.signal
}),
handleFetchResult
);
}
function selectFetchVariables(variableValues, variableUsages) {
if (!variableValues || !variableUsages || variableUsages.length === 0) {
return void 0;
}
const selected = /* @__PURE__ */ Object.create(null);
let hasValue = false;
for (const variableName of variableUsages) {
if (Object.prototype.hasOwnProperty.call(variableValues, variableName)) {
selected[variableName] = variableValues[variableName];
hasValue = true;
}
}
return hasValue ? selected : void 0;
}
function normalizeFetchErrors(errors, options) {
if (!errors.length) {
return [];
}
const { fetchNode, state } = options;
const flattenState = state?.flatten;
const fallbackPath = options.defaultPath ?? getDefaultErrorPath(fetchNode);
if (!flattenState) {
if (!fallbackPath) {
return [...errors];
}
return errors.map((error) => relocatedError(error, fallbackPath));
}
const entityPathMap = buildFlattenEntityPathMap(flattenState);
const relocated = [];
for (const error of errors) {
const errorPath = error.path;
if (errorPath) {
const entityIndexPosition = errorPath.indexOf("_entities");
if (entityIndexPosition !== -1) {
const dedupIndex = errorPath[entityIndexPosition + 1];
if (typeof dedupIndex === "number") {
const mappedPaths = entityPathMap.get(dedupIndex);
if (mappedPaths && mappedPaths.length) {
const tailStart = entityIndexPosition + 2;
const tailLen = errorPath.length - tailStart;
for (const mappedPath of mappedPaths) {
const newPath = new Array(
mappedPath.length + tailLen
);
let i = 0;
for (let j = 0; j < mappedPath.length; j++) {
newPath[i++] = mappedPath[j];
}
for (let j = tailStart; j < errorPath.length; j++) {
newPath[i++] = errorPath[j];
}
relocated.push(relocatedError(error, newPath));
}
continue;
}
}
}
}
if (fallbackPath) {
relocated.push(relocatedError(error, fallbackPath));
} else {
relocated.push(error);
}
}
return relocated;
}
function buildFlattenEntityPathMap(flattenState) {
const map = /* @__PURE__ */ new Map();
flattenState.representationOrder.forEach((dedupIndex, index) => {
const existing = map.get(dedupIndex);
if (existing) {
existing.push(flattenState.entityPaths[index]);
} else {
map.set(dedupIndex, [flattenState.entityPaths[index]]);
}
});
return map;
}
function mergeFlattenEntities(returnedEntities, flattenState) {
const { entityRefs, representationOrder } = flattenState;
for (let index = 0; index < entityRefs.length; index++) {
const target = entityRefs[index];
const dedupIndex = representationOrder[index];
const entity = returnedEntities[dedupIndex];
if (!target || !entity) {
continue;
}
mergeEntityPayload(target, entity);
}
}
function applyInputRewrites(representation, rewrites, supergraphSchema) {
let current = representation;
for (const rewrite of rewrites) {
const normalizedRewrite = normalizeRewrite(rewrite);
if (!normalizedRewrite) {
continue;
}
switch (normalizedRewrite.kind) {
case "ValueSetter":
current = applyValueSetter(
current,
normalizedRewrite.path,
normalizedRewrite.setValueTo,
supergraphSchema
);
break;
case "KeyRenamer":
applyKeyRenamer(
current,
normalizedRewrite.path,
normalizedRewrite.renameKeyTo,
supergraphSchema
);
break;
}
}
return current;
}
function applyOutputRewrites(data, rewrites, supergraphSchema) {
let current = data;
if (!current) {
return current;
}
for (const rewrite of rewrites) {
const normalizedRewrite = normalizeRewrite(rewrite);
if (!normalizedRewrite) {
continue;
}
switch (normalizedRewrite.kind) {
case "KeyRenamer":
applyKeyRenamer(
current,
normalizedRewrite.path,
normalizedRewrite.renameKeyTo,
supergraphSchema
);
break;
case "ValueSetter":
current = applyValueSetter(
current,
normalizedRewrite.path,
normalizedRewrite.setValueTo,
supergraphSchema
);
break;
}
}
return current;
}
const getDocumentNodeOfFetchingNode = memoize1(
function getDocumentNodeOfFetchNode(fetchingNode) {
const doc = parse(fetchingNode.operation, { noLocation: true });
documentStringMap.set(doc, fetchingNode.operation);
return doc;
}
);
const getDefaultErrorPath = memoize1(function getDefaultErrorPath2(fetchNode) {
const document = getDocumentNodeOfFetchingNode(fetchNode);
const operationAst = getOperationASTFromDocument(
document,
fetchNode.operationName
);
if (!operationAst) {
return [];
}
const rootSelection = operationAst.selectionSet.selections.find(
(selection) => selection.kind === Kind.FIELD
);
if (!rootSelection) {
return [];
}
const responseKey = rootSelection.alias?.value ?? rootSelection.name.value;
return responseKey ? [responseKey] : [];
});
function stableStringify(value) {
return hashValueOrderIndependent32Ultra(value);
}
function hasOwnProperties(obj) {
for (const _key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, _key)) {
return true;
}
}
return false;
}
function findInBucket(bucket, canonical) {
for (let i = 0; i < bucket.length; i++) {
if (bucket[i][0] === canonical) {
return bucket[i][1];
}
}
return void 0;
}
function canonicalEncodeEntity(value) {
if (value === null) {
return "N";
}
const t = typeof value;
if (t === "string") {
const v = value;
return `s${v.length}:${v}`;
}
if (t === "number") {
const n = value;
if (!Number.isFinite(n)) {
return `n~${n}`;
}
return `n${Object.is(n, -0) ? 0 : n}`;
}
if (t === "boolean") {
return value ? "b1" : "b0";
}
if (Array.isArray(value)) {
const arr = value;
let result = `A${arr.length}[`;
for (let i = 0; i < arr.length; i++) {
if (i > 0) result += ",";
result += canonicalEncodeEntity(arr[i]);
}
return result + "]";
}
if (t === "object") {
const obj = value;
const sortedKeys = Object.keys(obj).sort();
const definedKeys = [];
for (let i = 0; i < sortedKeys.length; i++) {
const k = sortedKeys[i];
if (obj[k] !== void 0) {
definedKeys.push(k);
}
}
let result = `O${definedKeys.length}{`;
for (let i = 0; i < definedKeys.length; i++) {
const k = definedKeys[i];
result += `k${k.length}:${k}=${canonicalEncodeEntity(obj[k])}`;
}
return result + "}";
}
try {
return `X${JSON.stringify(value)}`;
} catch {
return `X${String(value)}`;
}
}
function executePlanNode(planNode, executionContext, state) {
switch (planNode.kind) {
case "Sequence": {
let pending = null;
let nextState = state;
for (const node of planNode.nodes) {
const currentState = nextState;
nextState = void 0;
pending = handleMaybePromise(
() => pending,
() => executePlanNode(node, executionContext, currentState)
);
}
return pending;
}
case "Parallel": {
const promises = [];
planNode.nodes.forEach((node, index) => {
const maybePromise = executePlanNode(
node,
executionContext,
index === 0 ? state : void 0
);
if (isPromise(maybePromise)) {
promises.push(maybePromise);
}
});
if (promises.length === 1) {
return promises[0];
}
if (promises.length === 0) {
return;
}
return Promise.all(promises);
}
case "Flatten": {
const flattenContext = prepareFlattenContext(planNode, executionContext);
if (!flattenContext) {
return;
}
const errorPath = flattenContext.errorPath && flattenContext.errorPath.length ? [...flattenContext.errorPath] : void 0;
return executePlanNode(planNode.node, executionContext, {
representations: flattenContext.entityRefs,
errorPath,
flatten: flattenContext
});
}
case "Fetch": {
return executeFetchPlanNode(planNode, executionContext, state);
}
case "BatchFetch": {
const batchContext = prepareBatchFetchContext(planNode, executionContext);
if (!batchContext) {
return;
}
return executeBatchFetchPlanNode(
planNode,
executionContext,
batchContext
);
}
case "Condition": {
const conditionValue = executionContext.variableValues?.[planNode.condition];
if (conditionValue === true) {
if (planNode.ifClause) {
return executePlanNode(planNode.ifClause, executionContext);
}
} else if (planNode.elseClause) {
return executePlanNode(planNode.elseClause, executionContext);
}
break;
}
case "Subscription": {
return executePlanNode(planNode.primary, executionContext);
}
default:
throw new Error(`Invalid plan node: ${JSON.stringify(planNode)}`);
}
}
function normalizeRewrite(rewrite) {
if ("kind" in rewrite && rewrite.kind === "ValueSetter") {
return {
...rewrite,
path: normalizeRewritePath(rewrite.path)
};
}
if ("ValueSetter" in rewrite) {
return {
kind: "ValueSetter",
path: normalizeRewritePath(rewrite.ValueSetter?.path),
setValueTo: rewrite.ValueSetter?.setValueTo
};
}
if ("KeyRenamer" in rewrite) {
return {
kind: "KeyRenamer",
path: normalizeRewritePath(rewrite.KeyRenamer?.path),
renameKeyTo: rewrite.KeyRenamer?.renameKeyTo
};
}
throw new Error(`Unsupported fetch node rewrite: ${JSON.stringify(rewrite)}`);
}
function normalizeRewritePath(path) {
const normalized = [];
for (const segment of path) {
if ("TypenameEquals" in segment) {
normalized.push(`... on ${segment.TypenameEquals}`);
} else if ("Key" in segment) {
normalized.push(segment.Key);
} else {
throw new Error(
`Unsupported fetch node path segment: ${JSON.stringify(segment)}`
);
}
}
return normalized;
}
function applyKeyRenamer(entityRepresentation, path, renameKeyTo, supergraphSchema) {
const keyProp = path[0];
if (!keyProp) {
throw new Error("Invalid key prop");
}
const nextPath = path.slice(1);
if (keyProp.startsWith("... on")) {
const typeCondition = keyProp.split("... on ")[1];
if (isEntityRepresentation(entityRepresentation) && typeCondition && !entitySatisfiesTypeCondition(
supergraphSchema,
entityRepresentation.__typename,
typeCondition
)) {
return;
}
return applyKeyRenamer(
entityRepresentation,
nextPath,
renameKeyTo,
supergraphSchema
);
}
if (path.length === 1) {
entityRepresentation[renameKeyTo] = entityRepresentation[keyProp];
delete entityRepresentation[keyProp];
return;
}
const nextData = entityRepresentation[keyProp];
if (nextData == null) {
return;
}
if (Array.isArray(nextData)) {
return nextData.map(
(item) => applyKeyRenamer(item, nextPath, renameKeyTo, supergraphSchema)
);
}
return applyKeyRenamer(nextData, nextPath, renameKeyTo, supergraphSchema);
}
function applyValueSetter(data, path, setValueTo, supergraphSchema) {
if (Array.isArray(data)) {
return data.map(
(item) => applyValueSetter(item, path, setValueTo, supergraphSchema)
);
}
const keyProp = path[0];
if (!keyProp) {
return setValueTo;
}
const nextPath = path.slice(1);
if (keyProp.startsWith("... on")) {
const typeCondition = keyProp.split("... on ")[1];
if (!typeCondition) {
throw new Error("Invalid type condition");
}
if (isEntityRepresentation(data) && !entitySatisfiesTypeCondition(
supergraphSchema,
data.__typename,
typeCondition
)) {
return data;
}
return applyValueSetter(data, nextPath, setValueTo, supergraphSchema);
}
if (path.length === 1) {
const existingValue = data[keyProp];
if (existingValue === setValueTo) {
return data;
}
return {
...data,
[keyProp]: setValueTo
};
}
const nextData = data[keyProp];
if (nextData == null) {
return data;
}
return {
...data,
[keyProp]: applyValueSetter(
nextData,
nextPath,
setValueTo,
supergraphSchema
)
};
}
function entitySatisfiesTypeCondition(supergraphSchema, typeNameInEntity, typeConditionInInlineFragment) {
if (!typeConditionInInlineFragment) {
return false;
}
const normalizedTypeConditions = Array.isArray(typeConditionInInlineFragment) ? typeConditionInInlineFragment : [typeConditionInInlineFragment];
if (normalizedTypeConditions.includes(typeNameInEntity)) {
return true;
}
const entityType = supergraphSchema.getType(typeNameInEntity);
if (!isObjectType(entityType)) {
return false;
}
for (const typeCondition of normalizedTypeConditions) {
const conditionType = supergraphSchema.getType(typeCondition);
if (isAbstractType(conditionType) && supergraphSchema.isSubType(conditionType, entityType)) {
return true;
}
}
return false;
}
function projectSelectionSet(data, selectionSet, type, executionContext) {
if (data == null) {
return data;
}
if (Array.isArray(data)) {
return data.map(
(item) => projectSelectionSet(item, selectionSet, type, executionContext)
);
}
const parentType = isEntityRepresentation(data) ? executionContext.supergraphSchema.getType(data.__typename) : type;
if (!isObjectType(parentType) && !isInterfaceType(parentType)) {
return null;
}
if (isObjectType(parentType) && isInaccessibleObjectType(parentType, executionContext)) {
return null;
}
const result = {};
for (const selection of selectionSet.selections) {
if (!shouldIncludeCompiledSelection(
selection.directiveConditions,
executionContext.variableValues
)) {
continue;
}
if (selection.kind === "Field") {
const fieldMeta = getProjectionFieldMeta(
parentType,
selection.fieldName,
executionContext
);
if (!fieldMeta) {
throw new Error(
`Field not found: ${selection.fieldName} on ${parentType.name}`
);
}
const responseKey = selection.responseKey;
let projectedValue = selection.selectionSet ? projectSelectionSet(
data[responseKey],
selection.selectionSet,
fieldMeta.namedType,
executionContext
) : data[responseKey];
if (projectedValue !== void 0) {
if (fieldMeta.enumType) {
projectedValue = projectEnumValue(
projectedValue,
fieldMeta.enumType,
executionContext
);
}
if (result[responseKey] == null) {
result[responseKey] = projectedValue;
} else if (typeof result[responseKey] === "object" && projectedValue != null) {
result[responseKey] = mergeProjectedFieldValue(
result[responseKey],
projectedValue
);
} else {
result[responseKey] = projectedValue;
}
} else if (fieldMeta.field.name === "__typename") {
result[responseKey] = type.name;
} else if (fieldMeta.isNonNull) {
return null;
} else {
result[responseKey] = null;
}
} else if (selection.kind === "InlineFragment") {
const typeCondition = selection.typeCondition;
if (isEntityRepresentation(data)) {
if (typeCondition && !entitySatisfiesTypeConditionCached(
executionContext,
data.__typename,
typeCondition
)) {
continue;
}
const typeByTypename = executionContext.supergraphSchema.getType(
data.__typename
);
if (!isOutputType(typeByTypename)) {
throw new Error("Invalid type");
}
const projectedValue = projectSelectionSet(
data,
selection.selectionSet,
typeByTypename,
executionContext
);
mergeProjectedSelectionObject(result, projectedValue);
} else {
if (typeCondition && !entitySatisfiesTypeConditionCached(
executionContext,
parentType.name,
typeCondition
)) {
continue;
}
const projectedValue = projectSelectionSet(
data,
selection.selectionSet,
typeCondition ? executionContext.supergraphSchema.getType(typeCondition) : parentType,
executionContext
);
mergeProjectedSelectionObject(result, projectedValue);
}
} else if (selection.kind === "FragmentSpread") {
const fragment = executionContext.compiledProjection.fragments[selection.fragmentName];
if (!fragment) {
throw new Error(`Fragment "${selection.fragmentName}" not found`);
}
const typeCondition = fragment.typeCondition;
if (isEntityRepresentation(data) && typeCondition && !entitySatisfiesTypeConditionCached(
executionContext,
data.__typename,
typeCondition
)) {
continue;
}
const typeByTypename = executionContext.supergraphSchema.getType(
data.__typename || typeCondition
);
if (!isOutputType(typeByTypename)) {
throw new Error("Invalid type");
}
const projectedValue = projectSelectionSet(
data,
fragment.selectionSet,
typeByTypename,
executionContext
);
mergeProjectedSelectionObject(result, projectedValue);
}
}
return result;
}
function projectDataByOperation(executionContext) {
const rootType = executionContext.supergraphSchema.getRootType(
executionContext.operation.operation
);
if (!rootType) {
throw new Error("Root type not found");
}
return projectSelectionSet(
executionContext.data,
executionContext.compiledProjection.rootSelectionSet,
rootType,
executionContext
);
}
function projectRequires(requiresSelections, entity, supergraphSchema) {
if (!entity) {
return entity;
}
const runtime = {
supergraphSchema,
entityTypeConditionResult: /* @__PURE__ */ new Map()
};
const compiledRequiresSelections = getOrCompileRequiresSelections(requiresSelections);
return projectRequiresCompiled(compiledRequiresSelections, entity, runtime);
}
function projectRequiresCompiled(requiresSelections, entity, runtime) {
if (!entity) {
return entity;
}
if (Array.isArray(entity)) {
return entity.map(
(item) => projectRequiresCompiled(requiresSelections, item, runtime)
);
}
let result = null;
for (const requiresSelection of requiresSelections) {
switch (requiresSelection.kind) {
case "Field": {
let original = entity[requiresSelection.fieldName];
if (original === void 0) {
original = entity[requiresSelection.responseKey];
}
const projectedValue = requiresSelection.selections ? projectRequiresCompiled(
requiresSelection.selections,
original,
runtime
) : original;
if (projectedValue != null) {
result ??= {};
result[requiresSelection.responseKey] = projectedValue;
}
break;
}
case "InlineFragment": {
if (entitySatisfiesTypeConditionForRequires(
runtime,
entity.__typename,
requiresSelection.typeCondition
)) {
const projected = projectRequiresCompiled(
requiresSelection.selections,
entity,
runtime
);
if (projected) {
result ??= {};
mergeEntityPayload(result, projected);
}
}
break;
}
}
}
if (!result) {
return null;
}
for (const key in result) {
if (key !== "__typename") {
return result;
}
}
return null;
}
function entitySatisfiesTypeConditionForRequires(runtime, typeNameInEntity, typeConditionInInlineFragment) {
if (!typeConditionInInlineFragment) {
return false;
}
const typeConditionCacheKey = Array.isArray(typeConditionInInlineFragment) ? typeConditionInInlineFragment.join(",") : typeConditionInInlineFragment;
const cacheKey = `${typeNameInEntity}::${typeConditionCacheKey}`;
const cachedResult = runtime.entityTypeConditionResult.get(cacheKey);
if (cachedResult != null) {
return cachedResult;
}
const result = entitySatisfiesTypeCondition(
runtime.supergraphSchema,
typeNameInEntity,
typeConditionInInlineFragment
);
runtime.entityTypeConditionResult.set(cacheKey, result);
return result;
}
function getOperationProjectionCacheKey(executionRequest) {
return executionRequest.operationName ?? null;
}
function getOrCreateCompiledProjectionArtifacts(executionRequest) {
let artifactsByOperation = projectionArtifactsByDocument.get(
executionRequest.document
);
if (!artifactsByOperation) {
artifactsByOperation = /* @__PURE__ */ new Map();
projectionArtifactsByDocument.set(
executionRequest.document,
artifactsByOperation
);
}
const cacheKey = getOperationProjectionCacheKey(executionRequest);
const cachedArtifacts = artifactsByOperation.get(cacheKey);
if (cachedArtifacts) {
return cachedArtifacts;
}
const fragments = getFragmentsFromDocument(executionRequest.document);
const operation = getOperationASTFromRequest(executionRequest);
const artifacts = {
operation,
fragments,
compiledProjection: compileProjectionPlan(operation, fragments)
};
artifactsByOperation.set(cacheKey, artifacts);
return artifacts;
}
function getOrCompileRequiresSelections(requiresSelections) {
const cached = compiledRequiresCache.get(requiresSelections);
if (cached) {
return cached;
}
const compiled = compileRequiresSelections(requiresSelections);
compiledRequiresCache.set(requiresSelections, compiled);
return compiled;
}
function compileRequiresSelections(requiresSelections) {
const compiled = [];
for (const requiresSelection of requiresSelections) {
switch (requiresSelection.kind) {
case "Field": {
compiled.push({
kind: "Field",
fieldName: requiresSelection.name,
responseKey: requiresSelection.alias ?? requiresSelection.name,
selections: requiresSelection.selections ? compileRequiresSelections(requiresSelection.selections) : void 0
});
break;
}
case "InlineFragment": {
compiled.push({
kind: "InlineFragment",
typeCondition: requiresSelection.typeCondition,
selections: compileRequiresSelections(requiresSelection.selections)
});
break;
}
default:
throw new Error(
`Unsupported requires selection kind: ${requiresSelection.kind}`
);
}
}
return compiled;
}
function compileProjectionPlan(operation, fragments) {
const compiledFragments = {};
for (const fragmentName in fragments) {
const fragment = fragments[fragmentName];
if (!fragment) {
continue;
}
compiledFragments[fragmentName] = {
typeCondition: fragment.typeCondition?.name.value,
selectionSet: compileProjectionSelectionSet(fragment.selectionSet)
};
}
return {
rootSelectionSet: compileProjectionSelectionSet(operation.selectionSet),
fragments: compiledFragments
};
}
function compileProjectionSelectionSet(selectionSet) {
const selections = [];
for (const selection of selectionSet.selections) {
const directiveConditions = compileDirectiveConditions(
selection.directives
);
if (selection.kind === Kind.FIELD) {
selections.push({
kind: "Field",
fieldName: selection.name.value,
responseKey: selection.alias?.value || selection.name.value,
directiveConditions,
selectionSet: selection.selectionSet ? compileProjectionSelectionSet(selection.selectionSet) : void 0
});
continue;
}
if (selection.kind === Kind.INLINE_FRAGMENT) {
selections.push({
kind: "InlineFragment",
typeCondition: selection.typeCondition?.name.value,
directiveConditions,
selectionSet: compileProjectionSelectionSet(selection.selectionSet)
});
continue;
}
if (selection.kind === Kind.FRAGMENT_SPREAD) {
selections.push({
kind: "FragmentSpread",
fragmentName: selection.name.value,
directiveConditions
});
continue;
}
assertNever();
}
return { selections };
}
function compileDirectiveConditions(directives) {
if (!directives?.length) {
return void 0;
}
const conditions = [];
for (const directiveNode of directives) {
const directiveName = directiveNode.name.value;
if (directiveName !== "skip" && directiveName !== "include") {
continue;
}
const ifArg = directiveNode.arguments?.find(
(arg) => arg.name.value === "if"
);
if (!ifArg) {
conditions.push({ kind: "AlwaysExclude" });
continue;
}
const ifValueNode = ifArg.value;
if (ifValueNode.kind === Kind.VARIABLE) {
conditions.push(
directiveName === "skip" ? { kind: "SkipIf", variableName: ifValueNode.name.value } : { kind: "IncludeIf", variableName: ifValueNode.name.value }
);
continue;
}
if (ifValueNode.kind === Kind.BOOLEAN) {
conditions.push(
directiveName === "skip" ? { kind: "SkipIf", value: ifValueNode.value } : { kind: "IncludeIf", value: ifValueNode.value }
);
}
}
return conditions.length ? conditions : void 0;
}
function shouldIncludeCompiledSelection(directiveConditions, variableValues) {
if (!directiveConditions?.length) {
return true;
}
for (const condition of directiveConditions) {
switch (condition.kind) {
case "AlwaysExclude":
return false;
case "SkipIf": {
const ifValue = "variableName" in condition ? variableValues?.[condition.variableName] : condition.value;
if (ifValue) {
return false;
}
break;
}
case "IncludeIf": {
const ifValue = "variableName" in condition ? variableValues?.[condition.variableName] : condition.value;
if (!ifValue) {
return false;
}
break;
}
default:
assertNever();
}
}
return true;
}
function getProjectionFieldMeta(parentType, fieldName, executionContext) {
let byFieldName = executionContext.projectionRuntimeCache.fieldMetaByParentType.get(
parentType
);
if (!byFieldName) {
byFieldName = /* @__PURE__ */ new Map();
executionContext.projectionRuntimeCache.fieldMetaByParentType.set(
parentType,
byFieldName
);
}
if (byFieldName.has(fieldName)) {
return byFieldName.get(fieldName) || null;
}
const field = fieldName === "__typename" ? TypeNameMetaFieldDef : parentType.getFields()[fieldName];
if (!field) {
byFieldName.set(fieldName, null);
return null;