@xstate-devtools/adapter 0.1.3 → 0.1.5

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react.tsx"],"sourcesContent":["// packages/adapter/src/react.tsx\nimport React, {\n createContext, useContext, useRef, useEffect, useMemo, useState, type ReactNode,\n} from 'react'\nimport {\n useMachine as useXStateMachine,\n useActorRef as useXStateActorRef,\n useSelector,\n} from '@xstate/react'\nimport {\n createActor, type AnyStateMachine, type ActorOptions, type SnapshotFrom, type Actor,\n} from 'xstate'\nimport { createAdapter } from './index.js'\n\ntype AdapterContext = ReturnType<typeof createAdapter> | null\n\nconst InspectorContext = createContext<AdapterContext>(null)\n\n/**\n * Provides the inspector adapter to {@link useInspectedMachine} and\n * {@link useRestorableInspectedMachine}. By default it creates and owns a browser\n * adapter. Pass `adapter` to reuse an existing instance (e.g. a module singleton\n * shared with components that call `useMachine(machine, { inspect })` directly) —\n * provided adapters are NOT disposed on unmount, since the caller owns them.\n */\nexport function InspectorProvider({\n children, adapter,\n}: { children: ReactNode; adapter?: AdapterContext }) {\n const ownRef = useRef<ReturnType<typeof createAdapter> | null>(null)\n const useOwn = adapter == null\n if (useOwn && !ownRef.current && typeof window !== 'undefined') {\n ownRef.current = createAdapter()\n }\n const resolved = adapter ?? ownRef.current\n\n useEffect(() => {\n if (!useOwn) return\n return () => {\n ownRef.current?.dispose()\n ownRef.current = null\n }\n }, [useOwn])\n\n return (\n <InspectorContext.Provider value={resolved}>\n {children}\n </InspectorContext.Provider>\n )\n}\n\nexport function useInspectedMachine<T extends AnyStateMachine>(\n machine: T,\n options?: ActorOptions<T>\n) {\n const adapter = useContext(InspectorContext)\n return useXStateMachine(machine, {\n ...options,\n inspect: adapter?.inspect,\n })\n}\n\nexport function useInspectedActorRef<T extends AnyStateMachine>(\n machine: T,\n options?: ActorOptions<T>\n) {\n const adapter = useContext(InspectorContext)\n return useXStateActorRef(machine, {\n ...options,\n inspect: adapter?.inspect,\n })\n}\n\n/**\n * Like {@link useInspectedMachine}, but opts the actor into **live rewind** from the\n * DevTools panel. When the panel sends a restore command, this hook recreates the actor\n * from the supplied XState persisted snapshot.\n *\n * Caveats (live rewind is experimental):\n * - The actor is *recreated*, not rewound in place — its identity (sessionId) changes and\n * subscriptions re-fire from the restored state.\n * - Already-performed side effects (network calls, spawned children, messages sent to\n * parents) are NOT undone. This restores machine state, not the outside world.\n *\n * Unlike `useInspectedMachine` (which delegates to `@xstate/react`'s `useMachine`), this\n * hook owns the actor instance so it can recreate it — `useMachine` creates its actor once\n * and ignores later `snapshot` changes.\n */\nexport function useRestorableInspectedMachine<T extends AnyStateMachine>(\n machine: T,\n options?: ActorOptions<T>\n): [SnapshotFrom<T>, Actor<T>['send'], Actor<T>] {\n const adapter = useContext(InspectorContext)\n const restoreSnapshotRef = useRef<unknown>(options?.snapshot)\n const [generation, setGeneration] = useState(0)\n\n // Recreate the actor whenever `generation` bumps (i.e. on restore).\n const actorRef = useMemo(() => {\n return createActor(machine, {\n ...options,\n snapshot: restoreSnapshotRef.current,\n inspect: adapter?.inspect,\n } as ActorOptions<T>)\n // `machine`/`options` intentionally excluded — restore drives recreation via generation.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [generation, adapter])\n\n useEffect(() => {\n actorRef.start()\n return () => { actorRef.stop() }\n }, [actorRef])\n\n // Register a restore handler keyed by the (current) actor's sessionId.\n useEffect(() => {\n if (!adapter?.registerRestore) return\n return adapter.registerRestore(actorRef.sessionId, (persisted) => {\n restoreSnapshotRef.current = persisted\n setGeneration((g) => g + 1)\n })\n }, [adapter, actorRef])\n\n const snapshot = useSelector(actorRef, (s) => s) as SnapshotFrom<T>\n return [snapshot, actorRef.send, actorRef]\n}\n"],"mappings":";;;;;;AACA;AAAA,EACE;AAAA,EAAe;AAAA,EAAY;AAAA,EAAQ;AAAA,EAAW;AAAA,EAAS;AAAA,OAClD;AACP;AAAA,EACE,cAAc;AAAA,EACd,eAAe;AAAA,EACf;AAAA,OACK;AACP;AAAA,EACE;AAAA,OACK;AAiCH;AA5BJ,IAAM,mBAAmB,cAA8B,IAAI;AASpD,SAAS,kBAAkB;AAAA,EAChC;AAAA,EAAU;AACZ,GAAsD;AACpD,QAAM,SAAS,OAAgD,IAAI;AACnE,QAAM,SAAS,WAAW;AAC1B,MAAI,UAAU,CAAC,OAAO,WAAW,OAAO,WAAW,aAAa;AAC9D,WAAO,UAAU,cAAc;AAAA,EACjC;AACA,QAAM,WAAW,WAAW,OAAO;AAEnC,YAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AACb,WAAO,MAAM;AACX,aAAO,SAAS,QAAQ;AACxB,aAAO,UAAU;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAEX,SACE,oBAAC,iBAAiB,UAAjB,EAA0B,OAAO,UAC/B,UACH;AAEJ;AAEO,SAAS,oBACd,SACA,SACA;AACA,QAAM,UAAU,WAAW,gBAAgB;AAC3C,SAAO,iBAAiB,SAAS;AAAA,IAC/B,GAAG;AAAA,IACH,SAAS,SAAS;AAAA,EACpB,CAAC;AACH;AAEO,SAAS,qBACd,SACA,SACA;AACA,QAAM,UAAU,WAAW,gBAAgB;AAC3C,SAAO,kBAAkB,SAAS;AAAA,IAChC,GAAG;AAAA,IACH,SAAS,SAAS;AAAA,EACpB,CAAC;AACH;AAiBO,SAAS,8BACd,SACA,SAC+C;AAC/C,QAAM,UAAU,WAAW,gBAAgB;AAC3C,QAAM,qBAAqB,OAAgB,SAAS,QAAQ;AAC5D,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,CAAC;AAG9C,QAAM,WAAW,QAAQ,MAAM;AAC7B,WAAO,YAAY,SAAS;AAAA,MAC1B,GAAG;AAAA,MACH,UAAU,mBAAmB;AAAA,MAC7B,SAAS,SAAS;AAAA,IACpB,CAAoB;AAAA,EAGtB,GAAG,CAAC,YAAY,OAAO,CAAC;AAExB,YAAU,MAAM;AACd,aAAS,MAAM;AACf,WAAO,MAAM;AAAE,eAAS,KAAK;AAAA,IAAE;AAAA,EACjC,GAAG,CAAC,QAAQ,CAAC;AAGb,YAAU,MAAM;AACd,QAAI,CAAC,SAAS,gBAAiB;AAC/B,WAAO,QAAQ,gBAAgB,SAAS,WAAW,CAAC,cAAc;AAChE,yBAAmB,UAAU;AAC7B,oBAAc,CAAC,MAAM,IAAI,CAAC;AAAA,IAC5B,CAAC;AAAA,EACH,GAAG,CAAC,SAAS,QAAQ,CAAC;AAEtB,QAAM,WAAW,YAAY,UAAU,CAAC,MAAM,CAAC;AAC/C,SAAO,CAAC,UAAU,SAAS,MAAM,QAAQ;AAC3C;","names":[]}
@@ -0,0 +1,493 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/server.ts
31
+ var server_exports = {};
32
+ __export(server_exports, {
33
+ createServerAdapter: () => createServerAdapter
34
+ });
35
+ module.exports = __toCommonJS(server_exports);
36
+
37
+ // src/serialize.ts
38
+ function serializeGuard(guard) {
39
+ if (!guard) return void 0;
40
+ if (typeof guard === "string") return guard;
41
+ if (typeof guard === "function") return guard.name || "(inline)";
42
+ if (typeof guard === "object" && guard !== null) {
43
+ const g = guard;
44
+ return g.type ?? g.name ?? "(inline)";
45
+ }
46
+ return "(inline)";
47
+ }
48
+ function serializeAction(action) {
49
+ if (typeof action === "string") return action;
50
+ if (typeof action === "function") return action.name || "(anonymous)";
51
+ if (typeof action === "object" && action !== null) {
52
+ const a = action;
53
+ return a.type ?? a.name ?? String(action);
54
+ }
55
+ return String(action);
56
+ }
57
+ function serializeTransitionList(transitions) {
58
+ return transitions.map((t) => ({
59
+ eventType: t.eventType ?? "",
60
+ targets: (t.target ?? []).map((n) => n?.id ?? String(n)).filter(Boolean),
61
+ guard: serializeGuard(t.guard),
62
+ actions: (t.actions ?? []).map(serializeAction).filter(Boolean)
63
+ }));
64
+ }
65
+ function serializeInvokes(node) {
66
+ return node.invoke.map((inv) => ({
67
+ id: inv.id ?? "(unknown)",
68
+ src: typeof inv.src === "string" ? inv.src : inv.src?.id ?? inv.src?.name ?? "(inline)"
69
+ }));
70
+ }
71
+ function serializeNode(node) {
72
+ const allTransitions = [];
73
+ if (node.transitions instanceof Map) {
74
+ for (const [, tList] of node.transitions) {
75
+ allTransitions.push(...serializeTransitionList(tList));
76
+ }
77
+ }
78
+ const always = Array.isArray(node.always) ? serializeTransitionList(node.always) : [];
79
+ return {
80
+ id: node.id,
81
+ key: node.key,
82
+ type: node.type,
83
+ initial: node.initial?.target?.[0]?.key,
84
+ states: Object.fromEntries(
85
+ Object.entries(node.states ?? {}).map(([k, v]) => [k, serializeNode(v)])
86
+ ),
87
+ on: allTransitions,
88
+ always,
89
+ entry: (node.entry ?? []).map(serializeAction).filter(Boolean),
90
+ exit: (node.exit ?? []).map(serializeAction).filter(Boolean),
91
+ invoke: serializeInvokes(node)
92
+ };
93
+ }
94
+ function serializeMachine(machine, sourceLocation) {
95
+ return {
96
+ id: machine.id,
97
+ root: serializeNode(machine.root),
98
+ sourceLocation
99
+ };
100
+ }
101
+
102
+ // src/sanitize.ts
103
+ var MAX_DEPTH = 10;
104
+ var MAX_STRING_LENGTH = 500;
105
+ var MAX_ARRAY_LENGTH = 100;
106
+ var MAX_NODES = 1e4;
107
+ function sanitizeInner(value, ctx) {
108
+ if (ctx.depth > MAX_DEPTH) return "[MaxDepth]";
109
+ if (++ctx.budget.n > MAX_NODES) return "[Truncated]";
110
+ if (value === null || value === void 0) return value;
111
+ if (typeof value === "boolean" || typeof value === "number") return value;
112
+ if (typeof value === "string") {
113
+ return value.length > MAX_STRING_LENGTH ? value.slice(0, MAX_STRING_LENGTH) + "\u2026" : value;
114
+ }
115
+ if (typeof value === "function") return `[Function: ${value.name || "(anonymous)"}]`;
116
+ if (typeof value === "symbol") return `[Symbol: ${value.description ?? ""}]`;
117
+ if (typeof value === "bigint") return `[BigInt: ${value}]`;
118
+ if (value instanceof Error) return { __type: "Error", name: value.name, message: value.message };
119
+ if (value instanceof Date) return { __type: "Date", iso: value.toISOString() };
120
+ if (value instanceof RegExp) return { __type: "RegExp", source: value.source, flags: value.flags };
121
+ if (value instanceof Promise) return "[Promise]";
122
+ if (value instanceof WeakMap || value instanceof WeakSet) return "[WeakCollection]";
123
+ if (ArrayBuffer.isView(value)) return `[TypedArray: ${value.constructor.name}]`;
124
+ if (typeof Node !== "undefined" && value instanceof Node) {
125
+ return `[DOMNode: ${value.tagName ?? value.nodeName}]`;
126
+ }
127
+ if (ctx.seen.has(value)) return "[Circular]";
128
+ ctx.seen.add(value);
129
+ const child = { ...ctx, depth: ctx.depth + 1 };
130
+ if (value instanceof Map) {
131
+ const entries = [];
132
+ for (const [k, v] of value) {
133
+ if (entries.length >= MAX_ARRAY_LENGTH) break;
134
+ entries.push([sanitizeInner(k, child), sanitizeInner(v, child)]);
135
+ }
136
+ return { __type: "Map", entries };
137
+ }
138
+ if (value instanceof Set) {
139
+ const values = [];
140
+ for (const v of value) {
141
+ if (values.length >= MAX_ARRAY_LENGTH) break;
142
+ values.push(sanitizeInner(v, child));
143
+ }
144
+ return { __type: "Set", values };
145
+ }
146
+ if (Array.isArray(value)) {
147
+ const sliced = value.slice(0, MAX_ARRAY_LENGTH);
148
+ const result = sliced.map((v) => sanitizeInner(v, child));
149
+ if (value.length > MAX_ARRAY_LENGTH) result.push(`[\u2026${value.length - MAX_ARRAY_LENGTH} more]`);
150
+ return result;
151
+ }
152
+ if (typeof value === "object") {
153
+ const result = {};
154
+ let count = 0;
155
+ for (const [k, v] of Object.entries(value)) {
156
+ if (count++ >= MAX_ARRAY_LENGTH) {
157
+ result["\u2026"] = "[truncated]";
158
+ break;
159
+ }
160
+ result[k] = sanitizeInner(v, child);
161
+ }
162
+ return result;
163
+ }
164
+ return String(value);
165
+ }
166
+ function sanitize(value) {
167
+ return sanitizeInner(value, { depth: 0, budget: { n: 0 }, seen: /* @__PURE__ */ new WeakSet() });
168
+ }
169
+
170
+ // src/core.ts
171
+ function getSourceLocation() {
172
+ try {
173
+ const lines = new Error().stack?.split("\n") ?? [];
174
+ const callerLine = lines.find(
175
+ (l, i) => i > 3 && !l.includes("xstate") && !l.includes("adapter")
176
+ );
177
+ return callerLine?.trim().replace(/^at\s+/, "");
178
+ } catch {
179
+ return void 0;
180
+ }
181
+ }
182
+ function serializeSnapshot(snapshot) {
183
+ return {
184
+ value: sanitize(snapshot?.value ?? null),
185
+ context: sanitize(snapshot?.context),
186
+ status: snapshot?.status ?? "active",
187
+ error: snapshot?.error ? sanitize(snapshot.error) : void 0
188
+ };
189
+ }
190
+ function safeSerializeSnapshot(actorRef) {
191
+ try {
192
+ return serializeSnapshot(actorRef.getSnapshot());
193
+ } catch {
194
+ return { value: null, context: void 0, status: "active" };
195
+ }
196
+ }
197
+ function safePersistedSnapshot(actorRef) {
198
+ const getPersisted = actorRef.getPersistedSnapshot;
199
+ if (typeof getPersisted !== "function") {
200
+ return { error: "Actor does not support getPersistedSnapshot." };
201
+ }
202
+ try {
203
+ const raw = getPersisted.call(actorRef);
204
+ if (raw === void 0) return { error: "No persisted snapshot available." };
205
+ return { persisted: JSON.parse(JSON.stringify(raw)) };
206
+ } catch (e) {
207
+ return { error: `Snapshot is not JSON-serializable: ${e.message}` };
208
+ }
209
+ }
210
+ var SEQ_KEY = "__xstate_devtools_global_seq__";
211
+ function nextSeq() {
212
+ const g = globalThis;
213
+ const cur = g[SEQ_KEY] ?? 0;
214
+ const next = cur + 1;
215
+ g[SEQ_KEY] = next;
216
+ return next;
217
+ }
218
+ function createInspector(transport, source) {
219
+ const actorRefs = /* @__PURE__ */ new Map();
220
+ const restoreHandlers = /* @__PURE__ */ new Map();
221
+ const prefix = source + ":";
222
+ const tag = (sessionId) => prefix + sessionId;
223
+ const tagOptional = (id) => id ? prefix + id : void 0;
224
+ const stripIfMine = (id) => id.startsWith(prefix) ? id.slice(prefix.length) : null;
225
+ function checkAndNotifyStop(actorRef) {
226
+ let snap;
227
+ try {
228
+ snap = actorRef.getSnapshot();
229
+ } catch {
230
+ return;
231
+ }
232
+ if (snap?.status !== "active") {
233
+ transport.send({ type: "XSTATE_ACTOR_STOPPED", sessionId: tag(actorRef.sessionId) });
234
+ actorRefs.delete(actorRef.sessionId);
235
+ }
236
+ }
237
+ const unsubscribe = transport.subscribe((message) => {
238
+ if (message.type === "XSTATE_DISPATCH") {
239
+ const local = stripIfMine(message.sessionId);
240
+ if (local === null) return;
241
+ const ref = actorRefs.get(local);
242
+ if (ref) {
243
+ try {
244
+ ref.send(message.event);
245
+ } catch (e) {
246
+ console.warn("[xstate-devtools] dispatch error:", e);
247
+ }
248
+ }
249
+ } else if (message.type === "XSTATE_REQUEST_PERSISTED") {
250
+ const local = stripIfMine(message.sessionId);
251
+ if (local === null) return;
252
+ const ref = actorRefs.get(local);
253
+ if (!ref) return;
254
+ const { persisted, error } = safePersistedSnapshot(ref);
255
+ transport.send({
256
+ type: "XSTATE_PERSISTED_SNAPSHOT",
257
+ sessionId: tag(local),
258
+ persisted,
259
+ error,
260
+ timestamp: Date.now()
261
+ });
262
+ } else if (message.type === "XSTATE_RESTORE") {
263
+ const local = stripIfMine(message.sessionId);
264
+ if (local === null) return;
265
+ const handler = restoreHandlers.get(local);
266
+ if (handler) {
267
+ try {
268
+ handler(message.persisted);
269
+ } catch (e) {
270
+ console.warn("[xstate-devtools] restore error:", e);
271
+ }
272
+ }
273
+ }
274
+ });
275
+ const inspect = (inspectionEvent) => {
276
+ try {
277
+ if (inspectionEvent.type === "@xstate.actor") {
278
+ const actorRef = inspectionEvent.actorRef;
279
+ const sessionId = actorRef.sessionId;
280
+ actorRefs.set(sessionId, actorRef);
281
+ const logic = actorRef.logic;
282
+ const machine = logic?.root ? serializeMachine(logic, getSourceLocation()) : null;
283
+ transport.send({
284
+ type: "XSTATE_ACTOR_REGISTERED",
285
+ sessionId: tag(sessionId),
286
+ parentSessionId: tagOptional(actorRef._parent?.sessionId),
287
+ // actorRef.id is the invoke `id` for invoked actors — lets the debugger
288
+ // nest non-machine actors (promise/callback) under their state.
289
+ actorId: actorRef.id,
290
+ machine,
291
+ snapshot: safeSerializeSnapshot(actorRef),
292
+ globalSeq: nextSeq(),
293
+ timestamp: Date.now()
294
+ });
295
+ } else if (inspectionEvent.type === "@xstate.snapshot") {
296
+ transport.send({
297
+ type: "XSTATE_SNAPSHOT",
298
+ sessionId: tag(inspectionEvent.actorRef.sessionId),
299
+ snapshot: serializeSnapshot(inspectionEvent.snapshot),
300
+ timestamp: Date.now(),
301
+ globalSeq: nextSeq()
302
+ });
303
+ checkAndNotifyStop(inspectionEvent.actorRef);
304
+ } else if (inspectionEvent.type === "@xstate.event") {
305
+ transport.send({
306
+ type: "XSTATE_EVENT",
307
+ sessionId: tag(inspectionEvent.actorRef.sessionId),
308
+ event: inspectionEvent.event,
309
+ snapshotAfter: safeSerializeSnapshot(inspectionEvent.actorRef),
310
+ timestamp: Date.now(),
311
+ globalSeq: nextSeq()
312
+ });
313
+ checkAndNotifyStop(inspectionEvent.actorRef);
314
+ }
315
+ } catch (e) {
316
+ console.warn("[xstate-devtools] inspection failed, dropping event:", e.message);
317
+ }
318
+ };
319
+ function registerRestore(sessionId, handler) {
320
+ restoreHandlers.set(sessionId, handler);
321
+ return () => {
322
+ if (restoreHandlers.get(sessionId) === handler) restoreHandlers.delete(sessionId);
323
+ };
324
+ }
325
+ function dispose() {
326
+ unsubscribe();
327
+ actorRefs.clear();
328
+ restoreHandlers.clear();
329
+ }
330
+ return { inspect, dispose, registerRestore };
331
+ }
332
+
333
+ // src/server.ts
334
+ var OPEN_STATE = 1;
335
+ function trackLive(server, message) {
336
+ switch (message.type) {
337
+ case "XSTATE_ACTOR_REGISTERED":
338
+ server.liveActors.set(message.sessionId, { reg: message, snapshot: message.snapshot });
339
+ break;
340
+ case "XSTATE_SNAPSHOT": {
341
+ const live = server.liveActors.get(message.sessionId);
342
+ if (live) {
343
+ live.snapshot = message.snapshot;
344
+ }
345
+ break;
346
+ }
347
+ case "XSTATE_EVENT": {
348
+ const live = server.liveActors.get(message.sessionId);
349
+ if (live) {
350
+ live.snapshot = message.snapshotAfter;
351
+ }
352
+ break;
353
+ }
354
+ case "XSTATE_ACTOR_STOPPED":
355
+ server.liveActors.delete(message.sessionId);
356
+ break;
357
+ }
358
+ }
359
+ function createServerAdapter(options = {}) {
360
+ const port = options.port ?? (Number(process.env.XSTATE_DEVTOOLS_PORT) || 9301);
361
+ const host = options.host ?? "127.0.0.1";
362
+ const bufferSize = options.bufferSize ?? 200;
363
+ const key = `__xstate_devtools_server_${port}__`;
364
+ const cache = globalThis[key];
365
+ let server;
366
+ if (cache) {
367
+ server = cache;
368
+ if (bufferSize > server.bufferSize) server.bufferSize = bufferSize;
369
+ } else {
370
+ const clients = /* @__PURE__ */ new Set();
371
+ const dispatchHandlers = /* @__PURE__ */ new Set();
372
+ const liveActors = /* @__PURE__ */ new Map();
373
+ const recentEvents = [];
374
+ let wss = null;
375
+ let closed = false;
376
+ server = {
377
+ clients,
378
+ dispatchHandlers,
379
+ liveActors,
380
+ recentEvents,
381
+ bufferSize,
382
+ activated: false,
383
+ close: () => {
384
+ closed = true;
385
+ try {
386
+ wss?.close();
387
+ } catch {
388
+ }
389
+ clients.clear();
390
+ dispatchHandlers.clear();
391
+ liveActors.clear();
392
+ recentEvents.length = 0;
393
+ delete globalThis[key];
394
+ }
395
+ };
396
+ void (async () => {
397
+ try {
398
+ const mod = await import("ws");
399
+ const WSServer = mod.WebSocketServer ?? mod.Server;
400
+ if (closed) return;
401
+ wss = new WSServer({ port, host });
402
+ wss.on("connection", (ws) => {
403
+ for (const { reg, snapshot } of server.liveActors.values()) {
404
+ try {
405
+ ws.send(JSON.stringify({ ...reg, __xstateDevtools: true }));
406
+ } catch {
407
+ }
408
+ if (snapshot !== reg.snapshot) {
409
+ try {
410
+ ws.send(JSON.stringify({
411
+ type: "XSTATE_SNAPSHOT",
412
+ sessionId: reg.sessionId,
413
+ snapshot,
414
+ timestamp: reg.timestamp,
415
+ globalSeq: reg.globalSeq,
416
+ __xstateDevtools: true
417
+ }));
418
+ } catch {
419
+ }
420
+ }
421
+ }
422
+ try {
423
+ ws.send(JSON.stringify({
424
+ type: "XSTATE_REPLAY_DONE",
425
+ sessionIds: [...server.liveActors.keys()],
426
+ __xstateDevtools: true
427
+ }));
428
+ } catch {
429
+ }
430
+ if (!server.activated) {
431
+ server.activated = true;
432
+ for (const payload of server.recentEvents) {
433
+ try {
434
+ ws.send(payload);
435
+ } catch {
436
+ }
437
+ }
438
+ server.recentEvents.length = 0;
439
+ }
440
+ server.clients.add(ws);
441
+ ws.on("message", (raw) => {
442
+ try {
443
+ const text = typeof raw === "string" ? raw : raw.toString("utf8");
444
+ const msg = JSON.parse(text);
445
+ for (const cb of server.dispatchHandlers) cb(msg);
446
+ } catch {
447
+ }
448
+ });
449
+ ws.on("close", () => server.clients.delete(ws));
450
+ ws.on("error", () => server.clients.delete(ws));
451
+ });
452
+ wss.on("error", (err) => {
453
+ console.warn("[xstate-devtools] WS server error:", err.message);
454
+ });
455
+ } catch (e) {
456
+ console.warn(
457
+ "[xstate-devtools] could not start server adapter \u2014 install `ws` to enable.",
458
+ e.message
459
+ );
460
+ }
461
+ })();
462
+ globalThis[key] = server;
463
+ }
464
+ const transport = {
465
+ send(message) {
466
+ trackLive(server, message);
467
+ const payload = JSON.stringify({ ...message, __xstateDevtools: true });
468
+ if (!server.activated && (message.type === "XSTATE_EVENT" || message.type === "XSTATE_SNAPSHOT")) {
469
+ server.recentEvents.push(payload);
470
+ if (server.recentEvents.length > server.bufferSize) server.recentEvents.shift();
471
+ }
472
+ for (const ws of server.clients) {
473
+ if (ws.readyState === OPEN_STATE) {
474
+ try {
475
+ ws.send(payload);
476
+ } catch {
477
+ }
478
+ }
479
+ }
480
+ },
481
+ subscribe(handler) {
482
+ server.dispatchHandlers.add(handler);
483
+ return () => server.dispatchHandlers.delete(handler);
484
+ }
485
+ };
486
+ const inspector = createInspector(transport, "srv");
487
+ return { ...inspector, close: server.close };
488
+ }
489
+ // Annotate the CommonJS export names for ESM import in node:
490
+ 0 && (module.exports = {
491
+ createServerAdapter
492
+ });
493
+ //# sourceMappingURL=server.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server.ts","../src/serialize.ts","../src/sanitize.ts","../src/core.ts"],"sourcesContent":["// Server entrypoint — exposes a WebSocket bridge so the DevTools panel\n// can connect to actors running in Node.\nimport type { ExtensionToPageMessage, PageToExtensionMessage } from '@xstate-devtools/protocol'\nimport { createInspector, type Transport } from './core.js'\n\nexport interface ServerAdapterOptions {\n /** Port to listen on. Defaults to env XSTATE_DEVTOOLS_PORT or 9301. */\n port?: number\n /** Host to bind. Defaults to '127.0.0.1'. */\n host?: string\n /** Max events to buffer before the first panel connects. Default 200. */\n bufferSize?: number\n}\n\ninterface ClientLike {\n send(data: string): void\n on(event: string, listener: (...args: unknown[]) => void): void\n readyState: number\n}\n\nconst OPEN_STATE = 1\n\ntype ActorRegistered = Extract<PageToExtensionMessage, { type: 'XSTATE_ACTOR_REGISTERED' }>\n\ninterface LiveActor {\n /** The registration message, kept immutable so its snapshot stays the\n * registration-time one (the panel's time-travel floor). */\n reg: ActorRegistered\n /** Latest snapshot seen for this actor (the registration snapshot until updated). */\n snapshot: ActorRegistered['snapshot']\n}\n\ninterface CachedServer {\n clients: Set<ClientLike>\n dispatchHandlers: Set<(msg: ExtensionToPageMessage) => void>\n /** Currently-live actors (immutable registration + latest snapshot). */\n liveActors: Map<string, LiveActor>\n /** Pre-first-connection event/snapshot backlog, flushed once to the first panel. */\n recentEvents: string[]\n bufferSize: number\n /** Set once the first panel connects and drains the backlog. */\n activated: boolean\n close: () => void\n}\n\n/** Track live-actor state so it can be replayed to every connecting panel. */\nfunction trackLive(server: CachedServer, message: PageToExtensionMessage): void {\n switch (message.type) {\n case 'XSTATE_ACTOR_REGISTERED':\n server.liveActors.set(message.sessionId, { reg: message, snapshot: message.snapshot })\n break\n case 'XSTATE_SNAPSHOT': {\n const live = server.liveActors.get(message.sessionId)\n if (live) { live.snapshot = message.snapshot }\n break\n }\n case 'XSTATE_EVENT': {\n const live = server.liveActors.get(message.sessionId)\n if (live) { live.snapshot = message.snapshotAfter }\n break\n }\n case 'XSTATE_ACTOR_STOPPED':\n server.liveActors.delete(message.sessionId)\n break\n }\n}\n\n/**\n * Start a local WebSocket server that the DevTools panel can connect to.\n * Returns the inspector callback. Multiple panels can connect simultaneously.\n *\n * The WS server, connected clients, dispatch handlers, and the live-actor\n * registry are all stashed on globalThis keyed by port. This makes the function\n * idempotent across HMR re-evaluation: subsequent calls reuse the existing\n * server and only register new inspector hooks.\n *\n * Every connecting panel — including a reconnect after the editor/host restarts\n * — is replayed the current set of live actors (with their latest snapshots),\n * so actors registered at boot stay visible across reconnects (not just for\n * the first panel). The pre-connection event backlog, by contrast, is flushed\n * only to the very first panel; replaying it on every reconnect would re-flood\n * the log with stale events.\n */\nexport function createServerAdapter(options: ServerAdapterOptions = {}) {\n const port = options.port\n ?? (Number(process.env.XSTATE_DEVTOOLS_PORT) || 9301)\n const host = options.host ?? '127.0.0.1'\n const bufferSize = options.bufferSize ?? 200\n\n const key = `__xstate_devtools_server_${port}__`\n const cache = (globalThis as Record<string, unknown>)[key] as CachedServer | undefined\n\n let server: CachedServer\n if (cache) {\n server = cache\n // honour the most recent caller's buffer size if larger\n if (bufferSize > server.bufferSize) server.bufferSize = bufferSize\n } else {\n const clients = new Set<ClientLike>()\n const dispatchHandlers = new Set<(msg: ExtensionToPageMessage) => void>()\n const liveActors = new Map<string, LiveActor>()\n const recentEvents: string[] = []\n let wss: any = null\n let closed = false\n\n server = {\n clients, dispatchHandlers, liveActors, recentEvents, bufferSize,\n activated: false,\n close: () => {\n closed = true\n try { wss?.close() } catch { /* noop */ }\n clients.clear()\n dispatchHandlers.clear()\n liveActors.clear()\n recentEvents.length = 0\n delete (globalThis as Record<string, unknown>)[key]\n },\n }\n\n // Lazily import ws so this module is import-safe in environments that\n // never use the server entrypoint (or where ws isn't installed).\n void (async () => {\n try {\n const mod = await import('ws')\n const WSServer = (mod as any).WebSocketServer ?? (mod as any).Server\n if (closed) return\n wss = new WSServer({ port, host })\n wss.on('connection', (ws: ClientLike) => {\n // Replay current live actors to every connecting panel, so reconnects\n // see the current set. Send the immutable registration (carrying the\n // registration-time snapshot → correct time-travel floor), then a\n // snapshot update if the actor has advanced since.\n for (const { reg, snapshot } of server.liveActors.values()) {\n try { ws.send(JSON.stringify({ ...reg, __xstateDevtools: true })) } catch { /* ignore */ }\n if (snapshot !== reg.snapshot) {\n try {\n ws.send(JSON.stringify({\n type: 'XSTATE_SNAPSHOT', sessionId: reg.sessionId, snapshot,\n timestamp: reg.timestamp, globalSeq: reg.globalSeq, __xstateDevtools: true,\n }))\n } catch { /* ignore */ }\n }\n }\n // Tell the panel the authoritative live set so it can prune actors\n // from a previous session (reconnect/app-restart) without wiping the\n // ones we just replayed.\n try {\n ws.send(JSON.stringify({\n type: 'XSTATE_REPLAY_DONE',\n sessionIds: [...server.liveActors.keys()],\n __xstateDevtools: true,\n }))\n } catch { /* ignore */ }\n // Flush the pre-connection event backlog once, to the first panel only.\n if (!server.activated) {\n server.activated = true\n for (const payload of server.recentEvents) {\n try { ws.send(payload) } catch { /* ignore */ }\n }\n server.recentEvents.length = 0\n }\n server.clients.add(ws)\n ws.on('message', (raw: unknown) => {\n try {\n const text = typeof raw === 'string' ? raw : (raw as Buffer).toString('utf8')\n const msg = JSON.parse(text) as ExtensionToPageMessage\n for (const cb of server.dispatchHandlers) cb(msg)\n } catch {\n // ignore malformed messages\n }\n })\n ws.on('close', () => server.clients.delete(ws))\n ws.on('error', () => server.clients.delete(ws))\n })\n wss.on('error', (err: Error) => {\n console.warn('[xstate-devtools] WS server error:', err.message)\n })\n } catch (e) {\n console.warn(\n '[xstate-devtools] could not start server adapter — install `ws` to enable.',\n (e as Error).message,\n )\n }\n })()\n\n ;(globalThis as Record<string, unknown>)[key] = server\n }\n\n const transport: Transport = {\n send(message: PageToExtensionMessage) {\n // Maintain the live-actor registry so any panel that connects (or\n // reconnects) later can be replayed the current state.\n trackLive(server, message)\n const payload = JSON.stringify({ ...message, __xstateDevtools: true })\n // Buffer events only until the first panel connects; afterwards the log\n // streams live and the backlog is no longer replayed (avoids reconnect\n // re-flooding the log with stale events).\n if (!server.activated && (message.type === 'XSTATE_EVENT' || message.type === 'XSTATE_SNAPSHOT')) {\n server.recentEvents.push(payload)\n if (server.recentEvents.length > server.bufferSize) server.recentEvents.shift()\n }\n for (const ws of server.clients) {\n if (ws.readyState === OPEN_STATE) {\n try { ws.send(payload) } catch { /* ignore */ }\n }\n }\n },\n subscribe(handler) {\n server.dispatchHandlers.add(handler)\n return () => server.dispatchHandlers.delete(handler)\n },\n }\n\n const inspector = createInspector(transport, 'srv')\n return { ...inspector, close: server.close }\n}\n","// packages/adapter/src/serialize.ts\nimport type { AnyStateMachine } from 'xstate'\nimport type { SerializedMachine, SerializedStateNode, SerializedTransition, SerializedInvoke } from '@xstate-devtools/protocol'\n\nfunction serializeGuard(guard: unknown): string | undefined {\n if (!guard) return undefined\n if (typeof guard === 'string') return guard\n if (typeof guard === 'function') return (guard as Function).name || '(inline)'\n if (typeof guard === 'object' && guard !== null) {\n const g = guard as any\n return g.type ?? g.name ?? '(inline)'\n }\n return '(inline)'\n}\n\nfunction serializeAction(action: unknown): string {\n if (typeof action === 'string') return action\n if (typeof action === 'function') return (action as Function).name || '(anonymous)'\n if (typeof action === 'object' && action !== null) {\n const a = action as any\n return a.type ?? a.name ?? String(action)\n }\n return String(action)\n}\n\nfunction serializeTransitionList(transitions: any[]): SerializedTransition[] {\n return transitions.map((t: any) => ({\n eventType: t.eventType ?? '',\n targets: (t.target ?? []).map((n: any) => n?.id ?? String(n)).filter(Boolean),\n guard: serializeGuard(t.guard),\n actions: (t.actions ?? []).map(serializeAction).filter(Boolean),\n }))\n}\n\nfunction serializeInvokes(node: any): SerializedInvoke[] {\n return (node.invoke as any[]).map((inv: any) => ({\n id: inv.id ?? '(unknown)',\n src: typeof inv.src === 'string'\n ? inv.src\n : inv.src?.id ?? inv.src?.name ?? '(inline)',\n }))\n}\n\nfunction serializeNode(node: any): SerializedStateNode {\n const allTransitions: SerializedTransition[] = []\n if (node.transitions instanceof Map) {\n for (const [, tList] of node.transitions) {\n allTransitions.push(...serializeTransitionList(tList))\n }\n }\n\n const always = Array.isArray(node.always) ? serializeTransitionList(node.always) : []\n\n return {\n id: node.id,\n key: node.key,\n type: node.type,\n initial: node.initial?.target?.[0]?.key,\n states: Object.fromEntries(\n Object.entries(node.states ?? {}).map(([k, v]) => [k, serializeNode(v)])\n ),\n on: allTransitions,\n always,\n entry: (node.entry ?? []).map(serializeAction).filter(Boolean),\n exit: (node.exit ?? []).map(serializeAction).filter(Boolean),\n invoke: serializeInvokes(node),\n }\n}\n\nexport function serializeMachine(machine: AnyStateMachine, sourceLocation?: string): SerializedMachine {\n return {\n id: machine.id,\n root: serializeNode(machine.root),\n sourceLocation,\n }\n}\n","// packages/adapter/src/sanitize.ts\n\nconst MAX_DEPTH = 10\nconst MAX_STRING_LENGTH = 500\nconst MAX_ARRAY_LENGTH = 100\n// Hard ceiling on total nodes across the whole tree. The per-level caps above\n// still allow multiplicative blow-up (100^depth) on wide+deep or cross-linked\n// objects, which can produce a string too large for JSON.stringify to handle.\n// This bounds the output regardless of shape.\nconst MAX_NODES = 10000\n\ninterface Ctx {\n depth: number\n /** Shared mutable node counter — the global budget. */\n budget: { n: number }\n /** Objects/arrays seen on the current path + elsewhere, to break cycles and DAGs. */\n seen: WeakSet<object>\n}\n\nfunction sanitizeInner(value: unknown, ctx: Ctx): unknown {\n if (ctx.depth > MAX_DEPTH) return '[MaxDepth]'\n if (++ctx.budget.n > MAX_NODES) return '[Truncated]'\n if (value === null || value === undefined) return value\n if (typeof value === 'boolean' || typeof value === 'number') return value\n if (typeof value === 'string') {\n return value.length > MAX_STRING_LENGTH ? value.slice(0, MAX_STRING_LENGTH) + '…' : value\n }\n if (typeof value === 'function') return `[Function: ${value.name || '(anonymous)'}]`\n if (typeof value === 'symbol') return `[Symbol: ${value.description ?? ''}]`\n if (typeof value === 'bigint') return `[BigInt: ${value}]`\n if (value instanceof Error) return { __type: 'Error', name: value.name, message: value.message }\n if (value instanceof Date) return { __type: 'Date', iso: value.toISOString() }\n if (value instanceof RegExp) return { __type: 'RegExp', source: value.source, flags: value.flags }\n if (value instanceof Promise) return '[Promise]'\n if (value instanceof WeakMap || value instanceof WeakSet) return '[WeakCollection]'\n if (ArrayBuffer.isView(value)) return `[TypedArray: ${(value as any).constructor.name}]`\n // Detect DOM nodes (works in browser and is safe to check)\n if (typeof Node !== 'undefined' && value instanceof Node) {\n return `[DOMNode: ${(value as Element).tagName ?? value.nodeName}]`\n }\n\n // From here on we recurse into containers — guard against shared/circular refs.\n if (ctx.seen.has(value as object)) return '[Circular]'\n ctx.seen.add(value as object)\n const child = { ...ctx, depth: ctx.depth + 1 }\n\n if (value instanceof Map) {\n const entries: [unknown, unknown][] = []\n for (const [k, v] of value as Map<unknown, unknown>) {\n if (entries.length >= MAX_ARRAY_LENGTH) break\n entries.push([sanitizeInner(k, child), sanitizeInner(v, child)])\n }\n return { __type: 'Map', entries }\n }\n if (value instanceof Set) {\n const values: unknown[] = []\n for (const v of value as Set<unknown>) {\n if (values.length >= MAX_ARRAY_LENGTH) break\n values.push(sanitizeInner(v, child))\n }\n return { __type: 'Set', values }\n }\n if (Array.isArray(value)) {\n const sliced = value.slice(0, MAX_ARRAY_LENGTH)\n const result = sliced.map((v) => sanitizeInner(v, child))\n if (value.length > MAX_ARRAY_LENGTH) result.push(`[…${value.length - MAX_ARRAY_LENGTH} more]`)\n return result\n }\n if (typeof value === 'object') {\n const result: Record<string, unknown> = {}\n let count = 0\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (count++ >= MAX_ARRAY_LENGTH) { result['…'] = '[truncated]'; break }\n result[k] = sanitizeInner(v, child)\n }\n return result\n }\n return String(value)\n}\n\nexport function sanitize(value: unknown): unknown {\n return sanitizeInner(value, { depth: 0, budget: { n: 0 }, seen: new WeakSet() })\n}\n","// Transport-agnostic XState inspection core.\n// Browser and server entrypoints supply their own transports.\nimport type { AnyActorRef } from 'xstate'\nimport type {\n ExtensionToPageMessage, PageToExtensionMessage, SerializedSnapshot,\n} from '@xstate-devtools/protocol'\nimport { serializeMachine } from './serialize.js'\nimport { sanitize } from './sanitize.js'\n\nexport type Source = 'web' | 'srv'\n\nexport interface Transport {\n /** Send a protocol message outbound (toward the panel). */\n send: (message: PageToExtensionMessage) => void\n /** Subscribe to inbound dispatch messages from the panel. Returns a teardown. */\n subscribe: (handler: (message: ExtensionToPageMessage) => void) => () => void\n}\n\nfunction getSourceLocation(): string | undefined {\n try {\n const lines = new Error().stack?.split('\\n') ?? []\n const callerLine = lines.find(\n (l, i) => i > 3 && !l.includes('xstate') && !l.includes('adapter')\n )\n return callerLine?.trim().replace(/^at\\s+/, '')\n } catch {\n return undefined\n }\n}\n\nfunction serializeSnapshot(snapshot: any): SerializedSnapshot {\n return {\n value: sanitize(snapshot?.value ?? null) as SerializedSnapshot['value'],\n context: sanitize(snapshot?.context),\n status: snapshot?.status ?? 'active',\n error: snapshot?.error ? sanitize(snapshot.error) : undefined,\n }\n}\n\nfunction safeSerializeSnapshot(actorRef: AnyActorRef): SerializedSnapshot {\n try {\n return serializeSnapshot(actorRef.getSnapshot())\n } catch {\n return { value: null, context: undefined, status: 'active' }\n }\n}\n\n/**\n * Capture XState's persisted snapshot for an actor. Unlike the display snapshot,\n * this is meant to be restorable. We JSON round-trip it to guarantee it survives\n * the transport (and stays serializable); a throw here means the snapshot isn't\n * cleanly persistable, which we report as an error rather than silently dropping.\n */\nfunction safePersistedSnapshot(actorRef: AnyActorRef): { persisted?: unknown; error?: string } {\n const getPersisted = (actorRef as any).getPersistedSnapshot\n if (typeof getPersisted !== 'function') {\n return { error: 'Actor does not support getPersistedSnapshot.' }\n }\n try {\n const raw = getPersisted.call(actorRef)\n if (raw === undefined) return { error: 'No persisted snapshot available.' }\n return { persisted: JSON.parse(JSON.stringify(raw)) }\n } catch (e) {\n return { error: `Snapshot is not JSON-serializable: ${(e as Error).message}` }\n }\n}\n\n// Cached on globalThis so HMR re-evaluating this module doesn't reset the\n// monotonic seq counter mid-session. The panel re-numbers messages on ingest\n// to merge multiple sources, but keeping a stable per-process seq still helps\n// when the panel reconnects to an already-running adapter.\nconst SEQ_KEY = '__xstate_devtools_global_seq__'\nfunction nextSeq(): number {\n const g = globalThis as Record<string, unknown>\n const cur = (g[SEQ_KEY] as number | undefined) ?? 0\n const next = cur + 1\n g[SEQ_KEY] = next\n return next\n}\n\nexport function createInspector(transport: Transport, source: Source) {\n const actorRefs = new Map<string, AnyActorRef>()\n // Owner-registered restore handlers, keyed by local (un-prefixed) sessionId.\n // Populated by useRestorableInspectedMachine; an actor without a handler\n // simply can't be restored (live rewind is opt-in).\n const restoreHandlers = new Map<string, (persisted: unknown) => void>()\n const prefix = source + ':'\n const tag = (sessionId: string) => prefix + sessionId\n const tagOptional = (id: string | undefined) => (id ? prefix + id : undefined)\n const stripIfMine = (id: string): string | null =>\n id.startsWith(prefix) ? id.slice(prefix.length) : null\n\n function checkAndNotifyStop(actorRef: AnyActorRef) {\n let snap: any\n try { snap = actorRef.getSnapshot() } catch { return }\n if (snap?.status !== 'active') {\n transport.send({ type: 'XSTATE_ACTOR_STOPPED', sessionId: tag(actorRef.sessionId) })\n actorRefs.delete(actorRef.sessionId)\n }\n }\n\n const unsubscribe = transport.subscribe((message) => {\n if (message.type === 'XSTATE_DISPATCH') {\n const local = stripIfMine(message.sessionId)\n if (local === null) return // not for this transport source\n const ref = actorRefs.get(local)\n if (ref) {\n try { ref.send(message.event) } catch (e) {\n console.warn('[xstate-devtools] dispatch error:', e)\n }\n }\n } else if (message.type === 'XSTATE_REQUEST_PERSISTED') {\n const local = stripIfMine(message.sessionId)\n if (local === null) return // not for this transport source\n const ref = actorRefs.get(local)\n if (!ref) return\n const { persisted, error } = safePersistedSnapshot(ref)\n transport.send({\n type: 'XSTATE_PERSISTED_SNAPSHOT',\n sessionId: tag(local),\n persisted,\n error,\n timestamp: Date.now(),\n })\n } else if (message.type === 'XSTATE_RESTORE') {\n const local = stripIfMine(message.sessionId)\n if (local === null) return // not for this transport source\n const handler = restoreHandlers.get(local)\n if (handler) {\n try { handler(message.persisted) } catch (e) {\n console.warn('[xstate-devtools] restore error:', e)\n }\n }\n }\n })\n\n const inspect = (inspectionEvent: any) => {\n try {\n if (inspectionEvent.type === '@xstate.actor') {\n const actorRef: AnyActorRef = inspectionEvent.actorRef\n const sessionId: string = actorRef.sessionId\n actorRefs.set(sessionId, actorRef)\n\n // `logic` is internal and not on the public AnyActorRef type.\n const logic = (actorRef as any).logic\n const machine = logic?.root\n ? serializeMachine(logic, getSourceLocation())\n : null\n\n transport.send({\n type: 'XSTATE_ACTOR_REGISTERED',\n sessionId: tag(sessionId),\n parentSessionId: tagOptional((actorRef as any)._parent?.sessionId),\n // actorRef.id is the invoke `id` for invoked actors — lets the debugger\n // nest non-machine actors (promise/callback) under their state.\n actorId: (actorRef as any).id,\n machine,\n snapshot: safeSerializeSnapshot(actorRef),\n globalSeq: nextSeq(),\n timestamp: Date.now(),\n })\n } else if (inspectionEvent.type === '@xstate.snapshot') {\n transport.send({\n type: 'XSTATE_SNAPSHOT',\n sessionId: tag(inspectionEvent.actorRef.sessionId),\n snapshot: serializeSnapshot(inspectionEvent.snapshot),\n timestamp: Date.now(),\n globalSeq: nextSeq(),\n })\n checkAndNotifyStop(inspectionEvent.actorRef)\n } else if (inspectionEvent.type === '@xstate.event') {\n transport.send({\n type: 'XSTATE_EVENT',\n sessionId: tag(inspectionEvent.actorRef.sessionId),\n event: inspectionEvent.event,\n snapshotAfter: safeSerializeSnapshot(inspectionEvent.actorRef),\n timestamp: Date.now(),\n globalSeq: nextSeq(),\n })\n checkAndNotifyStop(inspectionEvent.actorRef)\n }\n } catch (e) {\n // Never let an inspection failure (e.g. an un-serializable snapshot too large\n // for JSON.stringify) propagate back into XState's synchronous inspection\n // callback — that would crash the host actor's start(). Drop the event.\n console.warn('[xstate-devtools] inspection failed, dropping event:', (e as Error).message)\n }\n }\n\n /**\n * Register an owner-side restore handler for an actor. Called by\n * useRestorableInspectedMachine. Returns an unregister function.\n */\n function registerRestore(sessionId: string, handler: (persisted: unknown) => void) {\n restoreHandlers.set(sessionId, handler)\n return () => {\n if (restoreHandlers.get(sessionId) === handler) restoreHandlers.delete(sessionId)\n }\n }\n\n function dispose() {\n unsubscribe()\n actorRefs.clear()\n restoreHandlers.clear()\n }\n\n return { inspect, dispose, registerRestore }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,32 @@
1
+ interface ServerAdapterOptions {
2
+ /** Port to listen on. Defaults to env XSTATE_DEVTOOLS_PORT or 9301. */
3
+ port?: number;
4
+ /** Host to bind. Defaults to '127.0.0.1'. */
5
+ host?: string;
6
+ /** Max events to buffer before the first panel connects. Default 200. */
7
+ bufferSize?: number;
8
+ }
9
+ /**
10
+ * Start a local WebSocket server that the DevTools panel can connect to.
11
+ * Returns the inspector callback. Multiple panels can connect simultaneously.
12
+ *
13
+ * The WS server, connected clients, dispatch handlers, and the live-actor
14
+ * registry are all stashed on globalThis keyed by port. This makes the function
15
+ * idempotent across HMR re-evaluation: subsequent calls reuse the existing
16
+ * server and only register new inspector hooks.
17
+ *
18
+ * Every connecting panel — including a reconnect after the editor/host restarts
19
+ * — is replayed the current set of live actors (with their latest snapshots),
20
+ * so actors registered at boot stay visible across reconnects (not just for
21
+ * the first panel). The pre-connection event backlog, by contrast, is flushed
22
+ * only to the very first panel; replaying it on every reconnect would re-flood
23
+ * the log with stale events.
24
+ */
25
+ declare function createServerAdapter(options?: ServerAdapterOptions): {
26
+ close: () => void;
27
+ inspect: (inspectionEvent: any) => void;
28
+ dispose: () => void;
29
+ registerRestore: (sessionId: string, handler: (persisted: unknown) => void) => () => void;
30
+ };
31
+
32
+ export { type ServerAdapterOptions, createServerAdapter };
@@ -0,0 +1,32 @@
1
+ interface ServerAdapterOptions {
2
+ /** Port to listen on. Defaults to env XSTATE_DEVTOOLS_PORT or 9301. */
3
+ port?: number;
4
+ /** Host to bind. Defaults to '127.0.0.1'. */
5
+ host?: string;
6
+ /** Max events to buffer before the first panel connects. Default 200. */
7
+ bufferSize?: number;
8
+ }
9
+ /**
10
+ * Start a local WebSocket server that the DevTools panel can connect to.
11
+ * Returns the inspector callback. Multiple panels can connect simultaneously.
12
+ *
13
+ * The WS server, connected clients, dispatch handlers, and the live-actor
14
+ * registry are all stashed on globalThis keyed by port. This makes the function
15
+ * idempotent across HMR re-evaluation: subsequent calls reuse the existing
16
+ * server and only register new inspector hooks.
17
+ *
18
+ * Every connecting panel — including a reconnect after the editor/host restarts
19
+ * — is replayed the current set of live actors (with their latest snapshots),
20
+ * so actors registered at boot stay visible across reconnects (not just for
21
+ * the first panel). The pre-connection event backlog, by contrast, is flushed
22
+ * only to the very first panel; replaying it on every reconnect would re-flood
23
+ * the log with stale events.
24
+ */
25
+ declare function createServerAdapter(options?: ServerAdapterOptions): {
26
+ close: () => void;
27
+ inspect: (inspectionEvent: any) => void;
28
+ dispose: () => void;
29
+ registerRestore: (sessionId: string, handler: (persisted: unknown) => void) => () => void;
30
+ };
31
+
32
+ export { type ServerAdapterOptions, createServerAdapter };