/** Serializes versioned writes without replacing edits made during a request. */ export class BoardSaveQueue { private revision = 0; private savedRevision = 0; private pending: Promise | null = null; value: T; error: Error | null = null; constructor( initial: T, private readonly write: (value: T) => Promise, private readonly notify: () => void, private readonly onSaved: (value: T) => void, ) { this.value = initial; } get dirty() { return this.revision !== this.savedRevision; } get saving() { return this.pending !== null; } update(value: T) { this.value = { ...value, version: this.value.version }; this.revision += 1; this.error = null; this.notify(); } flush(): Promise { if (this.pending) return this.pending; if (!this.dirty) return Promise.resolve(); this.error = null; // Defer execution so even a synchronous transport throw sees pending set. this.pending = Promise.resolve().then(async () => { while (this.dirty) { const revision = this.revision; const saved = await this.write(this.value); this.savedRevision = revision; this.value = revision === this.revision ? saved : { ...this.value, version: saved.version }; this.onSaved(saved); } }).catch((error: unknown) => { this.error = error instanceof Error ? error : new Error(String(error)); throw this.error; }).finally(() => { this.pending = null; this.notify(); }); this.notify(); return this.pending; } }