The live-page bridge protocol
Development opt-in, exact origins, source mapping and version 1 postMessage envelopes.
On this page
The live bridge runs inside a website that explicitly integrates it. Studio embeds that site's actual development-server URL. The site's scripts, CSS, native links, framework rendering and router continue to run on its own origin.
Add the bridge to the site's development entry point#
import { connectVoiceStudio } from '@voice/review';
const connection = connectVoiceStudio({
studioOrigin: 'http://127.0.0.1:4188'
});
// Dispose when the development integration is unloaded (e.g. HMR cleanup).
// connection.dispose();For plain HTML, serve the built dist/voice-review.js from the target site's
own development assets and load it normally:
<script src="/dev/voice-review.js"></script>
<script>
const voiceConnection = VoiceReview.connectVoiceStudio({
studioOrigin: 'http://127.0.0.1:4188'
});
</script>Keep this opt-in integration in development mode. Use the Studio's exact origin:
localhost and 127.0.0.1 are different origins, as are different ports. No
wildcard is accepted. The bridge receives only review data and sends selections,
annotation IDs, mapping diagnostics and the current page location. It never
receives the local backend pairing token or provider credentials.
Connect the live DOM to the source#
Explicit data-voice-unit attributes are preferred. The identifier must match
the source adapter's TextUnit.id, and its eligible DOM text must match that
unit's text exactly. A framework/i18n application needs a source adapter that
identifies its actual template or translation string. A rendered route is not
itself a source filename, and translated runtime text is not interchangeable
with a different-language fallback in an HTML file.
Without an explicit identifier, the bridge can temporarily mark one unique, exact visible element-text occurrence. It chooses the deepest element when an element and its only text-bearing descendant represent the same occurrence. Repeated text, duplicate unassigned source units, mismatched explicit IDs and ambiguous matches remain unmapped. It does not trim/collapse text, guess from similar wording or wrap native text nodes. Inline source fragments that do not correspond to a complete element need explicit adapter support.
Only temporary data-voice-unit attributes are added; they are restored when
the review is replaced or disconnected. Native nodes, links and event handlers
are preserved. Code, hidden regions, editable controls and data-voice-exclude
regions are excluded. Normal DOM updates trigger remapping; refresh() is
available for host-specific rendering lifecycles.
Protocol version 1#
The exported VoiceStudioParentMessage and VoiceStudioChildMessage types are
the transport contract. The parent uses postMessage with the target site's
exact origin and checks message origin and event.source itself. The bridge
accepts only its explicitly configured Studio origin and its actual parent or
opener window; after connection it retains that peer.
- Parent sends
voice-studio:connectwith a fresh randomsessionId(16-128 ASCII letters, digits,_or-;crypto.randomUUID()is suitable). - Child replies
voice-studio:readywithsessionId,protocolVersion: 1, currenturlandtitle. - Parent resolves the correct source document, then sends
voice-studio:reviewwithsessionId, a freshreviewId, exactpageUrl,units,findingsandfeedback.pageUrlincludes query and fragment. All spans remain UTF-16. - Child returns
voice-studio:mappingwithreviewIdand diagnostics. Selection replies carryselection; annotation clicks returnfindingIdorfeedbackId, undervoice-studio:selection,voice-studio:findingandvoice-studio:feedback. Parent ignores stale session/review IDs. - SPA history changes, hash/popstate events and location changes send
voice-studio:location. URL changes immediately clear old review anchors. Parent resolves and sends a new review for the new exact page URL. - Parent can send
voice-studio:select-findingwithsessionId,reviewIdandfindingId(ornull) to focus a report finding, orvoice-studio:navigatewithsessionIdandaction: 'back' | 'forward' | 'reload'for native history. voice-studio:disconnectclears the review and session. A full page reload creates a new bridge instance and requires a fresh connection handshake.
Malformed reviews or a review for an outdated page URL produce a scoped
voice-studio:error; messages from other origins, windows or sessions are
ignored.
The Studio host currently uses an iframe. The target site's CSP/frame headers
must allow the Studio origin to embed it and its development CSP must allow the
bridge asset and annotation styles. An external page opened with noopener
has no connected Studio opener; opening it separately is ordinary browsing,
not a connected review fallback. Remote pages without this opt-in bridge,
closed shadow roots, unsupported source adapters and iframe-blocking headers
remain explicit limitations. Live review never grants a page authority to
write source files: persistence and reviewed diffs remain in the Studio backend.
Git and source reference
Source for this page: packages/review/LIVE-BRIDGE.md. Content hash and Git revision: Build record.