opfs-enhanced
v1.0.4
Published
Enhanced file system operations for browsers using OPFS (Origin Private File System)
Maintainers
Readme
OPFS Enhanced 🗄️
A modern TypeScript library for browser-based file system operations using OPFS (Origin Private File System)
✨ Features
- 🚀 Modern API: Built on the latest OPFS standard, providing powerful browser file system operations
- 📁 Complete Functionality: Supports file reading/writing, directory operations, file copying/moving, and more
- 🎯 TypeScript: Fully written in TypeScript with complete type support
- 🛡️ Error Handling: Comprehensive error handling with user-friendly error messages
- 🔧 Easy to Use: API designed similar to fs-extra, reducing learning curve
- ⚡ High Performance: Utilizes native browser OPFS API for excellent performance
- 🌐 Browser Compatible: Supports OPFS functionality in modern browsers
🚀 Quick Start
Installation
npm install opfs-enhancedBasic Usage
import { FileSystem } from 'opfs-enhanced';
// Write file
await FileSystem.writeFile('hello.txt', 'Hello, World!');
// Read file
const content = await FileSystem.readFile('hello.txt');
console.log(content); // 'Hello, World!'
// Create directory
await FileSystem.ensureDir('my-folder');
// List directory contents
const files = await FileSystem.readdir('my-folder');
// Copy file
await FileSystem.copy('hello.txt', 'my-folder/hello-copy.txt');
// Move file
await FileSystem.move('hello.txt', 'my-folder/hello.txt');
// JSON operations
const data = { name: 'File Vault', version: '1.0.0' };
await FileSystem.writeJson('package.json', data);
const json = await FileSystem.readJson('package.json');Demo Application
A complete file manager web application is included in the examples/ directory to demonstrate the library's capabilities. To run the demo:
npm install
npm run devThen open http://localhost:3000 to see the file manager in action.
🏗️ Project Structure
opfs-enhanced/
├── src/ # TypeScript source code
│ ├── index.ts # Main library entry point
│ ├── types.ts # Type definitions
│ ├── core/ # Core functionality
│ │ └── filesystem.ts # File system operations
│ └── utils/ # Utility functions
│ ├── errors.ts # Error handling
│ └── path.ts # Path utilities
├── examples/ # Demo applications
│ └── web/ # Web file manager demo
│ ├── styles/ # Demo CSS files
│ └── scripts/ # Demo JavaScript files
├── tests/ # Test files
├── doc/ # Documentation
├── index.html # Demo application entry point
├── package.json # Project configuration
├── tsconfig.json # TypeScript configuration
├── vite.config.ts # Vite build configuration
└── README.md # This file📚 API Documentation
File Operations
writeFile(path: string, data: string | ArrayBuffer | Uint8Array, options?: WriteOptions): Promise<void>
Write content to a file.
// Write text file
await FileSystem.writeFile('note.txt', 'This is a note');
// Write binary file
const buffer = new Uint8Array([72, 101, 108, 108, 111]);
await FileSystem.writeFile('data.bin', buffer);readFile(path: string, encoding?: string): Promise<string>
Read file content as string.
const content = await FileSystem.readFile('note.txt');readFileBuffer(path: string): Promise<ArrayBuffer>
Read file content as ArrayBuffer.
const buffer = await FileSystem.readFileBuffer('data.bin');exists(path: string): Promise<boolean>
Check if file or directory exists.
const fileExists = await FileSystem.exists('note.txt');stat(path: string): Promise<OPFSStats>
Get file or directory statistics.
const stats = await FileSystem.stat('note.txt');
console.log(stats.size, stats.lastModified, stats.kind);remove(path: string): Promise<void>
Delete file or directory.
await FileSystem.remove('note.txt');
await FileSystem.remove('my-folder'); // Recursively delete directoryDirectory Operations
mkdir(path: string, options?: EnsureOptions): Promise<void>
Create directory.
await FileSystem.mkdir('new-folder');
await FileSystem.mkdir('deep/nested/folder', { recursive: true });ensureDir(path: string): Promise<void>
Ensure directory exists, create if it doesn't.
await FileSystem.ensureDir('path/to/folder');readdir(path: string): Promise<string[]>
List directory contents.
const files = await FileSystem.readdir('my-folder');
console.log(files); // ['file1.txt', 'file2.txt', 'subfolder']File Copy and Move Operations
copy(src: string, dest: string, options?: CopyOptions): Promise<void>
Copy file or directory.
// Copy file
await FileSystem.copy('source.txt', 'destination.txt');
// Copy directory
await FileSystem.copy('source-folder', 'dest-folder');
// Copy with options
await FileSystem.copy('source.txt', 'dest.txt', {
overwrite: true,
filter: (src, dest) => !src.endsWith('.tmp')
});move(src: string, dest: string, options?: MoveOptions): Promise<void>
Move file or directory.
await FileSystem.move('old-name.txt', 'new-name.txt');
await FileSystem.move('folder', 'new-location/folder');JSON Operations
readJson(path: string, options?: ReadJsonOptions): Promise<any>
Read JSON file.
const data = await FileSystem.readJson('config.json');
// With options
const data = await FileSystem.readJson('config.json', {
throws: false, // Return null instead of throwing error when file doesn't exist
reviver: (key, value) => key === 'date' ? new Date(value) : value
});writeJson(path: string, data: any, options?: WriteJsonOptions): Promise<void>
Write JSON file.
const data = { name: 'example', values: [1, 2, 3] };
await FileSystem.writeJson('data.json', data);
// With options
await FileSystem.writeJson('data.json', data, {
spaces: 4, // Number of spaces for indentation
replacer: (key, value) => typeof value === 'bigint' ? value.toString() : value
});Directory Traversal
walk(path: string, options?: WalkOptions): AsyncGenerator<FileInfo>
Recursively traverse directory.
// Traverse all files
for await (const file of FileSystem.walk('my-folder')) {
console.log(file.path, file.kind, file.size);
}
// Traverse with options
for await (const item of FileSystem.walk('my-folder', {
includeDirs: true, // Include directories
maxDepth: 2, // Maximum depth
filter: (path, info) => info.kind === 'file' && path.endsWith('.txt')
})) {
console.log(item.path);
}🔧 Advanced Usage
Error Handling
import { FileSystemError, FileSystemErrorCode } from 'opfs-enhanced';
try {
await FileSystem.readFile('non-existent.txt');
} catch (error) {
if (error instanceof FileSystemError) {
switch (error.code) {
case FileSystemErrorCode.FILE_NOT_FOUND:
console.log('File not found');
break;
case FileSystemErrorCode.PERMISSION_DENIED:
console.log('Permission denied');
break;
default:
console.log('Other error:', error.message);
}
}
}Path Operations
import { dirname, basename, extname, joinPath } from 'opfs-enhanced';
const filePath = 'documents/projects/readme.md';
console.log(dirname(filePath)); // 'documents/projects'
console.log(basename(filePath)); // 'readme.md'
console.log(extname(filePath)); // '.md'
const newPath = joinPath('assets', 'images', 'logo.png');
console.log(newPath); // 'assets/images/logo.png'🎯 Use Cases
1. Local Data Storage
// Save user settings
const userSettings = {
theme: 'dark',
language: 'en-US',
autoSave: true
};
await FileSystem.writeJson('settings.json', userSettings);
// Read user settings
const settings = await FileSystem.readJson('settings.json');2. File Editor
// Save document
await FileSystem.writeFile('documents/my-doc.md', documentContent);
// Create project structure
await FileSystem.ensureDir('project/src');
await FileSystem.ensureDir('project/assets');
await FileSystem.writeFile('project/README.md', '# My Project');3. Cache Management
// Cache data
const cacheData = { data: results, timestamp: Date.now() };
await FileSystem.writeJson('cache/api-results.json', cacheData);
// Clean expired cache
for await (const file of FileSystem.walk('cache')) {
const stats = await FileSystem.stat(file.path);
if (Date.now() - stats.lastModified > 24 * 60 * 60 * 1000) {
await FileSystem.remove(file.path);
}
}4. Backup Tool
// Create backup
const backupFolder = `backup-${new Date().toISOString().split('T')[0]}`;
await FileSystem.ensureDir(backupFolder);
await FileSystem.copy('important-data', `${backupFolder}/important-data`);🌐 Browser Support
| Browser | Version | Support | |---------|---------|---------| | Chrome | 86+ | ✅ Full | | Firefox | 111+ | ✅ Full | | Safari | 15.2+ | ✅ Full | | Edge | 86+ | ✅ Full |
Note: OPFS requires a secure context (HTTPS or localhost)
🚧 Limitations
- Browser Support: Requires modern browsers with OPFS support
- Secure Context: Must be used in HTTPS or localhost environment
- Storage Space: Limited by browser storage quota
- Cross-Domain: Data is stored per domain, cannot be accessed across domains
🧪 Development Guide
Project Setup
# Clone project
git clone <repository-url>
cd opfs-enhanced
# Install dependencies
npm install
# Development
npm run dev
# Build
npm run build
# Test
npm test
# Run demo
npm run previewContributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Testing
# Run all tests
npm test
# Run tests in watch mode
npm run test:watch
# Run tests with coverage
npm run test:coverage📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🙏 Acknowledgments
- OPFS API - For providing browser file system access
- TypeScript - For excellent type safety
- Vite - For fast development and building
- Biome - For code formatting and linting
- fs-extra - For API inspiration
🤝 Support
If you have any questions or need help, please:
- Check the documentation
- Search existing issues
- Create a new issue
Made with ❤️ by the File Vault team
