fix(export): server-accurate export size estimate (incl. media)#64
Draft
DavidBabinec wants to merge 1 commit into
Draft
fix(export): server-accurate export size estimate (incl. media)#64DavidBabinec wants to merge 1 commit into
DavidBabinec wants to merge 1 commit into
Conversation
… media The "Estimated size" line in the Export dialog was a client-side guess that ignored media entirely (`mediaAssetCount` was hardcoded to 0) and underestimated content ~10x (flat 8 KB shell + 1.5 KB/row constants). Toggling "Media files" never moved the number, which read as "media isn't exported" — but media *is* exported correctly; only the estimate was wrong. Replace the heuristic with an exact, server-computed estimate that reuses the export's own selection logic as a single source of truth: - New `POST /admin/api/cms/export/estimate` runs the identical table/row/media selection as the real export but computes the byte size instead of streaming the bundle. It never reads media files off disk or base64-encodes them: it serializes the real selection with empty `bytesBase64` strings and adds each asset's analytic Base64 length (4*ceil(n/3)). Because Base64 is ASCII, this equals the real bundle byte length exactly. - `export.ts` is refactored to share `buildBundle` + media-metadata mapping between the download and estimate paths, so they cannot drift. - `useExportEstimate` now fetches this endpoint (debounced, cancellable) and formats the result; the dialog mirrors the exact ExportRequest it will send. Verified live against a real site (19 images, ~69 MB): estimate without media = 183,618 B, with media = 96,769,329 B — byte-identical to the actual download. Tests assert estimate === real download size for the no-media, no-shell, and embedded-media cases. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The Estimated size line in the Export dialog was a client-side guess that:
mediaAssetCountwas hardcoded to0(ExportDialog.tsx:205, comment: "caller doesn't provide a cheap count yet"), so toggling Media files never changed the number.This read as "media isn't being exported" — but the export is correct; only the estimate was wrong. (Verified separately: a real export of a 19-image site embeds all binaries as base64 and round-trips on import. See the analysis in the conversation that produced this PR.)
Fix — one source of truth
Replace the heuristic with an exact, server-computed estimate that reuses the export's own selection logic so the number can never drift from the real download:
POST /admin/api/cms/export/estimate— runs the identical table/row/media selection as the real export, but computes the byte size instead of streaming the bundle. It never reads media files off disk or base64-encodes them: it serializes the real selection with emptybytesBase64strings and adds each asset's analytic Base64 length (4·⌈n/3⌉). Base64 is ASCII, so this equals the real bundle byte length exactly.export.tsrefactor —buildBundle+ the media-metadata mapping are shared between the download and estimate paths, so they can't diverge. Behavior of the existing download path is unchanged.useExportEstimate— now fetches the endpoint (debounced 250 ms, cancellable viaAbortController) and formats the result; the dialog mirrors the exactExportRequestit will send. The previous value stays on screen while a new estimate is in flight (no flicker); failures showunavailable.Verification
bun run build✓ ·bun run lint✓ ·bun test✓ — 5439 pass, 0 failcmsTransferExport.test.ts), plus a dialog test that the estimate re-fetches and grows when Media is toggled (exportDialog.test.tsx).🤖 Generated with Claude Code