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
package/dist/types.d.ts CHANGED
@@ -1,5 +1,4 @@
1
- import type { OPFSWorker } from './OPFSWorker';
2
- import type { Remote } from 'comlink';
1
+ import type { OPFSSync } from './core/OPFSSync';
3
2
  /**
4
3
  * Type for paths that can be either a string or URI
5
4
  */
@@ -37,8 +36,14 @@ export interface WatchEvent {
37
36
  timestamp: string;
38
37
  hash?: string;
39
38
  }
40
- export type { OPFSWorker };
41
- export type RemoteOPFSWorker = Remote<OPFSWorker>;
39
+ export type { OPFSSync };
40
+ /**
41
+ * Promise-based fs API surface shared by all backends: a Comlink proxy to
42
+ * `OPFSSync` in a worker, or an in-process `OPFSAsync` instance.
43
+ */
44
+ export type OPFSApi = {
45
+ [K in keyof OPFSSync]: OPFSSync[K];
46
+ };
42
47
  export interface OPFSOptions {
43
48
  /** Root path for the file system (default: '/') */
44
49
  root?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEtC;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,GAAG,CAAC;AAEpC,MAAM,MAAM,IAAI,GAAG,MAAM,GAAG,WAAW,CAAC;AAExC,MAAM,MAAM,cAAc,GAAG,OAAO,GAChC,MAAM,GACN,OAAO,GACP,SAAS,GACT,UAAU,GACV,MAAM,GACN,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,KAAK,CAAC;AAEV,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;AAEtC,MAAM,MAAM,QAAQ,GAAG,cAAc,GAAG,cAAc,CAAC;AAEvD,MAAM,WAAW,QAAQ;IACrB,IAAI,EAAE,IAAI,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;IACrB,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;CACxB;AAED,oBAAY,cAAc;IACtB,KAAK,UAAU;IACf,OAAO,YAAY;IACnB,OAAO,YAAY;CACtB;AAED,MAAM,WAAW,UAAU;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,cAAc,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,YAAY,EAAE,UAAU,EAAE,CAAC;AAC3B,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;AAElD,MAAM,WAAW,WAAW;IACxB,mDAAmD;IACnD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kFAAkF;IAClF,aAAa,CAAC,EAAE,IAAI,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;IACpF,6DAA6D;IAC7D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qEAAqE;IACrE,gBAAgB,CAAC,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAAC;CACvD;AAED,MAAM,WAAW,aAAa;IAC1B,2DAA2D;IAC3D,SAAS,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IACzB,mDAAmD;IACnD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC5B,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,eAAe;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;CACrB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEhD;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,GAAG,CAAC;AAEpC,MAAM,MAAM,IAAI,GAAG,MAAM,GAAG,WAAW,CAAC;AAExC,MAAM,MAAM,cAAc,GAAG,OAAO,GAChC,MAAM,GACN,OAAO,GACP,SAAS,GACT,UAAU,GACV,MAAM,GACN,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,KAAK,CAAC;AAEV,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;AAEtC,MAAM,MAAM,QAAQ,GAAG,cAAc,GAAG,cAAc,CAAC;AAEvD,MAAM,WAAW,QAAQ;IACrB,IAAI,EAAE,IAAI,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;IACrB,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;CACxB;AAED,oBAAY,cAAc;IACtB,KAAK,UAAU;IACf,OAAO,YAAY;IACnB,OAAO,YAAY;CACtB;AAED,MAAM,WAAW,UAAU;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,cAAc,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,YAAY,EAAE,QAAQ,EAAE,CAAC;AAEzB;;;GAGG;AACH,MAAM,MAAM,OAAO,GAAG;KAAG,CAAC,IAAI,MAAM,QAAQ,GAAG,QAAQ,CAAC,CAAC,CAAC;CAAE,CAAC;AAE7D,MAAM,WAAW,WAAW;IACxB,mDAAmD;IACnD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kFAAkF;IAClF,aAAa,CAAC,EAAE,IAAI,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;IACpF,6DAA6D;IAC7D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qEAAqE;IACrE,gBAAgB,CAAC,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAAC;CACvD;AAED,MAAM,WAAW,aAAa;IAC1B,2DAA2D;IAC3D,SAAS,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IACzB,mDAAmD;IACnD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC5B,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,eAAe;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;CACrB"}
@@ -0,0 +1,30 @@
1
+ import type { OPFSOptions, OPFSSync } from '../types';
2
+ import type { Remote } from 'comlink';
3
+ type RemoteOPFSSync = Remote<OPFSSync>;
4
+ export interface DedicatedWorkerOptions extends OPFSOptions {
5
+ /**
6
+ * URL of the worker script, e.g. `import url from 'opfs-worker/dedicated.worker.js?url'` (Vite).
7
+ *
8
+ * Defaults to the inlined worker (no URL needed). Pass an explicit url when you
9
+ * prefer the self-contained file (strict CSP without `blob:`, or DIY hosting).
10
+ */
11
+ url?: string | URL;
12
+ /** Bring your own Worker instance (overrides `url`) */
13
+ worker?: Worker;
14
+ }
15
+ export interface RawWorker {
16
+ /** Comlink proxy to `OPFSSync` (bytes in / bytes out) */
17
+ fs: RemoteOPFSSync;
18
+ /** Underlying browser Worker */
19
+ worker: Worker;
20
+ /** Calls worker `dispose()` then `terminate()` */
21
+ dispose: () => void;
22
+ }
23
+ /**
24
+ * Internal helper: spawn a dedicated worker and wrap `OPFSSync` with Comlink.
25
+ * Prefer {@link createOPFSDedicated}; access the proxy / Worker via
26
+ * `facade.backend` / `facade.worker`.
27
+ */
28
+ export declare function createDedicatedWorker(options?: DedicatedWorkerOptions): RawWorker;
29
+ export {};
30
+ //# sourceMappingURL=createDedicatedWorker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createDedicatedWorker.d.ts","sourceRoot":"","sources":["../../src/worker/createDedicatedWorker.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAItC,KAAK,cAAc,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;AAEvC,MAAM,WAAW,sBAAuB,SAAQ,WAAW;IACvD;;;;;OAKG;IACH,GAAG,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;IACnB,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,SAAS;IACtB,yDAAyD;IACzD,EAAE,EAAE,cAAc,CAAC;IACnB,gCAAgC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,kDAAkD;IAClD,OAAO,EAAE,MAAM,IAAI,CAAC;CACvB;AAeD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,sBAA2B,GAAG,SAAS,CAuBrF"}
@@ -0,0 +1,37 @@
1
+ import type { OPFSAsync } from '../core/OPFSAsync';
2
+ import type { OPFSOptions } from '../types';
3
+ import type { Remote } from 'comlink';
4
+ type RemoteOPFSAsync = Remote<OPFSAsync>;
5
+ export interface SharedWorkerOptions extends OPFSOptions {
6
+ /**
7
+ * URL of the worker script, e.g. `import url from 'opfs-worker/shared.worker.js?url'` (Vite).
8
+ *
9
+ * Defaults to `new URL('./shared.worker.js', import.meta.url)`, which works when
10
+ * `opfs-worker` is served as-is (CDN, unbundled deps). When your bundler inlines
11
+ * the package into app chunks, pass the url explicitly.
12
+ */
13
+ url?: string | URL;
14
+ /** Bring your own SharedWorker instance (overrides `url`) */
15
+ worker?: SharedWorker;
16
+ /** Worker name — tabs with the same script URL + name share one instance (default: 'opfs-worker') */
17
+ name?: string;
18
+ }
19
+ export interface RawSharedWorker {
20
+ /** Comlink proxy to the `OPFSAsync` instance shared by all connected tabs */
21
+ fs: RemoteOPFSAsync;
22
+ /** Underlying browser SharedWorker */
23
+ worker: SharedWorker;
24
+ /** Closes this tab's port; the worker keeps running for other tabs */
25
+ dispose: () => void;
26
+ }
27
+ /**
28
+ * Internal helper: connect to the SharedWorker and wrap `OPFSAsync` with Comlink.
29
+ * Prefer {@link createOPFSShared}; access the proxy / SharedWorker via
30
+ * `facade.backend` / `facade.worker`.
31
+ *
32
+ * Note: `OPFSOptions` are applied via `setOptions()` on the shared instance, so
33
+ * they affect every connected tab — use the same options in all tabs.
34
+ */
35
+ export declare function createSharedWorker(options?: SharedWorkerOptions): RawSharedWorker;
36
+ export {};
37
+ //# sourceMappingURL=createSharedWorker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createSharedWorker.d.ts","sourceRoot":"","sources":["../../src/worker/createSharedWorker.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEtC,KAAK,eAAe,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;AAEzC,MAAM,WAAW,mBAAoB,SAAQ,WAAW;IACpD;;;;;;OAMG;IACH,GAAG,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;IACnB,6DAA6D;IAC7D,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,qGAAqG;IACrG,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC5B,6EAA6E;IAC7E,EAAE,EAAE,eAAe,CAAC;IACpB,sCAAsC;IACtC,MAAM,EAAE,YAAY,CAAC;IACrB,sEAAsE;IACtE,OAAO,EAAE,MAAM,IAAI,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,mBAAwB,GAAG,eAAe,CA0BrF"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=dedicated.worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dedicated.worker.d.ts","sourceRoot":"","sources":["../../src/worker/dedicated.worker.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=shared.worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.worker.d.ts","sourceRoot":"","sources":["../../src/worker/shared.worker.ts"],"names":[],"mappings":""}
package/docs/README.md ADDED
@@ -0,0 +1,30 @@
1
+ # Docs
2
+
3
+ New here? Start with [Choosing a mode](./choosing-a-mode.md).
4
+
5
+ ## Guides
6
+
7
+ | Guide | About |
8
+ | ----------------------------------------- | -------------------------------------------------- |
9
+ | [Choosing a mode](./choosing-a-mode.md) | Which entry / backend to pick |
10
+ | [Dedicated worker](./guides/dedicated.md) | Default path + DIY worker script |
11
+ | [Async (no worker)](./guides/async.md) | `createOPFSAsync` on the current thread |
12
+ | [SharedWorker](./guides/sharedworker.md) | One fs shared by all tabs |
13
+ | [Pure classes](./guides/pure.md) | Drop `OPFSSync` / `OPFSAsync` into your own worker |
14
+ | [Streaming](./guides/streaming.md) | Large files with `importStream` |
15
+ | [Watching](./guides/watching.md) | Change events over `BroadcastChannel` |
16
+ | [Hashing](./guides/hashing.md) | etag vs SHA |
17
+
18
+ ## API
19
+
20
+ | Page | About |
21
+ | ----------------------------------------- | ------------------------------------- |
22
+ | [Create helpers](./api/create.md) | `createOPFS*` + **options table** |
23
+ | [Facade](./api/facade.md) | Node-like methods and aliases |
24
+ | [Backend](./api/backend.md) | `BaseOPFS` / `OPFSSync` / `OPFSAsync` |
25
+ | [File descriptors](./file-descriptors.md) | `open` / `read` / `write` / … |
26
+ | [Types](./types.md) | Types and errors |
27
+
28
+ ## Migration
29
+
30
+ [1.x → 2.x](./migration.md)
@@ -0,0 +1,36 @@
1
+ # Backend API
2
+
3
+ Classes from `opfs-worker/pure` (also re-exported from `/sync`, `/async`, `/sharedworker` where it makes sense). Bytes only — no encoding helpers.
4
+
5
+ ```
6
+ BaseOPFS mkdir, stat, readDir, watch, index, createIndex, …
7
+ ├─ OPFSSync sync access handles + FDs + writeStream
8
+ └─ OPFSAsync getFile / createWritable + writeStream (no FDs)
9
+ ```
10
+
11
+ `OPFSApi` = the `OPFSSync` method surface — both backends and Comlink proxies satisfy it.
12
+
13
+ ## Shared methods (`BaseOPFS`)
14
+
15
+ Path ops: `mkdir`, `stat`, `readDir`, `exists`, `clear`, `remove`, `rename`, `copy`, `realpath`, `index`, `createIndex`, `watch`, `unwatch`, `setOptions`, `dispose`.
16
+
17
+ Subclasses implement:
18
+
19
+ - `readFile` / `writeFile` / `appendFile`
20
+ - `writeStream(path, stream, onProgress?)`
21
+
22
+ ## `OPFSSync`
23
+
24
+ Dedicated-worker backend. Adds FD methods (`open` … `fsync`) and streams via chunked FD writes.
25
+
26
+ → [File descriptors](../file-descriptors.md), [dedicated guide](../guides/dedicated.md).
27
+
28
+ ## `OPFSAsync`
29
+
30
+ Promise File System API. Streams via `createWritable()`. FDs always throw `OperationNotSupportedError`. Writes need Safari 26+ (or Chrome / Firefox).
31
+
32
+ → [Async guide](../guides/async.md).
33
+
34
+ ## Comlink
35
+
36
+ Dedicated and SharedWorker facades expose the same backend surface on `fs.backend` (a Comlink proxy). For FD `read`/`write` from the main thread, transfer buffers with Comlink — the facade does that for you.
@@ -0,0 +1,82 @@
1
+ # Create helpers
2
+
3
+ Factories from the package entries. For when to pick which: [Choosing a mode](../choosing-a-mode.md).
4
+
5
+ ## Facade
6
+
7
+ | Function | From | Backend |
8
+ | ------------------------------- | ---------------------- | ----------------------------- |
9
+ | `createOPFSDedicated(options?)` | `.` or `/sync` | Dedicated worker + `OPFSSync` |
10
+ | `createOPFSAsync(options?)` | `.` or `/async` | In-process `OPFSAsync` |
11
+ | `createOPFSShared(options?)` | `.` or `/sharedworker` | SharedWorker + `OPFSAsync` |
12
+
13
+ All return [`OPFSFacade`](./facade.md).
14
+
15
+ ```typescript
16
+ import { createOPFSDedicated, createOPFSAsync, createOPFSShared } from 'opfs-worker';
17
+ ```
18
+
19
+ On the main entry only:
20
+
21
+ - `createOPFS` → `createOPFSDedicated`
22
+ - `createWorker` → same (deprecated)
23
+ - `OPFSFileSystem` → `OPFSFacade` (deprecated)
24
+
25
+ ## Escape hatch
26
+
27
+ Every facade exposes:
28
+
29
+ | Field | Meaning |
30
+ | ------------ | --------------------------------------------------------------------- |
31
+ | `fs.backend` | Raw [`OPFSApi`](../types.md#opfsapi) — bytes in / bytes out |
32
+ | `fs.worker` | `Worker` / `SharedWorker` when one was created; `undefined` for async |
33
+
34
+ ```typescript
35
+ const fs = createOPFSDedicated({ root: '/my-app' });
36
+ await fs.backend.writeFile('/a.bin', bytes);
37
+ fs.worker; // Worker
38
+ ```
39
+
40
+ ## Options
41
+
42
+ Passed to any `createOPFS*` (and to `setOptions()` later). Full type: [`OPFSOptions`](../types.md#opfsoptions).
43
+
44
+ | Option | Default | What it does |
45
+ | ------------------ | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
46
+ | `root` | `'/'` | Scope all paths under this OPFS subdirectory |
47
+ | `namespace` | `'opfs-worker:${root}'` | Stamp on every [watch](../guides/watching.md) event |
48
+ | `hashAlgorithm` | `'etag'` | File hash on `stat` / `index` / watch — `'etag'`, `'SHA-*'`, or `null`/`false` to disable. See [hashing](../guides/hashing.md) |
49
+ | `maxFileSize` | `50MB` | Skip SHA-\* hashing above this size (`etag` ignores it) |
50
+ | `broadcastChannel` | `'opfs-worker'` | Channel name, a `BroadcastChannel` instance, or `null` to disable |
51
+
52
+ ### Dedicated worker only
53
+
54
+ | Option | Type | Default | What it does |
55
+ | -------- | --------------- | -------------- | ---------------------------------------------------------------------------------- |
56
+ | `url` | `string \| URL` | inlined worker | Script URL for `opfs-worker/dedicated.worker.js` (or your own) instead of the blob |
57
+ | `worker` | `Worker` | — | Pass an existing `Worker` (overrides `url`) |
58
+
59
+ ### SharedWorker only
60
+
61
+ | Option | Type | Default | What it does |
62
+ | -------- | --------------- | ------------------- | ----------------------------------------------------------------------------------------------------- |
63
+ | `url` | `string \| URL` | next to the package | Script URL for `opfs-worker/shared.worker.js` — with Vite: `import url from '…/shared.worker.js?url'` |
64
+ | `worker` | `SharedWorker` | — | Pass an existing `SharedWorker` (overrides `url`) |
65
+ | `name` | `string` | `'opfs-worker'` | Tabs with the same script URL + name share one instance |
66
+
67
+ ```typescript
68
+ const fs = createOPFS({
69
+ root: '/my-app',
70
+ hashAlgorithm: 'SHA-256',
71
+ maxFileSize: 10 * 1024 * 1024,
72
+ });
73
+ ```
74
+
75
+ ## Prebuilt scripts
76
+
77
+ | Export | Hook up with |
78
+ | --------------------------------- | -------------------------------------------------------- |
79
+ | `opfs-worker/dedicated.worker.js` | `new Worker(url, { type: 'module' })` or `{ url }` |
80
+ | `opfs-worker/shared.worker.js` | `new SharedWorker(url, { type: 'module' })` or `{ url }` |
81
+
82
+ Walkthroughs: [dedicated](../guides/dedicated.md), [sharedworker](../guides/sharedworker.md).
@@ -0,0 +1,52 @@
1
+ # OPFSFacade
2
+
3
+ Node-ish API: encodings, auto-detect by extension, path as `string` or `URL`. You normally get one from [`createOPFS*`](./create.md); you can also `new OPFSFacade({ fs, worker?, dispose })`.
4
+
5
+ `fs.promises === fs`.
6
+
7
+ ## Escape hatch
8
+
9
+ | Field | Notes |
10
+ | ----- | ----- |
11
+ | `backend` | Raw [`OPFSApi`](../types.md#opfsapi) — same methods without encoding helpers |
12
+ | `worker` | `Worker` / `SharedWorker` if this facade owns one; `undefined` for async |
13
+
14
+ ## File I/O
15
+
16
+ | Method | Notes |
17
+ | ------ | ----- |
18
+ | `readFile` / `writeFile` / `appendFile` | Encoding as string, `{ encoding }`, or auto |
19
+ | `importStream` | Stream / Blob / File — [streaming](../guides/streaming.md) |
20
+ | `readText` / `writeText` / `appendText` | UTF-8 by default |
21
+
22
+ ## Directories & metadata
23
+
24
+ | Method | Notes |
25
+ | ------ | ----- |
26
+ | `mkdir` | `{ recursive }`; numeric mode is accepted and ignored |
27
+ | `readDir` | `DirentData[]` |
28
+ | `stat` / `exists` / `realpath` | |
29
+ | `remove` | `{ recursive, force }` |
30
+ | `rename` / `copy` | `copy` takes `{ recursive, overwrite }` |
31
+ | `clear` | Empty a dir (default `/`) |
32
+ | `index` | `Map<path, FileStat>` |
33
+ | `createIndex` | Bulk `[path, string \| Uint8Array \| Blob][]` |
34
+
35
+ ## Watch & lifecycle
36
+
37
+ | Method | Notes |
38
+ | ------ | ----- |
39
+ | `watch` | Returns `() => void` |
40
+ | `unwatch` | |
41
+ | `setOptions` | [Hashing](../guides/hashing.md) and friends |
42
+ | `dispose` | Tear down the backend |
43
+
44
+ ## Node aliases
45
+
46
+ `unlink` / `rm` / `rmdir` → `remove`. `readdir` → `readDir`. `lstat` → `stat`. `chmod` is a no-op (no Unix modes in OPFS).
47
+
48
+ ## File descriptors
49
+
50
+ `open`, `read`, `write`, `close`, `fstat`, `ftruncate`, `fsync` — dedicated / `OPFSSync` only. Async throws `ENOTSUP`.
51
+
52
+ Full story: [file descriptors](../file-descriptors.md).
@@ -0,0 +1,41 @@
1
+ # Choosing a mode
2
+
3
+ Sync access handles only work in a **dedicated** worker. Async writes (`createWritable`) work on the main thread and in SharedWorkers too, but Safari needs **26+** for writing.
4
+
5
+ ## Package entries
6
+
7
+ | Entry | What you get |
8
+ | --------------------------------- | --------------------------------------------------------------- |
9
+ | `opfs-worker` | Everything (plus 1.x aliases) |
10
+ | `opfs-worker/sync` | Dedicated worker only — `createOPFSDedicated`, `OPFSSync` |
11
+ | `opfs-worker/async` | No worker — `createOPFSAsync`, `OPFSAsync` |
12
+ | `opfs-worker/sharedworker` | SharedWorker helpers |
13
+ | `opfs-worker/pure` | Classes only — you own the thread |
14
+ | `opfs-worker/dedicated.worker.js` | Prebuilt dedicated Worker script |
15
+ | `opfs-worker/shared.worker.js` | Prebuilt SharedWorker script |
16
+
17
+ ## Modes
18
+
19
+ | | API | Reach for it when… | FD | Comlink |
20
+ | ----- | --------------------------------------------------------- | ------------------------------- | --------- | ------- |
21
+ | **1** | [`createOPFSDedicated()`](./guides/dedicated.md) | You want a normal `fs`-like API | yes | yes |
22
+ | **2** | [`OPFSSync` / `OPFSAsync` from `/pure`](./guides/pure.md) | You’re already in a worker | sync only | no |
23
+ | **3** | [`createOPFSAsync()`](./guides/async.md) | You don’t want a worker at all | no | no |
24
+ | **4** | [`createOPFSShared()`](./guides/sharedworker.md) | All tabs should share one fs | no | yes |
25
+
26
+ Need the raw bytes API or the browser Worker? Use `fs.backend` / `fs.worker` on any facade — no separate factory.
27
+
28
+ If size matters, import from `/sync`, `/async`, or `/sharedworker` instead of the main barrel.
29
+
30
+ ## Trade-offs
31
+
32
+ | | Dedicated (`OPFSSync`) | Async (`OPFSAsync`) |
33
+ | ------------------------- | -------------------------------------------------------------------------------------- | ------------------------------ |
34
+ | File descriptors | yes | `ENOTSUP` |
35
+ | Safari writes | yes (via the worker) | 26+ |
36
+ | SharedWorker | no | yes |
37
+ | One instance for all tabs | no (unless you build SharedWorker yourself) | Mode 4 |
38
+ | Bundle | ~80 KB inlined worker, or [prebuilt script](./guides/dedicated.md#diy-prebuilt-script) | small via `/async` |
39
+ | CSP without `blob:` | pass `url` / prebuilt script | no worker, or SharedWorker URL |
40
+
41
+ Aliases on the main entry: `createOPFS` / `createWorker` → `createOPFSDedicated`, `OPFSFileSystem` → `OPFSFacade`. See [Migration](./migration.md).
@@ -1,23 +1,22 @@
1
1
  # File Descriptors
2
2
 
3
- This document covers working with file descriptors in OPFS Worker, which provides low-level file I/O operations similar to POSIX file descriptors.
3
+ Low-level positional I/O, POSIX-style.
4
+
5
+ > Needs the **dedicated / sync** backend (`createOPFSDedicated` / `createOPFS`, or `OPFSSync` from `/pure`). Async and SharedWorker throw `ENOTSUP`.
4
6
 
5
7
  ## Requirements
6
8
 
7
- **Important**: When using file descriptors from the main window (browser), you must import and use `Comlink` for proper buffer handling:
9
+ If you talk to **`fs.backend`** from the main thread for FD `read`/`write`, transfer buffers with Comlink:
8
10
 
9
11
  ```typescript
10
12
  import { transfer } from 'comlink';
11
13
  ```
12
14
 
13
- ## Overview
15
+ The [facade](./api/facade.md) methods do this for you.
14
16
 
15
- File descriptors provide efficient, low-level access to files for reading, writing, and manipulating file data. They're particularly useful for:
17
+ ## Overview
16
18
 
17
- - **Large file operations**: Reading/writing files in chunks without loading entire content into memory
18
- - **Streaming operations**: Processing files sequentially or in specific positions
19
- - **Performance-critical applications**: Direct file access without the overhead of high-level methods
20
- - **Binary data manipulation**: Working with raw bytes at specific file positions
19
+ Useful when you need chunks, random access, or to avoid loading a whole file into memory.
21
20
 
22
21
  ## Table of Contents
23
22
 
@@ -170,7 +169,7 @@ console.log('read:', text);
170
169
  #### From Worker (Direct Usage)
171
170
 
172
171
  ```typescript
173
- // When using OPFSWorker directly in a worker
172
+ // When using OPFSSync directly in a worker
174
173
  const buffer = new Uint8Array(64);
175
174
  const { bytesRead, buffer: modifiedBuffer } = await fs.read(fd, buffer, 0, buffer.length, null);
176
175
 
@@ -0,0 +1,36 @@
1
+ # Async (no worker)
2
+
3
+ `OPFSAsync` on the current thread — `getFile()` / `createWritable()`, no Comlink, no worker in the bundle.
4
+
5
+ Same limits apply as SharedWorker (it’s the same backend).
6
+
7
+ ## Facade
8
+
9
+ ```typescript
10
+ import { createOPFSAsync } from 'opfs-worker/async';
11
+
12
+ const fs = createOPFSAsync({ root: '/my-app' });
13
+
14
+ await fs.writeFile('/note.txt', 'hello');
15
+ await fs.appendText('/note.txt', '!');
16
+ const text = await fs.readFile('/note.txt', 'utf-8');
17
+ ```
18
+
19
+ Import from `opfs-worker/async` if you care about bundle size — the main entry also carries the dedicated-worker path.
20
+
21
+ ## Raw class
22
+
23
+ ```typescript
24
+ import { OPFSAsync } from 'opfs-worker/async';
25
+
26
+ const fs = new OPFSAsync({ root: '/my-app' });
27
+ await fs.writeFile('/x.bin', new Uint8Array([1, 2, 3]));
28
+ ```
29
+
30
+ ## Limits
31
+
32
+ - **Writes** need `createWritable()` — Chrome, Firefox, Safari **26+**. Reads work anywhere OPFS does.
33
+ - **No file descriptors** — `open` / `read` / `write` / … throw `ENOTSUP`.
34
+ - Each write goes through a swap file and commits on close — fine for documents, awkward for tons of tiny random writes.
35
+
36
+ Streaming still works: [streaming](./streaming.md). For one fs across tabs: [SharedWorker](./sharedworker.md).
@@ -0,0 +1,76 @@
1
+ # Dedicated worker
2
+
3
+ The default path: `OPFSSync` inside a dedicated Web Worker. You get file descriptors and the fastest write path the browser allows for OPFS.
4
+
5
+ See also [Choosing a mode](../choosing-a-mode.md).
6
+
7
+ ## Facade
8
+
9
+ ```typescript
10
+ import { createOPFSDedicated } from 'opfs-worker';
11
+ // or from 'opfs-worker/sync'
12
+
13
+ const fs = createOPFSDedicated({ root: '/my-app' });
14
+
15
+ await fs.writeFile('/config.json', JSON.stringify({ theme: 'dark' }));
16
+ const config = await fs.readFile('/config.json'); // string — auto-detected
17
+ ```
18
+
19
+ `createOPFS` is the same thing with a shorter name.
20
+
21
+ The worker is inlined by default, so you don’t need a special bundler worker setup.
22
+
23
+ ## Raw backend
24
+
25
+ Bytes in, bytes out — no encoding helpers. Same facade, just talk to `backend`:
26
+
27
+ ```typescript
28
+ const fs = createOPFSDedicated({ root: '/my-app' });
29
+
30
+ await fs.backend.writeFile('/config.json', new TextEncoder().encode('{}'));
31
+ const bytes = await fs.backend.readFile('/config.json');
32
+
33
+ // Browser Worker, if you ever need it:
34
+ fs.worker; // Worker
35
+
36
+ fs.dispose(); // dispose + terminate
37
+ ```
38
+
39
+ ## Loading a real worker file
40
+
41
+ Pass `url` or `worker` when you can’t use the inline blob (strict CSP, custom hosting):
42
+
43
+ ```typescript
44
+ import workerUrl from 'opfs-worker/dedicated.worker.js?url'; // Vite
45
+
46
+ const fs = createOPFSDedicated({ root: '/my-app', url: workerUrl });
47
+ ```
48
+
49
+ ## DIY prebuilt script
50
+
51
+ `opfs-worker/dedicated.worker.js` is a self-contained Worker (Comlink + `OPFSSync` already inside):
52
+
53
+ ```typescript
54
+ import { wrap } from 'comlink';
55
+ import { OPFSFacade } from 'opfs-worker';
56
+ import workerUrl from 'opfs-worker/dedicated.worker.js?url';
57
+
58
+ const worker = new Worker(workerUrl, { type: 'module' });
59
+ const remote = wrap(worker);
60
+
61
+ const fs = new OPFSFacade({
62
+ fs: remote,
63
+ worker,
64
+ dispose: () => {
65
+ void remote.dispose();
66
+ worker.terminate();
67
+ },
68
+ });
69
+ ```
70
+
71
+ ## Heads-up
72
+
73
+ - Each call gets its own worker. Tabs don’t share state — use [SharedWorker](./sharedworker.md) for that.
74
+ - Sync access handles are a dedicated-worker-only browser API.
75
+
76
+ More: [file descriptors](../file-descriptors.md), [streaming](./streaming.md), [create helpers](../api/create.md).
@@ -0,0 +1,34 @@
1
+ # Hashing
2
+
3
+ Set once via `hashAlgorithm` / `maxFileSize` in options or `setOptions()`. Shows up on `stat()`, `index()`, and [watch](./watching.md) events (files only).
4
+
5
+ | Value | What you get |
6
+ | ----- | ------------ |
7
+ | `'etag'` (default) | Cheap tag from mtime + size — no content read |
8
+ | `'SHA-1'` … `'SHA-512'` | Real content hash (Web Crypto) |
9
+ | `null` / `false` | No `hash` field |
10
+
11
+ `maxFileSize` (default 50MB) only limits SHA-\* hashing. Oversized files skip the hash.
12
+
13
+ ```typescript
14
+ import { createOPFS } from 'opfs-worker';
15
+
16
+ const fs = createOPFS();
17
+
18
+ await fs.writeFile('/data.txt', 'Hello');
19
+ console.log((await fs.stat('/data.txt')).hash); // etag-ish, e.g. "m1abc-c"
20
+
21
+ await fs.setOptions({ hashAlgorithm: 'SHA-256' });
22
+ console.log((await fs.stat('/data.txt')).hash); // hex digest
23
+ ```
24
+
25
+ `root` scopes you under a subdirectory of OPFS. `namespace` is stamped on every watch event:
26
+
27
+ ```typescript
28
+ const fs = createOPFS({
29
+ root: '/my-app',
30
+ namespace: 'my-app:fs',
31
+ });
32
+ ```
33
+
34
+ Full options table: [`create` helpers](../api/create.md#options).
@@ -0,0 +1,46 @@
1
+ # Pure classes
2
+
3
+ Use the classes directly inside a worker (or thread) you already own. No nested worker, no Comlink `expose()` from this package — wiring to the main thread is on you.
4
+
5
+ ```typescript
6
+ import { OPFSSync, OPFSAsync } from 'opfs-worker/pure';
7
+ ```
8
+
9
+ | Class | Runs where | FD |
10
+ | ----- | ---------- | -- |
11
+ | `OPFSSync` | Dedicated worker only | yes |
12
+ | `OPFSAsync` | Main thread, dedicated, or SharedWorker | no |
13
+ | `BaseOPFS` | Shared base — usually you don’t instantiate it | — |
14
+
15
+ ## OPFSSync in your dedicated worker
16
+
17
+ ```typescript
18
+ // my-app.worker.ts
19
+ import { OPFSSync } from 'opfs-worker/pure';
20
+
21
+ const fs = new OPFSSync({
22
+ root: '/my-app',
23
+ broadcastChannel: 'my-app-events', // name only — instances can’t cross the wire
24
+ });
25
+
26
+ await fs.writeFile('/config.json', new TextEncoder().encode('{}'));
27
+ ```
28
+
29
+ `/pure` won’t hijack your worker’s message port.
30
+
31
+ ## OPFSAsync in a SharedWorker you write
32
+
33
+ ```typescript
34
+ import { expose } from 'comlink';
35
+ import { OPFSAsync } from 'opfs-worker/pure';
36
+
37
+ const fs = new OPFSAsync({ root: '/my-app' });
38
+
39
+ onconnect = (e) => {
40
+ expose(fs, e.ports[0]);
41
+ };
42
+ ```
43
+
44
+ Or skip the boilerplate and use the [SharedWorker guide](./sharedworker.md).
45
+
46
+ Also: [backend API](../api/backend.md), [dedicated](./dedicated.md), [async](./async.md).