@componentor/fs 2.0.2 → 2.0.4
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 +9 -1
- package/dist/index.cjs +29 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +29 -3
- package/dist/index.js.map +1 -1
- package/dist/kernel.js +1 -1
- package/dist/kernel.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -427,31 +427,56 @@ let cachedRoot = null;
|
|
|
427
427
|
const dirCache = new Map();
|
|
428
428
|
|
|
429
429
|
// Sync handle cache - MAJOR performance optimization
|
|
430
|
+
// Handles auto-release after idle timeout to allow external tools to access files
|
|
430
431
|
const syncHandleCache = new Map();
|
|
432
|
+
const syncHandleLastAccess = new Map();
|
|
431
433
|
const MAX_HANDLES = 100;
|
|
434
|
+
const HANDLE_IDLE_TIMEOUT = 2000;
|
|
435
|
+
let idleCleanupTimer = null;
|
|
436
|
+
|
|
437
|
+
function scheduleIdleCleanup() {
|
|
438
|
+
if (idleCleanupTimer) return;
|
|
439
|
+
idleCleanupTimer = setTimeout(() => {
|
|
440
|
+
idleCleanupTimer = null;
|
|
441
|
+
const now = Date.now();
|
|
442
|
+
for (const [p, lastAccess] of syncHandleLastAccess) {
|
|
443
|
+
if (now - lastAccess > HANDLE_IDLE_TIMEOUT) {
|
|
444
|
+
const h = syncHandleCache.get(p);
|
|
445
|
+
if (h) { try { h.flush(); h.close(); } catch {} syncHandleCache.delete(p); }
|
|
446
|
+
syncHandleLastAccess.delete(p);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
if (syncHandleCache.size > 0) scheduleIdleCleanup();
|
|
450
|
+
}, HANDLE_IDLE_TIMEOUT);
|
|
451
|
+
}
|
|
432
452
|
|
|
433
453
|
async function getSyncHandle(filePath, create) {
|
|
434
454
|
const cached = syncHandleCache.get(filePath);
|
|
435
|
-
if (cached)
|
|
455
|
+
if (cached) {
|
|
456
|
+
syncHandleLastAccess.set(filePath, Date.now());
|
|
457
|
+
return cached;
|
|
458
|
+
}
|
|
436
459
|
|
|
437
460
|
// Evict oldest handles if cache is full
|
|
438
461
|
if (syncHandleCache.size >= MAX_HANDLES) {
|
|
439
462
|
const keys = Array.from(syncHandleCache.keys()).slice(0, 10);
|
|
440
463
|
for (const key of keys) {
|
|
441
464
|
const h = syncHandleCache.get(key);
|
|
442
|
-
if (h) { try { h.close(); } catch {} syncHandleCache.delete(key); }
|
|
465
|
+
if (h) { try { h.close(); } catch {} syncHandleCache.delete(key); syncHandleLastAccess.delete(key); }
|
|
443
466
|
}
|
|
444
467
|
}
|
|
445
468
|
|
|
446
469
|
const fh = await getFileHandle(filePath, create);
|
|
447
470
|
const access = await fh.createSyncAccessHandle();
|
|
448
471
|
syncHandleCache.set(filePath, access);
|
|
472
|
+
syncHandleLastAccess.set(filePath, Date.now());
|
|
473
|
+
scheduleIdleCleanup();
|
|
449
474
|
return access;
|
|
450
475
|
}
|
|
451
476
|
|
|
452
477
|
function closeSyncHandle(filePath) {
|
|
453
478
|
const h = syncHandleCache.get(filePath);
|
|
454
|
-
if (h) { try { h.close(); } catch {} syncHandleCache.delete(filePath); }
|
|
479
|
+
if (h) { try { h.close(); } catch {} syncHandleCache.delete(filePath); syncHandleLastAccess.delete(filePath); }
|
|
455
480
|
}
|
|
456
481
|
|
|
457
482
|
function closeHandlesUnder(prefix) {
|
|
@@ -459,6 +484,7 @@ function closeHandlesUnder(prefix) {
|
|
|
459
484
|
if (p === prefix || p.startsWith(prefix + '/')) {
|
|
460
485
|
try { h.close(); } catch {}
|
|
461
486
|
syncHandleCache.delete(p);
|
|
487
|
+
syncHandleLastAccess.delete(p);
|
|
462
488
|
}
|
|
463
489
|
}
|
|
464
490
|
}
|