@graphql-tools/federation
Version:
Useful tools to create and manipulate GraphQL schemas.
1,867 lines • 67.2 kB
JavaScript
'use strict';
var delegate = require('@graphql-tools/delegate');
var utils = require('@graphql-tools/utils');
var disposablestack = require('@whatwg-node/disposablestack');
var events = require('@whatwg-node/events');
var fetch = require('@whatwg-node/fetch');
var executor = require('@graphql-tools/executor');
var executorHttp = require('@graphql-tools/executor-http');
var stitch = require('@graphql-tools/stitch');
var promiseHelpers = require('@whatwg-node/promise-helpers');
var graphql = require('graphql');
const getArgsFromKeysForFederation = utils.memoize1(
function getArgsFromKeysForFederation2(representations) {
return { representations };
}
);
function projectDataSelectionSet(data, selectionSet) {
if (data == null || selectionSet == null || !selectionSet?.selections?.length) {
return data;
}
if (data instanceof Error) {
return null;
}
if (Array.isArray(data)) {
return data.map((entry) => projectDataSelectionSet(entry, selectionSet));
}
const projectedData = {
__typename: data.__typename
};
for (const selection of selectionSet.selections) {
if (selection.kind === graphql.Kind.FIELD) {
const fieldName = selection.name.value;
const responseKey = selection.alias?.value || selection.name.value;
if (Object.prototype.hasOwnProperty.call(data, responseKey)) {
const projectedKeyData = projectDataSelectionSet(
data[responseKey],
selection.selectionSet
);
if (projectedData[fieldName]) {
if (projectedKeyData != null && !(projectedKeyData instanceof Error)) {
projectedData[fieldName] = utils.mergeDeep(
[projectedData[fieldName], projectedKeyData],
void 0,
true,
true
);
}
} else {
projectedData[fieldName] = projectedKeyData;
}
}
} else if (selection.kind === graphql.Kind.INLINE_FRAGMENT) {
if (selection.typeCondition && projectedData["__typename"] != null && projectedData["__typename"] !== selection.typeCondition.name.value) {
continue;
}
Object.assign(
projectedData,
utils.mergeDeep(
[
projectedData,
projectDataSelectionSet(data, selection.selectionSet)
],
void 0,
true,
true
)
);
}
}
return projectedData;
}
function getKeyFnForFederation(typeName, keys) {
if (keys.some((key) => key.includes("{") || key.includes("("))) {
const parsedSelectionSet = utils.parseSelectionSet(`{${keys.join(" ")}}`, {
noLocation: true
});
return function keyFn(root) {
if (root == null) {
return root;
}
return projectDataSelectionSet(
{
__typename: typeName,
...root
},
parsedSelectionSet
);
};
}
const allKeyProps = keys.flatMap((key) => key.split(" ")).map((key) => key.trim());
if (allKeyProps.length > 1) {
return function keyFn(root) {
if (root == null) {
return null;
}
return allKeyProps.reduce(
(prev, key) => {
if (key !== "__typename") {
prev[key] = root[key];
}
return prev;
},
{ __typename: typeName }
);
};
}
const keyProp = allKeyProps[0];
return utils.memoize1(function keyFn(root) {
if (root == null) {
return null;
}
const keyPropVal = root[keyProp];
if (keyPropVal == null) {
return null;
}
return {
__typename: typeName,
[keyProp]: keyPropVal
};
});
}
function getCacheKeyFnFromKey(key) {
if (key.includes("{") || key.includes("(")) {
const parsedSelectionSet = utils.parseSelectionSet(`{${key}}`, {
noLocation: true
});
return function cacheKeyFn(root) {
return JSON.stringify(projectDataSelectionSet(root, parsedSelectionSet));
};
}
const keyTrimmed = key.trim();
const keys = keyTrimmed.split(" ").map((key2) => key2.trim());
if (keys.length > 1) {
return function cacheKeyFn(root) {
return keys.map((key2) => {
const keyVal = root[key2];
if (keyVal == null) {
return "";
}
if (typeof keyVal === "object") {
return JSON.stringify(keyVal);
}
return keyVal;
}).join(" ");
};
}
return utils.memoize1(function cacheKeyFn(root) {
const keyVal = root[keyTrimmed];
if (keyVal == null) {
return "";
}
if (typeof keyVal === "object") {
return JSON.stringify(keyVal);
}
return keyVal;
});
}
function hasInaccessible(obj) {
return utils.getDirectiveExtensions(obj)?.inaccessible?.length;
}
function filterInternalFieldsAndTypes(finalSchema) {
const internalTypeNameRegexp = /^(?:_Entity|_Any|_FieldSet|_Service|link|inaccessible|(?:link__|join__|core__)[\w]*)$/;
return utils.mapSchema(finalSchema, {
[utils.MapperKind.DIRECTIVE]: (directive) => {
if (internalTypeNameRegexp.test(directive.name)) {
return null;
}
return directive;
},
[utils.MapperKind.TYPE]: (type) => {
if (internalTypeNameRegexp.test(type.name) || hasInaccessible(type)) {
return null;
}
return type;
},
[utils.MapperKind.FIELD]: (fieldConfig) => {
if (hasInaccessible(fieldConfig)) {
return null;
}
return fieldConfig;
},
[utils.MapperKind.QUERY_ROOT_FIELD]: (fieldConfig, fieldName) => {
if (fieldName === "_entities" || hasInaccessible(fieldConfig)) {
return null;
}
return fieldConfig;
},
[utils.MapperKind.ENUM_VALUE]: (valueConfig) => {
if (hasInaccessible(valueConfig)) {
return null;
}
return valueConfig;
},
[utils.MapperKind.ARGUMENT]: (argConfig) => {
if (hasInaccessible(argConfig)) {
return null;
}
return argConfig;
}
});
}
function getNamedTypeNode(typeNode) {
if (typeNode.kind !== graphql.Kind.NAMED_TYPE) {
return getNamedTypeNode(typeNode.type);
}
return typeNode;
}
function ensureSupergraphSDLAst(supergraphSdl) {
return typeof supergraphSdl === "string" ? graphql.parse(supergraphSdl, { noLocation: true }) : supergraphSdl;
}
const rootTypeMap = /* @__PURE__ */ new Map([
["Query", "query"],
["Mutation", "mutation"],
["Subscription", "subscription"]
]);
const memoizedASTPrint = utils.memoize1(graphql.print);
const memoizedTypePrint = utils.memoize1(
(type) => type.toString()
);
function getStitchingOptionsFromSupergraphSdl(opts) {
const supergraphAst = ensureSupergraphSDLAst(opts.supergraphSdl);
const subgraphEndpointMap = /* @__PURE__ */ new Map();
const subgraphTypesMap = /* @__PURE__ */ new Map();
const typeNameKeysBySubgraphMap = /* @__PURE__ */ new Map();
const typeNameFieldsKeyBySubgraphMap = /* @__PURE__ */ new Map();
const typeNameCanonicalMap = /* @__PURE__ */ new Map();
const subgraphTypeNameProvidedMap = /* @__PURE__ */ new Map();
const subgraphTypeNameFieldProvidedSelectionMap = /* @__PURE__ */ new Map();
const orphanTypeMap = /* @__PURE__ */ new Map();
const typeFieldASTMap = /* @__PURE__ */ new Map();
for (const definition of supergraphAst.definitions) {
if ("fields" in definition) {
const fieldMap = /* @__PURE__ */ new Map();
typeFieldASTMap.set(definition.name.value, fieldMap);
for (const field of definition.fields || []) {
fieldMap.set(field.name.value, field);
}
}
}
const subgraphExternalFieldMap = /* @__PURE__ */ new Map();
const subgraphNames = [];
graphql.visit(supergraphAst, {
EnumTypeDefinition(node) {
if (node.name.value === "join__Graph") {
node.values?.forEach((valueNode) => {
subgraphNames.push(valueNode.name.value);
});
}
}
});
function TypeWithFieldsVisitor(typeNode) {
if (typeNode.name.value === "Query" || typeNode.name.value === "Mutation" && !typeNode.directives?.some(
(directiveNode) => directiveNode.name.value === "join__type"
)) {
typeNode.directives = [
...typeNode.directives || [],
...subgraphNames.map((subgraphName) => ({
kind: graphql.Kind.DIRECTIVE,
name: {
kind: graphql.Kind.NAME,
value: "join__type"
},
arguments: [
{
kind: graphql.Kind.ARGUMENT,
name: {
kind: graphql.Kind.NAME,
value: "graph"
},
value: {
kind: graphql.Kind.ENUM,
value: subgraphName
}
}
]
}))
];
}
let isOrphan = true;
const fieldDefinitionNodesByGraphName = /* @__PURE__ */ new Map();
typeNode.directives?.forEach((directiveNode) => {
if (typeNode.kind === graphql.Kind.OBJECT_TYPE_DEFINITION) {
if (directiveNode.name.value === "join__owner") {
directiveNode.arguments?.forEach((argumentNode) => {
if (argumentNode.name.value === "graph" && argumentNode.value?.kind === graphql.Kind.ENUM) {
typeNameCanonicalMap.set(
typeNode.name.value,
argumentNode.value.value
);
}
});
}
}
if (directiveNode.name.value === "join__type") {
isOrphan = false;
const joinTypeGraphArgNode = directiveNode.arguments?.find(
(argumentNode) => argumentNode.name.value === "graph"
);
if (joinTypeGraphArgNode?.value?.kind === graphql.Kind.ENUM) {
const graphName = joinTypeGraphArgNode.value.value;
if (typeNode.kind === graphql.Kind.OBJECT_TYPE_DEFINITION || typeNode.kind === graphql.Kind.INTERFACE_TYPE_DEFINITION) {
const keyArgumentNode = directiveNode.arguments?.find(
(argumentNode) => argumentNode.name.value === "key"
);
const isResolvable = !directiveNode.arguments?.some(
(argumentNode) => argumentNode.name.value === "resolvable" && argumentNode.value?.kind === graphql.Kind.BOOLEAN && argumentNode.value.value === false
);
if (isResolvable && keyArgumentNode?.value?.kind === graphql.Kind.STRING) {
let typeNameKeysMap = typeNameKeysBySubgraphMap.get(graphName);
if (!typeNameKeysMap) {
typeNameKeysMap = /* @__PURE__ */ new Map();
typeNameKeysBySubgraphMap.set(graphName, typeNameKeysMap);
}
let keys = typeNameKeysMap.get(typeNode.name.value);
if (!keys) {
keys = [];
typeNameKeysMap.set(typeNode.name.value, keys);
}
keys.push(keyArgumentNode.value.value);
}
}
const fieldDefinitionNodesOfSubgraph = [];
typeNode.fields?.forEach((fieldNode) => {
const joinFieldDirectives = fieldNode.directives?.filter(
(directiveNode2) => directiveNode2.name.value === "join__field"
);
let notInSubgraph = true;
joinFieldDirectives?.forEach((joinFieldDirectiveNode) => {
const joinFieldGraphArgNode = joinFieldDirectiveNode.arguments?.find(
(argumentNode) => argumentNode.name.value === "graph"
);
if (joinFieldGraphArgNode?.value?.kind === graphql.Kind.ENUM && joinFieldGraphArgNode.value.value === graphName) {
notInSubgraph = false;
const isExternal = joinFieldDirectiveNode.arguments?.some(
(argumentNode) => argumentNode.name.value === "external" && argumentNode.value?.kind === graphql.Kind.BOOLEAN && argumentNode.value.value === true
);
const isOverridden = joinFieldDirectiveNode.arguments?.some(
(argumentNode) => argumentNode.name.value === "usedOverridden" && argumentNode.value?.kind === graphql.Kind.BOOLEAN && argumentNode.value.value === true
);
if (isExternal) {
let externalFieldsByType = subgraphExternalFieldMap.get(graphName);
if (!externalFieldsByType) {
externalFieldsByType = /* @__PURE__ */ new Map();
subgraphExternalFieldMap.set(
graphName,
externalFieldsByType
);
}
let externalFields = externalFieldsByType.get(
typeNode.name.value
);
if (!externalFields) {
externalFields = /* @__PURE__ */ new Set();
externalFieldsByType.set(
typeNode.name.value,
externalFields
);
}
externalFields.add(fieldNode.name.value);
}
if (!isExternal && !isOverridden) {
const typeArg = joinFieldDirectiveNode.arguments?.find(
(argumentNode) => argumentNode.name.value === "type"
);
const typeNode2 = typeArg?.value.kind === graphql.Kind.STRING ? graphql.parseType(typeArg.value.value) : fieldNode.type;
fieldDefinitionNodesOfSubgraph.push({
...fieldNode,
type: typeNode2,
directives: fieldNode.directives?.filter(
(directiveNode2) => directiveNode2.name.value !== "join__field"
)
});
}
const providedExtraField = joinFieldDirectiveNode.arguments?.find(
(argumentNode) => argumentNode.name.value === "provides"
);
if (providedExtraField?.value?.kind === graphql.Kind.STRING) {
let handleSelection2 = function(fieldNodeTypeName2, selection) {
switch (selection.kind) {
case graphql.Kind.FIELD:
{
const extraFieldTypeNode = supergraphAst.definitions.find(
(def) => "name" in def && def.name?.value === fieldNodeTypeName2
);
const extraFieldNodeInType = extraFieldTypeNode.fields?.find(
(fieldNode2) => fieldNode2.name.value === selection.name.value
);
if (extraFieldNodeInType) {
let typeNameProvidedMap = subgraphTypeNameProvidedMap.get(graphName);
if (!typeNameProvidedMap) {
typeNameProvidedMap = /* @__PURE__ */ new Map();
subgraphTypeNameProvidedMap.set(
graphName,
typeNameProvidedMap
);
}
let providedFields = typeNameProvidedMap.get(fieldNodeTypeName2);
if (!providedFields) {
providedFields = /* @__PURE__ */ new Set();
typeNameProvidedMap.set(
fieldNodeTypeName2,
providedFields
);
}
providedFields.add(selection.name.value);
if (selection.selectionSet) {
const extraFieldNodeNamedType = getNamedTypeNode(
extraFieldNodeInType.type
);
const extraFieldNodeTypeName = extraFieldNodeNamedType.name.value;
for (const subSelection of selection.selectionSet.selections) {
handleSelection2(
extraFieldNodeTypeName,
subSelection
);
}
}
}
}
break;
case graphql.Kind.INLINE_FRAGMENT:
{
const fragmentType = selection.typeCondition?.name?.value || fieldNodeType.name.value;
if (selection.selectionSet) {
for (const subSelection of selection.selectionSet.selections) {
handleSelection2(fragmentType, subSelection);
}
}
}
break;
}
};
const providesSelectionSet = utils.parseSelectionSet(
/* GraphQL */
`{ ${providedExtraField.value.value} }`
);
let typeNameFieldProvidedSelectionMap = subgraphTypeNameFieldProvidedSelectionMap.get(graphName);
if (!typeNameFieldProvidedSelectionMap) {
typeNameFieldProvidedSelectionMap = /* @__PURE__ */ new Map();
subgraphTypeNameFieldProvidedSelectionMap.set(
graphName,
typeNameFieldProvidedSelectionMap
);
}
let fieldProvidedSelectionMap = typeNameFieldProvidedSelectionMap.get(typeNode.name.value);
if (!fieldProvidedSelectionMap) {
fieldProvidedSelectionMap = /* @__PURE__ */ new Map();
typeNameFieldProvidedSelectionMap.set(
typeNode.name.value,
fieldProvidedSelectionMap
);
}
fieldProvidedSelectionMap.set(
fieldNode.name.value,
providesSelectionSet
);
const fieldNodeType = getNamedTypeNode(fieldNode.type);
const fieldNodeTypeName = fieldNodeType.name.value;
for (const selection of providesSelectionSet.selections) {
handleSelection2(fieldNodeTypeName, selection);
}
}
const requiresArgumentNode = joinFieldDirectiveNode.arguments?.find(
(argumentNode) => argumentNode.name.value === "requires"
);
if (requiresArgumentNode?.value?.kind === graphql.Kind.STRING) {
let typeNameFieldsKeyMap = typeNameFieldsKeyBySubgraphMap.get(graphName);
if (!typeNameFieldsKeyMap) {
typeNameFieldsKeyMap = /* @__PURE__ */ new Map();
typeNameFieldsKeyBySubgraphMap.set(
graphName,
typeNameFieldsKeyMap
);
}
let fieldsKeyMap = typeNameFieldsKeyMap.get(
typeNode.name.value
);
if (!fieldsKeyMap) {
fieldsKeyMap = /* @__PURE__ */ new Map();
typeNameFieldsKeyMap.set(typeNode.name.value, fieldsKeyMap);
}
fieldsKeyMap.set(
fieldNode.name.value,
requiresArgumentNode.value.value
);
}
}
});
if (!joinFieldDirectives?.length) {
fieldDefinitionNodesOfSubgraph.push({
...fieldNode,
directives: fieldNode.directives?.filter(
(directiveNode2) => directiveNode2.name.value !== "join__field"
)
});
} else if (notInSubgraph && typeNameKeysBySubgraphMap.get(graphName)?.get(typeNode.name.value)?.some((key) => key.split(" ").includes(fieldNode.name.value))) {
fieldDefinitionNodesOfSubgraph.push({
...fieldNode,
directives: fieldNode.directives?.filter(
(directiveNode2) => directiveNode2.name.value !== "join__field"
)
});
}
});
fieldDefinitionNodesByGraphName.set(
graphName,
fieldDefinitionNodesOfSubgraph
);
}
}
});
const joinImplementsDirectives = typeNode.directives?.filter(
(directiveNode) => directiveNode.name.value === "join__implements"
);
fieldDefinitionNodesByGraphName.forEach(
(fieldDefinitionNodesOfSubgraph, graphName) => {
const interfaces = [];
typeNode.interfaces?.forEach((interfaceNode) => {
const implementedSubgraphs = joinImplementsDirectives?.filter(
(directiveNode) => {
const argumentNode = directiveNode.arguments?.find(
(argumentNode2) => argumentNode2.name.value === "interface"
);
return argumentNode?.value?.kind === graphql.Kind.STRING && argumentNode.value.value === interfaceNode.name.value;
}
);
if (!implementedSubgraphs?.length || implementedSubgraphs.some((directiveNode) => {
const argumentNode = directiveNode.arguments?.find(
(argumentNode2) => argumentNode2.name.value === "graph"
);
return argumentNode?.value?.kind === graphql.Kind.ENUM && argumentNode.value.value === graphName;
})) {
interfaces.push(interfaceNode);
}
});
if (typeNode.name.value === "Query") {
fieldDefinitionNodesOfSubgraph.push(entitiesFieldDefinitionNode);
}
const objectTypedDefNodeForSubgraph = {
...typeNode,
interfaces,
fields: fieldDefinitionNodesOfSubgraph,
directives: typeNode.directives?.filter(
(directiveNode) => directiveNode.name.value !== "join__type" && directiveNode.name.value !== "join__owner" && directiveNode.name.value !== "join__implements"
)
};
let subgraphTypes = subgraphTypesMap.get(graphName);
if (!subgraphTypes) {
subgraphTypes = [];
subgraphTypesMap.set(graphName, subgraphTypes);
}
subgraphTypes.push(objectTypedDefNodeForSubgraph);
}
);
if (isOrphan) {
orphanTypeMap.set(typeNode.name.value, typeNode);
}
}
graphql.visit(supergraphAst, {
ScalarTypeDefinition(node) {
let isOrphan = !node.name.value.startsWith("link__") && !node.name.value.startsWith("join__");
node.directives?.forEach((directiveNode) => {
if (directiveNode.name.value === "join__type") {
directiveNode.arguments?.forEach((argumentNode) => {
if (argumentNode.name.value === "graph" && argumentNode?.value?.kind === graphql.Kind.ENUM) {
isOrphan = false;
const graphName = argumentNode.value.value;
let subgraphTypes = subgraphTypesMap.get(graphName);
if (!subgraphTypes) {
subgraphTypes = [];
subgraphTypesMap.set(graphName, subgraphTypes);
}
subgraphTypes.push({
...node,
directives: node.directives?.filter(
(directiveNode2) => directiveNode2.name.value !== "join__type"
)
});
}
});
}
});
if (isOrphan) {
orphanTypeMap.set(node.name.value, node);
}
},
InputObjectTypeDefinition(node) {
let isOrphan = true;
node.directives?.forEach((directiveNode) => {
if (directiveNode.name.value === "join__type") {
directiveNode.arguments?.forEach((argumentNode) => {
if (argumentNode.name.value === "graph" && argumentNode?.value?.kind === graphql.Kind.ENUM) {
isOrphan = false;
const graphName = argumentNode.value.value;
let subgraphTypes = subgraphTypesMap.get(graphName);
if (!subgraphTypes) {
subgraphTypes = [];
subgraphTypesMap.set(graphName, subgraphTypes);
}
subgraphTypes.push({
...node,
directives: node.directives?.filter(
(directiveNode2) => directiveNode2.name.value !== "join__type"
)
});
}
});
}
});
if (isOrphan) {
orphanTypeMap.set(node.name.value, node);
}
},
InterfaceTypeDefinition: TypeWithFieldsVisitor,
UnionTypeDefinition(node) {
let isOrphan = true;
node.directives?.forEach((directiveNode) => {
if (directiveNode.name.value === "join__type") {
directiveNode.arguments?.forEach((argumentNode) => {
if (argumentNode.name.value === "graph" && argumentNode?.value?.kind === graphql.Kind.ENUM) {
isOrphan = false;
const graphName = argumentNode.value.value;
const unionMembers = [];
node.directives?.forEach((directiveNode2) => {
if (directiveNode2.name.value === "join__unionMember") {
const graphArgumentNode = directiveNode2.arguments?.find(
(argumentNode2) => argumentNode2.name.value === "graph"
);
const memberArgumentNode = directiveNode2.arguments?.find(
(argumentNode2) => argumentNode2.name.value === "member"
);
if (graphArgumentNode?.value?.kind === graphql.Kind.ENUM && graphArgumentNode.value.value === graphName && memberArgumentNode?.value?.kind === graphql.Kind.STRING) {
unionMembers.push({
kind: graphql.Kind.NAMED_TYPE,
name: {
kind: graphql.Kind.NAME,
value: memberArgumentNode.value.value
}
});
}
}
});
if (unionMembers.length > 0) {
let subgraphTypes = subgraphTypesMap.get(graphName);
if (!subgraphTypes) {
subgraphTypes = [];
subgraphTypesMap.set(graphName, subgraphTypes);
}
subgraphTypes.push({
...node,
types: unionMembers,
directives: node.directives?.filter(
(directiveNode2) => directiveNode2.name.value !== "join__type" && directiveNode2.name.value !== "join__unionMember"
)
});
}
}
});
}
});
if (isOrphan && node.name.value !== "_Entity") {
orphanTypeMap.set(node.name.value, node);
}
},
EnumTypeDefinition(node) {
let isOrphan = true;
if (node.name.value === "join__Graph") {
node.values?.forEach((valueNode) => {
isOrphan = false;
valueNode.directives?.forEach((directiveNode) => {
if (directiveNode.name.value === "join__graph") {
directiveNode.arguments?.forEach((argumentNode) => {
if (argumentNode.name.value === "url" && argumentNode.value?.kind === graphql.Kind.STRING) {
subgraphEndpointMap.set(
valueNode.name.value,
argumentNode.value.value
);
}
});
}
});
});
}
node.directives?.forEach((directiveNode) => {
if (directiveNode.name.value === "join__type") {
isOrphan = false;
directiveNode.arguments?.forEach((argumentNode) => {
if (argumentNode.name.value === "graph" && argumentNode.value?.kind === graphql.Kind.ENUM) {
const graphName = argumentNode.value.value;
const enumValueNodes = [];
node.values?.forEach((valueNode) => {
const joinEnumValueDirectives = valueNode.directives?.filter(
(directiveNode2) => directiveNode2.name.value === "join__enumValue"
);
if (joinEnumValueDirectives?.length) {
joinEnumValueDirectives.forEach(
(joinEnumValueDirectiveNode) => {
joinEnumValueDirectiveNode.arguments?.forEach(
(argumentNode2) => {
if (argumentNode2.name.value === "graph" && argumentNode2.value?.kind === graphql.Kind.ENUM && argumentNode2.value.value === graphName) {
enumValueNodes.push({
...valueNode,
directives: valueNode.directives?.filter(
(directiveNode2) => directiveNode2.name.value !== "join__enumValue"
)
});
}
}
);
}
);
} else {
enumValueNodes.push(valueNode);
}
});
const enumTypedDefNodeForSubgraph = {
...node,
directives: node.directives?.filter(
(directiveNode2) => directiveNode2.name.value !== "join__type"
),
values: enumValueNodes
};
let subgraphTypes = subgraphTypesMap.get(graphName);
if (!subgraphTypes) {
subgraphTypes = [];
subgraphTypesMap.set(graphName, subgraphTypes);
}
subgraphTypes.push(enumTypedDefNodeForSubgraph);
}
});
}
});
if (isOrphan) {
orphanTypeMap.set(node.name.value, node);
}
},
ObjectTypeDefinition: TypeWithFieldsVisitor
});
const subschemas = [];
for (const [subgraphName, endpoint] of subgraphEndpointMap) {
let visitTypeDefinitionsForOrphanTypes2 = function(node) {
function visitNamedTypeNode(namedTypeNode) {
const typeName = namedTypeNode.name.value;
if (specifiedTypeNames.includes(typeName)) {
return node;
}
const orphanType = orphanTypeMap.get(typeName);
if (orphanType) {
if (!extraOrphanTypesForSubgraph.has(typeName)) {
extraOrphanTypesForSubgraph.set(typeName, {});
const extraOrphanType = visitTypeDefinitionsForOrphanTypes2(orphanType);
extraOrphanTypesForSubgraph.set(typeName, extraOrphanType);
}
} else if (!subgraphTypes.some((typeNode) => typeNode.name.value === typeName)) {
return null;
}
return node;
}
function visitFieldDefs(nodeFields) {
const fields = [];
for (const field of nodeFields || []) {
const isTypeNodeOk = visitNamedTypeNode(
getNamedTypeNode(field.type)
);
if (!isTypeNodeOk) {
continue;
}
if (field.kind === graphql.Kind.FIELD_DEFINITION) {
const args = visitFieldDefs(
field.arguments
);
fields.push({
...field,
arguments: args
});
} else {
fields.push(field);
}
}
return fields;
}
function visitObjectAndInterfaceDefs(node2) {
const fields = visitFieldDefs(node2.fields);
const interfaces = [];
for (const iface of node2.interfaces || []) {
const isTypeNodeOk = visitNamedTypeNode(iface);
if (!isTypeNodeOk) {
continue;
}
interfaces.push(iface);
}
return {
...node2,
fields,
interfaces
};
}
return graphql.visit(node, {
[graphql.Kind.OBJECT_TYPE_DEFINITION]: visitObjectAndInterfaceDefs,
[graphql.Kind.OBJECT_TYPE_EXTENSION]: visitObjectAndInterfaceDefs,
[graphql.Kind.INTERFACE_TYPE_DEFINITION]: visitObjectAndInterfaceDefs,
[graphql.Kind.INTERFACE_TYPE_EXTENSION]: visitObjectAndInterfaceDefs,
[graphql.Kind.UNION_TYPE_DEFINITION](node2) {
const types = [];
for (const type of node2.types || []) {
const isTypeNodeOk = visitNamedTypeNode(type);
if (!isTypeNodeOk) {
continue;
}
types.push(type);
}
return {
...node2,
types
};
},
[graphql.Kind.UNION_TYPE_EXTENSION](node2) {
const types = [];
for (const type of node2.types || []) {
const isTypeNodeOk = visitNamedTypeNode(type);
if (!isTypeNodeOk) {
continue;
}
types.push(type);
}
return {
...node2,
types
};
},
[graphql.Kind.INPUT_OBJECT_TYPE_DEFINITION](node2) {
const fields = visitFieldDefs(node2.fields);
return {
...node2,
fields
};
},
[graphql.Kind.INPUT_OBJECT_TYPE_EXTENSION](node2) {
const fields = visitFieldDefs(node2.fields);
return {
...node2,
fields
};
}
});
};
const mergeConfig = {};
const typeNameKeyMap = typeNameKeysBySubgraphMap.get(subgraphName);
const unionTypeNodes = [];
if (typeNameKeyMap) {
const typeNameFieldsKeyMap = typeNameFieldsKeyBySubgraphMap.get(subgraphName);
for (const [typeName, keys] of typeNameKeyMap) {
let getMergedTypeConfigFromKey2 = function(key) {
return {
selectionSet: `{ ${key} }`,
argsFromKeys: getArgsFromKeysForFederation,
key: getKeyFnForFederation(typeName, [key, ...extraKeys]),
fieldName: `_entities`,
dataLoaderOptions: {
cacheKeyFn: getCacheKeyFnFromKey(key),
...opts.batchDelegateOptions || {}
}
};
};
const mergedTypeConfig = mergeConfig[typeName] = {};
const fieldsKeyMap = typeNameFieldsKeyMap?.get(typeName);
const extraKeys = /* @__PURE__ */ new Set();
if (fieldsKeyMap) {
const fieldsConfig = mergedTypeConfig.fields = {};
for (const [fieldName, fieldNameKey] of fieldsKeyMap) {
const aliasedFieldNameKey = fieldNameKey.includes("(") ? `_${fieldNameKey.split("(")[0]}: ${fieldNameKey}` : fieldNameKey;
extraKeys.add(aliasedFieldNameKey);
fieldsConfig[fieldName] = {
selectionSet: `{ ${aliasedFieldNameKey} }`,
computed: true
};
}
}
if (typeNameCanonicalMap.get(typeName) === subgraphName) {
mergedTypeConfig.canonical = true;
}
if (keys.length === 1 && keys[0]) {
Object.assign(mergedTypeConfig, getMergedTypeConfigFromKey2(keys[0]));
}
if (keys.length > 1) {
const entryPoints = keys.map(
(key) => getMergedTypeConfigFromKey2(key)
);
mergedTypeConfig.entryPoints = entryPoints;
}
unionTypeNodes.push({
kind: graphql.Kind.NAMED_TYPE,
name: {
kind: graphql.Kind.NAME,
value: typeName
}
});
opts.onMergedTypeConfig?.(typeName, mergedTypeConfig);
}
}
const typeNameProvidedSelectionMap = subgraphTypeNameFieldProvidedSelectionMap.get(subgraphName);
if (typeNameProvidedSelectionMap) {
for (const [
typeName,
fieldSelectionMap
] of typeNameProvidedSelectionMap) {
const mergedTypeConfig = mergeConfig[typeName] ||= {};
const fieldsConfig = mergedTypeConfig.fields ||= {};
for (const [fieldName, selectionSet] of fieldSelectionMap) {
fieldsConfig[fieldName] = {
provides: selectionSet
};
}
}
}
const entitiesUnionTypeDefinitionNode = {
name: {
kind: graphql.Kind.NAME,
value: "_Entity"
},
kind: graphql.Kind.UNION_TYPE_DEFINITION,
types: unionTypeNodes
};
const extraOrphanTypesForSubgraph = /* @__PURE__ */ new Map();
const subgraphTypes = subgraphTypesMap.get(subgraphName) || [];
subgraphTypes.forEach((typeNode) => {
visitTypeDefinitionsForOrphanTypes2(typeNode);
});
const extendedSubgraphTypes = [
...subgraphTypes,
...extraOrphanTypesForSubgraph.values()
];
for (const interfaceInSubgraph of extendedSubgraphTypes) {
if (interfaceInSubgraph.kind === graphql.Kind.INTERFACE_TYPE_DEFINITION) {
let isOrphan = true;
for (const definitionNode of supergraphAst.definitions) {
if (definitionNode.kind === graphql.Kind.OBJECT_TYPE_DEFINITION && definitionNode.interfaces?.some(
(interfaceNode) => interfaceNode.name.value === interfaceInSubgraph.name.value
)) {
isOrphan = false;
}
}
if (isOrphan) {
interfaceInSubgraph.kind = graphql.Kind.OBJECT_TYPE_DEFINITION;
}
}
}
let schema;
let schemaAst = {
kind: graphql.Kind.DOCUMENT,
definitions: [
...extendedSubgraphTypes,
entitiesUnionTypeDefinitionNode,
anyTypeDefinitionNode
]
};
if (opts.onSubgraphAST) {
schemaAst = opts.onSubgraphAST(subgraphName, schemaAst);
}
try {
schema = graphql.buildASTSchema(schemaAst, {
assumeValidSDL: true,
assumeValid: true
});
} catch (e) {
throw new Error(
`Error building schema for subgraph ${subgraphName}: ${e?.stack || e?.message || e.toString()}`
);
}
let httpExecutorOpts;
if (typeof opts.httpExecutorOpts === "function") {
httpExecutorOpts = opts.httpExecutorOpts({
name: subgraphName,
endpoint
});
} else {
httpExecutorOpts = opts.httpExecutorOpts || {};
}
let executor$1 = executorHttp.buildHTTPExecutor({
endpoint,
...httpExecutorOpts
});
if (globalThis.process?.env?.["DEBUG"]) {
const origExecutor = executor$1;
executor$1 = function debugExecutor(execReq) {
const prefix = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${subgraphName}`;
console.debug(`${prefix} - subgraph-execute-start`, {
document: memoizedASTPrint(execReq.document),
variables: JSON.stringify(execReq.variables)
});
return promiseHelpers.handleMaybePromise(
() => origExecutor(execReq),
(res) => {
console.debug(
`[${(/* @__PURE__ */ new Date()).toISOString()}] ${subgraphName} - subgraph-execute-done`,
JSON.stringify(res)
);
return res;
},
(err) => {
console.error(
`[${(/* @__PURE__ */ new Date()).toISOString()}] ${subgraphName} - subgraph-execute-error`,
err
);
return err;
}
);
};
}
const typeNameProvidedMap = subgraphTypeNameProvidedMap.get(subgraphName);
const externalFieldMap = subgraphExternalFieldMap.get(subgraphName);
const transforms = [];
if (externalFieldMap?.size && extendedSubgraphTypes.some(
(t) => t.kind === graphql.Kind.INTERFACE_TYPE_DEFINITION
)) {
let createUnresolvableError2 = function(fieldName, fieldNode) {
return utils.createGraphQLError(
`Was not able to find any options for ${fieldName}: This shouldn't have happened.`,
{
extensions: {
[executor.CRITICAL_ERROR]: true
},
nodes: [fieldNode]
}
);
}, createIfaceFieldChecker2 = function(parentType) {
const providedInterfaceFields = typeNameProvidedMap?.get(
parentType.name
);
const implementations = schema.getPossibleTypes(parentType);
const ifaceFieldCheckResult = /* @__PURE__ */ new Map();
return function ifaceFieldChecker(fieldName) {
let result = ifaceFieldCheckResult.get(fieldName);
if (result == null) {
result = true;
for (const implementation of implementations) {
const externalFields = externalFieldMap?.get(implementation.name);
const providedFields = typeNameProvidedMap?.get(
implementation.name
);
if (!providedInterfaceFields?.has(fieldName) && !providedFields?.has(fieldName) && externalFields?.has(fieldName)) {
result = false;
break;
}
}
ifaceFieldCheckResult.set(fieldName, result);
}
return result;
};
};
const typeInfo = delegate.getTypeInfo(schema);
const visitorKeys = {
Document: ["definitions"],
OperationDefinition: ["selectionSet"],
SelectionSet: ["selections"],
Field: ["selectionSet"],
InlineFragment: ["selectionSet"],
FragmentDefinition: ["selectionSet"]
};
const unresolvableIfaceFieldCheckerMap = /* @__PURE__ */ new Map();
transforms.push({
transformRequest(request) {
return {
...request,
document: graphql.visit(
request.document,
graphql.visitWithTypeInfo(typeInfo, {
// To avoid resolving unresolvable interface fields
[graphql.Kind.FIELD](fieldNode) {
const fieldName = fieldNode.name.value;
if (fieldName !== "__typename") {
const parentType = typeInfo.getParentType();
if (graphql.isInterfaceType(parentType)) {
let unresolvableIfaceFieldChecker = unresolvableIfaceFieldCheckerMap.get(parentType.name);
if (unresolvableIfaceFieldChecker == null) {
unresolvableIfaceFieldChecker = createIfaceFieldChecker2(parentType);
unresolvableIfaceFieldCheckerMap.set(
parentType.name,
unresolvableIfaceFieldChecker
);
}
if (!unresolvableIfaceFieldChecker(fieldName)) {
throw createUnresolvableError2(fieldName, fieldNode);
}
}
}
}
}),
visitorKeys
)
};
}
});
}
const subschemaConfig = {
name: subgraphName,
endpoint,
schema,
executor: executor$1,
merge: mergeConfig,
transforms,
batch: opts.batch,
batchingOptions: opts.batchingOptions
};
subschemas.push(subschemaConfig);
}
const defaultMerger = stitch.getDefaultFieldConfigMerger(true);
const fieldConfigMerger = function(candidates) {
if (candidates.length === 1 || candidates.some((candidate) => candidate.fieldName === "_entities")) {
if (candidates[0]) {
return candidates[0].fieldConfig;
}
}
let operationType;
for (const candidate of candidates) {
const candidateOperationType = rootTypeMap.get(candidate.type.name);
if (candidateOperationType) {
operationType = candidateOperationType;
}
}
if (operationType) {
const defaultMergedField = defaultMerger(candidates);
const mergedResolver = function mergedResolver2(_root, _args, context, info) {
const originalSelectionSet = {
kind: graphql.Kind.SELECTION_SET,
selections: info.fieldNodes
};
const candidatesReversed = candidates.toReversed ? candidates.toReversed() : [...candidates].reverse();
let currentSubschema;
let currentScore = Infinity;
let currentUnavailableSelectionSet;
let currentFriendSubschemas;
let currentAvailableSelectionSet;
for (const candidate of candidatesReversed) {
if (candidate.transformedSubschema) {
const unavailableFields = delegate.extractUnavailableFieldsFromSelectionSet(
candidate.transformedSubschema.transformedSchema,
candidate.type,
originalSelectionSet,
() => true,
info.fragments
);
const score = stitch.calculateSelectionScore(
unavailableFields,
info.fragments
);
if (score < currentScore) {
currentScore = score;
currentSubschema = candidate.transformedSubschema;
currentFriendSubschemas = /* @__PURE__ */ new Map();
currentUnavailableSelectionSet = {
kind: graphql.Kind.SELECTION_SET,
selections: unavailableFields
};
currentAvailableSelectionSet = delegate.subtractSelectionSets(
originalSelectionSet,
currentUnavailableSelectionSet
);
for (const friendCandidate of candidates) {
if (friendCandidate === candidate || !friendCandidate.transformedSubschema || !currentUnavailableSelectionSet.selections.length) {
continue;
}
const unavailableFieldsInFriend = delegate.extractUnavailableFieldsFromSelectionSet(
friendCandidate.transformedSubschema.transformedSchema,
friendCandidate.type,
currentUnavailableSelectionSet,
() => true,
info.fragments
);
const friendScore = stitch.calculateSelectionScore(
unavailableFieldsInFriend,
info.fragments
);
if (friendScore < score) {
const unavailableInFriendSelectionSet = {
kind: graphql.Kind.SELECTION_SET,
selections: unavailableFieldsInFriend
};
const subschemaSelectionSet = delegate.subtractSelectionSets(
currentUnavailableSelectionSet,
unavailableInFriendSelectionSet
);
if (subschemaSelectionSet.selections.length) {
currentFriendSubschemas.set(
friendCandidate.transformedSubschema,
subschemaSelectionSet
);
currentUnavailableSelectionSet = unavailableInFriendSelectionSet;
}
}
}
}
}
}
if (!currentSubschema) {
throw new Error("Could not determine subschema");
}
const jobs = [];
let hasPromise = false;
const mainJob = delegate.delegateToSchema({
schema: currentSubschema,
operation: rootTypeMap.get(info.parentType.name) || "query",
context,
info: currentFriendSubschemas?.size ? {
...info,
fieldNodes: [
...currentAvailableSelectionSet?.selections || [],
...currentUnavailableSelectionSet?.selections || []
]
} : info
});
if (operationType !== "query") {
return mainJob;
}
if (promiseHelpers.isPromise(mainJob)) {
hasPromise = true;
}
jobs.push(mainJob);
if (currentFriendSubschemas?.size) {
for (const [
friendSubschema,
friendSelectionSet
] of currentFriendSubschemas) {
const friendJob = delegate.delegateToSchema({
schema: friendSubschema,
operation: rootTypeMap.get(info.parentType.name) || "query",
context,
info: {
...info,
fieldNodes: friendSelectionSet.selections
},
skipTypeMerging: true
});
if (promiseHelpers.isPromise(friendJob)) {
hasPromise = true;
}
jobs.push(friendJob);
}
}
if (jobs.length === 1) {
return jobs[0];
}
function getFieldNames() {
const fieldNames = /* @__PURE__ */ new Set();
originalSelectionSet?.selections.forEach((selection) => {
if (selection.kind === graphql.Kind.FIELD && selection.name.value === info.fieldName) {
selection.selectionSet?.selections.forEach((selection2) => {
if (selection2.kind === graphql.Kind.FIELD) {
fieldNames.add(selection2.name.value);
}
});
}
});
return fieldNames;
}
if (hasPromise) {
return Promise.all(jobs).then(
(results) => mergeResults(results, getFieldNames)
);
}
return mergeResults(jobs, getFieldNames);
};
if (operationType === "subscription") {
return {
...defaultMergedField,
subscribe: mergedResolver,
resolve: function identityFn(payload) {
return payload;
}
};
}
return {
...defaultMergedField,
resolve: mergedResolver
};
}
const filteredCandidates = candidates.filter((candidate) => {
const fieldASTMap = typeFieldASTMap.get(candidate.type.name);
if (fieldASTMap) {
const fieldAST = fieldASTMap.get(candidate.fieldName);
if (fieldAST) {
const typeNodeInAST = memoizedASTPrint(fieldAST.type);
const typeNodeInCandidate = memoizedTypePrint(
candidate.fieldConfig.type
);
return typeNodeInAST === typeNodeInCandidate;
}
}
return false;
});
return defaultMerger(
filteredCandidates.length ? filteredCandidates : candidates
);
};
function doesFieldExistInSupergraph(typeName, fieldName) {
for (const subschemaConfig of subschemas) {
const type = subschemaConfig.schema.getType(typeName);
if (type && "getFields" in type) {
if (type.getFields()[fieldName]) {
return true;
}
}
}
return false;
}
function getTypeInSupergraph(typeName) {
for (const subschemaConfig of subschemas) {
const type = subschemaConfig.schema.getType(typeName);
if (type) {
return type;
}
}
return void 0;
}
const extraDefinitions = [];
for (const definition of supergraphAst.definitions) {
if ("name" in definition && definition.name && definition.kind !== graphql.Kind.DIRECTIVE_DEFINITION) {
const typeName = definition.name.value;
const typeInSchema = getTypeInSupergraph(typeName);
if (!typeInSchema) {
extraDefinitions.push(definition);
} else if ("fields" in definition && definition.fields) {
const extraFields = [];
for (const field of definition.fields) {
if (!doesFieldExistInSupergraph(typeName, field.name.value)) {
extraFields.push(field);
}
}
if (extraFields.length) {
let definitionKind;
if (graphql.isObjectType(typeInSchema)) {
definitionKind = graphql.Kind.OBJECT_TYPE_DEFINITION;
} else if (graphql.isInterfaceType(typeInSchema)) {
definitionKind = graphql.Kind.INTERFACE_TYPE_DEFINITION;
} else if (graphql.isInputObjectType(typeInSchema)) {
definitionKind = graphql.Kind.INPUT_OBJECT_TYPE_DEFINITION;
}
if (definitionKind) {
extraDefinitions.push({
kind: definitionKind,
name: definition.name,
fields: extraFields
// `fields` are different in input object types and regular types
});
}
}
}
} else if (definition.kind === graphql.Kind.DIRECTIVE_DEFINITION && !definition.name.value.startsWith("join__") && !definition.name.value.startsWith("core")) {
extraDefinitions.push(definition);
}
}
const additionalTypeDefs = {
kind: graphql.Kind.DOCUMENT,
definitions: extraDefinitions
};
if (opts.onSubschemaConfig) {
for (const subschema of subschemas) {
opts.onSubschemaConfig(subschema);
}
}
return {
subschemas,
typeDefs: additionalTypeDefs,
assumeValid: true,
assumeValidSDL: true,
typeMergingOptions: {
useNonNullableFieldOnConflict: true,
validationSettings: {
validationLevel: stitch.ValidationLevel.Off
},
fieldConfigMerger
}
};
}
function getStitchedSchemaFromSupergraphSdl(opts) {
const stitchSchemasOpts = getStitchingOptionsFromSupergraphSdl(opts);
opts.onStitchingOptions?.(stitchSchemasOpts);
let supergraphSchema = stitch.stitchSchemas(stitchSchemasOpts);
supergraphSchema = filterInternalFieldsAndTypes(supergraphSchema);
if (opts.onStitchedSchema) {
supergraphSchema = opts.onStitchedSchema(supergraphSchema) || supergraphSchema;
}
return supergraphSchema;
}
const anyTypeDefinitionNode = {
name: {
kind: graphql.Kind.NAME,
value: "_Any"
},
kind: graphql.Kind.SCALAR_TYPE_DEFINITION
};
const entitiesFieldDefinitionNode = {
kind: graphql.Kind.FIELD_DEFINITION,
name: {
kind: graphql.Kind.NAME,
value: "_entities"
},
type: {
kind: graphql.Kind.NON_NULL_TYPE,
type: {
kind: graphql.Kind.LIST_TYPE,
type: {
kind: graphql.Kind.NAMED_TYPE,
name: {
kind: graphql.Kind.NAME,
value: "_Entity"
}
}
}
},
arguments: [
{
kind: graphql.Kind.INPUT_VALUE_DEFINITION,
name: {
kind: graphql.Kind.NAME,
value: "representations"
},
type: {
kind: graphql.Kind.NON_NULL_TYPE,
type: {
kind: graphql.Kind.LIST_TYPE,
type: {
kind: graphql.Kind.NON_NULL_TYPE,
type: {
kind: graphql.Kind.NAMED_TYPE,
name: {
kind: graphql.Kind.NAME,
value: "_Any"
}
}
}
}
}
}
]
};
const specifiedTypeNames = [
"ID",
"String",
"Float",
"Int",
"Boolean",
"_Any",
"_Entity"
];
function makeExternalObject(data, errors, getFieldNames) {
if (!delegate.isExternalObject(data) && typeof data === "object" && data != null) {
data[delegate.UNPATHED_ERRORS_SYMBOL] = errors;
}
if (errors.length) {
const errorsToPop = [...errors];
const fieldNamesToPop = [];
for (const fieldName of getFieldNames()) {
if (data?.[fieldName] == null) {
fieldNamesToPop.push(fieldName);
}
}
while (fieldNamesToPop.length && errorsToPop.length) {
const fieldName = fieldNamesToPop.pop();
if (!fieldName) {
break;
}
const error = errorsToPop.pop();
if (!error) {
break;
}
let errorToSet;
if (fieldNamesToPop.length || !errorsToPop.length) {
errorToSet = error;
} else {
errorToSet = new AggregateError(
errorsToPop,
errorsToPop.map((error2) => error2.message).join(", \n")
);
}
if (errorToSet) {
data ||= {};
data[fieldName] = errorToSet;
}
}
}
return data;
}
function mergeResults(results, getFieldNames) {
const errors = [];
const datas = [];
for (const result of results) {
if (result instanceof AggregateError) {
errors.push(...result.errors);
} else if (result instanceof Error) {
errors.push(result);
} else if (result != null) {
datas.push(result);
}
}
if (datas.length) {
if (datas.length === 1) {
return makeExternalObject(datas[0], errors, getFieldNames);
}
return makeExternalObject(
utils.mergeDeep(datas, void 0, true, true),
errors,
getFieldNames
);
}
if (errors.length) {
if (errors.length === 1) {
throw errors[0];
}
return new AggregateError(
errors,
errors.map((error) => error.message).join(", \n")
);
}
return null;
}
const DEFAULT_UPLINKS = [
"https://uplink.api.apollographql.com/",
"https://aws.uplink.api.apollographql.com/"
];
async function fetchSupergraphSdlFromManagedFederation(options = {}) {
const userDefinedUplinks = process.env["APOLLO_SCHEMA_CONFIG_DELIVERY_ENDPOINT"]?.split(",") ?? [];
const {
upLink = userDefinedUplinks[0] || DEFAULT_UPLINKS[0],
loggerByMessageLevel = DEFAULT_MESSAGE_LOGGER,
fetch: fetch$1 = fetch.fetch,
...variables
} = options;
if (!variables.graphRef) {
variables.graphRef = process.env["APOLLO_GRAPH_REF"];
}
if (!variables.apiKey) {
variables.apiKey = process.env["APOLLO_KEY"];
}
if (!upLink) {
throw new Error("No up link provided");
}
const response = await fetch$1(upLink, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
query: (
/* GraphQL */
`
query ($apiKey: String!, $graphRef: String!, $lastSeenId: ID) {
routerConfig(
ref: $graphRef
apiKey: $apiKey
ifAfterId: $lastSeenId
) {
__typename
... on FetchError {
code
message
minDelaySeconds
}
... on Unchanged {
id
minDelaySeconds
}
... on RouterConfigResult {
id
supergraphSdl: supergraphSDL
minDelaySeconds
messages {
level
body
}
}
}
}
`
),
variables
}),
signal: AbortSignal.timeout(3e4)
});
const responseBody = await response.text();
if (!response.ok) {
throw new Error(
`Failed to fetch supergraph SDL from '${upLink}' due to an HTTP error (${response.status}) ${responseBody}`
);
}
let result;
try {
result = JSON.parse(responseBody);
} catch (err) {
throw new Error(
`Failed to parse response from '${upLink}': ${err.message}
${responseBody}`
);
}
if (result.errors) {
throw new AggregateError(
result.errors,
`Failed to fetch supergraph SDL from '${upLink}'`
);
}
if (!result.data?.routerConfig) {
throw new Error(
`Failed to fetch supergraph SDL from '${upLink}': ${responseBody}`
);
}
const { routerConfig } = result.data;
if (routerConfig.__typename === "FetchError") {
return {
error: { code: routerConfig.code, message: routerConfig.message },
minDelaySeconds: routerConfig.minDelaySeconds
};
}
if (routerConfig.__typename === "Unchanged") {
return {
id: routerConfig.id,
minDelaySeconds: routerConfig.minDelaySeconds
};
}
for (const message of routerConfig.messages) {
loggerByMessageLevel[message.level](message.body);
}
return {
supergraphSdl: routerConfig.supergraphSdl,
id: routerConfig.id,
minDelaySeconds: routerConfig.minDelaySeconds
};
}
async function getStitchedSchemaFromManagedFederation(options) {
const result = await fetchSupergraphSdlFromManagedFederation({
graphRef: options.graphRef,
apiKey: options.apiKey,
upLink: options.upLink,
lastSeenId: options.lastSeenId,
fetch: options.fetch,
loggerByMessageLevel: options.loggerByMessageLevel
});
if ("supergraphSdl" in result) {
return {
...result,
schema: getStitchedSchemaFromSupergraphSdl({
supergraphSdl: result.supergraphSdl,
onStitchingOptions: options.onStitchingOptions,
onStitchedSchema: options.onStitchedSchema,
httpExecutorOpts: options.httpExecutorOpts,
onSubschemaConfig: options.onSubschemaConfig,
batch: options.batch
})
};
}
return result;
}
const DEFAULT_MESSAGE_LOGGER = {
ERROR: (message) => console.error("[Managed Federation] Uplink message: [ERROR]", message),
WARN: (message) => console.warn("[Managed Federation] Uplink message: [WARN]", message),
INFO: (message) => console.info("[Managed Federation] Uplink message: [INFO]", message)
};
const TypedEventTargetCtor = EventTarget;
class SupergraphSchemaManager extends TypedEventTargetCtor {
constructor(options = {}) {
super();
this.options = options;
}
schema = void 0;
#lastSeenId;
#retries = 1;
#timeout;
load = async (options) => {
this.options.apiKey ||= options.apollo.key;
this.options.graphRef ||= options.apollo.graphRef;
await this.#fetchSchema();
return {
executor(requestContext) {
return delegate.createDefaultExecutor(requestContext.schema)({
document: requestContext.document,
variables: requestContext.request.variables,
operationType: requestContext.operation.operation,
operationName: requestContext.operationName || void 0,
context: requestContext.context
});
}
};
};
onSchemaLoadOrUpdate = (callback) => {
const onSchemaChange = (event) => {
callback({
apiSchema: event.detail.schema,
coreSupergraphSdl: event.detail.supergraphSdl
});
};
this.addEventListener("schema", onSchemaChange);
return () => {
this.removeEventListener("schema", onSchemaChange);
};
};
start = (delayInSeconds = 0) => {
if (this.#timeout) {
this.stop();
}
this.#timeout = setTimeout(() => {
this.#log("info", "Polling started");
this.#retries = 1;
this.#fetchSchema();
}, delayInSeconds * 1e3);
};
forcePull = () => {
if (this.#timeout) {
clearTimeout(this.#timeout);
this.#timeout = void 0;
}
this.#retries = 1;
this.#fetchSchema();
};
stop = () => {
this.#log("info", "Polling stopped");
if (this.#timeout) {
clearTimeout(this.#timeout);
this.#timeout = void 0;
}
return utils.fakePromise();
};
#fetchSchema = async () => {
const { retryDelaySeconds = 0, minDelaySeconds = 0 } = this.options;
try {
this.#log("info", "Fetch schema from managed federation");
const result = await getStitchedSchemaFromManagedFederation({
...this.options,
loggerByMessageLevel: {
ERROR: (message) => {
const logEvent = new events.CustomEvent(
"log",
{
detail: { source: "uplink", level: "error", message }
}
);
this.dispatchEvent(logEvent);
},
WARN: (message) => {
const logEvent = new events.CustomEvent(
"log",
{
detail: { source: "uplink", level: "warn", message }
}
);
this.dispatchEvent(logEvent);
},
INFO: (message) => {
const logEvent = new events.CustomEvent(
"log",
{
detail: { source: "uplink", level: "info", message }
}
);
this.dispatchEvent(logEvent);
}
},
lastSeenId: this.#lastSeenId
});
if ("error" in result) {
this.#lastSeenId = void 0;
const errorEvent = new events.CustomEvent(
"error",
{
detail: {
error: result.error,
minDelaySeconds: result.minDelaySeconds
}
}
);
this.dispatchEvent(errorEvent);
this.#retryOnError(
result.error,
Math.max(result.minDelaySeconds, minDelaySeconds)
);
return;
}
if ("schema" in result) {
this.#lastSeenId = result.id;
this.schema = result.schema;
const schemaEvent = new events.CustomEvent(
"schema",
{
detail: {
schema: result.schema,
supergraphSdl: result.supergraphSdl
}
}
);
this.dispatchEvent(schemaEvent);
this.#log("info", "Supergraph successfully updated");
} else {
this.#log("info", "Supergraph is up to date");
}
this.#retries = 1;
const delay = Math.max(result.minDelaySeconds, minDelaySeconds);
this.#timeout = setTimeout(this.#fetchSchema, delay * 1e3);
this.#log("info", `Next pull in ${delay.toFixed(1)} seconds`);
} catch (e) {
this.#retryOnError(e, retryDelaySeconds ?? 0);
const errorEvent = new events.CustomEvent(
"error",
{
detail: e
}
);
this.dispatchEvent(errorEvent);
}
};
#retryOnError = (error, delayInSeconds) => {
const { maxRetries = 3 } = this.options;
const message = error?.message;
this.#log(
"error",
`Failed to pull schema from managed federation: ${message}`
);
if (this.#retries >= maxRetries) {
this.#timeout = void 0;
this.#log("error", "Max retries reached, giving up");
const failureEvent = new events.CustomEvent(
"failure",
{
detail: { error, delayInSeconds }
}
);
this.dispatchEvent(failureEvent);
return;
}
this.#retries++;
this.#log(
"info",
`Retrying (${this.#retries}/${maxRetries})${delayInSeconds ? ` in ${delayInSeconds.toFixed(1)} seconds` : ""}`
);
this.#timeout = setTimeout(this.#fetchSchema, delayInSeconds * 1e3);
};
#log = (level, message) => {
const logEvent = new events.CustomEvent("log", {
detail: {
source: "manager",
level,
message
}
});
this.dispatchEvent(logEvent);
};
[disposablestack.DisposableSymbols.dispose]() {
return this.stop();
}
}
exports.DEFAULT_UPLINKS = DEFAULT_UPLINKS;
exports.SupergraphSchemaManager = SupergraphSchemaManager;
exports.ensureSupergraphSDLAst = ensureSupergraphSDLAst;
exports.fetchSupergraphSdlFromManagedFederation = fetchSupergraphSdlFromManagedFederation;
exports.filterInternalFieldsAndTypes = filterInternalFieldsAndTypes;
exports.getArgsFromKeysForFederation = getArgsFromKeysForFederation;
exports.getCacheKeyFnFromKey = getCacheKeyFnFromKey;
exports.getKeyFnForFederation = getKeyFnForFederation;
exports.getNamedTypeNode = getNamedTypeNode;
exports.getStitchedSchemaFromManagedFederation = getStitchedSchemaFromManagedFederation;
exports.getStitchedSchemaFromSupergraphSdl = getStitchedSchemaFromSupergraphSdl;
exports.getStitchingOptionsFromSupergraphSdl = getStitchingOptionsFromSupergraphSdl;
exports.projectDataSelectionSet = projectDataSelectionSet;