@componentor/fs 2.0.6 → 2.0.8
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 +8 -14
- package/dist/index.cjs +89 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +89 -31
- package/dist/index.js.map +1 -1
- package/dist/kernel.js +54 -39
- package/dist/kernel.js.map +1 -1
- package/package.json +1 -1
package/dist/kernel.js
CHANGED
|
@@ -2,42 +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();
|
|
6
5
|
var MAX_SYNC_HANDLES = 100;
|
|
7
|
-
var
|
|
8
|
-
var
|
|
9
|
-
function
|
|
10
|
-
if (
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
syncHandleLastAccess.delete(path);
|
|
6
|
+
var unsafeModeSupported = null;
|
|
7
|
+
var debugTrace = false;
|
|
8
|
+
function trace(...args) {
|
|
9
|
+
if (debugTrace) console.log("[OPFS-T1]", ...args);
|
|
10
|
+
}
|
|
11
|
+
var releaseTimer = null;
|
|
12
|
+
var LEGACY_RELEASE_DELAY = 100;
|
|
13
|
+
function scheduleHandleRelease() {
|
|
14
|
+
if (unsafeModeSupported) return;
|
|
15
|
+
if (releaseTimer) return;
|
|
16
|
+
releaseTimer = setTimeout(() => {
|
|
17
|
+
releaseTimer = null;
|
|
18
|
+
const count = syncHandleCache.size;
|
|
19
|
+
for (const handle of syncHandleCache.values()) {
|
|
20
|
+
try {
|
|
21
|
+
handle.flush();
|
|
22
|
+
handle.close();
|
|
23
|
+
} catch {
|
|
26
24
|
}
|
|
27
25
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}, HANDLE_IDLE_TIMEOUT);
|
|
26
|
+
syncHandleCache.clear();
|
|
27
|
+
trace(`Released ${count} handles (legacy mode debounce)`);
|
|
28
|
+
}, LEGACY_RELEASE_DELAY);
|
|
32
29
|
}
|
|
33
30
|
async function getSyncAccessHandle(filePath, create) {
|
|
34
31
|
const cached = syncHandleCache.get(filePath);
|
|
35
32
|
if (cached) {
|
|
36
|
-
|
|
33
|
+
trace(`Handle cache HIT: ${filePath}`);
|
|
37
34
|
return cached;
|
|
38
35
|
}
|
|
39
36
|
if (syncHandleCache.size >= MAX_SYNC_HANDLES) {
|
|
40
37
|
const keysToDelete = Array.from(syncHandleCache.keys()).slice(0, 10);
|
|
38
|
+
trace(`LRU evicting ${keysToDelete.length} handles`);
|
|
41
39
|
for (const key of keysToDelete) {
|
|
42
40
|
const handle = syncHandleCache.get(key);
|
|
43
41
|
if (handle) {
|
|
@@ -46,15 +44,28 @@ async function getSyncAccessHandle(filePath, create) {
|
|
|
46
44
|
} catch {
|
|
47
45
|
}
|
|
48
46
|
syncHandleCache.delete(key);
|
|
49
|
-
syncHandleLastAccess.delete(key);
|
|
50
47
|
}
|
|
51
48
|
}
|
|
52
49
|
}
|
|
53
50
|
const fh = await getFileHandle(filePath, create);
|
|
54
|
-
|
|
51
|
+
let access;
|
|
52
|
+
if (unsafeModeSupported === null) {
|
|
53
|
+
try {
|
|
54
|
+
access = await fh.createSyncAccessHandle({ mode: "readwrite-unsafe" });
|
|
55
|
+
unsafeModeSupported = true;
|
|
56
|
+
trace(`readwrite-unsafe mode SUPPORTED - handles won't block`);
|
|
57
|
+
} catch {
|
|
58
|
+
access = await fh.createSyncAccessHandle();
|
|
59
|
+
unsafeModeSupported = false;
|
|
60
|
+
trace(`readwrite-unsafe mode NOT supported - using legacy mode`);
|
|
61
|
+
}
|
|
62
|
+
} else if (unsafeModeSupported) {
|
|
63
|
+
access = await fh.createSyncAccessHandle({ mode: "readwrite-unsafe" });
|
|
64
|
+
} else {
|
|
65
|
+
access = await fh.createSyncAccessHandle();
|
|
66
|
+
}
|
|
55
67
|
syncHandleCache.set(filePath, access);
|
|
56
|
-
|
|
57
|
-
scheduleIdleCleanup();
|
|
68
|
+
trace(`Handle ACQUIRED: ${filePath} (cache size: ${syncHandleCache.size})`);
|
|
58
69
|
return access;
|
|
59
70
|
}
|
|
60
71
|
function closeSyncHandle(filePath) {
|
|
@@ -65,7 +76,7 @@ function closeSyncHandle(filePath) {
|
|
|
65
76
|
} catch {
|
|
66
77
|
}
|
|
67
78
|
syncHandleCache.delete(filePath);
|
|
68
|
-
|
|
79
|
+
trace(`Handle RELEASED: ${filePath}`);
|
|
69
80
|
}
|
|
70
81
|
}
|
|
71
82
|
function closeAllSyncHandlesUnder(pathPrefix) {
|
|
@@ -77,14 +88,13 @@ function closeAllSyncHandlesUnder(pathPrefix) {
|
|
|
77
88
|
} catch {
|
|
78
89
|
}
|
|
79
90
|
syncHandleCache.delete(path);
|
|
80
|
-
syncHandleLastAccess.delete(path);
|
|
81
91
|
}
|
|
82
92
|
}
|
|
83
93
|
}
|
|
84
94
|
function purgeAllCaches() {
|
|
85
|
-
if (
|
|
86
|
-
clearTimeout(
|
|
87
|
-
|
|
95
|
+
if (releaseTimer) {
|
|
96
|
+
clearTimeout(releaseTimer);
|
|
97
|
+
releaseTimer = null;
|
|
88
98
|
}
|
|
89
99
|
for (const handle of syncHandleCache.values()) {
|
|
90
100
|
try {
|
|
@@ -94,7 +104,6 @@ function purgeAllCaches() {
|
|
|
94
104
|
}
|
|
95
105
|
}
|
|
96
106
|
syncHandleCache.clear();
|
|
97
|
-
syncHandleLastAccess.clear();
|
|
98
107
|
dirCache.clear();
|
|
99
108
|
cachedRoot = null;
|
|
100
109
|
}
|
|
@@ -154,14 +163,12 @@ async function handleRead(filePath, dataBuffer, payload) {
|
|
|
154
163
|
const offset = payload?.offset || 0;
|
|
155
164
|
const len = payload?.len || size - offset;
|
|
156
165
|
const view = new Uint8Array(dataBuffer, 0, Math.min(len, dataBuffer.byteLength));
|
|
157
|
-
|
|
158
|
-
return bytesRead;
|
|
166
|
+
return access.read(view, { at: offset });
|
|
159
167
|
}
|
|
160
168
|
async function handleWrite(filePath, dataBuffer, dataLength, payload) {
|
|
161
169
|
const access = await getSyncAccessHandle(filePath, true);
|
|
162
170
|
const offset = payload?.offset ?? 0;
|
|
163
|
-
|
|
164
|
-
if (shouldTruncate) {
|
|
171
|
+
if (payload?.truncate ?? offset === 0) {
|
|
165
172
|
access.truncate(0);
|
|
166
173
|
}
|
|
167
174
|
const data = new Uint8Array(dataBuffer, 0, dataLength);
|
|
@@ -486,6 +493,12 @@ async function processMessage(msg) {
|
|
|
486
493
|
case "purge":
|
|
487
494
|
purgeAllCaches();
|
|
488
495
|
return 1;
|
|
496
|
+
case "setDebug":
|
|
497
|
+
debugTrace = !!payload?.enabled;
|
|
498
|
+
trace(`Debug tracing ${debugTrace ? "ENABLED" : "DISABLED"}, unsafeMode: ${unsafeModeSupported}`);
|
|
499
|
+
return 1;
|
|
500
|
+
case "getDebugInfo":
|
|
501
|
+
return syncHandleCache.size;
|
|
489
502
|
default:
|
|
490
503
|
throw new Error(`Unknown operation: ${type}`);
|
|
491
504
|
}
|
|
@@ -511,6 +524,8 @@ async function processMessage(msg) {
|
|
|
511
524
|
}
|
|
512
525
|
Atomics.store(ctrl, 0, -1);
|
|
513
526
|
}
|
|
527
|
+
} finally {
|
|
528
|
+
scheduleHandleRelease();
|
|
514
529
|
}
|
|
515
530
|
Atomics.notify(ctrl, 0);
|
|
516
531
|
};
|
package/dist/kernel.js.map
CHANGED
|
@@ -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 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 = 2000; // Release handles after 2 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\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":[]}
|
|
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 enabled?: boolean; // For setDebug: enable/disable tracing\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// Uses readwrite-unsafe mode when available (no exclusive lock, allows external access)\n// Falls back to readwrite with debounced release for older browsers\nconst syncHandleCache = new Map<string, FileSystemSyncAccessHandle>();\nconst MAX_SYNC_HANDLES = 100; // Limit cache size to prevent memory issues\n\n// Track if readwrite-unsafe mode is supported (detected on first use)\nlet unsafeModeSupported: boolean | null = null;\n\n// Debug tracing - set via 'setDebug' message\nlet debugTrace = false;\nfunction trace(...args: unknown[]): void {\n if (debugTrace) console.log('[OPFS-T1]', ...args);\n}\n\n// Minimal timer for legacy mode only (readwrite-unsafe doesn't need timed release)\nlet releaseTimer: ReturnType<typeof setTimeout> | null = null;\nconst LEGACY_RELEASE_DELAY = 100; // 100ms for legacy readwrite\n\n// Lightweight release scheduling - only for legacy mode\nfunction scheduleHandleRelease(): void {\n // readwrite-unsafe mode: no release needed (handles don't block)\n if (unsafeModeSupported) return;\n\n // Legacy mode: debounced release\n if (releaseTimer) return; // Already scheduled\n releaseTimer = setTimeout(() => {\n releaseTimer = null;\n const count = syncHandleCache.size;\n for (const handle of syncHandleCache.values()) {\n try { handle.flush(); handle.close(); } catch { /* ignore */ }\n }\n syncHandleCache.clear();\n trace(`Released ${count} handles (legacy mode debounce)`);\n }, LEGACY_RELEASE_DELAY);\n}\n\nasync function getSyncAccessHandle(\n filePath: string,\n create: boolean\n): Promise<FileSystemSyncAccessHandle> {\n const cached = syncHandleCache.get(filePath);\n if (cached) {\n trace(`Handle cache HIT: ${filePath}`);\n return cached;\n }\n\n // Evict oldest handles if cache is full\n if (syncHandleCache.size >= MAX_SYNC_HANDLES) {\n const keysToDelete = Array.from(syncHandleCache.keys()).slice(0, 10);\n trace(`LRU evicting ${keysToDelete.length} handles`);\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\n // Try readwrite-unsafe mode first (no exclusive lock, Chrome 121+)\n // Falls back to readwrite if not supported\n let access: FileSystemSyncAccessHandle;\n if (unsafeModeSupported === null) {\n // First time - detect support\n try {\n access = await (fh as any).createSyncAccessHandle({ mode: 'readwrite-unsafe' });\n unsafeModeSupported = true;\n trace(`readwrite-unsafe mode SUPPORTED - handles won't block`);\n } catch {\n // Not supported, use default mode\n access = await fh.createSyncAccessHandle();\n unsafeModeSupported = false;\n trace(`readwrite-unsafe mode NOT supported - using legacy mode`);\n }\n } else if (unsafeModeSupported) {\n access = await (fh as any).createSyncAccessHandle({ mode: 'readwrite-unsafe' });\n } else {\n access = await fh.createSyncAccessHandle();\n }\n\n syncHandleCache.set(filePath, access);\n trace(`Handle ACQUIRED: ${filePath} (cache size: ${syncHandleCache.size})`);\n return access;\n}\n\nfunction closeSyncHandle(filePath: string): void {\n const handle = syncHandleCache.get(filePath);\n if (handle) {\n try { handle.close(); } catch { /* ignore */ }\n syncHandleCache.delete(filePath);\n trace(`Handle RELEASED: ${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 { handle.flush(); handle.close(); } catch { /* ignore */ }\n syncHandleCache.delete(path);\n }\n }\n}\n\n// Completely purge all caches - use before major cleanup operations\nfunction purgeAllCaches(): void {\n if (releaseTimer) {\n clearTimeout(releaseTimer);\n releaseTimer = null;\n }\n for (const handle of syncHandleCache.values()) {\n try { handle.flush(); handle.close(); } catch { /* ignore */ }\n }\n syncHandleCache.clear();\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 const view = new Uint8Array(dataBuffer, 0, Math.min(len, dataBuffer.byteLength));\n return access.read(view, { at: offset });\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 if (payload?.truncate ?? (offset === 0)) {\n access.truncate(0);\n }\n const data = new Uint8Array(dataBuffer, 0, dataLength);\n access.write(data, { at: offset });\n if (payload?.flush !== false) {\n access.flush();\n }\n return 1;\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 case 'setDebug':\n debugTrace = !!payload?.enabled;\n trace(`Debug tracing ${debugTrace ? 'ENABLED' : 'DISABLED'}, unsafeMode: ${unsafeModeSupported}`);\n return 1;\n case 'getDebugInfo':\n // Return debug info via metaBuffer (reuse for simplicity)\n return syncHandleCache.size;\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 } finally {\n // Schedule handle release (debounced - waits 100ms after last operation)\n scheduleHandleRelease();\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":[]}
|