Skip to content

Commit a3ffc24

Browse files
committed
Export memfs as well
1 parent b7da989 commit a3ffc24

File tree

7 files changed

+31
-12
lines changed

7 files changed

+31
-12
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
"execa": "^5.1.1",
3737
"fs-extra": "^11.3.2",
3838
"lodash": "^4.17.21",
39-
"memfs": "^4.49.0",
4039
"opfs-mock": "^2.4.0",
4140
"path-browserify": "^1.0.1",
4241
"playwright": "1.54.1",
@@ -50,6 +49,7 @@
5049
"yargs": "^17.7.2"
5150
},
5251
"dependencies": {
52+
"memfs": "^4.49.0",
5353
"vscode-jsonrpc": "^8.2.1"
5454
},
5555
"pnpm": {

pnpm-lock.yaml

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

spec/MultiTabWorkerBroker.spec.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,8 +201,9 @@ describe("MultiTabWorkerBroker", () => {
201201
// Teardown the leader
202202
await broker1.stop();
203203

204-
// Wait for follower to become leader
205-
await new Promise((resolve) => setTimeout(resolve, 100));
204+
// Wait for follower to become leader and initialize its worker
205+
// Need more time since the worker needs to be created and initialized
206+
await new Promise((resolve) => setTimeout(resolve, 150));
206207
expect(broker2.isLeader).toBe(true);
207208

208209
// Verify new leader can communicate

spec/vfs.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { test, describe, beforeEach, afterEach, expect } from "vitest";
22
import { vol } from "memfs";
33
import "opfs-mock";
4-
import { MemfsFileSystem } from "./MemFSFileSystem";
4+
import { MemfsFileSystem } from "../src/MemFSFileSystem";
55
import { SyncOPFSFileSystem } from "../src/SyncOPFSFileSystem";
66
import { VirtualFileSystem } from "../src/VirtualFileSystem";
77

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { fs, vol } from "memfs";
22
import path from "path";
3-
import { VirtualFileSystem } from "../src/VirtualFileSystem";
3+
import { VirtualFileSystem } from "./VirtualFileSystem.js";
44

55
// Memfs implementation
66
export class MemfsFileSystem implements VirtualFileSystem {

src/MultiTabWorkerBroker.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ export class MultiTabWorkerBroker {
4242
private connections = new Map<string, { reader: MultiTabMessageReader; writer: MultiTabMessageWriter }>();
4343
private nextConnectionId = 0;
4444
private shouldDebug = false;
45+
// Track the active lock request promise to ensure proper cleanup
46+
private activeLockPromise: Promise<any> | null = null;
4547

4648
constructor(
4749
private readonly lockName: string,
@@ -130,8 +132,8 @@ export class MultiTabWorkerBroker {
130132
// First, try to acquire the lock immediately with ifAvailable
131133
// This allows us to quickly determine if we can be leader or if another tab already has the lock
132134
// If we can acquire the lock, we are the leader, and we return promptly from start
133-
// Note: not awaited, because this won't ever return if we do acquire the lock as the leader
134-
navigator.locks
135+
// Store the lock promise so we can wait for it to complete during stop()
136+
this.activeLockPromise = navigator.locks
135137
.request(this.lockName, { ifAvailable: true }, async (lock) => {
136138
if (lock === null) {
137139
// Lock is not available - another tab is the leader
@@ -175,8 +177,8 @@ export class MultiTabWorkerBroker {
175177
private waitForLockAndBecomeLeader(): void {
176178
// Wait indefinitely to acquire the lock for failover
177179
// This will block until the current leader releases the lock
178-
// Note: not awaited, because this won't ever return if we do acquire the lock and become the leader
179-
navigator.locks
180+
// Store the lock promise so we can wait for it to complete during stop()
181+
this.activeLockPromise = navigator.locks
180182
.request(this.lockName, { signal: this.lockAbortController!.signal }, async () => {
181183
// We got the lock! Become the leader and start the worker
182184
await this.becomeLeader();
@@ -468,6 +470,21 @@ export class MultiTabWorkerBroker {
468470
this.lockAbortController.abort();
469471
}
470472

473+
// Wait for the lock to be fully released before proceeding
474+
// This is critical to ensure a new broker can immediately acquire the same lock
475+
const lockPromiseToAwait = this.activeLockPromise;
476+
if (lockPromiseToAwait) {
477+
try {
478+
await lockPromiseToAwait;
479+
} catch (error) {
480+
// Ignore abort errors which are expected during stop
481+
if (error && (error as any).name !== "AbortError") {
482+
this.error("Error while waiting for lock release:", error);
483+
}
484+
}
485+
this.activeLockPromise = null;
486+
}
487+
471488
// Terminate worker if we're the leader
472489
if (this.worker) {
473490
this.worker.terminate();

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export type { VirtualFileSystem } from "./VirtualFileSystem.js";
22
export { SyncOPFSFileSystem } from "./SyncOPFSFileSystem.js";
33
export { MultiTabWorkerBroker } from "./MultiTabWorkerBroker.js";
4+
export { MemfsFileSystem } from "./MemFSFileSystem.js";

0 commit comments

Comments
 (0)