@graphql-mesh/supergraph
Version:
160 lines (159 loc) • 8.14 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
const graphql_1 = require("graphql");
const cross_helpers_1 = require("@graphql-mesh/cross-helpers");
const store_1 = require("@graphql-mesh/store");
const string_interpolation_1 = require("@graphql-mesh/string-interpolation");
const utils_1 = require("@graphql-mesh/utils");
const federation_1 = require("@graphql-tools/federation");
const url_loader_1 = require("@graphql-tools/url-loader");
const utils_2 = require("@graphql-tools/utils");
class SupergraphHandler {
constructor({ config, baseDir, store, importFn, logger, }) {
this.config = config;
this.baseDir = baseDir;
this.supergraphSdl = store.proxy('nonExecutableSchema', store_1.PredefinedProxyOptions.JsonWithoutValidation);
this.importFn = importFn;
this.logger = logger;
}
async getSupergraphSdl() {
const schemaHeadersFactory = (0, string_interpolation_1.getInterpolatedHeadersFactory)(this.config.schemaHeaders);
const interpolatedSource = string_interpolation_1.stringInterpolator.parse(this.config.source, {
env: cross_helpers_1.process.env,
});
if ((0, utils_1.isUrl)(interpolatedSource)) {
const res = await (0, utils_1.readUrl)(interpolatedSource, {
headers: schemaHeadersFactory({
env: cross_helpers_1.process.env,
}),
cwd: this.baseDir,
allowUnknownExtensions: true,
importFn: this.importFn,
fetch: this.fetchFn,
logger: this.logger,
}).catch(e => {
throw new Error(`Failed to load supergraph SDL from ${interpolatedSource}:\n ${e.message}`);
});
return handleSupergraphResponse(res, interpolatedSource);
}
return this.supergraphSdl.getWithSet(async () => {
const sdlOrIntrospection = await (0, utils_1.readFile)(interpolatedSource, {
headers: schemaHeadersFactory({
env: cross_helpers_1.process.env,
}),
cwd: this.baseDir,
allowUnknownExtensions: true,
importFn: this.importFn,
fetch: this.fetchFn,
logger: this.logger,
}).catch(e => {
throw new Error(`Failed to load supergraph SDL from ${interpolatedSource}:\n ${e.message}`);
});
return handleSupergraphResponse(sdlOrIntrospection, interpolatedSource);
});
}
async getMeshSource({ fetchFn }) {
const subgraphConfigs = this.config.subgraphs || [];
this.fetchFn = fetchFn;
const supergraphSdl = await this.getSupergraphSdl();
const operationHeadersFactory = this.config.operationHeaders != null
? (0, string_interpolation_1.getInterpolatedHeadersFactory)(this.config.operationHeaders)
: undefined;
const joingraphEnum = supergraphSdl.definitions.find(def => def.kind === 'EnumTypeDefinition' && def.name.value === 'join__Graph');
const subgraphNameIdMap = new Map();
if (joingraphEnum) {
joingraphEnum.values?.forEach(value => {
value.directives?.forEach(directive => {
if (directive.name.value === 'join__graph') {
const nameArg = directive.arguments?.find(arg => arg.name.value === 'name');
if (nameArg?.value?.kind === 'StringValue') {
subgraphNameIdMap.set(value.name.value, nameArg.value.value);
}
}
});
});
}
const urlLoader = new url_loader_1.UrlLoader();
const schema = (0, federation_1.getStitchedSchemaFromSupergraphSdl)({
supergraphSdl,
onSubschemaConfig(subschemaConfig) {
const subgraphName = subschemaConfig.name;
let nonInterpolatedEndpoint = subschemaConfig.endpoint;
const subgraphRealName = subgraphNameIdMap.get(subgraphName);
const subgraphConfiguration = subgraphConfigs.find(subgraphConfig => subgraphConfig.name === subgraphRealName) || {
name: subgraphName,
};
nonInterpolatedEndpoint = subgraphConfiguration.endpoint || nonInterpolatedEndpoint;
const endpointFactory = (0, string_interpolation_1.getInterpolatedStringFactory)(nonInterpolatedEndpoint);
const connectionParamsFactory = (0, string_interpolation_1.getInterpolatedHeadersFactory)(subgraphConfiguration.connectionParams);
const subscriptionsEndpoint = subgraphConfiguration.subscriptionsEndpoint
? string_interpolation_1.stringInterpolator.parse(subgraphConfiguration.subscriptionsEndpoint, {
env: cross_helpers_1.process.env,
})
: undefined;
const subgraphExecutor = urlLoader.getExecutorAsync(nonInterpolatedEndpoint, {
...subgraphConfiguration,
subscriptionsEndpoint,
subscriptionsProtocol: subgraphConfiguration.subscriptionsProtocol,
// @ts-expect-error - this is a bug in the types
customFetch: fetchFn,
});
const subgraphOperationHeadersFactory = subgraphConfiguration.operationHeaders != null
? (0, string_interpolation_1.getInterpolatedHeadersFactory)(subgraphConfiguration.operationHeaders)
: undefined;
subschemaConfig.executor = function subgraphExecutorWithInterpolations(params) {
const resolverData = getResolverData(params);
let headers;
if (operationHeadersFactory) {
headers = operationHeadersFactory(resolverData);
}
if (subgraphOperationHeadersFactory) {
const subgraphHeaders = subgraphOperationHeadersFactory(resolverData);
if (headers) {
Object.assign(headers, subgraphHeaders);
}
else {
headers = subgraphHeaders;
}
}
return subgraphExecutor({
...params,
extensions: {
...(params.extensions || {}),
headers,
connectionParams: connectionParamsFactory(resolverData),
endpoint: endpointFactory(resolverData),
},
});
};
},
batch: this.config.batch == null ? true : this.config.batch,
});
return {
schema,
};
}
}
exports.default = SupergraphHandler;
function handleSupergraphResponse(sdlOrDocumentNode, interpolatedSource) {
if (typeof sdlOrDocumentNode === 'string') {
try {
return (0, graphql_1.parse)(sdlOrDocumentNode, { noLocation: true });
}
catch (e) {
throw new Error(`Supergraph source must be a valid GraphQL SDL string or a parsed DocumentNode, but got an invalid result from ${interpolatedSource} instead.\n Got result: ${sdlOrDocumentNode}\n Got error: ${e.message}`);
}
}
if (sdlOrDocumentNode?.kind !== 'Document') {
throw new Error(`Supergraph source must be a valid GraphQL SDL string or a parsed DocumentNode, but got an invalid result from ${interpolatedSource} instead.\n Got result: ${JSON.stringify(sdlOrDocumentNode, null, 2)}`);
}
return sdlOrDocumentNode;
}
const getResolverData = (0, utils_2.memoize1)(function getResolverData(params) {
return {
root: params.rootValue,
args: params.variables,
context: params.context,
env: cross_helpers_1.process.env,
};
});
;