UNPKG

hono-upload

Version:

A memory efficient upload handler for hono.

110 lines 2.83 kB
import createBusboy from "busboy"; const uploadErrors = { MISSING_BODY: "MISSING_BODY", INVALID_CONTENT_TYPE: "INVALID_CONTENT_TYPE", CONTENT_LENGTH_MISSING: "CONTENT_LENGTH_MISSING", MAX_FILE_SIZE_EXCEEDED: "MAX_FILE_SIZE_EXCEEDED", MAX_ONE_FILE_ALLOWED: "MAX_ONE_FILE_ALLOWED" }; async function uploadHandler({ queuingStrategy, onFile, ctx, ...params }) { const request = ctx.req.raw; const stream = request.body; if (!stream) { throw new Error(uploadErrors.MISSING_BODY); } const contentType = request.headers.get("Content-Type") || ""; if (!contentType.includes("multipart/form-data")) { throw new Error(uploadErrors.INVALID_CONTENT_TYPE); } const maxFileSize = (params.maxFileSize || Infinity) + 2 * 1024 * 1024; const requestSize = parseInt(request.headers.get("Content-Length") || "0", 10); if (requestSize === 0) { throw new Error(uploadErrors.CONTENT_LENGTH_MISSING); } if (maxFileSize && requestSize > maxFileSize) { throw new Error(uploadErrors.MAX_FILE_SIZE_EXCEEDED, { cause: new Error(requestSize.toString()) }); } const headers = Object.fromEntries(ctx.req.raw.headers.entries()); const queueStrategy = { highWaterMark: 3, size: () => 1, ...queuingStrategy }; return new Promise((resolve, reject) => { const busboy = createBusboy({ headers, highWaterMark: queueStrategy.highWaterMark, limits: { fields: 0, files: 1 } }); const writableStream = new WritableStream( { abort(reason) { reject(reason); }, write(chunk) { busboy.write(chunk); }, close() { busboy.end(); } }, queueStrategy ); function cleanup() { busboy.removeListener("error", onBusboyError); busboy.removeListener("file", onBusboyFile); } let result; function onBusboyError() { result = void 0; cleanup(); } function onBusboyFile(field, file, fileInfo) { try { const writeFile = onFile(file, { ...fileInfo, field }); if (writeFile instanceof Promise) { writeFile.then((v) => { result = v; busboy.emit("close"); }).catch((err) => { reject(err); }); } else { result = writeFile; } } catch (e) { reject(e); } } busboy.on("file", onBusboyFile); busboy.on("error", onBusboyError); busboy.on("close", () => { writableStream.close().catch(() => { }); cleanup(); if (result) resolve(result); }); stream.pipeTo(writableStream).catch((e) => { reject(e); }); }); } export { uploadErrors, uploadHandler }; //# sourceMappingURL=index.mjs.map