Files
sim/apps
Waleed b44d285607 fix(files): download a markdown file as a zip only when it really has assets (#7009)
* fix(files): download a markdown file as a zip only when it really has assets

A document that merely mentions an embed URL in prose or an inline code span
counted as having attachments, so any document about the files API downloaded
as a zip whose assets/ folder was empty.

- Detect embeds with the markdown lexer instead of scanning raw text, so only
  real image embeds count: prose, code spans, fenced samples, and links no
  longer do
- Choose the export format after resolving assets rather than from the
  candidate count, so a missing, unreadable, or oversized embed falls back to
  the plain document instead of an empty zip
- Move the document scan out of the copilot tool tree into lib/uploads/server,
  where both file routes already live, and drop two pass-through wrappers
- Share one <img> src reader between the clipboard handlers and the scan
- Walk tokens explicitly: marked's walkTokens concatenates per token and costs
  O(n^2), measuring 5.4s on a 254KB document against 14ms here, on a path
  anonymous public-share traffic reaches

* fix(files): keep an embed id spelled as the document spells it

Decoding the id let a percent-encoded embed resolve and bundle its asset while
the rewrite, which searches the document for that id, found nothing — the zip
kept an API URL that renders as a broken image offline. Keys stay decoded;
they are matched against stored keys, not against document text.

* fix(files): resolve an export asset by its stored id, rewrite by its spelling

An embed carries two representations and they are not interchangeable: metadata
resolves by the stored id, while the rewrite finds the embed by searching the
document for the spelling it used. Using one for both either drops a
percent-encoded asset or bundles it behind a link still pointing at the API.

* fix(files): resolve an embed by its stored id wherever one is read from a document

The export bundler decoded an embed's spelling before looking it up, but the
file-agent's embeddability warning did not, so a percent-encoded embed the
export resolves and bundles could still be reported as one that will not
survive an export. Both now share one helper.

Request-supplied ids are untouched: their route contracts already constrain
them to the plain id charset, so there is no spelling to decode.
2026-08-23 11:15:14 -07:00
..
…