@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.
@@ -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) return 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.resolvePath(resolved);
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 (opfsSyncEnabled && result.status === 0) {
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 (opfsSyncEnabled && result.status === 0) {
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 (opfsSyncEnabled && result.status === 0) {
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 (opfsSyncEnabled && result.status === 0) {
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 (opfsSyncEnabled && result.status === 0) {
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 (opfsSyncEnabled && result.status === 0) {
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 (opfsSyncEnabled && result.status === 0) {
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 (opfsSyncEnabled && result.status === 0) {
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 (opfsSyncEnabled && result.status === 0) {
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 (opfsSyncEnabled && result.status === 0) {
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 (opfsSyncEnabled && result.status === 0) {
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 (opfsSyncEnabled && result.status === 0 && result.data) {
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;