opfs-worker 2.0.0 → 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.
Files changed (135) hide show
  1. package/README.md +62 -439
  2. package/dist/BaseOPFS-BPw9AIQ-.cjs +4 -0
  3. package/dist/BaseOPFS-BPw9AIQ-.cjs.map +1 -0
  4. package/dist/BaseOPFS-Cylz6ijk.js +2036 -0
  5. package/dist/BaseOPFS-Cylz6ijk.js.map +1 -0
  6. package/dist/OPFSAsync-BKSAJJeh.js +124 -0
  7. package/dist/OPFSAsync-BKSAJJeh.js.map +1 -0
  8. package/dist/OPFSAsync-s2P7y3sw.cjs +2 -0
  9. package/dist/OPFSAsync-s2P7y3sw.cjs.map +1 -0
  10. package/dist/OPFSFacade-DePnNRgt.cjs +2 -0
  11. package/dist/OPFSFacade-DePnNRgt.cjs.map +1 -0
  12. package/dist/OPFSFacade-XohWlHuu.js +281 -0
  13. package/dist/OPFSFacade-XohWlHuu.js.map +1 -0
  14. package/dist/OPFSSync-C7KBepe_.cjs +2 -0
  15. package/dist/OPFSSync-C7KBepe_.cjs.map +1 -0
  16. package/dist/OPFSSync-CsSQkpk5.js +208 -0
  17. package/dist/OPFSSync-CsSQkpk5.js.map +1 -0
  18. package/dist/assets/dedicated.worker-nY3tK4zi.js.map +1 -0
  19. package/dist/{OPFSWorker.d.ts → core/BaseOPFS.d.ts} +34 -304
  20. package/dist/core/BaseOPFS.d.ts.map +1 -0
  21. package/dist/core/OPFSAsync.d.ts +55 -0
  22. package/dist/core/OPFSAsync.d.ts.map +1 -0
  23. package/dist/core/OPFSSync.d.ts +54 -0
  24. package/dist/core/OPFSSync.d.ts.map +1 -0
  25. package/dist/createOPFSAsync-BwKDmHsy.cjs +2 -0
  26. package/dist/createOPFSAsync-BwKDmHsy.cjs.map +1 -0
  27. package/dist/createOPFSAsync-Y4Mg6qte.js +10 -0
  28. package/dist/createOPFSAsync-Y4Mg6qte.js.map +1 -0
  29. package/dist/createOPFSDedicated-CsnV6MLP.js +2333 -0
  30. package/dist/createOPFSDedicated-CsnV6MLP.js.map +1 -0
  31. package/dist/createOPFSDedicated-pKTRWLdz.cjs +2283 -0
  32. package/dist/createOPFSDedicated-pKTRWLdz.cjs.map +1 -0
  33. package/dist/createOPFSShared-CGdd__PH.js +23 -0
  34. package/dist/createOPFSShared-CGdd__PH.js.map +1 -0
  35. package/dist/createOPFSShared-CskROt7U.cjs +2 -0
  36. package/dist/createOPFSShared-CskROt7U.cjs.map +1 -0
  37. package/dist/dedicated.worker.js +2281 -0
  38. package/dist/dedicated.worker.js.map +1 -0
  39. package/dist/{OPFSFacade.d.ts → facade/OPFSFacade.d.ts} +31 -23
  40. package/dist/facade/OPFSFacade.d.ts.map +1 -0
  41. package/dist/facade/createOPFSAsync.d.ts +16 -0
  42. package/dist/facade/createOPFSAsync.d.ts.map +1 -0
  43. package/dist/facade/createOPFSDedicated.d.ts +17 -0
  44. package/dist/facade/createOPFSDedicated.d.ts.map +1 -0
  45. package/dist/facade/createOPFSShared.d.ts +24 -0
  46. package/dist/facade/createOPFSShared.d.ts.map +1 -0
  47. package/dist/index.async.cjs +2 -0
  48. package/dist/index.async.cjs.map +1 -0
  49. package/dist/index.async.d.ts +10 -0
  50. package/dist/index.async.d.ts.map +1 -0
  51. package/dist/index.async.js +55 -0
  52. package/dist/index.async.js.map +1 -0
  53. package/dist/index.cjs +1 -2477
  54. package/dist/index.cjs.map +1 -1
  55. package/dist/index.d.ts +17 -3
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/index.js +61 -2828
  58. package/dist/index.js.map +1 -1
  59. package/dist/index.pure.cjs +1 -1
  60. package/dist/index.pure.cjs.map +1 -1
  61. package/dist/index.pure.d.ts +3 -1
  62. package/dist/index.pure.d.ts.map +1 -1
  63. package/dist/index.pure.js +50 -1053
  64. package/dist/index.pure.js.map +1 -1
  65. package/dist/index.sharedworker.cjs +2 -0
  66. package/dist/index.sharedworker.cjs.map +1 -0
  67. package/dist/index.sharedworker.d.ts +11 -0
  68. package/dist/index.sharedworker.d.ts.map +1 -0
  69. package/dist/index.sharedworker.js +55 -0
  70. package/dist/index.sharedworker.js.map +1 -0
  71. package/dist/index.sync.cjs +2 -0
  72. package/dist/index.sync.cjs.map +1 -0
  73. package/dist/index.sync.d.ts +11 -0
  74. package/dist/index.sync.d.ts.map +1 -0
  75. package/dist/index.sync.js +55 -0
  76. package/dist/index.sync.js.map +1 -0
  77. package/dist/shared.worker.js +2166 -0
  78. package/dist/shared.worker.js.map +1 -0
  79. package/dist/types.d.ts +9 -4
  80. package/dist/types.d.ts.map +1 -1
  81. package/dist/worker/createDedicatedWorker.d.ts +30 -0
  82. package/dist/worker/createDedicatedWorker.d.ts.map +1 -0
  83. package/dist/worker/createSharedWorker.d.ts +37 -0
  84. package/dist/worker/createSharedWorker.d.ts.map +1 -0
  85. package/dist/worker/dedicated.worker.d.ts +2 -0
  86. package/dist/worker/dedicated.worker.d.ts.map +1 -0
  87. package/dist/worker/shared.worker.d.ts +2 -0
  88. package/dist/worker/shared.worker.d.ts.map +1 -0
  89. package/docs/README.md +30 -0
  90. package/docs/api/backend.md +36 -0
  91. package/docs/api/create.md +82 -0
  92. package/docs/api/facade.md +52 -0
  93. package/docs/choosing-a-mode.md +41 -0
  94. package/docs/file-descriptors.md +8 -9
  95. package/docs/guides/async.md +36 -0
  96. package/docs/guides/dedicated.md +76 -0
  97. package/docs/guides/hashing.md +34 -0
  98. package/docs/guides/pure.md +46 -0
  99. package/docs/guides/sharedworker.md +57 -0
  100. package/docs/guides/streaming.md +51 -0
  101. package/docs/guides/watching.md +35 -0
  102. package/docs/migration.md +41 -0
  103. package/docs/types.md +20 -6
  104. package/package.json +42 -3
  105. package/src/{OPFSWorker.ts → core/BaseOPFS.ts} +54 -647
  106. package/src/core/OPFSAsync.ts +248 -0
  107. package/src/core/OPFSSync.ts +460 -0
  108. package/src/{OPFSFacade.ts → facade/OPFSFacade.ts} +83 -54
  109. package/src/facade/createOPFSAsync.ts +22 -0
  110. package/src/facade/createOPFSDedicated.ts +23 -0
  111. package/src/facade/createOPFSShared.ts +30 -0
  112. package/src/index.async.ts +11 -0
  113. package/src/index.pure.ts +3 -2
  114. package/src/index.sharedworker.ts +12 -0
  115. package/src/index.sync.ts +12 -0
  116. package/src/index.ts +37 -8
  117. package/src/types.ts +8 -4
  118. package/src/worker/createDedicatedWorker.ts +74 -0
  119. package/src/worker/createSharedWorker.ts +67 -0
  120. package/src/worker/dedicated.worker.ts +13 -0
  121. package/src/worker/shared.worker.ts +17 -0
  122. package/dist/OPFSFacade.d.ts.map +0 -1
  123. package/dist/OPFSWorker.d.ts.map +0 -1
  124. package/dist/assets/worker.entry-DUlEoroc.js.map +0 -1
  125. package/dist/createOPFSWorker.d.ts +0 -17
  126. package/dist/createOPFSWorker.d.ts.map +0 -1
  127. package/dist/helpers-DNj8ZoMu.cjs +0 -4
  128. package/dist/helpers-DNj8ZoMu.cjs.map +0 -1
  129. package/dist/helpers-WY2jfbOT.js +0 -1427
  130. package/dist/helpers-WY2jfbOT.js.map +0 -1
  131. package/dist/worker.entry.d.ts +0 -2
  132. package/dist/worker.entry.d.ts.map +0 -1
  133. package/docs/api-reference.md +0 -815
  134. package/src/createOPFSWorker.ts +0 -57
  135. package/src/worker.entry.ts +0 -6
