* ⚡ Keep only the shape data the worker reads
The worker kept a full copy of the current page for its selection and
snap indexes. It now keeps only the attributes the indexes and the
change replay read, and re-indexes only the shapes that changed.
On a 52k-shape page the worker heap goes from 698 MB to 286 MB.
Closes#12740
AI-assisted-by: claude-opus-5-5
* ♻️ Share the worker re-trim with its replay test
The worker and its replay test now share `retrim-objects`.
AI-assisted-by: claude-opus-5-5
* 🐛 Stop worker index updates from adding nil-keyed entries
When a commit touched a page the worker had not indexed, or deleted the
indexed page, `:index/update` ran the selection and snap updates with a
nil page. That left entries under a nil key (and a stale selection index
for a deleted page) for the rest of the session.
Skip updates for pages the worker does not hold, since a later
`:index/initialize` sends the whole page again, and drop the selection
and snap indexes when the changes delete the page.
AI-assisted-by: claude-opus-5-5
* 🐛 Free the worker's copy of a page when leaving it
The worker kept every visited page, with its selection and snap
indexes, for the whole session. On large files each visited page added
hundreds of MB to the worker heap.
Add an `:index/finalize` worker command that drops a page and its
indexes, and send it from `finalize-page`, which runs on every page
switch and when leaving the workspace. Coming back to a page indexes it
again from the full page, as before.
Closes#12738
AI-assisted-by: claude-opus-5-5
When render-wasm is active, shape exports (single file, ZIP, and Export
boards multi-page PDF) run on the shared worker WASM module so the UI
stays responsive. A progressive PDF session (begin/add-page/finish)
updates progress per page; cancel settles on the client. The server
exporter path remains for the SVG renderer.