From d265b83e888a3ad22c7bfc88d54411e545b48279 Mon Sep 17 00:00:00 2001 From: Ulises Gascon Date: Sat, 29 Aug 2026 18:12:09 +0200 Subject: [PATCH] docs: add JSDoc to the public API Document multer(options), the middleware methods, the storage engines and MulterError, including the options and error codes added in 2.3.0. Co-authored-by: Arham Sayyed --- index.js | 105 ++++++++++++++++++++++++++++++++++++++++++++ lib/multer-error.js | 17 +++++++ storage/disk.js | 18 ++++++++ storage/memory.js | 12 +++++ 4 files changed, 152 insertions(+) diff --git a/index.js b/index.js index 678ba29c..47f1eda6 100644 --- a/index.js +++ b/index.js @@ -4,10 +4,75 @@ var diskStorage = require('./storage/disk') var memoryStorage = require('./storage/memory') var MulterError = require('./lib/multer-error') +/** + * A file parsed from a multipart request. + * + * @typedef {Object} File + * @property {string} fieldname Name of the form field + * @property {string} originalname Name of the file on the client (client-supplied, treat as untrusted) + * @property {string} encoding Transfer encoding of the file + * @property {string} mimetype MIME type of the file + * @property {number} size Size of the file in bytes + * @property {string} [destination] Folder the file was saved to (`DiskStorage`) + * @property {string} [filename] Name of the file within `destination` (`DiskStorage`) + * @property {string} [path] Full path of the saved file (`DiskStorage`) + * @property {Buffer} [buffer] Contents of the file (`MemoryStorage`) + */ + +/** + * Size limits, passed to busboy. All are optional. + * + * @typedef {Object} Limits + * @property {number} [fieldNameSize=100] Max field name size in bytes + * @property {number} [fieldSize=1048576] Max field value size in bytes + * @property {number} [fields=Infinity] Max number of non-file fields + * @property {number} [fileSize=Infinity] Max file size in bytes (integer or `Infinity`) + * @property {number} [files=Infinity] Max number of file fields + * @property {number} [parts=Infinity] Max number of parts (fields + files) + * @property {number} [headerPairs=2000] Max number of header key/value pairs to parse + * @property {number} [fieldNestingDepth=Infinity] Max nesting depth of field names (`a[b][c]` has 2 levels) + * @property {number} [fieldArrayIndexLimit=Infinity] Max numeric array index accepted in field names + */ + +/** + * Decides whether a file is accepted. Call `cb(null, true)` to accept the + * file, `cb(null, false)` to skip it silently, or `cb(err)` to abort. + * + * @callback FileFilter + * @param {Object} req The request + * @param {File} file The file being uploaded (without `size`, `path` or `buffer`) + * @param {function(?Error, boolean=): void} cb + */ + +/** + * Storage engine. See StorageEngine.md for the full contract. + * + * @typedef {Object} StorageEngine + * @property {function(Object, File, function(?Error, Object=): void): void} _handleFile + * Consumes `file.stream` and calls back with the properties to merge into the file object + * @property {function(Object, File, function(?Error): void): void} _removeFile + * Removes a stored file when the request fails + */ + +/** + * @typedef {Object} Options + * @property {string} [dest] Folder to store files in (uses `DiskStorage`) + * @property {StorageEngine} [storage] Storage engine; defaults to `MemoryStorage` when neither `dest` nor `storage` is set + * @property {FileFilter} [fileFilter] Controls which files are accepted + * @property {Limits} [limits] Size limits + * @property {boolean} [preservePath=false] Keep the full client-supplied path in `file.originalname` + * @property {string} [defParamCharset='latin1'] Charset for part header parameters (e.g. filename) without an explicit one + */ + function allowAll (req, file, cb) { cb(null, true) } +/** + * @constructor + * @private + * @param {Options} options + */ function Multer (options) { if (options.storage) { this.storage = options.storage @@ -68,22 +133,54 @@ Multer.prototype._makeMiddleware = function (fields, fileStrategy) { return makeMiddleware(setup.bind(this)) } +/** + * Accept a single file for the field `name`. The file is stored in `req.file`. + * + * @param {string} name + * @returns {function(Object, Object, function(?Error): void): void} Express middleware + */ Multer.prototype.single = function (name) { return this._makeMiddleware([{ name: name, maxCount: 1 }], 'VALUE') } +/** + * Accept an array of files for the field `name`, stored in `req.files`. + * Files skipped by `fileFilter` do not count towards `maxCount`. + * + * @param {string} name + * @param {number} [maxCount] Error with `LIMIT_UNEXPECTED_FILE` if more files are accepted + * @returns {function(Object, Object, function(?Error): void): void} Express middleware + */ Multer.prototype.array = function (name, maxCount) { return this._makeMiddleware([{ name: name, maxCount: maxCount }], 'ARRAY') } +/** + * Accept a mix of files. `req.files` is an object keyed by field name, each + * value an array of files. + * + * @param {Array<{name: string, maxCount?: number}>} fields + * @returns {function(Object, Object, function(?Error): void): void} Express middleware + */ Multer.prototype.fields = function (fields) { return this._makeMiddleware(fields, 'OBJECT') } +/** + * Accept only text fields. Any file results in a `LIMIT_UNEXPECTED_FILE` error. + * + * @returns {function(Object, Object, function(?Error): void): void} Express middleware + */ Multer.prototype.none = function () { return this._makeMiddleware([], 'NONE') } +/** + * Accept all files, stored as an array in `req.files`. Only use this on routes + * that handle every uploaded file. + * + * @returns {function(Object, Object, function(?Error): void): void} Express middleware + */ Multer.prototype.any = function () { function setup () { return { @@ -99,6 +196,14 @@ Multer.prototype.any = function () { return makeMiddleware(setup.bind(this)) } +/** + * Create a multer instance. Text fields are parsed into `req.body`; files go to + * `req.file` or `req.files` depending on the method used. + * + * @param {Options} [options] + * @returns {Multer} + * @throws {TypeError} If `options` is not an object + */ function multer (options) { if (options === undefined) { return new Multer({}) diff --git a/lib/multer-error.js b/lib/multer-error.js index f2b9bca9..e89bdc7b 100644 --- a/lib/multer-error.js +++ b/lib/multer-error.js @@ -15,6 +15,23 @@ var errorMessages = { INVALID_FIELD_NAME: 'Invalid field name' } +/** + * Error raised by multer. Check `err.code` rather than the message. + * + * Codes: `LIMIT_PART_COUNT`, `LIMIT_FILE_SIZE`, `LIMIT_FILE_COUNT`, + * `LIMIT_FIELD_KEY`, `LIMIT_FIELD_VALUE`, `LIMIT_FIELD_COUNT`, + * `LIMIT_UNEXPECTED_FILE`, `MISSING_FIELD_NAME`, `LIMIT_FIELD_NESTING`, + * `LIMIT_FIELD_ARRAY_INDEX`, `INVALID_FIELD_NAME`, `STREAM_DESTROYED`. + * + * @constructor + * @extends Error + * @param {string} code One of the codes above + * @param {string} [field] Name of the field the error relates to + * @param {string} [filename] Client-supplied file name, for file errors + * @property {string} code + * @property {string} [field] + * @property {string} [filename] + */ function MulterError (code, field, filename) { Error.captureStackTrace(this, this.constructor) this.name = this.constructor.name diff --git a/storage/disk.js b/storage/disk.js index c5bb53f0..88fec572 100644 --- a/storage/disk.js +++ b/storage/disk.js @@ -19,6 +19,17 @@ function getDestination (req, file, cb) { cb(null, os.tmpdir()) } +/** + * Storage engine that writes files to disk. + * + * @constructor + * @private + * @param {Object} opts + * @param {string|function(Object, File, function(?Error, string=): void): void} [opts.destination] + * Folder to store files in, or a function that calls back with one. Defaults to `os.tmpdir()` + * @param {function(Object, File, function(?Error, string=): void): void} [opts.filename] + * Calls back with the file name to use. Defaults to a random hex name without extension + */ function DiskStorage (opts) { this.getFilename = (opts.filename || getFilename) @@ -92,6 +103,13 @@ DiskStorage.prototype._removeFile = function _removeFile (req, file, cb) { outStream.destroy() } +/** + * Create a disk storage engine. Sets `destination`, `filename` and `path` on + * the file object. + * + * @param {Object} opts See {@link DiskStorage} + * @returns {DiskStorage} + */ module.exports = function (opts) { return new DiskStorage(opts) } diff --git a/storage/memory.js b/storage/memory.js index 3ae9e331..2b8c7ab4 100644 --- a/storage/memory.js +++ b/storage/memory.js @@ -1,3 +1,9 @@ +/** + * Storage engine that keeps files in memory. + * + * @constructor + * @private + */ function MemoryStorage (opts) {} MemoryStorage.prototype._handleFile = function _handleFile (req, file, cb) { @@ -22,6 +28,12 @@ MemoryStorage.prototype._removeFile = function _removeFile (req, file, cb) { cb(null) } +/** + * Create a memory storage engine. Sets `buffer` on the file object with the + * whole file contents; set `limits.fileSize` to bound memory use. + * + * @returns {MemoryStorage} + */ module.exports = function (opts) { return new MemoryStorage(opts) }