The /runtime subpath queries features that the current host actually installed.
Legacy APIs retain their existing behavior. No capability is inferred from an SDK
package version or the existence of a global object.
import { getCapabilities, waitUntilReady, onCapabilitiesChanged } from "@urth/metatell-sdk/runtime";
import type { PluginRuntimeContext } from "@urth/metatell-sdk/lifecycle";
async function prepareObjects(sdk: PluginRuntimeContext) {
const room = sdk.getRoomScope();
const snapshot = await getCapabilities({ scope: room });
if (!snapshot.domains.objects?.capabilities.includes("spawn")) return;
await waitUntilReady("objects", { scope: room, timeoutMs: 5000 });
if (room.signal.aborted) return;
// Check the host's permission state and handle the operation's own failure.
}
function observeRuntime(sdk: PluginRuntimeContext) {
return onCapabilitiesChanged((snapshot) => {
console.log(snapshot.connection, snapshot.room);
}, { scope: sdk.scope });
}
protocolVersion: 1, host-installation epoch, and monotonic revision order
changes. Revision is not a persisted backend CAS token.room contains roomId, host sceneRevision, and room generation, or null.
The current host uses a local scene counter. Shared environment persistence
uses separate server-authoritative revisions (see environment).supported, ready, capabilities, and named
permission states (allowed, denied, unknown). Missing domains are
unsupported. Readiness does not grant permission.SdkDomain names are runtime, user, users, objects, triggers,
input, environment, chat, voice, emote, auth, camera, avatar,
waypoints, and backend. A domain appears only when the host advertises it.INTERNAL.getCapabilities rejects with UNSUPPORTED on a legacy host and DISCONNECTED
on a disconnected host. onCapabilitiesChanged delivers an initial snapshot and
ordered changes, including disconnection. With no driver it emits no initial
value, but can observe a later installation. Use getCapabilities to explicitly
check support. Unsubscribe or dispose the supplied scope to release listeners.
waitUntilReady resolves for a supported, ready domain. It rejects with
UNSUPPORTED for a missing domain, DISCONNECTED on connection loss, NOT_READY
at its deadline, or ABORTED when its owner is disposed. It does not retry an
operation or grant permission.
Request options accept scope, signal, and a finite positive timeoutMs up to
2147483647 milliseconds (default 5000). Cancellation releases request listeners,
abort handlers, and timers. Correlation IDs keep concurrent responses isolated.
An ordinary RPC timeout is TIMEOUT; a readiness deadline is NOT_READY.
SdkError (exported from /runtime) carries a code and, for RPC failures, the
request's correlationId. SdkErrorCode also includes INVALID_ARGUMENT,
PERMISSION_DENIED, CONFLICT, NOT_FOUND, STALE_SCENE, ASSET_FAILED, and
INTERNAL. These define a shared vocabulary; each domain must still implement
and test its transport and authorization. The RPC helper is internal, and
existing APIs are not silently converted to the new contract: chat, input,
objects, triggers, and auth keep their own errors. Cancellation cannot roll
back a server write that has already been accepted.
This protocol coordinates trusted plugins in the same window. It is not a security boundary against arbitrary JavaScript sharing the host page. Never send credentials, raw exceptions, or private host state in capability snapshots.
Personal and shared background drivers are described in environment. Each domain is advertised only when its host driver is installed.