Site builder: ship head code to published pages + fix 6 adversarial-review Minors #4
Reference in New Issue
Block a user
Delete Branch "headcode-and-minors"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Follow-up to PR #3.
Head code end-to-end (was: never reached published sites)
useWhpApi.ts):save()now sendshead_code+ fulldesigntokens;load()restores them viaupdateDesign(backward-compatible with old project.json).web-files/api/site-builder.php, shipped separately):generateCompiledHTML()gains a head-code slot;handlePublishreadshead_code/design.headCodefrom project.json and injects it raw into each published page's<head>(site owner's own markup, by design).php -lclean.6 Minors from the adversarial review
addPageids unique even within one millisecond.scopeId→ djb2 hash (collision-free across case/punctuation; 50k-id no-collision verified).safeUrlblocksdata:image/svg+xml(otherdata:image/*still allowed).sandboxon iframes (hook added+removed per call, no leak).531 tests green (from 503); build clean.
🤖 Generated with Claude Code
M-3: PageContext.addPage minted ids from bare `page_${Date.now()}` -- two adds inside the same millisecond collided on id, so a subsequent rename/delete/save silently acted on both pages at once. Added a module-scoped monotonic counter combined with the timestamp (nextPageId(), exported for direct unit testing) and used it everywhere an addPage-style id is minted (addPage, replaceAllPages). M-4: scopeId() lowercased + stripped non-alphanumeric characters from the node id into a slug, so two node ids differing only by case/punctuation (e.g. "AbC" vs "abc", or "a-b" vs "ab") collapsed onto the same scope -- defeating the whole point of scoping ids per node (M-1/Menu/Tabs/ColumnLayout/Gallery/etc. all rely on it). Now hashes the raw node id via the existing djb2 stableHash() instead of slugifying it: still deterministic (same id -> same scope) and a valid CSS ident, but collision-resistant across case/punctuation. This changes the exact scope strings Menu/Tabs/ColumnLayout/Gallery/etc. emit -- expected and fine, since none of their tests pinned an exact scope value (all already asserted structure/uniqueness). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>