Skip to content

fix: streaming Export leaves a recoverable .partial file on cancel/error#114

Merged
BorisTyshkevich merged 2 commits into
mainfrom
fix/export-cancel-partial-artifact-105
Jul 1, 2026
Merged

fix: streaming Export leaves a recoverable .partial file on cancel/error#114
BorisTyshkevich merged 2 commits into
mainfrom
fix/export-cancel-partial-artifact-105

Conversation

@BorisTyshkevich

Copy link
Copy Markdown
Collaborator

What & why

Closes #105.

Cancelling an export (or hitting a mid-stream server error) called writable.abort() on the File System Access API's FileSystemWritableFileStream. On Chrome this leaves a hidden, 0-byte .crswap swap file behind and never materializes the visible target the user picked — so a cancelled/failed export recovered neither the target file nor any partial data, just an invisible orphan.

streamToFile (src/ui/app.js) now close()s the writable in the catch path instead — finalizing whatever bytes were already committed under the target handle — then renames it in place to <name>.partial via FileSystemFileHandle.move() (Chrome 110+), so a cancelled/failed export leaves a clearly-labeled, inspectable partial artifact. Falls back to leaving the plain, non-renamed file when .move() is unsupported, or if the rename itself throws (e.g. a name collision) — best-effort, never blocks surfacing the original error.

Applies uniformly to both export paths that share streamToFile: the single-file export (exportDirect) and the per-statement script export (exportScript).

Checklist

  • npm test passes (the per-file coverage gate is non-negotiable)
  • Tests added/updated in the same change as the code
  • npm run build succeeds (single-file dist/sql.html)
  • Layers kept honest: pure logic in src/core/, network in src/net/ (injected fetch), DOM in src/ui/
  • No new runtime dependency
  • README / CHANGELOG.md ([Unreleased]) updated if behavior or the deployed surface changed
  • Reconciled affected tracked work (roadmap Roadmap to 1.0.0 #68, the issue body, ADR/CHANGELOG) if this change reshaped it — n/a beyond the CHANGELOG entry; this is a standalone inbox fix, not on the Roadmap to 1.0.0 #68 build order.

Test plan

  • npm test — 1281/1281 passing, all per-file coverage gates hold (app.js: 100/96.24/92.01/100 — within its documented floor)
  • npm run builddist/sql.html builds clean
  • Two independent review passes (correctness + test-quality) found no bugs; two test-quality nits (duplicated fixture, missing abort-not-called assertions) were applied
  • Not run through Playwright e2e — no existing e2e spec touches Export (native file pickers aren't exercised there), and this change doesn't touch any rendered UI, only an already-seamed error path already covered by unit tests with mocked FileSystemWritableFileStream/FileSystemFileHandle

🤖 Generated with Claude Code

BorisTyshkevich and others added 2 commits July 1, 2026 15:20
…ror (#105)

writable.abort() on Chrome's File System Access API leaves a hidden,
0-byte .crswap swap file behind and never materializes the visible
target — so a cancelled or mid-stream-failed export recovered nothing.
streamToFile now close()s the writable instead (finalizing whatever
bytes were already committed) and renames it in place to <name>.partial
via FileSystemFileHandle.move() (Chrome 110+), falling back to the
plain, non-renamed file when move() is unsupported or itself fails.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…tial-artifact-105

# Conflicts:
#	CHANGELOG.md
@BorisTyshkevich BorisTyshkevich merged commit fcd024f into main Jul 1, 2026
6 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.

inbox: cancelled Export leaves an orphaned 0-byte .crswap temp file instead of a recoverable partial artifact

1 participant