3.1 KiB
Browser displays
This package owns ordinary graph transactions for browser enrollment, assignment and reported mount state. Studio supplies the host adapter; the package contains no browser heartbeat, DOM code or private storage API.
A workspace entry conforms to WebStudioDisplayDirectory. Its conformance owns
an enrollment edge, and enroll({nonce,label}) returns the same target for that
nonce. Each directory currently permits 128 targets and rejects further enrollment
explicitly. This is a bounded prototype, not an automatic device inventory GC.
WebStudioDisplayTarget.assign accepts an optional subject/presentation pair.
The subject conforms to WebStudioPresentable, whose canPresent validates the
selected registered presentation. This role does not require Canvas or placements;
the example workspace adapters forward their existing presentation check. Named
presentations have checked subject-only module contracts; callbacks cannot be
stored in assignments. The target's subject is a graph edge, not a string ID in
JSON. Changing the edge and desired generation is one transaction.
Assignments and observed outcomes are durable. acknowledge accepts a generation,
monotonic report sequence, status (mounted, failed, empty) and bounded error.
Old generations and reordered reports return false without modifying state.
Reported success describes a client mount; it is not a claim of trusted execution.
The browser adapter uses a per-tab nonce and Web Lock. Duplicated tabs get distinct nonces; reloading resumes enrollment. Enrollment is a host startup/user action, never business-object creation from a component render. Multiple displays may mount the same subject. Losing the connection does not clear its desired state.
Studio's authenticated presence adapter validates target references against Camino before issuing an opaque connection lease. Leases expire after 45 seconds; recent connection observations remain for at most ten minutes, with a 256-record cap. A target ID is not a credential. There is no persistent heartbeat history.
Headless calls
A headless session uses the same generated descriptors and public operations as Studio. The caller supplies normal workspace authorization when opening its session; graph references alone grant no access.
const directory = await session.acquire(
{ enroll: interfaces.WebStudioDisplayDirectory.enroll },
session.bootstrap.entry,
);
const enrollment = await directory.enroll.call({
nonce: savedClientNonce,
label: "Preview display",
}).settled;
if (enrollment.status !== "accepted") throw Error(enrollment.status);
const target = await session.acquire(interfaces.WebStudioDisplayTarget, enrollment.value);
const result = await target.assign.call({
subject: presentableSubject,
presentation: "presentation:studio:canvas",
}).settled;
tools/local-first/studio-session.test.mjs is the executable example, including
reference rejection and stale-report tests. package.nix selects the server-only
TypeScript artifact. Native fields and relationships remain queryable in browser
replicas without bundling mutation implementations there.