@adea-ai/spatial
Scene and asset manifest contracts plus the shell-to-engine spatial protocol for Adea workspaces. It provides types, mount manifests, URL helpers, and telemetry validation without a rendering engine, binaries, or secrets.
Consolidates the former @adea-ai/asset-manifests and @adea-ai/spatial-protocol
packages, which always released together; both are deprecated in favor of this
package.
asset-manifests.ts: typed scene data shapes:SceneManifest,SceneZone,SceneStartPosition, assigned-props manifests, static-field asset URLs.manifests.ts:hqHomeManifest/hqWorkManifestmount constants (mirrors the engine's room layout; the engine is source of truth).scene-spawn.ts: cross-app spawn encode/parse and portal URL helpers.telemetry.ts:ScenePerformanceReportschema, validation, envelope, and navigation instrumentation.sim-bridge/(subpath@adea-ai/spatial/sim-bridge): the contract for embedding a separately hosted Agent Sim page. See below.data/: tracked scene manifests (home/,work/), mirrored from the engine'sscenes/sim/assets/; staged into the web public dir byscripts/sync-assets.mjs.
Tracked scene data is a public mirror, not proof that every file matches a particular private source revision or distributed pack. Manifest and payload acceptance need separate checks against the intended pack.
Hosted Agent Sim bridge (@adea-ai/spatial/sim-bridge)
Schema, validators and a launch contract for a hosted Agent Sim page embedded in an
iframe. It is a subpath export so the default desktop payload and the app bundle do not
include it, and it contains no private Agent Sim or asset code. It has no transport of its
own: callers pass MessageEvent-shaped values in and post through postToFrame /
postToHost.
-
Messages (
messages.ts): a closed, versioned set. Frame to host:frame.ready,frame.state,frame.close,frame.error. Host to frame:host.launch,host.dispose. There is no generic call, eval, filesystem, native-RPC or credential message, and the strict payload shapes reject any extra key (atokenfield included). Each message is accepted only when its sender origin is on the exact allowlist, itsevent.sourceis the exact frame (or parent) window, its envelope carries the per-mountbridgeIdthe host issued (createBridgeId), the version is supported, and it stays inside a finite size, depth, width and node budget (about 2 KiB; cyclic, deep and wide payloads are refused without being walked). Accessor properties are never read, and every discriminant is read as an own data property. Posts never use*. -
Origins (
origin.ts): exact canonicalscheme://host[:port]strings. No wildcards, suffix matching, paths ornull. Loopbackhttp:needs an explicitallowLoopbackHttpopt-in for local development. Being on the allowlist says where a frame was served from. It is not proof of an official desktop identity or an entitlement, and neither is localhost or any value embedded in the app. -
Launch (
launch.ts): the host asks the Adea backend for a launch (SimLaunchRequest); the backend checks entitlement and returns a one-time code valid for at most 120 seconds (SimLaunchGrant, which is also refused when it is stale, for another surface, or for a frame origin outside the allowlist). The host posts the code to the frame, which exchanges it at the sim origin for a sim-only session (SimSessionExchangeRequest/SimSessionExchangeResult). Neither body carries a token.createLaunchOnceandcreateLaunchCodeLedgerpin the single-use behaviour for the frame and for a backend implementation to match. -
Launch service (
service.ts): the backend logic for both steps, written against injectable ports and with no I/O, endpoint or storage of its own.createSimLaunchIssuerchecks a caller-suppliedSimEntitlementCheckerand issues a code through aSimLaunchCodeStore;createSimSessionExchangeredeems it once and returns theSet-Cookievalue separately from the JSON body. The sim origin and the entitlement source are inputs, never defaults: an absent or invalid origin answersnot_configuredbefore the entitlement source is asked, and any verdict other thanentitledfails closed. Nothing here chooses where entitlement comes from, where the sim is hosted, or how stores persist. -
Session cookie (
cookie.ts): named__Host-adea-sim, withHttpOnly,Secure,Path=/,SameSite=None,Partitioned, noDomain, and a lifetime of at most one hour. It authorizes the sim origin's assets only, never an Adea account API. -
Availability (
availability.ts):reduceSimLaunchis a pure state machine (idle,requesting,awaiting_frame,launching,running,unavailable,offline), and every state carries anattempt:startbegins attempt N+1 and a grant, frame message or timeout is applied only when it names the current attempt, so a late event from an interrupted attempt cannot launch, fail or close a newer one (mint a freshbridgeIdper attempt too). A surface isrunningonly after the frame says so, anddescribeSimAvailabilitygives truthful copy that states Chat and Dev are not affected. -
Scene channel (
scene.ts): feeds the running engine the workspace scene Virtual view draws, as a full snapshot and then diffs against the last revision the engine acknowledged, one revision in flight, withframe.scene.ack/nack/perfback.createSimSceneFeedis the host side andparseHostSceneMessagethe engine's validator. Spec:docs/specs/sim-bridge-scene.md.
Not part of this package: the hosted entry, the backend endpoints, the private backing origin that authorizes assets before serving cached responses, and any credentials or deployment. Those are separate work.