opfs-worker 2.1.0 → 2.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -37
- package/dist/BaseOPFS-Bu7FZtCb.cjs +2 -0
- package/dist/BaseOPFS-Bu7FZtCb.cjs.map +1 -0
- package/dist/{BaseOPFS-Cylz6ijk.js → BaseOPFS-C3NE4BKr.js} +804 -484
- package/dist/BaseOPFS-C3NE4BKr.js.map +1 -0
- package/dist/OPFSAsync-C0RsxCX5.cjs +2 -0
- package/dist/OPFSAsync-C0RsxCX5.cjs.map +1 -0
- package/dist/{OPFSAsync-BKSAJJeh.js → OPFSAsync-aeLUdIqd.js} +19 -19
- package/dist/OPFSAsync-aeLUdIqd.js.map +1 -0
- package/dist/OPFSFacade-BJv2yuWU.cjs +2 -0
- package/dist/OPFSFacade-BJv2yuWU.cjs.map +1 -0
- package/dist/OPFSFacade-DiogtQoq.js +308 -0
- package/dist/OPFSFacade-DiogtQoq.js.map +1 -0
- package/dist/OPFSSync-3qlSBYmz.cjs +2 -0
- package/dist/OPFSSync-3qlSBYmz.cjs.map +1 -0
- package/dist/{OPFSSync-CsSQkpk5.js → OPFSSync-CvSOswhW.js} +57 -57
- package/dist/OPFSSync-CvSOswhW.js.map +1 -0
- package/dist/assets/dedicated.worker-Bqqr9UBA.js.map +1 -0
- package/dist/core/BaseOPFS.d.ts +60 -9
- package/dist/core/BaseOPFS.d.ts.map +1 -1
- package/dist/core/OPFSAsync.d.ts.map +1 -1
- package/dist/core/OPFSSync.d.ts.map +1 -1
- package/dist/createOPFSAsync-B611B63X.js +10 -0
- package/dist/{createOPFSAsync-Y4Mg6qte.js.map → createOPFSAsync-B611B63X.js.map} +1 -1
- package/dist/createOPFSAsync-BATjJg8k.cjs +2 -0
- package/dist/{createOPFSAsync-BwKDmHsy.cjs.map → createOPFSAsync-BATjJg8k.cjs.map} +1 -1
- package/dist/createOPFSDedicated-DgudPTB8.js +2676 -0
- package/dist/createOPFSDedicated-DgudPTB8.js.map +1 -0
- package/dist/createOPFSDedicated-EmIwluQo.cjs +2597 -0
- package/dist/createOPFSDedicated-EmIwluQo.cjs.map +1 -0
- package/dist/{createOPFSShared-CGdd__PH.js → createOPFSShared-BWYln8jJ.js} +2 -2
- package/dist/{createOPFSShared-CGdd__PH.js.map → createOPFSShared-BWYln8jJ.js.map} +1 -1
- package/dist/{createOPFSShared-CskROt7U.cjs → createOPFSShared-DPJpCd7z.cjs} +2 -2
- package/dist/{createOPFSShared-CskROt7U.cjs.map → createOPFSShared-DPJpCd7z.cjs.map} +1 -1
- package/dist/dedicated.worker.js +1104 -790
- package/dist/dedicated.worker.js.map +1 -1
- package/dist/facade/OPFSFacade.d.ts +21 -3
- package/dist/facade/OPFSFacade.d.ts.map +1 -1
- package/dist/facade/createOPFSDedicated.d.ts +4 -2
- package/dist/facade/createOPFSDedicated.d.ts.map +1 -1
- package/dist/index.async.cjs +1 -1
- package/dist/index.async.js +33 -32
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +44 -43
- package/dist/index.pure.cjs +1 -1
- package/dist/index.pure.js +38 -37
- package/dist/index.sharedworker.cjs +1 -1
- package/dist/index.sharedworker.js +34 -33
- package/dist/index.sync.cjs +1 -1
- package/dist/index.sync.d.ts +2 -0
- package/dist/index.sync.d.ts.map +1 -1
- package/dist/index.sync.js +34 -32
- package/dist/shared.worker.js +1101 -791
- package/dist/shared.worker.js.map +1 -1
- package/dist/types.d.ts +38 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/helpers.d.ts +13 -3
- package/dist/utils/helpers.d.ts.map +1 -1
- package/dist/worker/createDedicatedWorker.d.ts +8 -3
- package/dist/worker/createDedicatedWorker.d.ts.map +1 -1
- package/docs/README.md +13 -25
- package/docs/api/README.md +221 -0
- package/docs/api/file-descriptors.md +137 -0
- package/docs/guides/async.md +4 -4
- package/docs/guides/dedicated.md +10 -8
- package/docs/guides/hashing.md +3 -3
- package/docs/guides/pure.md +4 -4
- package/docs/guides/sharedworker.md +2 -2
- package/docs/guides/streaming.md +146 -12
- package/docs/guides/watching.md +3 -3
- package/docs/migration.md +10 -11
- package/docs/types.md +93 -155
- package/package.json +20 -9
- package/src/core/BaseOPFS.ts +194 -29
- package/src/core/OPFSAsync.ts +4 -5
- package/src/core/OPFSSync.ts +6 -7
- package/src/facade/OPFSFacade.ts +51 -4
- package/src/facade/createOPFSDedicated.ts +4 -2
- package/src/index.sync.ts +2 -0
- package/src/index.ts +1 -5
- package/src/types.ts +42 -3
- package/src/utils/helpers.ts +32 -6
- package/src/worker/createDedicatedWorker.ts +85 -7
- package/src/worker/dedicated.worker.ts +12 -1
- package/dist/BaseOPFS-BPw9AIQ-.cjs +0 -4
- package/dist/BaseOPFS-BPw9AIQ-.cjs.map +0 -1
- package/dist/BaseOPFS-Cylz6ijk.js.map +0 -1
- package/dist/OPFSAsync-BKSAJJeh.js.map +0 -1
- package/dist/OPFSAsync-s2P7y3sw.cjs +0 -2
- package/dist/OPFSAsync-s2P7y3sw.cjs.map +0 -1
- package/dist/OPFSFacade-DePnNRgt.cjs +0 -2
- package/dist/OPFSFacade-DePnNRgt.cjs.map +0 -1
- package/dist/OPFSFacade-XohWlHuu.js +0 -281
- package/dist/OPFSFacade-XohWlHuu.js.map +0 -1
- package/dist/OPFSSync-C7KBepe_.cjs +0 -2
- package/dist/OPFSSync-C7KBepe_.cjs.map +0 -1
- package/dist/OPFSSync-CsSQkpk5.js.map +0 -1
- package/dist/assets/dedicated.worker-nY3tK4zi.js.map +0 -1
- package/dist/createOPFSAsync-BwKDmHsy.cjs +0 -2
- package/dist/createOPFSAsync-Y4Mg6qte.js +0 -10
- package/dist/createOPFSDedicated-CsnV6MLP.js +0 -2333
- package/dist/createOPFSDedicated-CsnV6MLP.js.map +0 -1
- package/dist/createOPFSDedicated-pKTRWLdz.cjs +0 -2283
- package/dist/createOPFSDedicated-pKTRWLdz.cjs.map +0 -1
- package/docs/api/backend.md +0 -36
- package/docs/api/create.md +0 -82
- package/docs/api/facade.md +0 -52
- package/docs/choosing-a-mode.md +0 -41
- package/docs/file-descriptors.md +0 -695
package/dist/types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { BaseOPFS } from './core/BaseOPFS';
|
|
1
2
|
import type { OPFSSync } from './core/OPFSSync';
|
|
2
3
|
/**
|
|
3
4
|
* Type for paths that can be either a string or URI
|
|
@@ -38,12 +39,11 @@ export interface WatchEvent {
|
|
|
38
39
|
}
|
|
39
40
|
export type { OPFSSync };
|
|
40
41
|
/**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
42
|
+
* Public bytes API shared by all backends (`OPFSSync`, `OPFSAsync`, or a
|
|
43
|
+
* Comlink proxy to one of them). Declared on {@link BaseOPFS}; subclasses
|
|
44
|
+
* implement the abstract I/O and FD methods.
|
|
43
45
|
*/
|
|
44
|
-
export type OPFSApi =
|
|
45
|
-
[K in keyof OPFSSync]: OPFSSync[K];
|
|
46
|
-
};
|
|
46
|
+
export type OPFSApi = Pick<BaseOPFS, keyof BaseOPFS>;
|
|
47
47
|
export interface OPFSOptions {
|
|
48
48
|
/** Root path for the file system (default: '/') */
|
|
49
49
|
root?: string;
|
|
@@ -56,6 +56,39 @@ export interface OPFSOptions {
|
|
|
56
56
|
/** Custom name for the broadcast channel (default: 'opfs-worker') */
|
|
57
57
|
broadcastChannel?: string | BroadcastChannel | null;
|
|
58
58
|
}
|
|
59
|
+
/** Payload accepted by {@link importFiles} for a single entry. */
|
|
60
|
+
export type ImportFileData = string | Uint8Array | Blob;
|
|
61
|
+
/**
|
|
62
|
+
* Entries for {@link importFiles}: an array of `[path, data]` tuples, a `Map`,
|
|
63
|
+
* or any iterable that yields the same pairs.
|
|
64
|
+
*/
|
|
65
|
+
export type ImportFilesEntries = Iterable<[string, ImportFileData]> | Map<string, ImportFileData>;
|
|
66
|
+
/** Progress event fired while {@link importFiles} writes entries. */
|
|
67
|
+
export interface ImportFilesProgress {
|
|
68
|
+
/** Path of the file currently being written */
|
|
69
|
+
path: string;
|
|
70
|
+
/** 0-based index of the current file */
|
|
71
|
+
index: number;
|
|
72
|
+
/** Total number of entries in this import */
|
|
73
|
+
count: number;
|
|
74
|
+
/** Bytes written for the current file so far */
|
|
75
|
+
bytesWritten: number;
|
|
76
|
+
/** Size of the current file in bytes */
|
|
77
|
+
bytesTotal: number;
|
|
78
|
+
/** Bytes written across all files so far */
|
|
79
|
+
totalBytesWritten: number;
|
|
80
|
+
/** Sum of all entry sizes in bytes */
|
|
81
|
+
totalBytes: number;
|
|
82
|
+
}
|
|
83
|
+
/** Result of a finished {@link importFiles} call. */
|
|
84
|
+
export interface ImportFilesResult {
|
|
85
|
+
/** Paths written, in import order */
|
|
86
|
+
paths: string[];
|
|
87
|
+
/** Number of files imported (`paths.length`) */
|
|
88
|
+
count: number;
|
|
89
|
+
/** Total bytes written across all files */
|
|
90
|
+
bytesWritten: number;
|
|
91
|
+
}
|
|
59
92
|
export interface RenameOptions {
|
|
60
93
|
/** Whether to overwrite existing files (default: false) */
|
|
61
94
|
overwrite?: boolean;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChD,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;;;;GAIG;AACH,MAAM,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,EAAE,MAAM,QAAQ,CAAC,CAAC;AAErD,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,kEAAkE;AAClE,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC;AAExD;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;AAElG,qEAAqE;AACrE,MAAM,WAAW,mBAAmB;IAChC,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,YAAY,EAAE,MAAM,CAAC;IACrB,wCAAwC;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,4CAA4C;IAC5C,iBAAiB,EAAE,MAAM,CAAC;IAC1B,sCAAsC;IACtC,UAAU,EAAE,MAAM,CAAC;CACtB;AAED,qDAAqD;AACrD,MAAM,WAAW,iBAAiB;IAC9B,qCAAqC;IACrC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,gDAAgD;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,YAAY,EAAE,MAAM,CAAC;CACxB;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"}
|
package/dist/utils/helpers.d.ts
CHANGED
|
@@ -5,17 +5,26 @@ import type { Encoding } from '../types';
|
|
|
5
5
|
* @throws {OPFSNotSupportedError} If the browser does not support the OPFS API
|
|
6
6
|
*/
|
|
7
7
|
export declare function checkOPFSSupport(): void;
|
|
8
|
+
/**
|
|
9
|
+
* Join a mount `root` with an API path into an absolute OPFS path.
|
|
10
|
+
*
|
|
11
|
+
* Lock keys and cross-instance coordination use this so `/x.txt` under
|
|
12
|
+
* `root: '/app'` and `/app/x.txt` under `root: '/'` resolve to the same file.
|
|
13
|
+
*/
|
|
14
|
+
export declare function absoluteOpfsPath(root: string, path: string): string;
|
|
8
15
|
/**
|
|
9
16
|
* Run a callback while holding an exclusive lock on a path
|
|
10
17
|
*
|
|
11
18
|
* Locks are always exclusive: OPFS permits a single sync access handle per file,
|
|
12
|
-
* so readers can't share access either.
|
|
19
|
+
* so readers can't share access either. The lock key is the absolute OPFS path
|
|
20
|
+
* (`root` + API `path`) so different mounts of the same file serialize correctly.
|
|
13
21
|
*
|
|
14
|
-
* @param path - The path to lock
|
|
22
|
+
* @param path - The API path to lock (relative to `root`)
|
|
15
23
|
* @param fn - The callback to run while holding the lock
|
|
24
|
+
* @param root - Mount root (default: `/`)
|
|
16
25
|
* @returns The value returned by the callback
|
|
17
26
|
*/
|
|
18
|
-
export declare function withLock<T>(path: string, fn: () => Promise<T
|
|
27
|
+
export declare function withLock<T>(path: string, fn: () => Promise<T>, root?: string): Promise<T>;
|
|
19
28
|
/**
|
|
20
29
|
* Split a path into an array of segments
|
|
21
30
|
*
|
|
@@ -174,6 +183,7 @@ export declare function removeEntry(parentHandle: FileSystemDirectoryHandle, pat
|
|
|
174
183
|
recursive?: boolean;
|
|
175
184
|
force?: boolean;
|
|
176
185
|
useTrash?: boolean;
|
|
186
|
+
root?: string;
|
|
177
187
|
}): Promise<void>;
|
|
178
188
|
/**
|
|
179
189
|
* Validate read/write arguments for file descriptor operations
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/utils/helpers.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAGzC;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAIvC;AAED
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/utils/helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,7 +9,7 @@ export interface DedicatedWorkerOptions extends OPFSOptions {
|
|
|
9
9
|
* prefer the self-contained file (strict CSP without `blob:`, or DIY hosting).
|
|
10
10
|
*/
|
|
11
11
|
url?: string | URL;
|
|
12
|
-
/** Bring your own Worker instance (overrides `url`) */
|
|
12
|
+
/** Bring your own Worker instance (overrides `url`) — not pooled */
|
|
13
13
|
worker?: Worker;
|
|
14
14
|
}
|
|
15
15
|
export interface RawWorker {
|
|
@@ -17,13 +17,18 @@ export interface RawWorker {
|
|
|
17
17
|
fs: RemoteOPFSSync;
|
|
18
18
|
/** Underlying browser Worker */
|
|
19
19
|
worker: Worker;
|
|
20
|
-
/**
|
|
20
|
+
/** Drops this facade's port; terminates the Worker when the last user of this pool entry disposes */
|
|
21
21
|
dispose: () => void;
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
|
-
* Internal helper: spawn a dedicated worker and wrap `OPFSSync` with Comlink.
|
|
24
|
+
* Internal helper: spawn (or reuse) a dedicated worker and wrap `OPFSSync` with Comlink.
|
|
25
25
|
* Prefer {@link createOPFSDedicated}; access the proxy / Worker via
|
|
26
26
|
* `facade.backend` / `facade.worker`.
|
|
27
|
+
*
|
|
28
|
+
* Calls with the same `root` (and same `url`, if any) share one Worker on this page.
|
|
29
|
+
* Different roots get different Workers. Passing `worker` bypasses the pool.
|
|
30
|
+
*
|
|
31
|
+
* `setOptions` hits the shared instance — keep options consistent for the same root.
|
|
27
32
|
*/
|
|
28
33
|
export declare function createDedicatedWorker(options?: DedicatedWorkerOptions): RawWorker;
|
|
29
34
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createDedicatedWorker.d.ts","sourceRoot":"","sources":["../../src/worker/createDedicatedWorker.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"createDedicatedWorker.d.ts","sourceRoot":"","sources":["../../src/worker/createDedicatedWorker.ts"],"names":[],"mappings":"AAKA,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,oEAAoE;IACpE,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,qGAAqG;IACrG,OAAO,EAAE,MAAM,IAAI,CAAC;CACvB;AAmCD;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,sBAA2B,GAAG,SAAS,CA2ErF"}
|
package/docs/README.md
CHANGED
|
@@ -1,30 +1,18 @@
|
|
|
1
1
|
# Docs
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
- [API overview](./api/README.md) — entries, facade methods, options, trade-offs
|
|
4
|
+
- [File descriptors](./api/file-descriptors.md) — positional `open` / `read` / `write`
|
|
5
|
+
- [Types](./types.md)
|
|
6
|
+
- [Migration from 1.x](./migration.md)
|
|
4
7
|
|
|
5
8
|
## Guides
|
|
6
9
|
|
|
7
|
-
| Guide | About
|
|
8
|
-
| ----------------------------------------- |
|
|
9
|
-
| [
|
|
10
|
-
| [
|
|
11
|
-
| [
|
|
12
|
-
| [
|
|
13
|
-
| [
|
|
14
|
-
| [
|
|
15
|
-
| [
|
|
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)
|
|
10
|
+
| Guide | About |
|
|
11
|
+
| ----------------------------------------- | --------------------------------------------------------- |
|
|
12
|
+
| [Dedicated worker](./guides/dedicated.md) | How to use OPFS via a dedicated worker (the default path) |
|
|
13
|
+
| [Async](./guides/async.md) | How to use OPFS on the main thread, without a worker |
|
|
14
|
+
| [SharedWorker](./guides/sharedworker.md) | How to share one filesystem across all tabs |
|
|
15
|
+
| [Pure classes](./guides/pure.md) | How to drop OPFS into a worker you already run |
|
|
16
|
+
| [Streaming](./guides/streaming.md) | How to handle large files and bulk uploads |
|
|
17
|
+
| [Watching](./guides/watching.md) | How to listen for file changes across tabs |
|
|
18
|
+
| [Hashing](./guides/hashing.md) | How file hashes / etags work on `stat` and watch events |
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# API
|
|
2
|
+
|
|
3
|
+
The sync backend works in every browser that has OPFS, but the browser only allows it inside a dedicated worker — `createOPFS()` / `createOPFSDedicated()` set that up for you. The async backend can run on the main thread or in a SharedWorker, but needs a modern browser — writes will not work in Safari before 26.
|
|
4
|
+
|
|
5
|
+
## Package entries
|
|
6
|
+
|
|
7
|
+
| Import from | Worker | Use it when |
|
|
8
|
+
| -------------------------- | ------------------------------------------ | --------------------------------------------------------------------- |
|
|
9
|
+
| `opfs-worker` | Starts a dedicated worker | Default; fine if bundle size doesn’t matter or tree-shaking is set up |
|
|
10
|
+
| `opfs-worker/sync` | Starts a dedicated worker | Same as the default, without async / shared code in the bundle |
|
|
11
|
+
| `opfs-worker/async` | Runs directly in the current thread | Main thread or your own worker; Safari prior to 26 can’t write |
|
|
12
|
+
| `opfs-worker/sharedworker` | Starts one SharedWorker shared by all tabs | One shared fs process for every tab; Safari prior to 26 can’t write |
|
|
13
|
+
| `opfs-worker/pure` | None | Low-level classes to build your own custom worker |
|
|
14
|
+
|
|
15
|
+
## Facade
|
|
16
|
+
|
|
17
|
+
Every helper returns an `OPFSFacade` — the same Node-like API in all modes. The facade hides the actual work: depending on which helper you call, it either creates a dedicated worker and talks to it, works with OPFS directly in the current thread, or connects to a SharedWorker.
|
|
18
|
+
|
|
19
|
+
Each takes optional `[options](#options)`.
|
|
20
|
+
|
|
21
|
+
| Function | From | Under the hood |
|
|
22
|
+
| ------------------ | ------------------------------------------- | ------------------------------------------------ |
|
|
23
|
+
| `createOPFS` | `opfs-worker` or `opfs-worker/sync` | Dedicated worker + `OPFSSync` |
|
|
24
|
+
| `createOPFSAsync` | `opfs-worker` or `opfs-worker/async` | OPFS directly, `OPFSAsync` in the current thread |
|
|
25
|
+
| `createOPFSShared` | `opfs-worker` or `opfs-worker/sharedworker` | SharedWorker + `OPFSAsync` |
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { createOPFS, createOPFSAsync, createOPFSShared } from 'opfs-worker';
|
|
29
|
+
|
|
30
|
+
const fs = createOPFS(); // or createOPFSAsync(), createOPFSShared({ url: '...' })
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### File I/O
|
|
34
|
+
|
|
35
|
+
Paths are `string | URL` everywhere below.
|
|
36
|
+
|
|
37
|
+
| Method | Parameters | Returns |
|
|
38
|
+
| -------------- | -------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | -------------------------------------------------------------------------- | --------------- |
|
|
39
|
+
| `readFile` | `path`, optional `encoding` or `{ encoding }` | `Promise<string | Uint8Array>` — auto by extension if omitted (`.txt`→ string,`.bin` → bytes) |
|
|
40
|
+
| `writeFile` | `path`, `data` (`string | Uint8Array | ArrayBuffer | Blob`), optional encoding | `Promise<void>` |
|
|
41
|
+
| `appendFile` | `path`, `data` (`string | Uint8Array | ArrayBuffer | Blob`), optional encoding | `Promise<void>` |
|
|
42
|
+
| `readText` | `path`, `encoding?` (default `'utf-8'`) | `Promise<string>` |
|
|
43
|
+
| `writeText` | `path`, `text`, `encoding?` (default `'utf-8'`) | `Promise<void>` |
|
|
44
|
+
| `appendText` | `path`, `text`, `encoding?` (default `'utf-8'`) | `Promise<void>` |
|
|
45
|
+
| `readBlob` | `path` | `Promise<Blob>` — disk-backed, not copied into memory. See [streaming](../guides/streaming.md) |
|
|
46
|
+
| `importStream` | `path`, `ReadableStream | Blob | File`, optional `{ onProgress }` | `Promise<number>` — bytes written. See [streaming](../guides/streaming.md) |
|
|
47
|
+
| `importFiles` | `[path, data][]` / `Map` / iterable, optional `{ onProgress }` | `Promise<ImportFilesResult>` — paths, count, bytes. See [streaming](../guides/streaming.md) |
|
|
48
|
+
|
|
49
|
+
For Node compatibility, `fs.promises` is the same instance (`fs.promises === fs`).
|
|
50
|
+
|
|
51
|
+
### Directories & metadata
|
|
52
|
+
|
|
53
|
+
| Method | Parameters | Returns |
|
|
54
|
+
| ---------- | -------------------------------------------------------------------- | ------------------------------------------------------------------- |
|
|
55
|
+
| `mkdir` | `path`, optional `{ recursive }` (numeric mode accepted and ignored) | `Promise<void>` |
|
|
56
|
+
| `readDir` | `path` | `Promise<DirentData[]>` |
|
|
57
|
+
| `stat` | `path` | `Promise<FileStat>` |
|
|
58
|
+
| `exists` | `path` | `Promise<boolean>` |
|
|
59
|
+
| `realpath` | `path` | `Promise<string>` |
|
|
60
|
+
| `remove` | `path`, optional `{ recursive, force }` | `Promise<void>` |
|
|
61
|
+
| `rename` | `oldPath`, `newPath`, optional `{ overwrite }` | `Promise<void>` |
|
|
62
|
+
| `copy` | `source`, `destination`, optional `{ recursive, overwrite }` | `Promise<void>` |
|
|
63
|
+
| `clear` | `path?` (default `/`) | `Promise<void>` — empties the directory, keeps the directory itself |
|
|
64
|
+
| `index` | — | `Promise<Map<string, FileStat>>` |
|
|
65
|
+
|
|
66
|
+
### Watch & lifecycle
|
|
67
|
+
|
|
68
|
+
| Method | Parameters | Returns |
|
|
69
|
+
| ------------ | --------------------------------------------------------------------- | ------------------------------------------------ |
|
|
70
|
+
| `watch` | `path`, optional `{ recursive, include, exclude }` | `() => void` unsubscribe |
|
|
71
|
+
| `unwatch` | `path` | `void` |
|
|
72
|
+
| `setOptions` | `options` — see [Options](#options) / [hashing](../guides/hashing.md) | `Promise<void>` |
|
|
73
|
+
| `dispose` | — | `void` — tears down watches, backend, and worker |
|
|
74
|
+
|
|
75
|
+
### File descriptors
|
|
76
|
+
|
|
77
|
+
Dedicated / `OPFSSync` only — async throws `ENOTSUP`. Details: [file descriptors](./file-descriptors.md).
|
|
78
|
+
|
|
79
|
+
| Method | Parameters | Returns |
|
|
80
|
+
| ----------- | -------------------------------------------------- | ------------------------------------------- |
|
|
81
|
+
| `open` | `path`, optional `{ create, exclusive, truncate }` | `Promise<number>` — file descriptor |
|
|
82
|
+
| `read` | `fd`, `buffer`, `offset`, `length`, `position?` | `Promise<{ bytesRead, buffer }>` |
|
|
83
|
+
| `write` | `fd`, `buffer`, `offset?`, `length?`, `position?` | `Promise<number>` — bytes written |
|
|
84
|
+
| `close` | `fd` | `Promise<void>` |
|
|
85
|
+
| `fstat` | `fd` | `Promise<FileStat>` |
|
|
86
|
+
| `ftruncate` | `fd`, `size?` (default `0`) | `Promise<void>` |
|
|
87
|
+
| `fsync` | `fd` | `Promise<void>` — best-effort flush in OPFS |
|
|
88
|
+
|
|
89
|
+
### Node aliases
|
|
90
|
+
|
|
91
|
+
| Alias | Parameters | Returns |
|
|
92
|
+
| --------- | --------------------------------------- | ----------------------------------------------- |
|
|
93
|
+
| `unlink` | `path` | same as `remove(path)` |
|
|
94
|
+
| `rm` | `path`, optional `{ recursive, force }` | same as `remove` |
|
|
95
|
+
| `rmdir` | `path` | same as `remove(path)` |
|
|
96
|
+
| `readdir` | `path` | same as `readDir` |
|
|
97
|
+
| `lstat` | `path` | same as `stat` |
|
|
98
|
+
| `chmod` | `path`, `mode` | `Promise<void>` — no-op (no Unix modes in OPFS) |
|
|
99
|
+
|
|
100
|
+
### Backend access
|
|
101
|
+
|
|
102
|
+
`fs.backend` is the raw bytes API the facade wraps — a Comlink proxy to the worker for dedicated / SharedWorker, or the in-process `OPFSAsync` instance for async. Same methods as the facade, but without encoding helpers (you pass / get `Uint8Array`).
|
|
103
|
+
|
|
104
|
+
| Field | Type | Notes |
|
|
105
|
+
| ------------ | -------------------------------- | -------------------- | ---------- | ---------------------------------------------------- |
|
|
106
|
+
| `fs.backend` | `[OPFSApi](../types.md#opfsapi)` | bytes in / bytes out |
|
|
107
|
+
| `fs.worker` | `Worker | SharedWorker | undefined` | set when a worker was created; `undefined` for async |
|
|
108
|
+
|
|
109
|
+
## Options
|
|
110
|
+
|
|
111
|
+
Passed to any `createOPFS*` (and to `setOptions()` later).
|
|
112
|
+
|
|
113
|
+
| Option | Default | What it does |
|
|
114
|
+
| ------------------ | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
|
|
115
|
+
| `root` | `'/'` | Scope all paths under this OPFS subdirectory |
|
|
116
|
+
| `namespace` | `'opfs-worker:${root}'` | Stamp on every [watch](../guides/watching.md) event |
|
|
117
|
+
| `hashAlgorithm` | `'etag'` | File hash on `stat` / `index` / watch — `'etag'`, `'SHA-*'`, or `null`/`false` to disable. See [hashing](../guides/hashing.md) |
|
|
118
|
+
| `maxFileSize` | `50MB` | Skip SHA- hashing above this size (`etag` ignores it) |
|
|
119
|
+
| `broadcastChannel` | `'opfs-worker'` | Channel name, a `BroadcastChannel` instance, or `null` to disable |
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
const fs = createOPFS({
|
|
123
|
+
root: '/my-app',
|
|
124
|
+
hashAlgorithm: 'SHA-256',
|
|
125
|
+
maxFileSize: 10 * 1024 * 1024,
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Dedicated worker only
|
|
130
|
+
|
|
131
|
+
| Option | Type | Default | What it does |
|
|
132
|
+
| -------- | -------- | ------- | ------------------------------------------- | ---------------------------------------------------------------------------------- |
|
|
133
|
+
| `url` | `string | URL` | inlined worker | Script URL for `opfs-worker/dedicated.worker.js` (or your own) instead of the blob |
|
|
134
|
+
| `worker` | `Worker` | — | Pass an existing `Worker` (overrides `url`) |
|
|
135
|
+
|
|
136
|
+
Leave these unset unless you need them — the default inlined worker is enough.
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
const fs = createOPFS({ root: '/my-app' });
|
|
140
|
+
|
|
141
|
+
// Escape hatches only:
|
|
142
|
+
// createOPFS({ root: '/my-app', url: workerUrl }) // CSP without blob:
|
|
143
|
+
// createOPFS({ root: '/my-app', worker: existingWorker }) // bring your own Worker
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### SharedWorker only
|
|
147
|
+
|
|
148
|
+
| Option | Type | Default | What it does |
|
|
149
|
+
| -------- | -------------- | --------------- | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
|
|
150
|
+
| `url` | `string | URL` | next to the package | Script URL for `opfs-worker/shared.worker.js` — with Vite: `import url from '…/shared.worker.js?url'` |
|
|
151
|
+
| `worker` | `SharedWorker` | — | Pass an existing `SharedWorker` (overrides `url`) |
|
|
152
|
+
| `name` | `string` | `'opfs-worker'` | Tabs with the same script URL + name share one instance |
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
import workerUrl from 'opfs-worker/shared.worker.js?url'; // Vite
|
|
156
|
+
import { createOPFSShared } from 'opfs-worker/sharedworker';
|
|
157
|
+
|
|
158
|
+
const fs = createOPFSShared({
|
|
159
|
+
root: '/my-app',
|
|
160
|
+
url: workerUrl,
|
|
161
|
+
name: 'opfs-worker',
|
|
162
|
+
});
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Ready-made worker files
|
|
166
|
+
|
|
167
|
+
These files already contain a backend (`OPFSSync` or `OPFSAsync`) wrapped in Comlink expose.
|
|
168
|
+
|
|
169
|
+
| Export | Inside | Start with |
|
|
170
|
+
| --------------------------------- | --------------------- | -------------------------------------------------------- |
|
|
171
|
+
| `opfs-worker/dedicated.worker.js` | Comlink + `OPFSSync` | `new Worker(url, { type: 'module' })` or `{ url }` |
|
|
172
|
+
| `opfs-worker/shared.worker.js` | Comlink + `OPFSAsync` | `new SharedWorker(url, { type: 'module' })` or `{ url }` |
|
|
173
|
+
|
|
174
|
+
### Use the facade with a worker URL
|
|
175
|
+
|
|
176
|
+
This is required for SharedWorker. For dedicated workers, use it only when the default inlined worker is blocked by CSP or you want to host the script yourself.
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
import workerUrl from 'opfs-worker/dedicated.worker.js?url';
|
|
180
|
+
|
|
181
|
+
const fs = createOPFS({ root: '/my-app', url: workerUrl });
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
You can also create the `Worker` yourself and pass it to the facade. The facade still handles Comlink, options, encoding helpers, buffer transfers, and cleanup.
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
const worker = new Worker(workerUrl, { type: 'module' });
|
|
188
|
+
const fs = createOPFS({ root: '/my-app', worker });
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Use the worker without the facade
|
|
192
|
+
|
|
193
|
+
Wrap it with Comlink and configure the backend manually. This exposes the bytes API directly: no encoding helpers, automatic FD buffer transfers, or automatic worker termination.
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
import { wrap } from 'comlink';
|
|
197
|
+
import type { OPFSApi } from 'opfs-worker';
|
|
198
|
+
import workerUrl from 'opfs-worker/dedicated.worker.js?url';
|
|
199
|
+
|
|
200
|
+
const worker = new Worker(workerUrl, { type: 'module' });
|
|
201
|
+
const backend = wrap<OPFSApi>(worker);
|
|
202
|
+
|
|
203
|
+
await backend.setOptions({ root: '/my-app' });
|
|
204
|
+
await backend.writeFile('/hello.txt', new TextEncoder().encode('hello'));
|
|
205
|
+
|
|
206
|
+
await backend.dispose();
|
|
207
|
+
worker.terminate();
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Guides: [Dedicated worker](../guides/dedicated.md), [SharedWorker](../guides/sharedworker.md).
|
|
211
|
+
|
|
212
|
+
## Trade-offs
|
|
213
|
+
|
|
214
|
+
| | Dedicated (`OPFSSync`) | Async (`OPFSAsync`) |
|
|
215
|
+
| ----------------------------------- | ------------------------------------------------ | ---------------------------- |
|
|
216
|
+
| File descriptors | yes | throw `ENOTSUP` |
|
|
217
|
+
| Browser support | every browser that has OPFS | Safari before 26 can’t write |
|
|
218
|
+
| SharedWorker | no | yes |
|
|
219
|
+
| One instance for all tabs | no | yes, with `createOPFSShared` |
|
|
220
|
+
| Bundle | ~80 KB inlined worker, or ready-made worker file | small via `/async` |
|
|
221
|
+
| Works under strict CSP (no `blob:`) | pass a worker `url` instead of the inlined blob | n/a |
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# File Descriptors
|
|
2
|
+
|
|
3
|
+
Positional I/O on the **dedicated / sync** backend (`createOPFSDedicated` / `createOPFS`, or `OPFSSync` from `/pure`). Async and SharedWorker throw `ENOTSUP`.
|
|
4
|
+
|
|
5
|
+
If you call FD `read`/`write` on **`fs.backend`** from the main thread, transfer buffers with Comlink. The [facade](./README.md#facade) does that for you.
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { transfer } from 'comlink';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## `open(path, options?): Promise<number>`
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
const fd = await fs.open('/data/config.json');
|
|
15
|
+
const fd = await fs.open('/data/new.txt', { create: true });
|
|
16
|
+
const fd = await fs.open('/data/unique.txt', { create: true, exclusive: true });
|
|
17
|
+
const fd = await fs.open('/data/log.txt', { create: true, truncate: true });
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
| Option | Default | |
|
|
21
|
+
| ----------- | ------- | ---------------------------------------------- |
|
|
22
|
+
| `create` | `false` | Create the file if missing |
|
|
23
|
+
| `exclusive` | `false` | With `create`, fail if the file already exists |
|
|
24
|
+
| `truncate` | `false` | Truncate to zero length |
|
|
25
|
+
|
|
26
|
+
Throws `AlreadyExistsError` (`exclusive`), `FileTypeError` (path is a directory), or `FileSystemOperationError`.
|
|
27
|
+
|
|
28
|
+
`exclusive` is best-effort only — two workers can still race. OPFS has no real file locking.
|
|
29
|
+
|
|
30
|
+
## `read(fd, buffer, offset, length, position?): Promise<{ bytesRead, buffer }>`
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
const buffer = new Uint8Array(1024);
|
|
34
|
+
const { bytesRead, buffer: out } = await fs.read(fd, buffer, 0, 1024, null);
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
- `position` `null` / `undefined` — current cursor, then advance
|
|
38
|
+
- `position` number — that offset, cursor unchanged
|
|
39
|
+
- Returns `bytesRead === 0` at EOF
|
|
40
|
+
|
|
41
|
+
With a Comlink proxy, buffers are transferred both ways. Use the **returned** buffer; the original is detached after transfer.
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import { transfer } from 'comlink';
|
|
45
|
+
|
|
46
|
+
const buffer = new Uint8Array(64);
|
|
47
|
+
const { bytesRead, buffer: out } = await fs.read(
|
|
48
|
+
fd,
|
|
49
|
+
transfer(buffer, [buffer.buffer]),
|
|
50
|
+
0,
|
|
51
|
+
buffer.length,
|
|
52
|
+
null
|
|
53
|
+
);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Inside a worker with `OPFSSync` directly, plain buffers are fine — no `transfer`.
|
|
57
|
+
|
|
58
|
+
Chunked read from the main thread:
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
const fd = await fs.open('/data/large-file.txt');
|
|
62
|
+
const chunkSize = 1024;
|
|
63
|
+
let buffer = new Uint8Array(chunkSize);
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
while (true) {
|
|
67
|
+
const result = await fs.read(
|
|
68
|
+
fd,
|
|
69
|
+
transfer(buffer, [buffer.buffer]),
|
|
70
|
+
0,
|
|
71
|
+
chunkSize,
|
|
72
|
+
null
|
|
73
|
+
);
|
|
74
|
+
if (result.bytesRead === 0) break;
|
|
75
|
+
processChunk(result.buffer.subarray(0, result.bytesRead));
|
|
76
|
+
buffer = new Uint8Array(chunkSize);
|
|
77
|
+
}
|
|
78
|
+
} finally {
|
|
79
|
+
await fs.close(fd);
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Prefer small chunks over allocating a buffer the size of the whole file.
|
|
84
|
+
|
|
85
|
+
## `write(fd, buffer, offset?, length?, position?): Promise<number>`
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
const data = new TextEncoder().encode('Hello, World!');
|
|
89
|
+
const bytesWritten = await fs.write(fd, data);
|
|
90
|
+
const bytesWritten2 = await fs.write(fd, data2, 0, 10, 100);
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Same `position` rules as `read`. Extends the file if you write past EOF. Triggers watch events.
|
|
94
|
+
|
|
95
|
+
## Positioning
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
await fs.read(fd, buf, 0, 10, null); // cursor 0 → 10
|
|
99
|
+
await fs.read(fd, buf, 0, 10, null); // cursor 10 → 20
|
|
100
|
+
await fs.read(fd, buf, 0, 10, 0); // reads at 0, cursor stays 20
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## `fstat` / `ftruncate` / `fsync`
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
const stats = await fs.fstat(fd);
|
|
107
|
+
await fs.ftruncate(fd, 5);
|
|
108
|
+
await fs.fsync(fd);
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`ftruncate` clamps the cursor if it sits past the new size, emits a watch event, and flushes.
|
|
112
|
+
|
|
113
|
+
`fsync` is best-effort. Unlike POSIX, the browser does not guarantee durability on power loss.
|
|
114
|
+
|
|
115
|
+
## `close(fd)`
|
|
116
|
+
|
|
117
|
+
Always close in a `finally`. Pending writes are flushed; open FDs are also closed when the worker is disposed.
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
const fd = await fs.open('/data/file.txt');
|
|
121
|
+
try {
|
|
122
|
+
// …
|
|
123
|
+
} finally {
|
|
124
|
+
await fs.close(fd);
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Errors
|
|
129
|
+
|
|
130
|
+
| Error | When |
|
|
131
|
+
| -------------------------------------- | --------------------------------- |
|
|
132
|
+
| `AlreadyExistsError` | `exclusive: true` and file exists |
|
|
133
|
+
| `ExistenceError` | Missing path |
|
|
134
|
+
| `FileTypeError` | File vs directory mismatch |
|
|
135
|
+
| `ValidationError` | Bad offset / length / args |
|
|
136
|
+
| `FileSystemOperationError` / `IOError` | Underlying FS / I/O failure |
|
|
137
|
+
| `PermissionError` | Access denied |
|
package/docs/guides/async.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Async
|
|
1
|
+
# Async
|
|
2
2
|
|
|
3
|
-
`OPFSAsync` on the current thread
|
|
3
|
+
`OPFSAsync` on the **current** thread (main or a worker you already run). Does not create a worker. Uses `getFile()` / `createWritable()`, no Comlink.
|
|
4
4
|
|
|
5
5
|
Same limits apply as SharedWorker (it’s the same backend).
|
|
6
6
|
|
|
@@ -16,7 +16,7 @@ await fs.appendText('/note.txt', '!');
|
|
|
16
16
|
const text = await fs.readFile('/note.txt', 'utf-8');
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
Import from `opfs-worker/async`
|
|
19
|
+
Import from `opfs-worker/async` to keep the dedicated-worker code out of the bundle.
|
|
20
20
|
|
|
21
21
|
## Raw class
|
|
22
22
|
|
|
@@ -31,6 +31,6 @@ await fs.writeFile('/x.bin', new Uint8Array([1, 2, 3]));
|
|
|
31
31
|
|
|
32
32
|
- **Writes** need `createWritable()` — Chrome, Firefox, Safari **26+**. Reads work anywhere OPFS does.
|
|
33
33
|
- **No file descriptors** — `open` / `read` / `write` / … throw `ENOTSUP`.
|
|
34
|
-
- Each write goes through a swap file and commits on close — fine for documents,
|
|
34
|
+
- Each write goes through a swap file and commits on close — fine for documents, slow for many tiny random writes.
|
|
35
35
|
|
|
36
36
|
Streaming still works: [streaming](./streaming.md). For one fs across tabs: [SharedWorker](./sharedworker.md).
|