Files

62 lines
3.1 KiB
Markdown
Raw Permalink Normal View History

# 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.
```ts
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.