API @deepkit/filesystem
npm install @deepkit/filesystem
Represents a file or directory in the filesystem system. In-memory filesystem adapter for testing purposes. Generic FilesystemError. Base of all errors thrown by the Filesystem system. Thrown when a file or directory does not exist. Thrown when an operation is aborted. A sorting comparator for FilesystemFile that sorts directories first, then by path. Creates a provider for Deepkit App to provide a Filesystem instance. If a function is given as adapter, it will be called once when the filesystem is created.
The function can have additional dependencies defined as parameters that will be resolved, e.g. configuration options. Creates a provider for Deepkit App to provide a default Filesystem instance,
that can be received or injected via Settings for file and directory permissions. Unknown when the adapter can't read it. Can be unknown in files() due to limits of listings in adapter, but available in get().Classes
export class FilesystemFile {
size: number;
lastModified?: Date;
/**
* Visibility of the file.
*
* Note that some adapters might not support reading the visibility of a file.
* In this case, the visibility is always 'private'.
*
* Some adapters might support reading the visibility per file, but not when listing files.
* In this case you have to call additional `filesystem.get(file)` to load the visibility.
*/
visibility: FileVisibility;
constructor(public path: string, public type: FileType = );
/**
* Returns true if this file is a symbolic link.
*/
isFile(): boolean;
/**
* Returns true if this file is a directory.
*/
isDirectory(): boolean;
/**
* Returns the name (basename) of the file.
*/
get name(): string;
/**
* Returns true if this file is in the given directory.
*
* /folder/file.txt => / => true
* /folder/file.txt => /folder => true
* /folder/file.txt => /folder/ => true
*
* /folder2/file.txt => /folder/ => false
* /folder/file.txt => /folder/folder2 => false
*/
inDirectory(directory: string): boolean;
/**
* Returns the directory (dirname) of the file.
*/
get directory(): string;
/**
* Returns the extension of the file, or an empty string if not existing or a directory.
*/
get extension(): string;
}
export class Filesystem {
options: FilesystemOptions;
constructor(public adapter: FilesystemAdapter, options: Partial<FilesystemOptions> = {});
/**
* Closes the adapter (close connections, etc).
*/
async close();
/**
* Reads a file from local file system.
*/
async readLocalFile(path: string): Promise<Uint8Array | undefined>;
/**
* Returns all files (and directories) directly in the given folder.
*
* Returns a Progress object that can be used to track the progress of the operation.
*/
files(path: FilesystemPath): Operation<FilesystemFile[]>;
/**
* Returns all files (and directories) paths in the given folder.
*
* Returns a Progress object that can be used to track the progress of the operation.
*/
fileNames(path: FilesystemPath): Operation<string[]>;
/**
* Returns all files (and directories) in the given folder and all subfolders.
*
* Returns a Progress object that can be used to track the progress of the operation.
*/
allFiles(path: FilesystemPath): Operation<FilesystemFile[]>;
/**
* Returns all files (and directories) paths in the given folder and all subfolders.
*
* Returns a Progress object that can be used to track the progress of the operation.
*/
allFileNames(path: FilesystemPath): Operation<string[]>;
/**
* Returns all directories directly in the given folder.
*
* Returns a Progress object that can be used to track the progress of the operation.
*/
directories(path: FilesystemPath): Operation<FilesystemFile[]>;
/**
* Returns all directories in the given folder and all subfolders.
*
* Returns a Progress object that can be used to track the progress of the operation.
*/
allDirectories(path: FilesystemPath): Operation<FilesystemFile[]>;
/**
* Writes the given content to the given path.
* Ensures that all parent directories exist.
* Overwrites if already existing.
*
* Returns a Progress object that can be used to track the progress of the operation.
*/
write(path: FilesystemPath, content: Uint8Array | string, visibility?: FileVisibility): Operation<void>;
/**
* Writes a given file reference (with path pointing to the file, e.g. UploadedFile) to the given directory.
*
* If no name is given, the basename of the file path is used.
*
* Returns the path to the saved file, so it can be used to store the path in a database.
*
* @example
* ```typescript
* filesystem.writeFile('uploads', uploadedFile);
* filesystem.writeFile('uploads', uploadedFile, {name: user.id});
* ```
*/
async writeFile(directory: string, file: {
path: string;
}, options: {
name?: string;
visibility?: FileVisibility;
} = {}): Promise<string>;
/**
* Appends the given content to the given file.
*
* Warning: On many filesystem adapters this loads the whole file first into memory.
*/
append(path: FilesystemPath, content: Uint8Array | string): Operation<void>;
/**
* Prepends the given content to the given file.
*
* Warning: On almost all filesystem adapters this loads the whole file first into memory.
*/
prepend(path: FilesystemPath, content: Uint8Array | string): Operation<void>;
/**
* Reads the contents of the given path as binary.
*
* Returns a Progress object that can be used to track the progress of the operation.
*
* @throws Error if the file does not exist.
*/
read(path: FilesystemPath): Operation<Uint8Array>;
/**
* Reads the contents of the given path as string.
*
* Returns a Progress object that can be used to track the progress of the operation.
*
* @throws Error if the file does not exist.
*/
readAsText(path: FilesystemPath): Operation<string>;
/**
* Returns the file at the given path.
*
* @throws FilesystemFileNotFound if the file does not exist.
*/
async get(path: FilesystemPath): Promise<FilesystemFile>;
/**
* Returns the file at the given path or undefined if not existing.
*/
getOrUndefined(path: FilesystemPath): Promise<FilesystemFile | undefined>;
/**
* Returns true if all the given paths exist.
*/
exists(path: FilesystemPath | FilesystemPath[]): Promise<boolean>;
/**
* Deletes all the given paths.
* Does nothing if the file does not exist.
*
* Throws an error if the path is not a file.
*/
async delete(path: FilesystemPath | FilesystemPath[]): Promise<void>;
/**
* Deletes the directory at the given path and all files and directories in it recursively.
*/
deleteDirectory(path: FilesystemPath): Operation<void>;
/**
* Copies the file or directory from source to destination, recursively.
*/
copy(source: FilesystemPath, destination: FilesystemPath): Operation<void>;
/**
* Moves the file or directory from source to destination, recursively.
*
* This might or might not be an atomic operation. If the adapter does not support moving,
* it will emulate it by doing it manually by copying and then deleting. While it copies,
* the source file keeps existing, so it's not atomic. If the process crashes, the source
* and destination might be in an inconsistent state.
*/
move(source: FilesystemPath, destination: FilesystemPath): Operation<void>;
/**
* Creates a new directory, and all parent directories if not existing.
*/
makeDirectory(path: FilesystemPath, visibility?: FileVisibility): Promise<void>;
/**
* Returns the public URL for the given path.
*/
publicUrl(path: FilesystemPath): string;
/**
* Sets the visibility of the given path.
*/
async setVisibility(path: FilesystemPath, visibility: FileVisibility): Promise<void>;
}
export class FilesystemLocalAdapter implements FilesystemAdapter {
fs?: typeof fs;
constructor(options: Partial<FilesystemLocalAdapterOptions>);
supportsVisibility();
supportsDirectory();
getPath(path: string): string;
async copy(source: string, destination: string, reporter: Reporter): Promise<void>;
async delete(paths: string[]): Promise<void>;
async makeDirectory(path: string, visibility: FileVisibility): Promise<void>;
async deleteDirectory(path: string, reporter: Reporter): Promise<void>;
async exists(paths: string[]): Promise<boolean>;
async files(path: string): Promise<FilesystemFile[]>;
async allFiles(path: string, reporter: Reporter): Promise<FilesystemFile[]>;
async directories(path: string): Promise<FilesystemFile[]>;
async allDirectories(path: string, reporter: Reporter): Promise<FilesystemFile[]>;
async get(path: string): Promise<FilesystemFile | undefined>;
async move(source: string, destination: string, reporter: Reporter): Promise<void>;
async read(path: string, reporter: Reporter): Promise<Uint8Array>;
async write(path: string, contents: Uint8Array, visibility: FileVisibility, reporter: Reporter): Promise<void>;
async append(path: string, contents: Uint8Array, reporter: Reporter): Promise<void>;
async setVisibility(path: string, visibility: FileVisibility): Promise<void>;
}
export class FilesystemMemoryAdapter implements FilesystemAdapter {
constructor(options: Partial<FilesystemMemoryAdapterOptions> = {});
supportsVisibility();
supportsDirectory();
async files(path: string): Promise<FilesystemFile[]>;
async makeDirectory(path: string, visibility: FileVisibility): Promise<void>;
async allFiles(path: string): Promise<FilesystemFile[]>;
async directories(path: string): Promise<FilesystemFile[]>;
async allDirectories(path: string): Promise<FilesystemFile[]>;
async write(path: string, contents: Uint8Array, visibility: FileVisibility, reporter: Reporter): Promise<void>;
async read(path: string, reporter: Reporter): Promise<Uint8Array>;
async exists(paths: string[]): Promise<boolean>;
async delete(paths: string[]): Promise<void>;
async deleteDirectory(path: string, reporter: Reporter): Promise<void>;
async get(path: string): Promise<FilesystemFile | undefined>;
async copy(source: string, destination: string, reporter: Reporter): Promise<void>;
async move(source: string, destination: string, reporter: Reporter): Promise<void>;
async setVisibility(path: string, visibility: FileVisibility): Promise<void>;
}
Errors
export class FilesystemError extends Error {
}
export class FilesystemFileNotFound extends FilesystemError {
}
export class FilesystemOperationAborted extends FilesystemError {
}
Functions
<T>(callback: (reporter: Reporter) => Promise<T>): Operation<T>
(path: FilesystemPath): string
(a: FilesystemFile, b: FilesystemFile): number
(path: string): string[]
(name: string, adapter: FilesystemAdapter | (() => FilesystemAdapter), options?: Partial<FilesystemOptions>): ({ provide: string; useFactory: () => FilesystemAdapter; } | { ...; })[]
(adapter: FilesystemAdapter | (() => FilesystemAdapter), options?: Partial<FilesystemOptions>): ({ provide: string; useFactory: () => FilesystemAdapter; } | { provide: string | typeof Filesystem; useFactory: (adapter: FilesystemAdapter & Inject<string>) => Filesystem; })[]
Filesystem
class.Types
type FileType = 'file' | 'directory';
type FileVisibility = 'public' | 'private' | 'unknown';
interface Operation<T> extends Promise<T> {
/**
* Adds a callback that is called when the progress changes.
* Filesystem adapters might report progress on some operations,
* like read/write content, read folder, copy, move, etc.
*
* The unit of loaded and total is not defined and depends on the adapter.
* It might be bytes or the amount of files. if total=0, the total is unknown.
*/
onProgress(callback: (loaded: number, total: number) => void): this;
/**
* When called the filesystem adapter tries to abort the operation.
* This is not guaranteed to work, as some adapters might not support it.
* When aborted, the promise will be rejected with an FilesystemOperationAborted error.
*/
abort(): Promise<void>;
/**
* Returns true if the operation was aborted.
*/
aborted: boolean;
}
interface FilesystemAdapter {
supportsVisibility(): boolean;
supportsDirectory(): boolean;
setVisibility?(path: string, visibility: FileVisibility): Promise<void>;
/**
* Closes the adapter (close connections, etc).
*/
close?(): Promise<void>;
/**
* Returns all files (and directories) directly in the given folder.
*/
files(path: string, reporter: Reporter): Promise<FilesystemFile[]>;
/**
* Returns all files (and directories) in the given folder and all sub folders.
*
* If the adapter does not support this, it will be emulated by calling files() recursively.
*/
allFiles?(path: string, reporter: Reporter): Promise<FilesystemFile[]>;
/**
* Returns all directories directly in the given folder.
*/
directories?(path: string, reporter: Reporter): Promise<FilesystemFile[]>;
/**
* Returns all directories in the given folder and all sub folders.
*
* If the adapter does not support this, it will be emulated by calling directories() recursively.
*/
allDirectories?(path: string, reporter: Reporter): Promise<FilesystemFile[]>;
/**
* Creates a new directory and all parent directories if not existing.
* Does nothing if the directory already exists.
*/
makeDirectory(path: string, visibility: FileVisibility): Promise<void>;
/**
* Returns the public URL for the given path.
*
* For local filesystem it's the configured base URL + the path.
* For adapters like S3 it's the public S3 URL to the file.
*/
publicUrl?(path: string): string;
/**
* Writes the given contents to the given path.
* Ensures that all parent directories exist.
*/
write(path: string, contents: Uint8Array, visibility: FileVisibility, reporter: Reporter): Promise<void>;
/**
* Appends the given contents to the given file.
*
* Optional. If not implemented, the file will be read into memory, content appended, and then written.
*/
append?(path: string, contents: Uint8Array, reporter: Reporter): Promise<void>;
/**
* Prepends the given contents to the given file.
*
* Optional. If not implemented, the file will be read into memory, content prepended, and then written.
*/
prepend?(path: string, contents: Uint8Array, reporter: Reporter): Promise<void>;
/**
* Reads the contents of the given path.
* @throws Error if the file does not exist.
*/
read(path: string, reporter: Reporter): Promise<Uint8Array>;
/**
* Returns the file at the given path or undefined if not existing.
*/
get(path: string): Promise<FilesystemFile | undefined>;
/**
* Returns true if all the given paths exist.
*/
exists(path: string[]): Promise<boolean>;
/**
* Deletes all the given paths.
* Throws an error if the file does not exist or the path is a directory.
*/
delete(path: string[]): Promise<void>;
/**
* Deletes the directory at the given path and all files and directories in it recursively.
* Does nothing if the directory does not exist.
*/
deleteDirectory(path: string, reporter: Reporter): Promise<void>;
/**
* Copies the file from source to destination.
* Ensures that all parent directories exist.
* If source is a directory, it copies the directory recursively.
*
* If the adapter does not support copying file and directories, do not implement it. The Filesystem class emulates it by doing it manually.
*
* If the adapter only supports copying a file, implement moveFile.
*/
copy?(source: string, destination: string, reporter: Reporter): Promise<void>;
copyFile?(source: string, destination: string): Promise<void>;
/**
* Moves the file from source to destination.
* Ensures that all parent directories exist.
* If source is a directory, it moves the directory recursively.
*
* If the adapter does not support moving files and directories, do not implement it. The Filesystem class emulates it by doing it manually. read, write, then delete.
*
* If the adapter only supports moving a file, implement moveFile.
*/
move?(source: string, destination: string, reporter: Reporter): Promise<void>;
moveFile?(source: string, destination: string): Promise<void>;
}
type Reporter = { progress: (loaded: number, total: number) => void, onAbort: () => Promise<void>, aborted: boolean };
type FilesystemPath = string | FilesystemFile | string[];
interface FilesystemOptions {
/**
* Default visibility for new files.
*/
visibility: FileVisibility;
/**
* Default visibility for new directories.
*/
directoryVisibility: FileVisibility;
/**
* Transforms a given path to a cleaned path (e.g. remove not allowed characters, remove whitespaces, etc).
* Per default replaces all not allowed characters [^a-zA-Z0-9\.\-\_\/]) with a dash.
*/
pathNormalizer: (path: string) => string;
baseUrl?: string;
/**
* Transforms a given path to a public URL.
*/
urlBuilder: (path: string) => string;
}
type NamedFilesystem<Name extends string> = Filesystem & Inject<`app.filesystem.${Name}`>;
interface FilesystemLocalAdapterOptions {
root: string;
permissions: {
file: {
public: number; //default 0o644
private: number; //default 0o600
},
directory: {
public: number; //default 0o755
private: number; //default 0o700
}
};
}
interface FilesystemMemoryAdapterOptions {
}