@foal/storage
Version:
Storage components for FoalTS
119 lines (118 loc) • 4.13 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Disk = exports.FileDoesNotExist = void 0;
exports.isFileDoesNotExist = isFileDoesNotExist;
// std
const path_1 = require("path");
// 3p
const core_1 = require("@foal/core");
const mime_1 = require("mime");
/**
* Error thrown by the file storage (disk) if the file could
* not be found.
*
* @export
* @class FileDoesNotExist
* @extends {Error}
*/
class FileDoesNotExist extends Error {
filename;
name = 'FileDoesNotExist';
constructor(filename) {
super(`The file "${filename}" does not exist.`);
this.filename = filename;
}
}
exports.FileDoesNotExist = FileDoesNotExist;
/**
* Check if an object is an instance of FileDoesNotExist.
*
* This function is a help when you have several packages using @foal/storage.
* Npm can install the package several times, which leads to duplicate class
* definitions. If this is the case, the keyword `instanceof` may return false
* while the object is an instance of the class. This function fixes this
* problem.
*
* @export
* @param {*} obj - The object to check.
* @returns {obj is FileDoesNotExist} - True if the error is an instance of FileDoesNotExist. False otherwise.
*/
function isFileDoesNotExist(obj) {
return obj instanceof FileDoesNotExist ||
(typeof obj === 'object' && obj !== null && obj.name === 'FileDoesNotExist');
}
/**
* Agnostic file storage.
*
* @export
* @abstract
* @class Disk
*/
class Disk {
static concreteClassConfigPath = 'settings.disk.driver';
static concreteClassName = 'ConcreteDisk';
static defaultConcreteClassPath = (0, path_1.join)(__dirname, './local-disk.service');
/**
* Create a directory if it does not exist.
*
* Depending on the storage system, the concept of directory may not exist. In this case,
* the method should do nothing, which is the default behavior.
*
* @param dirname Name or path of the directory to create.
* @returns {Promise<void>}
*/
async mkdirIfNotExists(dirname) {
// Do nothing by default.
}
/**
* Create an HttpResponse object to download or display the file in the
* browser.
*
* @param {string} path - The path of the file.
* @param {{ forceDownload?: boolean, filename?: string }} [options={}]
* @param {boolean} [options.forceDownload=false] - Indicate if the browser should download
* the file directly without trying to display it in the window.
* @param {filename} [options.string=options.file] - Default name used by the browser when
* saving the file to the disk.
* @returns {Promise<HttpResponse>}
* @memberof Disk
*/
async createHttpResponse(path, options = {}) {
const { file, size } = await this.read(path, 'stream');
const response = new core_1.HttpResponseOK(file, { stream: true });
if (options.cache) {
response.setHeader('Cache-Control', options.cache);
}
const mimeType = (0, mime_1.getType)(path) || 'application/octet-stream';
return response
.setHeader('Content-Type', mimeType)
.setHeader('Content-Length', size.toString())
.setHeader('Content-Disposition', (options.forceDownload ? 'attachment' : 'inline')
+ `; filename="${options.filename || (0, path_1.basename)(path)}"`);
}
/**
* Returns true if the write options has a "name" property.
*
* @protected
* @param {*} options - Write options.
* @returns {options is { name: string }} True or false.
* @memberof Disk
*/
hasName(options) {
// options.name === '' returns false;
return !!options.name;
}
/**
* Returns true if the write options has a "extension" property.
*
* @protected
* @param {*} options - Write options.
* @returns {options is { extension: string }} True or false.
* @memberof Disk
*/
hasExtension(options) {
// options.extension === '' returns false;
return !!options.extension;
}
}
exports.Disk = Disk;