UNPKG

@graphql-mesh/serve-cli

Version:
124 lines (123 loc) 4.9 kB
import { promises as fsPromises } from 'node:fs'; import { createServer as createHTTPServer } from 'node:http'; import { createServer as createHTTPSServer } from 'node:https'; import { createAsyncDisposable, getTerminateStack } from '@graphql-mesh/utils'; import { defaultOptions } from './cli.js'; export async function startServerForRuntime(runtime, { log, host = defaultOptions.host, port = defaultOptions.port, sslCredentials, maxHeaderSize = 16_384, disableWebsockets = false, }) { const terminateStack = getTerminateStack(); terminateStack.use(runtime); process.on('message', message => { if (message === 'invalidateUnifiedGraph') { log.info(`Invalidating Supergraph`); runtime.invalidateUnifiedGraph(); } }); const serverOpts = { log, host, port, sslCredentials, maxHeaderSize, disableWebsockets, }; const server = await startNodeHttpServer(runtime, serverOpts); terminateStack.use(server); return server; } async function startNodeHttpServer(gwRuntime, opts) { const { log, host = defaultOptions.host, port = defaultOptions.port, sslCredentials, maxHeaderSize, disableWebsockets, } = opts; let server; let protocol; if (sslCredentials) { protocol = 'https'; const sslOptionsForNodeHttp = {}; if (sslCredentials.ca_file_name) { sslOptionsForNodeHttp.ca = await fsPromises.readFile(sslCredentials.ca_file_name); } if (sslCredentials.cert_file_name) { sslOptionsForNodeHttp.cert = await fsPromises.readFile(sslCredentials.cert_file_name); } if (sslCredentials.dh_params_file_name) { sslOptionsForNodeHttp.dhparam = await fsPromises.readFile(sslCredentials.dh_params_file_name); } if (sslCredentials.key_file_name) { sslOptionsForNodeHttp.key = await fsPromises.readFile(sslCredentials.key_file_name); } if (sslCredentials.passphrase) { sslOptionsForNodeHttp.passphrase = sslCredentials.passphrase; } if (sslCredentials.ssl_ciphers) { sslOptionsForNodeHttp.ciphers = sslCredentials.ssl_ciphers; } if (sslCredentials.ssl_prefer_low_memory_usage) { sslOptionsForNodeHttp.honorCipherOrder = true; } server = createHTTPSServer({ ...sslOptionsForNodeHttp, maxHeaderSize, }, gwRuntime); } else { protocol = 'http'; server = createHTTPServer({ maxHeaderSize, }, gwRuntime); } const url = `${protocol}://${host}:${port}`.replace('0.0.0.0', 'localhost'); log.debug(`Starting server on ${url}`); if (!disableWebsockets) { const { WebSocketServer } = await import('ws'); const wsServer = new WebSocketServer({ path: gwRuntime.graphqlEndpoint, server, }); const graphqlWSOptions = getGraphQLWSOptions(gwRuntime); const { useServer } = await import('graphql-ws/lib/use/ws'); useServer(graphqlWSOptions, wsServer); } return new Promise((resolve, reject) => { server.once('error', reject); server.listen(port, host, () => { log.info(`Listening on ${url}`); resolve(createAsyncDisposable(() => new Promise(resolve => { process.stderr.write('\n'); log.info(`Stopping the server`); server.closeAllConnections(); server.close(() => { log.info(`Stopped the server successfully`); resolve(); }); }))); }); }); } export function getGraphQLWSOptions(gwRuntime) { return { execute: (args) => args.rootValue.execute(args), subscribe: (args) => args.rootValue.subscribe(args), onSubscribe: async (ctx, msg) => { const { schema, execute, subscribe, contextFactory, parse, validate } = gwRuntime.getEnveloped({ connectionParams: ctx.connectionParams, req: ctx.extra.request, }); const args = { schema: schema || (await gwRuntime.getSchema()), operationName: msg.payload.operationName, document: parse(msg.payload.query), variableValues: msg.payload.variables, contextValue: await contextFactory(), rootValue: { execute, subscribe, }, }; if (args.schema) { const errors = validate(args.schema, args.document); if (errors.length) return errors; } return args; }, // eslint-disable-next-line @typescript-eslint/consistent-type-imports }; }