import type { HelixRoom } from './multiplayer.js'; import type { RoomVarValue } from './multiplayer-contract/room.js'; import type { WorldSpawn } from './universal-vehicles.js'; import type { ActionSurfaceAction } from './action-surface.js'; export type DeviceDefinitionReference = { id: string; version: string; }; export type DevicePortKindV1 = 'value' | 'event' | 'command' | 'stream'; export type DevicePortDirectionV1 = 'input' | 'output' | 'bidirectional'; export type DevicePortDataTypeV1 = 'boolean' | 'number' | 'string' | 'media.audio' | 'media.video'; export type DevicePortAuthorityV1 = 'local' | 'server'; export type DeviceStreamRoutabilityV1 = 'routable' | 'embedded-only' | 'unavailable'; /** Engine-neutral endpoint declaration. Concrete Links belong to the host. */ export interface DevicePortV1 { id: string; direction: DevicePortDirectionV1; kind: DevicePortKindV1; dataType: DevicePortDataTypeV1; /** Exact compatibility identity, such as helix.audio/1. */ interface?: string; /** Stable event/command/stream meaning. Defaults to the port id for v1 devices. */ semantic?: string; /** Signal authority lane. Legacy declarations inherit from Device authority. */ authority?: DevicePortAuthorityV1; stateKey?: string; autoPair?: boolean; maxLinks?: number; /** Stream availability; meaningful only for stream outputs. */ routability?: DeviceStreamRoutabilityV1; } export interface DevicePortAddressV1 { instanceId: string; port: string; } /** Opaque host registry token; it never contains media samples. */ export type DeviceStreamHandleV1 = string & { readonly __deviceStreamHandleV1: unique symbol; }; /** Host-authored delivery. Callers never provide an authorization role. */ export interface DeviceBusEnvelopeV1 { schemaVersion: 1; deliveryId: string; linkId: string; source: DevicePortAddressV1; target: DevicePortAddressV1; kind: DevicePortKindV1; semantic: string; hostSequence: number; hopCount: number; payload?: T; stream?: { status: DeviceStreamRoutabilityV1; handle?: DeviceStreamHandleV1; mediaKind: 'audio' | 'video'; }; } export interface DeviceBusBudgetsV1 { maxGraphLinks: number; maxLinksPerEndpoint: number; maxHopsPerDelivery: number; maxQueuedDeliveriesPerTick: number; maxDeliveriesPerLinkPerTick: number; replayWindow: number; } /** A Device mount can come from an owned World spawn or an authored Build asset. */ export type WorldDeviceMount = Pick & Partial>; /** * App kinds a definition's `screen` components may bind to. * * `remoteImage` is the narrowest kind: ONE external image the host draws, * addressed by a URL held in typed string state rather than by `entry`. It is * not a document, so `network.fetch` is its only legal permission and its * `entry` may be omitted. * * `ownerImage` is ONE image the owned copy's owner uploaded (the Custom * Poster, capability `app.image.owner`). It names no source, origin or * permission: the image is per-copy state on the owned instance and the HOST * resolves it through the placement the viewer is entitled to see. A host * without owned, placed copies (a Device Lab, an SDK-hosted world) does not * grant `app.image.owner`, so `mount()` refuses it rather than showing a * blank face. */ export type DeviceAppTypeV1 = 'localWeb' | 'remoteWeb' | 'youtube' | 'canvas' | 'remoteImage' | 'ownerImage'; /** Permissions an app declaration may request from the host. */ export type DeviceAppPermissionV1 = 'web.content' | 'network.fetch' | 'web.externalNavigation' | 'audio.media'; /** * Engine-neutral app declaration. The SDK types the declared surface — which * powers a package asks for and where its content may come from — and never * how a renderer draws it. */ export interface DeviceAppDefinitionV1 { type: DeviceAppTypeV1; /** Authored source or host renderer id. Optional for `remoteImage`; absent for `ownerImage`. */ entry?: string; allowedOrigins?: string[]; permissions?: DeviceAppPermissionV1[]; } export interface DeviceDefinitionV1 { format: 'helix.device'; formatVersion: 1; id: string; version: string; state: Record; interactions: Array<{ id: string; label: string; verb?: 'use' | 'open' | 'close' | 'toggle' | 'play' | 'sit' | 'custom'; maxDistanceM?: number; /** Viewer-local HUD for one declared web app; never a replicated state action. */ presentation?: { kind: 'webPanel'; app: string; }; /** Universal Action Surface control; omitted means a normal run row. */ control?: { kind: 'number'; stateKey: string; min?: number; max?: number; step?: number; unit?: string; } | { kind: 'choice'; stateKey: string; options: Array<{ value: string; label: string; disabled?: boolean; reason?: string; }>; } | { /** Native text entry rendered by the Universal Action Surface. */ kind: 'text'; /** Typed Device state written after authority accepts the submission. */ stateKey: string; /** The interaction label is the Action Surface label; these tune its input. */ placeholder?: string; maxLength?: number; inputMode?: ActionSurfaceAction['inputMode']; }; }>; compatibility?: { hosts: Array<'home' | 'world'>; requiredCapabilities?: string[]; }; /** Native powers granted by the host; unknown/ungranted powers refuse mount. */ capabilities?: string[]; /** Public endpoints. Home/World composition owns concrete Links. */ ports?: DevicePortV1[]; /** Apps a screen component may bind to, keyed by the name it binds with. */ apps?: Record; [key: string]: unknown; } export interface WorldDevicePresentation { applyState(state: Readonly>): void; dispose(): void | Promise; } export interface WorldDevicePresentationAdapter { /** Renderer powers only; room authority, typed state and time come from the host. */ readonly capabilities: ReadonlySet; mount(input: { spawn: WorldDeviceMount; definition: DeviceDefinitionV1; now: () => number; /** Route a run/number/choice invocation into placement-scoped authority. */ interact: (interactionId: string, args?: Record) => void; }): WorldDevicePresentation | Promise; } export type WorldDeviceDefinitionResolver = (reference: DeviceDefinitionReference) => Promise; export interface WorldDevicePersistenceEntry { value: Record; version: number; } export interface WorldDevicePersistence { load(placementId: string): Promise; save(placementId: string, value: Record, expectedVersion: number): Promise; } /** * World-scoped persistence backed by the existing HELIX dataStore contract. * It deliberately never addresses a Universal Item instance: the same owned * item keeps its per-instance state, while a Build-authored Device uses this * World namespace and lifecycle. */ export declare class WorldDeviceDataStorePersistence implements WorldDevicePersistence { readonly dataStore: { getEntry(key: string): Promise<{ value: T; version: number; } | null>; set(key: string, value: unknown, options?: { expectedVersion?: number; }): Promise; }; constructor(dataStore: { getEntry(key: string): Promise<{ value: T; version: number; } | null>; set(key: string, value: unknown, options?: { expectedVersion?: number; }): Promise; }); key(placementId: string): string; load(placementId: string): Promise; save(placementId: string, value: Record, expectedVersion: number): Promise; } /** Stable placement-scoped module id shared with the platform compositor. */ export declare function deviceRuntimeModuleId(definitionId: string, placementId: string): string; /** * Renderer-neutral World Device host. The world supplies its engine adapter; * HELIX supplies immutable placement identity, authoritative room state/actions, * server time, compatibility checks, and lifecycle. */ export declare class WorldDeviceHost { #private; readonly room: Pick; readonly adapter: WorldDevicePresentationAdapter; readonly resolveDefinition: WorldDeviceDefinitionResolver; constructor(room: Pick, adapter: WorldDevicePresentationAdapter, resolveDefinition: WorldDeviceDefinitionResolver); now: () => number; mount(spawn: WorldDeviceMount): Promise; dispose(): Promise; }