forked from mirror/crumbs-original
Three issues found in review, all around switching to a different note while the editor is already open (via a note-link or backlink chip): - TiptapEditor's onTransaction/onUpdate had no guard against writing state after the component is torn down. Removing a focused editor's DOM node fires a native blur, which ProseMirror turns into one last transaction synchronously during that same teardown pass, crashing with state_unsafe_mutation. Deferred the onTransaction write to a microtask (checked against a destroyed flag) so it lands after Svelte's current pass finishes; guarded onUpdate synchronously. - openEditor/openNoteById in NotesView.svelte awaited a network fetch before ever showing the editor, for every note open (not just link-driven navigation) — a regression for an offline-first app, and the source of a real race: two rapid note-link clicks left two fetches in flight with no ordering guarantee, so whichever resolved last won, not whichever was clicked last. Reverted to opening instantly from local/IndexedDB data (with a request-id guard against the residual race), and instead fetch backlinks lazily in NoteEditor.svelte only if not already present — mirroring the existing attachments-fetch pattern already in that file. Also applied the same post-teardown guard to that pre-existing attachments effect, since remounting on note-switch newly exposes it to the same class of race. - FormattingToolbar's closeDropdowns() cleared search results but never cancelled the pending debounce timer, so a stale query could repopulate results after the dropdown had already closed. Added the missing clearTimeout, plus a try/catch around the search fetch for consistency with the pattern used elsewhere in the app. Verified: pnpm check (0 errors), full unit suite (316/316), and the existing e2e suite including all note-linking scenarios (19/19) all pass against these changes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>