@componentor/fs 2.0.0 → 2.0.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 CHANGED
@@ -446,6 +446,20 @@ Another tab or operation has the file open. The library uses `navigator.locks` t
446
446
 
447
447
  ## Changelog
448
448
 
449
+ ### v2.0.2 (2025)
450
+
451
+ **Improvements:**
452
+ - Sync access handles now auto-release after 5 seconds of inactivity
453
+ - Allows external tools (like OPFS Chrome extension) to access files when idle
454
+ - Maintains full performance during active operations
455
+
456
+ ### v2.0.1 (2025)
457
+
458
+ **Bug Fixes:**
459
+ - Fixed mtime not updating correctly when files are modified
460
+ - `stat()` now always returns accurate `lastModified` from OPFS instead of approximation
461
+ - Ensures git status and other mtime-dependent operations work correctly
462
+
449
463
  ### v2.0.0 (2025)
450
464
 
451
465
  **Major rewrite with sync API support and performance tiers.**
package/dist/kernel.js CHANGED
@@ -2,10 +2,40 @@
2
2
  var cachedRoot = null;
3
3
  var dirCache = /* @__PURE__ */ new Map();
4
4
  var syncHandleCache = /* @__PURE__ */ new Map();
5
+ var syncHandleLastAccess = /* @__PURE__ */ new Map();
5
6
  var MAX_SYNC_HANDLES = 100;
7
+ var HANDLE_IDLE_TIMEOUT = 5e3;
8
+ var idleCleanupTimer = null;
9
+ function scheduleIdleCleanup() {
10
+ if (idleCleanupTimer) return;
11
+ idleCleanupTimer = setTimeout(() => {
12
+ idleCleanupTimer = null;
13
+ const now = Date.now();
14
+ for (const [path, lastAccess] of syncHandleLastAccess) {
15
+ if (now - lastAccess > HANDLE_IDLE_TIMEOUT) {
16
+ const handle = syncHandleCache.get(path);
17
+ if (handle) {
18
+ try {
19
+ handle.flush();
20
+ handle.close();
21
+ } catch {
22
+ }
23
+ syncHandleCache.delete(path);
24
+ }
25
+ syncHandleLastAccess.delete(path);
26
+ }
27
+ }
28
+ if (syncHandleCache.size > 0) {
29
+ scheduleIdleCleanup();
30
+ }
31
+ }, HANDLE_IDLE_TIMEOUT);
32
+ }
6
33
  async function getSyncAccessHandle(filePath, create) {
7
34
  const cached = syncHandleCache.get(filePath);
8
- if (cached) return cached;
35
+ if (cached) {
36
+ syncHandleLastAccess.set(filePath, Date.now());
37
+ return cached;
38
+ }
9
39
  if (syncHandleCache.size >= MAX_SYNC_HANDLES) {
10
40
  const keysToDelete = Array.from(syncHandleCache.keys()).slice(0, 10);
11
41
  for (const key of keysToDelete) {
@@ -16,12 +46,15 @@ async function getSyncAccessHandle(filePath, create) {
16
46
  } catch {
17
47
  }
18
48
  syncHandleCache.delete(key);
49
+ syncHandleLastAccess.delete(key);
19
50
  }
20
51
  }
21
52
  }
22
53
  const fh = await getFileHandle(filePath, create);
23
54
  const access = await fh.createSyncAccessHandle();
24
55
  syncHandleCache.set(filePath, access);
56
+ syncHandleLastAccess.set(filePath, Date.now());
57
+ scheduleIdleCleanup();
25
58
  return access;
26
59
  }
27
60
  function closeSyncHandle(filePath) {
@@ -32,6 +65,7 @@ function closeSyncHandle(filePath) {
32
65
  } catch {
33
66
  }
34
67
  syncHandleCache.delete(filePath);
68
+ syncHandleLastAccess.delete(filePath);
35
69
  }
36
70
  }
37
71
  function closeAllSyncHandlesUnder(pathPrefix) {
@@ -43,10 +77,15 @@ function closeAllSyncHandlesUnder(pathPrefix) {
43
77
  } catch {
44
78
  }
45
79
  syncHandleCache.delete(path);
80
+ syncHandleLastAccess.delete(path);
46
81
  }
47
82
  }
48
83
  }
