@worker-tools/middleware
Version:
A suite of standalone HTTP server middlewares for Worker Runtimes.
144 lines • 5.89 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.defaultBodyParser = exports.bodyParser = exports.X_BINARY = exports.BINARY = exports.TEXT_PLAIN = exports.TEXT_HTML = exports.FORM_DATA = exports.FORM = exports.JSON = void 0;
const context_js_1 = require("./context.js");
const content_negotiation_js_1 = require("./content-negotiation.js");
const response_creators_1 = require("@worker-tools/response-creators");
exports.JSON = 'application/json';
exports.FORM = 'application/x-www-form-urlencoded';
exports.FORM_DATA = 'multipart/form-data';
exports.TEXT_HTML = 'text/html';
exports.TEXT_PLAIN = 'text/plain';
/** Standard MIME type for binary data */
exports.BINARY = 'application/octet-stream';
/** Non-standard MIME type for binary data. Sometimes used, so included anyway. */
exports.X_BINARY = 'application/x-binary';
const defaultBody = [
exports.FORM,
exports.FORM_DATA,
exports.JSON,
exports.BINARY,
exports.X_BINARY,
exports.TEXT_HTML,
exports.TEXT_PLAIN,
];
// Not possible to provide a fallback rn: https://github.com/microsoft/TypeScript/issues/48073
const _isString = (x) => !(x[1] instanceof File);
const _isFile = (x) => x[1] instanceof File;
const isBodyTextContext = (nx) => { var _a; return (_a = nx.accepted) === null || _a === void 0 ? void 0 : _a.startsWith('text/'); };
const isBodyVendorJSONContext = (nx) => { var _a; return ((_a = nx.accepted) === null || _a === void 0 ? void 0 : _a.startsWith('application/')) && nx.accepted.endsWith('+json'); };
// const isBodyVendorBinaryContext = <J = any>(nx: BodyContext<J>): nx is BodyVendorBinaryContext =>
// nx.accepted?.startsWith('application/vnd.')
const MB = 1024 ** 2;
async function checkSize(req, maxSize) {
let size = 0;
await req.clone().body.pipeTo(new WritableStream({
write(chunk, ctrl) {
size += chunk.byteLength;
if (size > maxSize) {
ctrl.error(new Error('Payload too large'));
}
}
}));
return size <= maxSize;
}
const bodyParser = (opts = {}) => async (ax) => {
var _a;
const x = await ax;
const nx = x;
const ok = await checkSize(x.request, (_a = opts.maxSize) !== null && _a !== void 0 ? _a : 1 * MB);
if (!ok)
throw (0, response_creators_1.payloadTooLarge)();
switch (nx.accepted) {
case exports.JSON: {
nx.body = nx.json = await x.request.json();
return nx;
}
case exports.FORM: {
nx.body = nx.form = new URLSearchParams(await x.request.text());
// FIXME: Multiple values per key??
// nx.form = Object.fromEntries(form);
return nx;
}
case exports.FORM_DATA: {
nx.body = nx.formData = await x.request.formData();
// FIXME: Multiple values per key??
// const tuples = [...formData];
// nx.form = Object.fromEntries(tuples.filter(isString));
// nx.files = Object.fromEntries(tuples.filter(isFile));
return nx;
}
case exports.BINARY:
case exports.X_BINARY: {
nx.body = nx.arrayBuffer = await x.request.arrayBuffer();
nx.blob = new Blob([nx.arrayBuffer]); // TODO: does this copy??
return nx;
}
default: {
if (isBodyTextContext(nx)) {
nx.body = nx.text = await x.request.text();
}
else if (isBodyVendorJSONContext(nx)) {
nx.body = nx.json = await x.request.json();
return nx;
// } else if (isBodyVendorBinaryContext(nx)) {
// nx.body = nx.buffer = await x.request.arrayBuffer();
// nx.blob = new Blob([nx.buffer]) // TODO: does this copy??
// return nx;
}
else {
// Anything else gets the binary treatment (outside of scope of type system)
nx.body = nx.buffer = await x.request.arrayBuffer();
nx.blob = new Blob([nx.buffer]);
return nx;
}
return nx;
}
}
};
exports.bodyParser = bodyParser;
const defaultBodyParser = (options) => (0, context_js_1.combine)((0, content_negotiation_js_1.accepts)(defaultBody), (0, exports.bodyParser)(options));
exports.defaultBodyParser = defaultBodyParser;
// type ErrorOf<T> = T extends { error?: infer E } ? E : never
// (async () => {
// const ctx: Context = { request: new Request('/'), effects: [], waitUntil: (_f: any) => {}, handled: Promise.resolve(null as any) }
// const z = provides([])(accepts([])(ctx))
// const x = await parseBody()(accepts(['text/x-foo', 'application/vnd.github.v3+json', FORM, FORM_DATA])(ctx))
// if (x.accepted === 'application/vnd.github.v3+json') {
// x.body
// } else if (x.accepted === 'text/x-foo') {
// x.body
// } else if (x.accepted === 'application/x-www-form-urlencoded') {
// x.body
// }
// const y = await bodyParser()(ctx)
// if (y.accepted === 'application/x-www-form-urlencoded') {
// y.bodyParams
// y.body
// }
// if (y.accepted === 'multipart/form-data') {
// y.formData
// y.body
// }
// if (y.accepted === 'application/foobar+json') {
// y.json
// y.body
// }
// // if (x.accepted === 'application/x-www-form-urlencoded') {
// // x.body
// // x.bodyParams
// // x.form
// // }
// // else if (x.accepted === 'multipart/form-data') {
// // x.formData
// // x.form
// // x.files
// // } else if (x.accepted === 'application/octet-stream' || x.accepted === 'application/x-binary') {
// // x.buffer
// // x.blob
// // } else if (x.accepted === 'application/vnd.github.v3+json') {
// // } else if (x.accepted === 'text/foo') {
// // x.text
// // }
// })
//# sourceMappingURL=body-parser.js.map