@componentor/fs 3.0.4 → 3.0.5

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 CHANGED
@@ -82,6 +82,7 @@ const fs = new VFSFileSystem({
82
82
  strictPermissions: false, // Enforce Unix permissions (default: false)
83
83
  sabSize: 4194304, // SharedArrayBuffer size in bytes (default: 4MB)
84
84
  debug: false, // Enable debug logging (default: false)
85
+ swScope: undefined, // Custom service worker scope (default: auto-scoped per root)
85
86
  });
86
87
  ```
87
88
 
@@ -508,6 +509,14 @@ Make sure `opfsSync` is enabled (it's `true` by default). Files are mirrored to
508
509
 
509
510
  ## Changelog
510
511
 
512
+ ### v3.0.5 (2026)
513
+
514
+ **Fixes:**
515
+ - Scope the internal service worker by default so it won't collide with the host application's own service worker
516
+ - Remove unnecessary `clients.claim()` from the service worker — it only acts as a MessagePort broker and never needs to control pages
517
+ - Namespace leader lock, BroadcastChannel, and SW scope by `root` so multiple `VFSFileSystem` instances with different roots don't collide
518
+ - Add `swScope` config option for custom service worker scope override
519
+
511
520
  ### v3.0.4 (2026)
512
521
 
513
522
  **Features:**
package/dist/index.js CHANGED
@@ -1302,6 +1302,9 @@ var VFSFileSystem = class {
1302
1302
  // Config
1303
1303
  config;
1304
1304
  tabId;
1305
+ /** Namespace string derived from root — used for lock names, BroadcastChannel, and SW scope
1306
+ * so multiple VFS instances with different roots don't collide. */
1307
+ ns;
1305
1308
  // Service worker registration for multi-tab port transfer
1306
1309
  swReg = null;
1307
1310
  isFollower = false;
@@ -1323,9 +1326,11 @@ var VFSFileSystem = class {
1323
1326
  umask: config.umask ?? 18,
1324
1327
  strictPermissions: config.strictPermissions ?? false,
1325
1328
  sabSize: config.sabSize ?? DEFAULT_SAB_SIZE,
1326
- debug: config.debug ?? false
1329
+ debug: config.debug ?? false,
1330
+ swScope: config.swScope
1327
1331
  };
1328
1332
  this.tabId = crypto.randomUUID();
1333
+ this.ns = `vfs-${this.config.root.replace(/[^a-zA-Z0-9]/g, "_")}`;
1329
1334
  this.readyPromise = new Promise((resolve2) => {
1330
1335
  this.resolveReady = resolve2;
1331
1336
  });
@@ -1398,7 +1403,7 @@ var VFSFileSystem = class {
1398
1403
  return;
1399
1404
  }
1400
1405
  let decided = false;
1401
- navigator.locks.request("vfs-leader", { ifAvailable: true }, async (lock) => {
1406
+ navigator.locks.request(`${this.ns}-leader`, { ifAvailable: true }, async (lock) => {
1402
1407
  if (decided) return;
1403
1408
  decided = true;
1404
1409
  if (lock) {
@@ -1415,7 +1420,7 @@ var VFSFileSystem = class {
1415
1420
  /** Queue for leader takeover when the current leader's lock is released */
1416
1421
  waitForLeaderLock() {
1417
1422
  if (!("locks" in navigator)) return;
1418
- navigator.locks.request("vfs-leader", async () => {
1423
+ navigator.locks.request(`${this.ns}-leader`, async () => {
1419
1424
  console.log("[VFS] Leader lock acquired \u2014 promoting to leader");
1420
1425
  this.holdingLeaderLock = true;
1421
1426
  this.promoteToLeader();
@@ -1459,7 +1464,7 @@ var VFSFileSystem = class {
1459
1464
  tabId: this.tabId
1460
1465
  });
1461
1466
  this.connectToLeader();
1462
- this.leaderChangeBc = new BroadcastChannel("vfs-leader-change");
1467
+ this.leaderChangeBc = new BroadcastChannel(`${this.ns}-leader-change`);
1463
1468
  this.leaderChangeBc.onmessage = () => {
1464
1469
  if (this.isFollower) {
1465
1470
  console.log("[VFS] Leader changed \u2014 reconnecting");
@@ -1485,7 +1490,8 @@ var VFSFileSystem = class {
1485
1490
  async getServiceWorker() {
1486
1491
  if (!this.swReg) {
1487
1492
  const swUrl = new URL("./workers/service.worker.js", import.meta.url);
1488
- this.swReg = await navigator.serviceWorker.register(swUrl.href, { type: "module" });
1493
+ const scope = this.config.swScope ?? new URL(`./${this.ns}/`, swUrl).href;
1494
+ this.swReg = await navigator.serviceWorker.register(swUrl.href, { type: "module", scope });
1489
1495
  }
1490
1496
  const reg = this.swReg;
1491
1497
  if (reg.active) return reg.active;
@@ -1530,7 +1536,7 @@ var VFSFileSystem = class {
1530
1536
  }
1531
1537
  };
1532
1538
  mc.port1.start();
1533
- const bc2 = new BroadcastChannel("vfs-leader-change");
1539
+ const bc2 = new BroadcastChannel(`${this.ns}-leader-change`);
1534
1540
  bc2.postMessage({ type: "leader-changed" });
1535
1541
  bc2.close();
1536
1542
  }).catch((err) => {