import { type DesktopConnectionState, type DesktopRfbFactory, type DesktopStreamCapability } from "@opengeni/sdk"; import { type RefObject } from "react"; import { type DesktopWebSocketFactory } from "./use-relay-frame-stream.js"; export type UseDesktopStreamOptions = { /** The desktop cell of the negotiated capabilities (`capabilities.DesktopStream`). */ capability: DesktopStreamCapability | null; /** The mount target. RFB (or the frame canvas) attaches here on connect. */ containerRef: RefObject; /** Read-only by default (v1 ruling H). interactive only when cap.mode allows. */ interactive?: boolean | undefined; scaleViewport?: boolean | undefined; /** Custom RFB factory. Otherwise call enableDesktopViewer() on the desktop subpath. */ rfbFactory?: DesktopRfbFactory | undefined; /** Additional WebSocket protocols for an authenticated placement proxy. */ webSocketProtocols?: string[] | undefined; /** Custom socket factory for the `relay-frames` transport (tests). Defaults to * `new WebSocket(url)`. Mirrors `rfbFactory` for the frame renderer. */ webSocketFactory?: DesktopWebSocketFactory | undefined; }; export type UseDesktopStreamResult = { state: DesktopConnectionState; error: Error | null; /** Manual reconnect (e.g. after a securityfailure once a fresh URL arrives). */ reconnect: () => void; /** Synchronous input on the already-open RFB authority. */ sendKey?: ((keysym: number, code: string, down?: boolean) => boolean) | undefined; }; /** * Drive the noVNC RFB lifecycle from a `DesktopStreamCapability`, using the * SDK's `desktop.ts` reducer + `desktopSocketUrl`. SSR-safe: the RFB import and * the DOM attach happen inside `useEffect`, so a server render is a no-op and * the component shows its placeholder until hydration. * * Read-only is enforced at three layers: `capability.mode` (server) → * `interactive` prop → `RFB.viewOnly`. v1 always resolves to read-only. On a * capability `url` change (a rotation), the old RFB disconnects and a fresh one * connects to the new URL — a brief "desktop blink", acceptable on rollover. * * Transport dispatch: a Modal box negotiates `transport: "vnc-ws"` and drives the * noVNC RFB below. A SELF-HOSTED machine negotiates `transport: "relay-frames"` * (PNG-per-frame over the relay, view-only) — that path is delegated to * `useRelayFrameStream`, which paints a ``. Both hooks are ALWAYS called * (rules of hooks); each is dormant for the other's transport, and we return the * result of whichever owns the surface. The public interface is identical either * way, so `DesktopViewer` is transport-agnostic. */ export declare function useDesktopStream(options: UseDesktopStreamOptions): UseDesktopStreamResult;