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
@@ -0,0 +1,57 @@
1
+ # SharedWorker
2
+
3
+ One `OPFSAsync` for every tab. Locks live in that single instance, so writes don’t stomp each other across tabs. Watch events go out on `BroadcastChannel` like everywhere else.
4
+
5
+ Same limits as [async](./async.md): Safari 26+ for writes, no FDs.
6
+
7
+ SharedWorkers are keyed by **script URL**, so we can’t inline the worker. Use the shipped file: `opfs-worker/shared.worker.js`.
8
+
9
+ ## With a bundler (Vite example)
10
+
11
+ ```typescript
12
+ import workerUrl from 'opfs-worker/shared.worker.js?url';
13
+ import { createOPFSShared } from 'opfs-worker/sharedworker';
14
+
15
+ const fs = createOPFSShared({ root: '/my-app', url: workerUrl });
16
+
17
+ await fs.writeText('/shared-config.json', '{}');
18
+ ```
19
+
20
+ ## Without a bundler
21
+
22
+ Default URL looks for `./shared.worker.js` next to the package files:
23
+
24
+ ```typescript
25
+ import { createOPFSShared } from 'opfs-worker/sharedworker';
26
+
27
+ const fs = createOPFSShared({ root: '/my-app' });
28
+ ```
29
+
30
+ Or pass your own instance:
31
+
32
+ ```typescript
33
+ const worker = new SharedWorker(
34
+ new URL('opfs-worker/shared.worker.js', import.meta.url),
35
+ { type: 'module', name: 'opfs-worker' }
36
+ );
37
+ const fs = createOPFSShared({ root: '/my-app', worker });
38
+ ```
39
+
40
+ ## Raw backend
41
+
42
+ ```typescript
43
+ const fs = createOPFSShared({ root: '/my-app', url: workerUrl });
44
+
45
+ await fs.backend.writeFile('/a.bin', bytes);
46
+ fs.worker; // SharedWorker
47
+
48
+ fs.dispose(); // closes this tab’s port only
49
+ ```
50
+
51
+ ## Notes
52
+
53
+ - `dispose()` does **not** kill the worker for other tabs — only your port.
54
+ - `setOptions` hits the shared instance, so keep options consistent across tabs.
55
+ - Same script URL + `name` (default `'opfs-worker'`) → same instance.
56
+
57
+ Also: [async](./async.md), [watching](./watching.md), [create helpers](../api/create.md).
@@ -0,0 +1,51 @@
1
+ # Streaming
2
+
3
+ Write big files without holding the whole thing in memory.
4
+
5
+ | | Method |
6
+ | --- | --- |
7
+ | Facade | `importStream(path, source, options?)` |
8
+ | Backend / raw | `writeStream(path, stream, onProgress?)` |
9
+
10
+ Both create or overwrite the file, return bytes written, and fire a watch event when done.
11
+
12
+ ## `importStream` (facade)
13
+
14
+ Takes a `ReadableStream<Uint8Array>`, or a `Blob` / `File` (we call `.stream()` for you):
15
+
16
+ ```typescript
17
+ import { createOPFS } from 'opfs-worker';
18
+
19
+ const fs = createOPFS({ root: '/my-app' });
20
+
21
+ const file = input.files[0];
22
+ await fs.importStream(`/uploads/${file.name}`, file, {
23
+ onProgress: (n) => console.log(`wrote ${n} bytes`),
24
+ });
25
+
26
+ const res = await fetch('/large.bin');
27
+ await fs.importStream('/cache/large.bin', res.body!);
28
+ ```
29
+
30
+ With a worker backend the facade transfers the stream and proxies `onProgress` — you don’t need Comlink `transfer` yourself.
31
+
32
+ ## `writeStream` (raw)
33
+
34
+ ```typescript
35
+ import { createOPFS } from 'opfs-worker';
36
+
37
+ const fs = createOPFS();
38
+ await fs.backend.writeStream('/data.bin', someBlob.stream(), (n) => console.log(n));
39
+ ```
40
+
41
+ ## When to use what
42
+
43
+ | API | Good for |
44
+ | --- | -------- |
45
+ | `writeFile` | Stuff already in memory |
46
+ | `importStream` / `writeStream` | Large `File` / `Blob` / network bodies |
47
+ | `createIndex` | Many small entries (Blobs here are still fully buffered) |
48
+
49
+ Dedicated path chunks through FDs; async path uses `createWritable()` (Safari 26+ for writes).
50
+
51
+ Also: [facade](../api/facade.md), [backend](../api/backend.md).
@@ -0,0 +1,35 @@
1
+ # Watching
2
+
3
+ Changes go out on a `BroadcastChannel` (default name `opfs-worker`). Nothing is emitted unless you `watch` a path.
4
+
5
+ ```typescript
6
+ import { createOPFS } from 'opfs-worker';
7
+
8
+ const channel = new BroadcastChannel('opfs-worker');
9
+ channel.onmessage = (e) => console.log(e.data);
10
+
11
+ const fs = createOPFS({
12
+ root: '/my-app',
13
+ namespace: 'my-app:fs',
14
+ broadcastChannel: channel, // or just the string 'opfs-worker'
15
+ });
16
+
17
+ const stop = fs.watch('/', {
18
+ recursive: true,
19
+ include: ['**/*.json'],
20
+ exclude: ['tmp/**'],
21
+ });
22
+
23
+ await fs.writeFile('/config.json', '{}');
24
+ // → { namespace, path, type: 'added' | 'changed' | 'removed', isDirectory, timestamp, hash? }
25
+
26
+ stop(); // or fs.unwatch('/')
27
+ ```
28
+
29
+ `watch` returns an unsubscribe function. Options: [`WatchOptions`](../types.md#watchoptions). Payload: [`WatchEvent`](../types.md#watchevent).
30
+
31
+ ## Gotchas
32
+
33
+ - Into a worker, pass a **channel name** (string). You can’t post a `BroadcastChannel` instance across the wire. On the main thread the facade accepts either.
34
+ - SharedWorker: one backend + one channel → every listening tab sees the same events.
35
+ - Whether events include `hash` depends on [hashing](./hashing.md) settings.
@@ -0,0 +1,41 @@
1
+ # Migration (1.x → 2.x)
2
+
3
+ ## Renames
4
+
5
+ | Was | Now |
6
+ | ------------------------ | ------------------------------------------------------------------------------------ |
7
+ | `createWorker` | `createOPFSDedicated` (`createOPFS` alias; deprecated `createWorker` still exported) |
8
+ | `OPFSFileSystem` | `OPFSFacade` (deprecated alias kept) |
9
+ | `OPFSWorker` | `OPFSSync` |
10
+ | `opfs-worker/raw` | `opfs-worker/pure` |
11
+ | `opfs-worker/raw?worker` | `createOPFSDedicated()` + `fs.backend` / `fs.worker`, or `dedicated.worker.js` |
12
+ | `fs.sync(entries)` | `fs.createIndex(entries)` |
13
+
14
+ ```diff
15
+ - import { createWorker, OPFSFileSystem } from 'opfs-worker';
16
+ - const fs: OPFSFileSystem = createWorker({ root: '/my-app' });
17
+ + import { createOPFS, OPFSFacade } from 'opfs-worker';
18
+ + const fs: OPFSFacade = createOPFS({ root: '/my-app' });
19
+ ```
20
+
21
+ ```diff
22
+ - import { OPFSWorker } from 'opfs-worker/raw';
23
+ + import { OPFSSync } from 'opfs-worker/pure';
24
+ ```
25
+
26
+ ## New in 2.x
27
+
28
+ - Async: `createOPFSAsync` / `opfs-worker/async`
29
+ - SharedWorker: `createOPFSShared` / `opfs-worker/sharedworker`
30
+ - Prebuilt scripts: `dedicated.worker.js`, `shared.worker.js`
31
+ - Streaming: `importStream` / `writeStream`
32
+ - Escape hatch on every facade: `fs.backend` / `fs.worker`
33
+ - Clearer names: `createOPFSDedicated`, `createOPFSAsync`, `createOPFSShared`
34
+
35
+ ## Behaviour
36
+
37
+ - Concurrent `readFile` on one path takes the same exclusive lock as writes
38
+ - Multiple FDs on one path share one sync handle, each with its own cursor
39
+ - Dedicated `dispose()` terminates the browser `Worker`
40
+
41
+ Full entry map: [Choosing a mode](./choosing-a-mode.md).
package/docs/types.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Types
2
2
 
3
- This document contains all TypeScript types and interfaces provided by OPFS Worker.
3
+ TypeScript types shipped with the package.
4
4
 
5
5
  ## Core Types
6
6
 
@@ -68,21 +68,35 @@ interface WatchOptions {
68
68
  - `include`: Glob patterns to include in watching (default: all files)
69
69
  - `exclude`: Glob patterns to exclude from watching (default: none)
70
70
 
71
- ### `RemoteOPFSWorker`
71
+ ### `OPFSApi`
72
72
 
73
- Remote file system interface type for Comlink communication.
73
+ Promise-based fs API surface shared by all backends — a Comlink proxy to `OPFSSync` in a worker, or an in-process `OPFSAsync` instance. This is what `OPFSFacade` talks to (see `OPFSBackend` in [Create helpers](./api/create.md)).
74
74
 
75
75
  ```typescript
76
- type RemoteOPFSWorker = Remote<OPFSWorker>;
76
+ type OPFSApi = { [K in keyof OPFSSync]: OPFSSync[K] };
77
77
  ```
78
78
 
79
- This type represents the remote interface when using the worker with Comlink.
79
+ ### `PathLike`
80
+
81
+ ```typescript
82
+ type PathLike = string | URL;
83
+ ```
84
+
85
+ ### `FileOpenOptions`
86
+
87
+ ```typescript
88
+ interface FileOpenOptions {
89
+ create?: boolean;
90
+ exclusive?: boolean;
91
+ truncate?: boolean;
92
+ }
93
+ ```
80
94
 
81
95
  ## Configuration Types
82
96
 
83
97
  ### `OPFSOptions`
84
98
 
85
- Configuration options for creating an OPFS Worker instance.
99
+ Configuration for all backends. Human-readable table: [Create helpers → Options](./api/create.md#options).
86
100
 
87
101
  ```typescript
88
102
  interface OPFSOptions {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opfs-worker",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "A robust TypeScript library for working with Origin Private File System (OPFS) through Web Workers",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -18,7 +18,27 @@
18
18
  "source": "./src/index.pure.ts",
19
19
  "import": "./dist/index.pure.js",
20
20
  "require": "./dist/index.pure.cjs"
21
- }
21
+ },
22
+ "./sync": {
23
+ "types": "./dist/index.sync.d.ts",
24
+ "source": "./src/index.sync.ts",
25
+ "import": "./dist/index.sync.js",
26
+ "require": "./dist/index.sync.cjs"
27
+ },
28
+ "./async": {
29
+ "types": "./dist/index.async.d.ts",
30
+ "source": "./src/index.async.ts",
31
+ "import": "./dist/index.async.js",
32
+ "require": "./dist/index.async.cjs"
33
+ },
34
+ "./sharedworker": {
35
+ "types": "./dist/index.sharedworker.d.ts",
36
+ "source": "./src/index.sharedworker.ts",
37
+ "import": "./dist/index.sharedworker.js",
38
+ "require": "./dist/index.sharedworker.cjs"
39
+ },
40
+ "./dedicated.worker.js": "./dist/dedicated.worker.js",
41
+ "./shared.worker.js": "./dist/shared.worker.js"
22
42
  },
23
43
  "sideEffects": false,
24
44
  "files": [
@@ -29,9 +49,15 @@
29
49
  "LICENSE"
30
50
  ],
31
51
  "scripts": {
32
- "build": "vite build && tsc -p tsconfig.build.json",
52
+ "build": "bun run build:lib && bun run build:workers && bun run build:types",
53
+ "build:lib": "vite build",
54
+ "build:workers": "bun run build:worker:dedicated && bun run build:worker:shared",
55
+ "build:worker:dedicated": "OPFS_WORKER=dedicated.worker vite build -c vite.worker.config.ts",
56
+ "build:worker:shared": "OPFS_WORKER=shared.worker vite build -c vite.worker.config.ts",
57
+ "build:types": "tsc -p tsconfig.build.json",
33
58
  "build:demo": "vite build demo --base=./",
34
59
  "dev": "concurrently \"vite build --watch --mode development\" \"tsc -p tsconfig.build.json --watch\"",
60
+ "dev:demo": "vite demo",
35
61
  "preview": "vite preview demo",
36
62
  "type-check": "tsc --noEmit",
37
63
  "lint": "eslint src --ext .ts,.tsx --fix --max-warnings=9999 --quiet",
@@ -63,18 +89,31 @@
63
89
  "homepage": "https://github.com/kachurun/opfs-worker#readme",
64
90
  "devDependencies": {
65
91
  "@changesets/cli": "^2.29.5",
92
+ "@codemirror/lang-css": "6.3.1",
93
+ "@codemirror/lang-html": "6.4.11",
94
+ "@codemirror/lang-javascript": "6.2.5",
95
+ "@codemirror/lang-json": "6.0.2",
96
+ "@codemirror/lang-markdown": "6.5.1",
97
+ "@codemirror/lang-xml": "6.1.0",
98
+ "@codemirror/theme-one-dark": "6.1.3",
66
99
  "@flexbe/eslint-config": "^1.0.11",
100
+ "@tailwindcss/vite": "4.3.3",
67
101
  "@types/minimatch": "^6.0.0",
68
102
  "@types/node": "^24.2.0",
69
103
  "@types/react": "^19.1.9",
70
104
  "@types/react-dom": "^19.1.7",
71
105
  "@typescript-eslint/eslint-plugin": "^8.39.0",
72
106
  "@typescript-eslint/parser": "^8.39.0",
107
+ "@uiw/react-codemirror": "4.25.11",
73
108
  "@vitest/coverage-v8": "^3.2.4",
109
+ "daisyui": "5.7.4",
74
110
  "eslint": "^9.32.0",
75
111
  "happy-dom": "^18.0.1",
112
+ "lucide-react": "1.26.0",
76
113
  "react": "^19.1.1",
77
114
  "react-dom": "^19.1.1",
115
+ "react-icons": "5.7.0",
116
+ "tailwindcss": "4.3.3",
78
117
  "typescript": "^5.9.2",
79
118
  "vite": "^7.0.6",
80
119
  "vitest": "^3.2.4"