@componentor/fs 3.0.7 → 3.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 +7 -0
- package/dist/index.js +103 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -509,6 +509,13 @@ Make sure `opfsSync` is enabled (it's `true` by default). Files are mirrored to
|
|
|
509
509
|
|
|
510
510
|
## Changelog
|
|
511
511
|
|
|
512
|
+
### v3.0.8 (2026)
|
|
513
|
+
|
|
514
|
+
**Improvements:**
|
|
515
|
+
- Add VFS helper functions: `unpackToOPFS`, `loadFromOPFS`, and `repairVFS` for VFS maintenance, migration, and recovery
|
|
516
|
+
- Helpers work in both Worker (sync access handle) and main thread (in-memory buffer + async writable) contexts
|
|
517
|
+
- Remove redundant I/O call in `unpackToOPFS` directory creation
|
|
518
|
+
|
|
512
519
|
### v3.0.7 (2026)
|
|
513
520
|
|
|
514
521
|
**Fixes:**
|
package/dist/index.js
CHANGED
|
@@ -3236,6 +3236,87 @@ var VFSEngine = class {
|
|
|
3236
3236
|
};
|
|
3237
3237
|
|
|
3238
3238
|
// src/helpers.ts
|
|
3239
|
+
var MemoryHandle = class {
|
|
3240
|
+
buf;
|
|
3241
|
+
len;
|
|
3242
|
+
constructor(initialData) {
|
|
3243
|
+
if (initialData && initialData.byteLength > 0) {
|
|
3244
|
+
this.buf = new Uint8Array(initialData);
|
|
3245
|
+
this.len = initialData.byteLength;
|
|
3246
|
+
} else {
|
|
3247
|
+
this.buf = new Uint8Array(1024 * 1024);
|
|
3248
|
+
this.len = 0;
|
|
3249
|
+
}
|
|
3250
|
+
}
|
|
3251
|
+
getSize() {
|
|
3252
|
+
return this.len;
|
|
3253
|
+
}
|
|
3254
|
+
read(target, opts) {
|
|
3255
|
+
const offset = opts?.at ?? 0;
|
|
3256
|
+
const dst = new Uint8Array(target.buffer, target.byteOffset, target.byteLength);
|
|
3257
|
+
const bytesToRead = Math.min(dst.length, this.len - offset);
|
|
3258
|
+
if (bytesToRead <= 0) return 0;
|
|
3259
|
+
dst.set(this.buf.subarray(offset, offset + bytesToRead));
|
|
3260
|
+
return bytesToRead;
|
|
3261
|
+
}
|
|
3262
|
+
write(data, opts) {
|
|
3263
|
+
const offset = opts?.at ?? 0;
|
|
3264
|
+
const src = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
3265
|
+
const needed = offset + src.length;
|
|
3266
|
+
if (needed > this.buf.length) {
|
|
3267
|
+
this.grow(needed);
|
|
3268
|
+
}
|
|
3269
|
+
this.buf.set(src, offset);
|
|
3270
|
+
if (needed > this.len) this.len = needed;
|
|
3271
|
+
return src.length;
|
|
3272
|
+
}
|
|
3273
|
+
truncate(size) {
|
|
3274
|
+
if (size > this.buf.length) {
|
|
3275
|
+
this.grow(size);
|
|
3276
|
+
}
|
|
3277
|
+
if (size > this.len) {
|
|
3278
|
+
this.buf.fill(0, this.len, size);
|
|
3279
|
+
}
|
|
3280
|
+
this.len = size;
|
|
3281
|
+
}
|
|
3282
|
+
flush() {
|
|
3283
|
+
}
|
|
3284
|
+
close() {
|
|
3285
|
+
}
|
|
3286
|
+
/** Get the current data as an ArrayBuffer (trimmed to actual size) */
|
|
3287
|
+
getBuffer() {
|
|
3288
|
+
return this.buf.buffer.slice(0, this.len);
|
|
3289
|
+
}
|
|
3290
|
+
grow(minSize) {
|
|
3291
|
+
const newSize = Math.max(minSize, this.buf.length * 2);
|
|
3292
|
+
const newBuf = new Uint8Array(newSize);
|
|
3293
|
+
newBuf.set(this.buf.subarray(0, this.len));
|
|
3294
|
+
this.buf = newBuf;
|
|
3295
|
+
}
|
|
3296
|
+
};
|
|
3297
|
+
async function openVFSHandle(fileHandle) {
|
|
3298
|
+
try {
|
|
3299
|
+
const handle = await fileHandle.createSyncAccessHandle();
|
|
3300
|
+
return { handle, isMemory: false };
|
|
3301
|
+
} catch {
|
|
3302
|
+
const file = await fileHandle.getFile();
|
|
3303
|
+
const data = await file.arrayBuffer();
|
|
3304
|
+
return { handle: new MemoryHandle(data), isMemory: true };
|
|
3305
|
+
}
|
|
3306
|
+
}
|
|
3307
|
+
async function openFreshVFSHandle(fileHandle) {
|
|
3308
|
+
try {
|
|
3309
|
+
const handle = await fileHandle.createSyncAccessHandle();
|
|
3310
|
+
return { handle, isMemory: false };
|
|
3311
|
+
} catch {
|
|
3312
|
+
return { handle: new MemoryHandle(), isMemory: true };
|
|
3313
|
+
}
|
|
3314
|
+
}
|
|
3315
|
+
async function saveMemoryHandle(fileHandle, memHandle) {
|
|
3316
|
+
const writable = await fileHandle.createWritable();
|
|
3317
|
+
await writable.write(memHandle.getBuffer());
|
|
3318
|
+
await writable.close();
|
|
3319
|
+
}
|
|
3239
3320
|
async function navigateToRoot(root) {
|
|
3240
3321
|
let dir = await navigator.storage.getDirectory();
|
|
3241
3322
|
if (root && root !== "/") {
|
|
@@ -3262,15 +3343,21 @@ async function writeOPFSFile(rootDir, path, data) {
|
|
|
3262
3343
|
const parentDir = await ensureParentDirs(rootDir, path);
|
|
3263
3344
|
const name = basename2(path);
|
|
3264
3345
|
const fileHandle = await parentDir.getFileHandle(name, { create: true });
|
|
3265
|
-
const syncHandle = await fileHandle.createSyncAccessHandle();
|
|
3266
3346
|
try {
|
|
3267
|
-
syncHandle.
|
|
3268
|
-
|
|
3269
|
-
syncHandle.
|
|
3347
|
+
const syncHandle = await fileHandle.createSyncAccessHandle();
|
|
3348
|
+
try {
|
|
3349
|
+
syncHandle.truncate(0);
|
|
3350
|
+
if (data.byteLength > 0) {
|
|
3351
|
+
syncHandle.write(data, { at: 0 });
|
|
3352
|
+
}
|
|
3353
|
+
syncHandle.flush();
|
|
3354
|
+
} finally {
|
|
3355
|
+
syncHandle.close();
|
|
3270
3356
|
}
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3357
|
+
} catch {
|
|
3358
|
+
const writable = await fileHandle.createWritable();
|
|
3359
|
+
await writable.write(data);
|
|
3360
|
+
await writable.close();
|
|
3274
3361
|
}
|
|
3275
3362
|
}
|
|
3276
3363
|
async function clearDirectory(dir, skip) {
|
|
@@ -3302,7 +3389,7 @@ async function readOPFSRecursive(dir, prefix, skip) {
|
|
|
3302
3389
|
async function unpackToOPFS(root = "/") {
|
|
3303
3390
|
const rootDir = await navigateToRoot(root);
|
|
3304
3391
|
const vfsFileHandle = await rootDir.getFileHandle(".vfs.bin");
|
|
3305
|
-
const handle = await vfsFileHandle
|
|
3392
|
+
const { handle } = await openVFSHandle(vfsFileHandle);
|
|
3306
3393
|
let entries;
|
|
3307
3394
|
try {
|
|
3308
3395
|
const engine = new VFSEngine();
|
|
@@ -3340,7 +3427,7 @@ async function loadFromOPFS(root = "/") {
|
|
|
3340
3427
|
} catch (_) {
|
|
3341
3428
|
}
|
|
3342
3429
|
const vfsFileHandle = await rootDir.getFileHandle(".vfs.bin", { create: true });
|
|
3343
|
-
const handle = await vfsFileHandle
|
|
3430
|
+
const { handle, isMemory } = await openFreshVFSHandle(vfsFileHandle);
|
|
3344
3431
|
try {
|
|
3345
3432
|
const engine = new VFSEngine();
|
|
3346
3433
|
engine.init(handle);
|
|
@@ -3357,6 +3444,9 @@ async function loadFromOPFS(root = "/") {
|
|
|
3357
3444
|
files++;
|
|
3358
3445
|
}
|
|
3359
3446
|
engine.flush();
|
|
3447
|
+
if (isMemory) {
|
|
3448
|
+
await saveMemoryHandle(vfsFileHandle, handle);
|
|
3449
|
+
}
|
|
3360
3450
|
return { files, directories };
|
|
3361
3451
|
} finally {
|
|
3362
3452
|
handle.close();
|
|
@@ -3458,7 +3548,7 @@ async function repairVFS(root = "/") {
|
|
|
3458
3548
|
}
|
|
3459
3549
|
await rootDir.removeEntry(".vfs.bin");
|
|
3460
3550
|
const newFileHandle = await rootDir.getFileHandle(".vfs.bin", { create: true });
|
|
3461
|
-
const handle = await newFileHandle
|
|
3551
|
+
const { handle, isMemory } = await openFreshVFSHandle(newFileHandle);
|
|
3462
3552
|
try {
|
|
3463
3553
|
const engine = new VFSEngine();
|
|
3464
3554
|
engine.init(handle);
|
|
@@ -3479,6 +3569,9 @@ async function repairVFS(root = "/") {
|
|
|
3479
3569
|
if (result.status !== 0) lost++;
|
|
3480
3570
|
}
|
|
3481
3571
|
engine.flush();
|
|
3572
|
+
if (isMemory) {
|
|
3573
|
+
await saveMemoryHandle(newFileHandle, handle);
|
|
3574
|
+
}
|
|
3482
3575
|
} finally {
|
|
3483
3576
|
handle.close();
|
|
3484
3577
|
}
|