UNPKG

@graphql-mesh/serve-runtime

Version:
110 lines (109 loc) 4.25 kB
import { createYoga } from 'graphql-yoga'; import { convertSupergraphToFusiongraph } from '@graphql-mesh/fusion-federation'; import { useFusiongraph } from '@graphql-mesh/fusion-runtime'; // eslint-disable-next-line import/no-extraneous-dependencies import { DefaultLogger, getHeadersObj, wrapFetchWithHooks } from '@graphql-mesh/utils'; import { buildHTTPExecutor } from '@graphql-tools/executor-http'; import { useExecutor } from '@graphql-tools/executor-yoga'; import { isPromise } from '@graphql-tools/utils'; import { handleUnifiedGraphConfig } from './handleUnifiedGraphConfig.js'; export function createServeRuntime(config) { let fetchAPI = config.fetchAPI; // eslint-disable-next-line prefer-const let logger; let wrappedFetchFn; const serveContext = { get fetch() { return wrappedFetchFn; }, get logger() { return logger; }, cwd: globalThis.process?.cwd(), cache: 'cache' in config ? config.cache : undefined, pubsub: 'pubsub' in config ? config.pubsub : undefined, }; let supergraphYogaPlugin; if ('http' in config) { const executor = buildHTTPExecutor({ fetch: fetchAPI?.fetch, ...config.http, }); supergraphYogaPlugin = useExecutor(executor); } else if ('fusiongraph' in config) { supergraphYogaPlugin = useFusiongraph({ getFusiongraph() { return handleUnifiedGraphConfig(config.fusiongraph || './fusiongraph.graphql', serveContext); }, transports: config.transports, polling: config.polling, additionalResolvers: config.additionalResolvers, transportBaseContext: serveContext, }); } else if ('supergraph' in config) { supergraphYogaPlugin = useFusiongraph({ getFusiongraph() { const supergraph$ = handleUnifiedGraphConfig(config.supergraph || './supergraph.graphql', serveContext); serveContext.logger?.info?.(`Converting Federation Supergraph to Fusiongraph`); if (isPromise(supergraph$)) { return supergraph$.then(supergraph => convertSupergraphToFusiongraph(supergraph)); } return convertSupergraphToFusiongraph(supergraph$); }, transports: config.transports, polling: config.polling, additionalResolvers: config.additionalResolvers, transportBaseContext: serveContext, }); } const defaultFetchPlugin = { onFetch({ setFetchFn }) { setFetchFn(fetchAPI.fetch); }, onYogaInit({ yoga }) { const onFetchHooks = []; for (const plugin of yoga.getEnveloped._plugins) { if (plugin.onFetch) { onFetchHooks.push(plugin.onFetch); } } wrappedFetchFn = wrapFetchWithHooks(onFetchHooks); }, }; const yoga = createYoga({ fetchAPI: config.fetchAPI, logging: config.logging == null ? new DefaultLogger() : config.logging, plugins: [defaultFetchPlugin, supergraphYogaPlugin, ...(config.plugins?.(serveContext) || [])], context({ request, req, connectionParams }) { // Maybe Node-like environment if (req?.headers) { return { headers: getHeadersObj(req.headers), connectionParams, }; } // Fetch environment if (request?.headers) { return { headers: getHeadersObj(request.headers), connectionParams, }; } return undefined; }, cors: config.cors, graphiql: config.graphiql, batching: config.batching, graphqlEndpoint: config.graphqlEndpoint, maskedErrors: config.maskedErrors, }); fetchAPI ||= yoga.fetchAPI; logger = yoga.logger; Object.defineProperty(yoga, 'invalidateUnifiedGraph', { value: supergraphYogaPlugin.invalidateUnifiedGraph, configurable: true, }); return yoga; }