Check the whole saved file name: aliases, URL refresh, extensionless rows

Astra's review of #356 found three ways a name could still get past the
check. An old build's alias for a picture uses the image's own id, which was
never checked. getAssetUrl answered by that alias. An extensionless row
whose id carries its own extension ("payload.bat") got a URL.

isSavableImageFileName now checks the name the app will actually write: a
safe id, and an image extension, or no extension at all on an id without a
dot. Aliases are only made, and URLs only refreshed, under such a name.
Characters Windows refuses in a file name are refused in ids too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5d27078246Dara Adedeji committed on 10/21/2026, 5:08:01 PMparent8a330ab
4 files changedLine totals unavailable