/** * Dependency-free adapter to the Stately Inspector (https://stately.ai/inspect), * mirroring the wire protocol of `@statelyai/inspect@0.7.2` * (`createBrowserInspector` + `BrowserAdapter` + `createInspector`). Spec: section 5. * * SSR-safe: nothing here touches `window` at import time, and without a host * window (and without a custom adapter) the inspector is a silent no-op. */ import type { MachineDevtoolsEvent, MachineDevtoolsLike, MachineDevtoolsSnapshot } from "./types.js"; /** `_version` field of every inspection event (protocol version of `@statelyai/inspect`). */ export declare const STATELY_INSPECT_PROTOCOL_VERSION = "0.7.2"; export declare const STATELY_INSPECT_DEFAULT_URL = "https://stately.ai/inspect"; /** Name of the popup opened by `window.open`; the inspector page identifies itself by it. */ export declare const STATELY_INSPECT_WINDOW_NAME = "xstateinspector"; /** Sent by the inspector page once it listens; events are buffered until then. */ export declare const STATELY_CONNECTED_MESSAGE_TYPE = "@statelyai.connected"; export declare const STATELY_DISCONNECTED_MESSAGE_TYPE = "@statelyai.disconnected"; interface StatelyInspectionEventBase { readonly _version: string; readonly sessionId: string; /** `Date.now().toString()` */ readonly createdAt: string; readonly id: null; /** Session id of the root actor; every `Statechart` is its own root. */ readonly rootId: string; } export interface StatelyActorEvent extends StatelyInspectionEventBase { readonly type: "@xstate.actor"; readonly name: string; /** JSON of the machine config (functions as `{ type: fn.name }`). */ readonly definition: string | undefined; readonly parentId: undefined; readonly snapshot: MachineDevtoolsSnapshot; } export interface StatelyEventEvent extends StatelyInspectionEventBase { readonly type: "@xstate.event"; readonly event: MachineDevtoolsEvent; readonly sourceId: undefined; } export interface StatelySnapshotEvent extends StatelyInspectionEventBase { readonly type: "@xstate.snapshot"; readonly snapshot: MachineDevtoolsSnapshot; readonly event: MachineDevtoolsEvent; } export type StatelyInspectionEvent = StatelyActorEvent | StatelyEventEvent | StatelySnapshotEvent; /** * Transport behind `statelyInspector`. The built-in browser transport * (popup/iframe + `postMessage`) is used unless a custom one is passed via * `StatelyInspectorOptions.adapter`; a WebSocket transport is a natural * custom adapter. Events arrive already filtered and serialized, so an * adapter only has to deliver them (and buffer them itself while it is not * ready, if it needs to). */ export interface StatelyInspectorAdapter { /** Called from `inspector.start()`. */ start?(): void; /** Called from `inspector.stop()`. */ stop?(): void; send(event: StatelyInspectionEvent): void; } export interface StatelyInspectorOptions { /** @default "https://stately.ai/inspect" */ url?: string; /** Load the inspector into this iframe instead of `window.open(url, "xstateinspector")`. */ iframe?: HTMLIFrameElement | null; /** Host window (injectable for tests). @default globalThis.window */ window?: Window; /** Open the inspector immediately. @default true */ autoStart?: boolean; /** Events kept while not connected (oldest dropped first). @default 200 */ maxDeferredEvents?: number; /** Drops the events it returns `false` for (checked before `serialize`). @default () => true */ filter?: (event: StatelyInspectionEvent) => boolean; /** * Turns an event into what is put on the wire. The default * (`serializeInspectionEvent`) is a JSON round-trip that renders functions * as `{ type: fn.name }`, HTML elements as their `outerHTML` and circular * references as `"[Circular]"`. A custom serializer that keeps the shape * may compose it: `(e) => strip(serializeInspectionEvent(e))`. */ serialize?: (event: StatelyInspectionEvent) => StatelyInspectionEvent; /** * Custom transport (e.g. a WebSocket). Replaces the browser transport, so * it cannot be combined with `url`, `iframe` or `window`. */ adapter?: StatelyInspectorAdapter; } export interface StatelyInspector extends MachineDevtoolsLike { /** * Browser transport: `"connected"` after the `@statelyai.connected` * handshake. Custom adapter: `"connected"` between `start()` and `stop()` * (the adapter owns its real connection state). */ readonly status: "disconnected" | "connected"; /** Opens the inspector window/iframe and starts listening for the handshake. Idempotent. */ start(): void; /** Posts `@statelyai.disconnected` and stops forwarding. Idempotent. */ stop(): void; /** Forwards one already-built inspection event (filter → serialize → transport). */ send(event: StatelyInspectionEvent): void; } /** * Creates the adapter. Wire it globally with * `DefaultOptions.update({ MACHINE_DEVTOOLS: statelyInspector() })` or per * instance through `StatechartOptions.inspector`. */ export declare function statelyInspector(options?: StatelyInspectorOptions): StatelyInspector; /** * Default `serialize`: a JSON round-trip that survives anything a machine * config or context may hold. Functions become `{ type: fn.name }` (so the * builtins render exactly like XState's in the inspector), HTML elements * their `outerHTML`, circular references `"[Circular]"`, bigints strings. * `undefined` fields are dropped, as with any JSON. */ export declare function serializeInspectionEvent(event: StatelyInspectionEvent): StatelyInspectionEvent; /** `crypto.randomUUID()` when available, otherwise a v4-shaped UUID from `getRandomValues`/`Math.random`. */ export declare function createSessionId(): string; export {};