From 4f9e29e5e7619224ebe8aecb173a3e380ae4e536 Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Sun, 22 Mar 2026 13:29:33 -0700 Subject: [PATCH] fix(canvas): persist deletions immediately to prevent resurrection Destructive operations (forget, delete, remember) now flush to IndexedDB + localStorage immediately instead of using 2s debounce, preventing deleted items from reappearing on page reload. Co-Authored-By: Claude Opus 4.6 --- lib/community-sync.ts | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/lib/community-sync.ts b/lib/community-sync.ts index f83103f..44239e1 100644 --- a/lib/community-sync.ts +++ b/lib/community-sync.ts @@ -699,7 +699,7 @@ export class CommunitySync extends EventTarget { this.dispatchEvent(new CustomEvent("shape-state-changed", { detail: { shapeId, state: 'forgotten', data: this.#doc.shapes?.[shapeId] } })); - this.#scheduleSave(); + this.#saveImmediate(); this.#syncToServer(); } @@ -734,7 +734,7 @@ export class CommunitySync extends EventTarget { this.dispatchEvent(new CustomEvent("shape-state-changed", { detail: { shapeId, state: 'present', data: this.#doc.shapes?.[shapeId] } })); - this.#scheduleSave(); + this.#saveImmediate(); this.#syncToServer(); } @@ -756,7 +756,7 @@ export class CommunitySync extends EventTarget { this.dispatchEvent(new CustomEvent("shape-state-changed", { detail: { shapeId, state: 'deleted', data: this.#doc.shapes?.[shapeId] } })); - this.#scheduleSave(); + this.#saveImmediate(); this.#syncToServer(); } @@ -1013,6 +1013,18 @@ export class CommunitySync extends EventTarget { }, 2000); } + /** Flush doc to IndexedDB immediately (no debounce). Use for destructive ops. */ + #saveImmediate(): void { + if (!this.#offlineStore) return; + if (this.#saveDebounceTimer) { + clearTimeout(this.#saveDebounceTimer); + this.#saveDebounceTimer = null; + } + const binary = Automerge.save(this.#doc); + this.#offlineStore.saveDocImmediate(this.#communitySlug, binary); + this.#offlineStore.saveDocEmergency(this.#communitySlug, binary); + } + #persistSyncState(): void { if (!this.#offlineStore) return;