A browser-compatible file system module based on OPFS, inspired by Deno fs APIs. Supports async/sync operations, streaming zip/unzip, and Result-based error handling.
npm install happy-opfs






A browser file system module based on OPFS, providing Deno-style APIs.
---
---
The standard OPFS API differs significantly from familiar path-based file system APIs like Node.js and Deno. This library bridges that gap by providing Deno-style APIs in the browser.
All async APIs return Result types (similar to Rust) for better error handling.
``sh`
pnpm add happy-opfsor
npm install happy-opfsor
yarn add happy-opfsor via JSR
jsr add @happy-js/happy-opfs
> [!NOTE]
> This package depends on @std/path from JSR. Add this to your .npmrc:`
> `
> @jsr:registry=https://npm.jsr.io
>
| Category | APIs |
|----------|------|
| Core | createFile, mkdir, readDir, readFile, writeFile, remove, stat |appendFile
| Extended | , copy, move, exists, emptyDir, readTextFile, readBlobFile, readJsonFile, writeJsonFile |readFile
| Stream | with { encoding: 'stream' }, openWritableFileStream |mkTemp
| Temp | , generateTempPath, pruneTemp, deleteTemp |zip
| Zip | , unzip, zipFromUrl, unzipFromUrl |downloadFile
| Network | , uploadFile |mkdirSync
| Sync | All core operations have sync versions (e.g., , readFileSync) via Web Workers. Use SyncChannel.connect, SyncChannel.listen, SyncChannel.attach, SyncChannel.isReady for setup |
Run examples locally:
`sh`
pnpm run egOpen https://localhost:5173
`ts
import { mkdir, writeFile, readTextFile, remove } from 'happy-opfs';
// Write and read files
await mkdir('/data');
await writeFile('/data/hello.txt', 'Hello, OPFS!');
(await readTextFile('/data/hello.txt')).inspect((content) => {
console.log(content); // 'Hello, OPFS!'
});
await remove('/data');
`
See more examples in the examples/ directory:
- Basic Usage - File CRUD operations
- Download & Upload - Network operations with progress
- Zip Operations - Compress and extract files
- Stream Operations - Read and write files using streams
- Sync API - Synchronous operations via Worker
- Shared Messenger - Share sync messenger between contexts
| Browser | Version |
|---------|---------|
| Chrome | 86+ |
| Edge | 86+ |
| Firefox | 111+ |
| Safari | 15.2+ |
For detailed compatibility, see MDN - OPFS.
You can install OPFS Explorer to visually inspect the file system.
In 1.x, readFile returned ArrayBuffer by default. In 2.x, it returns Uint8Array.
`ts
// 1.x - default returned ArrayBuffer
const result = await readFile('/path/to/file');
// 2.x - default returns Uint8Array
const result = await readFile('/path/to/file');
// Migration: use .buffer property to get ArrayBuffer if needed
const uint8Array = await readFile('/path/to/file');
const arrayBuffer = uint8Array.unwrap().buffer;
`
These deprecated APIs have been removed. Use the new alternatives:
`ts
// 1.x
const stream = await readFileStream('/path/to/file');
const writable = await writeFileStream('/path/to/file');
// 2.x
const stream = await readFile('/path/to/file', { encoding: 'stream' });
const writable = await openWritableFileStream('/path/to/file');
`
Coverage is collected using V8 provider in real browser environment.
- src/sync/channel/listen.ts is excluded because it runs in Web Worker context where V8 cannot instrumentsrc/async/core/*.ts
- has branches running in Worker context (via createSyncAccessHandle`), tested through mock tests