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.
Files changed (111) hide show
  1. package/README.md +51 -37
  2. package/dist/BaseOPFS-Bu7FZtCb.cjs +2 -0
  3. package/dist/BaseOPFS-Bu7FZtCb.cjs.map +1 -0
  4. package/dist/{BaseOPFS-Cylz6ijk.js → BaseOPFS-C3NE4BKr.js} +804 -484
  5. package/dist/BaseOPFS-C3NE4BKr.js.map +1 -0
  6. package/dist/OPFSAsync-C0RsxCX5.cjs +2 -0
  7. package/dist/OPFSAsync-C0RsxCX5.cjs.map +1 -0
  8. package/dist/{OPFSAsync-BKSAJJeh.js → OPFSAsync-aeLUdIqd.js} +19 -19
  9. package/dist/OPFSAsync-aeLUdIqd.js.map +1 -0
  10. package/dist/OPFSFacade-BJv2yuWU.cjs +2 -0
  11. package/dist/OPFSFacade-BJv2yuWU.cjs.map +1 -0
  12. package/dist/OPFSFacade-DiogtQoq.js +308 -0
  13. package/dist/OPFSFacade-DiogtQoq.js.map +1 -0
  14. package/dist/OPFSSync-3qlSBYmz.cjs +2 -0
  15. package/dist/OPFSSync-3qlSBYmz.cjs.map +1 -0
  16. package/dist/{OPFSSync-CsSQkpk5.js → OPFSSync-CvSOswhW.js} +57 -57
  17. package/dist/OPFSSync-CvSOswhW.js.map +1 -0
  18. package/dist/assets/dedicated.worker-Bqqr9UBA.js.map +1 -0
  19. package/dist/core/BaseOPFS.d.ts +60 -9
  20. package/dist/core/BaseOPFS.d.ts.map +1 -1
  21. package/dist/core/OPFSAsync.d.ts.map +1 -1
  22. package/dist/core/OPFSSync.d.ts.map +1 -1
  23. package/dist/createOPFSAsync-B611B63X.js +10 -0
  24. package/dist/{createOPFSAsync-Y4Mg6qte.js.map → createOPFSAsync-B611B63X.js.map} +1 -1
  25. package/dist/createOPFSAsync-BATjJg8k.cjs +2 -0
  26. package/dist/{createOPFSAsync-BwKDmHsy.cjs.map → createOPFSAsync-BATjJg8k.cjs.map} +1 -1
  27. package/dist/createOPFSDedicated-DgudPTB8.js +2676 -0
  28. package/dist/createOPFSDedicated-DgudPTB8.js.map +1 -0
  29. package/dist/createOPFSDedicated-EmIwluQo.cjs +2597 -0
  30. package/dist/createOPFSDedicated-EmIwluQo.cjs.map +1 -0
  31. package/dist/{createOPFSShared-CGdd__PH.js → createOPFSShared-BWYln8jJ.js} +2 -2
  32. package/dist/{createOPFSShared-CGdd__PH.js.map → createOPFSShared-BWYln8jJ.js.map} +1 -1
  33. package/dist/{createOPFSShared-CskROt7U.cjs → createOPFSShared-DPJpCd7z.cjs} +2 -2
  34. package/dist/{createOPFSShared-CskROt7U.cjs.map → createOPFSShared-DPJpCd7z.cjs.map} +1 -1
  35. package/dist/dedicated.worker.js +1104 -790
  36. package/dist/dedicated.worker.js.map +1 -1
  37. package/dist/facade/OPFSFacade.d.ts +21 -3
  38. package/dist/facade/OPFSFacade.d.ts.map +1 -1
  39. package/dist/facade/createOPFSDedicated.d.ts +4 -2
  40. package/dist/facade/createOPFSDedicated.d.ts.map +1 -1
  41. package/dist/index.async.cjs +1 -1
  42. package/dist/index.async.js +33 -32
  43. package/dist/index.cjs +1 -1
  44. package/dist/index.d.ts +1 -5
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +44 -43
  47. package/dist/index.pure.cjs +1 -1
  48. package/dist/index.pure.js +38 -37
  49. package/dist/index.sharedworker.cjs +1 -1
  50. package/dist/index.sharedworker.js +34 -33
  51. package/dist/index.sync.cjs +1 -1
  52. package/dist/index.sync.d.ts +2 -0
  53. package/dist/index.sync.d.ts.map +1 -1
  54. package/dist/index.sync.js +34 -32
  55. package/dist/shared.worker.js +1101 -791
  56. package/dist/shared.worker.js.map +1 -1
  57. package/dist/types.d.ts +38 -5
  58. package/dist/types.d.ts.map +1 -1
  59. package/dist/utils/helpers.d.ts +13 -3
  60. package/dist/utils/helpers.d.ts.map +1 -1
  61. package/dist/worker/createDedicatedWorker.d.ts +8 -3
  62. package/dist/worker/createDedicatedWorker.d.ts.map +1 -1
  63. package/docs/README.md +13 -25
  64. package/docs/api/README.md +221 -0
  65. package/docs/api/file-descriptors.md +137 -0
  66. package/docs/guides/async.md +4 -4
  67. package/docs/guides/dedicated.md +10 -8
  68. package/docs/guides/hashing.md +3 -3
  69. package/docs/guides/pure.md +4 -4
  70. package/docs/guides/sharedworker.md +2 -2
  71. package/docs/guides/streaming.md +146 -12
  72. package/docs/guides/watching.md +3 -3
  73. package/docs/migration.md +10 -11
  74. package/docs/types.md +93 -155
  75. package/package.json +20 -9
  76. package/src/core/BaseOPFS.ts +194 -29
  77. package/src/core/OPFSAsync.ts +4 -5
  78. package/src/core/OPFSSync.ts +6 -7
  79. package/src/facade/OPFSFacade.ts +51 -4
  80. package/src/facade/createOPFSDedicated.ts +4 -2
  81. package/src/index.sync.ts +2 -0
  82. package/src/index.ts +1 -5
  83. package/src/types.ts +42 -3
  84. package/src/utils/helpers.ts +32 -6
  85. package/src/worker/createDedicatedWorker.ts +85 -7
  86. package/src/worker/dedicated.worker.ts +12 -1
  87. package/dist/BaseOPFS-BPw9AIQ-.cjs +0 -4
  88. package/dist/BaseOPFS-BPw9AIQ-.cjs.map +0 -1
  89. package/dist/BaseOPFS-Cylz6ijk.js.map +0 -1
  90. package/dist/OPFSAsync-BKSAJJeh.js.map +0 -1
  91. package/dist/OPFSAsync-s2P7y3sw.cjs +0 -2
  92. package/dist/OPFSAsync-s2P7y3sw.cjs.map +0 -1
  93. package/dist/OPFSFacade-DePnNRgt.cjs +0 -2
  94. package/dist/OPFSFacade-DePnNRgt.cjs.map +0 -1
  95. package/dist/OPFSFacade-XohWlHuu.js +0 -281
  96. package/dist/OPFSFacade-XohWlHuu.js.map +0 -1
  97. package/dist/OPFSSync-C7KBepe_.cjs +0 -2
  98. package/dist/OPFSSync-C7KBepe_.cjs.map +0 -1
  99. package/dist/OPFSSync-CsSQkpk5.js.map +0 -1
  100. package/dist/assets/dedicated.worker-nY3tK4zi.js.map +0 -1
  101. package/dist/createOPFSAsync-BwKDmHsy.cjs +0 -2
  102. package/dist/createOPFSAsync-Y4Mg6qte.js +0 -10
  103. package/dist/createOPFSDedicated-CsnV6MLP.js +0 -2333
  104. package/dist/createOPFSDedicated-CsnV6MLP.js.map +0 -1
  105. package/dist/createOPFSDedicated-pKTRWLdz.cjs +0 -2283
  106. package/dist/createOPFSDedicated-pKTRWLdz.cjs.map +0 -1
  107. package/docs/api/backend.md +0 -36
  108. package/docs/api/create.md +0 -82
  109. package/docs/api/facade.md +0 -52
  110. package/docs/choosing-a-mode.md +0 -41
  111. package/docs/file-descriptors.md +0 -695
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OPFSSync-3qlSBYmz.cjs","sources":["../src/core/OPFSSync.ts"],"sourcesContent":["import { transfer } from 'comlink';\n\nimport { BaseOPFS } from './BaseOPFS';\nimport { WatchEventType } from '../types';\nimport {\n AlreadyExistsError,\n OPFSError,\n ValidationError,\n createFDError,\n mapDomError\n} from '../utils/errors';\n\nimport {\n calculateReadLength,\n createSyncHandleSafe,\n normalizePath,\n resolvePath,\n safeCloseSyncHandle,\n validateReadWriteArgs\n} from '../utils/helpers';\n\nimport type { FileOpenOptions, FileStat, OPFSOptions } from '../types';\n\n/**\n * Sync OPFS backend using `FileSystemSyncAccessHandle` (dedicated worker only).\n *\n * Provides high-level file I/O and Node-like file descriptors.\n *\n * @example\n * ```typescript\n * import { OPFSSync } from 'opfs-worker/pure';\n *\n * const fs = new OPFSSync();\n * await fs.writeFile('/data/config.json', new TextEncoder().encode(JSON.stringify({ theme: 'dark' })));\n * const config = await fs.readFile('/data/config.json');\n * ```\n */\nexport class OPFSSync extends BaseOPFS {\n /** Shared sync handles per path (OPFS allows only one handle per file) */\n private openHandles = new Map<string, {\n fileHandle: FileSystemFileHandle;\n syncHandle: FileSystemSyncAccessHandle;\n refCount: number;\n }>();\n\n /** Map of open file descriptors to their metadata */\n private openFiles = new Map<number, {\n path: string;\n fileHandle: FileSystemFileHandle;\n syncHandle: FileSystemSyncAccessHandle;\n position: number;\n }>();\n\n /** Next available file descriptor number */\n private nextFd = 1;\n\n constructor(options?: OPFSOptions) {\n super(options);\n }\n\n /**\n * Get file info by descriptor with validation\n * @private\n */\n private _getFileDescriptor(fd: number): { path: string; fileHandle: FileSystemFileHandle; syncHandle: FileSystemSyncAccessHandle; position: number } {\n const fileInfo = this.openFiles.get(fd);\n\n if (!fileInfo) {\n throw new ValidationError('descriptor', `Invalid file descriptor: ${ fd }`);\n }\n\n return fileInfo;\n }\n\n async readFile(path: string): Promise<Uint8Array> {\n await this.mount();\n\n try {\n return await this.withPathLock(path, async() => {\n const fd = await this.open(path);\n\n try {\n const { size } = await this.fstat(fd);\n const buffer = new Uint8Array(size);\n\n if (size > 0) {\n await this.read(fd, buffer, 0, size, 0);\n }\n\n return transfer(buffer, [buffer.buffer]);\n }\n finally {\n await this.close(fd);\n }\n });\n }\n catch (err) {\n if (err instanceof OPFSError) {\n throw err;\n }\n\n throw mapDomError(err, { path, isDirectory: false });\n }\n }\n\n async writeFile(\n path: string,\n data: Uint8Array | ArrayBuffer\n ): Promise<void> {\n await this.mount();\n\n const buffer = data instanceof Uint8Array ? data : new Uint8Array(data);\n\n await this.withPathLock(path, async() => {\n const existed = await this.exists(path);\n const fd = await this.open(path, { create: true, truncate: true });\n\n try {\n await this.write(fd, buffer, 0, buffer.length, null, false);\n await this.fsync(fd);\n }\n finally {\n await this.close(fd);\n }\n\n await this.notifyChange({ path, type: existed ? WatchEventType.Changed : WatchEventType.Added, isDirectory: false });\n });\n }\n\n async appendFile(\n path: string,\n data: Uint8Array | ArrayBuffer\n ): Promise<void> {\n await this.mount();\n\n const buffer = data instanceof Uint8Array ? data : new Uint8Array(data);\n\n await this.withPathLock(path, async() => {\n const fd = await this.open(path, { create: true });\n\n try {\n const { size } = await this.fstat(fd);\n\n await this.write(fd, buffer, 0, buffer.length, size, false);\n await this.fsync(fd);\n }\n finally {\n await this.close(fd);\n }\n\n await this.notifyChange({ path, type: WatchEventType.Changed, isDirectory: false });\n });\n }\n\n async writeStream(\n path: string,\n stream: ReadableStream<Uint8Array>,\n onProgress?: (bytesWritten: number) => unknown\n ): Promise<number> {\n await this.mount();\n\n return this.withPathLock(path, async() => {\n const existed = await this.exists(path);\n const fd = await this.open(path, { create: true, truncate: true });\n const reader = stream.getReader();\n let totalBytes = 0;\n\n try {\n while (true) {\n const { done, value: chunk } = await reader.read();\n\n if (done) {\n break;\n }\n\n let offset = 0;\n\n while (offset < chunk.byteLength) {\n offset += await this.write(\n fd,\n chunk,\n offset,\n chunk.byteLength - offset,\n null,\n false\n );\n }\n\n totalBytes += chunk.byteLength;\n await onProgress?.(totalBytes);\n }\n\n await this.fsync(fd);\n }\n catch (error) {\n await reader.cancel(error).catch(() => {});\n\n throw error;\n }\n finally {\n reader.releaseLock();\n await this.close(fd);\n }\n\n await this.notifyChange({\n path,\n type: existed ? WatchEventType.Changed : WatchEventType.Added,\n isDirectory: false,\n });\n\n return totalBytes;\n });\n }\n\n async open(path: string, options?: FileOpenOptions): Promise<number> {\n await this.mount();\n\n const { create = false, exclusive = false, truncate = false } = options || {};\n\n // Normalize path to prevent path-related issues\n const normalizedPath = normalizePath(resolvePath(path));\n\n try {\n // Use lock for atomic operations when creating files\n if (create && exclusive) {\n return await this.withPathLock(normalizedPath, async() => {\n const exists = await this.exists(normalizedPath);\n\n if (exists) {\n throw new AlreadyExistsError(normalizedPath);\n }\n\n return this._openFile(normalizedPath, create, truncate);\n });\n }\n\n return await this._openFile(normalizedPath, create, truncate);\n }\n catch (error: any) {\n if (error instanceof OPFSError) {\n throw error;\n }\n\n // TypeMismatchError here means the path actually refers to a directory\n // so we map it as a directory-type error (EISDIR) for better Node.js parity.\n const isTypeMismatchDirectory = error && error.name === 'TypeMismatchError';\n\n throw mapDomError(error, {\n path: normalizedPath,\n isDirectory: !!isTypeMismatchDirectory,\n });\n }\n }\n\n /**\n * Internal method to open a file (without locking)\n *\n * Multiple FDs for the same path share one sync access handle (OPFS limit),\n * with independent per-FD positions — similar to Node.js.\n * @private\n */\n private async _openFile(path: string, create: boolean, truncate: boolean): Promise<number> {\n let shared = this.openHandles.get(path);\n\n if (!shared) {\n const fileHandle = await this.getFileHandle(path, create);\n\n // Verify that we got a file handle, not a directory\n try {\n await fileHandle.getFile();\n }\n catch (error: any) {\n throw mapDomError(error, { path, isDirectory: true });\n }\n\n const syncHandle = await createSyncHandleSafe(fileHandle, path);\n\n shared = { fileHandle, syncHandle, refCount: 0 };\n this.openHandles.set(path, shared);\n }\n\n shared.refCount++;\n\n if (truncate) {\n shared.syncHandle.truncate(0);\n shared.syncHandle.flush();\n }\n\n const fd = this.nextFd++;\n\n this.openFiles.set(fd, {\n path,\n fileHandle: shared.fileHandle,\n syncHandle: shared.syncHandle,\n position: 0,\n });\n\n return fd;\n }\n\n async close(fd: number): Promise<void> {\n const fileInfo = this._getFileDescriptor(fd);\n\n this.openFiles.delete(fd);\n\n const shared = this.openHandles.get(fileInfo.path);\n\n if (!shared) {\n return;\n }\n\n shared.refCount--;\n\n // Only close the underlying sync handle when the last FD for this path is gone\n if (shared.refCount <= 0) {\n safeCloseSyncHandle(fd, shared.syncHandle, fileInfo.path);\n this.openHandles.delete(fileInfo.path);\n }\n }\n\n async read(\n fd: number,\n buffer: Uint8Array,\n offset: number,\n length: number,\n position: number | null | undefined\n ): Promise<{ bytesRead: number; buffer: Uint8Array }> {\n const fileInfo = this._getFileDescriptor(fd);\n\n // Validate arguments\n validateReadWriteArgs(buffer.length, offset, length, position);\n\n try {\n const readPosition = position ?? fileInfo.position;\n\n // Get file size and calculate read length\n const fileSize = fileInfo.syncHandle.getSize();\n const { isEOF, actualLength } = calculateReadLength(readPosition, length, fileSize);\n\n if (isEOF) {\n return transfer({ bytesRead: 0, buffer }, [buffer.buffer]); // End of file\n }\n\n // Create a subarray view for the read operation\n const targetBuffer = buffer.subarray(offset, offset + actualLength);\n\n // Perform efficient positioned read\n const bytesRead = fileInfo.syncHandle.read(targetBuffer, { at: readPosition });\n\n // Update position if position was not explicitly specified (null means use current position)\n if (position == null) {\n fileInfo.position = readPosition + bytesRead;\n }\n\n return transfer({ bytesRead, buffer }, [buffer.buffer]);\n }\n catch (error) {\n throw createFDError('read', fd, fileInfo.path, error);\n }\n }\n\n async write(\n fd: number,\n buffer: Uint8Array,\n offset: number = 0,\n length?: number,\n position?: number | null | undefined,\n emitEvent: boolean = true\n ): Promise<number> {\n const fileInfo = this._getFileDescriptor(fd);\n\n // Calculate actual length to write\n const actualLength = length ?? (buffer.length - offset);\n\n // Validate arguments using helper\n validateReadWriteArgs(buffer.length, offset, actualLength, position);\n\n try {\n // Determine write position: use specified position, or current position if null/undefined\n const writePosition = position ?? fileInfo.position;\n\n // Create a subarray view for the write operation\n const sourceBuffer = buffer.subarray(offset, offset + actualLength);\n\n // Perform efficient positioned write\n const bytesWritten = fileInfo.syncHandle.write(sourceBuffer, { at: writePosition });\n\n // Update position if position was null or undefined (i.e., use current position)\n // Also update position when writing at current position (position === fileInfo.position)\n if (position == null || position === fileInfo.position) {\n fileInfo.position = writePosition + bytesWritten;\n }\n\n if (emitEvent) {\n await this.notifyChange({ path: fileInfo.path, type: WatchEventType.Changed, isDirectory: false });\n }\n\n return bytesWritten;\n }\n catch (error) {\n throw createFDError('write', fd, fileInfo.path, error);\n }\n }\n\n async fstat(fd: number): Promise<FileStat> {\n const fileInfo = this._getFileDescriptor(fd);\n\n // Simply reuse existing stat() method with the file path\n return this.stat(fileInfo.path);\n }\n\n async ftruncate(fd: number, size: number = 0): Promise<void> {\n const fileInfo = this._getFileDescriptor(fd);\n\n // Validate size parameter\n if (size < 0 || !Number.isInteger(size)) {\n throw new ValidationError('argument', 'Invalid size');\n }\n\n try {\n fileInfo.syncHandle.truncate(size);\n fileInfo.syncHandle.flush();\n\n // Adjust position if it's beyond the new file size\n if (fileInfo.position > size) {\n fileInfo.position = size;\n }\n\n await this.notifyChange({ path: fileInfo.path, type: WatchEventType.Changed, isDirectory: false });\n }\n catch (error) {\n throw createFDError('truncate', fd, fileInfo.path, error);\n }\n }\n\n async fsync(fd: number): Promise<void> {\n const fileInfo = this._getFileDescriptor(fd);\n\n try {\n fileInfo.syncHandle.flush();\n }\n catch (error) {\n throw createFDError('sync', fd, fileInfo.path, error);\n }\n }\n\n override dispose(): void {\n // Close each shared sync handle once (not per FD)\n for (const [path, shared] of this.openHandles) {\n safeCloseSyncHandle(-1, shared.syncHandle, path);\n }\n\n this.openHandles.clear();\n this.openFiles.clear();\n this.nextFd = 1;\n\n super.dispose();\n }\n}\n"],"names":["OPFSSync","BaseOPFS","options","fd","fileInfo","ValidationError","path","size","buffer","transfer","err","OPFSError","mapDomError","data","existed","WatchEventType","stream","onProgress","reader","totalBytes","done","chunk","offset","error","create","exclusive","truncate","normalizedPath","normalizePath","resolvePath","AlreadyExistsError","isTypeMismatchDirectory","shared","fileHandle","syncHandle","createSyncHandleSafe","safeCloseSyncHandle","length","position","validateReadWriteArgs","readPosition","fileSize","isEOF","actualLength","calculateReadLength","targetBuffer","bytesRead","createFDError","emitEvent","writePosition","sourceBuffer","bytesWritten"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- import { transfer as d } from "comlink";
2
- import { B as D, V as g, w as y, O as F, m as u, n as C, r as x, A, J as I, G as H, C as m, H as S, h as w, W as h } from "./BaseOPFS-Cylz6ijk.js";
3
- class L extends D {
1
+ import { transfer as f } from "comlink";
2
+ import { B as m, V as p, O as g, m as d, W as h, o as D, t as C, A as x, K as P, H as F, G as H, J as L, h as w } from "./BaseOPFS-C3NE4BKr.js";
3
+ class _ extends m {
4
4
  /** Shared sync handles per path (OPFS allows only one handle per file) */
5
5
  openHandles = /* @__PURE__ */ new Map();
6
6
  /** Map of open file descriptors to their metadata */
@@ -17,34 +17,34 @@ class L extends D {
17
17
  _getFileDescriptor(e) {
18
18
  const t = this.openFiles.get(e);
19
19
  if (!t)
20
- throw new g("descriptor", `Invalid file descriptor: ${e}`);
20
+ throw new p("descriptor", `Invalid file descriptor: ${e}`);
21
21
  return t;
22
22
  }
23
23
  async readFile(e) {
24
24
  await this.mount();
25
25
  try {
26
- return await y(e, async () => {
26
+ return await this.withPathLock(e, async () => {
27
27
  const t = await this.open(e);
28
28
  try {
29
29
  const { size: a } = await this.fstat(t), s = new Uint8Array(a);
30
- return a > 0 && await this.read(t, s, 0, a, 0), d(s, [s.buffer]);
30
+ return a > 0 && await this.read(t, s, 0, a, 0), f(s, [s.buffer]);
31
31
  } finally {
32
32
  await this.close(t);
33
33
  }
34
34
  });
35
35
  } catch (t) {
36
- throw t instanceof F ? t : u(t, { path: e, isDirectory: !1 });
36
+ throw t instanceof g ? t : d(t, { path: e, isDirectory: !1 });
37
37
  }
38
38
  }
39
39
  async writeFile(e, t) {
40
40
  await this.mount();
41
41
  const a = t instanceof Uint8Array ? t : new Uint8Array(t);
42
- await y(e, async () => {
43
- const s = await this.exists(e), i = await this.open(e, { create: !0, truncate: !0 });
42
+ await this.withPathLock(e, async () => {
43
+ const s = await this.exists(e), n = await this.open(e, { create: !0, truncate: !0 });
44
44
  try {
45
- await this.write(i, a, 0, a.length, null, !1), await this.fsync(i);
45
+ await this.write(n, a, 0, a.length, null, !1), await this.fsync(n);
46
46
  } finally {
47
- await this.close(i);
47
+ await this.close(n);
48
48
  }
49
49
  await this.notifyChange({ path: e, type: s ? h.Changed : h.Added, isDirectory: !1 });
50
50
  });
@@ -52,11 +52,11 @@ class L extends D {
52
52
  async appendFile(e, t) {
53
53
  await this.mount();
54
54
  const a = t instanceof Uint8Array ? t : new Uint8Array(t);
55
- await y(e, async () => {
55
+ await this.withPathLock(e, async () => {
56
56
  const s = await this.open(e, { create: !0 });
57
57
  try {
58
- const { size: i } = await this.fstat(s);
59
- await this.write(s, a, 0, a.length, i, !1), await this.fsync(s);
58
+ const { size: n } = await this.fstat(s);
59
+ await this.write(s, a, 0, a.length, n, !1), await this.fsync(s);
60
60
  } finally {
61
61
  await this.close(s);
62
62
  }
@@ -64,9 +64,9 @@ class L extends D {
64
64
  });
65
65
  }
66
66
  async writeStream(e, t, a) {
67
- return await this.mount(), y(e, async () => {
68
- const s = await this.exists(e), i = await this.open(e, { create: !0, truncate: !0 }), r = t.getReader();
69
- let n = 0;
67
+ return await this.mount(), this.withPathLock(e, async () => {
68
+ const s = await this.exists(e), n = await this.open(e, { create: !0, truncate: !0 }), r = t.getReader();
69
+ let i = 0;
70
70
  try {
71
71
  for (; ; ) {
72
72
  const { done: o, value: c } = await r.read();
@@ -75,43 +75,43 @@ class L extends D {
75
75
  let l = 0;
76
76
  for (; l < c.byteLength; )
77
77
  l += await this.write(
78
- i,
78
+ n,
79
79
  c,
80
80
  l,
81
81
  c.byteLength - l,
82
82
  null,
83
83
  !1
84
84
  );
85
- n += c.byteLength, await a?.(n);
85
+ i += c.byteLength, await a?.(i);
86
86
  }
87
- await this.fsync(i);
87
+ await this.fsync(n);
88
88
  } catch (o) {
89
89
  throw await r.cancel(o).catch(() => {
90
90
  }), o;
91
91
  } finally {
92
- r.releaseLock(), await this.close(i);
92
+ r.releaseLock(), await this.close(n);
93
93
  }
94
94
  return await this.notifyChange({
95
95
  path: e,
96
96
  type: s ? h.Changed : h.Added,
97
97
  isDirectory: !1
98
- }), n;
98
+ }), i;
99
99
  });
100
100
  }
101
101
  async open(e, t) {
102
102
  await this.mount();
103
- const { create: a = !1, exclusive: s = !1, truncate: i = !1 } = t || {}, r = C(x(e));
103
+ const { create: a = !1, exclusive: s = !1, truncate: n = !1 } = t || {}, r = D(C(e));
104
104
  try {
105
- return a && s ? await y(r, async () => {
105
+ return a && s ? await this.withPathLock(r, async () => {
106
106
  if (await this.exists(r))
107
- throw new A(r);
108
- return this._openFile(r, a, i);
109
- }) : await this._openFile(r, a, i);
110
- } catch (n) {
111
- if (n instanceof F)
112
- throw n;
113
- const o = n && n.name === "TypeMismatchError";
114
- throw u(n, {
107
+ throw new x(r);
108
+ return this._openFile(r, a, n);
109
+ }) : await this._openFile(r, a, n);
110
+ } catch (i) {
111
+ if (i instanceof g)
112
+ throw i;
113
+ const o = i && i.name === "TypeMismatchError";
114
+ throw d(i, {
115
115
  path: r,
116
116
  isDirectory: !!o
117
117
  });
@@ -131,47 +131,47 @@ class L extends D {
131
131
  try {
132
132
  await r.getFile();
133
133
  } catch (o) {
134
- throw u(o, { path: e, isDirectory: !0 });
134
+ throw d(o, { path: e, isDirectory: !0 });
135
135
  }
136
- const n = await I(r, e);
137
- s = { fileHandle: r, syncHandle: n, refCount: 0 }, this.openHandles.set(e, s);
136
+ const i = await P(r, e);
137
+ s = { fileHandle: r, syncHandle: i, refCount: 0 }, this.openHandles.set(e, s);
138
138
  }
139
139
  s.refCount++, a && (s.syncHandle.truncate(0), s.syncHandle.flush());
140
- const i = this.nextFd++;
141
- return this.openFiles.set(i, {
140
+ const n = this.nextFd++;
141
+ return this.openFiles.set(n, {
142
142
  path: e,
143
143
  fileHandle: s.fileHandle,
144
144
  syncHandle: s.syncHandle,
145
145
  position: 0
146
- }), i;
146
+ }), n;
147
147
  }
148
148
  async close(e) {
149
149
  const t = this._getFileDescriptor(e);
150
150
  this.openFiles.delete(e);
151
151
  const a = this.openHandles.get(t.path);
152
- a && (a.refCount--, a.refCount <= 0 && (H(e, a.syncHandle, t.path), this.openHandles.delete(t.path)));
152
+ a && (a.refCount--, a.refCount <= 0 && (F(e, a.syncHandle, t.path), this.openHandles.delete(t.path)));
153
153
  }
154
- async read(e, t, a, s, i) {
154
+ async read(e, t, a, s, n) {
155
155
  const r = this._getFileDescriptor(e);
156
- m(t.length, a, s, i);
156
+ H(t.length, a, s, n);
157
157
  try {
158
- const n = i ?? r.position, o = r.syncHandle.getSize(), { isEOF: c, actualLength: l } = S(n, s, o);
158
+ const i = n ?? r.position, o = r.syncHandle.getSize(), { isEOF: c, actualLength: l } = L(i, s, o);
159
159
  if (c)
160
- return d({ bytesRead: 0, buffer: t }, [t.buffer]);
161
- const f = t.subarray(a, a + l), p = r.syncHandle.read(f, { at: n });
162
- return i == null && (r.position = n + p), d({ bytesRead: p, buffer: t }, [t.buffer]);
163
- } catch (n) {
164
- throw w("read", e, r.path, n);
160
+ return f({ bytesRead: 0, buffer: t }, [t.buffer]);
161
+ const y = t.subarray(a, a + l), u = r.syncHandle.read(y, { at: i });
162
+ return n == null && (r.position = i + u), f({ bytesRead: u, buffer: t }, [t.buffer]);
163
+ } catch (i) {
164
+ throw w("read", e, r.path, i);
165
165
  }
166
166
  }
167
- async write(e, t, a = 0, s, i, r = !0) {
168
- const n = this._getFileDescriptor(e), o = s ?? t.length - a;
169
- m(t.length, a, o, i);
167
+ async write(e, t, a = 0, s, n, r = !0) {
168
+ const i = this._getFileDescriptor(e), o = s ?? t.length - a;
169
+ H(t.length, a, o, n);
170
170
  try {
171
- const c = i ?? n.position, l = t.subarray(a, a + o), f = n.syncHandle.write(l, { at: c });
172
- return (i == null || i === n.position) && (n.position = c + f), r && await this.notifyChange({ path: n.path, type: h.Changed, isDirectory: !1 }), f;
171
+ const c = n ?? i.position, l = t.subarray(a, a + o), y = i.syncHandle.write(l, { at: c });
172
+ return (n == null || n === i.position) && (i.position = c + y), r && await this.notifyChange({ path: i.path, type: h.Changed, isDirectory: !1 }), y;
173
173
  } catch (c) {
174
- throw w("write", e, n.path, c);
174
+ throw w("write", e, i.path, c);
175
175
  }
176
176
  }
177
177
  async fstat(e) {
@@ -181,7 +181,7 @@ class L extends D {
181
181
  async ftruncate(e, t = 0) {
182
182
  const a = this._getFileDescriptor(e);
183
183
  if (t < 0 || !Number.isInteger(t))
184
- throw new g("argument", "Invalid size");
184
+ throw new p("argument", "Invalid size");
185
185
  try {
186
186
  a.syncHandle.truncate(t), a.syncHandle.flush(), a.position > t && (a.position = t), await this.notifyChange({ path: a.path, type: h.Changed, isDirectory: !1 });
187
187
  } catch (s) {
@@ -198,11 +198,11 @@ class L extends D {
198
198
  }
199
199
  dispose() {
200
200
  for (const [e, t] of this.openHandles)
201
- H(-1, t.syncHandle, e);
201
+ F(-1, t.syncHandle, e);
202
202
  this.openHandles.clear(), this.openFiles.clear(), this.nextFd = 1, super.dispose();
203
203
  }
204
204
  }
205
205
  export {
206
- L as O
206
+ _ as O
207
207
  };
208
- //# sourceMappingURL=OPFSSync-CsSQkpk5.js.map
208
+ //# sourceMappingURL=OPFSSync-CvSOswhW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OPFSSync-CvSOswhW.js","sources":["../src/core/OPFSSync.ts"],"sourcesContent":["import { transfer } from 'comlink';\n\nimport { BaseOPFS } from './BaseOPFS';\nimport { WatchEventType } from '../types';\nimport {\n AlreadyExistsError,\n OPFSError,\n ValidationError,\n createFDError,\n mapDomError\n} from '../utils/errors';\n\nimport {\n calculateReadLength,\n createSyncHandleSafe,\n normalizePath,\n resolvePath,\n safeCloseSyncHandle,\n validateReadWriteArgs\n} from '../utils/helpers';\n\nimport type { FileOpenOptions, FileStat, OPFSOptions } from '../types';\n\n/**\n * Sync OPFS backend using `FileSystemSyncAccessHandle` (dedicated worker only).\n *\n * Provides high-level file I/O and Node-like file descriptors.\n *\n * @example\n * ```typescript\n * import { OPFSSync } from 'opfs-worker/pure';\n *\n * const fs = new OPFSSync();\n * await fs.writeFile('/data/config.json', new TextEncoder().encode(JSON.stringify({ theme: 'dark' })));\n * const config = await fs.readFile('/data/config.json');\n * ```\n */\nexport class OPFSSync extends BaseOPFS {\n /** Shared sync handles per path (OPFS allows only one handle per file) */\n private openHandles = new Map<string, {\n fileHandle: FileSystemFileHandle;\n syncHandle: FileSystemSyncAccessHandle;\n refCount: number;\n }>();\n\n /** Map of open file descriptors to their metadata */\n private openFiles = new Map<number, {\n path: string;\n fileHandle: FileSystemFileHandle;\n syncHandle: FileSystemSyncAccessHandle;\n position: number;\n }>();\n\n /** Next available file descriptor number */\n private nextFd = 1;\n\n constructor(options?: OPFSOptions) {\n super(options);\n }\n\n /**\n * Get file info by descriptor with validation\n * @private\n */\n private _getFileDescriptor(fd: number): { path: string; fileHandle: FileSystemFileHandle; syncHandle: FileSystemSyncAccessHandle; position: number } {\n const fileInfo = this.openFiles.get(fd);\n\n if (!fileInfo) {\n throw new ValidationError('descriptor', `Invalid file descriptor: ${ fd }`);\n }\n\n return fileInfo;\n }\n\n async readFile(path: string): Promise<Uint8Array> {\n await this.mount();\n\n try {\n return await this.withPathLock(path, async() => {\n const fd = await this.open(path);\n\n try {\n const { size } = await this.fstat(fd);\n const buffer = new Uint8Array(size);\n\n if (size > 0) {\n await this.read(fd, buffer, 0, size, 0);\n }\n\n return transfer(buffer, [buffer.buffer]);\n }\n finally {\n await this.close(fd);\n }\n });\n }\n catch (err) {\n if (err instanceof OPFSError) {\n throw err;\n }\n\n throw mapDomError(err, { path, isDirectory: false });\n }\n }\n\n async writeFile(\n path: string,\n data: Uint8Array | ArrayBuffer\n ): Promise<void> {\n await this.mount();\n\n const buffer = data instanceof Uint8Array ? data : new Uint8Array(data);\n\n await this.withPathLock(path, async() => {\n const existed = await this.exists(path);\n const fd = await this.open(path, { create: true, truncate: true });\n\n try {\n await this.write(fd, buffer, 0, buffer.length, null, false);\n await this.fsync(fd);\n }\n finally {\n await this.close(fd);\n }\n\n await this.notifyChange({ path, type: existed ? WatchEventType.Changed : WatchEventType.Added, isDirectory: false });\n });\n }\n\n async appendFile(\n path: string,\n data: Uint8Array | ArrayBuffer\n ): Promise<void> {\n await this.mount();\n\n const buffer = data instanceof Uint8Array ? data : new Uint8Array(data);\n\n await this.withPathLock(path, async() => {\n const fd = await this.open(path, { create: true });\n\n try {\n const { size } = await this.fstat(fd);\n\n await this.write(fd, buffer, 0, buffer.length, size, false);\n await this.fsync(fd);\n }\n finally {\n await this.close(fd);\n }\n\n await this.notifyChange({ path, type: WatchEventType.Changed, isDirectory: false });\n });\n }\n\n async writeStream(\n path: string,\n stream: ReadableStream<Uint8Array>,\n onProgress?: (bytesWritten: number) => unknown\n ): Promise<number> {\n await this.mount();\n\n return this.withPathLock(path, async() => {\n const existed = await this.exists(path);\n const fd = await this.open(path, { create: true, truncate: true });\n const reader = stream.getReader();\n let totalBytes = 0;\n\n try {\n while (true) {\n const { done, value: chunk } = await reader.read();\n\n if (done) {\n break;\n }\n\n let offset = 0;\n\n while (offset < chunk.byteLength) {\n offset += await this.write(\n fd,\n chunk,\n offset,\n chunk.byteLength - offset,\n null,\n false\n );\n }\n\n totalBytes += chunk.byteLength;\n await onProgress?.(totalBytes);\n }\n\n await this.fsync(fd);\n }\n catch (error) {\n await reader.cancel(error).catch(() => {});\n\n throw error;\n }\n finally {\n reader.releaseLock();\n await this.close(fd);\n }\n\n await this.notifyChange({\n path,\n type: existed ? WatchEventType.Changed : WatchEventType.Added,\n isDirectory: false,\n });\n\n return totalBytes;\n });\n }\n\n async open(path: string, options?: FileOpenOptions): Promise<number> {\n await this.mount();\n\n const { create = false, exclusive = false, truncate = false } = options || {};\n\n // Normalize path to prevent path-related issues\n const normalizedPath = normalizePath(resolvePath(path));\n\n try {\n // Use lock for atomic operations when creating files\n if (create && exclusive) {\n return await this.withPathLock(normalizedPath, async() => {\n const exists = await this.exists(normalizedPath);\n\n if (exists) {\n throw new AlreadyExistsError(normalizedPath);\n }\n\n return this._openFile(normalizedPath, create, truncate);\n });\n }\n\n return await this._openFile(normalizedPath, create, truncate);\n }\n catch (error: any) {\n if (error instanceof OPFSError) {\n throw error;\n }\n\n // TypeMismatchError here means the path actually refers to a directory\n // so we map it as a directory-type error (EISDIR) for better Node.js parity.\n const isTypeMismatchDirectory = error && error.name === 'TypeMismatchError';\n\n throw mapDomError(error, {\n path: normalizedPath,\n isDirectory: !!isTypeMismatchDirectory,\n });\n }\n }\n\n /**\n * Internal method to open a file (without locking)\n *\n * Multiple FDs for the same path share one sync access handle (OPFS limit),\n * with independent per-FD positions — similar to Node.js.\n * @private\n */\n private async _openFile(path: string, create: boolean, truncate: boolean): Promise<number> {\n let shared = this.openHandles.get(path);\n\n if (!shared) {\n const fileHandle = await this.getFileHandle(path, create);\n\n // Verify that we got a file handle, not a directory\n try {\n await fileHandle.getFile();\n }\n catch (error: any) {\n throw mapDomError(error, { path, isDirectory: true });\n }\n\n const syncHandle = await createSyncHandleSafe(fileHandle, path);\n\n shared = { fileHandle, syncHandle, refCount: 0 };\n this.openHandles.set(path, shared);\n }\n\n shared.refCount++;\n\n if (truncate) {\n shared.syncHandle.truncate(0);\n shared.syncHandle.flush();\n }\n\n const fd = this.nextFd++;\n\n this.openFiles.set(fd, {\n path,\n fileHandle: shared.fileHandle,\n syncHandle: shared.syncHandle,\n position: 0,\n });\n\n return fd;\n }\n\n async close(fd: number): Promise<void> {\n const fileInfo = this._getFileDescriptor(fd);\n\n this.openFiles.delete(fd);\n\n const shared = this.openHandles.get(fileInfo.path);\n\n if (!shared) {\n return;\n }\n\n shared.refCount--;\n\n // Only close the underlying sync handle when the last FD for this path is gone\n if (shared.refCount <= 0) {\n safeCloseSyncHandle(fd, shared.syncHandle, fileInfo.path);\n this.openHandles.delete(fileInfo.path);\n }\n }\n\n async read(\n fd: number,\n buffer: Uint8Array,\n offset: number,\n length: number,\n position: number | null | undefined\n ): Promise<{ bytesRead: number; buffer: Uint8Array }> {\n const fileInfo = this._getFileDescriptor(fd);\n\n // Validate arguments\n validateReadWriteArgs(buffer.length, offset, length, position);\n\n try {\n const readPosition = position ?? fileInfo.position;\n\n // Get file size and calculate read length\n const fileSize = fileInfo.syncHandle.getSize();\n const { isEOF, actualLength } = calculateReadLength(readPosition, length, fileSize);\n\n if (isEOF) {\n return transfer({ bytesRead: 0, buffer }, [buffer.buffer]); // End of file\n }\n\n // Create a subarray view for the read operation\n const targetBuffer = buffer.subarray(offset, offset + actualLength);\n\n // Perform efficient positioned read\n const bytesRead = fileInfo.syncHandle.read(targetBuffer, { at: readPosition });\n\n // Update position if position was not explicitly specified (null means use current position)\n if (position == null) {\n fileInfo.position = readPosition + bytesRead;\n }\n\n return transfer({ bytesRead, buffer }, [buffer.buffer]);\n }\n catch (error) {\n throw createFDError('read', fd, fileInfo.path, error);\n }\n }\n\n async write(\n fd: number,\n buffer: Uint8Array,\n offset: number = 0,\n length?: number,\n position?: number | null | undefined,\n emitEvent: boolean = true\n ): Promise<number> {\n const fileInfo = this._getFileDescriptor(fd);\n\n // Calculate actual length to write\n const actualLength = length ?? (buffer.length - offset);\n\n // Validate arguments using helper\n validateReadWriteArgs(buffer.length, offset, actualLength, position);\n\n try {\n // Determine write position: use specified position, or current position if null/undefined\n const writePosition = position ?? fileInfo.position;\n\n // Create a subarray view for the write operation\n const sourceBuffer = buffer.subarray(offset, offset + actualLength);\n\n // Perform efficient positioned write\n const bytesWritten = fileInfo.syncHandle.write(sourceBuffer, { at: writePosition });\n\n // Update position if position was null or undefined (i.e., use current position)\n // Also update position when writing at current position (position === fileInfo.position)\n if (position == null || position === fileInfo.position) {\n fileInfo.position = writePosition + bytesWritten;\n }\n\n if (emitEvent) {\n await this.notifyChange({ path: fileInfo.path, type: WatchEventType.Changed, isDirectory: false });\n }\n\n return bytesWritten;\n }\n catch (error) {\n throw createFDError('write', fd, fileInfo.path, error);\n }\n }\n\n async fstat(fd: number): Promise<FileStat> {\n const fileInfo = this._getFileDescriptor(fd);\n\n // Simply reuse existing stat() method with the file path\n return this.stat(fileInfo.path);\n }\n\n async ftruncate(fd: number, size: number = 0): Promise<void> {\n const fileInfo = this._getFileDescriptor(fd);\n\n // Validate size parameter\n if (size < 0 || !Number.isInteger(size)) {\n throw new ValidationError('argument', 'Invalid size');\n }\n\n try {\n fileInfo.syncHandle.truncate(size);\n fileInfo.syncHandle.flush();\n\n // Adjust position if it's beyond the new file size\n if (fileInfo.position > size) {\n fileInfo.position = size;\n }\n\n await this.notifyChange({ path: fileInfo.path, type: WatchEventType.Changed, isDirectory: false });\n }\n catch (error) {\n throw createFDError('truncate', fd, fileInfo.path, error);\n }\n }\n\n async fsync(fd: number): Promise<void> {\n const fileInfo = this._getFileDescriptor(fd);\n\n try {\n fileInfo.syncHandle.flush();\n }\n catch (error) {\n throw createFDError('sync', fd, fileInfo.path, error);\n }\n }\n\n override dispose(): void {\n // Close each shared sync handle once (not per FD)\n for (const [path, shared] of this.openHandles) {\n safeCloseSyncHandle(-1, shared.syncHandle, path);\n }\n\n this.openHandles.clear();\n this.openFiles.clear();\n this.nextFd = 1;\n\n super.dispose();\n }\n}\n"],"names":["OPFSSync","BaseOPFS","options","fd","fileInfo","ValidationError","path","size","buffer","transfer","err","OPFSError","mapDomError","data","existed","WatchEventType","stream","onProgress","reader","totalBytes","done","chunk","offset","error","create","exclusive","truncate","normalizedPath","normalizePath","resolvePath","AlreadyExistsError","isTypeMismatchDirectory","shared","fileHandle","syncHandle","createSyncHandleSafe","safeCloseSyncHandle","length","position","validateReadWriteArgs","readPosition","fileSize","isEOF","actualLength","calculateReadLength","targetBuffer","bytesRead","createFDError","emitEvent","writePosition","sourceBuffer","bytesWritten"],"mappings":"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"}