@statelyai/sdk 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +7 -675
- package/README.md +268 -161
- package/dist/cli.d.mts +24 -5
- package/dist/cli.mjs +79 -18
- package/dist/embed.d.mts +3 -3
- package/dist/embed.mjs +23 -9
- package/dist/graph.mjs +27 -19
- package/dist/{graphToXStateTS-Cfp_fxSH.mjs → graphToXStateTS-BSUj97r0.mjs} +45 -18
- package/dist/index.d.mts +5 -34
- package/dist/index.mjs +2 -2
- package/dist/inspect-WUC2inmJ.d.mts +206 -0
- package/dist/inspect.d.mts +3 -49
- package/dist/inspect.mjs +229 -62
- package/dist/patchTypes.d.mts +225 -0
- package/dist/patchTypes.mjs +1 -0
- package/dist/protocol-B1cNV7QB.d.mts +397 -0
- package/dist/sync.mjs +1 -1
- package/dist/{transport-C1fRAuv-.mjs → transport-lomH7b0v.mjs} +14 -13
- package/package.json +14 -5
- package/dist/protocol-CZVFCSg3.d.mts +0 -225
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { c as ExportFormatMap, d as ProtocolMessage, o as ExportCallOptions, r as EmbedEventMap, s as ExportFormat } from "./protocol-B1cNV7QB.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/transport.d.ts
|
|
4
|
+
interface Transport {
|
|
5
|
+
send(msg: ProtocolMessage): void;
|
|
6
|
+
onMessage(handler: (msg: ProtocolMessage) => void): () => void;
|
|
7
|
+
destroy(): void;
|
|
8
|
+
readonly ready: boolean;
|
|
9
|
+
onReady(handler: () => void): () => void;
|
|
10
|
+
}
|
|
11
|
+
interface PostMessageTransportOptions {
|
|
12
|
+
iframe: HTMLIFrameElement;
|
|
13
|
+
targetOrigin: string;
|
|
14
|
+
/** Filter by source. Defaults to iframe.contentWindow. */
|
|
15
|
+
source?: Window;
|
|
16
|
+
}
|
|
17
|
+
declare function createPostMessageTransport(options: PostMessageTransportOptions): Transport;
|
|
18
|
+
interface WebSocketTransportOptions {
|
|
19
|
+
url: string;
|
|
20
|
+
role: 'client' | 'viz';
|
|
21
|
+
sessionId: string;
|
|
22
|
+
metadata?: {
|
|
23
|
+
name?: string;
|
|
24
|
+
machineId?: string;
|
|
25
|
+
};
|
|
26
|
+
/** Reconnect on disconnect. Default true. */
|
|
27
|
+
reconnect?: boolean;
|
|
28
|
+
/** Max reconnect attempts. Default 10. */
|
|
29
|
+
maxReconnectAttempts?: number;
|
|
30
|
+
}
|
|
31
|
+
declare function createWebSocketTransport(options: WebSocketTransportOptions): Transport;
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/inspect.d.ts
|
|
34
|
+
interface MinimalActorRef {
|
|
35
|
+
id: string;
|
|
36
|
+
sessionId: string;
|
|
37
|
+
systemId?: string;
|
|
38
|
+
_parent?: MinimalActorRef;
|
|
39
|
+
logic?: {
|
|
40
|
+
config?: unknown;
|
|
41
|
+
};
|
|
42
|
+
getSnapshot(): MinimalSnapshot;
|
|
43
|
+
system: {
|
|
44
|
+
inspect: (observer: (event: InspectionEvent) => void) => {
|
|
45
|
+
unsubscribe: () => void;
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
interface MinimalSnapshot {
|
|
50
|
+
value: unknown;
|
|
51
|
+
status: unknown;
|
|
52
|
+
context?: unknown;
|
|
53
|
+
children?: Record<string, MinimalActorRef>;
|
|
54
|
+
}
|
|
55
|
+
type InspectionEvent = {
|
|
56
|
+
type: '@xstate.actor';
|
|
57
|
+
actorRef: MinimalActorRef;
|
|
58
|
+
rootId: string;
|
|
59
|
+
} | {
|
|
60
|
+
type: '@xstate.snapshot';
|
|
61
|
+
actorRef: MinimalActorRef;
|
|
62
|
+
rootId: string;
|
|
63
|
+
snapshot: MinimalSnapshot;
|
|
64
|
+
event: unknown;
|
|
65
|
+
} | {
|
|
66
|
+
type: '@xstate.event';
|
|
67
|
+
actorRef: MinimalActorRef;
|
|
68
|
+
rootId: string;
|
|
69
|
+
sourceRef?: MinimalActorRef;
|
|
70
|
+
event: unknown;
|
|
71
|
+
} | {
|
|
72
|
+
type: '@xstate.microstep';
|
|
73
|
+
actorRef: MinimalActorRef;
|
|
74
|
+
rootId: string;
|
|
75
|
+
snapshot: MinimalSnapshot;
|
|
76
|
+
event: unknown;
|
|
77
|
+
} | {
|
|
78
|
+
type: '@xstate.action';
|
|
79
|
+
actorRef: MinimalActorRef;
|
|
80
|
+
rootId: string;
|
|
81
|
+
action: {
|
|
82
|
+
type: string;
|
|
83
|
+
params: unknown;
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
interface AdoptedActor {
|
|
87
|
+
/** `actor.sessionId` from xstate. Unique across the system. */
|
|
88
|
+
actorId: string;
|
|
89
|
+
/** Parent actor's sessionId, or `null` for the root. */
|
|
90
|
+
parentActorId: string | null;
|
|
91
|
+
/** Root actor's sessionId (equal to `actorId` for the root). */
|
|
92
|
+
rootId: string;
|
|
93
|
+
/** `actor.id` — a human-facing local name. */
|
|
94
|
+
id: string;
|
|
95
|
+
/** `actor.systemId`, if registered under one. */
|
|
96
|
+
systemId: string | undefined;
|
|
97
|
+
/** Latest serialized snapshot streamed for this actor. */
|
|
98
|
+
snapshot: unknown | null;
|
|
99
|
+
/** Machine config sent to the visualizer, or `null` for non-machine actors. */
|
|
100
|
+
machineConfig: unknown;
|
|
101
|
+
}
|
|
102
|
+
interface InspectorEvents {
|
|
103
|
+
register: AdoptedActor;
|
|
104
|
+
snapshot: AdoptedActor;
|
|
105
|
+
stopped: {
|
|
106
|
+
actorId: string;
|
|
107
|
+
};
|
|
108
|
+
error: EmbedEventMap['error'];
|
|
109
|
+
}
|
|
110
|
+
type EventName = keyof InspectorEvents;
|
|
111
|
+
type Handler<E extends EventName> = (data: InspectorEvents[E]) => void;
|
|
112
|
+
interface ManualActorOptions {
|
|
113
|
+
/** Initial snapshot. */
|
|
114
|
+
snapshot?: unknown;
|
|
115
|
+
/** Machine config for the visualizer. Without this, the actor shows as a generic node. */
|
|
116
|
+
machine?: unknown;
|
|
117
|
+
/** Parent actor id (for hierarchy). */
|
|
118
|
+
parent?: string;
|
|
119
|
+
/** System-level id (optional alias). */
|
|
120
|
+
systemId?: string;
|
|
121
|
+
}
|
|
122
|
+
interface CreateInspectorOptions {
|
|
123
|
+
/**
|
|
124
|
+
* Root xstate actor to adopt. The inspector walks its `system`.
|
|
125
|
+
* Omit this for manual-only mode where you call `.actor()` / `.snapshot()`.
|
|
126
|
+
*/
|
|
127
|
+
actor?: any;
|
|
128
|
+
/** WebSocket URL of the devtools server. Default: `'ws://localhost:4242'`. */
|
|
129
|
+
url?: string;
|
|
130
|
+
/** Auto-open browser to visualizer. Default: `true`. */
|
|
131
|
+
autoOpen?: boolean;
|
|
132
|
+
/**
|
|
133
|
+
* Relay session id. Defaults to the root actor's `sessionId` (auto mode)
|
|
134
|
+
* or a random id (manual mode). This is the `?session=<id>` value the viz
|
|
135
|
+
* iframe connects with.
|
|
136
|
+
*/
|
|
137
|
+
sessionId?: string;
|
|
138
|
+
/** Display name for this system in the visualizer. */
|
|
139
|
+
name?: string;
|
|
140
|
+
/**
|
|
141
|
+
* Serialize a snapshot for the wire. Defaults to `{value, status}` —
|
|
142
|
+
* dropping context entirely because xstate contexts routinely contain
|
|
143
|
+
* spawned actor refs which are not JSON-safe.
|
|
144
|
+
*/
|
|
145
|
+
serializeSnapshot?: (snapshot: MinimalSnapshot) => unknown;
|
|
146
|
+
/**
|
|
147
|
+
* Extract the machine config for a given actor. Defaults to reading
|
|
148
|
+
* `actor.logic.config`. Return `null` for non-machine actors.
|
|
149
|
+
*/
|
|
150
|
+
extractMachineConfig?: (actor: any) => unknown;
|
|
151
|
+
/** Selected actor id to focus on first. Defaults to the root actor. */
|
|
152
|
+
selectedActorId?: string;
|
|
153
|
+
/** Panel layout forwarded into the system init message. */
|
|
154
|
+
panels?: {
|
|
155
|
+
leftPanels?: string[];
|
|
156
|
+
rightPanels?: string[];
|
|
157
|
+
activePanels?: string[];
|
|
158
|
+
};
|
|
159
|
+
theme?: 'light' | 'dark';
|
|
160
|
+
readOnly?: boolean;
|
|
161
|
+
depth?: number;
|
|
162
|
+
/**
|
|
163
|
+
* Advanced: inject a pre-built transport (e.g. a channel from a
|
|
164
|
+
* multiplexed connection). When provided, `url`/`name` are ignored and the
|
|
165
|
+
* inspector shares that transport instead of opening its own WebSocket.
|
|
166
|
+
*/
|
|
167
|
+
transport?: Transport;
|
|
168
|
+
}
|
|
169
|
+
interface Inspector {
|
|
170
|
+
/** Snapshot of currently-adopted actors keyed by `actorId`. */
|
|
171
|
+
readonly actors: ReadonlyMap<string, AdoptedActor>;
|
|
172
|
+
/** The relay sessionId this inspector registered under. */
|
|
173
|
+
readonly sessionId: string;
|
|
174
|
+
/** Subscribe to lifecycle / error events. Returns an unsubscribe function. */
|
|
175
|
+
on<E extends EventName>(event: E, handler: Handler<E>): () => void;
|
|
176
|
+
off<E extends EventName>(event: E, handler: Handler<E>): void;
|
|
177
|
+
/** Export the currently-viewed machine in a given format. */
|
|
178
|
+
export<F extends ExportFormat>(format: F, options?: ExportCallOptions<F>): Promise<ExportFormatMap[F]['result']>;
|
|
179
|
+
/**
|
|
180
|
+
* Register a manual actor. In auto mode this adds an actor alongside the
|
|
181
|
+
* xstate-discovered ones; in manual mode it's the only way to add actors.
|
|
182
|
+
*/
|
|
183
|
+
actor(id: string, options?: ManualActorOptions): void;
|
|
184
|
+
/**
|
|
185
|
+
* Push a snapshot update for an actor. The actor is auto-registered if
|
|
186
|
+
* it hasn't been `.actor()`'d yet.
|
|
187
|
+
*/
|
|
188
|
+
snapshot(actorId: string, snapshot: unknown, event?: unknown): void;
|
|
189
|
+
/**
|
|
190
|
+
* Log an event targeting an actor. Sends a snapshot message with the
|
|
191
|
+
* actor's current snapshot + the new event so it appears in the event log.
|
|
192
|
+
*/
|
|
193
|
+
event(actorId: string, event: string | {
|
|
194
|
+
type: string;
|
|
195
|
+
[key: string]: unknown;
|
|
196
|
+
}, options?: {
|
|
197
|
+
source?: string;
|
|
198
|
+
}): void;
|
|
199
|
+
/** Mark an actor as stopped and remove it from the tree. */
|
|
200
|
+
stop(actorId: string): void;
|
|
201
|
+
/** Tear down the WebSocket + xstate subscription. */
|
|
202
|
+
destroy(): void;
|
|
203
|
+
}
|
|
204
|
+
declare function createStatelyInspector(options: CreateInspectorOptions): Inspector;
|
|
205
|
+
//#endregion
|
|
206
|
+
export { ManualActorOptions as a, createPostMessageTransport as c, InspectorEvents as i, createWebSocketTransport as l, CreateInspectorOptions as n, createStatelyInspector as o, Inspector as r, Transport as s, AdoptedActor as t };
|
package/dist/inspect.d.mts
CHANGED
|
@@ -1,49 +1,3 @@
|
|
|
1
|
-
import { a as EmbedMode, c as ExportFormatMap, i as EmbedEventName, n as EmbedEventHandler, o as ExportCallOptions, r as EmbedEventMap, s as ExportFormat } from "./protocol-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
interface CreateInspectorOptions {
|
|
5
|
-
/** WebSocket URL of the devtools server. Default: 'ws://localhost:4242' */
|
|
6
|
-
url?: string;
|
|
7
|
-
/** Auto-open browser to visualizer. Default: true */
|
|
8
|
-
autoOpen?: boolean;
|
|
9
|
-
/** Unique session ID. Auto-generated if not provided. */
|
|
10
|
-
sessionId?: string;
|
|
11
|
-
/** Display name for this connection in the visualizer. */
|
|
12
|
-
name?: string;
|
|
13
|
-
}
|
|
14
|
-
interface Inspector {
|
|
15
|
-
/** Send a machine for inspection (starts visualization). */
|
|
16
|
-
inspect(options: InspectOptions): void;
|
|
17
|
-
/** Update the machine currently being inspected. */
|
|
18
|
-
update(machine: unknown, format?: string): void;
|
|
19
|
-
/** Change the visualization mode. */
|
|
20
|
-
setMode(mode: EmbedMode): void;
|
|
21
|
-
/** Export the current machine in a given format. Returns a promise. */
|
|
22
|
-
export<F extends ExportFormat>(format: F, options?: ExportCallOptions<F>): Promise<ExportFormatMap[F]['result']>;
|
|
23
|
-
/** Subscribe to events from the visualizer. */
|
|
24
|
-
on<K extends EmbedEventName>(event: K, handler: EmbedEventHandler<K>): void;
|
|
25
|
-
/** Unsubscribe from an event. */
|
|
26
|
-
off<K extends EmbedEventName>(event: K, handler: EmbedEventHandler<K>): void;
|
|
27
|
-
/** Send a state snapshot for real-time inspection. */
|
|
28
|
-
sendSnapshot(snapshot: unknown, event?: unknown): void;
|
|
29
|
-
/** Clean up the connection. */
|
|
30
|
-
destroy(): void;
|
|
31
|
-
/** Session ID for this connection. */
|
|
32
|
-
readonly sessionId: string;
|
|
33
|
-
}
|
|
34
|
-
interface InspectOptions {
|
|
35
|
-
machine: unknown;
|
|
36
|
-
format?: string;
|
|
37
|
-
mode?: EmbedMode;
|
|
38
|
-
theme?: 'light' | 'dark';
|
|
39
|
-
readOnly?: boolean;
|
|
40
|
-
depth?: number;
|
|
41
|
-
panels?: {
|
|
42
|
-
leftPanels?: string[];
|
|
43
|
-
rightPanels?: string[];
|
|
44
|
-
activePanels?: string[];
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
declare function createStatelyInspector(options?: CreateInspectorOptions): Inspector;
|
|
48
|
-
//#endregion
|
|
49
|
-
export { CreateInspectorOptions, type EmbedEventHandler, type EmbedEventMap, type EmbedEventName, type EmbedMode, type ExportCallOptions, type ExportFormat, type ExportFormatMap, InspectOptions, Inspector, createStatelyInspector };
|
|
1
|
+
import { a as EmbedMode, c as ExportFormatMap, i as EmbedEventName, n as EmbedEventHandler, o as ExportCallOptions, r as EmbedEventMap, s as ExportFormat } from "./protocol-B1cNV7QB.mjs";
|
|
2
|
+
import { a as ManualActorOptions, i as InspectorEvents, n as CreateInspectorOptions, o as createStatelyInspector, r as Inspector, s as Transport, t as AdoptedActor } from "./inspect-WUC2inmJ.mjs";
|
|
3
|
+
export { AdoptedActor, CreateInspectorOptions, EmbedEventHandler, EmbedEventMap, EmbedEventName, EmbedMode, ExportCallOptions, ExportFormat, ExportFormatMap, Inspector, InspectorEvents, ManualActorOptions, Transport, createStatelyInspector };
|
package/dist/inspect.mjs
CHANGED
|
@@ -1,20 +1,33 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as createPendingExportManager, n as createWebSocketTransport, r as createEventRegistry } from "./transport-lomH7b0v.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/inspect.ts
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
const defaultSerializeSnapshot = (snapshot) => ({
|
|
5
|
+
value: snapshot?.value,
|
|
6
|
+
status: snapshot?.status
|
|
7
|
+
});
|
|
8
|
+
const defaultExtractMachineConfig = (actor) => actor?.logic?.config ?? null;
|
|
9
|
+
let nextManualId = 0;
|
|
10
|
+
function generateSessionId() {
|
|
11
|
+
return `manual-${Date.now()}-${nextManualId++}`;
|
|
6
12
|
}
|
|
7
13
|
function createStatelyInspector(options) {
|
|
8
|
-
const { url = "ws://localhost:4242", autoOpen = true,
|
|
14
|
+
const { url = "ws://localhost:4242", autoOpen = true, actor: rootActor, name, serializeSnapshot = defaultSerializeSnapshot, extractMachineConfig = defaultExtractMachineConfig, selectedActorId, panels, theme, readOnly, depth, transport: injectedTransport } = options;
|
|
15
|
+
const root = rootActor ? rootActor : null;
|
|
16
|
+
const rootActorId = root?.sessionId ?? generateSessionId();
|
|
17
|
+
const sessionId = options.sessionId ?? rootActorId;
|
|
18
|
+
const displayName = name ?? (root ? `system:${root.id}` : "system:manual");
|
|
9
19
|
let destroyed = false;
|
|
20
|
+
let initSent = false;
|
|
10
21
|
const pendingMessages = [];
|
|
11
22
|
const events = createEventRegistry();
|
|
12
|
-
const
|
|
23
|
+
const localListeners = {};
|
|
24
|
+
const transport = injectedTransport ?? createWebSocketTransport({
|
|
13
25
|
url,
|
|
14
26
|
role: "client",
|
|
15
27
|
sessionId,
|
|
16
|
-
|
|
28
|
+
metadata: { name: displayName }
|
|
17
29
|
});
|
|
30
|
+
const ownsTransport = !injectedTransport;
|
|
18
31
|
const exportManager = createPendingExportManager((message) => send(message));
|
|
19
32
|
function send(msg) {
|
|
20
33
|
if (!transport.ready) {
|
|
@@ -23,17 +36,11 @@ function createStatelyInspector(options) {
|
|
|
23
36
|
}
|
|
24
37
|
transport.send(msg);
|
|
25
38
|
}
|
|
26
|
-
function flush() {
|
|
27
|
-
while (pendingMessages.length > 0) {
|
|
28
|
-
const msg = pendingMessages.shift();
|
|
29
|
-
transport.send(msg);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
39
|
transport.onReady(() => {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
transport.send({
|
|
40
|
+
pendingMessages.length = 0;
|
|
41
|
+
initSent = false;
|
|
42
|
+
sendInit();
|
|
43
|
+
if (autoOpen) transport.send({
|
|
37
44
|
type: "@statelyai.requestOpen",
|
|
38
45
|
sessionId
|
|
39
46
|
});
|
|
@@ -41,79 +48,239 @@ function createStatelyInspector(options) {
|
|
|
41
48
|
transport.onMessage((msg) => {
|
|
42
49
|
if (destroyed) return;
|
|
43
50
|
switch (msg.type) {
|
|
44
|
-
case "@statelyai.ready":
|
|
45
|
-
events.emit("ready", { version: msg.version });
|
|
46
|
-
break;
|
|
47
|
-
case "@statelyai.loaded":
|
|
48
|
-
events.emit("loaded", { graph: msg.graph });
|
|
49
|
-
break;
|
|
50
|
-
case "@statelyai.change":
|
|
51
|
-
events.emit("change", {
|
|
52
|
-
graph: msg.graph,
|
|
53
|
-
machineConfig: msg.machineConfig
|
|
54
|
-
});
|
|
55
|
-
break;
|
|
56
|
-
case "@statelyai.save":
|
|
57
|
-
events.emit("save", {
|
|
58
|
-
graph: msg.graph,
|
|
59
|
-
machineConfig: msg.machineConfig
|
|
60
|
-
});
|
|
61
|
-
break;
|
|
62
51
|
case "@statelyai.retrieved":
|
|
63
52
|
exportManager.resolve(msg.requestId, msg.data);
|
|
64
53
|
break;
|
|
65
54
|
case "@statelyai.error":
|
|
66
55
|
exportManager.reject(new Error(msg.message), msg.requestId);
|
|
56
|
+
emitLocal("error", {
|
|
57
|
+
code: msg.code,
|
|
58
|
+
message: msg.message
|
|
59
|
+
});
|
|
67
60
|
events.emit("error", {
|
|
68
61
|
code: msg.code,
|
|
69
62
|
message: msg.message
|
|
70
63
|
});
|
|
71
64
|
break;
|
|
65
|
+
default: break;
|
|
72
66
|
}
|
|
73
67
|
});
|
|
68
|
+
function emitLocal(event, data) {
|
|
69
|
+
const set = localListeners[event];
|
|
70
|
+
if (!set) return;
|
|
71
|
+
for (const handler of set) handler(data);
|
|
72
|
+
}
|
|
73
|
+
const actors = /* @__PURE__ */ new Map();
|
|
74
|
+
/** Tracks which actors we've already emitted local 'register' events for. */
|
|
75
|
+
const locallyRegistered = /* @__PURE__ */ new Set();
|
|
76
|
+
/**
|
|
77
|
+
* Maps target actorId → source actorId for the most recent `@xstate.event`.
|
|
78
|
+
* Read + cleared by `handleSnapshot` so the source info propagates into the
|
|
79
|
+
* `actorSnapshot` message. xstate emits `@xstate.event` immediately before
|
|
80
|
+
* `@xstate.snapshot` for the same actor.
|
|
81
|
+
*/
|
|
82
|
+
const pendingEventSource = /* @__PURE__ */ new Map();
|
|
83
|
+
function emitRegisterOnce(entry) {
|
|
84
|
+
if (locallyRegistered.has(entry.actorId)) return;
|
|
85
|
+
locallyRegistered.add(entry.actorId);
|
|
86
|
+
emitLocal("register", entry);
|
|
87
|
+
}
|
|
88
|
+
function snapshotValue(actorRef) {
|
|
89
|
+
try {
|
|
90
|
+
return serializeSnapshot(actorRef.getSnapshot());
|
|
91
|
+
} catch {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function toEntry(actorRef) {
|
|
96
|
+
return {
|
|
97
|
+
actorId: actorRef.sessionId,
|
|
98
|
+
parentActorId: actorRef._parent?.sessionId ?? null,
|
|
99
|
+
rootId: rootActorId,
|
|
100
|
+
id: actorRef.id,
|
|
101
|
+
systemId: actorRef.systemId,
|
|
102
|
+
snapshot: snapshotValue(actorRef),
|
|
103
|
+
machineConfig: extractMachineConfig(actorRef)
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function toSystemEntry(entry) {
|
|
107
|
+
return {
|
|
108
|
+
actorId: entry.actorId,
|
|
109
|
+
parentActorId: entry.parentActorId,
|
|
110
|
+
id: entry.id,
|
|
111
|
+
machine: entry.machineConfig,
|
|
112
|
+
snapshot: entry.snapshot ?? void 0
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Walk the actor tree and populate the local `actors` map. Idempotent —
|
|
117
|
+
* existing entries stay in place but have their snapshot refreshed.
|
|
118
|
+
*/
|
|
119
|
+
function backfillActorTree(actorRef) {
|
|
120
|
+
const existing = actors.get(actorRef.sessionId);
|
|
121
|
+
const entry = existing ?? toEntry(actorRef);
|
|
122
|
+
if (existing) existing.snapshot = snapshotValue(actorRef);
|
|
123
|
+
else actors.set(entry.actorId, entry);
|
|
124
|
+
emitRegisterOnce(entry);
|
|
125
|
+
const children = actorRef.getSnapshot()?.children ?? {};
|
|
126
|
+
for (const child of Object.values(children)) if (child) backfillActorTree(child);
|
|
127
|
+
}
|
|
128
|
+
function sendInit() {
|
|
129
|
+
if (root) backfillActorTree(root);
|
|
130
|
+
send({
|
|
131
|
+
type: "@statelyai.system.init",
|
|
132
|
+
mode: "inspecting",
|
|
133
|
+
actors: Array.from(actors.values()).map(toSystemEntry),
|
|
134
|
+
selectedActorId: selectedActorId ?? rootActorId,
|
|
135
|
+
...theme && { theme },
|
|
136
|
+
...readOnly !== void 0 && { readOnly },
|
|
137
|
+
...depth !== void 0 && { depth },
|
|
138
|
+
...panels?.leftPanels && { leftPanels: panels.leftPanels },
|
|
139
|
+
...panels?.rightPanels && { rightPanels: panels.rightPanels },
|
|
140
|
+
...panels?.activePanels && { activePanels: panels.activePanels }
|
|
141
|
+
});
|
|
142
|
+
initSent = true;
|
|
143
|
+
}
|
|
144
|
+
function handleActor(actorRef) {
|
|
145
|
+
if (actors.has(actorRef.sessionId)) return;
|
|
146
|
+
const entry = toEntry(actorRef);
|
|
147
|
+
actors.set(entry.actorId, entry);
|
|
148
|
+
if (!initSent) return;
|
|
149
|
+
send({
|
|
150
|
+
type: "@statelyai.system.actorRegistered",
|
|
151
|
+
actorId: entry.actorId,
|
|
152
|
+
parentActorId: entry.parentActorId,
|
|
153
|
+
id: entry.id,
|
|
154
|
+
machine: entry.machineConfig,
|
|
155
|
+
snapshot: entry.snapshot ?? void 0
|
|
156
|
+
});
|
|
157
|
+
emitRegisterOnce(entry);
|
|
158
|
+
}
|
|
159
|
+
function handleSnapshot(actorRef, snapshot, triggeringEvent) {
|
|
160
|
+
if (!actors.has(actorRef.sessionId)) handleActor(actorRef);
|
|
161
|
+
const entry = actors.get(actorRef.sessionId);
|
|
162
|
+
if (!entry) return;
|
|
163
|
+
const serialized = serializeSnapshot(snapshot);
|
|
164
|
+
entry.snapshot = serialized;
|
|
165
|
+
const sourceActorId = pendingEventSource.get(entry.actorId) ?? null;
|
|
166
|
+
pendingEventSource.delete(entry.actorId);
|
|
167
|
+
if (initSent) send({
|
|
168
|
+
type: "@statelyai.system.actorSnapshot",
|
|
169
|
+
actorId: entry.actorId,
|
|
170
|
+
snapshot: serialized,
|
|
171
|
+
event: triggeringEvent ?? null,
|
|
172
|
+
...sourceActorId ? { sourceActorId } : {}
|
|
173
|
+
});
|
|
174
|
+
emitLocal("snapshot", entry);
|
|
175
|
+
const status = snapshot?.status;
|
|
176
|
+
if (status === "done" || status === "stopped" || status === "error") {
|
|
177
|
+
actors.delete(entry.actorId);
|
|
178
|
+
pendingEventSource.delete(entry.actorId);
|
|
179
|
+
if (initSent) send({
|
|
180
|
+
type: "@statelyai.system.actorStopped",
|
|
181
|
+
actorId: entry.actorId
|
|
182
|
+
});
|
|
183
|
+
emitLocal("stopped", { actorId: entry.actorId });
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (root) backfillActorTree(root);
|
|
187
|
+
const subscription = root ? root.system.inspect((inspectionEvent) => {
|
|
188
|
+
if (destroyed) return;
|
|
189
|
+
switch (inspectionEvent.type) {
|
|
190
|
+
case "@xstate.actor":
|
|
191
|
+
handleActor(inspectionEvent.actorRef);
|
|
192
|
+
break;
|
|
193
|
+
case "@xstate.event":
|
|
194
|
+
if (inspectionEvent.sourceRef) pendingEventSource.set(inspectionEvent.actorRef.sessionId, inspectionEvent.sourceRef.sessionId);
|
|
195
|
+
break;
|
|
196
|
+
case "@xstate.snapshot":
|
|
197
|
+
handleSnapshot(inspectionEvent.actorRef, inspectionEvent.snapshot, inspectionEvent.event);
|
|
198
|
+
break;
|
|
199
|
+
default: break;
|
|
200
|
+
}
|
|
201
|
+
}) : null;
|
|
202
|
+
function manualRegister(id, opts) {
|
|
203
|
+
if (actors.has(id)) return;
|
|
204
|
+
const entry = {
|
|
205
|
+
actorId: id,
|
|
206
|
+
parentActorId: opts?.parent ?? null,
|
|
207
|
+
rootId: rootActorId,
|
|
208
|
+
id,
|
|
209
|
+
systemId: opts?.systemId,
|
|
210
|
+
snapshot: opts?.snapshot ?? null,
|
|
211
|
+
machineConfig: opts?.machine ?? null
|
|
212
|
+
};
|
|
213
|
+
actors.set(id, entry);
|
|
214
|
+
if (initSent) send({
|
|
215
|
+
type: "@statelyai.system.actorRegistered",
|
|
216
|
+
actorId: id,
|
|
217
|
+
parentActorId: entry.parentActorId,
|
|
218
|
+
id,
|
|
219
|
+
machine: entry.machineConfig,
|
|
220
|
+
snapshot: entry.snapshot ?? void 0
|
|
221
|
+
});
|
|
222
|
+
emitRegisterOnce(entry);
|
|
223
|
+
}
|
|
224
|
+
function manualSnapshot(actorId, snapshot, event, sourceActorId) {
|
|
225
|
+
if (!actors.has(actorId)) manualRegister(actorId);
|
|
226
|
+
const entry = actors.get(actorId);
|
|
227
|
+
entry.snapshot = snapshot;
|
|
228
|
+
if (initSent) send({
|
|
229
|
+
type: "@statelyai.system.actorSnapshot",
|
|
230
|
+
actorId,
|
|
231
|
+
snapshot,
|
|
232
|
+
event: event ?? null,
|
|
233
|
+
...sourceActorId ? { sourceActorId } : {}
|
|
234
|
+
});
|
|
235
|
+
emitLocal("snapshot", entry);
|
|
236
|
+
}
|
|
237
|
+
function manualEvent(actorId, event, eventOpts) {
|
|
238
|
+
const eventObj = typeof event === "string" ? { type: event } : { ...event };
|
|
239
|
+
manualSnapshot(actorId, actors.get(actorId)?.snapshot ?? null, eventObj, eventOpts?.source ?? null);
|
|
240
|
+
}
|
|
241
|
+
function manualStop(actorId) {
|
|
242
|
+
if (!actors.has(actorId)) return;
|
|
243
|
+
actors.delete(actorId);
|
|
244
|
+
if (initSent) send({
|
|
245
|
+
type: "@statelyai.system.actorStopped",
|
|
246
|
+
actorId
|
|
247
|
+
});
|
|
248
|
+
emitLocal("stopped", { actorId });
|
|
249
|
+
}
|
|
74
250
|
return {
|
|
251
|
+
actors,
|
|
75
252
|
get sessionId() {
|
|
76
253
|
return sessionId;
|
|
77
254
|
},
|
|
78
|
-
inspect(opts) {
|
|
79
|
-
send(toInitMessage(opts));
|
|
80
|
-
},
|
|
81
|
-
update(machine, format) {
|
|
82
|
-
send({
|
|
83
|
-
type: "@statelyai.update",
|
|
84
|
-
machine,
|
|
85
|
-
format
|
|
86
|
-
});
|
|
87
|
-
},
|
|
88
|
-
setMode(mode) {
|
|
89
|
-
send({
|
|
90
|
-
type: "@statelyai.setMode",
|
|
91
|
-
mode
|
|
92
|
-
});
|
|
93
|
-
},
|
|
94
|
-
export(format, callOptions) {
|
|
95
|
-
return exportManager.start(format, callOptions, "Inspector is destroyed", () => destroyed);
|
|
96
|
-
},
|
|
97
255
|
on(event, handler) {
|
|
98
|
-
|
|
256
|
+
if (!localListeners[event]) localListeners[event] = /* @__PURE__ */ new Set();
|
|
257
|
+
localListeners[event].add(handler);
|
|
258
|
+
return () => {
|
|
259
|
+
localListeners[event].delete(handler);
|
|
260
|
+
};
|
|
99
261
|
},
|
|
100
262
|
off(event, handler) {
|
|
101
|
-
|
|
263
|
+
localListeners[event]?.delete(handler);
|
|
102
264
|
},
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
type: "@statelyai.inspectSnapshot",
|
|
106
|
-
snapshot,
|
|
107
|
-
event: event ?? null
|
|
108
|
-
});
|
|
265
|
+
export(format, callOptions) {
|
|
266
|
+
return exportManager.start(format, callOptions, "Inspector is destroyed", () => destroyed);
|
|
109
267
|
},
|
|
268
|
+
actor: manualRegister,
|
|
269
|
+
snapshot: manualSnapshot,
|
|
270
|
+
event: manualEvent,
|
|
271
|
+
stop: manualStop,
|
|
110
272
|
destroy() {
|
|
111
273
|
if (destroyed) return;
|
|
112
274
|
destroyed = true;
|
|
113
|
-
|
|
275
|
+
try {
|
|
276
|
+
subscription?.unsubscribe();
|
|
277
|
+
} catch {}
|
|
278
|
+
if (ownsTransport) transport.destroy();
|
|
114
279
|
exportManager.clear("Inspector destroyed");
|
|
115
280
|
events.clear();
|
|
281
|
+
actors.clear();
|
|
116
282
|
pendingMessages.length = 0;
|
|
283
|
+
for (const set of Object.values(localListeners)) set?.clear();
|
|
117
284
|
}
|
|
118
285
|
};
|
|
119
286
|
}
|