UNPKG

@orpc/server

Version:

<div align="center"> <image align="center" src="https://orpc.dev/logo.webp" width=280 alt="oRPC logo" /> </div>

153 lines (146 loc) 5.13 kB
import { ORPCError } from '@orpc/client'; import { once, toArray, intercept, resolveMaybeOptionalOptions } from '@orpc/shared'; import compression from '@orpc/interop/compression'; import { toStandardLazyRequest, sendStandardResponse } from '@orpc/standard-server-node'; import { r as resolveFriendlyStandardHandleOptions } from '../../shared/server.DZ5BIITo.mjs'; import '@orpc/standard-server'; import '@orpc/contract'; import { C as CompositeStandardHandlerPlugin, b as StandardRPCHandler } from '../../shared/server.Bxx6tqNe.mjs'; import '@orpc/client/standard'; import '@orpc/standard-server/batch'; import '@orpc/standard-server-fetch'; import { S as StrictGetMethodPlugin } from '../../shared/server.TEVCLCFC.mjs'; import '../../shared/server.Ds4HPpvH.mjs'; class BodyLimitPlugin { maxBodySize; constructor(options) { this.maxBodySize = options.maxBodySize; } initRuntimeAdapter(options) { options.adapterInterceptors ??= []; options.adapterInterceptors.push(async (options2) => { const checkHeader = once(() => { if (Number(options2.request.headers["content-length"]) > this.maxBodySize) { throw new ORPCError("PAYLOAD_TOO_LARGE"); } }); const originalEmit = options2.request.emit; let currentBodySize = 0; options2.request.emit = (event, ...args) => { if (event === "data") { checkHeader(); currentBodySize += args[0].length; if (currentBodySize > this.maxBodySize) { throw new ORPCError("PAYLOAD_TOO_LARGE"); } } return originalEmit.call(options2.request, event, ...args); }; try { return await options2.next(options2); } finally { options2.request.emit = originalEmit; } }); } } class CompressionPlugin { compressionHandler; constructor(options = {}) { this.compressionHandler = compression({ ...options, filter: (req, res) => { const hasContentDisposition = res.hasHeader("content-disposition"); const contentType = res.getHeader("content-type")?.toString(); if (!hasContentDisposition && contentType?.startsWith("text/event-stream")) { return false; } return options.filter ? options.filter(req, res) : compression.filter(req, res); } }); } initRuntimeAdapter(options) { options.adapterInterceptors ??= []; options.adapterInterceptors.unshift(async (options2) => { let resolve; let reject; const promise = new Promise((res, rej) => { resolve = res; reject = rej; }); const originalWrite = options2.response.write; const originalEnd = options2.response.end; const originalOn = options2.response.on; this.compressionHandler( options2.request, options2.response, async (err) => { if (err) { reject(err); } else { try { resolve(await options2.next()); } catch (error) { reject(error); } } } ); try { return await promise; } finally { options2.response.write = originalWrite; options2.response.end = originalEnd; options2.response.on = originalOn; } }); } } class CompositeNodeHttpHandlerPlugin extends CompositeStandardHandlerPlugin { initRuntimeAdapter(options) { for (const plugin of this.plugins) { plugin.initRuntimeAdapter?.(options); } } } class NodeHttpHandler { constructor(standardHandler, options = {}) { this.standardHandler = standardHandler; const plugin = new CompositeNodeHttpHandlerPlugin(options.plugins); plugin.initRuntimeAdapter(options); this.adapterInterceptors = toArray(options.adapterInterceptors); this.sendStandardResponseOptions = options; } sendStandardResponseOptions; adapterInterceptors; async handle(request, response, ...rest) { return intercept( this.adapterInterceptors, { ...resolveFriendlyStandardHandleOptions(resolveMaybeOptionalOptions(rest)), request, response, sendStandardResponseOptions: this.sendStandardResponseOptions }, async ({ request: request2, response: response2, sendStandardResponseOptions, ...options }) => { const standardRequest = toStandardLazyRequest(request2, response2); const result = await this.standardHandler.handle(standardRequest, options); if (!result.matched) { return { matched: false }; } await sendStandardResponse(response2, result.response, sendStandardResponseOptions); return { matched: true }; } ); } } class RPCHandler extends NodeHttpHandler { constructor(router, options = {}) { if (options.strictGetMethodPluginEnabled ?? true) { options.plugins ??= []; options.plugins.push(new StrictGetMethodPlugin()); } super(new StandardRPCHandler(router, options), options); } } export { BodyLimitPlugin, CompositeNodeHttpHandlerPlugin, CompressionPlugin, NodeHttpHandler, RPCHandler };