@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
JavaScript
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 };