49
84
  function purgeAllCaches() {
85
+ if (idleCleanupTimer) {
86
+ clearTimeout(idleCleanupTimer);
87
+ idleCleanupTimer = null;
88
+ }
50
89
  for (const handle of syncHandleCache.values()) {
51
90
  try {
52
91
  handle.flush();
@@ -55,6 +94,7 @@ function purgeAllCaches() {
55
94
  }
56
95
  }
57
96
  syncHandleCache.clear();
97
+ syncHandleLastAccess.clear();
58
98
  dirCache.clear();
59
99
  cachedRoot = null;
60
100
  }
@@ -156,15 +196,6 @@ async function handleStat(filePath, metaBuffer) {
156
196
  view.setFloat64(16, Date.now(), true);
157
197
  return STAT_SIZE;
158
198
  }
159
- const cachedHandle = syncHandleCache.get(filePath);
160
- if (cachedHandle) {
161
- const size = cachedHandle.getSize();
162
- view.setUint8(0, 0);
163
- view.setUint32(4, 33188, true);
164
- view.setFloat64(8, size, true);
165
- view.setFloat64(16, Date.now(), true);
166
- return STAT_SIZE;
167
- }
168
199
  const name = parts.pop();
169
200
  const parent = parts.length > 0 ? await getDirectoryHandle(parts, false) : await getRoot();
170
201
  try {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/worker/kernel.ts"],"sourcesContent":["/**\n * OPFS Worker Kernel\n * Runs in a dedicated Web Worker thread, handles all OPFS operations.\n * Uses SharedArrayBuffer + Atomics for zero-copy data transfer and synchronization.\n */\n\n/// <reference lib=\"webworker\" />\n\ninterface KernelMessage {\n type: string;\n path: string;\n ctrlBuffer: SharedArrayBuffer; // SharedArrayBuffer for control signal\n metaBuffer: SharedArrayBuffer;\n dataBuffer: SharedArrayBuffer;\n dataLength?: number;\n payload?: {\n offset?: number;\n len?: number;\n newPath?: string;\n recursive?: boolean;\n truncate?: boolean; // For write: false to keep existing data (stream mode)\n };\n}\n\n// Cache for performance\nlet cachedRoot: FileSystemDirectoryHandle | null = null;\nconst dirCache = new Map<string, FileSystemDirectoryHandle>();\n\n// Sync access handle cache - MAJOR performance optimization (2-5x speedup)\n// Handles are kept open and reused, only closed on file deletion/rename/shutdown\nconst syncHandleCache = new Map<string, FileSystemSyncAccessHandle>();\nconst MAX_SYNC_HANDLES = 100; // Limit cache size to prevent memory issues\n\nasync function getSyncAccessHandle(\n filePath: string,\n create: boolean\n): Promise<FileSystemSyncAccessHandle> {\n const cached = syncHandleCache.get(filePath);\n if (cached) return cached;\n\n // Evict oldest handles if cache is full to prevent memory issues\n if (syncHandleCache.size >= MAX_SYNC_HANDLES) {\n const keysToDelete = Array.from(syncHandleCache.keys()).slice(0, 10);\n for (const key of keysToDelete) {\n const handle = syncHandleCache.get(key);\n if (handle) {\n try { handle.close(); } catch { /* ignore */ }\n syncHandleCache.delete(key);\n }\n }\n }\n\n const fh = await getFileHandle(filePath, create);\n const access = await fh.createSyncAccessHandle();\n syncHandleCache.set(filePath, access);\n return access;\n}\n\nfunction closeSyncHandle(filePath: string): void {\n const handle = syncHandleCache.get(filePath);\n if (handle) {\n try {\n handle.close();\n } catch {\n // Ignore close errors (handle may already be closed)\n }\n syncHandleCache.delete(filePath);\n }\n}\n\nfunction closeAllSyncHandlesUnder(pathPrefix: string): void {\n for (const [path, handle] of syncHandleCache) {\n if (path === pathPrefix || path.startsWith(pathPrefix + '/')) {\n try {\n // Flush before closing to ensure data is persisted\n handle.flush();\n handle.close();\n } catch {\n // Ignore errors (handle may already be closed)\n }\n syncHandleCache.delete(path);\n }\n }\n}\n\n// Completely purge all caches - use before major cleanup operations\nfunction purgeAllCaches(): void {\n // Flush and close all sync handles\n for (const handle of syncHandleCache.values()) {\n try {\n handle.flush();\n handle.close();\n } catch {\n // Ignore errors\n }\n }\n syncHandleCache.clear();\n\n // Clear directory cache\n dirCache.clear();\n\n // Clear root cache\n cachedRoot = null;\n}\n\n// Flush all cached sync handles to ensure data is persisted\nfunction flushAllSyncHandles(): void {\n for (const handle of syncHandleCache.values()) {\n try {\n handle.flush();\n } catch {\n // Ignore flush errors (handle may be invalid)\n }\n }\n}\n\nasync function getRoot(): Promise<FileSystemDirectoryHandle> {\n if (!cachedRoot) {\n cachedRoot = await navigator.storage.getDirectory();\n }\n return cachedRoot;\n}\n\nfunction parsePath(filePath: string): string[] {\n return filePath.split('/').filter(Boolean);\n}\n\nasync function getDirectoryHandle(\n parts: string[],\n create = false\n): Promise<FileSystemDirectoryHandle> {\n if (parts.length === 0) return getRoot();\n\n const cacheKey = parts.join('/');\n const cached = dirCache.get(cacheKey);\n if (cached) return cached;\n\n let curr = await getRoot();\n let pathSoFar = '';\n\n for (const part of parts) {\n pathSoFar += (pathSoFar ? '/' : '') + part;\n\n const cachedDir = dirCache.get(pathSoFar);\n if (cachedDir) {\n curr = cachedDir;\n } else {\n curr = await curr.getDirectoryHandle(part, { create });\n dirCache.set(pathSoFar, curr);\n }\n }\n\n return curr;\n}\n\nasync function getFileHandle(\n filePath: string,\n create = false\n): Promise<FileSystemFileHandle> {\n const parts = parsePath(filePath);\n const fileName = parts.pop();\n if (!fileName) throw new Error('Invalid file path');\n const dir = parts.length > 0 ? await getDirectoryHandle(parts, create) : await getRoot();\n return await dir.getFileHandle(fileName, { create });\n}\n\nasync function getParentAndName(\n filePath: string\n): Promise<{ parent: FileSystemDirectoryHandle; name: string }> {\n const parts = parsePath(filePath);\n const name = parts.pop();\n if (!name) throw new Error('Invalid path');\n const parent = parts.length > 0 ? await getDirectoryHandle(parts, false) : await getRoot();\n return { parent, name };\n}\n\n// Operation handlers - use SharedArrayBuffer for data transfer\n\nasync function handleRead(\n filePath: string,\n dataBuffer: SharedArrayBuffer,\n payload?: { offset?: number; len?: number }\n): Promise<number> {\n const access = await getSyncAccessHandle(filePath, false);\n const size = access.getSize();\n const offset = payload?.offset || 0;\n const len = payload?.len || (size - offset);\n\n // Read directly into SharedArrayBuffer\n const view = new Uint8Array(dataBuffer, 0, Math.min(len, dataBuffer.byteLength));\n const bytesRead = access.read(view, { at: offset });\n return bytesRead;\n}\n\nasync function handleWrite(\n filePath: string,\n dataBuffer: SharedArrayBuffer,\n dataLength: number,\n payload?: { offset?: number; truncate?: boolean; flush?: boolean }\n): Promise<number> {\n const access = await getSyncAccessHandle(filePath, true);\n const offset = payload?.offset ?? 0;\n // Truncate by default when offset is 0 (writeFileSync behavior),\n // but allow callers to opt out for stream writes\n const shouldTruncate = payload?.truncate ?? (offset === 0);\n if (shouldTruncate) {\n access.truncate(0);\n }\n // Read from SharedArrayBuffer\n const data = new Uint8Array(dataBuffer, 0, dataLength);\n access.write(data, { at: offset });\n // Flush by default for durability, but allow skipping for performance\n // Data is still written and readable, just not guaranteed to survive crashes\n if (payload?.flush !== false) {\n access.flush();\n }\n return 1; // Success\n}\n\nasync function handleAppend(\n filePath: string,\n dataBuffer: SharedArrayBuffer,\n dataLength: number\n): Promise<number> {\n const access = await getSyncAccessHandle(filePath, true);\n const size = access.getSize();\n const data = new Uint8Array(dataBuffer, 0, dataLength);\n access.write(data, { at: size });\n access.flush();\n return 1;\n}\n\nasync function handleTruncate(\n filePath: string,\n payload?: { len?: number }\n): Promise<number> {\n const access = await getSyncAccessHandle(filePath, false);\n access.truncate(payload?.len ?? 0);\n access.flush();\n return 1;\n}\n\n// Binary stat layout (24 bytes) - faster than JSON for hot path:\n// Offset 0: type (Uint8) - 0=file, 1=directory\n// Offset 4: mode (Uint32)\n// Offset 8: size (Float64)\n// Offset 16: mtimeMs (Float64)\nconst STAT_SIZE = 24;\n\nasync function handleStat(\n filePath: string,\n metaBuffer: SharedArrayBuffer\n): Promise<number> {\n const parts = parsePath(filePath);\n const view = new DataView(metaBuffer);\n\n // mode: 33188 = 0o100644 (regular file), 16877 = 0o40755 (directory)\n if (parts.length === 0) {\n view.setUint8(0, 1); // directory\n view.setUint32(4, 16877, true);\n view.setFloat64(8, 0, true); // size\n view.setFloat64(16, Date.now(), true); // mtimeMs\n return STAT_SIZE;\n }\n\n // Fast path: if sync handle is cached, we know it's a file\n const cachedHandle = syncHandleCache.get(filePath);\n if (cachedHandle) {\n const size = cachedHandle.getSize();\n view.setUint8(0, 0); // file\n view.setUint32(4, 33188, true);\n view.setFloat64(8, size, true);\n // Note: can't get mtime from sync handle, use current time as approximation\n view.setFloat64(16, Date.now(), true);\n return STAT_SIZE;\n }\n\n const name = parts.pop()!;\n const parent = parts.length > 0 ? await getDirectoryHandle(parts, false) : await getRoot();\n\n try {\n const fh = await parent.getFileHandle(name);\n const file = await fh.getFile();\n view.setUint8(0, 0); // file\n view.setUint32(4, 33188, true);\n view.setFloat64(8, file.size, true);\n view.setFloat64(16, file.lastModified, true);\n return STAT_SIZE;\n } catch {\n try {\n await parent.getDirectoryHandle(name);\n view.setUint8(0, 1); // directory\n view.setUint32(4, 16877, true);\n view.setFloat64(8, 0, true);\n view.setFloat64(16, Date.now(), true);\n return STAT_SIZE;\n } catch {\n return -2; // Not found\n }\n }\n}\n\nasync function handleExists(filePath: string): Promise<number> {\n // Fast path: if sync handle is cached, file definitely exists\n if (syncHandleCache.has(filePath)) return 1;\n\n try {\n const parts = parsePath(filePath);\n if (parts.length === 0) return 1;\n\n const name = parts.pop()!;\n const parent = parts.length > 0 ? await getDirectoryHandle(parts, false) : await getRoot();\n\n try {\n await parent.getFileHandle(name);\n return 1;\n } catch {\n try {\n await parent.getDirectoryHandle(name);\n return 1;\n } catch {\n return 0;\n }\n }\n } catch {\n return 0;\n }\n}\n\nasync function handleMkdir(\n filePath: string,\n payload?: { recursive?: boolean }\n): Promise<number> {\n const parts = parsePath(filePath);\n\n if (payload?.recursive) {\n let curr = await getRoot();\n for (const part of parts) {\n curr = await curr.getDirectoryHandle(part, { create: true });\n }\n } else {\n const name = parts.pop();\n if (!name) throw new Error('Invalid path');\n const parent = parts.length > 0 ? await getDirectoryHandle(parts, false) : await getRoot();\n await parent.getDirectoryHandle(name, { create: true });\n }\n\n return 1;\n}\n\nasync function handleRmdir(\n filePath: string,\n payload?: { recursive?: boolean }\n): Promise<number> {\n const { parent, name } = await getParentAndName(filePath);\n // Normalize path - ensure leading slash for consistent cache lookups\n const normalizedPath = '/' + parsePath(filePath).join('/');\n const pathPrefix = parsePath(filePath).join('/');\n\n if (payload?.recursive) {\n // Close ALL cached sync handles for files under this directory\n // Use normalized path with leading slash to match cached handle keys\n closeAllSyncHandlesUnder(normalizedPath);\n await parent.removeEntry(name, { recursive: true });\n // Clear ALL cached dir handles that start with this path prefix\n for (const key of dirCache.keys()) {\n if (key === pathPrefix || key.startsWith(pathPrefix + '/')) {\n dirCache.delete(key);\n }\n }\n } else {\n const dir = await parent.getDirectoryHandle(name);\n const entries = dir.entries();\n const first = await entries.next();\n if (!first.done) {\n // Use InvalidModificationError so it maps to ENOTEMPTY\n const e = new Error('InvalidModificationError');\n e.name = 'InvalidModificationError';\n throw e;\n }\n await parent.removeEntry(name);\n // Only invalidate the specific directory\n dirCache.delete(pathPrefix);\n }\n\n return 1;\n}\n\nasync function handleUnlink(filePath: string): Promise<number> {\n const { parent, name } = await getParentAndName(filePath);\n\n // Verify it's a file, not a directory (Node.js unlink semantics)\n try {\n await parent.getFileHandle(name);\n } catch {\n // Check if it's a directory\n try {\n await parent.getDirectoryHandle(name);\n throw new Error('EISDIR: illegal operation on a directory');\n } catch (e) {\n // Re-throw EISDIR, otherwise it's not found\n if ((e as Error).message?.includes('EISDIR')) throw e;\n throw new Error('NotFoundError');\n }\n }\n\n // Close cached sync handle before removing file\n closeSyncHandle(filePath);\n await parent.removeEntry(name);\n return 1;\n}\n\n// Binary readdir layout - faster than JSON for hot path:\n// Offset 0: entry count (Uint32)\n// For each entry: 2 bytes length (Uint16) + UTF-8 name bytes\nconst textEncoder = new TextEncoder();\n\nasync function handleReaddir(\n filePath: string,\n metaBuffer: SharedArrayBuffer\n): Promise<number> {\n const parts = parsePath(filePath);\n const dir = parts.length > 0 ? await getDirectoryHandle(parts, false) : await getRoot();\n\n // Collect entries\n const entries: string[] = [];\n for await (const [name] of dir.entries()) {\n entries.push(name);\n }\n\n // Binary encode: [count:u32] [len:u16 + utf8]...\n const view = new DataView(metaBuffer);\n const bytes = new Uint8Array(metaBuffer);\n view.setUint32(0, entries.length, true);\n\n let offset = 4;\n for (const name of entries) {\n const encoded = textEncoder.encode(name);\n view.setUint16(offset, encoded.length, true);\n offset += 2;\n bytes.set(encoded, offset);\n offset += encoded.length;\n }\n\n return offset;\n}\n\n// === MEMORY-SAFE CHUNK ALLOCATION (Zero overhead in normal operation) ===\n\nconst MIN_CHUNK = 64 * 1024; // 64KB floor\nconst MAX_CHUNK = 1024 * 1024; // 1MB ceiling\nconst DEFAULT_CHUNK = 256 * 1024; // 256KB default\nconst LAST_RESORT_CHUNK = 8 * 1024; // 8KB emergency\n\n// State\nlet chunkSize = DEFAULT_CHUNK;\nlet failureCount = 0;\n\n// Only yield on actual failure (use microtask, not setTimeout)\nconst yieldMicrotask = (): Promise<void> => new Promise(resolve => queueMicrotask(resolve));\n\n// Get current chunk size (fast path - just return cached value)\nfunction getChunkSize(): number {\n return chunkSize;\n}\n\n// Called after successful operations - gradually recover chunk size\nfunction maybeIncreaseChunk(): void {\n if (failureCount === 0 && chunkSize < MAX_CHUNK) {\n chunkSize = Math.min(MAX_CHUNK, chunkSize + 64 * 1024);\n }\n}\n\n// Called on allocation failure - reduce and remember\nfunction reduceChunkOnFailure(): number {\n failureCount++;\n chunkSize = Math.max(MIN_CHUNK, Math.floor(chunkSize / 2));\n return chunkSize;\n}\n\n// Safe allocation - only adds overhead on actual failure\nasync function safeAllocateChunk(\n srcFile: File,\n offset: number,\n requestedSize: number\n): Promise<Uint8Array> {\n const size = Math.min(requestedSize, chunkSize);\n\n try {\n // Fast path - no overhead\n const chunk = srcFile.slice(offset, offset + size);\n return new Uint8Array(await chunk.arrayBuffer());\n } catch (e) {\n // Slow path - only on failure\n const msg = e instanceof Error ? e.message : String(e);\n if (!msg.includes('allocation') && !msg.includes('Array buffer') && !msg.includes('out of memory')) {\n throw e; // Not a memory error\n }\n\n // Retry with smaller chunks\n let retrySize = reduceChunkOnFailure();\n while (retrySize >= MIN_CHUNK) {\n await yieldMicrotask(); // Microtask yield (fast, not setTimeout)\n try {\n const chunk = srcFile.slice(offset, offset + retrySize);\n return new Uint8Array(await chunk.arrayBuffer());\n } catch {\n retrySize = reduceChunkOnFailure();\n }\n }\n\n // Last resort\n await yieldMicrotask();\n try {\n chunkSize = LAST_RESORT_CHUNK;\n const chunk = srcFile.slice(offset, offset + LAST_RESORT_CHUNK);\n return new Uint8Array(await chunk.arrayBuffer());\n } catch {\n throw new Error('ENOMEM: unable to allocate memory');\n }\n }\n}\n\n// Lock-protected streaming copy using cached sync handles\nasync function streamCopyFile(\n srcHandle: FileSystemFileHandle,\n dstPath: string\n): Promise<void> {\n const srcFile = await srcHandle.getFile();\n const size = srcFile.size;\n\n // Lock destination path for multi-tab safety\n await navigator.locks.request(`opfs:${dstPath}`, async () => {\n const access = await getSyncAccessHandle(dstPath, true);\n access.truncate(0);\n\n // Chunked streaming for memory safety\n let offset = 0;\n while (offset < size) {\n const remaining = size - offset;\n\n // Safe allocation (only adds overhead on failure)\n const data = await safeAllocateChunk(srcFile, offset, remaining);\n\n access.write(data, { at: offset });\n offset += data.byteLength;\n }\n\n // Gradually recover chunk size after successful operation\n maybeIncreaseChunk();\n access.flush();\n });\n}\n\nasync function handleRename(\n oldPath: string,\n payload?: { newPath?: string }\n): Promise<number> {\n if (!payload?.newPath) throw new Error('newPath required');\n\n const newPath = payload.newPath;\n const oldParts = parsePath(oldPath);\n const newParts = parsePath(newPath);\n\n const oldName = oldParts.pop()!;\n const newName = newParts.pop()!;\n\n const oldParent = oldParts.length > 0 ? await getDirectoryHandle(oldParts, false) : await getRoot();\n const newParent = newParts.length > 0 ? await getDirectoryHandle(newParts, true) : await getRoot();\n\n // Try file first\n try {\n const fh = await oldParent.getFileHandle(oldName);\n\n // Close cached sync handle before rename\n closeSyncHandle(oldPath);\n\n // TIER 1: Use native move() if available (fastest, zero-copy, memory safe)\n if ('move' in fh && typeof (fh as any).move === 'function') {\n await (fh as any).move(newParent, newName);\n return 1;\n }\n\n // TIER 2: Fallback to stream copy (memory safe for large files)\n await streamCopyFile(fh, newPath);\n await oldParent.removeEntry(oldName);\n return 1;\n } catch {\n // Directory rename\n const oldDir = await oldParent.getDirectoryHandle(oldName);\n const pathPrefix = parsePath(oldPath).join('/');\n\n // Close all cached sync handles for files in this directory\n closeAllSyncHandlesUnder(pathPrefix);\n\n // Try native move for directories too\n if ('move' in oldDir && typeof (oldDir as any).move === 'function') {\n await (oldDir as any).move(newParent, newName);\n // Invalidate dir cache for moved directory\n for (const key of dirCache.keys()) {\n if (key === pathPrefix || key.startsWith(pathPrefix + '/')) {\n dirCache.delete(key);\n }\n }\n return 1;\n }\n\n // Fallback: recursive copy with streaming (track paths for lock discipline)\n async function copyDir(src: FileSystemDirectoryHandle, dst: FileSystemDirectoryHandle, dstBasePath: string) {\n for await (const [name, handle] of src.entries()) {\n const dstFilePath = dstBasePath + '/' + name;\n if (handle.kind === 'file') {\n const srcFile = handle as FileSystemFileHandle;\n await streamCopyFile(srcFile, dstFilePath);\n } else {\n const newSubDir = await dst.getDirectoryHandle(name, { create: true });\n await copyDir(handle as FileSystemDirectoryHandle, newSubDir, dstFilePath);\n }\n }\n }\n\n const newDir = await newParent.getDirectoryHandle(newName, { create: true });\n await copyDir(oldDir, newDir, newPath);\n await oldParent.removeEntry(oldName, { recursive: true });\n\n // Invalidate dir cache (pathPrefix already defined above)\n for (const key of dirCache.keys()) {\n if (key === pathPrefix || key.startsWith(pathPrefix + '/')) {\n dirCache.delete(key);\n }\n }\n\n return 1;\n }\n}\n\nasync function handleCopy(\n srcPath: string,\n payload?: { newPath?: string }\n): Promise<number> {\n if (!payload?.newPath) throw new Error('newPath required');\n\n const dstPath = payload.newPath;\n const srcParts = parsePath(srcPath);\n const srcName = srcParts.pop()!;\n const srcParent = srcParts.length > 0 ? await getDirectoryHandle(srcParts, false) : await getRoot();\n const srcFh = await srcParent.getFileHandle(srcName);\n\n // Use streaming copy with lock-protected destination (memory safe for large files)\n await streamCopyFile(srcFh, dstPath);\n\n return 1;\n}\n\n// Operations that don't need per-file locking\nconst LOCKLESS_OPS = new Set(['stat', 'exists', 'readdir', 'mkdir', 'flush', 'purge']);\n\n// Process incoming messages with SharedArrayBuffer-based communication\nasync function processMessage(msg: KernelMessage): Promise<void> {\n const { type, path: filePath, ctrlBuffer, metaBuffer, dataBuffer, dataLength, payload } = msg;\n\n // Create Int32Array view from the SharedArrayBuffer\n const ctrl = new Int32Array(ctrlBuffer);\n\n // Core operation logic\n const executeOperation = async (): Promise<number> => {\n switch (type) {\n case 'read':\n case 'readChunk': // Alias for chunked reads (same handler, different offset/len)\n return handleRead(filePath, dataBuffer, payload);\n case 'write':\n return handleWrite(filePath, dataBuffer, dataLength || 0, payload);\n case 'append':\n return handleAppend(filePath, dataBuffer, dataLength || 0);\n case 'truncate':\n return handleTruncate(filePath, payload);\n case 'stat':\n return handleStat(filePath, metaBuffer);\n case 'exists':\n return handleExists(filePath);\n case 'mkdir':\n return handleMkdir(filePath, payload);\n case 'rmdir':\n return handleRmdir(filePath, payload);\n case 'unlink':\n return handleUnlink(filePath);\n case 'readdir':\n return handleReaddir(filePath, metaBuffer);\n case 'rename':\n return handleRename(filePath, payload);\n case 'copy':\n return handleCopy(filePath, payload);\n case 'flush':\n flushAllSyncHandles();\n return 1;\n case 'purge':\n // Completely clear all caches - use between major operations\n purgeAllCaches();\n return 1;\n default:\n throw new Error(`Unknown operation: ${type}`);\n }\n };\n\n // Wrapper that handles result signaling\n const runAndSignal = async () => {\n try {\n const result = await executeOperation();\n Atomics.store(ctrl, 0, result);\n } catch (e: unknown) {\n const error = e instanceof Error ? e : new Error(String(e));\n const errorName = error.name || '';\n const errorMsg = error.message || 'Unknown error';\n\n // Check both error name and message for not-found conditions\n // DOM exceptions have name='NotFoundError' and message like \"could not be found\"\n const isNotFound = errorName === 'NotFoundError' ||\n errorMsg.includes('NotFoundError') ||\n errorMsg.includes('not found') ||\n errorMsg.includes('could not be found');\n\n if (isNotFound) {\n Atomics.store(ctrl, 0, -2);\n } else {\n // Write error name to metaBuffer for proper error mapping\n // Use error name if it's a known DOM exception, otherwise use message\n const errorInfo = errorName && errorName !== 'Error' ? errorName : errorMsg;\n const encoded = new TextEncoder().encode(errorInfo);\n const view = new Uint8Array(metaBuffer);\n view.set(encoded);\n // Add null terminator to prevent reading stale data from reused buffer\n if (encoded.length < metaBuffer.byteLength) {\n view[encoded.length] = 0;\n }\n Atomics.store(ctrl, 0, -1);\n }\n }\n Atomics.notify(ctrl, 0);\n };\n\n // Use Web Locks API to prevent NoModificationAllowedError across tabs\n // Skip locking for read-only operations that don't use createSyncAccessHandle\n if (LOCKLESS_OPS.has(type)) {\n await runAndSignal();\n } else {\n await navigator.locks.request(`opfs:${filePath}`, runAndSignal);\n }\n}\n\n// Main message handler\n// Note: Serialization is NOT needed here because:\n// - Tier 1 Sync: Client blocks on Atomics.wait, so only one message at a time\n// - Tier 1 Async: Client serializes via asyncOperationPromise before sending\nself.onmessage = (event: MessageEvent<KernelMessage>) => {\n processMessage(event.data);\n};\n\n// Signal ready\nself.postMessage({ type: 'ready' });\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/worker/kernel.ts"],"sourcesContent":["/**\n * OPFS Worker Kernel\n * Runs in a dedicated Web Worker thread, handles all OPFS operations.\n * Uses SharedArrayBuffer + Atomics for zero-copy data transfer and synchronization.\n */\n\n/// <reference lib=\"webworker\" />\n\ninterface KernelMessage {\n type: string;\n path: string;\n ctrlBuffer: SharedArrayBuffer; // SharedArrayBuffer for control signal\n metaBuffer: SharedArrayBuffer;\n dataBuffer: SharedArrayBuffer;\n dataLength?: number;\n payload?: {\n offset?: number;\n len?: number;\n newPath?: string;\n recursive?: boolean;\n truncate?: boolean; // For write: false to keep existing data (stream mode)\n };\n}\n\n// Cache for performance\nlet cachedRoot: FileSystemDirectoryHandle | null = null;\nconst dirCache = new Map<string, FileSystemDirectoryHandle>();\n\n// Sync access handle cache - MAJOR performance optimization (2-5x speedup)\n// Handles are cached during active use but auto-released after idle timeout\n// This allows external tools (like OPFS Chrome extension) to access files when idle\nconst syncHandleCache = new Map<string, FileSystemSyncAccessHandle>();\nconst syncHandleLastAccess = new Map<string, number>();\nconst MAX_SYNC_HANDLES = 100; // Limit cache size to prevent memory issues\nconst HANDLE_IDLE_TIMEOUT = 5000; // Release handles after 5 seconds of inactivity\nlet idleCleanupTimer: ReturnType<typeof setTimeout> | null = null;\n\n// Periodically close idle handles to allow external access\nfunction scheduleIdleCleanup(): void {\n if (idleCleanupTimer) return; // Already scheduled\n\n idleCleanupTimer = setTimeout(() => {\n idleCleanupTimer = null;\n const now = Date.now();\n\n for (const [path, lastAccess] of syncHandleLastAccess) {\n if (now - lastAccess > HANDLE_IDLE_TIMEOUT) {\n const handle = syncHandleCache.get(path);\n if (handle) {\n try {\n handle.flush();\n handle.close();\n } catch { /* ignore */ }\n syncHandleCache.delete(path);\n }\n syncHandleLastAccess.delete(path);\n }\n }\n\n // Reschedule if there are still cached handles\n if (syncHandleCache.size > 0) {\n scheduleIdleCleanup();\n }\n }, HANDLE_IDLE_TIMEOUT);\n}\n\nasync function getSyncAccessHandle(\n filePath: string,\n create: boolean\n): Promise<FileSystemSyncAccessHandle> {\n const cached = syncHandleCache.get(filePath);\n if (cached) {\n // Update last access time\n syncHandleLastAccess.set(filePath, Date.now());\n return cached;\n }\n\n // Evict oldest handles if cache is full to prevent memory issues\n if (syncHandleCache.size >= MAX_SYNC_HANDLES) {\n const keysToDelete = Array.from(syncHandleCache.keys()).slice(0, 10);\n for (const key of keysToDelete) {\n const handle = syncHandleCache.get(key);\n if (handle) {\n try { handle.close(); } catch { /* ignore */ }\n syncHandleCache.delete(key);\n syncHandleLastAccess.delete(key);\n }\n }\n }\n\n const fh = await getFileHandle(filePath, create);\n const access = await fh.createSyncAccessHandle();\n syncHandleCache.set(filePath, access);\n syncHandleLastAccess.set(filePath, Date.now());\n\n // Schedule cleanup for idle handles\n scheduleIdleCleanup();\n\n return access;\n}\n\nfunction closeSyncHandle(filePath: string): void {\n const handle = syncHandleCache.get(filePath);\n if (handle) {\n try {\n handle.close();\n } catch {\n // Ignore close errors (handle may already be closed)\n }\n syncHandleCache.delete(filePath);\n syncHandleLastAccess.delete(filePath);\n }\n}\n\nfunction closeAllSyncHandlesUnder(pathPrefix: string): void {\n for (const [path, handle] of syncHandleCache) {\n if (path === pathPrefix || path.startsWith(pathPrefix + '/')) {\n try {\n // Flush before closing to ensure data is persisted\n handle.flush();\n handle.close();\n } catch {\n // Ignore errors (handle may already be closed)\n }\n syncHandleCache.delete(path);\n syncHandleLastAccess.delete(path);\n }\n }\n}\n\n// Completely purge all caches - use before major cleanup operations\nfunction purgeAllCaches(): void {\n // Cancel any scheduled idle cleanup\n if (idleCleanupTimer) {\n clearTimeout(idleCleanupTimer);\n idleCleanupTimer = null;\n }\n\n // Flush and close all sync handles\n for (const handle of syncHandleCache.values()) {\n try {\n handle.flush();\n handle.close();\n } catch {\n // Ignore errors\n }\n }\n syncHandleCache.clear();\n syncHandleLastAccess.clear();\n\n // Clear directory cache\n dirCache.clear();\n\n // Clear root cache\n cachedRoot = null;\n}\n\n// Flush all cached sync handles to ensure data is persisted\nfunction flushAllSyncHandles(): void {\n for (const handle of syncHandleCache.values()) {\n try {\n handle.flush();\n } catch {\n // Ignore flush errors (handle may be invalid)\n }\n }\n}\n\nasync function getRoot(): Promise<FileSystemDirectoryHandle> {\n if (!cachedRoot) {\n cachedRoot = await navigator.storage.getDirectory();\n }\n return cachedRoot;\n}\n\nfunction parsePath(filePath: string): string[] {\n return filePath.split('/').filter(Boolean);\n}\n\nasync function getDirectoryHandle(\n parts: string[],\n create = false\n): Promise<FileSystemDirectoryHandle> {\n if (parts.length === 0) return getRoot();\n\n const cacheKey = parts.join('/');\n const cached = dirCache.get(cacheKey);\n if (cached) return cached;\n\n let curr = await getRoot();\n let pathSoFar = '';\n\n for (const part of parts) {\n pathSoFar += (pathSoFar ? '/' : '') + part;\n\n const cachedDir = dirCache.get(pathSoFar);\n if (cachedDir) {\n curr = cachedDir;\n } else {\n curr = await curr.getDirectoryHandle(part, { create });\n dirCache.set(pathSoFar, curr);\n }\n }\n\n return curr;\n}\n\nasync function getFileHandle(\n filePath: string,\n create = false\n): Promise<FileSystemFileHandle> {\n const parts = parsePath(filePath);\n const fileName = parts.pop();\n if (!fileName) throw new Error('Invalid file path');\n const dir = parts.length > 0 ? await getDirectoryHandle(parts, create) : await getRoot();\n return await dir.getFileHandle(fileName, { create });\n}\n\nasync function getParentAndName(\n filePath: string\n): Promise<{ parent: FileSystemDirectoryHandle; name: string }> {\n const parts = parsePath(filePath);\n const name = parts.pop();\n if (!name) throw new Error('Invalid path');\n const parent = parts.length > 0 ? await getDirectoryHandle(parts, false) : await getRoot();\n return { parent, name };\n}\n\n// Operation handlers - use SharedArrayBuffer for data transfer\n\nasync function handleRead(\n filePath: string,\n dataBuffer: SharedArrayBuffer,\n payload?: { offset?: number; len?: number }\n): Promise<number> {\n const access = await getSyncAccessHandle(filePath, false);\n const size = access.getSize();\n const offset = payload?.offset || 0;\n const len = payload?.len || (size - offset);\n\n // Read directly into SharedArrayBuffer\n const view = new Uint8Array(dataBuffer, 0, Math.min(len, dataBuffer.byteLength));\n const bytesRead = access.read(view, { at: offset });\n return bytesRead;\n}\n\nasync function handleWrite(\n filePath: string,\n dataBuffer: SharedArrayBuffer,\n dataLength: number,\n payload?: { offset?: number; truncate?: boolean; flush?: boolean }\n): Promise<number> {\n const access = await getSyncAccessHandle(filePath, true);\n const offset = payload?.offset ?? 0;\n // Truncate by default when offset is 0 (writeFileSync behavior),\n // but allow callers to opt out for stream writes\n const shouldTruncate = payload?.truncate ?? (offset === 0);\n if (shouldTruncate) {\n access.truncate(0);\n }\n // Read from SharedArrayBuffer\n const data = new Uint8Array(dataBuffer, 0, dataLength);\n access.write(data, { at: offset });\n // Flush by default for durability, but allow skipping for performance\n // Data is still written and readable, just not guaranteed to survive crashes\n if (payload?.flush !== false) {\n access.flush();\n }\n return 1; // Success\n}\n\nasync function handleAppend(\n filePath: string,\n dataBuffer: SharedArrayBuffer,\n dataLength: number\n): Promise<number> {\n const access = await getSyncAccessHandle(filePath, true);\n const size = access.getSize();\n const data = new Uint8Array(dataBuffer, 0, dataLength);\n access.write(data, { at: size });\n access.flush();\n return 1;\n}\n\nasync function handleTruncate(\n filePath: string,\n payload?: { len?: number }\n): Promise<number> {\n const access = await getSyncAccessHandle(filePath, false);\n access.truncate(payload?.len ?? 0);\n access.flush();\n return 1;\n}\n\n// Binary stat layout (24 bytes) - faster than JSON for hot path:\n// Offset 0: type (Uint8) - 0=file, 1=directory\n// Offset 4: mode (Uint32)\n// Offset 8: size (Float64)\n// Offset 16: mtimeMs (Float64)\nconst STAT_SIZE = 24;\n\nasync function handleStat(\n filePath: string,\n metaBuffer: SharedArrayBuffer\n): Promise<number> {\n const parts = parsePath(filePath);\n const view = new DataView(metaBuffer);\n\n // mode: 33188 = 0o100644 (regular file), 16877 = 0o40755 (directory)\n if (parts.length === 0) {\n view.setUint8(0, 1); // directory\n view.setUint32(4, 16877, true);\n view.setFloat64(8, 0, true); // size\n view.setFloat64(16, Date.now(), true); // mtimeMs\n return STAT_SIZE;\n }\n\n const name = parts.pop()!;\n const parent = parts.length > 0 ? await getDirectoryHandle(parts, false) : await getRoot();\n\n try {\n const fh = await parent.getFileHandle(name);\n // Always get File object for accurate mtime - OPFS updates lastModified on writes\n const file = await fh.getFile();\n view.setUint8(0, 0); // file\n view.setUint32(4, 33188, true);\n view.setFloat64(8, file.size, true);\n view.setFloat64(16, file.lastModified, true);\n return STAT_SIZE;\n } catch {\n try {\n await parent.getDirectoryHandle(name);\n view.setUint8(0, 1); // directory\n view.setUint32(4, 16877, true);\n view.setFloat64(8, 0, true);\n view.setFloat64(16, Date.now(), true);\n return STAT_SIZE;\n } catch {\n return -2; // Not found\n }\n }\n}\n\nasync function handleExists(filePath: string): Promise<number> {\n // Fast path: if sync handle is cached, file definitely exists\n if (syncHandleCache.has(filePath)) return 1;\n\n try {\n const parts = parsePath(filePath);\n if (parts.length === 0) return 1;\n\n const name = parts.pop()!;\n const parent = parts.length > 0 ? await getDirectoryHandle(parts, false) : await getRoot();\n\n try {\n await parent.getFileHandle(name);\n return 1;\n } catch {\n try {\n await parent.getDirectoryHandle(name);\n return 1;\n } catch {\n return 0;\n }\n }\n } catch {\n return 0;\n }\n}\n\nasync function handleMkdir(\n filePath: string,\n payload?: { recursive?: boolean }\n): Promise<number> {\n const parts = parsePath(filePath);\n\n if (payload?.recursive) {\n let curr = await getRoot();\n for (const part of parts) {\n curr = await curr.getDirectoryHandle(part, { create: true });\n }\n } else {\n const name = parts.pop();\n if (!name) throw new Error('Invalid path');\n const parent = parts.length > 0 ? await getDirectoryHandle(parts, false) : await getRoot();\n await parent.getDirectoryHandle(name, { create: true });\n }\n\n return 1;\n}\n\nasync function handleRmdir(\n filePath: string,\n payload?: { recursive?: boolean }\n): Promise<number> {\n const { parent, name } = await getParentAndName(filePath);\n // Normalize path - ensure leading slash for consistent cache lookups\n const normalizedPath = '/' + parsePath(filePath).join('/');\n const pathPrefix = parsePath(filePath).join('/');\n\n if (payload?.recursive) {\n // Close ALL cached sync handles for files under this directory\n // Use normalized path with leading slash to match cached handle keys\n closeAllSyncHandlesUnder(normalizedPath);\n await parent.removeEntry(name, { recursive: true });\n // Clear ALL cached dir handles that start with this path prefix\n for (const key of dirCache.keys()) {\n if (key === pathPrefix || key.startsWith(pathPrefix + '/')) {\n dirCache.delete(key);\n }\n }\n } else {\n const dir = await parent.getDirectoryHandle(name);\n const entries = dir.entries();\n const first = await entries.next();\n if (!first.done) {\n // Use InvalidModificationError so it maps to ENOTEMPTY\n const e = new Error('InvalidModificationError');\n e.name = 'InvalidModificationError';\n throw e;\n }\n await parent.removeEntry(name);\n // Only invalidate the specific directory\n dirCache.delete(pathPrefix);\n }\n\n return 1;\n}\n\nasync function handleUnlink(filePath: string): Promise<number> {\n const { parent, name } = await getParentAndName(filePath);\n\n // Verify it's a file, not a directory (Node.js unlink semantics)\n try {\n await parent.getFileHandle(name);\n } catch {\n // Check if it's a directory\n try {\n await parent.getDirectoryHandle(name);\n throw new Error('EISDIR: illegal operation on a directory');\n } catch (e) {\n // Re-throw EISDIR, otherwise it's not found\n if ((e as Error).message?.includes('EISDIR')) throw e;\n throw new Error('NotFoundError');\n }\n }\n\n // Close cached sync handle before removing file\n closeSyncHandle(filePath);\n await parent.removeEntry(name);\n return 1;\n}\n\n// Binary readdir layout - faster than JSON for hot path:\n// Offset 0: entry count (Uint32)\n// For each entry: 2 bytes length (Uint16) + UTF-8 name bytes\nconst textEncoder = new TextEncoder();\n\nasync function handleReaddir(\n filePath: string,\n metaBuffer: SharedArrayBuffer\n): Promise<number> {\n const parts = parsePath(filePath);\n const dir = parts.length > 0 ? await getDirectoryHandle(parts, false) : await getRoot();\n\n // Collect entries\n const entries: string[] = [];\n for await (const [name] of dir.entries()) {\n entries.push(name);\n }\n\n // Binary encode: [count:u32] [len:u16 + utf8]...\n const view = new DataView(metaBuffer);\n const bytes = new Uint8Array(metaBuffer);\n view.setUint32(0, entries.length, true);\n\n let offset = 4;\n for (const name of entries) {\n const encoded = textEncoder.encode(name);\n view.setUint16(offset, encoded.length, true);\n offset += 2;\n bytes.set(encoded, offset);\n offset += encoded.length;\n }\n\n return offset;\n}\n\n// === MEMORY-SAFE CHUNK ALLOCATION (Zero overhead in normal operation) ===\n\nconst MIN_CHUNK = 64 * 1024; // 64KB floor\nconst MAX_CHUNK = 1024 * 1024; // 1MB ceiling\nconst DEFAULT_CHUNK = 256 * 1024; // 256KB default\nconst LAST_RESORT_CHUNK = 8 * 1024; // 8KB emergency\n\n// State\nlet chunkSize = DEFAULT_CHUNK;\nlet failureCount = 0;\n\n// Only yield on actual failure (use microtask, not setTimeout)\nconst yieldMicrotask = (): Promise<void> => new Promise(resolve => queueMicrotask(resolve));\n\n// Get current chunk size (fast path - just return cached value)\nfunction getChunkSize(): number {\n return chunkSize;\n}\n\n// Called after successful operations - gradually recover chunk size\nfunction maybeIncreaseChunk(): void {\n if (failureCount === 0 && chunkSize < MAX_CHUNK) {\n chunkSize = Math.min(MAX_CHUNK, chunkSize + 64 * 1024);\n }\n}\n\n// Called on allocation failure - reduce and remember\nfunction reduceChunkOnFailure(): number {\n failureCount++;\n chunkSize = Math.max(MIN_CHUNK, Math.floor(chunkSize / 2));\n return chunkSize;\n}\n\n// Safe allocation - only adds overhead on actual failure\nasync function safeAllocateChunk(\n srcFile: File,\n offset: number,\n requestedSize: number\n): Promise<Uint8Array> {\n const size = Math.min(requestedSize, chunkSize);\n\n try {\n // Fast path - no overhead\n const chunk = srcFile.slice(offset, offset + size);\n return new Uint8Array(await chunk.arrayBuffer());\n } catch (e) {\n // Slow path - only on failure\n const msg = e instanceof Error ? e.message : String(e);\n if (!msg.includes('allocation') && !msg.includes('Array buffer') && !msg.includes('out of memory')) {\n throw e; // Not a memory error\n }\n\n // Retry with smaller chunks\n let retrySize = reduceChunkOnFailure();\n while (retrySize >= MIN_CHUNK) {\n await yieldMicrotask(); // Microtask yield (fast, not setTimeout)\n try {\n const chunk = srcFile.slice(offset, offset + retrySize);\n return new Uint8Array(await chunk.arrayBuffer());\n } catch {\n retrySize = reduceChunkOnFailure();\n }\n }\n\n // Last resort\n await yieldMicrotask();\n try {\n chunkSize = LAST_RESORT_CHUNK;\n const chunk = srcFile.slice(offset, offset + LAST_RESORT_CHUNK);\n return new Uint8Array(await chunk.arrayBuffer());\n } catch {\n throw new Error('ENOMEM: unable to allocate memory');\n }\n }\n}\n\n// Lock-protected streaming copy using cached sync handles\nasync function streamCopyFile(\n srcHandle: FileSystemFileHandle,\n dstPath: string\n): Promise<void> {\n const srcFile = await srcHandle.getFile();\n const size = srcFile.size;\n\n // Lock destination path for multi-tab safety\n await navigator.locks.request(`opfs:${dstPath}`, async () => {\n const access = await getSyncAccessHandle(dstPath, true);\n access.truncate(0);\n\n // Chunked streaming for memory safety\n let offset = 0;\n while (offset < size) {\n const remaining = size - offset;\n\n // Safe allocation (only adds overhead on failure)\n const data = await safeAllocateChunk(srcFile, offset, remaining);\n\n access.write(data, { at: offset });\n offset += data.byteLength;\n }\n\n // Gradually recover chunk size after successful operation\n maybeIncreaseChunk();\n access.flush();\n });\n}\n\nasync function handleRename(\n oldPath: string,\n payload?: { newPath?: string }\n): Promise<number> {\n if (!payload?.newPath) throw new Error('newPath required');\n\n const newPath = payload.newPath;\n const oldParts = parsePath(oldPath);\n const newParts = parsePath(newPath);\n\n const oldName = oldParts.pop()!;\n const newName = newParts.pop()!;\n\n const oldParent = oldParts.length > 0 ? await getDirectoryHandle(oldParts, false) : await getRoot();\n const newParent = newParts.length > 0 ? await getDirectoryHandle(newParts, true) : await getRoot();\n\n // Try file first\n try {\n const fh = await oldParent.getFileHandle(oldName);\n\n // Close cached sync handle before rename\n closeSyncHandle(oldPath);\n\n // TIER 1: Use native move() if available (fastest, zero-copy, memory safe)\n if ('move' in fh && typeof (fh as any).move === 'function') {\n await (fh as any).move(newParent, newName);\n return 1;\n }\n\n // TIER 2: Fallback to stream copy (memory safe for large files)\n await streamCopyFile(fh, newPath);\n await oldParent.removeEntry(oldName);\n return 1;\n } catch {\n // Directory rename\n const oldDir = await oldParent.getDirectoryHandle(oldName);\n const pathPrefix = parsePath(oldPath).join('/');\n\n // Close all cached sync handles for files in this directory\n closeAllSyncHandlesUnder(pathPrefix);\n\n // Try native move for directories too\n if ('move' in oldDir && typeof (oldDir as any).move === 'function') {\n await (oldDir as any).move(newParent, newName);\n // Invalidate dir cache for moved directory\n for (const key of dirCache.keys()) {\n if (key === pathPrefix || key.startsWith(pathPrefix + '/')) {\n dirCache.delete(key);\n }\n }\n return 1;\n }\n\n // Fallback: recursive copy with streaming (track paths for lock discipline)\n async function copyDir(src: FileSystemDirectoryHandle, dst: FileSystemDirectoryHandle, dstBasePath: string) {\n for await (const [name, handle] of src.entries()) {\n const dstFilePath = dstBasePath + '/' + name;\n if (handle.kind === 'file') {\n const srcFile = handle as FileSystemFileHandle;\n await streamCopyFile(srcFile, dstFilePath);\n } else {\n const newSubDir = await dst.getDirectoryHandle(name, { create: true });\n await copyDir(handle as FileSystemDirectoryHandle, newSubDir, dstFilePath);\n }\n }\n }\n\n const newDir = await newParent.getDirectoryHandle(newName, { create: true });\n await copyDir(oldDir, newDir, newPath);\n await oldParent.removeEntry(oldName, { recursive: true });\n\n // Invalidate dir cache (pathPrefix already defined above)\n for (const key of dirCache.keys()) {\n if (key === pathPrefix || key.startsWith(pathPrefix + '/')) {\n dirCache.delete(key);\n }\n }\n\n return 1;\n }\n}\n\nasync function handleCopy(\n srcPath: string,\n payload?: { newPath?: string }\n): Promise<number> {\n if (!payload?.newPath) throw new Error('newPath required');\n\n const dstPath = payload.newPath;\n const srcParts = parsePath(srcPath);\n const srcName = srcParts.pop()!;\n const srcParent = srcParts.length > 0 ? await getDirectoryHandle(srcParts, false) : await getRoot();\n const srcFh = await srcParent.getFileHandle(srcName);\n\n // Use streaming copy with lock-protected destination (memory safe for large files)\n await streamCopyFile(srcFh, dstPath);\n\n return 1;\n}\n\n// Operations that don't need per-file locking\nconst LOCKLESS_OPS = new Set(['stat', 'exists', 'readdir', 'mkdir', 'flush', 'purge']);\n\n// Process incoming messages with SharedArrayBuffer-based communication\nasync function processMessage(msg: KernelMessage): Promise<void> {\n const { type, path: filePath, ctrlBuffer, metaBuffer, dataBuffer, dataLength, payload } = msg;\n\n // Create Int32Array view from the SharedArrayBuffer\n const ctrl = new Int32Array(ctrlBuffer);\n\n // Core operation logic\n const executeOperation = async (): Promise<number> => {\n switch (type) {\n case 'read':\n case 'readChunk': // Alias for chunked reads (same handler, different offset/len)\n return handleRead(filePath, dataBuffer, payload);\n case 'write':\n return handleWrite(filePath, dataBuffer, dataLength || 0, payload);\n case 'append':\n return handleAppend(filePath, dataBuffer, dataLength || 0);\n case 'truncate':\n return handleTruncate(filePath, payload);\n case 'stat':\n return handleStat(filePath, metaBuffer);\n case 'exists':\n return handleExists(filePath);\n case 'mkdir':\n return handleMkdir(filePath, payload);\n case 'rmdir':\n return handleRmdir(filePath, payload);\n case 'unlink':\n return handleUnlink(filePath);\n case 'readdir':\n return handleReaddir(filePath, metaBuffer);\n case 'rename':\n return handleRename(filePath, payload);\n case 'copy':\n return handleCopy(filePath, payload);\n case 'flush':\n flushAllSyncHandles();\n return 1;\n case 'purge':\n // Completely clear all caches - use between major operations\n purgeAllCaches();\n return 1;\n default:\n throw new Error(`Unknown operation: ${type}`);\n }\n };\n\n // Wrapper that handles result signaling\n const runAndSignal = async () => {\n try {\n const result = await executeOperation();\n Atomics.store(ctrl, 0, result);\n } catch (e: unknown) {\n const error = e instanceof Error ? e : new Error(String(e));\n const errorName = error.name || '';\n const errorMsg = error.message || 'Unknown error';\n\n // Check both error name and message for not-found conditions\n // DOM exceptions have name='NotFoundError' and message like \"could not be found\"\n const isNotFound = errorName === 'NotFoundError' ||\n errorMsg.includes('NotFoundError') ||\n errorMsg.includes('not found') ||\n errorMsg.includes('could not be found');\n\n if (isNotFound) {\n Atomics.store(ctrl, 0, -2);\n } else {\n // Write error name to metaBuffer for proper error mapping\n // Use error name if it's a known DOM exception, otherwise use message\n const errorInfo = errorName && errorName !== 'Error' ? errorName : errorMsg;\n const encoded = new TextEncoder().encode(errorInfo);\n const view = new Uint8Array(metaBuffer);\n view.set(encoded);\n // Add null terminator to prevent reading stale data from reused buffer\n if (encoded.length < metaBuffer.byteLength) {\n view[encoded.length] = 0;\n }\n Atomics.store(ctrl, 0, -1);\n }\n }\n Atomics.notify(ctrl, 0);\n };\n\n // Use Web Locks API to prevent NoModificationAllowedError across tabs\n // Skip locking for read-only operations that don't use createSyncAccessHandle\n if (LOCKLESS_OPS.has(type)) {\n await runAndSignal();\n } else {\n await navigator.locks.request(`opfs:${filePath}`, runAndSignal);\n }\n}\n\n// Main message handler\n// Note: Serialization is NOT needed here because:\n// - Tier 1 Sync: Client blocks on Atomics.wait, so only one message at a time\n// - Tier 1 Async: Client serializes via asyncOperationPromise before sending\nself.onmessage = (event: MessageEvent<KernelMessage>) => {\n processMessage(event.data);\n};\n\n// Signal ready\nself.postMessage({ type: 'ready' });\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@componentor/fs",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "Battle-tested OPFS-based Node.js fs polyfill with sync and async APIs",
5
5
  "license": "MIT",
6
6
  "author": "Componentor",