UNPKG

@worker-tools/middleware

Version:

A suite of standalone HTTP server middlewares for Worker Runtimes.

144 lines 5.89 kB
"use strict"; 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