/** * Shared tokens and two-sided plugin shape. * Remote state values and ordinary remote method arguments/results must be JSON-serializable. * RpcOptions are recognized by the proxy and sent through the transport control plane. */ export interface Service { readonly id: string; readonly _type?: T; } export function defineService(id: string): Service { return { id }; } const rpcOptionsMarker = Symbol("rpc-options"); export interface RpcOptions { /** Set by the session runtime. Client callers cannot override it. */ readonly clientId?: string; readonly signal?: AbortSignal; readonly [rpcOptionsMarker]: true; } export function rpcOptions(options: { clientId?: string; signal?: AbortSignal } = {}): RpcOptions { return { ...options, [rpcOptionsMarker]: true }; } export function isRpcOptions(value: unknown): value is RpcOptions { return typeof value === "object" && value !== null && rpcOptionsMarker in value; } export interface RemoteState { readonly value: T; subscribe(listener: (value: T) => void): () => void; } export interface MutableRemoteState extends RemoteState { set(value: T): void; } export interface AppPlugin { id: string; session?(context: SessionContext): void | Promise; client?(context: ClientContext): void | Promise; } export function definePlugin( plugin: AppPlugin, ): AppPlugin { return plugin; }