Skip to content

feat(studio-server): the preview records the kind and origin of each early error - #7041

Merged
miguel-heygen merged 2 commits into
mainfrom
feat/preview-error-kinds
Nov 3, 2026
Merged

miguel-heygen merged 2 commits into
mainfrom
feat/preview-error-kinds

Conversation

@miguel-heygen

Copy link
Copy Markdown
Collaborator

What changes

The Studio preview already keeps every error raised before the player attaches, as text, in window.__hfPreviewErrors. It now also pushes one { name, origin } object per error into a second array, window.__hfPreviewErrorKinds, in the same order. The text array is unchanged.

  • name is the error's constructor name when it is SyntaxError, TypeError, ReferenceError or RangeError, and other for anything else (including an error with no error object).
  • origin is where the failing script came from, read from the error's filename:
    • runtime: the preview runtime script (/api/runtime.js),
    • project: a page or file under /api/projects/, which covers the composition's own inline scripts and its project files,
    • studio: any other script served by the same server,
    • unknown: no filename (for example a cross-origin "Script error."), or one that is not on this server.

The new array carries no message text, so a host that embeds the preview can tell what kind of error it was and where it came from without reading anything the author wrote.

Why

A host that embeds the preview only had the message text, which is free-form and can contain authored content. A fixed name and origin is enough to tell a bug in the runtime from a bug in the project, and it can be reported safely.

No visible change

Nothing on screen changes. No Studio or player file is touched; the preview page gains one inline array that only code reads.

Tests

preview.test.ts runs the injected script against a fake window and raises five errors: one from the runtime, one from a project file, one from another script on the server with a custom error class, one from another site, and one with no filename. It expects the exact { name, origin } list, the message array unchanged, and no error text anywhere in the new array. 150 tests pass in the file, 3 runs in a row.

fails without the fix: preview.test.ts › records the kind and origin of each early error, never its text, and leaves the messages as they were fails on main, where the array does not exist.

Size

62 changed lines: one constant, one inline script and its test.

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve at 5173140f. No blockers.

  • Privacy: kinds only ever holds one of four fixed built-in names or "other", plus one of four fixed origin labels. Neither the message nor the file path is copied in. known[name]===1 also stops inherited keys such as toString from getting through. The test checks that no "secret" text leaks.
  • Origin: the runtime path comes from adapter.runtimeUrl, which is /api/runtime.js in both the CLI and Vite adapters, so it isn't hard-coded. A URL is only classified when it is same-origin, so a cross-origin "Script error." or a CDN library comes out as unknown. The composition's inline scripts report the page URL, which is under /api/projects/, so they come out as project.
  • Compatibility: the __hfPreviewErrors text array is pushed to exactly as before. The new array is added alongside it, in the same order.
  • Fix-line rule: the "fails without the fix:" line names preview.test.ts › records the kind and origin of each early error…, and that test reads __hfPreviewErrorKinds, which doesn't exist on main.

Non-blocking: the /api/projects/ prefix is a literal, while the runtime path comes from the adapter. If a host ever mounts the API under a different prefix, project errors would be labelled studio. Deriving the prefix the same way would keep the two consistent.

@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Edit accuracy: accurate 267 (base branch 267), smooth 129 of those

The gate passes.
Smoothness is reported in the artifact, not gated. A case fails only if it fails 2 of 3 runs.

Quarantined, measured but not gated (8)

@miguel-heygen
miguel-heygen force-pushed the feat/preview-error-kinds branch from 5173140 to 2bab77d Compare November 3, 2026 00:07
@miguel-heygen
miguel-heygen force-pushed the feat/preview-error-kinds branch from 2bab77d to de1116a Compare November 3, 2026 02:57

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve at a745dab7. No blockers.

Delta since 5173140f (my earlier approval): a rebase onto main plus one commit for the code-scanning finding.

  • scriptJson: it is JSON.stringify with <, U+2028 and U+2029 escaped. That stops a value from closing the tag with </script>, opening <!--, or breaking the line in older engines. It is applied in both places that inline a value: the runtime path in the early-errors script, and cdnBase in the GSAP fallback. cdnBase already escaped <, so its only new behaviour is the line-separator escaping. The JSON.parse round-trip in the new test shows the value itself is unchanged.
  • Feature unchanged: the rest of the early-errors script is byte-for-byte the same as what I reviewed before. The fix line still names the kinds test, which fails on main.
  • CI so far: regression failed at "Set up Docker Buildx" in shard-1, which is an infrastructure step and not this change. preview-regression and PR captures passed, and CI and CodeQL are still running.

@miguel-heygen
miguel-heygen added this pull request to the merge queue Nov 3, 2026
Merged via the queue into main with commit b84835c Nov 3, 2026
96 of 107 checks passed
@miguel-heygen
miguel-heygen deleted the feat/preview-error-kinds branch November 3, 2026 08:04
@miguel-heygen miguel-heygen mentioned this pull request Nov 3, 2026
1 task done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants