@graphql-mesh/fusion-runtime
Version:
Runtime for GraphQL Mesh Fusion Supergraph
266 lines (265 loc) • 11.9 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.subgraphNameByExecutionRequest = void 0;
exports.getOnSubgraphExecute = getOnSubgraphExecute;
exports.wrapExecutorWithHooks = wrapExecutorWithHooks;
exports.compareSchemas = compareSchemas;
exports.compareSubgraphNames = compareSubgraphNames;
const change_case_1 = require("change-case");
const graphql_1 = require("graphql");
const utils_1 = require("@graphql-mesh/utils");
const utils_2 = require("@graphql-tools/utils");
async function defaultTransportsGetter(kind) {
try {
let transport = await Promise.resolve(`${`@graphql-mesh/transport-${kind}`}`).then(s => __importStar(require(s)));
if (!transport) {
throw new Error(`@graphql-mesh/transport-${kind} module does not export anything`);
}
if (typeof transport !== 'object') {
throw new Error(`@graphql-mesh/transport-${kind} module does not export an object`);
}
if (transport.default?.getSubgraphExecutor) {
transport = transport.default;
}
if (!transport.getSubgraphExecutor) {
throw new Error(`@graphql-mesh/transport-${kind} module does not export "getSubgraphExecutor"`);
}
if (typeof transport.getSubgraphExecutor !== 'function') {
throw new Error(`@graphql-mesh/transport-${kind} module's export "getSubgraphExecutor" is not a function`);
}
return transport;
}
catch (e) {
if (e.code === 'MODULE_NOT_FOUND') {
throw new Error(`No transport found for ${kind}. Please make sure you have installed @graphql-mesh/transport-${kind} or defined the transport config in "mesh.config.ts"`);
}
else {
throw e; // bubble non-module_not_found errors
}
}
}
function getTransportExecutor({ transportContext, transportEntry, subgraphName = '', subgraph, transports = defaultTransportsGetter, }) {
const kind = transportEntry.kind;
transportContext?.logger?.debug(`Loading transport "${kind}" for subgraph ${subgraphName}`);
return (0, utils_1.mapMaybePromise)(typeof transports === 'function' ? transports(kind) : transports[kind], transport => {
if (!transport) {
throw new Error(`Transport "${kind}" is empty`);
}
if (typeof transport !== 'object') {
throw new Error(`Transport "${kind}" is not an object`);
}
let getSubgraphExecutor;
if ('default' in transport) {
getSubgraphExecutor = transport.default?.getSubgraphExecutor;
}
else {
getSubgraphExecutor = transport.getSubgraphExecutor;
}
if (!getSubgraphExecutor) {
throw new Error(`Transport "${kind}" does not have "getSubgraphExecutor"`);
}
if (typeof getSubgraphExecutor !== 'function') {
throw new Error(`Transport "${kind}" "getSubgraphExecutor" is not a function`);
}
return getSubgraphExecutor({
subgraphName,
subgraph,
transportEntry,
getTransportExecutor(transportEntry) {
return getTransportExecutor({
transportContext,
transportEntry,
subgraphName,
subgraph,
transports,
});
},
...transportContext,
});
});
}
exports.subgraphNameByExecutionRequest = new WeakMap();
/**
* This function creates a executor factory that uses the transport packages,
* and wraps them with the hooks
*/
function getOnSubgraphExecute({ onSubgraphExecuteHooks, transportContext, transportEntryMap, getSubgraphSchema, transportExecutorStack, transports, }) {
const subgraphExecutorMap = new Map();
return function onSubgraphExecute(subgraphName, executionRequest) {
exports.subgraphNameByExecutionRequest.set(executionRequest, subgraphName);
let executor = subgraphExecutorMap.get(subgraphName);
// If the executor is not initialized yet, initialize it
if (executor == null) {
transportContext?.logger?.debug(`Initializing executor for subgraph ${subgraphName}`);
// Lazy executor that loads transport executor on demand
executor = function lazyExecutor(subgraphExecReq) {
return (0, utils_1.mapMaybePromise)(
// Gets the transport executor for the given subgraph
getTransportExecutor({
transportContext,
subgraphName,
get subgraph() {
return getSubgraphSchema(subgraphName);
},
get transportEntry() {
return transportEntryMap?.[subgraphName];
},
transports,
}), executor_ => {
if ((0, utils_1.isDisposable)(executor_)) {
transportExecutorStack.use(executor_);
}
// Wraps the transport executor with hooks
executor = wrapExecutorWithHooks({
executor: executor_,
onSubgraphExecuteHooks,
subgraphName,
transportEntryMap,
transportContext,
getSubgraphSchema,
});
// Caches the executor for future use
subgraphExecutorMap.set(subgraphName, executor);
return executor(subgraphExecReq);
});
};
// Caches the lazy executor to prevent race conditions
subgraphExecutorMap.set(subgraphName, executor);
}
return executor(executionRequest);
};
}
/**
* This function wraps the executor created by the transport package
* with `onSubgraphExecuteHooks` to hook into the execution phase of subgraphs
*/
function wrapExecutorWithHooks({ executor, onSubgraphExecuteHooks, subgraphName, transportEntryMap, getSubgraphSchema, transportContext, }) {
return function executorWithHooks(executionRequest) {
executionRequest.info = executionRequest.info || {};
executionRequest.info.executionRequest = executionRequest;
const requestId = executionRequest.context?.request && utils_1.requestIdByRequest.get(executionRequest.context.request);
let execReqLogger = transportContext?.logger?.child?.(subgraphName);
if (execReqLogger) {
if (requestId) {
execReqLogger = execReqLogger.child(requestId);
}
utils_1.loggerForExecutionRequest.set(executionRequest, execReqLogger);
}
if (onSubgraphExecuteHooks.length === 0) {
return executor(executionRequest);
}
const onSubgraphExecuteDoneHooks = [];
return (0, utils_1.mapMaybePromise)((0, utils_1.iterateAsync)(onSubgraphExecuteHooks, onSubgraphExecuteHook => onSubgraphExecuteHook({
get subgraph() {
return getSubgraphSchema(subgraphName);
},
subgraphName,
get transportEntry() {
return transportEntryMap?.[subgraphName];
},
executionRequest,
setExecutionRequest(newExecutionRequest) {
execReqLogger.debug('Updating execution request to: ', newExecutionRequest);
executionRequest = newExecutionRequest;
},
executor,
setExecutor(newExecutor) {
execReqLogger.debug('executor has been updated');
executor = newExecutor;
},
requestId,
logger: execReqLogger,
}), onSubgraphExecuteDoneHooks), () => {
if (onSubgraphExecuteDoneHooks.length === 0) {
return executor(executionRequest);
}
return (0, utils_1.mapMaybePromise)(executor(executionRequest), currentResult => {
const executeDoneResults = [];
return (0, utils_1.mapMaybePromise)((0, utils_1.iterateAsync)(onSubgraphExecuteDoneHooks, onSubgraphExecuteDoneHook => onSubgraphExecuteDoneHook({
result: currentResult,
setResult(newResult) {
execReqLogger.debug('overriding result with: ', newResult);
currentResult = newResult;
},
}), executeDoneResults), () => {
if (!(0, utils_2.isAsyncIterable)(currentResult)) {
return currentResult;
}
if (executeDoneResults.length === 0) {
return currentResult;
}
const onNextHooks = [];
const onEndHooks = [];
for (const executeDoneResult of executeDoneResults) {
if (executeDoneResult.onNext) {
onNextHooks.push(executeDoneResult.onNext);
}
if (executeDoneResult.onEnd) {
onEndHooks.push(executeDoneResult.onEnd);
}
}
if (onNextHooks.length === 0 && onEndHooks.length === 0) {
return currentResult;
}
return (0, utils_2.mapAsyncIterator)(currentResult, currentResult => (0, utils_1.mapMaybePromise)((0, utils_1.iterateAsync)(onNextHooks, onNext => onNext({
result: currentResult,
setResult: res => {
execReqLogger.debug('overriding result with: ', res);
currentResult = res;
},
})), () => currentResult), undefined, () => onEndHooks.length === 0 ? undefined : (0, utils_1.iterateAsync)(onEndHooks, onEnd => onEnd()));
});
});
});
};
}
function compareSchemas(a, b) {
let aStr;
if (typeof a === 'string') {
aStr = a;
}
else if ((0, utils_2.isDocumentNode)(a)) {
aStr = (0, graphql_1.print)(a);
}
else {
aStr = (0, utils_2.printSchemaWithDirectives)(a);
}
let bStr;
if (typeof b === 'string') {
bStr = b;
}
else if ((0, utils_2.isDocumentNode)(b)) {
bStr = (0, graphql_1.print)(b);
}
else {
bStr = (0, utils_2.printSchemaWithDirectives)(b);
}
return aStr === bStr;
}
// TODO: Fix this in GraphQL Tools
function compareSubgraphNames(name1, name2) {
return (0, change_case_1.constantCase)(name1) === (0, change_case_1.constantCase)(name2);
}