ufiber
Version:
Next-gen webserver for node-js developer
94 lines (92 loc) • 2.89 kB
JavaScript
import { formatBytes } from "./tools.js";
import uws from "../../uws";
//#region src/utils/body.ts
/**
* Simple FormData-like container for Node.
* Supports multiple values per key and JSON conversion.
*/
var FormData = class extends Map {
/**
* Appends a new value for the given key.
* If the key already exists, converts the value into an array
* and pushes the new value into it.
*
* @param name - The key name.
* @param value - The value to append.
*/
append(key, value) {
const current = this.get(key);
if (current === void 0) this.set(key, value);
else if (Array.isArray(current)) current.push(value);
else this.set(key, [current, value]);
}
/**
* Returns the first value associated with the given key.
* If multiple values exist, only the first one is returned.
*
* @param name - The key to look up.
* @returns The first value, or `undefined` if not found.
*/
get(name) {
const val = super.get(name);
return Array.isArray(val) ? val[0] : val;
}
/**
* Returns all values associated with the given key.
* Always returns an array (empty if key not found).
*
* @param name - The key to look up.
* @returns An array of values.
*/
getAll(key) {
const v = super.get(key);
return Array.isArray(v) ? v : v !== void 0 ? [v] : [];
}
/**
* Converts the entire form to a plain JavaScript object.
*
* @returns A `Record<string, any>` containing all keys and values.
*/
toJSON() {
const obj = {};
for (const [k, v] of this.entries()) obj[k] = v;
return obj;
}
};
/**
* Parse multipart/form-data bodies from a readable stream.
*/
const formParse = (buf, cType, options = {}) => {
const { files = 5, fileSize = 5 * 1024 * 1024, fileFields } = options;
const form = new FormData();
const parts = uws.getParts(buf, cType);
if (parts) {
let fileCount = 0;
parts.forEach((part) => {
const { name, data, filename, type: mimeType } = part;
const buffer = Buffer.from(data);
if (!filename || !mimeType) {
const value = buffer.toString("utf8");
form.append(name, value);
return;
}
fileCount++;
if (fileCount > files) throw new Error(`Too many files uploaded. Maximum allowed: ${files}, received: ${fileCount}`);
if (fileFields && !(Array.isArray(fileFields) && fileFields.includes(name) || fileFields === name)) throw new Error(`File upload not allowed for field '${name}'`);
if (buffer.byteLength > fileSize) throw new RangeError(`File '${filename}' is ${formatBytes(buffer.byteLength)}, max allowed ${formatBytes(fileSize)}`);
const ext = filename.includes(".") ? filename.split(".").pop().toLowerCase().slice(0, 10) : "";
const fileInfo = {
filename,
mimeType: mimeType.slice(0, 100),
extension: ext,
readable: formatBytes(buffer.length),
bytes: buffer.length,
buffer
};
form.append(name, fileInfo);
});
}
return form;
};
//#endregion
export { FormData, formParse };