UNPKG

@graphql-mesh/http

Version:
116 lines (110 loc) 4.49 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); const crossHelpers = require('@graphql-mesh/cross-helpers'); const utils = require('@graphql-mesh/utils'); const server = require('@whatwg-node/server'); const ittyRouter = require('itty-router'); const ittyRouterExtras = require('itty-router-extras'); const graphqlYoga = require('graphql-yoga'); const fetch = require('@whatwg-node/fetch'); const graphqlHandler = (mesh$, playgroundTitle, playgroundEnabled, graphqlEndpoint, corsConfig) => { const yoga$ = mesh$.then(mesh => graphqlYoga.createYoga({ parserCache: false, validationCache: false, plugins: [ ...mesh.plugins, graphqlYoga.useLogger({ skipIntrospection: true, logFn: (eventName, { args }) => { if (eventName.endsWith('-start')) { mesh.logger.debug(`\t headers: `, args.contextValue.headers); } }, }), ], logging: mesh.logger, maskedErrors: false, graphiql: playgroundEnabled && { title: playgroundTitle, }, cors: corsConfig, graphqlEndpoint, landingPage: false, })); return async (request, ...args) => { const yoga = await yoga$; return yoga.handle(request, ...args); }; }; function createMeshHTTPHandler({ baseDir, getBuiltMesh, rawServeConfig = {}, playgroundTitle, }) { let readyFlag = false; let logger = new utils.DefaultLogger('Mesh HTTP'); const mesh$ = getBuiltMesh().then(mesh => { readyFlag = true; logger = mesh.logger.child('HTTP'); return mesh; }); const { cors: corsConfig, staticFiles, playground: playgroundEnabled, endpoint: graphqlPath = '/graphql', // TODO // trustProxy = 'loopback', } = rawServeConfig; const serverAdapter = server.createServerAdapter(ittyRouter.Router()); serverAdapter.all('/healthcheck', () => new fetch.Response(null, { status: 200, })); serverAdapter.all('/readiness', () => new fetch.Response(null, { status: readyFlag ? 204 : 503, })); serverAdapter.post('*', async (request) => { if (readyFlag) { const { pubsub } = await mesh$; for (const eventName of pubsub.getEventNames()) { const { pathname } = new URL(request.url); if (eventName === `webhook:${request.method.toLowerCase()}:${pathname}`) { const body = await request.text(); logger.debug(`Received webhook request for ${pathname}`, body); pubsub.publish(eventName, request.headers.get('content-type') === 'application/json' ? JSON.parse(body) : body); return new fetch.Response(null, { status: 204, statusText: 'OK', }); } } } return undefined; }); if (staticFiles) { const indexPath = crossHelpers.path.join(baseDir, staticFiles, 'index.html'); serverAdapter.get('*', async (request) => { const url = new URL(request.url); if (graphqlPath !== '/' && url.pathname === '/' && (await utils.pathExists(indexPath))) { const indexFile = await crossHelpers.fs.promises.readFile(indexPath); return new fetch.Response(indexFile, { status: 200, headers: { 'Content-Type': 'text/html', }, }); } const filePath = crossHelpers.path.join(baseDir, staticFiles, url.pathname); if (await utils.pathExists(filePath)) { const body = await crossHelpers.fs.promises.readFile(filePath); return new fetch.Response(body, { status: 200, }); } return undefined; }); } else if (graphqlPath !== '/') { serverAdapter.get('/', () => new fetch.Response(null, { status: 302, headers: { Location: graphqlPath, }, })); } serverAdapter.all('*', ittyRouterExtras.withCookies, graphqlHandler(mesh$, playgroundTitle, playgroundEnabled, graphqlPath, corsConfig)); return serverAdapter; } exports.createMeshHTTPHandler = createMeshHTTPHandler;