@graphql-mesh/serve-runtime
Version:
108 lines (107 loc) • 4.33 kB
JavaScript
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 { useExecutor } from '@graphql-tools/executor-yoga';
import { isPromise } from '@graphql-tools/utils';
import { getProxyExecutor } from './getProxyExecutor.js';
import { handleUnifiedGraphConfig } from './handleUnifiedGraphConfig.js';
export function createServeRuntime(config) {
let fetchAPI = config.fetchAPI;
// eslint-disable-next-line prefer-const
let logger;
let wrappedFetchFn;
const configContext = {
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 ('fusiongraph' in config) {
supergraphYogaPlugin = useFusiongraph({
getFusiongraph: () => handleUnifiedGraphConfig(config.fusiongraph, configContext),
transports: config.transports,
polling: config.polling,
additionalResolvers: config.additionalResolvers,
transportBaseContext: configContext,
});
}
else if ('supergraph' in config) {
supergraphYogaPlugin = useFusiongraph({
getFusiongraph() {
const supergraph$ = handleUnifiedGraphConfig(config.supergraph, configContext);
configContext.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: configContext,
});
}
else if ('proxy' in config) {
let schema;
const executorPlugin = useExecutor(getProxyExecutor(config, configContext, () => schema));
supergraphYogaPlugin = {
onSchemaChange: payload => {
schema = payload.schema;
},
...executorPlugin,
invalidateUnifiedGraph: () => (executorPlugin.invalidateSupergraph || executorPlugin.invalidateUnifiedGraph)(),
};
}
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?.(configContext) || [])],
context: ({ request, req, connectionParams }) => ({
...configContext,
headers:
// Maybe Node-like environment
req?.headers
? getHeadersObj(req.headers)
: // Fetch environment
request?.headers
? getHeadersObj(request.headers)
: // Unknown environment
{},
connectionParams,
}),
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;
}