@componentor/fs 3.0.1 → 3.0.3
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 +42 -16
- package/dist/index.js +226 -24
- package/dist/index.js.map +1 -1
- package/dist/workers/server.worker.js +7 -4
- package/dist/workers/server.worker.js.map +1 -1
- package/dist/workers/sync-relay.worker.js +86 -16
- package/dist/workers/sync-relay.worker.js.map +1 -1
- package/package.json +1 -1
|
@@ -456,7 +456,9 @@ var VFSEngine = class {
|
|
|
456
456
|
resolvePath(path, depth = 0) {
|
|
457
457
|
if (depth > MAX_SYMLINK_DEPTH) return void 0;
|
|
458
458
|
const idx = this.pathIndex.get(path);
|
|
459
|
-
if (idx === void 0)
|
|
459
|
+
if (idx === void 0) {
|
|
460
|
+
return this.resolvePathComponents(path, true, depth);
|
|
461
|
+
}
|
|
460
462
|
const inode = this.readInode(idx);
|
|
461
463
|
if (inode.type === INODE_TYPE.SYMLINK) {
|
|
462
464
|
const target = decoder.decode(this.readData(inode.firstBlock, inode.blockCount, inode.size));
|
|
@@ -466,7 +468,8 @@ var VFSEngine = class {
|
|
|
466
468
|
return idx;
|
|
467
469
|
}
|
|
468
470
|
/** Resolve symlinks in intermediate path components */
|
|
469
|
-
resolvePathComponents(path, followLast = true) {
|
|
471
|
+
resolvePathComponents(path, followLast = true, depth = 0) {
|
|
472
|
+
if (depth > MAX_SYMLINK_DEPTH) return void 0;
|
|
470
473
|
const parts = path.split("/").filter(Boolean);
|
|
471
474
|
let current = "/";
|
|
472
475
|
for (let i = 0; i < parts.length; i++) {
|
|
@@ -479,11 +482,11 @@ var VFSEngine = class {
|
|
|
479
482
|
const target = decoder.decode(this.readData(inode.firstBlock, inode.blockCount, inode.size));
|
|
480
483
|
const resolved = target.startsWith("/") ? target : this.resolveRelative(current, target);
|
|
481
484
|
if (isLast) {
|
|
482
|
-
return this.
|
|
485
|
+
return this.resolvePathComponents(resolved, true, depth + 1);
|
|
483
486
|
}
|
|
484
487
|
const remaining = parts.slice(i + 1).join("/");
|
|
485
488
|
const newPath = resolved + (remaining ? "/" + remaining : "");
|
|
486
|
-
return this.resolvePathComponents(newPath, followLast);
|
|
489
|
+
return this.resolvePathComponents(newPath, followLast, depth + 1);
|
|
487
490
|
}
|
|
488
491
|
}
|
|
489
492
|
return this.pathIndex.get(current);
|
|
@@ -1321,6 +1324,7 @@ var leaderLoopRunning = false;
|
|
|
1321
1324
|
var opfsSyncPort = null;
|
|
1322
1325
|
var opfsSyncEnabled = false;
|
|
1323
1326
|
var suppressPaths = /* @__PURE__ */ new Set();
|
|
1327
|
+
var watchBc = null;
|
|
1324
1328
|
var sab;
|
|
1325
1329
|
var ctrl;
|
|
1326
1330
|
var readySab;
|
|
@@ -1447,21 +1451,21 @@ function handleRequest(reqTabId, buffer) {
|
|
|
1447
1451
|
break;
|
|
1448
1452
|
case OP.WRITE:
|
|
1449
1453
|
result = engine.write(path, data ?? new Uint8Array(0), flags);
|
|
1450
|
-
if (
|
|
1454
|
+
if (result.status === 0) {
|
|
1451
1455
|
syncOp = op;
|
|
1452
1456
|
syncPath = path;
|
|
1453
1457
|
}
|
|
1454
1458
|
break;
|
|
1455
1459
|
case OP.APPEND:
|
|
1456
1460
|
result = engine.append(path, data ?? new Uint8Array(0));
|
|
1457
|
-
if (
|
|
1461
|
+
if (result.status === 0) {
|
|
1458
1462
|
syncOp = op;
|
|
1459
1463
|
syncPath = path;
|
|
1460
1464
|
}
|
|
1461
1465
|
break;
|
|
1462
1466
|
case OP.UNLINK:
|
|
1463
1467
|
result = engine.unlink(path);
|
|
1464
|
-
if (
|
|
1468
|
+
if (result.status === 0) {
|
|
1465
1469
|
syncOp = op;
|
|
1466
1470
|
syncPath = path;
|
|
1467
1471
|
}
|
|
@@ -1474,14 +1478,14 @@ function handleRequest(reqTabId, buffer) {
|
|
|
1474
1478
|
break;
|
|
1475
1479
|
case OP.MKDIR:
|
|
1476
1480
|
result = engine.mkdir(path, flags);
|
|
1477
|
-
if (
|
|
1481
|
+
if (result.status === 0) {
|
|
1478
1482
|
syncOp = op;
|
|
1479
1483
|
syncPath = path;
|
|
1480
1484
|
}
|
|
1481
1485
|
break;
|
|
1482
1486
|
case OP.RMDIR:
|
|
1483
1487
|
result = engine.rmdir(path, flags);
|
|
1484
|
-
if (
|
|
1488
|
+
if (result.status === 0) {
|
|
1485
1489
|
syncOp = op;
|
|
1486
1490
|
syncPath = path;
|
|
1487
1491
|
}
|
|
@@ -1492,7 +1496,7 @@ function handleRequest(reqTabId, buffer) {
|
|
|
1492
1496
|
case OP.RENAME: {
|
|
1493
1497
|
const newPath = data ? decodeSecondPath(data) : "";
|
|
1494
1498
|
result = engine.rename(path, newPath);
|
|
1495
|
-
if (
|
|
1499
|
+
if (result.status === 0) {
|
|
1496
1500
|
syncOp = op;
|
|
1497
1501
|
syncPath = path;
|
|
1498
1502
|
syncNewPath = newPath;
|
|
@@ -1505,7 +1509,7 @@ function handleRequest(reqTabId, buffer) {
|
|
|
1505
1509
|
case OP.TRUNCATE: {
|
|
1506
1510
|
const len = data ? new DataView(data.buffer, data.byteOffset, data.byteLength).getUint32(0, true) : 0;
|
|
1507
1511
|
result = engine.truncate(path, len);
|
|
1508
|
-
if (
|
|
1512
|
+
if (result.status === 0) {
|
|
1509
1513
|
syncOp = op;
|
|
1510
1514
|
syncPath = path;
|
|
1511
1515
|
}
|
|
@@ -1514,7 +1518,7 @@ function handleRequest(reqTabId, buffer) {
|
|
|
1514
1518
|
case OP.COPY: {
|
|
1515
1519
|
const destPath = data ? decodeSecondPath(data) : "";
|
|
1516
1520
|
result = engine.copy(path, destPath, flags);
|
|
1517
|
-
if (
|
|
1521
|
+
if (result.status === 0) {
|
|
1518
1522
|
syncOp = op;
|
|
1519
1523
|
syncPath = destPath;
|
|
1520
1524
|
}
|
|
@@ -1529,6 +1533,10 @@ function handleRequest(reqTabId, buffer) {
|
|
|
1529
1533
|
case OP.CHMOD: {
|
|
1530
1534
|
const chmodMode = data ? new DataView(data.buffer, data.byteOffset, data.byteLength).getUint32(0, true) : 0;
|
|
1531
1535
|
result = engine.chmod(path, chmodMode);
|
|
1536
|
+
if (result.status === 0) {
|
|
1537
|
+
syncOp = op;
|
|
1538
|
+
syncPath = path;
|
|
1539
|
+
}
|
|
1532
1540
|
break;
|
|
1533
1541
|
}
|
|
1534
1542
|
case OP.CHOWN: {
|
|
@@ -1540,6 +1548,10 @@ function handleRequest(reqTabId, buffer) {
|
|
|
1540
1548
|
const uid = dv.getUint32(0, true);
|
|
1541
1549
|
const gid = dv.getUint32(4, true);
|
|
1542
1550
|
result = engine.chown(path, uid, gid);
|
|
1551
|
+
if (result.status === 0) {
|
|
1552
|
+
syncOp = op;
|
|
1553
|
+
syncPath = path;
|
|
1554
|
+
}
|
|
1543
1555
|
break;
|
|
1544
1556
|
}
|
|
1545
1557
|
case OP.UTIMES: {
|
|
@@ -1551,11 +1563,19 @@ function handleRequest(reqTabId, buffer) {
|
|
|
1551
1563
|
const atime = dv.getFloat64(0, true);
|
|
1552
1564
|
const mtime = dv.getFloat64(8, true);
|
|
1553
1565
|
result = engine.utimes(path, atime, mtime);
|
|
1566
|
+
if (result.status === 0) {
|
|
1567
|
+
syncOp = op;
|
|
1568
|
+
syncPath = path;
|
|
1569
|
+
}
|
|
1554
1570
|
break;
|
|
1555
1571
|
}
|
|
1556
1572
|
case OP.SYMLINK: {
|
|
1557
1573
|
const target = data ? new TextDecoder().decode(data) : "";
|
|
1558
1574
|
result = engine.symlink(target, path);
|
|
1575
|
+
if (result.status === 0) {
|
|
1576
|
+
syncOp = op;
|
|
1577
|
+
syncPath = path;
|
|
1578
|
+
}
|
|
1559
1579
|
break;
|
|
1560
1580
|
}
|
|
1561
1581
|
case OP.READLINK:
|
|
@@ -1564,7 +1584,7 @@ function handleRequest(reqTabId, buffer) {
|
|
|
1564
1584
|
case OP.LINK: {
|
|
1565
1585
|
const newPath = data ? decodeSecondPath(data) : "";
|
|
1566
1586
|
result = engine.link(path, newPath);
|
|
1567
|
-
if (
|
|
1587
|
+
if (result.status === 0) {
|
|
1568
1588
|
syncOp = op;
|
|
1569
1589
|
syncPath = newPath;
|
|
1570
1590
|
}
|
|
@@ -1600,7 +1620,7 @@ function handleRequest(reqTabId, buffer) {
|
|
|
1600
1620
|
const pos = dv.getInt32(4, true);
|
|
1601
1621
|
const writeData = data.subarray(8);
|
|
1602
1622
|
result = engine.fwrite(fd, writeData, pos === -1 ? null : pos);
|
|
1603
|
-
if (
|
|
1623
|
+
if (result.status === 0) {
|
|
1604
1624
|
syncOp = op;
|
|
1605
1625
|
syncPath = engine.getPathForFd(fd) ?? void 0;
|
|
1606
1626
|
}
|
|
@@ -1620,7 +1640,7 @@ function handleRequest(reqTabId, buffer) {
|
|
|
1620
1640
|
const fd = dv.getUint32(0, true);
|
|
1621
1641
|
const len = dv.getUint32(4, true);
|
|
1622
1642
|
result = engine.ftruncate(fd, len);
|
|
1623
|
-
if (
|
|
1643
|
+
if (result.status === 0) {
|
|
1624
1644
|
syncOp = op;
|
|
1625
1645
|
syncPath = engine.getPathForFd(fd) ?? void 0;
|
|
1626
1646
|
}
|
|
@@ -1634,7 +1654,7 @@ function handleRequest(reqTabId, buffer) {
|
|
|
1634
1654
|
break;
|
|
1635
1655
|
case OP.MKDTEMP:
|
|
1636
1656
|
result = engine.mkdtemp(path);
|
|
1637
|
-
if (
|
|
1657
|
+
if (result.status === 0 && result.data) {
|
|
1638
1658
|
syncOp = op;
|
|
1639
1659
|
syncPath = new TextDecoder().decode(result.data instanceof Uint8Array ? result.data : new Uint8Array(0));
|
|
1640
1660
|
}
|
|
@@ -1654,6 +1674,7 @@ function handleRequest(reqTabId, buffer) {
|
|
|
1654
1674
|
ret._op = syncOp;
|
|
1655
1675
|
ret._path = syncPath;
|
|
1656
1676
|
ret._newPath = syncNewPath;
|
|
1677
|
+
broadcastWatch(syncOp, syncPath, syncNewPath);
|
|
1657
1678
|
}
|
|
1658
1679
|
return ret;
|
|
1659
1680
|
}
|
|
@@ -1844,6 +1865,39 @@ async function initEngine(config) {
|
|
|
1844
1865
|
[mc.port2]
|
|
1845
1866
|
);
|
|
1846
1867
|
}
|
|
1868
|
+
watchBc = new BroadcastChannel("vfs-watch");
|
|
1869
|
+
}
|
|
1870
|
+
function broadcastWatch(op, path, newPath) {
|
|
1871
|
+
if (!watchBc) return;
|
|
1872
|
+
let eventType;
|
|
1873
|
+
switch (op) {
|
|
1874
|
+
case OP.WRITE:
|
|
1875
|
+
case OP.APPEND:
|
|
1876
|
+
case OP.TRUNCATE:
|
|
1877
|
+
case OP.FWRITE:
|
|
1878
|
+
case OP.FTRUNCATE:
|
|
1879
|
+
case OP.CHMOD:
|
|
1880
|
+
case OP.CHOWN:
|
|
1881
|
+
case OP.UTIMES:
|
|
1882
|
+
eventType = "change";
|
|
1883
|
+
break;
|
|
1884
|
+
case OP.UNLINK:
|
|
1885
|
+
case OP.RMDIR:
|
|
1886
|
+
case OP.RENAME:
|
|
1887
|
+
case OP.MKDIR:
|
|
1888
|
+
case OP.MKDTEMP:
|
|
1889
|
+
case OP.SYMLINK:
|
|
1890
|
+
case OP.LINK:
|
|
1891
|
+
case OP.COPY:
|
|
1892
|
+
eventType = "rename";
|
|
1893
|
+
break;
|
|
1894
|
+
default:
|
|
1895
|
+
return;
|
|
1896
|
+
}
|
|
1897
|
+
watchBc.postMessage({ eventType, path });
|
|
1898
|
+
if (op === OP.RENAME && newPath) {
|
|
1899
|
+
watchBc.postMessage({ eventType: "rename", path: newPath });
|
|
1900
|
+
}
|
|
1847
1901
|
}
|
|
1848
1902
|
function notifyOPFSSync(op, path, newPath) {
|
|
1849
1903
|
if (!opfsSyncPort) return;
|
|
@@ -1871,6 +1925,18 @@ function notifyOPFSSync(op, path, newPath) {
|
|
|
1871
1925
|
}
|
|
1872
1926
|
break;
|
|
1873
1927
|
}
|
|
1928
|
+
case OP.SYMLINK: {
|
|
1929
|
+
const result = engine.read(path);
|
|
1930
|
+
if (result.status === 0) {
|
|
1931
|
+
if (result.data && result.data.byteLength > 0) {
|
|
1932
|
+
const buf = result.data.buffer.byteLength === result.data.byteLength ? result.data.buffer : result.data.slice().buffer;
|
|
1933
|
+
opfsSyncPort.postMessage({ op: "write", path, data: buf, ts }, [buf]);
|
|
1934
|
+
} else {
|
|
1935
|
+
opfsSyncPort.postMessage({ op: "write", path, data: new ArrayBuffer(0), ts });
|
|
1936
|
+
}
|
|
1937
|
+
}
|
|
1938
|
+
break;
|
|
1939
|
+
}
|
|
1874
1940
|
case OP.UNLINK:
|
|
1875
1941
|
case OP.RMDIR:
|
|
1876
1942
|
opfsSyncPort.postMessage({ op: "delete", path, ts });
|
|
@@ -1891,6 +1957,7 @@ function handleExternalChange(msg) {
|
|
|
1891
1957
|
case "external-write": {
|
|
1892
1958
|
suppressPaths.add(msg.path);
|
|
1893
1959
|
const result = engine.write(msg.path, new Uint8Array(msg.data), 0);
|
|
1960
|
+
if (result.status === 0) broadcastWatch(OP.WRITE, msg.path);
|
|
1894
1961
|
console.log("[sync-relay] external-write:", msg.path, `${msg.data?.byteLength ?? 0}B`, `status=${result.status}`);
|
|
1895
1962
|
break;
|
|
1896
1963
|
}
|
|
@@ -1899,8 +1966,10 @@ function handleExternalChange(msg) {
|
|
|
1899
1966
|
const result = engine.unlink(msg.path);
|
|
1900
1967
|
if (result.status !== 0) {
|
|
1901
1968
|
const rmdirResult = engine.rmdir(msg.path, 1);
|
|
1969
|
+
if (rmdirResult.status === 0) broadcastWatch(OP.RMDIR, msg.path);
|
|
1902
1970
|
console.log("[sync-relay] external-delete (rmdir):", msg.path, `status=${rmdirResult.status}`);
|
|
1903
1971
|
} else {
|
|
1972
|
+
broadcastWatch(OP.UNLINK, msg.path);
|
|
1904
1973
|
console.log("[sync-relay] external-delete:", msg.path, `status=${result.status}`);
|
|
1905
1974
|
}
|
|
1906
1975
|
break;
|
|
@@ -1910,6 +1979,7 @@ function handleExternalChange(msg) {
|
|
|
1910
1979
|
if (msg.newPath) {
|
|
1911
1980
|
suppressPaths.add(msg.newPath);
|
|
1912
1981
|
const result = engine.rename(msg.path, msg.newPath);
|
|
1982
|
+
if (result.status === 0) broadcastWatch(OP.RENAME, msg.path, msg.newPath);
|
|
1913
1983
|
console.log("[sync-relay] external-rename:", msg.path, "\u2192", msg.newPath, `status=${result.status}`);
|
|
1914
1984
|
}
|
|
1915
1985
|
break;
|