UNPKG

flydrive

Version:

File storage library with unified API to manage files across multiple cloud storage providers like S3, GCS, R2 and so on

313 lines (307 loc) 8.56 kB
var __defProp = Object.defineProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; // src/errors.ts var errors_exports = {}; __export(errors_exports, { E_CANNOT_CHECK_FILE_EXISTENCE: () => E_CANNOT_CHECK_FILE_EXISTENCE, E_CANNOT_COPY_FILE: () => E_CANNOT_COPY_FILE, E_CANNOT_DELETE_DIRECTORY: () => E_CANNOT_DELETE_DIRECTORY, E_CANNOT_DELETE_FILE: () => E_CANNOT_DELETE_FILE, E_CANNOT_GENERATE_URL: () => E_CANNOT_GENERATE_URL, E_CANNOT_GET_METADATA: () => E_CANNOT_GET_METADATA, E_CANNOT_MOVE_FILE: () => E_CANNOT_MOVE_FILE, E_CANNOT_READ_FILE: () => E_CANNOT_READ_FILE, E_CANNOT_SET_VISIBILITY: () => E_CANNOT_SET_VISIBILITY, E_CANNOT_WRITE_FILE: () => E_CANNOT_WRITE_FILE, E_INVALID_KEY: () => E_INVALID_KEY, E_PATH_TRAVERSAL_DETECTED: () => E_PATH_TRAVERSAL_DETECTED, E_UNALLOWED_CHARACTERS: () => E_UNALLOWED_CHARACTERS }); import { createError } from "@poppinss/utils"; var E_CANNOT_WRITE_FILE = createError( 'Cannot write file at location "%s"', "E_CANNOT_WRITE_FILE" ); var E_CANNOT_READ_FILE = createError( 'Cannot read file from location "%s"', "E_CANNOT_READ_FILE" ); var E_CANNOT_DELETE_FILE = createError( 'Cannot delete file at location "%s"', "E_CANNOT_DELETE_FILE" ); var E_CANNOT_DELETE_DIRECTORY = createError( 'Cannot delete directory at location "%s"', "E_CANNOT_DELETE_DIRECTORY" ); var E_CANNOT_COPY_FILE = createError( 'Cannot copy file from "%s" to "%s"', "E_CANNOT_COPY_FILE" ); var E_CANNOT_MOVE_FILE = createError( 'Cannot move file from "%s" to "%s"', "E_CANNOT_MOVE_FILE" ); var E_CANNOT_CHECK_FILE_EXISTENCE = createError( 'Unable to check existence for file at location "%s"', "E_CANNOT_CHECK_FILE_EXISTENCE" ); var E_CANNOT_GET_METADATA = createError( 'Unable to retrieve metadata of file at location "%s"', "E_CANNOT_GET_METADATA" ); var E_CANNOT_SET_VISIBILITY = createError( 'Unable to set visibility for file at location "%s"', "E_CANNOT_SET_VISIBILITY" ); var E_CANNOT_GENERATE_URL = createError( 'Cannot generate URL for file at location "%s"', "E_CANNOT_GENERATE_URL" ); var E_UNALLOWED_CHARACTERS = createError( 'The key "%s" has unallowed characters', "E_UNALLOWED_CHARACTERS" ); var E_INVALID_KEY = createError( 'Invalid key "%s". After normalization results in an empty string', "E_INVALID_KEY" ); var E_PATH_TRAVERSAL_DETECTED = createError( 'Path traversal segment detected in key "%s"', "E_PATH_TRAVERSAL_DETECTED" ); // src/key_normalizer.ts import { slash } from "@poppinss/utils"; import { normalize } from "node:path/posix"; import string from "@poppinss/utils/string"; var KeyNormalizer = class _KeyNormalizer { /** * The set of allowed characters. Key free to re-assign a new * value */ static allowedCharacterSet = /^[A-Za-z0-9-_!\/\.\s]*$/; /** * Normalizes the key by condensing whitespaces, using unix * slashes, and replacing consecutive slashes with one * slash ("/"). */ #preNormalize(key) { let normalizedKey = string.condenseWhitespace(key); return slash(normalizedKey).replace(/\/{2,}/g, "/").replace(/\.{3,}\//g, "../"); } /** * Validates the key to check for unallowed characters */ #validateCharacterSet(key, originalKey) { if (!_KeyNormalizer.allowedCharacterSet.test(key)) { throw new E_UNALLOWED_CHARACTERS([originalKey]); } } /** * Checks for path traversel in key */ #checkForPathTraversal(key, originalKey) { const tokens = key.split("/"); for (let token of tokens) { if (token === "..") { throw new E_PATH_TRAVERSAL_DETECTED([originalKey]); } } } /** * Further normalizing the key after validating it. Here we remove * starting and ending path expressions like "." and "/" from * the key. */ #postNormalize(key) { let normalizedKey = normalize(key); return normalizedKey.replace(/^\/|\/$/g, "").replace(/^\.|\.$/g, ""); } /** * Normalize the key */ normalize(key) { let normalizedKey = this.#preNormalize(key); this.#validateCharacterSet(normalizedKey, key); this.#checkForPathTraversal(normalizedKey, key); normalizedKey = this.#postNormalize(normalizedKey); if (normalizedKey.trim() === "") { throw new E_INVALID_KEY([key]); } return normalizedKey; } }; // src/driver_file.ts import { basename } from "node:path"; var DriveFile = class { /** * The driver to use for performing read-only operations */ #driver; /** * Known metadata from the snapshot or from the files listing * API */ #metaData; /** * The normalizer is used to normalize and validate keys */ #normalizer = new KeyNormalizer(); /** * Reference to the normalized file key */ key; /** * The basename of the file. Extracted from the key */ name; /** * Flags to know if the object is a file or a directory */ isFile = true; isDirectory = false; constructor(key, driver, metaData) { this.#driver = driver; this.#metaData = metaData; this.key = this.#normalizer.normalize(key); this.name = basename(this.key); } /** * Check if the file exists. This method cannot check existence * of directories. */ async exists() { try { return await this.#driver.exists(this.key); } catch (error) { throw new E_CANNOT_CHECK_FILE_EXISTENCE([this.key], { cause: error }); } } /** * Returns file contents as a UTF-8 string. Use "getArrayBuffer" method * if you need more control over the file contents decoding. */ async get() { try { return await this.#driver.get(this.key); } catch (error) { throw new E_CANNOT_READ_FILE([this.key], { cause: error }); } } /** * Returns file contents as a Readable stream. */ async getStream() { try { return await this.#driver.getStream(this.key); } catch (error) { throw new E_CANNOT_READ_FILE([this.key], { cause: error }); } } /** * Returns file contents as a Uint8Array. */ async getBytes() { try { return await this.#driver.getBytes(this.key); } catch (error) { throw new E_CANNOT_READ_FILE([this.key], { cause: error }); } } /** * @deprecated * @see {@link DriveFile.getBytes} */ async getArrayBuffer() { process.emitWarning( 'getArrayBuffer() method has been deprecated. Instead use "getBytes"', "DeprecationWarning" ); return this.getBytes(); } /** * Returns metadata of the given file. */ async getMetaData() { if (this.#metaData) { return this.#metaData; } try { return await this.#driver.getMetaData(this.key); } catch (error) { throw new E_CANNOT_GET_METADATA([this.key], { cause: error }); } } /** * Returns the visibility of the file */ async getVisibility() { try { return await this.#driver.getVisibility(this.key); } catch (error) { throw new E_CANNOT_GET_METADATA([this.key], { cause: error }); } } /** * Returns the public URL of the file */ async getUrl() { try { return await this.#driver.getUrl(this.key); } catch (error) { throw new E_CANNOT_GENERATE_URL([this.key], { cause: error }); } } /** * Returns a signed/temporary URL of the file */ async getSignedUrl(options) { try { return await this.#driver.getSignedUrl(this.key, options); } catch (error) { throw new E_CANNOT_GENERATE_URL([this.key], { cause: error }); } } /** * Returns a snapshot of the file. The snapshot could be persisted * within any database storage and later you can create a file * instance from it using the "disk.fromSnapshot" method. */ async toSnapshot() { const metaData = await this.getMetaData(); return { key: this.key, name: this.name, contentLength: metaData.contentLength, lastModified: metaData.lastModified.toString(), etag: metaData.etag, contentType: metaData.contentType }; } }; // src/drive_directory.ts import { basename as basename2 } from "node:path"; var DriveDirectory = class { constructor(prefix) { this.prefix = prefix; this.name = basename2(this.prefix); } isFile = false; isDirectory = true; name; }; export { E_CANNOT_WRITE_FILE, E_CANNOT_DELETE_FILE, E_CANNOT_DELETE_DIRECTORY, E_CANNOT_COPY_FILE, E_CANNOT_MOVE_FILE, E_CANNOT_SET_VISIBILITY, errors_exports, KeyNormalizer, DriveFile, DriveDirectory };