Skip to content

fix: address bugs B1–B8 from IMPROVEMENTS.md#213

Merged
d0x2f merged 2 commits into
masterfrom
fix/bugs-b1-b8
May 4, 2026
Merged

fix: address bugs B1–B8 from IMPROVEMENTS.md#213
d0x2f merged 2 commits into
masterfrom
fix/bugs-b1-b8

Conversation

@d0x2f
Copy link
Copy Markdown
Owner

@d0x2f d0x2f commented May 4, 2026

Summary

Fixes all 8 bugs identified in the codebase review.

  • B1 (App.svelte): Memory leak — media query listener was added as an anonymous function but removeEventListener was called with a different reference (darkModeChangeListener), so the listener was never removed. Fixed by storing the handler in handleSchemeChange and referencing it in both calls.
  • B2 (Menu.svelte): ClipboardJS instance created at module scope, never destroyed and used an overly broad 'button' selector. Moved into onMount, narrowed selector to [data-clipboard-text], destroyed in cleanup.
  • B3 (Board.svelte): Null dereference in dragula accepts callback — .column accessed without checking if $cards.find() returned a result. Added null guard.
  • B4 (Board.svelte): Same null dereference pattern in the drop handler. Added early return guard.
  • B5 (api.js): requestJson called .json() on any response regardless of HTTP status, silently treating 4xx/5xx error bodies as valid data. Now throws on !response.ok.
  • B6 (firestore.js): data.column.id and data.owner.id accessed without null checks in normaliseCard, crashing the onSnapshot callback on partial Firestore documents. Added optional chaining.
  • B7 (firestore.js): document._document.createTime is a private, undocumented Firestore SDK field that can silently break on any SDK update. Replaced with Date.now() as the fallback.
  • B8 (store.js): Race condition in passwordValid derived store — rapid changes to board or password could leave a stale promise result as the final value. Fixed with a cancellation flag.

Test plan

  • CI passes (lint, build, Cypress)
  • Copy-link button still copies the board URL
  • Drag-and-drop between columns still works
  • Password-protected board flow still works

🤖 Generated with Claude Code

d0x2f and others added 2 commits May 4, 2026 21:14
B1 (App.svelte): store media query handler in named var so removeEventListener removes the correct reference
B2 (Menu.svelte): move ClipboardJS into onMount, narrow selector to [data-clipboard-text], destroy on cleanup
B3 (Board.svelte): guard accepts callback against missing card during store mid-update
B4 (Board.svelte): guard drop handler against missing card during store mid-update
B5 (api.js): throw on non-OK HTTP status in requestJson so callers can distinguish failure
B6 (firestore.js): optional-chain column/owner in normaliseCard to survive partial Firestore writes
B7 (firestore.js): replace private _document field access with Date.now() fallback
B8 (store.js): cancel stale passwordValid promises with a generation flag to prevent stale results

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ection

- getBoard (onMount): wrap in try/catch so HTTP 404 navigates to /not-found
  instead of propagating as an unhandled rejection
- updateBoard (board subscriber): use .catch() since the call is fire-and-forget
  and a sync try/catch cannot catch async errors
- Remove resolved Bugs section from IMPROVEMENTS.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@d0x2f d0x2f merged commit 1cf1ab9 into master May 4, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant