aab_node_storage_local_fs
v1.0.1
Published
Local file system storage provider implementation for AppSolve Application Blocks Storage Core. Provides a unified interface for local file operations with configurable base path using AAB_STORAGE_LOCAL_FS_PATH environment variable.
Downloads
14
Maintainers
Readme
AppSolve Application Blocks - Storage Local File System
Local file system storage provider implementation for AppSolve Application Blocks Storage Core. This package provides a unified interface for local file system operations through the StorageProvider interface, enabling seamless local file management with security, reliability, and ease of use.
Features
- Secure: Built-in path validation prevents directory traversal attacks
- Automatic Directory Creation: Creates parent directories automatically when storing files
- Binary Support: Full support for binary files through Buffer-based operations
- Configurable: Uses environment variables for flexible configuration
- Well Tested: Comprehensive test suite with 100% coverage
- TypeScript First: Written in TypeScript with full type definitions
- Promise-based: Modern async/await API
- Recursive Operations: Supports recursive directory listing and deletion
Installation
npm install aab_node_storage_local_fsQuick Start
import { LocalFileSystemStorageProvider } from 'aab_node_storage_local_fs';
// Create provider with default configuration
const provider = new LocalFileSystemStorageProvider();
// Store a text file
await provider.put('documents/hello.txt', Buffer.from('Hello, World!', 'utf8'));
// Retrieve the file
const content = await provider.get('documents/hello.txt');
console.log(content.toString('utf8')); // 'Hello, World!'
// List directory contents
const files = await provider.list('documents');
console.log(files); // ['hello.txt']
// Delete the file
await provider.delete('documents/hello.txt');Configuration
The storage provider uses the AAB_STORAGE_LOCAL_FS_PATH environment variable to determine the base storage directory. If not set, it defaults to ./storage in the current working directory.
Environment Variable
export AAB_STORAGE_LOCAL_FS_PATH="/path/to/storage"Programmatic Configuration
// Use custom base path
const provider = new LocalFileSystemStorageProvider('/custom/storage/path');
// Get the configured base path
console.log(provider.getBasePath()); // '/custom/storage/path'API Reference
Constructor
new LocalFileSystemStorageProvider(basePath?: string)Creates a new storage provider instance.
basePath(optional): Custom base path for storage. If not provided, usesAAB_STORAGE_LOCAL_FS_PATHenvironment variable or defaults to./storage
Methods
getBasePath(): string
Returns the absolute base path used for storage operations.
put(path: string, data: Buffer): Promise<void>
Stores data at the specified path. Creates parent directories automatically if they don't exist.
// Store text file
await provider.put('documents/readme.txt', Buffer.from('Content', 'utf8'));
// Store binary file
const imageData = await fs.readFile('image.jpg');
await provider.put('images/photo.jpg', imageData);
// Store JSON data
const jsonData = JSON.stringify({ key: 'value' });
await provider.put('data/config.json', Buffer.from(jsonData, 'utf8'));get(path: string): Promise<Buffer>
Retrieves file contents as a Buffer.
// Get text file
const textBuffer = await provider.get('documents/readme.txt');
const text = textBuffer.toString('utf8');
// Get binary file
const imageBuffer = await provider.get('images/photo.jpg');
// Get and parse JSON
const jsonBuffer = await provider.get('data/config.json');
const data = JSON.parse(jsonBuffer.toString('utf8'));list(path: string): Promise<string[]>
Lists files and directories at the specified path. Returns entries sorted alphabetically.
// List root directory
const rootFiles = await provider.list('');
// List subdirectory
const documents = await provider.list('documents');
// List nested directory
const images = await provider.list('assets/images');delete(path: string): Promise<void>
Deletes a file or directory. Directories are deleted recursively with all their contents.
// Delete a file
await provider.delete('documents/old-file.txt');
// Delete a directory and all contents
await provider.delete('temporary-folder');Error Handling
The provider throws descriptive errors for various scenarios:
try {
await provider.get('nonexistent.txt');
} catch (error) {
console.log(error.message); // 'File does not exist: nonexistent.txt'
}
try {
await provider.put('../../../etc/passwd', Buffer.from('malicious'));
} catch (error) {
console.log(error.message); // 'Invalid path: attempts to escape base directory'
}Common error scenarios:
- Path validation errors: When paths attempt to escape the base directory
- File not found: When trying to get or delete non-existent files
- Type mismatch: When trying to get a directory as a file or list a file as a directory
- Permission errors: When the process lacks necessary file system permissions
Security
Path Validation
The provider includes robust path validation to prevent directory traversal attacks:
// These paths will throw security errors:
// '../../../etc/passwd'
// 'folder/../../../sensitive'
// '..\\windows\\system32'
// These paths are safe:
// 'documents/file.txt'
// 'assets/images/photo.jpg'
// 'data/config.json'File System Permissions
Ensure your application has appropriate permissions to read/write in the configured storage directory.
Examples
Basic File Operations
import { LocalFileSystemStorageProvider } from 'aab_node_storage_local_fs';
const provider = new LocalFileSystemStorageProvider();
// Create a text file
await provider.put('notes/todo.txt', Buffer.from(`
TODO List:
- Implement storage provider ✓
- Write documentation ✓
- Add tests ✓
`, 'utf8'));
// Read and display the file
const todoContent = await provider.get('notes/todo.txt');
console.log(todoContent.toString('utf8'));
// List all notes
const notes = await provider.list('notes');
console.log('Available notes:', notes);Working with Binary Files
import { promises as fs } from 'fs';
// Upload an image
const imageData = await fs.readFile('local-image.jpg');
await provider.put('uploads/user-avatar.jpg', imageData);
// Download the image
const downloadedImage = await provider.get('uploads/user-avatar.jpg');
await fs.writeFile('downloaded-avatar.jpg', downloadedImage);Organizing Files in Directories
// Create organized file structure
await provider.put('projects/website/src/index.html', Buffer.from('<html>...</html>'));
await provider.put('projects/website/src/styles.css', Buffer.from('body { ... }'));
await provider.put('projects/website/assets/logo.png', logoBuffer);
// List project structure
const projects = await provider.list('projects');
console.log('Projects:', projects); // ['website']
const websiteFiles = await provider.list('projects/website');
console.log('Website files:', websiteFiles); // ['assets', 'src']
const srcFiles = await provider.list('projects/website/src');
console.log('Source files:', srcFiles); // ['index.html', 'styles.css']Configuration Management
// Store configuration
const config = {
database: {
host: 'localhost',
port: 5432,
name: 'myapp'
},
features: {
enableCache: true,
maxUsers: 1000
}
};
await provider.put('config/app.json', Buffer.from(JSON.stringify(config, null, 2)));
// Load configuration
const configBuffer = await provider.get('config/app.json');
const loadedConfig = JSON.parse(configBuffer.toString('utf8'));
console.log('Loaded config:', loadedConfig);Backup and Cleanup
// Create backup of important files
const importantFiles = await provider.list('documents/important');
for (const file of importantFiles) {
const content = await provider.get(`documents/important/${file}`);
await provider.put(`backups/${new Date().toISOString().split('T')[0]}/${file}`, content);
}
// Clean up old temporary files
const tempFiles = await provider.list('temp');
for (const file of tempFiles) {
await provider.delete(`temp/${file}`);
}Development
Prerequisites
- Node.js 16 or higher
- npm or yarn
Setup
# Clone the repository
git clone https://github.com/cmeegamarachchi/aab_node_storage_local_fs.git
cd aab_node_storage_local_fs
# Install dependencies
npm install
# Build the project
npm run build
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Lint code
npm run lint
# Format code
npm run formatTesting
The project includes comprehensive tests covering all functionality:
# Run all tests
npm test
# Run tests in watch mode
npm run test:watch
# Generate coverage report
npm run test:coverageBuilding
# Clean previous build
npm run clean
# Build TypeScript to JavaScript
npm run build
# Prepare for publishing (clean + build)
npm run prepublishOnlyContributing
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Make your changes
- Add tests for your changes
- Ensure all tests pass:
npm test - Commit your changes:
git commit -m 'Add amazing feature' - Push to the branch:
git push origin feature/amazing-feature - Open a Pull Request
Code Style
This project uses:
- Prettier for code formatting (120 character line width)
- ESLint for code linting
- TypeScript for type safety
Code is automatically formatted on save in VS Code with the provided configuration.
Publishing to npm
To publish this package to npm:
Prerequisites
- Create an npm account at npmjs.com
- Login to npm:
npm login - Verify login:
npm whoami
Publishing Steps
# Update version (patch/minor/major)
npm version patch # for bug fixes
npm version minor # for new features
npm version major # for breaking changes
# Build and publish
npm publishScoped Publishing (Optional)
To publish under an organization scope:
# Update package.json name to: "@your-org/aab_node_storage_local_fs"
npm publish --access publicChangelog
[1.0.0] - 2024-08-04
Added
- Initial release
LocalFileSystemStorageProviderclass implementingStorageProviderinterface- Support for all storage operations:
put,get,list,delete - Path validation security features
- Automatic directory creation
- Environment variable configuration
- Comprehensive test suite
- TypeScript support with full type definitions
- Documentation and examples
License
ISC License - see the LICENSE file for details.
Support
- Issues: GitHub Issues
- Documentation: This README and inline code documentation
- Core Package: aab_node_storage_core
Related Packages
- aab_node_storage_core: Core interfaces and types for storage providers
Author
Chintana Meegamarachchi
Made with care for the AppSolve Application Blocks ecosystem
