UNPKG

graphql-sse

Version:

Zero-dependency, HTTP/1 safe, simple, GraphQL over Server-Sent Events Protocol server and client

103 lines (102 loc) 3.71 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createHandler = void 0; const handler_1 = require("../handler"); /** * The ready-to-use handler for [fastify](https://www.fastify.io). * * Errors thrown from the provided options or callbacks (or even due to * library misuse or potential bugs) will reject the handler or bubble to the * returned iterator. They are considered internal errors and you should take care * of them accordingly. * * For production environments, its recommended not to transmit the exact internal * error details to the client, but instead report to an error logging tool or simply * the console. * * ```ts * import Fastify from 'fastify'; // yarn add fastify * import { createHandler } from 'graphql-sse/lib/use/fastify'; * * const handler = createHandler({ schema }); * * const fastify = Fastify(); * * fastify.all('/graphql/stream', async (req, reply) => { * try { * await handler(req, reply); * } catch (err) { * console.error(err); * reply.code(500).send(); * } * }); * * fastify.listen({ port: 4000 }); * console.log('Listening to port 4000'); * ``` * * @category Server/fastify */ function createHandler(options) { const handler = (0, handler_1.createHandler)(options); return async function handleRequest(req, reply) { const [body, init] = await handler({ method: req.method, url: req.url, headers: { get(key) { var _a; const header = (_a = reply.getHeader(key)) !== null && _a !== void 0 ? _a : req.headers[key]; return Array.isArray(header) ? header.join('\n') : String(header); }, }, body: () => new Promise((resolve, reject) => { if (req.body) { // body was parsed by middleware // eslint-disable-next-line @typescript-eslint/no-explicit-any -- even if fastify incorrectly parsed the body, we cannot re-read it return resolve(req.body); } let body = ''; req.raw.on('data', (chunk) => (body += chunk)); req.raw.once('error', reject); req.raw.once('end', () => { req.raw.off('error', reject); resolve(body); }); }), raw: req, context: { reply }, }); const middlewareHeaders = {}; for (const [key, val] of Object.entries(reply.getHeaders())) { middlewareHeaders[key] = Array.isArray(val) ? val.join('\n') : String(val); } reply.raw.writeHead(init.status, init.statusText, { ...middlewareHeaders, ...init.headers, }); if (!body || typeof body === 'string') { return new Promise((resolve) => reply.raw.end(body, () => resolve())); } reply.raw.once('close', body.return); for await (const value of body) { const closed = await new Promise((resolve, reject) => { if (!reply.raw.writable) { // response's close event might be late resolve(true); } else { reply.raw.write(value, (err) => (err ? reject(err) : resolve(false))); } }); if (closed) { break; } } reply.raw.off('close', body.return); return new Promise((resolve) => reply.raw.end(resolve)); }; } exports.createHandler = createHandler;