postMessage protocol you can drive the
preview with and hear back on.
Every message carries vpod: 1. That is the protocol version, and it is also what
tells a vpod message apart from everything else posting into a page; several
frameworks post bare strings, so a message without it is ignored in both
directions.
In one page
Wait for
ready before sending anything you care about. A message posted before
the preview has attached its listener is not queued, it is lost — and ready is
also the first point at which there is a machine for run to run on.What the preview sends
Two fields on
ready are worth reading rather than ignoring:
networkis"sab"or"none", which is the honest answer to “can the guest reach the internet from here” (see networking inside an iframe). It says nothing about which backend the SDK chose, on purpose.warmis whether the snapshot came from cache rather than the network, so a page timing its own demo is not quoting a cold number as a warm one.
error distinguishes a snapshot that could not be resolved ("snapshot", raised
before any bytes are downloaded) from a machine that would not start ("boot").
What the preview accepts
An unknown theme name is ignored rather than falling back to the default. That is
the opposite of the URL’s behaviour, and deliberately: a
?theme= typo is a page
you can only fix by reloading it, where a message you sent is one you can send
again.
run needs a key
run is honoured for a keyed preview and refused for a keyless one.
By the time the message arrives, the browser has already enforced
frame-ancestors from the key’s allowlist, so “framed at all” is “on the
list” — there is no second check to do and no allowlist to ship to the client. A
keyless preview is served frame-ancestors *, so being framed vouches for
nothing, and an embed that any page could execute commands in is a different
product.
Everything else works either way. A keyless embed still reports ready, streams
output, and takes reset and theme.
Origins, in both directions
Three rules, and each closes a real hole:- The preview always posts to an explicit target origin, never
"*". A preview that broadcast guest output to whoever happened to be framing it would leak the contents of a private snapshot to a page that only managed to load it. - Inbound messages whose
event.originis not the embedder are ignored. The embedder is not the only thing that can reach that window. - Anything without the
vpodtag is ignored, in both directions.
location.ancestorOrigins, which is
exact and unaffected by Referrer-Policy, and falls back to document.referrer
where that does not exist (Firefox).
An embedder serving
Referrer-Policy: no-referrer in Firefox leaves the preview
with no origin it can address, so it sends no messages at all. The embed still
loads and still works — it is the bridge that goes quiet. Chromium and Safari have
ancestorOrigins and are unaffected.A preview you drive and nobody types in
readonly=1 disables the keyboard at the terminal, but not run: the cmd
parameter and an embedder’s run message both call the line editor directly.