opfs-worker 1.3.2 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +64 -458
- package/dist/BaseOPFS-BPw9AIQ-.cjs +4 -0
- package/dist/BaseOPFS-BPw9AIQ-.cjs.map +1 -0
- package/dist/BaseOPFS-Cylz6ijk.js +2036 -0
- package/dist/BaseOPFS-Cylz6ijk.js.map +1 -0
- package/dist/OPFSAsync-BKSAJJeh.js +124 -0
- package/dist/OPFSAsync-BKSAJJeh.js.map +1 -0
- package/dist/OPFSAsync-s2P7y3sw.cjs +2 -0
- package/dist/OPFSAsync-s2P7y3sw.cjs.map +1 -0
- package/dist/OPFSFacade-DePnNRgt.cjs +2 -0
- package/dist/OPFSFacade-DePnNRgt.cjs.map +1 -0
- package/dist/OPFSFacade-XohWlHuu.js +281 -0
- package/dist/OPFSFacade-XohWlHuu.js.map +1 -0
- package/dist/OPFSSync-C7KBepe_.cjs +2 -0
- package/dist/OPFSSync-C7KBepe_.cjs.map +1 -0
- package/dist/OPFSSync-CsSQkpk5.js +208 -0
- package/dist/OPFSSync-CsSQkpk5.js.map +1 -0
- package/dist/assets/dedicated.worker-nY3tK4zi.js.map +1 -0
- package/dist/{worker.d.ts → core/BaseOPFS.d.ts} +34 -300
- package/dist/core/BaseOPFS.d.ts.map +1 -0
- package/dist/core/OPFSAsync.d.ts +55 -0
- package/dist/core/OPFSAsync.d.ts.map +1 -0
- package/dist/core/OPFSSync.d.ts +54 -0
- package/dist/core/OPFSSync.d.ts.map +1 -0
- package/dist/createOPFSAsync-BwKDmHsy.cjs +2 -0
- package/dist/createOPFSAsync-BwKDmHsy.cjs.map +1 -0
- package/dist/createOPFSAsync-Y4Mg6qte.js +10 -0
- package/dist/createOPFSAsync-Y4Mg6qte.js.map +1 -0
- package/dist/createOPFSDedicated-CsnV6MLP.js +2333 -0
- package/dist/createOPFSDedicated-CsnV6MLP.js.map +1 -0
- package/dist/createOPFSDedicated-pKTRWLdz.cjs +2283 -0
- package/dist/createOPFSDedicated-pKTRWLdz.cjs.map +1 -0
- package/dist/createOPFSShared-CGdd__PH.js +23 -0
- package/dist/createOPFSShared-CGdd__PH.js.map +1 -0
- package/dist/createOPFSShared-CskROt7U.cjs +2 -0
- package/dist/createOPFSShared-CskROt7U.cjs.map +1 -0
- package/dist/dedicated.worker.js +2281 -0
- package/dist/dedicated.worker.js.map +1 -0
- package/dist/{facade.d.ts → facade/OPFSFacade.d.ts} +35 -10
- package/dist/facade/OPFSFacade.d.ts.map +1 -0
- package/dist/facade/createOPFSAsync.d.ts +16 -0
- package/dist/facade/createOPFSAsync.d.ts.map +1 -0
- package/dist/facade/createOPFSDedicated.d.ts +17 -0
- package/dist/facade/createOPFSDedicated.d.ts.map +1 -0
- package/dist/facade/createOPFSShared.d.ts +24 -0
- package/dist/facade/createOPFSShared.d.ts.map +1 -0
- package/dist/index.async.cjs +2 -0
- package/dist/index.async.cjs.map +1 -0
- package/dist/index.async.d.ts +10 -0
- package/dist/index.async.d.ts.map +1 -0
- package/dist/index.async.js +55 -0
- package/dist/index.async.js.map +1 -0
- package/dist/index.cjs +1 -2466
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +15 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +61 -2799
- package/dist/index.js.map +1 -1
- package/dist/index.pure.cjs +2 -0
- package/dist/index.pure.cjs.map +1 -0
- package/dist/index.pure.d.ts +8 -0
- package/dist/index.pure.d.ts.map +1 -0
- package/dist/index.pure.js +53 -0
- package/dist/index.pure.js.map +1 -0
- package/dist/index.sharedworker.cjs +2 -0
- package/dist/index.sharedworker.cjs.map +1 -0
- package/dist/index.sharedworker.d.ts +11 -0
- package/dist/index.sharedworker.d.ts.map +1 -0
- package/dist/index.sharedworker.js +55 -0
- package/dist/index.sharedworker.js.map +1 -0
- package/dist/index.sync.cjs +2 -0
- package/dist/index.sync.cjs.map +1 -0
- package/dist/index.sync.d.ts +11 -0
- package/dist/index.sync.d.ts.map +1 -0
- package/dist/index.sync.js +55 -0
- package/dist/index.sync.js.map +1 -0
- package/dist/shared.worker.js +2166 -0
- package/dist/shared.worker.js.map +1 -0
- package/dist/types.d.ts +9 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/helpers.d.ts +11 -1
- package/dist/utils/helpers.d.ts.map +1 -1
- package/dist/worker/createDedicatedWorker.d.ts +30 -0
- package/dist/worker/createDedicatedWorker.d.ts.map +1 -0
- package/dist/worker/createSharedWorker.d.ts +37 -0
- package/dist/worker/createSharedWorker.d.ts.map +1 -0
- package/dist/worker/dedicated.worker.d.ts +2 -0
- package/dist/worker/dedicated.worker.d.ts.map +1 -0
- package/dist/worker/shared.worker.d.ts +2 -0
- package/dist/worker/shared.worker.d.ts.map +1 -0
- package/docs/README.md +30 -0
- package/docs/api/backend.md +36 -0
- package/docs/api/create.md +82 -0
- package/docs/api/facade.md +52 -0
- package/docs/choosing-a-mode.md +41 -0
- package/docs/file-descriptors.md +695 -0
- package/docs/guides/async.md +36 -0
- package/docs/guides/dedicated.md +76 -0
- package/docs/guides/hashing.md +34 -0
- package/docs/guides/pure.md +46 -0
- package/docs/guides/sharedworker.md +57 -0
- package/docs/guides/streaming.md +51 -0
- package/docs/guides/watching.md +35 -0
- package/docs/migration.md +41 -0
- package/docs/types.md +246 -0
- package/package.json +55 -10
- package/src/core/BaseOPFS.ts +951 -0
- package/src/core/OPFSAsync.ts +248 -0
- package/src/core/OPFSSync.ts +460 -0
- package/src/facade/OPFSFacade.ts +489 -0
- package/src/facade/createOPFSAsync.ts +22 -0
- package/src/facade/createOPFSDedicated.ts +23 -0
- package/src/facade/createOPFSShared.ts +30 -0
- package/src/index.async.ts +11 -0
- package/src/index.pure.ts +8 -0
- package/src/index.sharedworker.ts +12 -0
- package/src/index.sync.ts +12 -0
- package/src/index.ts +44 -0
- package/src/types.ts +103 -0
- package/src/utils/encoder.ts +205 -0
- package/src/utils/errors.ts +297 -0
- package/src/utils/helpers.ts +465 -0
- package/src/worker/createDedicatedWorker.ts +74 -0
- package/src/worker/createSharedWorker.ts +67 -0
- package/src/worker/dedicated.worker.ts +13 -0
- package/src/worker/shared.worker.ts +17 -0
- package/dist/assets/worker-1Wh1cr7P.js.map +0 -1
- package/dist/assets/worker-BeJaVyBV.js.map +0 -1
- package/dist/assets/worker-DYYLzR1Y.js.map +0 -1
- package/dist/facade.d.ts.map +0 -1
- package/dist/helpers-BuGfPAg0.js +0 -1439
- package/dist/helpers-BuGfPAg0.js.map +0 -1
- package/dist/helpers-CF7A2WQG.cjs +0 -4
- package/dist/helpers-CF7A2WQG.cjs.map +0 -1
- package/dist/helpers-CIiblZ8d.cjs +0 -4
- package/dist/helpers-CIiblZ8d.cjs.map +0 -1
- package/dist/helpers-CKOebsbw.js +0 -1423
- package/dist/helpers-CKOebsbw.js.map +0 -1
- package/dist/helpers-Ca2c767K.js +0 -1427
- package/dist/helpers-Ca2c767K.js.map +0 -1
- package/dist/helpers-Dwc92hv9.cjs +0 -4
- package/dist/helpers-Dwc92hv9.cjs.map +0 -1
- package/dist/raw.cjs +0 -2
- package/dist/raw.cjs.map +0 -1
- package/dist/raw.d.ts +0 -13
- package/dist/raw.d.ts.map +0 -1
- package/dist/raw.js +0 -1001
- package/dist/raw.js.map +0 -1
- package/dist/worker.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -1,111 +1,23 @@
|
|
|
1
1
|
# OPFS Worker
|
|
2
2
|
|
|
3
|
-
[
|
|
3
|
+
[npm](https://www.npmjs.com/package/opfs-worker)
|
|
4
|
+
[demo](https://kachurun.github.io/opfs-worker/)
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
## What is OPFS?
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
OPFS ([Origin Private File System](https://developer.mozilla.org/en-US/docs/Web/API/File_System_API/Origin_private_file_system)) is a private file store for your origin. No file picker, no permission prompts. It lives under the usual site quota, and clearing site data wipes it.
|
|
8
9
|
|
|
9
|
-
-
|
|
10
|
-
- [Installation](#installation)
|
|
11
|
-
- [Quick Start](#quick-start)
|
|
12
|
-
- [Demo](#demo)
|
|
13
|
-
- [API Reference](#api-reference)
|
|
14
|
-
- [Types](#types)
|
|
15
|
-
- [Browser Support](#browser-support)
|
|
16
|
-
- [Development](#development)
|
|
17
|
-
- [License](#license)
|
|
10
|
+
This library gives you a real filesystem on top of it — read, write, and watch files with a familiar Node-like API.
|
|
18
11
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
- **
|
|
24
|
-
- **
|
|
25
|
-
- **
|
|
26
|
-
- **
|
|
27
|
-
|
|
28
|
-
### 🛠️ **Developer Experience**
|
|
29
|
-
|
|
30
|
-
- **Better DX vs File System Access API**: Familiar Node.js-like API instead of complex browser APIs
|
|
31
|
-
- **Type-safe**: Full TypeScript support with comprehensive type definitions
|
|
32
|
-
- **Comlink-powered**: Seamless RPC communication between main thread and worker
|
|
33
|
-
|
|
34
|
-
### 🌐 **Compatibility & Standards**
|
|
35
|
-
|
|
36
|
-
- **Cross-browser compatible**: Works in all modern browsers including Safari, Firefox, Chrome, and Edge
|
|
37
|
-
- **OPFS-native**: Built directly on Origin Private File System standards
|
|
38
|
-
- **No polyfills needed**: Uses native browser capabilities
|
|
39
|
-
|
|
40
|
-
### 📁 **File System Operations**
|
|
41
|
-
|
|
42
|
-
- **Complete API**: `readFile`, `writeFile`, `mkdir`, `remove`, `copy`, `rename`, and more
|
|
43
|
-
- **Binary file support**: Handle images, documents, and any binary data seamlessly
|
|
44
|
-
- **Hash support**: Built-in file hash calculation (SHA-1, SHA-256, SHA-384, SHA-512)
|
|
45
|
-
- **File indexing**: Complete file system indexing with metadata and search
|
|
46
|
-
|
|
47
|
-
### 🔄 **Advanced Features**
|
|
48
|
-
|
|
49
|
-
- **Sync operations**: Bulk file synchronization from external data sources
|
|
50
|
-
- **Event broadcasting**: Real-time file change notifications via BroadcastChannel
|
|
51
|
-
- **Include/exclude filters**: Fine-grained control over file watching patterns
|
|
52
|
-
- **Comprehensive error handling**: Detailed error types for better debugging
|
|
53
|
-
|
|
54
|
-
## When to Use
|
|
55
|
-
|
|
56
|
-
**Use OPFS Worker when you need a persistent file system directly in the browser with an API almost like Node.js `fs`.** It's faster than IndexedDB for file operations and provides better DX than raw File System Access API.
|
|
57
|
-
|
|
58
|
-
Here are the key use cases:
|
|
59
|
-
|
|
60
|
-
### 🚀 **Offline-First Applications**
|
|
61
|
-
|
|
62
|
-
- **Progressive Web Apps (PWAs)**: Store user data, cached resources, and app state locally
|
|
63
|
-
- **Media applications**: Cache images, videos, and audio files for offline playback
|
|
64
|
-
- **Data synchronization**: Local-first data with background sync to remote servers
|
|
65
|
-
|
|
66
|
-
### 💾 **Performance & Caching**
|
|
67
|
-
|
|
68
|
-
- **Asset caching**: Store and serve static files (CSS, JS, images) from local storage
|
|
69
|
-
- **Database caching**: Cache API responses and database queries locally
|
|
70
|
-
- **Session persistence**: Maintain user sessions and preferences across browser restarts
|
|
71
|
-
- **Resource preloading**: Preload critical resources for instant access
|
|
72
|
-
|
|
73
|
-
### 🎨 **Editor & IDE Features**
|
|
74
|
-
|
|
75
|
-
- **Code editors**: File tree navigation, syntax highlighting, and project management
|
|
76
|
-
- **Design tools**: Canvas state persistence, project files, and asset management
|
|
77
|
-
- **Document editors**: Rich text, markdown, and collaborative editing with local storage
|
|
78
|
-
- **Build tools**: Local development servers, build caches, and project configurations
|
|
79
|
-
|
|
80
|
-
### 🔄 **State Management**
|
|
81
|
-
|
|
82
|
-
- **Application state**: Persist complex application state and user preferences
|
|
83
|
-
- **Form data**: Auto-save forms and restore user input on page refresh
|
|
84
|
-
- **Game state**: Save game progress, levels, and user achievements
|
|
85
|
-
- **User preferences**: Settings, themes, and personalized configurations
|
|
86
|
-
|
|
87
|
-
### 📱 **Mobile & Cross-Platform**
|
|
88
|
-
|
|
89
|
-
- **Mobile web apps**: Native-like file management on mobile devices
|
|
90
|
-
- **Cross-tab synchronization**: Share data between multiple browser tabs
|
|
91
|
-
- **Worker-based processing**: Offload file operations to background threads
|
|
92
|
-
- **Progressive Web Apps**: Full offline capabilities with file system access
|
|
93
|
-
|
|
94
|
-
### ❌ **When NOT to Use**
|
|
95
|
-
|
|
96
|
-
- **Server-side storage**: This is a client-side solution, not a replacement for server storage
|
|
97
|
-
- **Cross-origin access**: Files are isolated to the specific domain/origin
|
|
98
|
-
- **Large datasets**: OPFS has browser-specific storage limitations:
|
|
99
|
-
- **Chrome/Edge**: Up to ~50% of free disk space (check via `navigator.storage.estimate()`)
|
|
100
|
-
- **Safari**: Usually 1-2 GB, sometimes less
|
|
101
|
-
- **Firefox**: Shared limit with IndexedDB, similar to Chromium
|
|
102
|
-
|
|
103
|
-
### ⚡ **Performance Notes**
|
|
104
|
-
|
|
105
|
-
- **Faster than IndexedDB**: Direct file system access without database overhead
|
|
106
|
-
- **Slower than native FS**: Browser APIs have performance limitations compared to desktop file systems
|
|
107
|
-
- **Worker-based**: File operations run in background threads, keeping main thread responsive
|
|
108
|
-
- **Memory efficient**: Files are stored in browser's native file system, not in memory
|
|
12
|
+
- **High-level Node-like API.** `readFile`, `writeFile`, `mkdir`, `stat`, `rename`, `copy`, `readDir` — with encodings, auto-detection by extension, and `string | URL` paths. You write `fs` code, not handle plumbing. → [facade API](docs/api/facade.md)
|
|
13
|
+
- **Low-level positional I/O.** `open` / `read` / `write` at an offset, plus `ftruncate` and `fsync` — enough for random-access formats and databases. → [file descriptors](docs/file-descriptors.md)
|
|
14
|
+
- **Sync API by default.** `createOPFS()` runs sync access handles in a dedicated worker: the fastest path OPFS offers, with file descriptors, and it works in every browser that has OPFS — including older Safari. You don't manage `Worker`, Comlink, or handles yourself. → [dedicated](docs/guides/dedicated.md)
|
|
15
|
+
- **Async API for modern browsers / SharedWorkers.** Uses `createWritable()` — runs on the main thread or inside a SharedWorker, no dedicated worker needed. Safari 26+ for writes. → [async](docs/guides/async.md) · [sharedworker](docs/guides/sharedworker.md)
|
|
16
|
+
- **Any way you want to run it.** Inlined dedicated worker, your own worker file, raw classes inside a worker you control, or one SharedWorker for every tab. Same methods in all of them. → [choosing a mode](docs/choosing-a-mode.md)
|
|
17
|
+
- **Memory-friendly for big files.** Streaming support means you can pull in gigabyte-sized files without blowing RAM — `importStream` writes a `ReadableStream`, `Blob`, or `File` chunk by chunk, with optional progress callbacks. → [streaming](docs/guides/streaming.md)
|
|
18
|
+
- **Cross-tab `watch()`.** Changes broadcast over `BroadcastChannel`, so listeners fire in every context that shares the filesystem. → [watching](docs/guides/watching.md)
|
|
19
|
+
- **Built-in file hashing.** `stat()` can carry a cheap etag or a real SHA hash, with a size cap so big files don't get hashed by accident — handy for caching and diffing. → [hashing](docs/guides/hashing.md)
|
|
20
|
+
- **Small and typed.** Full TypeScript types, ESM and CJS, two small runtime deps (`comlink`, `minimatch`) — and the async entry pulls in no worker code at all. → [types](docs/types.md)
|
|
109
21
|
|
|
110
22
|
## Installation
|
|
111
23
|
|
|
@@ -113,379 +25,73 @@ Here are the key use cases:
|
|
|
113
25
|
npm install opfs-worker
|
|
114
26
|
```
|
|
115
27
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
- `comlink` - Required for both modes (automatically included with inline mode)
|
|
119
|
-
- A bundler with Web Worker support (Vite, Webpack, Rollup, etc.) - Required for manual worker setup
|
|
120
|
-
|
|
121
|
-
## Quick Start
|
|
122
|
-
|
|
123
|
-
This library provides two ways to use OPFS with Web Workers:
|
|
124
|
-
|
|
125
|
-
### Inline Worker (Recommended)
|
|
126
|
-
|
|
127
|
-
The easiest way to get started - just import and use:
|
|
128
|
-
|
|
129
|
-
```typescript
|
|
130
|
-
import { createWorker } from 'opfs-worker';
|
|
131
|
-
|
|
132
|
-
async function basicExample() {
|
|
133
|
-
// Create a file system instance with default root path '/'
|
|
134
|
-
const fs = await createWorker();
|
|
135
|
-
|
|
136
|
-
// Write a file
|
|
137
|
-
await fs.writeFile('/config.json', JSON.stringify({ theme: 'dark' }));
|
|
138
|
-
|
|
139
|
-
// Read the file back
|
|
140
|
-
const config = await fs.readFile('/config.json');
|
|
141
|
-
console.log(JSON.parse(config));
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Extended example with all options
|
|
145
|
-
async function extendedExample() {
|
|
146
|
-
const broadcastChannel = new BroadcastChannel('my-app-events');
|
|
147
|
-
|
|
148
|
-
const fs = await createWorker({
|
|
149
|
-
root: '/my-app',
|
|
150
|
-
namespace: 'my-app:fs',
|
|
151
|
-
hashAlgorithm: 'SHA-256',
|
|
152
|
-
maxFileSize: 100 * 1024 * 1024, // 100MB
|
|
153
|
-
broadcastChannel
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
// Handle binary files
|
|
157
|
-
const imageData = new Uint8Array([58, /* binary data */]);
|
|
158
|
-
await fs.writeFile('/image.png', imageData);
|
|
159
|
-
const binaryData = await fs.readFile('/image.png', 'binary');
|
|
160
|
-
|
|
161
|
-
// Text files are automatically handled
|
|
162
|
-
await fs.writeFile('/config.txt', 'Hello, World!');
|
|
163
|
-
const textContent = await fs.readFile('/config.txt'); // Returns string
|
|
164
|
-
|
|
165
|
-
// Use file watching with BroadcastChannel
|
|
166
|
-
await fs.watch('/', {
|
|
167
|
-
recursive: true,
|
|
168
|
-
include: ['*.json'],
|
|
169
|
-
exclude: ['dist/**']
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
broadcastChannel.onmessage = (event) => {
|
|
173
|
-
console.log(`File changed: `, event.data);
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
// Get file statistics with hashing
|
|
177
|
-
const stats = await fs.stat('/image.png');
|
|
178
|
-
|
|
179
|
-
console.log(
|
|
180
|
-
`File size: ${stats.size} bytes`,
|
|
181
|
-
`Hash: ${stats.hash}`
|
|
182
|
-
);
|
|
183
|
-
}
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
> **Note:** File change events are sent via BroadcastChannel. Set the `broadcastChannel` option to customize the channel name, or use the default 'opfs-worker' channel. The watch system only sends events for watched paths, making it efficient and focused.
|
|
187
|
-
|
|
188
|
-
### Manual Worker Setup
|
|
189
|
-
|
|
190
|
-
For more control over the worker lifecycle, use the worker directly with your bundler:
|
|
191
|
-
|
|
192
|
-
```typescript
|
|
193
|
-
import OPFSWorker from 'opfs-worker/raw?worker';
|
|
194
|
-
import { wrap } from 'comlink';
|
|
195
|
-
|
|
196
|
-
async function basicExample() {
|
|
197
|
-
// Create and wrap the worker with default root path '/'
|
|
198
|
-
const worker = wrap(new OPFSWorker());
|
|
199
|
-
|
|
200
|
-
// Use the file system
|
|
201
|
-
await worker.writeFile('/config.json', JSON.stringify({ theme: 'dark' }));
|
|
202
|
-
const config = await worker.readFile('/config.json');
|
|
203
|
-
console.log(JSON.parse(config));
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// Extended example with all options
|
|
207
|
-
async function extendedExample() {
|
|
208
|
-
// Create with all available options
|
|
209
|
-
const worker = wrap(new OPFSWorker({
|
|
210
|
-
root: '/my-app',
|
|
211
|
-
namespace: 'my-app:fs',
|
|
212
|
-
hashAlgorithm: 'SHA-256',
|
|
213
|
-
maxFileSize: 100 * 1024 * 1024, // 100MB
|
|
214
|
-
broadcastChannel: 'my-app-events' // You can't pass a BroadcastChannel instance to the worker, so you must use a broadcast channel name here
|
|
215
|
-
}));
|
|
216
|
-
|
|
217
|
-
// Bulk sync from external data
|
|
218
|
-
const entries = [
|
|
219
|
-
['/data/config.json', JSON.stringify({ version: '1.0' })],
|
|
220
|
-
['/data/users.json', JSON.stringify([{ id: 1, name: 'John' }])]
|
|
221
|
-
];
|
|
222
|
-
await worker.sync(entries, { cleanBefore: true });
|
|
223
|
-
|
|
224
|
-
// Create directories
|
|
225
|
-
await worker.mkdir('/data/logs', { recursive: true });
|
|
226
|
-
|
|
227
|
-
// Append to log files (worker works with bytes)
|
|
228
|
-
const logEntry = new TextEncoder().encode(`${new Date().toISOString()}: App started\n`);
|
|
229
|
-
await worker.appendFile('/data/logs/app.log', logEntry);
|
|
230
|
-
|
|
231
|
-
// Watch for changes
|
|
232
|
-
await worker.watch('/data', { recursive: true });
|
|
233
|
-
|
|
234
|
-
const channel = new BroadcastChannel('my-app-events');
|
|
235
|
-
channel.onmessage = (event) => {
|
|
236
|
-
console.log('File changed:', event.data);
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
**Note:** Manual worker setup requires a bundler that supports Web Workers (like Vite, Webpack, Rollup, etc.) and the `comlink` package for communication between the main thread and worker.
|
|
242
|
-
|
|
243
|
-
### Hash Algorithm Configuration
|
|
244
|
-
|
|
245
|
-
The file system supports global hash algorithm configuration. Instead of passing hash options to individual methods, you can set the hash algorithm once and it will be used for all file operations that support hashing.
|
|
246
|
-
|
|
247
|
-
```typescript
|
|
248
|
-
import { createWorker } from 'opfs-worker';
|
|
249
|
-
|
|
250
|
-
async function hashExample() {
|
|
251
|
-
const fs = await createWorker();
|
|
252
|
-
|
|
253
|
-
// Enable SHA-256 hashing globally
|
|
254
|
-
fs.setOptions({ hashAlgorithm: 'SHA-256' });
|
|
255
|
-
|
|
256
|
-
// Write a file
|
|
257
|
-
await fs.writeFile('/data.txt', 'Hello World');
|
|
258
|
-
|
|
259
|
-
// Get stats - hash will be included automatically
|
|
260
|
-
const stats = await fs.stat('/data.txt');
|
|
261
|
-
console.log(`Hash: ${stats.hash}`); // SHA-256 hash
|
|
262
|
-
|
|
263
|
-
// Get file system index - all files will include hashes
|
|
264
|
-
const index = await fs.index();
|
|
265
|
-
for (const [path, stat] of index) {
|
|
266
|
-
if (stat.isFile && stat.hash) {
|
|
267
|
-
console.log(`${path}: ${stat.hash}`);
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// Watch events will also include hash information
|
|
272
|
-
const channel = new BroadcastChannel('opfs-worker');
|
|
273
|
-
channel.onmessage = (event) => {
|
|
274
|
-
if (event.data.hash) {
|
|
275
|
-
console.log(`File ${event.data.path} changed, hash: ${event.data.hash}`);
|
|
276
|
-
}
|
|
277
|
-
};
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
// Configure maximum file size for hashing
|
|
281
|
-
async function maxFileSizeExample() {
|
|
282
|
-
const fs = await createWorker();
|
|
283
|
-
|
|
284
|
-
// Set custom maximum file size (100MB instead of default 50MB)
|
|
285
|
-
fs.setOptions({
|
|
286
|
-
hashAlgorithm: 'SHA-256',
|
|
287
|
-
maxFileSize: 100 * 1024 * 1024 // 100MB
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
// Files up to 100MB will be hashed
|
|
291
|
-
// Files larger than this will not have hash information
|
|
292
|
-
const stats = await fs.stat('/large-file.dat');
|
|
293
|
-
if (stats.hash) {
|
|
294
|
-
console.log(`Hash: ${stats.hash}`);
|
|
295
|
-
} else {
|
|
296
|
-
console.log('File too large for hashing');
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
**Supported Hash Algorithms:**
|
|
302
|
-
|
|
303
|
-
- `'SHA-1'` - Fastest, good for general use (default)
|
|
304
|
-
- `'SHA-256'` - More secure, widely supported
|
|
305
|
-
- `'SHA-384'` - Higher security
|
|
306
|
-
- `'SHA-512'` - Highest security
|
|
307
|
-
- `null` - Disable hashing for maximum performance
|
|
308
|
-
|
|
309
|
-
**Note:** When hashing is enabled, it affects all file operations including `stat()`, `index()`, and watch events. Set to `null` when you don't need hash information to improve performance.
|
|
310
|
-
|
|
311
|
-
### Root Path Configuration
|
|
312
|
-
|
|
313
|
-
The file system supports configuring the root path through options. The root path determines where in OPFS the file system's root will be created. All file paths passed to the API are relative to this root path.
|
|
28
|
+
## Quick start
|
|
314
29
|
|
|
315
30
|
```typescript
|
|
316
|
-
import {
|
|
31
|
+
import { createOPFS } from 'opfs-worker';
|
|
317
32
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
// This creates /config.json in OPFS root
|
|
33
|
+
const fs = createOPFS({
|
|
34
|
+
root: '/my-app',
|
|
35
|
+
hashAlgorithm: 'SHA-256'
|
|
36
|
+
});
|
|
323
37
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
// This creates /my-app/config.json in OPFS root
|
|
38
|
+
await fs.mkdir('/project');
|
|
39
|
+
await fs.writeFile('/project/hello.txt', 'Hello, OPFS!');
|
|
40
|
+
await fs.rename('/project/hello.txt', '/project/readme.txt');
|
|
328
41
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
await fsCustom.writeFile('/config.json', '{}');
|
|
332
|
-
// This creates /new-app/config.json in OPFS root
|
|
333
|
-
}
|
|
42
|
+
const files = await fs.readDir('/project');
|
|
43
|
+
const text = await fs.readFile('/project/readme.txt'); // 'Hello, OPFS!'
|
|
334
44
|
```
|
|
335
45
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
-
|
|
341
|
-
|
|
342
|
-
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
- [
|
|
357
|
-
- [
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
-
|
|
364
|
-
-
|
|
365
|
-
-
|
|
366
|
-
|
|
367
|
-
**Core File Operations:**
|
|
368
|
-
|
|
369
|
-
- `readFile(path, encoding?)` - Read files as text or binary with auto-detection
|
|
370
|
-
- `writeFile(path, data, encoding?)` - Write text or binary data with auto-detection
|
|
371
|
-
- `readText(path, encoding?)` - Read files as text with specified encoding
|
|
372
|
-
- `writeText(path, text, encoding?)` - Write text with specified encoding
|
|
373
|
-
- `appendText(path, text, encoding?)` - Append text with specified encoding
|
|
374
|
-
|
|
375
|
-
**Common Operations:**
|
|
376
|
-
|
|
377
|
-
- `mkdir(path, options?)` - Create directories
|
|
378
|
-
- `readDir(path)` - List directory contents
|
|
379
|
-
- `stat(path)` - Get file/directory statistics
|
|
380
|
-
- `remove(path, options?)` - Remove files/directories
|
|
381
|
-
- `copy(source, destination, options?)` - Copy files/directories
|
|
382
|
-
- `rename(oldPath, newPath)` - Rename files/directories
|
|
383
|
-
|
|
384
|
-
**File Descriptors (Low-level I/O):**
|
|
385
|
-
|
|
386
|
-
- `open(path, options?)` - Open file and return descriptor
|
|
387
|
-
- `read(fd, buffer, offset, length, position?)` - Read from descriptor (returns `{bytesRead, buffer}`)
|
|
388
|
-
- `write(fd, buffer, offset?, length?, position?)` - Write to descriptor
|
|
389
|
-
- `fstat(fd)` - Get stats by descriptor
|
|
390
|
-
- `ftruncate(fd, size?)` - Truncate file by descriptor
|
|
391
|
-
- `fsync(fd)` - Sync file data to storage
|
|
392
|
-
- `close(fd)` - Close file descriptor
|
|
393
|
-
|
|
394
|
-
**Note**: The `read()` method uses `Comlink.transfer()` for efficient buffer handling. **From the main window**, you must transfer buffer ownership to the worker, and **from the worker**, the buffer is transferred back to you. See [File Descriptors Guide](docs/file-descriptors.md) for complete usage examples.
|
|
395
|
-
|
|
396
|
-
_For detailed file descriptor documentation, see [File Descriptors Guide](docs/file-descriptors.md)_
|
|
397
|
-
|
|
398
|
-
**Advanced Features:**
|
|
399
|
-
|
|
400
|
-
- `watch(path, options?)` - Watch for file changes with minimatch patterns
|
|
401
|
-
- `index()` - Get complete file system index
|
|
402
|
-
- `sync(entries, options?)` - Bulk synchronization
|
|
403
|
-
- `setOptions(options)` - Update configuration
|
|
404
|
-
|
|
405
|
-
**Binary File Support:**
|
|
406
|
-
|
|
407
|
-
- Full support for images, documents, and any binary data
|
|
408
|
-
- Automatic conversion between Uint8Array, ArrayBuffer, and Blob
|
|
409
|
-
- Multiple text encodings (UTF-8, UTF-16, ASCII, Base64, etc.)
|
|
410
|
-
|
|
411
|
-
**Utility Functions:**
|
|
412
|
-
|
|
413
|
-
- Path manipulation (`basename`, `dirname`, `normalizePath`, etc.)
|
|
414
|
-
- Data conversion helpers
|
|
415
|
-
- OPFS support detection
|
|
416
|
-
|
|
417
|
-
For detailed API documentation with examples, see [docs/api-reference.md](docs/api-reference.md).
|
|
418
|
-
|
|
419
|
-
## Types
|
|
420
|
-
|
|
421
|
-
Full TypeScript types are provided — see [docs/types.md](docs/types.md) for complete type definitions including `FileStat`, `DirentData`, `WatchOptions`, `OPFSOptions`, and more.
|
|
422
|
-
|
|
423
|
-
## Browser Support
|
|
424
|
-
|
|
425
|
-
This library works in **all modern browsers**, including Safari, Firefox, Chrome, and Edge.
|
|
426
|
-
|
|
427
|
-
**Requirements:**
|
|
428
|
-
|
|
429
|
-
- Web Workers support (available in all modern browsers)
|
|
430
|
-
- File System Access API (for OPFS functionality)
|
|
431
|
-
|
|
432
|
-
**Browser Compatibility:**
|
|
433
|
-
|
|
434
|
-
- ✅ Chrome 86+
|
|
435
|
-
- ✅ Edge 86+
|
|
436
|
-
- ✅ Firefox 111+
|
|
437
|
-
- ✅ Safari 15.2+
|
|
438
|
-
- ✅ Opera 72+
|
|
46
|
+
## Choose a mode
|
|
47
|
+
|
|
48
|
+
| What you want | Use |
|
|
49
|
+
| ---------------------------------------------------------------- | ---------------------------------------------------- |
|
|
50
|
+
| Node-like `fs` via dedicated worker (default, works everywhere) | `createOPFS()` |
|
|
51
|
+
| Node-like `fs` on the main thread (modern browsers / Safari 26+) | `createOPFSAsync()` from `opfs-worker/async` |
|
|
52
|
+
| Node-like `fs` via SharedWorker (modern browsers / Safari 26+) | `createOPFSShared()` from `opfs-worker/sharedworker` |
|
|
53
|
+
| OPFS inside a worker you already run (classes only) | `OPFSSync` / `OPFSAsync` from `opfs-worker/pure` |
|
|
54
|
+
|
|
55
|
+
Trade-offs (FDs, Safari, size, CSP): [Choosing a mode](docs/choosing-a-mode.md).
|
|
56
|
+
|
|
57
|
+
## Docs
|
|
58
|
+
|
|
59
|
+
- [Docs index](docs/README.md)
|
|
60
|
+
- [Choosing a mode](docs/choosing-a-mode.md)
|
|
61
|
+
- Guides
|
|
62
|
+
- [Dedicated worker](docs/guides/dedicated.md)
|
|
63
|
+
- [Async](docs/guides/async.md)
|
|
64
|
+
- [SharedWorker](docs/guides/sharedworker.md)
|
|
65
|
+
- [Pure classes](docs/guides/pure.md)
|
|
66
|
+
- [Streaming](docs/guides/streaming.md)
|
|
67
|
+
- [Watching](docs/guides/watching.md)
|
|
68
|
+
- [Hashing](docs/guides/hashing.md)
|
|
69
|
+
- API
|
|
70
|
+
- [Create helpers & options](docs/api/create.md)
|
|
71
|
+
- [Facade](docs/api/facade.md)
|
|
72
|
+
- [Backend](docs/api/backend.md)
|
|
73
|
+
- [File descriptors](docs/file-descriptors.md)
|
|
74
|
+
- [Types](docs/types.md)
|
|
75
|
+
- [Migration from 1.x](docs/migration.md)
|
|
439
76
|
|
|
440
77
|
## Development
|
|
441
78
|
|
|
442
|
-
### Building
|
|
443
|
-
|
|
444
|
-
```bash
|
|
445
|
-
npm run build
|
|
446
|
-
```
|
|
447
|
-
|
|
448
|
-
### Development Server
|
|
449
|
-
|
|
450
|
-
```bash
|
|
451
|
-
npm run dev
|
|
452
|
-
```
|
|
453
|
-
|
|
454
|
-
### Testing
|
|
455
|
-
|
|
456
79
|
```bash
|
|
457
|
-
|
|
458
|
-
|
|
80
|
+
bun install
|
|
81
|
+
bun run build
|
|
82
|
+
bun run test
|
|
83
|
+
bun run lint
|
|
84
|
+
bun run type-check
|
|
459
85
|
```
|
|
460
86
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
```bash
|
|
464
|
-
npm run lint
|
|
465
|
-
npm run lint:fix
|
|
466
|
-
```
|
|
87
|
+
Demo app: `bun run dev:demo` / `bun run build:demo` / `bun run preview`.
|
|
467
88
|
|
|
468
89
|
## License
|
|
469
90
|
|
|
470
91
|
MIT
|
|
471
92
|
|
|
472
|
-
##
|
|
473
|
-
|
|
474
|
-
Contributions are welcome!
|
|
475
|
-
|
|
476
|
-
**How to contribute:**
|
|
477
|
-
|
|
478
|
-
- 🐛 **Report bugs** or suggest features via [GitHub Issues](https://github.com/kachurun/opfs-worker/issues)
|
|
479
|
-
- 💡 **Submit ideas** for improvements or new features
|
|
480
|
-
- 🔧 **Send PRs** for bug fixes, documentation, or enhancements
|
|
481
|
-
- 📚 **Improve docs** - help make the library more accessible
|
|
482
|
-
|
|
483
|
-
**Getting started:**
|
|
93
|
+
## 👤 Maintainer
|
|
484
94
|
|
|
485
|
-
|
|
486
|
-
2. Create a feature branch
|
|
487
|
-
3. Make your changes
|
|
488
|
-
4. Add tests if applicable
|
|
489
|
-
5. Submit a Pull Request
|
|
95
|
+
<img src="https://github.com/kachurun.png" width="100" height="100" alt="@kachurun's avatar">
|
|
490
96
|
|
|
491
|
-
|
|
97
|
+
Maintained with ❤️ by [@kachurun](https://github.com/kachurun)
|