@@ -1,815 +0,0 @@
1
- # API Reference
2
-
3
- This document contains the complete API reference for OPFS Worker.
4
-
5
- ## Table of Contents
6
-
7
- - [API Reference](#api-reference)
8
- - [Table of Contents](#table-of-contents)
9
- - [Entry Points](#entry-points)
10
- - [Mode 1: Node-like facade](#mode-1-node-like-facade)
11
- - [`createOPFS(options?: OPFSOptions)`](#createopfsoptions-opfsoptions)
12
- - [Mode 2: Raw worker API from the main thread](#mode-2-raw-worker-api-from-the-main-thread)
13
- - [`createOPFSWorker(options?: OPFSOptions)`](#createopfsworkeroptions-opfsoptions)
14
- - [Mode 3: `OPFSWorker` inside your own worker](#mode-3-opfsworker-inside-your-own-worker)
15
- - [`OPFSWorker` from `opfs-worker/pure`](#opfsworker-from-opfs-workerpure)
16
- - [Core Methods](#core-methods)
17
- - [Read File](#read-file)
18
- - [`readFile(path: string, encoding?: Encoding | 'binary'): Promise<string | Uint8Array>`](#readfilepath-string-encoding-encoding--binary-promisestring--uint8array)
19
- - [Write File](#write-file)
20
- - [`writeFile(path: string, data: string | Uint8Array | ArrayBuffer, encoding?: Encoding): Promise<void>`](#writefilepath-string-data-string--uint8array--arraybuffer-encoding-encoding-promisevoid)
21
- - [Append File](#append-file)
22
- - [`appendFile(path: string, data: string | Uint8Array | ArrayBuffer, encoding?: Encoding): Promise<void>`](#appendfilepath-string-data-string--uint8array--arraybuffer-encoding-encoding-promisevoid)
23
- - [Create Directory](#create-directory)
24
- - [`mkdir(path: string, options?: { recursive?: boolean }): Promise<void>`](#mkdirpath-string-options--recursive-boolean--promisevoid)
25
- - [Read Directory](#read-directory)
26
- - [`readDir(path: string): Promise<DirentData[]>`](#readdirpath-string-promisedirentdata)
27
- - [Get Stats](#get-stats)
28
- - [`stat(path: string): Promise<FileStat>`](#statpath-string-promisefilestat)
29
- - [Check Existence](#check-existence)
30
- - [`exists(path: string): Promise<boolean>`](#existspath-string-promiseboolean)
31
- - [Remove Path](#remove-path)
32
- - [`remove(path: string, options?: { recursive?: boolean; force?: boolean }): Promise<void>`](#removepath-string-options--recursive-boolean-force-boolean--promisevoid)
33
- - [Copy Path](#copy-path)
34
- - [`copy(source: string, destination: string, options?: { recursive?: boolean; force?: boolean }): Promise<void>`](#copysource-string-destination-string-options--recursive-boolean-force-boolean--promisevoid)
35
- - [Rename Path](#rename-path)
36
- - [`rename(oldPath: string, newPath: string): Promise<void>`](#renameoldpath-string-newpath-string-promisevoid)
37
- - [Clear Directory](#clear-directory)
38
- - [`clear(path?: string): Promise<void>`](#clearpath-string-promisevoid)
39
- - [Index File System](#index-file-system)
40
- - [`index(): Promise<Map<string, FileStat>>`](#index-promisemapstring-filestat)
41
- - [Sync File System](#sync-file-system)
42
- - [`sync(entries: [string, string | Uint8Array | Blob][], options?: { cleanBefore?: boolean }): Promise<void>`](#syncentries-string-string--uint8array--blob-options--cleanbefore-boolean--promisevoid)
43
- - [Watch](#watch)
44
- - [`watch(path: string, options?: WatchOptions): Promise<void>`](#watchpath-string-options-watchoptions-promisevoid)
45
- - [Watch Behavior](#watch-behavior)
46
- - [Unwatch](#unwatch)
47
- - [`unwatch(path: string): void`](#unwatchpath-string-void)
48
- - [Dispose](#dispose)
49
- - [`dispose(): void`](#dispose-void)
50
- - [Configuration](#configuration)
51
- - [`setOptions(options: { root?: string; hashAlgorithm?: null | false | 'etag' | 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512'; maxFileSize?: number }): Promise<void>`](#setoptionsoptions--root-string-hashalgorithm-null--false--etag--sha-1--sha-256--sha-384--sha-512-maxfilesize-number--promisevoid)
52
- - [Resolve Path](#resolve-path)
53
- - [`realpath(path: string): Promise<string>`](#realpathpath-string-promisestring)
54
- - [File Descriptors](#file-descriptors)
55
- - [File Descriptors Overview](#file-descriptors-overview)
56
- - [File Descriptor Methods](#file-descriptor-methods)
57
- - [Binary File Handling](#binary-file-handling)
58
- - [Reading Binary Files](#reading-binary-files)
59
- - [Writing Binary Files](#writing-binary-files)
60
- - [Working with Different Data Types](#working-with-different-data-types)
61
- - [File Upload and Download](#file-upload-and-download)
62
- - [Supported Encodings](#supported-encodings)
63
- - [Utility Functions](#utility-functions)
64
- - [Path Utilities](#path-utilities)
65
- - [Data Conversion](#data-conversion)
66
- - [File System Utilities](#file-system-utilities)
67
-
68
- ## Entry Points
69
-
70
- ### Mode 1: Node-like facade
71
-
72
- #### `createOPFS(options?: OPFSOptions)`
73
-
74
- Starts an inlined worker and returns a facade with a Node-like API (strings, encodings, auto-detection). Comlink is used under the hood.
75
-
76
- ```typescript
77
- import { createOPFS } from 'opfs-worker';
78
-
79
- const fs = createOPFS();
80
-
81
- const fsCustom = createOPFS({
82
- root: '/my-app',
83
- hashAlgorithm: 'SHA-256',
84
- broadcastChannel: 'my-app-events'
85
- });
86
-
87
- const channel = new BroadcastChannel('my-app-events');
88
- channel.onmessage = (event) => {
89
- console.log('File changed:', event.data);
90
- };
91
- ```
92
-
93
- **Parameters:**
94
-
95
- - `options` (optional): Configuration options
96
- - `root` (optional): Root path for the file system (default: '/')
97
- - `namespace` (optional): Namespace for the file system (default: 'opfs-worker:${root}'), will be sent to the BroadcastChannel with each event
98
- - `hashAlgorithm` (optional): Hash algorithm for file hashing
99
- - `broadcastChannel` (optional): Custom name for the broadcast channel (default: 'opfs-worker')
100
-
101
- **Returns:** `OPFSFacade`
102
-
103
- ### Mode 2: Raw worker API from the main thread
104
-
105
- #### `createOPFSWorker(options?: OPFSOptions)`
106
-
107
- Same entry as Mode 1, but without the facade. Returns a Comlink proxy to `OPFSWorker` (bytes in / bytes out). Useful if you want to wrap it yourself or prefer the lower-level API. The built-in `OPFSFacade` is itself built on this function, so it doubles as a reference implementation for your own wrapper.
108
-
109
- ```typescript
110
- import { createOPFSWorker } from 'opfs-worker';
111
-
112
- const { fs, worker, dispose } = createOPFSWorker({
113
- root: '/my-app',
114
- broadcastChannel: 'my-app-events',
115
- });
116
-
117
- await fs.writeFile('/config.json', new TextEncoder().encode('{}'));
118
- dispose();
119
- ```
120
-
121
- **Returns:** `{ fs, worker, dispose }` — `fs` is `RemoteOPFSWorker`, `worker` is the browser `Worker`, `dispose()` cleans up both.
122
-
123
- **Deprecated aliases (1.x compatibility):** `createWorker` → `createOPFS`, `OPFSFileSystem` → `OPFSFacade`. `opfs-worker/raw` is removed — use `opfs-worker/pure`.
124
-
125
- ### Mode 3: `OPFSWorker` inside your own worker
126
-
127
- #### `OPFSWorker` from `opfs-worker/pure`
128
-
129
- Use the class directly inside a worker you control. No nested worker, no Comlink. How you bundle that worker and talk to the main thread is up to you.
130
-
131
- ```typescript
132
- import { OPFSWorker } from 'opfs-worker/pure';
133
-
134
- const fs = new OPFSWorker({
135
- root: '/my-app',
136
- broadcastChannel: 'my-app-events', // name only
137
- });
138
-
139
- await fs.writeFile('/config.json', new TextEncoder().encode('{}'));
140
- ```
141
-
142
- `opfs-worker/pure` does not call Comlink `expose()`, so it will not take over your worker's message port.
143
-
144
- ## Core Methods
145
-
146
- ### Read File
147
-
148
- #### `readFile(path: string, encoding?: Encoding | 'binary'): Promise<string | Uint8Array>`
149
-
150
- Read a file from the file system. Supports both text and binary files.
151
-
152
- ```typescript
153
- // Read as text (default)
154
- const content = await fs.readFile('/config/settings.json');
155
-
156
- // Read as binary
157
- const binaryData = await fs.readFile('/images/logo.png', 'binary');
158
-
159
- // Read with specific encoding
160
- const utf8Content = await fs.readFile('/data/utf8.txt', 'utf-8');
161
-
162
- // Handle binary data
163
- const imageBuffer = await fs.readFile('/image.png', 'binary');
164
- const blob = new Blob([imageBuffer], { type: 'image/png' });
165
- const url = URL.createObjectURL(blob);
166
- ```
167
-
168
- **Parameters:**
169
-
170
- - `path`: The path to the file to read
171
- - `encoding` (optional): The encoding to use ('utf-8', 'binary', 'utf-16le', 'ascii', 'latin1', 'base64', 'hex')
172
-
173
- **Returns:** `Promise<string | Uint8Array>` - File contents as string or binary data
174
-
175
- **Throws:** `ExistenceError` if the file doesn't exist
176
-
177
- **Binary File Handling:**
178
-
179
- - Use `'binary'` encoding to read files as `Uint8Array`
180
- - Binary data can be converted to `Blob` for use with `URL.createObjectURL()`
181
- - Supports various encodings for text files
182
-
183
- ### Write File
184
-
185
- #### `writeFile(path: string, data: string | Uint8Array | ArrayBuffer, encoding?: Encoding): Promise<void>`
186
-
187
- Write data to a file, creating or overwriting it. Supports both text and binary data.
188
-
189
- ```typescript
190
- // Write text data
191
- await fs.writeFile('/config/settings.json', JSON.stringify({ theme: 'dark' }));
192
-
193
- // Write binary data
194
- const binaryData = new Uint8Array([1, 2, 3, 4, 5]);
195
- await fs.writeFile('/data/binary.dat', binaryData);
196
-
197
- // Write with specific encoding
198
- await fs.writeFile('/data/utf16.txt', 'Hello World', 'utf-16le');
199
-
200
- // Write binary data from file input
201
- const fileInput = document.getElementById('file') as HTMLInputElement;
202
- const file = fileInput.files?.[0];
203
- if (file) {
204
- const arrayBuffer = await file.arrayBuffer();
205
- await fs.writeFile('/uploaded-file', new Uint8Array(arrayBuffer));
206
- }
207
-
208
- // Write binary data from fetch
209
- const response = await fetch('/api/image.png');
210
- const arrayBuffer = await response.arrayBuffer();
211
- await fs.writeFile('/downloaded-image.png', new Uint8Array(arrayBuffer));
212
- ```
213
-
214
- **Parameters:**
215
-
216
- - `path`: The path to the file to write
217
- - `data`: The data to write (string, Uint8Array, or ArrayBuffer)
218
- - `encoding` (optional): The encoding to use when writing string data ('utf-8', 'utf-16le', 'ascii', 'latin1', 'base64', 'hex')
219
-
220
- **Binary File Handling:**
221
-
222
- - Pass `Uint8Array` or `ArrayBuffer` directly for binary data
223
- - Use with file uploads, image processing, or any binary content
224
- - Supports various text encodings for string data
225
-
226
- ### Append File
227
-
228
- #### `appendFile(path: string, data: string | Uint8Array | ArrayBuffer, encoding?: Encoding): Promise<void>`
229
-
230
- Append data to the end of a file.
231
-
232
- ```typescript
233
- // Append text to a log file
234
- await fs.appendFile('/logs/app.log', `[${new Date().toISOString()}] User logged in\n`);
235
-
236
- // Append binary data
237
- const additionalData = new Uint8Array([6, 7, 8]);
238
- await fs.appendFile('/data/binary.dat', additionalData);
239
- ```
240
-
241
- ### Create Directory
242
-
243
- #### `mkdir(path: string, options?: { recursive?: boolean }): Promise<void>`
244
-
245
- Create a directory.
246
-
247
- ```typescript
248
- // Create a single directory
249
- await fs.mkdir('/users/john');
250
-
251
- // Create nested directories
252
- await fs.mkdir('/users/john/documents/projects', { recursive: true });
253
- ```
254
-
255
- **Parameters:**
256
-
257
- - `path`: The path where the directory should be created
258
- - `options.recursive` (optional): Whether to create parent directories if they don't exist
259
-
260
- ### Read Directory
261
-
262
- #### `readDir(path: string): Promise<DirentData[]>`
263
-
264
- Read a directory's contents.
265
-
266
- ```typescript
267
- // Get simple list of names
268
- const files = await fs.readDir('/users/john/documents');
269
- console.log('Files:', files); // ['readme.txt', 'config.json', 'images']
270
-
271
- // Get detailed information
272
- const detailed = await fs.readDir('/users/john/documents');
273
- detailed.forEach(item => {
274
- console.log(`${item.name} - ${item.isFile ? 'file' : 'directory'}`);
275
- });
276
- ```
277
-
278
- **Returns:**
279
-
280
- - `Promise<DirentData[]>` - Always returns detailed file/directory information
281
-
282
- ### Get Stats
283
-
284
- #### `stat(path: string): Promise<FileStat>`
285
-
286
- Get file or directory statistics. If hashing is enabled globally, file hashes will be included automatically.
287
-
288
- ```typescript
289
- // Basic stats
290
- const stats = await fs.stat('/config/settings.json');
291
- console.log(`File size: ${stats.size} bytes`);
292
- console.log(`Is file: ${stats.isFile}`);
293
- console.log(`Modified: ${stats.mtime}`);
294
-
295
- // If hashing is enabled globally, hash will be included
296
- if (stats.hash) {
297
- console.log(`Hash: ${stats.hash}`);
298
- }
299
- ```
300
-
301
- **Parameters:**
302
-
303
- - `path`: The path to the file or directory
304
-
305
- **Returns:** `Promise<FileStat>` - File/directory statistics
306
-
307
- **Note:** File hashing is controlled globally via the constructor options or `setOptions()` method. When enabled, all file stats will automatically include hash information.
308
-
309
- ### Check Existence
310
-
311
- #### `exists(path: string): Promise<boolean>`
312
-
313
- Check if a file or directory exists.
314
-
315
- ```typescript
316
- const exists = await fs.exists('/config/settings.json');
317
- console.log(`File exists: ${exists}`);
318
- ```
319
-
320
- **Returns:** `Promise<boolean>` - True if the file or directory exists
321
-
322
- ### Remove Path
323
-
324
- #### `remove(path: string, options?: { recursive?: boolean; force?: boolean }): Promise<void>`
325
-
326
- Remove files and directories.
327
-
328
- ```typescript
329
- // Remove a file
330
- await fs.remove('/path/to/file.txt');
331
-
332
- // Remove a directory and all its contents
333
- await fs.remove('/path/to/directory', { recursive: true });
334
-
335
- // Remove with force (ignore if doesn't exist)
336
- await fs.remove('/maybe/exists', { force: true });
337
- ```
338
-
339
- **Parameters:**
340
-
341
- - `path`: The path to remove
342
- - `options.recursive` (optional): Whether to remove directories recursively (default: false)
343
- - `options.force` (optional): Whether to ignore errors if the path doesn't exist (default: false)
344
-
345
- ### Copy Path
346
-
347
- #### `copy(source: string, destination: string, options?: { recursive?: boolean; force?: boolean }): Promise<void>`
348
-
349
- Copy files and directories.
350
-
351
- ```typescript
352
- // Copy a file
353
- await fs.copy('/source/file.txt', '/dest/file.txt');
354
-
355
- // Copy a directory and all its contents
356
- await fs.copy('/source/dir', '/dest/dir', { recursive: true });
357
-
358
- // Copy without overwriting existing files
359
- await fs.copy('/source', '/dest', { recursive: true, force: false });
360
- ```
361
-
362
- **Parameters:**
363
-
364
- - `source`: The source path to copy from
365
- - `destination`: The destination path to copy to
366
- - `options.recursive` (optional): Whether to copy directories recursively (default: false)
367
- - `options.force` (optional): Whether to overwrite existing files (default: true)
368
-
369
- ### Rename Path
370
-
371
- #### `rename(oldPath: string, newPath: string): Promise<void>`
372
-
373
- Rename a file or directory.
374
-
375
- ```typescript
376
- await fs.rename('/old/path/file.txt', '/new/path/renamed.txt');
377
- ```
378
-
379
- **Parameters:**
380
-
381
- - `oldPath`: The current path of the file or directory
382
- - `newPath`: The new path for the file or directory
383
-
384
- ### Clear Directory
385
-
386
- #### `clear(path?: string): Promise<void>`
387
-
388
- Clear all contents of a directory without removing the directory itself.
389
-
390
- ```typescript
391
- // Clear root directory contents
392
- await fs.clear('/');
393
-
394
- // Clear specific directory contents
395
- await fs.clear('/data');
396
- ```
397
-
398
- **Parameters:**
399
-
400
- - `path` (optional): The path to the directory to clear (default: '/')
401
-
402
- ### Index File System
403
-
404
- #### `index(): Promise<Map<string, FileStat>>`
405
-
406
- Recursively list all files and directories with their stats. If hashing is enabled globally, file hashes will be included automatically.
407
-
408
- ```typescript
409
- // Get complete file system index
410
- const index = await fs.index();
411
-
412
- // Iterate through all files and directories
413
- for (const [path, stat] of index) {
414
- console.log(`${path}: ${stat.isFile ? 'file' : 'directory'} (${stat.size} bytes)`);
415
- if (stat.hash) console.log(` Hash: ${stat.hash}`);
416
- }
417
-
418
- // Get specific file stats
419
- const fileStats = index.get('/data/config.json');
420
- if (fileStats) {
421
- console.log(`File size: ${fileStats.size} bytes`);
422
- if (fileStats.hash) console.log(`Hash: ${fileStats.hash}`);
423
- }
424
- ```
425
-
426
- **Returns:** `Promise<Map<string, FileStat>>` - Map of path => FileStat
427
-
428
- **Note:** File hashing is controlled globally via the constructor options or `setOptions()` method. When enabled, all file stats in the index will automatically include hash information.
429
-
430
- ### Sync File System
431
-
432
- #### `sync(entries: [string, string | Uint8Array | Blob][], options?: { cleanBefore?: boolean }): Promise<void>`
433
-
434
- Synchronize the file system with external data.
435
-
436
- ```typescript
437
- // Sync with external data
438
- const entries: [string, string | Uint8Array | Blob][] = [
439
- ['/config.json', JSON.stringify({ theme: 'dark' })],
440
- ['/data/binary.dat', new Uint8Array([1, 2, 3, 4])],
441
- ['/upload.txt', new Blob(['file content'], { type: 'text/plain' })]
442
- ];
443
-
444
- // Sync without clearing existing files
445
- await fs.sync(entries);
446
-
447
- // Clean file system and then sync
448
- await fs.sync(entries, { cleanBefore: true });
449
- ```
450
-
451
- **Parameters:**
452
-
453
- - `entries`: Array of [path, data] tuples to sync
454
- - `options.cleanBefore` (optional): Whether to clear the file system before syncing (default: false)
455
-
456
- ### Watch
457
-
458
- #### `watch(path: string, options?: WatchOptions): Promise<void>`
459
-
460
- Start watching a file or directory for changes. Detected changes are sent via BroadcastChannel
461
- using the channel name specified in the `broadcastChannel` option.
462
-
463
- ```typescript
464
- // Start watching a directory recursively (default behavior)
465
- await fs.watch('/docs');
466
-
467
- // Start watching a directory shallow (only immediate children)
468
- await fs.watch('/docs', { recursive: false });
469
-
470
- // Watch a single file (non-recursive)
471
- await fs.watch('/config.json', { recursive: false });
472
-
473
- // Watch with minimatch patterns and include/exclude options
474
- await fs.watch('/**/*.js', {
475
- recursive: true,
476
- include: ['**/*.js', '**/*.ts'],
477
- exclude: ['**/dist/**', '**/node_modules/**']
478
- });
479
-
480
- // Listen for changes via BroadcastChannel
481
- const channel = new BroadcastChannel('opfs-worker'); // or your custom channel name
482
- channel.onmessage = (event) => {
483
- const { path, type, isDirectory, timestamp, hash } = event.data;
484
- console.log(`File ${path} was ${type} at ${timestamp}`);
485
- if (hash) console.log(`Hash: ${hash}`);
486
- };
487
- ```
488
-
489
- **Parameters:**
490
-
491
- - `path`: File or directory to watch (supports minimatch glob patterns)
492
- - `options` (optional): Watch options
493
- - `options.recursive` (optional): Whether to watch recursively (default: `true`)
494
- - `true`: Watch the entire directory tree
495
- - `false`: Only watch the specified path and its immediate children (shallow watching)
496
- - `options.include` (optional): Glob patterns to include in watching (minimatch syntax, default: `['**']`)
497
- - `options.exclude` (optional): Glob patterns to exclude from watching (minimatch syntax, default: `[]`)
498
-
499
- **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 `createOPFS()` function automatically handles the BroadcastChannel setup.
500
-
501
- #### Watch Behavior
502
-
503
- The watch system provides real-time change detection with the following characteristics:
504
-
505
- - **Immediate Events**: Events are sent immediately when file system operations occur
506
- - **Watched Paths Only**: Events are only sent for paths that are actively being watched
507
- - **Minimatch Support**: Watch paths support glob patterns like `/**/*.js`, `*.txt`, etc.
508
- - **Include/Exclude Filters**: Fine-grained control over which files trigger events
509
- - **Internal Changes Only**: The worker detects changes made through its own operations
510
- - **Efficient**: Only watched paths generate events, reducing unnecessary broadcasts
511
-
512
- **Example Watch Patterns:**
513
-
514
- ```typescript
515
- // Watch all JavaScript files recursively
516
- await fs.watch('/**/*.js');
517
-
518
- // Watch source files but exclude build artifacts
519
- await fs.watch('/', {
520
- recursive: true,
521
- include: ['**/*.ts', '**/*.js', '**/*.tsx', '**/*.jsx'],
522
- exclude: ['**/node_modules/**', '**/dist/**', '**/*.d.ts']
523
- });
524
-
525
- // Watch immediate children only (shallow)
526
- await fs.watch('/data/*', { recursive: false });
527
-
528
- // Watch specific file types in multiple directories
529
- await fs.watch('/**/*.{json,yaml,yml}');
530
- ```
531
-
532
- ### Unwatch
533
-
534
- #### `unwatch(path: string): void`
535
-
536
- Stop watching a watched path.
537
-
538
- ```typescript
539
- fs.unwatch('/docs');
540
- ```
541
-
542
- ### Dispose
543
-
544
- #### `dispose(): void`
545
-
546
- Dispose of resources and clean up the file system instance. This method should be called when the file system instance is no longer needed to properly clean up resources like the broadcast channel and watch timers.
547
-
548
- ```typescript
549
- // Clean up resources when done
550
- fs.dispose();
551
- ```
552
-
553
- **Note:** This method closes the broadcast channel, clears watch timers, and cleans up all watched paths. Call this when you're done with the file system instance to prevent memory leaks.
554
-
555
- ### Configuration
556
-
557
- #### `setOptions(options: { root?: string; hashAlgorithm?: null | false | 'etag' | 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512'; maxFileSize?: number }): Promise<void>`
558
-
559
- Update configuration options for the file system, including root path, hash algorithm, and maximum file size for hashing.
560
-
561
- ```typescript
562
- // Change root path (automatically remounts)
563
- await fs.setOptions({ root: '/new-app' });
564
-
565
- // Default is 'etag' (mtime + size, no content read). Opt into SHA when needed:
566
- await fs.setOptions({ hashAlgorithm: 'SHA-256' });
567
-
568
- // Set custom maximum file size for SHA-* hashing (100MB)
569
- await fs.setOptions({ maxFileSize: 100 * 1024 * 1024 });
570
-
571
- // Disable hashing
572
- await fs.setOptions({ hashAlgorithm: null });
573
-
574
- // Update multiple options at once
575
- await fs.setOptions({
576
- root: '/my-app',
577
- hashAlgorithm: 'etag',
578
- maxFileSize: 50 * 1024 * 1024 // 50MB (only used by SHA-*)
579
- });
580
- ```
581
-
582
- **Parameters:**
583
-
584
- - `options.root` (optional): Root path for the file system
585
- - `options.hashAlgorithm` (optional): `'etag'` (default), `'SHA-*'`, or `null`/`false` to disable
586
- - `options.maxFileSize` (optional): Maximum file size in bytes for SHA-\* hashing (default: 50MB); ignored by `'etag'`
587
-
588
- **Note:** When the `root` option is changed, the file system automatically remounts to the new location. All other options are updated immediately.
589
-
590
- ### Resolve Path
591
-
592
- #### `realpath(path: string): Promise<string>`
593
-
594
- Resolve a path to an absolute path.
595
-
596
- ```typescript
597
- // Resolve relative path
598
- const absolute = await fs.realpath('./config/../data/file.txt');
599
- console.log(absolute); // '/data/file.txt'
600
- ```
601
-
602
- **Returns:** `Promise<string>` - The absolute normalized path
603
-
604
- **Throws:** `ExistenceError` if the path doesn't exist
605
-
606
- ## File Descriptors
607
-
608
- OPFS Worker provides low-level file I/O operations through file descriptors, similar to POSIX file descriptors. File descriptors are useful for:
609
-
610
- - **Large file operations**: Reading/writing files in chunks without loading entire content into memory
611
- - **Streaming operations**: Processing files sequentially or in specific positions
612
- - **Performance-critical applications**: Direct file access without the overhead of high-level methods
613
- - **Binary data manipulation**: Working with raw bytes at specific file positions
614
-
615
- For comprehensive documentation on file descriptors, see [File Descriptors Guide](file-descriptors.md).
616
-
617
- ### File Descriptors Overview
618
-
619
- File descriptors provide efficient, low-level access to files for reading, writing, and manipulating file data. They maintain a current position that advances with read/write operations and support both sequential and random access patterns.
620
-
621
- **Key Benefits:**
622
-
623
- - **Efficient I/O**: Direct access to file data without intermediate buffers
624
- - **Position control**: Read/write at specific file positions or advance automatically
625
- - **Resource management**: Automatic cleanup when closed
626
- - **Performance**: Better for large files and streaming operations
627
-
628
- ### File Descriptor Methods
629
-
630
- The following methods are available for working with file descriptors:
631
-
632
- - **`open(path, options?)`** - Open a file and return a file descriptor
633
- - **`read(fd, buffer, offset, length, position?)`** - Read data from a file descriptor
634
- - **`write(fd, buffer, offset?, length?, position?)`** - Write data to a file descriptor
635
- - **`fstat(fd)`** - Get file status information by file descriptor
636
- - **`ftruncate(fd, size?)`** - Truncate file to specified size
637
- - **`fsync(fd)`** - Synchronize file data to storage
638
- - **`close(fd)`** - Close a file descriptor
639
-
640
- **Quick Example:**
641
-
642
- ```typescript
643
- const fd = await fs.open('/data/file.txt');
644
- const buffer = new Uint8Array(1024);
645
- const bytesRead = await fs.read(fd, buffer, 0, 1024, null);
646
- console.log(`Read ${bytesRead} bytes`);
647
- await fs.close(fd);
648
- ```
649
-
650
- **Important:** Always close file descriptors when you're done with them to prevent resource leaks.
651
-
652
- ## Binary File Handling
653
-
654
- This library provides comprehensive support for binary files, making it easy to work with images, documents, and other binary data.
655
-
656
- ### Reading Binary Files
657
-
658
- ```typescript
659
- // Read as binary data
660
- const imageData = await fs.readFile('/image.png', 'binary');
661
- const documentData = await fs.readFile('/document.pdf', 'binary');
662
-
663
- // Convert to Blob for use with URLs
664
- const imageBuffer = await fs.readFile('/image.png', 'binary');
665
- const blob = new Blob([imageBuffer], { type: 'image/png' });
666
- const url = URL.createObjectURL(blob);
667
-
668
- // Display image
669
- const img = document.createElement('img');
670
- img.src = url;
671
- document.body.appendChild(img);
672
- ```
673
-
674
- ### Writing Binary Files
675
-
676
- ```typescript
677
- // Write binary data directly
678
- const binaryData = new Uint8Array([1, 2, 3, 4, 5]);
679
- await fs.writeFile('/data.bin', binaryData);
680
-
681
- // From file input
682
- const fileInput = document.getElementById('file') as HTMLInputElement;
683
- const file = fileInput.files?.[0];
684
- if (file) {
685
- const arrayBuffer = await file.arrayBuffer();
686
- await fs.writeFile('/uploaded-file', new Uint8Array(arrayBuffer));
687
- }
688
-
689
- // From fetch response
690
- const response = await fetch('/api/download/file.pdf');
691
- const arrayBuffer = await response.arrayBuffer();
692
- await fs.writeFile('/downloaded-file.pdf', new Uint8Array(arrayBuffer));
693
-
694
- // From canvas
695
- const canvas = document.createElement('canvas');
696
- const ctx = canvas.getContext('2d');
697
- // ... draw something ...
698
- canvas.toBlob(async (blob) => {
699
- if (blob) {
700
- const arrayBuffer = await blob.arrayBuffer();
701
- await fs.writeFile('/canvas-image.png', new Uint8Array(arrayBuffer));
702
- }
703
- });
704
- ```
705
-
706
- ### Working with Different Data Types
707
-
708
- ```typescript
709
- // Convert between different binary formats
710
- const uint8Array = new Uint8Array([1, 2, 3, 4, 5]);
711
- const arrayBuffer = uint8Array.buffer;
712
-
713
- // All of these work the same way
714
- await fs.writeFile('/data1.bin', uint8Array);
715
- await fs.writeFile('/data2.bin', arrayBuffer);
716
- await fs.writeFile('/data3.bin', new Uint8Array(arrayBuffer));
717
-
718
- // Read back as binary
719
- const data = await fs.readFile('/data1.bin', 'binary');
720
- console.log(data); // Uint8Array
721
- ```
722
-
723
- ### File Upload and Download
724
-
725
- ```typescript
726
- // Handle file uploads
727
- const handleFileUpload = async (file: File) => {
728
- const arrayBuffer = await file.arrayBuffer();
729
- await fs.writeFile(`/uploads/${file.name}`, new Uint8Array(arrayBuffer));
730
- };
731
-
732
- // Create downloadable files
733
- const createDownloadLink = async (filePath: string, fileName: string) => {
734
- const data = await fs.readFile(filePath, 'binary');
735
- const blob = new Blob([data]);
736
- const url = URL.createObjectURL(blob);
737
-
738
- const a = document.createElement('a');
739
- a.href = url;
740
- a.download = fileName;
741
- a.click();
742
-
743
- URL.revokeObjectURL(url);
744
- };
745
- ```
746
-
747
- ### Supported Encodings
748
-
749
- The library supports various encodings for text files:
750
-
751
- - `'utf-8'` (default) - UTF-8 encoding
752
- - `'utf-16le'` - UTF-16 little-endian
753
- - `'ascii'` - ASCII encoding
754
- - `'latin1'` - Latin-1 encoding
755
- - `'base64'` - Base64 encoding
756
- - `'hex'` - Hexadecimal encoding
757
- - `'binary'` - Raw binary data (returns Uint8Array)
758
-
759
- ## Utility Functions
760
-
761
- The library exports several utility functions that can be used independently:
762
-
763
- ### Path Utilities
764
-
765
- ```typescript
766
- import { basename, dirname, normalizePath, resolvePath, extname } from 'opfs-worker';
767
-
768
- // Extract filename from path
769
- basename('/path/to/file.txt'); // 'file.txt'
770
- basename('/path/to/directory/'); // ''
771
-
772
- // Extract directory path
773
- dirname('/path/to/file.txt'); // '/path/to'
774
- dirname('file.txt'); // '/'
775
-
776
- // Normalize path to start with '/'
777
- normalizePath('path/to/file'); // '/path/to/file'
778
- normalizePath('/path/to/file'); // '/path/to/file'
779
-
780
- // Resolve relative paths
781
- resolvePath('./config/../data/file.txt'); // '/data/file.txt'
782
- resolvePath('/path/to/../file.txt'); // '/path/file.txt'
783
-
784
- // Get file extension
785
- extname('/path/to/file.txt'); // '.txt'
786
- extname('/path/to/file'); // ''
787
- extname('/path/to/file.name.ext'); // '.ext'
788
- ```
789
-
790
- ### Data Conversion
791
-
792
- ```typescript
793
- import { convertBlobToUint8Array } from 'opfs-worker';
794
-
795
- // Convert Blob to Uint8Array
796
- const fileInput = document.getElementById('file') as HTMLInputElement;
797
- const file = fileInput.files?.[0];
798
- if (file) {
799
- const data = await convertBlobToUint8Array(file);
800
- await fs.writeFile('/uploaded-file', data);
801
- }
802
- ```
803
-
804
- ### File System Utilities
805
-
806
- ```typescript
807
- import { checkOPFSSupport, splitPath, joinPath } from 'opfs-worker';
808
-
809
- // Check if browser supports OPFS
810
- checkOPFSSupport(); // Throws error if not supported
811
-
812
- // Path manipulation
813
- splitPath('/path/to/file'); // ['path', 'to', 'file']
814
- joinPath(['path', 'to', 'file']); // '/path/to/file'
815
- ```