@componentor/fs 3.0.21 → 3.0.23
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/dist/index.d.mts +2 -0
- package/dist/index.js +42 -26
- package/dist/index.js.map +1 -1
- package/dist/workers/async-relay.worker.js +9 -2
- package/dist/workers/async-relay.worker.js.map +1 -1
- package/dist/workers/opfs-sync.worker.js +23 -8
- package/dist/workers/opfs-sync.worker.js.map +1 -1
- package/dist/workers/repair.worker.js +21 -9
- package/dist/workers/repair.worker.js.map +1 -1
- package/dist/workers/server.worker.js +21 -9
- package/dist/workers/server.worker.js.map +1 -1
- package/dist/workers/sync-relay.worker.js +57 -20
- package/dist/workers/sync-relay.worker.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -232,6 +232,8 @@ declare class VFSFileSystem {
|
|
|
232
232
|
* The readyPromise will resolve once OPFS mode is ready, but init()
|
|
233
233
|
* will reject with the corruption error to inform the caller. */
|
|
234
234
|
private handleCorruptVFS;
|
|
235
|
+
/** Initialize the async-relay worker. Called after sync-relay signals ready. */
|
|
236
|
+
private initAsyncRelay;
|
|
235
237
|
/** Start as leader — tell sync-relay to init VFS engine + OPFS handle */
|
|
236
238
|
private startAsLeader;
|
|
237
239
|
/** Start as follower — connect to leader via service worker port brokering */
|
package/dist/index.js
CHANGED
|
@@ -1381,6 +1381,7 @@ var VFSFileSystem = class {
|
|
|
1381
1381
|
const msg = e.data;
|
|
1382
1382
|
if (msg.type === "ready") {
|
|
1383
1383
|
this.isReady = true;
|
|
1384
|
+
this.initAsyncRelay();
|
|
1384
1385
|
this.resolveReady();
|
|
1385
1386
|
if (!this.isFollower) {
|
|
1386
1387
|
this.initLeaderBroker();
|
|
@@ -1405,23 +1406,6 @@ var VFSFileSystem = class {
|
|
|
1405
1406
|
}
|
|
1406
1407
|
}
|
|
1407
1408
|
};
|
|
1408
|
-
if (this.hasSAB) {
|
|
1409
|
-
this.asyncWorker.postMessage({
|
|
1410
|
-
type: "init-leader",
|
|
1411
|
-
asyncSab: this.asyncSab,
|
|
1412
|
-
wakeSab: this.sab
|
|
1413
|
-
});
|
|
1414
|
-
} else {
|
|
1415
|
-
const mc = new MessageChannel();
|
|
1416
|
-
this.asyncWorker.postMessage(
|
|
1417
|
-
{ type: "init-port", port: mc.port1 },
|
|
1418
|
-
[mc.port1]
|
|
1419
|
-
);
|
|
1420
|
-
this.syncWorker.postMessage(
|
|
1421
|
-
{ type: "async-port", port: mc.port2 },
|
|
1422
|
-
[mc.port2]
|
|
1423
|
-
);
|
|
1424
|
-
}
|
|
1425
1409
|
this.acquireLeaderLock();
|
|
1426
1410
|
}
|
|
1427
1411
|
/** Use Web Locks API for leader election. The tab that acquires the lock is
|
|
@@ -1516,6 +1500,26 @@ var VFSFileSystem = class {
|
|
|
1516
1500
|
this._mode = "opfs";
|
|
1517
1501
|
this.sendOPFSInit();
|
|
1518
1502
|
}
|
|
1503
|
+
/** Initialize the async-relay worker. Called after sync-relay signals ready. */
|
|
1504
|
+
initAsyncRelay() {
|
|
1505
|
+
if (this.hasSAB) {
|
|
1506
|
+
this.asyncWorker.postMessage({
|
|
1507
|
+
type: "init-leader",
|
|
1508
|
+
asyncSab: this.asyncSab,
|
|
1509
|
+
wakeSab: this.sab
|
|
1510
|
+
});
|
|
1511
|
+
} else {
|
|
1512
|
+
const mc = new MessageChannel();
|
|
1513
|
+
this.asyncWorker.postMessage(
|
|
1514
|
+
{ type: "init-port", port: mc.port1 },
|
|
1515
|
+
[mc.port1]
|
|
1516
|
+
);
|
|
1517
|
+
this.syncWorker.postMessage(
|
|
1518
|
+
{ type: "async-port", port: mc.port2 },
|
|
1519
|
+
[mc.port2]
|
|
1520
|
+
);
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1519
1523
|
/** Start as leader — tell sync-relay to init VFS engine + OPFS handle */
|
|
1520
1524
|
startAsLeader() {
|
|
1521
1525
|
this.isFollower = false;
|
|
@@ -2695,6 +2699,16 @@ var VFSEngine = class {
|
|
|
2695
2699
|
}
|
|
2696
2700
|
/** Resolve symlinks in intermediate path components */
|
|
2697
2701
|
resolvePathComponents(path, followLast = true, depth = 0) {
|
|
2702
|
+
const result = this.resolvePathFull(path, followLast, depth);
|
|
2703
|
+
return result?.idx;
|
|
2704
|
+
}
|
|
2705
|
+
/**
|
|
2706
|
+
* Resolve a path following symlinks, returning both the inode index AND the
|
|
2707
|
+
* fully resolved path. This is needed by readdir: when listing a symlinked
|
|
2708
|
+
* directory, we must search for children under the resolved target path
|
|
2709
|
+
* (where files actually exist in pathIndex), not under the symlink path.
|
|
2710
|
+
*/
|
|
2711
|
+
resolvePathFull(path, followLast = true, depth = 0) {
|
|
2698
2712
|
if (depth > MAX_SYMLINK_DEPTH) return void 0;
|
|
2699
2713
|
const parts = path.split("/").filter(Boolean);
|
|
2700
2714
|
let current = "/";
|
|
@@ -2708,14 +2722,16 @@ var VFSEngine = class {
|
|
|
2708
2722
|
const target = decoder8.decode(this.readData(inode.firstBlock, inode.blockCount, inode.size));
|
|
2709
2723
|
const resolved = target.startsWith("/") ? target : this.resolveRelative(current, target);
|
|
2710
2724
|
if (isLast) {
|
|
2711
|
-
return this.
|
|
2725
|
+
return this.resolvePathFull(resolved, true, depth + 1);
|
|
2712
2726
|
}
|
|
2713
2727
|
const remaining = parts.slice(i + 1).join("/");
|
|
2714
2728
|
const newPath = resolved + (remaining ? "/" + remaining : "");
|
|
2715
|
-
return this.
|
|
2729
|
+
return this.resolvePathFull(newPath, followLast, depth + 1);
|
|
2716
2730
|
}
|
|
2717
2731
|
}
|
|
2718
|
-
|
|
2732
|
+
const finalIdx = this.pathIndex.get(current);
|
|
2733
|
+
if (finalIdx === void 0) return void 0;
|
|
2734
|
+
return { idx: finalIdx, resolvedPath: current };
|
|
2719
2735
|
}
|
|
2720
2736
|
resolveRelative(from, target) {
|
|
2721
2737
|
const dir = from.substring(0, from.lastIndexOf("/")) || "/";
|
|
@@ -2914,10 +2930,10 @@ var VFSEngine = class {
|
|
|
2914
2930
|
if (idx === void 0) return { status: CODE_TO_STATUS.ENOENT, data: null };
|
|
2915
2931
|
return this.encodeStatResponse(idx);
|
|
2916
2932
|
}
|
|
2917
|
-
// ---- LSTAT (no symlink follow) ----
|
|
2933
|
+
// ---- LSTAT (no symlink follow for the FINAL component) ----
|
|
2918
2934
|
lstat(path) {
|
|
2919
2935
|
path = this.normalizePath(path);
|
|
2920
|
-
const idx = this.
|
|
2936
|
+
const idx = this.resolvePathComponents(path, false);
|
|
2921
2937
|
if (idx === void 0) return { status: CODE_TO_STATUS.ENOENT, data: null };
|
|
2922
2938
|
return this.encodeStatResponse(idx);
|
|
2923
2939
|
}
|
|
@@ -3004,12 +3020,12 @@ var VFSEngine = class {
|
|
|
3004
3020
|
// ---- READDIR ----
|
|
3005
3021
|
readdir(path, flags = 0) {
|
|
3006
3022
|
path = this.normalizePath(path);
|
|
3007
|
-
const
|
|
3008
|
-
if (
|
|
3009
|
-
const inode = this.readInode(idx);
|
|
3023
|
+
const resolved = this.resolvePathFull(path, true);
|
|
3024
|
+
if (!resolved) return { status: CODE_TO_STATUS.ENOENT, data: null };
|
|
3025
|
+
const inode = this.readInode(resolved.idx);
|
|
3010
3026
|
if (inode.type !== INODE_TYPE.DIRECTORY) return { status: CODE_TO_STATUS.ENOTDIR, data: null };
|
|
3011
3027
|
const withFileTypes = (flags & 1) !== 0;
|
|
3012
|
-
const children = this.getDirectChildren(
|
|
3028
|
+
const children = this.getDirectChildren(resolved.resolvedPath);
|
|
3013
3029
|
if (withFileTypes) {
|
|
3014
3030
|
let totalSize2 = 4;
|
|
3015
3031
|
const entries = [];
|