UNPKG

@graphql-mesh/fusion-runtime

Version:

Runtime for GraphQL Mesh Fusion Supergraph

266 lines (265 loc) • 11.9 kB
"use strict"; 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); }