You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					536 lines
				
				21 KiB
			
		
		
			
		
	
	
					536 lines
				
				21 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								"use strict";
							 | 
						||
| 
								 | 
							
								var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
							 | 
						||
| 
								 | 
							
								    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
							 | 
						||
| 
								 | 
							
								    return new (P || (P = Promise))(function (resolve, reject) {
							 | 
						||
| 
								 | 
							
								        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
							 | 
						||
| 
								 | 
							
								        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
							 | 
						||
| 
								 | 
							
								        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
							 | 
						||
| 
								 | 
							
								        step((generator = generator.apply(thisArg, _arguments || [])).next());
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								var __importDefault = (this && this.__importDefault) || function (mod) {
							 | 
						||
| 
								 | 
							
								    return (mod && mod.__esModule) ? mod : { "default": mod };
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								Object.defineProperty(exports, "__esModule", { value: true });
							 | 
						||
| 
								 | 
							
								exports.GridFsStorageCtr = exports.GridFsStorage = void 0;
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Plugin definition
							 | 
						||
| 
								 | 
							
								 * @module multer-gridfs-storage/gridfs
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								const crypto_1 = __importDefault(require("crypto"));
							 | 
						||
| 
								 | 
							
								const events_1 = require("events");
							 | 
						||
| 
								 | 
							
								const mongodb_1 = require("mongodb");
							 | 
						||
| 
								 | 
							
								const is_promise_1 = __importDefault(require("is-promise"));
							 | 
						||
| 
								 | 
							
								const is_generator_1 = __importDefault(require("is-generator"));
							 | 
						||
| 
								 | 
							
								const pump_1 = __importDefault(require("pump"));
							 | 
						||
| 
								 | 
							
								const mongodb_uri_1 = __importDefault(require("mongodb-uri"));
							 | 
						||
| 
								 | 
							
								const utils_1 = require("./utils");
							 | 
						||
| 
								 | 
							
								const cache_1 = require("./cache");
							 | 
						||
| 
								 | 
							
								const isGeneratorFn = is_generator_1.default.fn;
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Default file information
							 | 
						||
| 
								 | 
							
								 * @const defaults
							 | 
						||
| 
								 | 
							
								 **/
							 | 
						||
| 
								 | 
							
								const defaults = {
							 | 
						||
| 
								 | 
							
								    metadata: null,
							 | 
						||
| 
								 | 
							
								    chunkSize: 261120,
							 | 
						||
| 
								 | 
							
								    bucketName: 'fs',
							 | 
						||
| 
								 | 
							
								    aliases: null,
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Multer GridFS Storage Engine class definition.
							 | 
						||
| 
								 | 
							
								 * @extends EventEmitter
							 | 
						||
| 
								 | 
							
								 * @param {object} configuration
							 | 
						||
| 
								 | 
							
								 * @param {string} [configuration.url] - The url pointing to a MongoDb database
							 | 
						||
| 
								 | 
							
								 * @param {object} [configuration.options] - Options to use when connection with an url.
							 | 
						||
| 
								 | 
							
								 * @param {object} [configuration.connectionOpts] - DEPRECATED: Use options instead.
							 | 
						||
| 
								 | 
							
								 * @param {boolean | string} [configuration.cache] - Store this connection in the internal cache.
							 | 
						||
| 
								 | 
							
								 * @param {Db | Promise} [configuration.db] - The MongoDb database instance to use or a promise that resolves with it
							 | 
						||
| 
								 | 
							
								 * @param {Function} [configuration.file] - A function to control the file naming in the database
							 | 
						||
| 
								 | 
							
								 * @fires GridFsStorage#connection
							 | 
						||
| 
								 | 
							
								 * @fires GridFsStorage#connectionFailed
							 | 
						||
| 
								 | 
							
								 * @fires GridFsStorage#file
							 | 
						||
| 
								 | 
							
								 * @fires GridFsStorage#streamError
							 | 
						||
| 
								 | 
							
								 * @fires GridFsStorage#dbError
							 | 
						||
| 
								 | 
							
								 * @version 0.0.3
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								class GridFsStorage extends events_1.EventEmitter {
							 | 
						||
| 
								 | 
							
								    constructor(configuration) {
							 | 
						||
| 
								 | 
							
								        super();
							 | 
						||
| 
								 | 
							
								        this.db = null;
							 | 
						||
| 
								 | 
							
								        this.client = null;
							 | 
						||
| 
								 | 
							
								        this.connected = false;
							 | 
						||
| 
								 | 
							
								        this.connecting = false;
							 | 
						||
| 
								 | 
							
								        this.caching = false;
							 | 
						||
| 
								 | 
							
								        this.error = null;
							 | 
						||
| 
								 | 
							
								        if (!configuration ||
							 | 
						||
| 
								 | 
							
								            (!configuration.url &&
							 | 
						||
| 
								 | 
							
								                !configuration.db)) {
							 | 
						||
| 
								 | 
							
								            throw new Error('Error creating storage engine. At least one of url or db option must be provided.');
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        this.setMaxListeners(0);
							 | 
						||
| 
								 | 
							
								        this.configuration = configuration;
							 | 
						||
| 
								 | 
							
								        this._file = this.configuration.file;
							 | 
						||
| 
								 | 
							
								        const { url, cache, options } = this.configuration;
							 | 
						||
| 
								 | 
							
								        if (url) {
							 | 
						||
| 
								 | 
							
								            this.caching = Boolean(cache);
							 | 
						||
| 
								 | 
							
								            this._options = options;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if (this.caching) {
							 | 
						||
| 
								 | 
							
								            const { cache, url } = configuration;
							 | 
						||
| 
								 | 
							
								            const cacheName = typeof cache === 'string' ? cache : 'default';
							 | 
						||
| 
								 | 
							
								            this.cacheName = cacheName;
							 | 
						||
| 
								 | 
							
								            this.cacheIndex = GridFsStorage.cache.initialize({
							 | 
						||
| 
								 | 
							
								                url,
							 | 
						||
| 
								 | 
							
								                cacheName,
							 | 
						||
| 
								 | 
							
								                init: this._options,
							 | 
						||
| 
								 | 
							
								            });
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        this._connect();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Generates 16 bytes long strings in hexadecimal format
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    static generateBytes() {
							 | 
						||
| 
								 | 
							
								        return __awaiter(this, void 0, void 0, function* () {
							 | 
						||
| 
								 | 
							
								            return new Promise((resolve, reject) => {
							 | 
						||
| 
								 | 
							
								                crypto_1.default.randomBytes(16, (error, buffer) => {
							 | 
						||
| 
								 | 
							
								                    if (error) {
							 | 
						||
| 
								 | 
							
								                        reject(error);
							 | 
						||
| 
								 | 
							
								                        return;
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                    resolve({ filename: buffer.toString('hex') });
							 | 
						||
| 
								 | 
							
								                });
							 | 
						||
| 
								 | 
							
								            });
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Merge the properties received in the file function with default values
							 | 
						||
| 
								 | 
							
								     * @param extra Extra properties like contentType
							 | 
						||
| 
								 | 
							
								     * @param fileSettings Properties received in the file function
							 | 
						||
| 
								 | 
							
								     * @return An object with the merged properties wrapped in a promise
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    static _mergeProps(extra, fileSettings) {
							 | 
						||
| 
								 | 
							
								        return __awaiter(this, void 0, void 0, function* () {
							 | 
						||
| 
								 | 
							
								            // If the filename is not provided generate one
							 | 
						||
| 
								 | 
							
								            const previous = yield (fileSettings.filename
							 | 
						||
| 
								 | 
							
								                ? {}
							 | 
						||
| 
								 | 
							
								                : GridFsStorage.generateBytes());
							 | 
						||
| 
								 | 
							
								            // If no id is provided generate one
							 | 
						||
| 
								 | 
							
								            // If an error occurs the emitted file information will contain the id
							 | 
						||
| 
								 | 
							
								            const hasId = fileSettings.id;
							 | 
						||
| 
								 | 
							
								            if (!hasId) {
							 | 
						||
| 
								 | 
							
								                previous.id = new mongodb_1.ObjectId();
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            return Object.assign(Object.assign(Object.assign(Object.assign({}, previous), defaults), extra), fileSettings);
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Handles generator function and promise results
							 | 
						||
| 
								 | 
							
								     * @param result - Can be a promise or a generator yielded value
							 | 
						||
| 
								 | 
							
								     * @param isGen - True if is a yielded value
							 | 
						||
| 
								 | 
							
								     **/
							 | 
						||
| 
								 | 
							
								    static _handleResult(result, isGen) {
							 | 
						||
| 
								 | 
							
								        return __awaiter(this, void 0, void 0, function* () {
							 | 
						||
| 
								 | 
							
								            let value = result;
							 | 
						||
| 
								 | 
							
								            if (isGen) {
							 | 
						||
| 
								 | 
							
								                if (result.done) {
							 | 
						||
| 
								 | 
							
								                    throw new Error('Generator ended unexpectedly');
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                value = result.value;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            return value;
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Storage interface method to handle incoming files
							 | 
						||
| 
								 | 
							
								     * @param {Request} request - The request that trigger the upload
							 | 
						||
| 
								 | 
							
								     * @param {File} file - The uploaded file stream
							 | 
						||
| 
								 | 
							
								     * @param cb - A standard node callback to signal the end of the upload or an error
							 | 
						||
| 
								 | 
							
								     **/
							 | 
						||
| 
								 | 
							
								    _handleFile(request, file, cb) {
							 | 
						||
| 
								 | 
							
								        if (this.connecting) {
							 | 
						||
| 
								 | 
							
								            this.ready()
							 | 
						||
| 
								 | 
							
								                /* eslint-disable-next-line promise/prefer-await-to-then */
							 | 
						||
| 
								 | 
							
								                .then(() => __awaiter(this, void 0, void 0, function* () { return this.fromFile(request, file); }))
							 | 
						||
| 
								 | 
							
								                /* eslint-disable-next-line promise/prefer-await-to-then */
							 | 
						||
| 
								 | 
							
								                .then((file) => {
							 | 
						||
| 
								 | 
							
								                cb(null, file);
							 | 
						||
| 
								 | 
							
								            })
							 | 
						||
| 
								 | 
							
								                .catch(cb);
							 | 
						||
| 
								 | 
							
								            return;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        this._updateConnectionStatus();
							 | 
						||
| 
								 | 
							
								        if (this.connected) {
							 | 
						||
| 
								 | 
							
								            this.fromFile(request, file)
							 | 
						||
| 
								 | 
							
								                /* eslint-disable-next-line promise/prefer-await-to-then */
							 | 
						||
| 
								 | 
							
								                .then((file) => {
							 | 
						||
| 
								 | 
							
								                cb(null, file);
							 | 
						||
| 
								 | 
							
								            })
							 | 
						||
| 
								 | 
							
								                .catch(cb);
							 | 
						||
| 
								 | 
							
								            return;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        cb(new Error('The database connection must be open to store files'));
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Storage interface method to delete files in case an error turns the request invalid
							 | 
						||
| 
								 | 
							
								     * @param request - The request that trigger the upload
							 | 
						||
| 
								 | 
							
								     * @param {File} file - The uploaded file stream
							 | 
						||
| 
								 | 
							
								     * @param cb - A standard node callback to signal the end of the upload or an error
							 | 
						||
| 
								 | 
							
								     **/
							 | 
						||
| 
								 | 
							
								    _removeFile(request, file, cb) {
							 | 
						||
| 
								 | 
							
								        const options = { bucketName: file.bucketName };
							 | 
						||
| 
								 | 
							
								        const bucket = new mongodb_1.GridFSBucket(this.db, options);
							 | 
						||
| 
								 | 
							
								        bucket.delete(file.id, cb);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Waits for the MongoDb connection associated to the storage to succeed or fail
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    ready() {
							 | 
						||
| 
								 | 
							
								        return __awaiter(this, void 0, void 0, function* () {
							 | 
						||
| 
								 | 
							
								            if (this.error) {
							 | 
						||
| 
								 | 
							
								                throw this.error;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            if (this.connected) {
							 | 
						||
| 
								 | 
							
								                return { db: this.db, client: this.client };
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            return new Promise((resolve, reject) => {
							 | 
						||
| 
								 | 
							
								                const done = (result) => {
							 | 
						||
| 
								 | 
							
								                    this.removeListener('connectionFailed', fail);
							 | 
						||
| 
								 | 
							
								                    resolve(result);
							 | 
						||
| 
								 | 
							
								                };
							 | 
						||
| 
								 | 
							
								                const fail = (error) => {
							 | 
						||
| 
								 | 
							
								                    this.removeListener('connection', done);
							 | 
						||
| 
								 | 
							
								                    reject(error);
							 | 
						||
| 
								 | 
							
								                };
							 | 
						||
| 
								 | 
							
								                this.once('connection', done);
							 | 
						||
| 
								 | 
							
								                this.once('connectionFailed', fail);
							 | 
						||
| 
								 | 
							
								            });
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Pipes the file stream to the MongoDb database. The file requires a property named `file` which is a readable stream
							 | 
						||
| 
								 | 
							
								     * @param request - The http request where the file was uploaded
							 | 
						||
| 
								 | 
							
								     * @param {File} file - The file stream to pipe
							 | 
						||
| 
								 | 
							
								     * @return  {Promise} Resolves with the uploaded file
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    fromFile(request, file) {
							 | 
						||
| 
								 | 
							
								        return __awaiter(this, void 0, void 0, function* () {
							 | 
						||
| 
								 | 
							
								            return this.fromStream(file.stream, request, file);
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Pipes the file stream to the MongoDb database. The request and file parameters are optional and used for file generation only
							 | 
						||
| 
								 | 
							
								     * @param readStream - The http request where the file was uploaded
							 | 
						||
| 
								 | 
							
								     * @param [request] - The http request where the file was uploaded
							 | 
						||
| 
								 | 
							
								     * @param {File} [file] - The file stream to pipe
							 | 
						||
| 
								 | 
							
								     * @return Resolves with the uploaded file
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    fromStream(readStream, request, file) {
							 | 
						||
| 
								 | 
							
								        return __awaiter(this, void 0, void 0, function* () {
							 | 
						||
| 
								 | 
							
								            return new Promise((resolve, reject) => {
							 | 
						||
| 
								 | 
							
								                readStream.on('error', reject);
							 | 
						||
| 
								 | 
							
								                this.fromMulterStream(readStream, request, file)
							 | 
						||
| 
								 | 
							
								                    /* eslint-disable-next-line promise/prefer-await-to-then */
							 | 
						||
| 
								 | 
							
								                    .then(resolve)
							 | 
						||
| 
								 | 
							
								                    .catch(reject);
							 | 
						||
| 
								 | 
							
								            });
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    _openConnection(url, options) {
							 | 
						||
| 
								 | 
							
								        return __awaiter(this, void 0, void 0, function* () {
							 | 
						||
| 
								 | 
							
								            let client = null;
							 | 
						||
| 
								 | 
							
								            let db;
							 | 
						||
| 
								 | 
							
								            const connection = yield mongodb_1.MongoClient.connect(url, options);
							 | 
						||
| 
								 | 
							
								            if (connection instanceof mongodb_1.MongoClient) {
							 | 
						||
| 
								 | 
							
								                client = connection;
							 | 
						||
| 
								 | 
							
								                const parsedUri = mongodb_uri_1.default.parse(url);
							 | 
						||
| 
								 | 
							
								                db = client.db(parsedUri.database);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else {
							 | 
						||
| 
								 | 
							
								                db = connection;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            return { client, db };
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Create a writable stream with backwards compatibility with GridStore
							 | 
						||
| 
								 | 
							
								     * @param {object} options - The stream options
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    createStream(options) {
							 | 
						||
| 
								 | 
							
								        const settings = {
							 | 
						||
| 
								 | 
							
								            id: options.id,
							 | 
						||
| 
								 | 
							
								            chunkSizeBytes: options.chunkSize,
							 | 
						||
| 
								 | 
							
								            contentType: options.contentType,
							 | 
						||
| 
								 | 
							
								            metadata: options.metadata,
							 | 
						||
| 
								 | 
							
								            aliases: options.aliases,
							 | 
						||
| 
								 | 
							
								            disableMD5: options.disableMD5,
							 | 
						||
| 
								 | 
							
								        };
							 | 
						||
| 
								 | 
							
								        const gfs = new mongodb_1.GridFSBucket(this.db, { bucketName: options.bucketName });
							 | 
						||
| 
								 | 
							
								        return gfs.openUploadStream(options.filename, settings);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    fromMulterStream(readStream, request, file) {
							 | 
						||
| 
								 | 
							
								        return __awaiter(this, void 0, void 0, function* () {
							 | 
						||
| 
								 | 
							
								            if (this.connecting) {
							 | 
						||
| 
								 | 
							
								                yield this.ready();
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            const fileSettings = yield this._generate(request, file);
							 | 
						||
| 
								 | 
							
								            let settings;
							 | 
						||
| 
								 | 
							
								            const setType = typeof fileSettings;
							 | 
						||
| 
								 | 
							
								            const allowedTypes = new Set(['undefined', 'number', 'string', 'object']);
							 | 
						||
| 
								 | 
							
								            if (!allowedTypes.has(setType)) {
							 | 
						||
| 
								 | 
							
								                throw new Error('Invalid type for file settings, got ' + setType);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            if (fileSettings === null || fileSettings === undefined) {
							 | 
						||
| 
								 | 
							
								                settings = {};
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else if (setType === 'string' || setType === 'number') {
							 | 
						||
| 
								 | 
							
								                settings = {
							 | 
						||
| 
								 | 
							
								                    filename: fileSettings.toString(),
							 | 
						||
| 
								 | 
							
								                };
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else {
							 | 
						||
| 
								 | 
							
								                settings = fileSettings;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            const contentType = file ? file.mimetype : undefined;
							 | 
						||
| 
								 | 
							
								            const streamOptions = yield GridFsStorage._mergeProps({ contentType }, settings);
							 | 
						||
| 
								 | 
							
								            return new Promise((resolve, reject) => {
							 | 
						||
| 
								 | 
							
								                const emitError = (streamError) => {
							 | 
						||
| 
								 | 
							
								                    this.emit('streamError', streamError, streamOptions);
							 | 
						||
| 
								 | 
							
								                    reject(streamError);
							 | 
						||
| 
								 | 
							
								                };
							 | 
						||
| 
								 | 
							
								                const emitFile = (f) => {
							 | 
						||
| 
								 | 
							
								                    const storedFile = {
							 | 
						||
| 
								 | 
							
								                        id: f._id,
							 | 
						||
| 
								 | 
							
								                        filename: f.filename,
							 | 
						||
| 
								 | 
							
								                        metadata: f.metadata || null,
							 | 
						||
| 
								 | 
							
								                        bucketName: streamOptions.bucketName,
							 | 
						||
| 
								 | 
							
								                        chunkSize: f.chunkSize,
							 | 
						||
| 
								 | 
							
								                        size: f.length,
							 | 
						||
| 
								 | 
							
								                        md5: f.md5,
							 | 
						||
| 
								 | 
							
								                        uploadDate: f.uploadDate,
							 | 
						||
| 
								 | 
							
								                        contentType: f.contentType,
							 | 
						||
| 
								 | 
							
								                    };
							 | 
						||
| 
								 | 
							
								                    this.emit('file', storedFile);
							 | 
						||
| 
								 | 
							
								                    resolve(storedFile);
							 | 
						||
| 
								 | 
							
								                };
							 | 
						||
| 
								 | 
							
								                const writeStream = this.createStream(streamOptions);
							 | 
						||
| 
								 | 
							
								                // Multer already handles the error event on the readable stream(Busboy).
							 | 
						||
| 
								 | 
							
								                // Invoking the callback with an error will cause file removal and aborting routines to be called twice
							 | 
						||
| 
								 | 
							
								                writeStream.on('error', emitError);
							 | 
						||
| 
								 | 
							
								                writeStream.on('finish', emitFile);
							 | 
						||
| 
								 | 
							
								                // @ts-ignore
							 | 
						||
| 
								 | 
							
								                pump_1.default([readStream, writeStream]);
							 | 
						||
| 
								 | 
							
								            });
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Determines if a new connection should be created, a explicit connection is provided or a cached instance is required.
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    _connect() {
							 | 
						||
| 
								 | 
							
								        const { db, client = null } = this.configuration;
							 | 
						||
| 
								 | 
							
								        if (db && !is_promise_1.default(db) && !is_promise_1.default(client)) {
							 | 
						||
| 
								 | 
							
								            this._setDb(db, client);
							 | 
						||
| 
								 | 
							
								            return;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        this._resolveConnection()
							 | 
						||
| 
								 | 
							
								            /* eslint-disable-next-line promise/prefer-await-to-then */
							 | 
						||
| 
								 | 
							
								            .then(({ db, client }) => {
							 | 
						||
| 
								 | 
							
								            this._setDb(db, client);
							 | 
						||
| 
								 | 
							
								        })
							 | 
						||
| 
								 | 
							
								            .catch((error) => {
							 | 
						||
| 
								 | 
							
								            this._fail(error);
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Returns a promise that will resolve to the db and client from the cache or a new connection depending on the provided configuration
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    _resolveConnection() {
							 | 
						||
| 
								 | 
							
								        return __awaiter(this, void 0, void 0, function* () {
							 | 
						||
| 
								 | 
							
								            this.connecting = true;
							 | 
						||
| 
								 | 
							
								            const { db, client = null } = this.configuration;
							 | 
						||
| 
								 | 
							
								            if (db) {
							 | 
						||
| 
								 | 
							
								                const [_db, _client] = yield Promise.all([db, client]);
							 | 
						||
| 
								 | 
							
								                return { db: _db, client: _client };
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            if (!this.caching) {
							 | 
						||
| 
								 | 
							
								                return this._createConnection();
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            const { cache } = GridFsStorage;
							 | 
						||
| 
								 | 
							
								            if (!cache.isOpening(this.cacheIndex) && cache.isPending(this.cacheIndex)) {
							 | 
						||
| 
								 | 
							
								                const cached = cache.get(this.cacheIndex);
							 | 
						||
| 
								 | 
							
								                cached.opening = true;
							 | 
						||
| 
								 | 
							
								                return this._createConnection();
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            return cache.waitFor(this.cacheIndex);
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Handles creating a new connection from an url and storing it in the cache if necessary*}>}
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    _createConnection() {
							 | 
						||
| 
								 | 
							
								        return __awaiter(this, void 0, void 0, function* () {
							 | 
						||
| 
								 | 
							
								            const { url } = this.configuration;
							 | 
						||
| 
								 | 
							
								            const options = this._options;
							 | 
						||
| 
								 | 
							
								            const { cache } = GridFsStorage;
							 | 
						||
| 
								 | 
							
								            try {
							 | 
						||
| 
								 | 
							
								                const { db, client } = yield this._openConnection(url, options);
							 | 
						||
| 
								 | 
							
								                if (this.caching) {
							 | 
						||
| 
								 | 
							
								                    cache.resolve(this.cacheIndex, db, client);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                return { db, client };
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            catch (error) {
							 | 
						||
| 
								 | 
							
								                if (this.cacheIndex) {
							 | 
						||
| 
								 | 
							
								                    cache.reject(this.cacheIndex, error);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                throw error;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Updates the connection status based on the internal db or client object
							 | 
						||
| 
								 | 
							
								     **/
							 | 
						||
| 
								 | 
							
								    _updateConnectionStatus() {
							 | 
						||
| 
								 | 
							
								        var _a, _b;
							 | 
						||
| 
								 | 
							
								        if (!this.db) {
							 | 
						||
| 
								 | 
							
								            this.connected = false;
							 | 
						||
| 
								 | 
							
								            this.connecting = false;
							 | 
						||
| 
								 | 
							
								            return;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if (this.client) {
							 | 
						||
| 
								 | 
							
								            // @ts-ignore
							 | 
						||
| 
								 | 
							
								            this.connected = this.client.isConnected
							 | 
						||
| 
								 | 
							
								                ? // @ts-ignore
							 | 
						||
| 
								 | 
							
								                    this.client.isConnected()
							 | 
						||
| 
								 | 
							
								                : true;
							 | 
						||
| 
								 | 
							
								            return;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        // @ts-expect-error
							 | 
						||
| 
								 | 
							
								        this.connected = ((_b = (_a = this.db) === null || _a === void 0 ? void 0 : _a.topology) === null || _b === void 0 ? void 0 : _b.isConnected()) || true;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Sets the database connection and emit the connection event
							 | 
						||
| 
								 | 
							
								     * @param db - Database instance or Mongoose instance to set
							 | 
						||
| 
								 | 
							
								     * @param [client] - Optional Mongo client for MongoDb v3
							 | 
						||
| 
								 | 
							
								     **/
							 | 
						||
| 
								 | 
							
								    _setDb(db, client) {
							 | 
						||
| 
								 | 
							
								        this.connecting = false;
							 | 
						||
| 
								 | 
							
								        // Check if the object is a mongoose instance, a mongoose Connection or a mongo Db object
							 | 
						||
| 
								 | 
							
								        this.db = utils_1.getDatabase(db);
							 | 
						||
| 
								 | 
							
								        if (client) {
							 | 
						||
| 
								 | 
							
								            this.client = client;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        const errorEvent = (error_) => {
							 | 
						||
| 
								 | 
							
								            // Needs verification. Sometimes the event fires without an error object
							 | 
						||
| 
								 | 
							
								            // although the docs specify each of the events has a MongoError argument
							 | 
						||
| 
								 | 
							
								            this._updateConnectionStatus();
							 | 
						||
| 
								 | 
							
								            const error = error_ || new Error('Unknown database error');
							 | 
						||
| 
								 | 
							
								            this.emit('dbError', error);
							 | 
						||
| 
								 | 
							
								        };
							 | 
						||
| 
								 | 
							
								        // This are all the events that emit errors
							 | 
						||
| 
								 | 
							
								        const errorEventNames = ['error', 'parseError', 'timeout', 'close'];
							 | 
						||
| 
								 | 
							
								        let eventSource;
							 | 
						||
| 
								 | 
							
								        if (utils_1.shouldListenOnDb()) {
							 | 
						||
| 
								 | 
							
								            eventSource = this.db;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else if (this.client) {
							 | 
						||
| 
								 | 
							
								            eventSource = this.client;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if (eventSource) {
							 | 
						||
| 
								 | 
							
								            for (const evt of errorEventNames)
							 | 
						||
| 
								 | 
							
								                eventSource.on(evt, errorEvent);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        this._updateConnectionStatus();
							 | 
						||
| 
								 | 
							
								        // Emit on next tick so user code can set listeners in case the db object is already available
							 | 
						||
| 
								 | 
							
								        process.nextTick(() => {
							 | 
						||
| 
								 | 
							
								            this.emit('connection', { db: this.db, client: this.client });
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Removes the database reference and emit the connectionFailed event
							 | 
						||
| 
								 | 
							
								     * @param err - The error received while trying to connect
							 | 
						||
| 
								 | 
							
								     **/
							 | 
						||
| 
								 | 
							
								    _fail(error) {
							 | 
						||
| 
								 | 
							
								        this.connecting = false;
							 | 
						||
| 
								 | 
							
								        this.db = null;
							 | 
						||
| 
								 | 
							
								        this.client = null;
							 | 
						||
| 
								 | 
							
								        this.error = error;
							 | 
						||
| 
								 | 
							
								        this._updateConnectionStatus();
							 | 
						||
| 
								 | 
							
								        // Fail event is only emitted after either a then promise handler or an I/O phase so is guaranteed to be asynchronous
							 | 
						||
| 
								 | 
							
								        this.emit('connectionFailed', error);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Tests for generator functions or plain functions and delegates to the appropriate method
							 | 
						||
| 
								 | 
							
								     * @param request - The request that trigger the upload as received in _handleFile
							 | 
						||
| 
								 | 
							
								     * @param {File} file - The uploaded file stream as received in _handleFile
							 | 
						||
| 
								 | 
							
								     * @return A promise with the value generated by the file function
							 | 
						||
| 
								 | 
							
								     **/
							 | 
						||
| 
								 | 
							
								    _generate(request, file) {
							 | 
						||
| 
								 | 
							
								        return __awaiter(this, void 0, void 0, function* () {
							 | 
						||
| 
								 | 
							
								            let result;
							 | 
						||
| 
								 | 
							
								            let generator;
							 | 
						||
| 
								 | 
							
								            let isGen = false;
							 | 
						||
| 
								 | 
							
								            if (!this._file) {
							 | 
						||
| 
								 | 
							
								                return {};
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            if (isGeneratorFn(this._file)) {
							 | 
						||
| 
								 | 
							
								                isGen = true;
							 | 
						||
| 
								 | 
							
								                generator = this._file(request, file);
							 | 
						||
| 
								 | 
							
								                this._file = generator;
							 | 
						||
| 
								 | 
							
								                result = generator.next();
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else if (is_generator_1.default(this._file)) {
							 | 
						||
| 
								 | 
							
								                isGen = true;
							 | 
						||
| 
								 | 
							
								                generator = this._file;
							 | 
						||
| 
								 | 
							
								                result = generator.next([request, file]);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else {
							 | 
						||
| 
								 | 
							
								                result = this._file(request, file);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            return GridFsStorage._handleResult(result, isGen);
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								exports.GridFsStorage = GridFsStorage;
							 | 
						||
| 
								 | 
							
								GridFsStorage.cache = new cache_1.Cache();
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Event emitted when the MongoDb connection is ready to use
							 | 
						||
| 
								 | 
							
								 * @event module:multer-gridfs-storage/gridfs~GridFSStorage#connection
							 | 
						||
| 
								 | 
							
								 * @param {{db: Db, client: MongoClient}} result - An object containing the mongodb database and client
							 | 
						||
| 
								 | 
							
								 * @version 0.0.3
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Event emitted when the MongoDb connection fails to open
							 | 
						||
| 
								 | 
							
								 * @event module:multer-gridfs-storage/gridfs~GridFSStorage#connectionFailed
							 | 
						||
| 
								 | 
							
								 * @param {Error} err - The error received when attempting to connect
							 | 
						||
| 
								 | 
							
								 * @version 2.0.0
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Event emitted when a new file is uploaded
							 | 
						||
| 
								 | 
							
								 * @event module:multer-gridfs-storage/gridfs~GridFSStorage#file
							 | 
						||
| 
								 | 
							
								 * @param {File} file - The uploaded file
							 | 
						||
| 
								 | 
							
								 * @version 0.0.3
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Event emitted when an error occurs streaming to MongoDb
							 | 
						||
| 
								 | 
							
								 * @event module:multer-gridfs-storage/gridfs~GridFSStorage#streamError
							 | 
						||
| 
								 | 
							
								 * @param {Error} error - The error thrown by the stream
							 | 
						||
| 
								 | 
							
								 * @param {Object} conf - The failed file configuration
							 | 
						||
| 
								 | 
							
								 * @version 1.3
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Event emitted when the internal database connection emits an error
							 | 
						||
| 
								 | 
							
								 * @event module:multer-gridfs-storage/gridfs~GridFSStorage#dbError
							 | 
						||
| 
								 | 
							
								 * @param {Error} error - The error thrown by the database connection
							 | 
						||
| 
								 | 
							
								 * @version 1.2.2
							 | 
						||
| 
								 | 
							
								 **/
							 | 
						||
| 
								 | 
							
								exports.GridFsStorageCtr = new Proxy(GridFsStorage, {
							 | 
						||
| 
								 | 
							
								    apply(target, thisArg, argumentsList) {
							 | 
						||
| 
								 | 
							
								        // @ts-expect-error
							 | 
						||
| 
								 | 
							
								        return new target(...argumentsList); // eslint-disable-line new-cap
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								//# sourceMappingURL=gridfs.js.map
							 |