UNPKG

@graphql-mesh/fusion-runtime

Version:

Runtime for GraphQL Mesh Fusion Supergraph

138 lines (137 loc) 5.38 kB
import { buildASTSchema, buildSchema, isSchema, } from 'graphql'; import { useReadinessCheck } from 'graphql-yoga'; import { getInContextSDK } from '@graphql-mesh/runtime'; import { mapMaybePromise, resolveAdditionalResolversWithoutImport } from '@graphql-mesh/utils'; import { stitchSchemas } from '@graphql-tools/stitch'; import { isDocumentNode, isPromise } from '@graphql-tools/utils'; import { extractSubgraphsFromFusiongraph } from './getSubschemasFromFusiongraph.js'; import { defaultTransportsOption, getOnSubgraphExecute, } from './utils.js'; function ensureSchema(source) { if (isSchema(source)) { return source; } if (typeof source === 'string') { return buildSchema(source, { assumeValid: true, assumeValidSDL: true }); } if (isDocumentNode(source)) { return buildASTSchema(source, { assumeValid: true, assumeValidSDL: true }); } return source; } export function useFusiongraph(opts) { let fusiongraph; let lastLoadedFusiongraph; let yoga; // TODO: We need to figure this out in a better way let inContextSDK; function handleLoadedFusiongraph(loadedFusiongraph) { if (loadedFusiongraph != null && lastLoadedFusiongraph === loadedFusiongraph) { return; } lastLoadedFusiongraph = loadedFusiongraph; fusiongraph = ensureSchema(loadedFusiongraph); const { transportEntryMap, subschemaMap, additionalTypeDefs, additionalResolversFromTypeDefs } = extractSubgraphsFromFusiongraph(fusiongraph); const subgraphMap = new Map(); const subschemas = []; const onSubgraphExecute = getOnSubgraphExecute({ fusiongraph, plugins: yoga.getEnveloped._plugins, transports: opts.transports || defaultTransportsOption, transportBaseContext: opts.transportBaseContext, transportEntryMap, subgraphMap, }); for (const [subschemaName, subschemaConfig] of subschemaMap) { subgraphMap.set(subschemaName, subschemaConfig.schema); subschemas.push({ ...subschemaConfig, name: subschemaName, executor(execReq) { return onSubgraphExecute(subschemaName, execReq); }, }); } fusiongraph = stitchSchemas({ subschemas, assumeValid: true, assumeValidSDL: true, typeDefs: [opts.additionalTypedefs, ...additionalTypeDefs], resolvers: [ opts.additionalResolvers, additionalResolversFromTypeDefs.map(additionalResolver => resolveAdditionalResolversWithoutImport(additionalResolver)), ], }); if (opts.additionalResolvers || additionalResolversFromTypeDefs.length) { const onDelegateHooks = []; for (const plugin of yoga.getEnveloped._plugins) { if (plugin.onDelegate) { onDelegateHooks.push(plugin.onDelegate); } } inContextSDK = getInContextSDK(fusiongraph, subschemas, opts.transportBaseContext?.logger, onDelegateHooks); } } function getAndSetFusiongraph() { const supergraph$ = opts.getFusiongraph(opts.transportBaseContext); return mapMaybePromise(supergraph$, handleLoadedFusiongraph); } if (opts.polling) { setInterval(getAndSetFusiongraph, opts.polling); } let initialFusiongraph$; let initiated = false; function ensureFusiongraph() { if (!initiated) { initialFusiongraph$ = getAndSetFusiongraph(); } initiated = true; return initialFusiongraph$; } return { onYogaInit(payload) { yoga = payload.yoga; }, onPluginInit({ addPlugin }) { if (opts.readinessCheckEndpoint) { addPlugin( // TODO: fix useReadinessCheck typings to inherit the context useReadinessCheck({ endpoint: opts.readinessCheckEndpoint, check() { const initialFusiongraph$ = ensureFusiongraph(); if (isPromise(initialFusiongraph$)) { return initialFusiongraph$.then(() => !!fusiongraph); } return !!fusiongraph; }, })); } }, onRequestParse() { return { onRequestParseDone() { return ensureFusiongraph(); }, }; }, onEnveloped({ setSchema }) { setSchema(fusiongraph); }, onContextBuilding({ extendContext }) { const initialFusiongraph$ = ensureFusiongraph(); function handleInitiatedFusiongraph() { if (inContextSDK) { extendContext(inContextSDK); } extendContext(opts.transportBaseContext); } if (isPromise(initialFusiongraph$)) { return initialFusiongraph$.then(handleInitiatedFusiongraph); } handleInitiatedFusiongraph(); }, invalidateUnifiedGraph() { return getAndSetFusiongraph(); }, }; }