@venturialstd/file-system
v0.0.2
Published
Provider-agnostic file system module (Backblaze, extensible to AWS S3) with file/folder tree persistence
Keywords
Readme
@venturialstd/file-system
Provider-agnostic file storage and tree API for Venturial backends. Ships with Backblaze B2; designed so additional providers (e.g. AWS S3) can be added without changing consumer code.
Table of contents
Features
- Unified API — Upload, download, delete, list, exists/head; optional signed URLs
- File and folder model — TypeORM entities with parent-child relationships; tree stored in your DB
- Tree operations — Create/read folders and files; get full tree or subtree; list children
- Settings-driven — Provider and bucket come from Settings; credentials come from the Backblaze package only
- Domain errors — Provider errors mapped to
FileSystemNotFoundError,FileSystemPermissionDeniedError,FileSystemRateLimitError,FileSystemNotSupportedError - Permanent delete — Backblaze: delete uses
exists→versionIdfor permanent deletion when supported
Installation
npm (standalone):
npm install @venturialstd/file-system @venturialstd/backblaze @venturialstd/coreMonorepo — in your app’s package.json:
{
"dependencies": {
"@venturialstd/file-system": "file:src/file-system",
"@venturialstd/backblaze": "file:src/backblaze",
"@venturialstd/core": "^2.0.0"
}
}Configuration
All file-system runtime config is read from Settings (no arguments to FileSystemModule.forRoot()).
| Purpose | Setting key | Scope / section | Example |
|----------------|-------------------------------------|----------------------|-----------|
| Provider | FILE_SYSTEM_SETTING_KEYS.GENERAL_PROVIDER | FILE-SYSTEM / GENERAL / PROVIDER | backblaze |
| Bucket name | FILE_SYSTEM_SETTING_KEYS.BACKBLAZE_BUCKET_NAME | FILE-SYSTEM / BACKBLAZE / BUCKET_NAME | my-bucket |
- The package exports
FILE_SYSTEM_SETTINGS(andSETTINGS) so@venturialstd/corecan discover and register these keys. - Credentials and region are not configured in file-system; they are taken only from the Backblaze package configuration.
Quick start
1. Register entities and module
Ensure TypeORM loads the file-system entities (e.g. via SharedModule or your entity glob). Then import the module:
import { FileSystemModule } from '@venturialstd/file-system';
@Module({
imports: [
// ... TypeORM with FileSystemFile, FileSystemFolder
FileSystemModule.forRoot(),
],
})
export class AppModule {}2. Configure Settings
Create or seed settings for the keys above (provider and bucket). If you use a settings admin UI, add entries for FILE-SYSTEM / GENERAL / PROVIDER and FILE-SYSTEM / BACKBLAZE / BUCKET_NAME.
3. Use the service
import { FileSystemService } from '@venturialstd/file-system';
@Injectable()
export class MyService {
constructor(private readonly fileSystem: FileSystemService) {}
async example() {
// Blob
await this.fileSystem.upload('path/file.pdf', buffer, { contentType: 'application/pdf' });
const data = await this.fileSystem.download('path/file.pdf');
const meta = await this.fileSystem.exists('path/file.pdf');
const list = await this.fileSystem.list('path/', { maxKeys: 100 });
// Tree
const root = await this.fileSystem.createFolder('Documents', null);
const sub = await this.fileSystem.createFolder('Projects', root.id);
const file = await this.fileSystem.uploadAndCreateFile(sub.id, 'readme.txt', Buffer.from('Hello'));
const tree = await this.fileSystem.getTree();
const children = await this.fileSystem.getChildren(sub.id);
}
}API
FileSystemService (main entry)
| Method | Description |
|--------|-------------|
| upload(key, body, options?) | Upload buffer/string to key |
| download(key) | Download as ArrayBuffer |
| deleteObject(key, options?) | Delete object; options.versionId for permanent delete (Backblaze) |
| list(prefix, options?) | List objects with pagination |
| exists(key) | Head object; returns metadata (includes versionId when available) |
| createFolder(name, parentId) | Create folder; parentId === null for root |
| getFolder(id), getFile(id) | Load folder or file entity |
| getChildren(folderId) | Direct children (folders + files); folderId === null for root |
| getTree(rootFolderId?) | Full tree or subtree |
| uploadAndCreateFile(folderId, fileName, body, options?) | Upload blob and create file record in tree |
| deleteFile(id), deleteFolder(id) | Delete file/folder and blob(s); uses exists + versionId for Backblaze |
Provider contract (IFileSystemProvider)
Implement this interface to add a new storage backend:
| Method | Required | Description |
|--------|----------|-------------|
| upload(key, body, options?) | ✓ | Upload to key |
| download(key) | ✓ | Return ArrayBuffer |
| delete(key, options?) | ✓ | Delete object; options.versionId for permanent delete |
| list(prefix, options?) | ✓ | List with pagination |
| exists(key) | ✓ | Head; return metadata (e.g. versionId) |
| deleteMany(keys?) | optional | Bulk delete |
| getSignedDownloadUrl(key, expiresInSeconds?) | optional | Throw FileSystemNotSupportedError if unsupported |
| getSignedUploadUrl(key, contentType?, expiresInSeconds?) | optional | Same |
File and folder model
- Entities:
FileSystemFile,FileSystemFolder(TypeORM). Folders use a closure-table tree; files have optionalfolderId. - Tree: Stored in your database; create/update/delete via the service keep it in sync.
- Delete: For Backblaze,
deleteFile/deleteFoldercallexiststo getversionId, thendeletewith that id for permanent deletion.
Adding a provider
- Implement
IFileSystemProviderin a new class (e.g.S3FileSystemProvider). - In
FileSystemModule.forRoot(), support the new provider in config (e.g. Settings or options) and register the provider (factory + token). - No changes in code that uses
FileSystemService; only configuration switches the provider.
License
MIT
