# @push.rocks/smartfs Modern, pluggable filesystem module with fluent API, Web Streams support, and multiple storage backends. ## Issue Reporting and Security For reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who want to sign a contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly. ## Features - **🎯 Fluent API** - Action-last chainable interface for elegant code - **🔌 Pluggable Providers** - Support for multiple storage backends (Node.js fs, memory, S3, etc.) - **🌊 Web Streams** - Modern streaming with Web Streams API - **💾 Transactions** - Atomic multi-file operations with automatic rollback - **👀 File Watching** - Event-based file system monitoring - **⚡ Async-Only** - Modern async/await patterns throughout - **📦 Zero Dependencies** - Core functionality with minimal dependencies - **🎨 TypeScript** - Full type safety and IntelliSense support ## Installation ```bash pnpm install @push.rocks/smartfs ``` ## Quick Start ```typescript import { SmartFs, SmartFsProviderNode } from '@push.rocks/smartfs'; // Create a SmartFS instance with Node.js provider const fs = new SmartFs(new SmartFsProviderNode()); // Write and read files with fluent API await fs.file('/path/to/file.txt') .encoding('utf8') .write('Hello, World!'); const content = await fs.file('/path/to/file.txt') .encoding('utf8') .read(); console.log(content); // "Hello, World!" ``` ## API Overview ### File Operations The fluent API uses **action-last pattern** - configure first, then execute: ```typescript // Read file const content = await fs.file('/path/to/file.txt') .encoding('utf8') .read(); // Write file await fs.file('/path/to/file.txt') .encoding('utf8') .mode(0o644) .write('content'); // Atomic write (write to temp, then rename) await fs.file('/path/to/file.txt') .atomic() .write('content'); // Append to file await fs.file('/path/to/file.txt') .encoding('utf8') .append('more content'); // Copy file await fs.file('/source.txt') .preserveTimestamps() .copy('/destination.txt'); // Move file await fs.file('/old.txt') .move('/new.txt'); // Delete file await fs.file('/path/to/file.txt') .delete(); // Check existence const exists = await fs.file('/path/to/file.txt').exists(); // Get stats const stats = await fs.file('/path/to/file.txt').stat(); ``` ### Directory Operations ```typescript // Create directory await fs.directory('/path/to/dir').create(); // Create nested directories await fs.directory('/path/to/nested/dir') .recursive() .create(); // List directory const entries = await fs.directory('/path/to/dir').list(); // List recursively with filter const tsFiles = await fs.directory('/path/to/dir') .recursive() .filter('*.ts') .includeStats() .list(); // Filter with RegExp const files = await fs.directory('/path/to/dir') .filter(/\.txt$/) .list(); // Filter with function const largeFiles = await fs.directory('/path/to/dir') .includeStats() .filter(entry => entry.stats && entry.stats.size > 1024) .list(); // Delete directory await fs.directory('/path/to/dir') .recursive() .delete(); // Check existence const exists = await fs.directory('/path/to/dir').exists(); ``` ### Streaming Operations SmartFS uses **Web Streams API** for efficient handling of large files: ```typescript // Read stream const readStream = await fs.file('/large-file.bin') .chunkSize(64 * 1024) .readStream(); const reader = readStream.getReader(); while (true) { const { done, value } = await reader.read(); if (done) break; // Process chunk (Uint8Array) console.log('Chunk size:', value.length); } // Write stream const writeStream = await fs.file('/output.bin').writeStream(); const writer = writeStream.getWriter(); await writer.write(new Uint8Array([1, 2, 3])); await writer.write(new Uint8Array([4, 5, 6])); await writer.close(); // Pipe streams const input = await fs.file('/input.txt').readStream(); const output = await fs.file('/output.txt').writeStream(); await input.pipeTo(output); ``` ### Transactions Execute multiple file operations atomically with automatic rollback on failure: ```typescript // Simple transaction await fs.transaction() .file('/file1.txt').write('content 1') .file('/file2.txt').write('content 2') .file('/file3.txt').delete() .commit(); // Transaction with error handling const tx = fs.transaction() .file('/important.txt').write('critical data') .file('/backup.txt').copy('/backup-old.txt') .file('/temp.txt').delete(); try { await tx.commit(); console.log('Transaction completed successfully'); } catch (error) { console.error('Transaction failed and was rolled back:', error); // All operations are automatically reverted } ``` ### File Watching Monitor filesystem changes with event-based watching: ```typescript // Watch a single file const watcher = await fs.watch('/path/to/file.txt') .onChange(event => { console.log('File changed:', event.path); }) .start(); // Watch directory recursively const dirWatcher = await fs.watch('/path/to/dir') .recursive() .filter('*.ts') .debounce(100) .onChange(event => console.log('Changed:', event.path)) .onAdd(event => console.log('Added:', event.path)) .onDelete(event => console.log('Deleted:', event.path)) .start(); // Stop watching await dirWatcher.stop(); // Watch with custom filter const customWatcher = await fs.watch('/path/to/dir') .recursive() .filter(path => path.endsWith('.ts') && !path.includes('test')) .onAll(event => { console.log(`${event.type}: ${event.path}`); }) .start(); ``` ## Providers SmartFS supports multiple storage backends through providers: ### Node.js Provider Uses Node.js `fs/promises` API for local filesystem operations: ```typescript import { SmartFs, SmartFsProviderNode } from '@push.rocks/smartfs'; const fs = new SmartFs(new SmartFsProviderNode()); ``` **Capabilities:** - ✅ File watching - ✅ Atomic writes - ✅ Transactions - ✅ Streaming - ✅ Symbolic links - ✅ File permissions ### Memory Provider In-memory virtual filesystem, perfect for testing: ```typescript import { SmartFs, SmartFsProviderMemory } from '@push.rocks/smartfs'; const fs = new SmartFs(new SmartFsProviderMemory()); // All operations work in memory await fs.file('/virtual/file.txt').write('data'); const content = await fs.file('/virtual/file.txt').read(); // Clear all data fs.provider.clear(); ``` **Capabilities:** - ✅ File watching - ✅ Atomic writes - ✅ Transactions - ✅ Streaming - ❌ Symbolic links - ✅ File permissions ### Custom Providers Create your own provider by implementing `ISmartFsProvider`: ```typescript import type { ISmartFsProvider } from '@push.rocks/smartfs'; class MyCustomProvider implements ISmartFsProvider { public readonly name = 'custom'; public readonly capabilities = { supportsWatch: true, supportsAtomic: true, supportsTransactions: true, supportsStreaming: true, supportsSymlinks: false, supportsPermissions: true, }; // Implement all required methods... async readFile(path: string, options?) { /* ... */ } async writeFile(path: string, content, options?) { /* ... */ } // ... etc } const fs = new SmartFs(new MyCustomProvider()); ``` ## Advanced Usage ### Encoding Options ```typescript // UTF-8 (default for text) await fs.file('/file.txt').encoding('utf8').write('text'); // Binary const buffer = Buffer.from([0x48, 0x65, 0x6c, 0x6c, 0x6f]); await fs.file('/file.bin').write(buffer); // Base64 await fs.file('/file.txt').encoding('base64').write('SGVsbG8='); // Hex await fs.file('/file.txt').encoding('hex').write('48656c6c6f'); ``` ### File Permissions ```typescript // Set file mode await fs.file('/script.sh') .mode(0o755) .write('#!/bin/bash\necho "Hello"'); // Set directory mode await fs.directory('/private') .mode(0o700) .create(); ``` ### Complex Filtering ```typescript // Multiple conditions const files = await fs.directory('/src') .recursive() .includeStats() .filter(entry => { if (!entry.stats) return false; return entry.isFile && entry.name.endsWith('.ts') && entry.stats.size > 1024 && entry.stats.mtime > new Date('2024-01-01'); }) .list(); ``` ### Transaction Operations ```typescript // Complex transaction const tx = fs.transaction(); // Write multiple files tx.file('/data/file1.json').write(JSON.stringify(data1)); tx.file('/data/file2.json').write(JSON.stringify(data2)); // Copy backups tx.file('/data/file1.json').copy('/backup/file1.json'); tx.file('/data/file2.json').copy('/backup/file2.json'); // Delete old files tx.file('/data/old1.json').delete(); tx.file('/data/old2.json').delete(); // Execute atomically await tx.commit(); ``` ## Type Definitions SmartFS is fully typed with TypeScript: ```typescript import type { IFileStats, IDirectoryEntry, IWatchEvent, ITransactionOperation, TEncoding, TFileMode, } from '@push.rocks/smartfs'; ``` ## Testing ```bash # Run all tests pnpm test # Run specific test pnpm tstest test/test.memory.provider.ts --verbose # Run with log output pnpm tstest test/test.node.provider.ts --logfile .nogit/testlogs/test.log ``` ## Error Handling SmartFS throws descriptive errors: ```typescript try { await fs.file('/nonexistent.txt').read(); } catch (error) { console.error(error.message); // "ENOENT: no such file or directory, open '/nonexistent.txt'" } // Transactions automatically rollback on error try { await fs.transaction() .file('/file1.txt').write('data') .file('/file2.txt').write('data') .commit(); } catch (error) { // All operations are reverted console.error('Transaction failed:', error); } ``` ## Performance Tips 1. **Use streaming** for large files (> 1MB) 2. **Batch operations** with transactions 3. **Use memory provider** for testing 4. **Enable atomic writes** for critical data 5. **Debounce watchers** to reduce event spam ## License and Legal Information This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. **Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file. ### Trademarks This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH. ### Company Information Task Venture Capital GmbH Registered at District court Bremen HRB 35230 HB, Germany For any legal inquiries or if you require further information, please contact us via email at hello@task.vc. By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.