Comparing version 0.0.1-0 to 0.0.1-1
import { | ||
__export | ||
} from "./chunk-CSAU5B4Q.js"; | ||
DriveFile, | ||
E_CANNOT_COPY_FILE, | ||
E_CANNOT_DELETE_DIRECTORY, | ||
E_CANNOT_DELETE_FILE, | ||
E_CANNOT_MOVE_FILE, | ||
E_CANNOT_SET_VISIBILITY, | ||
E_CANNOT_WRITE_FILE, | ||
KeyNormalizer, | ||
errors_exports | ||
} from "./chunk-ZANMH6SI.js"; | ||
// src/errors.ts | ||
var errors_exports = {}; | ||
__export(errors_exports, { | ||
E_CANNOT_COPY_FILE: () => E_CANNOT_COPY_FILE, | ||
E_CANNOT_DELETE_FILE: () => E_CANNOT_DELETE_FILE, | ||
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_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_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_GET_METADATA = createError( | ||
'Unable to retrieve metadata of file at location "%s"', | ||
"E_CANNOT_GET_METADATA" | ||
); | ||
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 { | ||
// src/disk.ts | ||
import { unlink } from "node:fs/promises"; | ||
import { createReadStream } from "node:fs"; | ||
var Disk = class { | ||
constructor(driver) { | ||
this.driver = driver; | ||
} | ||
/** | ||
* The set of allowed characters. Key free to re-assign a new | ||
* value | ||
* The normalizer is used to normalize and validate keys | ||
*/ | ||
static allowedCharacterSet = /^[A-Za-z0-9-_!\/\.\s]*$/; | ||
#normalizer = new KeyNormalizer(); | ||
/** | ||
* Normalizes the key by condensing whitespaces, using unix | ||
* slashes, and replacing consecutive slashes with one | ||
* slash ("/"). | ||
* Creates a new instance of the DriveFile. It can be used | ||
* to lazily fetch file contents or convert it into a | ||
* snapshot for persistence | ||
*/ | ||
#preNormalize(key) { | ||
let normalizedKey = string.condenseWhitespace(key); | ||
return slash(normalizedKey).replace(/\/{2,}/g, "/"); | ||
file(key) { | ||
return new DriveFile(key, this.driver); | ||
} | ||
/** | ||
* Validates the key to check for unallowed characters | ||
* Returns file contents as a UTF-8 string. Use "getArrayBuffer" method | ||
* if you need more control over the file contents decoding. | ||
*/ | ||
#validateCharacterSet(key, originalKey) { | ||
if (!_KeyNormalizer.allowedCharacterSet.test(key)) { | ||
throw new E_UNALLOWED_CHARACTERS([originalKey]); | ||
} | ||
get(key) { | ||
return this.file(key).get(); | ||
} | ||
/** | ||
* Checks for path traversel in key | ||
* Returns file contents as a Readable stream. | ||
*/ | ||
#checkForPathTraversal(key, originalKey) { | ||
const tokens = key.split("/"); | ||
for (let token of tokens) { | ||
if (token === "..") { | ||
throw new E_PATH_TRAVERSAL_DETECTED([originalKey]); | ||
} | ||
} | ||
getStream(key) { | ||
return this.file(key).getStream(); | ||
} | ||
/** | ||
* Further normalizing the key after validating it. Here we remove | ||
* starting and ending path expressions like "." and "/" from | ||
* the key. | ||
* Returns file contents as a Uint8Array. | ||
*/ | ||
#postNormalize(key) { | ||
let normalizedKey = normalize(key); | ||
return normalizedKey.replace(/^\/|\/$/g, "").replace(/^\.|\.$/g, ""); | ||
getArrayBuffer(key) { | ||
return this.file(key).getArrayBuffer(); | ||
} | ||
/** | ||
* Normalize the key | ||
* Returns metadata of the given file. | ||
*/ | ||
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]); | ||
getMetaData(key) { | ||
return this.file(key).getMetaData(); | ||
} | ||
/** | ||
* Returns the visibility of the file | ||
*/ | ||
async getVisibility(key) { | ||
return this.file(key).getVisibility(); | ||
} | ||
/** | ||
* Update the visibility of the file | ||
*/ | ||
async setVisibility(key, visibility) { | ||
key = this.#normalizer.normalize(key); | ||
try { | ||
return await this.driver.setVisibility(key, visibility); | ||
} catch (error) { | ||
throw new E_CANNOT_SET_VISIBILITY([key], { cause: error }); | ||
} | ||
return normalizedKey; | ||
} | ||
}; | ||
// src/disk.ts | ||
var Disk = class { | ||
constructor(driver, normalizer) { | ||
this.driver = driver; | ||
this.#normalizer = normalizer || new KeyNormalizer(); | ||
} | ||
#normalizer; | ||
/** | ||
* Create new file or update an existing file. In case of an error, | ||
* the "E_CANNOT_WRITE_FILE" exception is thrown | ||
*/ | ||
async put(key, contents, options) { | ||
@@ -133,2 +86,6 @@ key = this.#normalizer.normalize(key); | ||
} | ||
/** | ||
* Create new file or update an existing file using a Readable Stream | ||
* In case of an error, the "E_CANNOT_WRITE_FILE" exception is thrown | ||
*/ | ||
async putStream(key, contents, options) { | ||
@@ -142,39 +99,14 @@ key = this.#normalizer.normalize(key); | ||
} | ||
async get(key) { | ||
key = this.#normalizer.normalize(key); | ||
try { | ||
return await this.driver.get(key); | ||
} catch (error) { | ||
throw new E_CANNOT_READ_FILE([key], { cause: error }); | ||
} | ||
} | ||
async getStream(key) { | ||
key = this.#normalizer.normalize(key); | ||
try { | ||
return await this.driver.getStream(key); | ||
} catch (error) { | ||
throw new E_CANNOT_READ_FILE([key], { cause: error }); | ||
} | ||
} | ||
async getArrayBuffer(key) { | ||
key = this.#normalizer.normalize(key); | ||
try { | ||
return await this.driver.getArrayBuffer(key); | ||
} catch (error) { | ||
throw new E_CANNOT_READ_FILE([key], { cause: error }); | ||
} | ||
} | ||
async getMetaData(key) { | ||
key = this.#normalizer.normalize(key); | ||
try { | ||
return await this.driver.getMetaData(key); | ||
} catch (error) { | ||
throw new E_CANNOT_GET_METADATA([key], { cause: error }); | ||
} | ||
} | ||
async copy(source, destination) { | ||
/** | ||
* Copies file from the "source" to the "destination" within the | ||
* same bucket or the root location of local filesystem. | ||
* | ||
* Use "copyFromFs" method to copy files from local filesystem to | ||
* a cloud provider | ||
*/ | ||
async copy(source, destination, options) { | ||
source = this.#normalizer.normalize(source); | ||
destination = this.#normalizer.normalize(destination); | ||
try { | ||
return await this.driver.copy(source, destination); | ||
return await this.driver.copy(source, destination, options); | ||
} catch (error) { | ||
@@ -184,7 +116,20 @@ throw new E_CANNOT_COPY_FILE([source, destination], { cause: error }); | ||
} | ||
async move(source, destination) { | ||
/** | ||
* Copies file from the local filesystem to the cloud provider. | ||
*/ | ||
copyFromFs(source, destination, options) { | ||
return this.putStream(destination, createReadStream(source), options); | ||
} | ||
/** | ||
* Moves file from the "source" to the "destination" within the | ||
* same bucket or the root location of local filesystem. | ||
* | ||
* Use "moveFromFs" method to move files from local filesystem to | ||
* a cloud provider | ||
*/ | ||
async move(source, destination, options) { | ||
source = this.#normalizer.normalize(source); | ||
destination = this.#normalizer.normalize(destination); | ||
try { | ||
return await this.driver.move(source, destination); | ||
return await this.driver.move(source, destination, options); | ||
} catch (error) { | ||
@@ -194,2 +139,13 @@ throw new E_CANNOT_MOVE_FILE([source, destination], { cause: error }); | ||
} | ||
/** | ||
* Moves file from the local filesystem to the cloud provider. | ||
*/ | ||
async moveFromFs(source, destination, options) { | ||
await this.putStream(destination, createReadStream(source), options); | ||
await unlink(source); | ||
} | ||
/** | ||
* Deletes a file for the given key. Use "deleteAll" method to delete | ||
* files for a matching folder prefix. | ||
*/ | ||
async delete(key) { | ||
@@ -203,2 +159,14 @@ key = this.#normalizer.normalize(key); | ||
} | ||
/** | ||
* Delete all files matching the given prefix. In case of "fs" driver, | ||
* the mentioned folder will be deleted. | ||
*/ | ||
async deleteAll(prefix) { | ||
prefix = this.#normalizer.normalize(prefix); | ||
try { | ||
return await this.driver.deleteAll(prefix); | ||
} catch (error) { | ||
throw new E_CANNOT_DELETE_DIRECTORY([prefix], { cause: error }); | ||
} | ||
} | ||
}; | ||
@@ -205,0 +173,0 @@ export { |
/// <reference types="node" resolution-mode="require"/> | ||
/// <reference types="node" resolution-mode="require"/> | ||
import type { Readable } from 'node:stream'; | ||
import type { DriverContract, ObjectMetaData, WriteOptions } from './types.js'; | ||
import { DriveFile } from './driver_file.js'; | ||
import type { DriverContract, ObjectMetaData, ObjectVisibility, WriteOptions } from './types.js'; | ||
/** | ||
@@ -10,14 +12,78 @@ * Disk offers a unified API for working with different drivers | ||
driver: DriverContract; | ||
constructor(driver: DriverContract, normalizer?: { | ||
normalize(key: string): string; | ||
}); | ||
put(key: string, contents: string | Uint8Array, options?: WriteOptions): Promise<void>; | ||
putStream(key: string, contents: Readable, options?: WriteOptions): Promise<void>; | ||
constructor(driver: DriverContract); | ||
/** | ||
* Creates a new instance of the DriveFile. It can be used | ||
* to lazily fetch file contents or convert it into a | ||
* snapshot for persistence | ||
*/ | ||
file(key: string): DriveFile; | ||
/** | ||
* Returns file contents as a UTF-8 string. Use "getArrayBuffer" method | ||
* if you need more control over the file contents decoding. | ||
*/ | ||
get(key: string): Promise<string>; | ||
/** | ||
* Returns file contents as a Readable stream. | ||
*/ | ||
getStream(key: string): Promise<Readable>; | ||
/** | ||
* Returns file contents as a Uint8Array. | ||
*/ | ||
getArrayBuffer(key: string): Promise<ArrayBuffer>; | ||
/** | ||
* Returns metadata of the given file. | ||
*/ | ||
getMetaData(key: string): Promise<ObjectMetaData>; | ||
copy(source: string, destination: string): Promise<void>; | ||
move(source: string, destination: string): Promise<void>; | ||
/** | ||
* Returns the visibility of the file | ||
*/ | ||
getVisibility(key: string): Promise<ObjectVisibility>; | ||
/** | ||
* Update the visibility of the file | ||
*/ | ||
setVisibility(key: string, visibility: ObjectVisibility): Promise<void>; | ||
/** | ||
* Create new file or update an existing file. In case of an error, | ||
* the "E_CANNOT_WRITE_FILE" exception is thrown | ||
*/ | ||
put(key: string, contents: string | Uint8Array, options?: WriteOptions): Promise<void>; | ||
/** | ||
* Create new file or update an existing file using a Readable Stream | ||
* In case of an error, the "E_CANNOT_WRITE_FILE" exception is thrown | ||
*/ | ||
putStream(key: string, contents: Readable, options?: WriteOptions): Promise<void>; | ||
/** | ||
* Copies file from the "source" to the "destination" within the | ||
* same bucket or the root location of local filesystem. | ||
* | ||
* Use "copyFromFs" method to copy files from local filesystem to | ||
* a cloud provider | ||
*/ | ||
copy(source: string, destination: string, options?: WriteOptions): Promise<void>; | ||
/** | ||
* Copies file from the local filesystem to the cloud provider. | ||
*/ | ||
copyFromFs(source: string | URL, destination: string, options?: WriteOptions): Promise<void>; | ||
/** | ||
* Moves file from the "source" to the "destination" within the | ||
* same bucket or the root location of local filesystem. | ||
* | ||
* Use "moveFromFs" method to move files from local filesystem to | ||
* a cloud provider | ||
*/ | ||
move(source: string, destination: string, options?: WriteOptions): Promise<void>; | ||
/** | ||
* Moves file from the local filesystem to the cloud provider. | ||
*/ | ||
moveFromFs(source: string | URL, destination: string, options?: WriteOptions): Promise<void>; | ||
/** | ||
* Deletes a file for the given key. Use "deleteAll" method to delete | ||
* files for a matching folder prefix. | ||
*/ | ||
delete(key: string): Promise<void>; | ||
/** | ||
* Delete all files matching the given prefix. In case of "fs" driver, | ||
* the mentioned folder will be deleted. | ||
*/ | ||
deleteAll(prefix: string): Promise<void>; | ||
} |
@@ -14,2 +14,6 @@ /** | ||
/** | ||
* Unable to delete directory | ||
*/ | ||
export declare const E_CANNOT_DELETE_DIRECTORY: new (args: [key: string], options?: ErrorOptions | undefined) => import("@poppinss/utils").Exception; | ||
/** | ||
* Unable to copy file | ||
@@ -27,2 +31,10 @@ */ | ||
/** | ||
* Unable to set file visibility | ||
*/ | ||
export declare const E_CANNOT_SET_VISIBILITY: new (args: [key: string], options?: ErrorOptions | undefined) => import("@poppinss/utils").Exception; | ||
/** | ||
* Unable to generate URL for a file | ||
*/ | ||
export declare const E_CANNOT_GENERATE_URL: new (args: [key: string], options?: ErrorOptions | undefined) => import("@poppinss/utils").Exception; | ||
/** | ||
* The file key has unallowed set of characters | ||
@@ -29,0 +41,0 @@ */ |
/// <reference types="node" resolution-mode="require"/> | ||
import { Readable } from 'node:stream'; | ||
import { DriveFile } from './driver_file.js'; | ||
import { DriveDirectory } from './drive_directory.js'; | ||
/** | ||
@@ -12,3 +14,2 @@ * The visibility of the object. | ||
export type ObjectMetaData = { | ||
visibility: ObjectVisibility; | ||
contentType?: string; | ||
@@ -34,2 +35,12 @@ contentLength: number; | ||
/** | ||
* Options accepted during the creation of a signed URL. | ||
*/ | ||
export type SignedURLOptions = { | ||
expiresIn?: string | number; | ||
contentType?: string; | ||
contentDisposition?: string; | ||
} & { | ||
[key: string]: any; | ||
}; | ||
/** | ||
* The interface every driver must implement. | ||
@@ -39,12 +50,6 @@ */ | ||
/** | ||
* Write object to the destination with the provided | ||
* contents. | ||
* Return a boolean indicating if the file exists | ||
*/ | ||
put(key: string, contents: string | Uint8Array, options?: WriteOptions): Promise<void>; | ||
exist(key: string): Promise<boolean>; | ||
/** | ||
* Write object to the destination with the provided | ||
* contents as a readable stream | ||
*/ | ||
putStream(key: string, contents: Readable, options?: WriteOptions): Promise<void>; | ||
/** | ||
* Return contents of a object for the given key as a UTF-8 string. | ||
@@ -72,2 +77,28 @@ * Should throw "E_CANNOT_READ_FILE" error when the file | ||
/** | ||
* Return the visibility of the file | ||
*/ | ||
getVisibility(key: string): Promise<ObjectVisibility>; | ||
/** | ||
* Return the public URL to access the file | ||
*/ | ||
getUrl(key: string): Promise<string>; | ||
/** | ||
* Return the signed/temporary URL to access the file | ||
*/ | ||
getSignedUrl(key: string, options?: SignedURLOptions): Promise<string>; | ||
/** | ||
* Update the visibility of the file | ||
*/ | ||
setVisibility(key: string, visibility: ObjectVisibility): Promise<void>; | ||
/** | ||
* Write object to the destination with the provided | ||
* contents. | ||
*/ | ||
put(key: string, contents: string | Uint8Array, options?: WriteOptions): Promise<void>; | ||
/** | ||
* Write object to the destination with the provided | ||
* contents as a readable stream | ||
*/ | ||
putStream(key: string, contents: Readable, options?: WriteOptions): Promise<void>; | ||
/** | ||
* Copy the file from within the disk root location. Both | ||
@@ -93,2 +124,13 @@ * the "source" and "destination" will be the key names | ||
deleteAll(prefix: string): Promise<void>; | ||
/** | ||
* The list all method must return an array of objects with | ||
* the ability to paginate results (if supported). | ||
*/ | ||
listAll(prefix: string, options?: { | ||
recursive?: boolean; | ||
paginationToken?: string; | ||
}): Promise<{ | ||
paginationToken?: string; | ||
objects: Iterable<DriveFile | DriveDirectory>; | ||
}>; | ||
} |
{ | ||
"name": "flydrive", | ||
"description": "File storage library with unified API to manage files across multiple cloud storage providers like S3, GCS, R2 and so on", | ||
"version": "0.0.1-0", | ||
"version": "0.0.1-1", | ||
"engines": { | ||
@@ -30,3 +30,3 @@ "node": ">=20.6.0" | ||
"pretest": "npm run lint", | ||
"test": "c8 npm run quick:test", | ||
"test": "cross-env NODE_DEBUG=flydrive:* c8 npm run quick:test", | ||
"prebuild": "npm run lint && npm run clean", | ||
@@ -49,17 +49,18 @@ "build": "tsup-node && tsc --emitDeclarationOnly --declaration", | ||
"devDependencies": { | ||
"@adonisjs/env": "^6.0.0", | ||
"@adonisjs/env": "^6.0.1", | ||
"@adonisjs/eslint-config": "^1.3.0", | ||
"@adonisjs/prettier-config": "^1.3.0", | ||
"@adonisjs/tsconfig": "^1.3.0", | ||
"@aws-sdk/client-s3": "^3.552.0", | ||
"@google-cloud/storage": "^7.9.0", | ||
"@japa/assert": "^2.1.0", | ||
"@aws-sdk/client-s3": "^3.564.0", | ||
"@google-cloud/storage": "^7.10.2", | ||
"@japa/assert": "^3.0.0", | ||
"@japa/file-system": "^2.3.0", | ||
"@japa/runner": "^3.1.1", | ||
"@swc/core": "^1.4.6", | ||
"@swc/core": "^1.4.17", | ||
"@types/etag": "^1.8.3", | ||
"@types/mime-types": "^2.1.4", | ||
"@types/node": "^20.11.25", | ||
"@types/node": "^20.12.7", | ||
"c8": "^9.1.0", | ||
"copyfiles": "^2.4.1", | ||
"cross-env": "^7.0.3", | ||
"del-cli": "^5.1.0", | ||
@@ -66,0 +67,0 @@ "eslint": "^8.57.0", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
21389
13
525
24
1