@xstate-devtools/adapter 0.1.6 → 0.1.7

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.
@@ -74,10 +74,11 @@ function serializeMachine(machine, sourceLocation) {
74
74
  var MAX_DEPTH = 10;
75
75
  var MAX_STRING_LENGTH = 500;
76
76
  var MAX_ARRAY_LENGTH = 100;
77
- var MAX_NODES = 1e4;
77
+ var MAX_NODES = 2e4;
78
+ var MIN_KEY_BUDGET = 500;
78
79
  function sanitizeInner(value, ctx) {
79
80
  if (ctx.depth > MAX_DEPTH) return "[MaxDepth]";
80
- if (++ctx.budget.n > MAX_NODES) return "[Truncated]";
81
+ if (++ctx.budget.n > ctx.budget.max) return "[Truncated]";
81
82
  if (value === null || value === void 0) return value;
82
83
  if (typeof value === "boolean" || typeof value === "number") return value;
83
84
  if (typeof value === "string") {
@@ -95,6 +96,15 @@ function sanitizeInner(value, ctx) {
95
96
  if (typeof Node !== "undefined" && value instanceof Node) {
96
97
  return `[DOMNode: ${value.tagName ?? value.nodeName}]`;
97
98
  }
99
+ if (!Array.isArray(value) && !(value instanceof Map) && !(value instanceof Set) && typeof value.toJSON === "function") {
100
+ try {
101
+ const json = value.toJSON();
102
+ if (json !== value) {
103
+ return sanitizeInner(json, ctx);
104
+ }
105
+ } catch {
106
+ }
107
+ }
98
108
  if (ctx.seen.has(value)) return "[Circular]";
99
109
  ctx.seen.add(value);
100
110
  const child = { ...ctx, depth: ctx.depth + 1 };
@@ -121,21 +131,24 @@ function sanitizeInner(value, ctx) {
121
131
  return result;
122
132
  }
123
133
  if (typeof value === "object") {
134
+ const entries = Object.entries(value);
124
135
  const result = {};
136
+ const perKey = ctx.depth === 0 && entries.length > 0 ? Math.max(MIN_KEY_BUDGET, Math.floor(MAX_NODES / Math.min(entries.length, MAX_ARRAY_LENGTH))) : 0;
125
137
  let count = 0;
126
- for (const [k, v] of Object.entries(value)) {
138
+ for (const [k, v] of entries) {
127
139
  if (count++ >= MAX_ARRAY_LENGTH) {
128
140
  result["\u2026"] = "[truncated]";
129
141
  break;
130
142
  }
131
- result[k] = sanitizeInner(v, child);
143
+ const kctx = perKey ? { ...child, budget: { n: 0, max: perKey } } : child;
144
+ result[k] = sanitizeInner(v, kctx);
132
145
  }
133
146
  return result;
134
147
  }
135
148
  return String(value);
136
149
  }
137
150
  function sanitize(value) {
138
- return sanitizeInner(value, { depth: 0, budget: { n: 0 }, seen: /* @__PURE__ */ new WeakSet() });
151
+ return sanitizeInner(value, { depth: 0, budget: { n: 0, max: MAX_NODES }, seen: /* @__PURE__ */ new WeakSet() });
139
152
  }
140
153
 
141
154
  // src/core.ts
@@ -304,4 +317,4 @@ function createInspector(transport, source) {
304
317
  export {
305
318
  createInspector
306
319
  };
307
- //# sourceMappingURL=chunk-M4XORXVP.js.map
320
+ //# sourceMappingURL=chunk-YSEN6P3B.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/serialize.ts","../src/sanitize.ts","../src/core.ts"],"sourcesContent":["// packages/adapter/src/serialize.ts\nimport type { AnyStateMachine } from 'xstate'\nimport type { SerializedMachine, SerializedStateNode, SerializedTransition, SerializedInvoke } from '@xstate-devtools/protocol'\n\n// XState v5 higher-order guards (`and`/`or`/`not`) resolve to a named function\n// carrying `.check` and `.guards` (an array of the inner guards). Flattening\n// them to the bare combinator name drops the actual conditions, so recurse and\n// compose a readable label — e.g. `or(not(hasNegativeBasketValue), and(a, b))` —\n// mirroring the static parser's guard labels.\nfunction serializeGuard(guard: unknown): string | undefined {\n if (!guard) return undefined\n if (typeof guard === 'string') return guard\n if (typeof guard === 'function') {\n const fn = guard as any\n if (Array.isArray(fn.guards) && typeof fn.check === 'function') {\n const parts = (fn.guards as unknown[]).map(g => serializeGuard(g) ?? '(inline)')\n return `${fn.name || '(combinator)'}(${parts.join(', ')})`\n }\n return fn.name || '(inline)'\n }\n if (typeof guard === 'object') {\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// Node budget. The per-level caps above still allow multiplicative blow-up\n// (100^depth) on wide+deep or cross-linked objects, which can produce a string\n// too large for JSON.stringify to handle. This bounds the output regardless of\n// shape. Each TOP-LEVEL key of the root value gets its OWN slice of this budget\n// (see the object branch) so one huge value — a store, an actor ref, a logger —\n// can't spend it all depth-first and leave the rest of the context as \"[Truncated]\".\nconst MAX_NODES = 20000\nconst MIN_KEY_BUDGET = 500\n\ninterface Ctx {\n depth: number\n /** Mutable node counter + ceiling — per top-level key at the root, shared below it. */\n budget: { n: number; max: 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 > ctx.budget.max) 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 // Respect toJSON, like JSON.stringify — critical for XState ActorRefs held in\n // context (e.g. `receiver`/spawned children): their toJSON is a tiny\n // { xstate$$type, id } marker, whereas recursing into the raw ref walks the\n // whole actor system and eats the node budget, truncating everything else.\n // Not for Map/Set/Array (handled below) or plain objects (no toJSON).\n if (!Array.isArray(value) && !(value instanceof Map) && !(value instanceof Set) &&\n typeof (value as { toJSON?: unknown }).toJSON === 'function') {\n try {\n const json = (value as { toJSON: () => unknown }).toJSON()\n if (json !== value) { return sanitizeInner(json, ctx) }\n } catch { /* fall through to normal object handling */ }\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 entries = Object.entries(value as Record<string, unknown>)\n const result: Record<string, unknown> = {}\n // At the root, fair-share the budget across top-level keys so a giant value\n // can't starve the rest into \"[Truncated]\" (depth-first would spend it early).\n const perKey = ctx.depth === 0 && entries.length > 0\n ? Math.max(MIN_KEY_BUDGET, Math.floor(MAX_NODES / Math.min(entries.length, MAX_ARRAY_LENGTH)))\n : 0\n let count = 0\n for (const [k, v] of entries) {\n if (count++ >= MAX_ARRAY_LENGTH) { result['…'] = '[truncated]'; break }\n const kctx = perKey ? { ...child, budget: { n: 0, max: perKey } } : child\n result[k] = sanitizeInner(v, kctx)\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, max: MAX_NODES }, 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":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createInspector
3
- } from "./chunk-M4XORXVP.js";
3
+ } from "./chunk-YSEN6P3B.js";
4
4
 
5
5
  // src/index.ts
6
6
  function createAdapter() {
@@ -31,4 +31,4 @@ function createAdapter() {
31
31
  export {
32
32
  createAdapter
33
33
  };
34
- //# sourceMappingURL=chunk-W5QGSHOC.js.map
34
+ //# sourceMappingURL=chunk-ZYQ7OVET.js.map
package/dist/index.cjs CHANGED
@@ -100,10 +100,11 @@ function serializeMachine(machine, sourceLocation) {
100
100
  var MAX_DEPTH = 10;
101
101
  var MAX_STRING_LENGTH = 500;
102
102
  var MAX_ARRAY_LENGTH = 100;
103
- var MAX_NODES = 1e4;
103
+ var MAX_NODES = 2e4;
104
+ var MIN_KEY_BUDGET = 500;
104
105
  function sanitizeInner(value, ctx) {
105
106
  if (ctx.depth > MAX_DEPTH) return "[MaxDepth]";
106
- if (++ctx.budget.n > MAX_NODES) return "[Truncated]";
107
+ if (++ctx.budget.n > ctx.budget.max) return "[Truncated]";
107
108
  if (value === null || value === void 0) return value;
108
109
  if (typeof value === "boolean" || typeof value === "number") return value;
109
110
  if (typeof value === "string") {
@@ -121,6 +122,15 @@ function sanitizeInner(value, ctx) {
121
122
  if (typeof Node !== "undefined" && value instanceof Node) {
122
123
  return `[DOMNode: ${value.tagName ?? value.nodeName}]`;
123
124
  }
125
+ if (!Array.isArray(value) && !(value instanceof Map) && !(value instanceof Set) && typeof value.toJSON === "function") {
126
+ try {
127
+ const json = value.toJSON();
128
+ if (json !== value) {
129
+ return sanitizeInner(json, ctx);
130
+ }
131
+ } catch {
132
+ }
133
+ }
124
134
  if (ctx.seen.has(value)) return "[Circular]";
125
135
  ctx.seen.add(value);
126
136
  const child = { ...ctx, depth: ctx.depth + 1 };
@@ -147,21 +157,24 @@ function sanitizeInner(value, ctx) {
147
157
  return result;
148
158
  }
149
159
  if (typeof value === "object") {
160
+ const entries = Object.entries(value);
150
161
  const result = {};
162
+ const perKey = ctx.depth === 0 && entries.length > 0 ? Math.max(MIN_KEY_BUDGET, Math.floor(MAX_NODES / Math.min(entries.length, MAX_ARRAY_LENGTH))) : 0;
151
163
  let count = 0;
152
- for (const [k, v] of Object.entries(value)) {
164
+ for (const [k, v] of entries) {
153
165
  if (count++ >= MAX_ARRAY_LENGTH) {
154
166
  result["\u2026"] = "[truncated]";
155
167
  break;
156
168
  }
157
- result[k] = sanitizeInner(v, child);
169
+ const kctx = perKey ? { ...child, budget: { n: 0, max: perKey } } : child;
170
+ result[k] = sanitizeInner(v, kctx);
158
171
  }
159
172
  return result;
160
173
  }
161
174
  return String(value);
162
175
  }
163
176
  function sanitize(value) {
164
- return sanitizeInner(value, { depth: 0, budget: { n: 0 }, seen: /* @__PURE__ */ new WeakSet() });
177
+ return sanitizeInner(value, { depth: 0, budget: { n: 0, max: MAX_NODES }, seen: /* @__PURE__ */ new WeakSet() });
165
178
  }
166
179
 
167
180
  // src/core.ts
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/serialize.ts","../src/sanitize.ts","../src/core.ts"],"sourcesContent":["// Browser entrypoint — uses window.postMessage via the extension's injected bridge.\nimport type { ExtensionToPageMessage, PageToExtensionMessage } from '@xstate-devtools/protocol'\nimport { createInspector, type Transport } from './core.js'\n\ndeclare global {\n interface Window {\n __XSTATE_DEVTOOLS__?: {\n send: (message: unknown) => void\n }\n }\n}\n\nexport function createAdapter() {\n if (typeof window === 'undefined') {\n // Non-browser env (SSR/SSG/server) — return a no-op so importing this module is safe.\n return { inspect: () => {}, dispose: () => {}, registerRestore: () => () => {} }\n }\n\n const transport: Transport = {\n send(message: PageToExtensionMessage) {\n window.__XSTATE_DEVTOOLS__?.send({ ...message, __xstateDevtools: true })\n },\n subscribe(handler) {\n const onMessage = (evt: MessageEvent) => {\n if (evt.source !== window) return\n const data = evt.data\n if (!data?.__xstateDevtools) return\n handler(data as ExtensionToPageMessage)\n }\n window.addEventListener('message', onMessage)\n return () => window.removeEventListener('message', onMessage)\n },\n }\n\n return createInspector(transport, 'web')\n}\n","// packages/adapter/src/serialize.ts\nimport type { AnyStateMachine } from 'xstate'\nimport type { SerializedMachine, SerializedStateNode, SerializedTransition, SerializedInvoke } from '@xstate-devtools/protocol'\n\n// XState v5 higher-order guards (`and`/`or`/`not`) resolve to a named function\n// carrying `.check` and `.guards` (an array of the inner guards). Flattening\n// them to the bare combinator name drops the actual conditions, so recurse and\n// compose a readable label — e.g. `or(not(hasNegativeBasketValue), and(a, b))` —\n// mirroring the static parser's guard labels.\nfunction serializeGuard(guard: unknown): string | undefined {\n if (!guard) return undefined\n if (typeof guard === 'string') return guard\n if (typeof guard === 'function') {\n const fn = guard as any\n if (Array.isArray(fn.guards) && typeof fn.check === 'function') {\n const parts = (fn.guards as unknown[]).map(g => serializeGuard(g) ?? '(inline)')\n return `${fn.name || '(combinator)'}(${parts.join(', ')})`\n }\n return fn.name || '(inline)'\n }\n if (typeof guard === 'object') {\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":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/serialize.ts","../src/sanitize.ts","../src/core.ts"],"sourcesContent":["// Browser entrypoint — uses window.postMessage via the extension's injected bridge.\nimport type { ExtensionToPageMessage, PageToExtensionMessage } from '@xstate-devtools/protocol'\nimport { createInspector, type Transport } from './core.js'\n\ndeclare global {\n interface Window {\n __XSTATE_DEVTOOLS__?: {\n send: (message: unknown) => void\n }\n }\n}\n\nexport function createAdapter() {\n if (typeof window === 'undefined') {\n // Non-browser env (SSR/SSG/server) — return a no-op so importing this module is safe.\n return { inspect: () => {}, dispose: () => {}, registerRestore: () => () => {} }\n }\n\n const transport: Transport = {\n send(message: PageToExtensionMessage) {\n window.__XSTATE_DEVTOOLS__?.send({ ...message, __xstateDevtools: true })\n },\n subscribe(handler) {\n const onMessage = (evt: MessageEvent) => {\n if (evt.source !== window) return\n const data = evt.data\n if (!data?.__xstateDevtools) return\n handler(data as ExtensionToPageMessage)\n }\n window.addEventListener('message', onMessage)\n return () => window.removeEventListener('message', onMessage)\n },\n }\n\n return createInspector(transport, 'web')\n}\n","// packages/adapter/src/serialize.ts\nimport type { AnyStateMachine } from 'xstate'\nimport type { SerializedMachine, SerializedStateNode, SerializedTransition, SerializedInvoke } from '@xstate-devtools/protocol'\n\n// XState v5 higher-order guards (`and`/`or`/`not`) resolve to a named function\n// carrying `.check` and `.guards` (an array of the inner guards). Flattening\n// them to the bare combinator name drops the actual conditions, so recurse and\n// compose a readable label — e.g. `or(not(hasNegativeBasketValue), and(a, b))` —\n// mirroring the static parser's guard labels.\nfunction serializeGuard(guard: unknown): string | undefined {\n if (!guard) return undefined\n if (typeof guard === 'string') return guard\n if (typeof guard === 'function') {\n const fn = guard as any\n if (Array.isArray(fn.guards) && typeof fn.check === 'function') {\n const parts = (fn.guards as unknown[]).map(g => serializeGuard(g) ?? '(inline)')\n return `${fn.name || '(combinator)'}(${parts.join(', ')})`\n }\n return fn.name || '(inline)'\n }\n if (typeof guard === 'object') {\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// Node budget. The per-level caps above still allow multiplicative blow-up\n// (100^depth) on wide+deep or cross-linked objects, which can produce a string\n// too large for JSON.stringify to handle. This bounds the output regardless of\n// shape. Each TOP-LEVEL key of the root value gets its OWN slice of this budget\n// (see the object branch) so one huge value — a store, an actor ref, a logger —\n// can't spend it all depth-first and leave the rest of the context as \"[Truncated]\".\nconst MAX_NODES = 20000\nconst MIN_KEY_BUDGET = 500\n\ninterface Ctx {\n depth: number\n /** Mutable node counter + ceiling — per top-level key at the root, shared below it. */\n budget: { n: number; max: 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 > ctx.budget.max) 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 // Respect toJSON, like JSON.stringify — critical for XState ActorRefs held in\n // context (e.g. `receiver`/spawned children): their toJSON is a tiny\n // { xstate$$type, id } marker, whereas recursing into the raw ref walks the\n // whole actor system and eats the node budget, truncating everything else.\n // Not for Map/Set/Array (handled below) or plain objects (no toJSON).\n if (!Array.isArray(value) && !(value instanceof Map) && !(value instanceof Set) &&\n typeof (value as { toJSON?: unknown }).toJSON === 'function') {\n try {\n const json = (value as { toJSON: () => unknown }).toJSON()\n if (json !== value) { return sanitizeInner(json, ctx) }\n } catch { /* fall through to normal object handling */ }\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 entries = Object.entries(value as Record<string, unknown>)\n const result: Record<string, unknown> = {}\n // At the root, fair-share the budget across top-level keys so a giant value\n // can't starve the rest into \"[Truncated]\" (depth-first would spend it early).\n const perKey = ctx.depth === 0 && entries.length > 0\n ? Math.max(MIN_KEY_BUDGET, Math.floor(MAX_NODES / Math.min(entries.length, MAX_ARRAY_LENGTH)))\n : 0\n let count = 0\n for (const [k, v] of entries) {\n if (count++ >= MAX_ARRAY_LENGTH) { result['…'] = '[truncated]'; break }\n const kctx = perKey ? { ...child, budget: { n: 0, max: perKey } } : child\n result[k] = sanitizeInner(v, kctx)\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, max: MAX_NODES }, 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":[]}
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createAdapter
3
- } from "./chunk-W5QGSHOC.js";
4
- import "./chunk-M4XORXVP.js";
3
+ } from "./chunk-ZYQ7OVET.js";
4
+ import "./chunk-YSEN6P3B.js";
5
5
  export {
6
6
  createAdapter
7
7
  };
package/dist/react.cjs CHANGED
@@ -106,10 +106,11 @@ function serializeMachine(machine, sourceLocation) {
106
106
  var MAX_DEPTH = 10;
107
107
  var MAX_STRING_LENGTH = 500;
108
108
  var MAX_ARRAY_LENGTH = 100;
109
- var MAX_NODES = 1e4;
109
+ var MAX_NODES = 2e4;
110
+ var MIN_KEY_BUDGET = 500;
110
111
  function sanitizeInner(value, ctx) {
111
112
  if (ctx.depth > MAX_DEPTH) return "[MaxDepth]";
112
- if (++ctx.budget.n > MAX_NODES) return "[Truncated]";
113
+ if (++ctx.budget.n > ctx.budget.max) return "[Truncated]";
113
114
  if (value === null || value === void 0) return value;
114
115
  if (typeof value === "boolean" || typeof value === "number") return value;
115
116
  if (typeof value === "string") {
@@ -127,6 +128,15 @@ function sanitizeInner(value, ctx) {
127
128
  if (typeof Node !== "undefined" && value instanceof Node) {
128
129
  return `[DOMNode: ${value.tagName ?? value.nodeName}]`;
129
130
  }
131
+ if (!Array.isArray(value) && !(value instanceof Map) && !(value instanceof Set) && typeof value.toJSON === "function") {
132
+ try {
133
+ const json = value.toJSON();
134
+ if (json !== value) {
135
+ return sanitizeInner(json, ctx);
136
+ }
137
+ } catch {
138
+ }
139
+ }
130
140
  if (ctx.seen.has(value)) return "[Circular]";
131
141
  ctx.seen.add(value);
132
142
  const child = { ...ctx, depth: ctx.depth + 1 };
@@ -153,21 +163,24 @@ function sanitizeInner(value, ctx) {
153
163
  return result;
154
164
  }
155
165
  if (typeof value === "object") {
166
+ const entries = Object.entries(value);
156
167
  const result = {};
168
+ const perKey = ctx.depth === 0 && entries.length > 0 ? Math.max(MIN_KEY_BUDGET, Math.floor(MAX_NODES / Math.min(entries.length, MAX_ARRAY_LENGTH))) : 0;
157
169
  let count = 0;
158
- for (const [k, v] of Object.entries(value)) {
170
+ for (const [k, v] of entries) {
159
171
  if (count++ >= MAX_ARRAY_LENGTH) {
160
172
  result["\u2026"] = "[truncated]";
161
173
  break;
162
174
  }
163
- result[k] = sanitizeInner(v, child);
175
+ const kctx = perKey ? { ...child, budget: { n: 0, max: perKey } } : child;
176
+ result[k] = sanitizeInner(v, kctx);
164
177
  }
165
178
  return result;
166
179
  }
167
180
  return String(value);
168
181
  }
169
182
  function sanitize(value) {
170
- return sanitizeInner(value, { depth: 0, budget: { n: 0 }, seen: /* @__PURE__ */ new WeakSet() });
183
+ return sanitizeInner(value, { depth: 0, budget: { n: 0, max: MAX_NODES }, seen: /* @__PURE__ */ new WeakSet() });
171
184
  }
172
185
 
173
186
  // src/core.ts
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/react.tsx","../src/serialize.ts","../src/sanitize.ts","../src/core.ts","../src/index.ts"],"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","// packages/adapter/src/serialize.ts\nimport type { AnyStateMachine } from 'xstate'\nimport type { SerializedMachine, SerializedStateNode, SerializedTransition, SerializedInvoke } from '@xstate-devtools/protocol'\n\n// XState v5 higher-order guards (`and`/`or`/`not`) resolve to a named function\n// carrying `.check` and `.guards` (an array of the inner guards). Flattening\n// them to the bare combinator name drops the actual conditions, so recurse and\n// compose a readable label — e.g. `or(not(hasNegativeBasketValue), and(a, b))` —\n// mirroring the static parser's guard labels.\nfunction serializeGuard(guard: unknown): string | undefined {\n if (!guard) return undefined\n if (typeof guard === 'string') return guard\n if (typeof guard === 'function') {\n const fn = guard as any\n if (Array.isArray(fn.guards) && typeof fn.check === 'function') {\n const parts = (fn.guards as unknown[]).map(g => serializeGuard(g) ?? '(inline)')\n return `${fn.name || '(combinator)'}(${parts.join(', ')})`\n }\n return fn.name || '(inline)'\n }\n if (typeof guard === 'object') {\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","// Browser entrypoint — uses window.postMessage via the extension's injected bridge.\nimport type { ExtensionToPageMessage, PageToExtensionMessage } from '@xstate-devtools/protocol'\nimport { createInspector, type Transport } from './core.js'\n\ndeclare global {\n interface Window {\n __XSTATE_DEVTOOLS__?: {\n send: (message: unknown) => void\n }\n }\n}\n\nexport function createAdapter() {\n if (typeof window === 'undefined') {\n // Non-browser env (SSR/SSG/server) — return a no-op so importing this module is safe.\n return { inspect: () => {}, dispose: () => {}, registerRestore: () => () => {} }\n }\n\n const transport: Transport = {\n send(message: PageToExtensionMessage) {\n window.__XSTATE_DEVTOOLS__?.send({ ...message, __xstateDevtools: true })\n },\n subscribe(handler) {\n const onMessage = (evt: MessageEvent) => {\n if (evt.source !== window) return\n const data = evt.data\n if (!data?.__xstateDevtools) return\n handler(data as ExtensionToPageMessage)\n }\n window.addEventListener('message', onMessage)\n return () => window.removeEventListener('message', onMessage)\n },\n }\n\n return createInspector(transport, 'web')\n}\n"],"mappings":"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","names":["import_react","useXStateMachine","useXStateActorRef"]}
1
+ {"version":3,"sources":["../src/react.tsx","../src/serialize.ts","../src/sanitize.ts","../src/core.ts","../src/index.ts"],"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","// packages/adapter/src/serialize.ts\nimport type { AnyStateMachine } from 'xstate'\nimport type { SerializedMachine, SerializedStateNode, SerializedTransition, SerializedInvoke } from '@xstate-devtools/protocol'\n\n// XState v5 higher-order guards (`and`/`or`/`not`) resolve to a named function\n// carrying `.check` and `.guards` (an array of the inner guards). Flattening\n// them to the bare combinator name drops the actual conditions, so recurse and\n// compose a readable label — e.g. `or(not(hasNegativeBasketValue), and(a, b))` —\n// mirroring the static parser's guard labels.\nfunction serializeGuard(guard: unknown): string | undefined {\n if (!guard) return undefined\n if (typeof guard === 'string') return guard\n if (typeof guard === 'function') {\n const fn = guard as any\n if (Array.isArray(fn.guards) && typeof fn.check === 'function') {\n const parts = (fn.guards as unknown[]).map(g => serializeGuard(g) ?? '(inline)')\n return `${fn.name || '(combinator)'}(${parts.join(', ')})`\n }\n return fn.name || '(inline)'\n }\n if (typeof guard === 'object') {\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// Node budget. The per-level caps above still allow multiplicative blow-up\n// (100^depth) on wide+deep or cross-linked objects, which can produce a string\n// too large for JSON.stringify to handle. This bounds the output regardless of\n// shape. Each TOP-LEVEL key of the root value gets its OWN slice of this budget\n// (see the object branch) so one huge value — a store, an actor ref, a logger —\n// can't spend it all depth-first and leave the rest of the context as \"[Truncated]\".\nconst MAX_NODES = 20000\nconst MIN_KEY_BUDGET = 500\n\ninterface Ctx {\n depth: number\n /** Mutable node counter + ceiling — per top-level key at the root, shared below it. */\n budget: { n: number; max: 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 > ctx.budget.max) 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 // Respect toJSON, like JSON.stringify — critical for XState ActorRefs held in\n // context (e.g. `receiver`/spawned children): their toJSON is a tiny\n // { xstate$$type, id } marker, whereas recursing into the raw ref walks the\n // whole actor system and eats the node budget, truncating everything else.\n // Not for Map/Set/Array (handled below) or plain objects (no toJSON).\n if (!Array.isArray(value) && !(value instanceof Map) && !(value instanceof Set) &&\n typeof (value as { toJSON?: unknown }).toJSON === 'function') {\n try {\n const json = (value as { toJSON: () => unknown }).toJSON()\n if (json !== value) { return sanitizeInner(json, ctx) }\n } catch { /* fall through to normal object handling */ }\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 entries = Object.entries(value as Record<string, unknown>)\n const result: Record<string, unknown> = {}\n // At the root, fair-share the budget across top-level keys so a giant value\n // can't starve the rest into \"[Truncated]\" (depth-first would spend it early).\n const perKey = ctx.depth === 0 && entries.length > 0\n ? Math.max(MIN_KEY_BUDGET, Math.floor(MAX_NODES / Math.min(entries.length, MAX_ARRAY_LENGTH)))\n : 0\n let count = 0\n for (const [k, v] of entries) {\n if (count++ >= MAX_ARRAY_LENGTH) { result['…'] = '[truncated]'; break }\n const kctx = perKey ? { ...child, budget: { n: 0, max: perKey } } : child\n result[k] = sanitizeInner(v, kctx)\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, max: MAX_NODES }, 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","// Browser entrypoint — uses window.postMessage via the extension's injected bridge.\nimport type { ExtensionToPageMessage, PageToExtensionMessage } from '@xstate-devtools/protocol'\nimport { createInspector, type Transport } from './core.js'\n\ndeclare global {\n interface Window {\n __XSTATE_DEVTOOLS__?: {\n send: (message: unknown) => void\n }\n }\n}\n\nexport function createAdapter() {\n if (typeof window === 'undefined') {\n // Non-browser env (SSR/SSG/server) — return a no-op so importing this module is safe.\n return { inspect: () => {}, dispose: () => {}, registerRestore: () => () => {} }\n }\n\n const transport: Transport = {\n send(message: PageToExtensionMessage) {\n window.__XSTATE_DEVTOOLS__?.send({ ...message, __xstateDevtools: true })\n },\n subscribe(handler) {\n const onMessage = (evt: MessageEvent) => {\n if (evt.source !== window) return\n const data = evt.data\n if (!data?.__xstateDevtools) return\n handler(data as ExtensionToPageMessage)\n }\n window.addEventListener('message', onMessage)\n return () => window.removeEventListener('message', onMessage)\n },\n }\n\n return createInspector(transport, 'web')\n}\n"],"mappings":"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","names":["import_react","useXStateMachine","useXStateActorRef"]}
package/dist/react.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createAdapter
3
- } from "./chunk-W5QGSHOC.js";
4
- import "./chunk-M4XORXVP.js";
3
+ } from "./chunk-ZYQ7OVET.js";
4
+ import "./chunk-YSEN6P3B.js";
5
5
 
6
6
  // src/react.tsx
7
7
  import {
package/dist/server.cjs CHANGED
@@ -110,10 +110,11 @@ function serializeMachine(machine, sourceLocation) {
110
110
  var MAX_DEPTH = 10;
111
111
  var MAX_STRING_LENGTH = 500;
112
112
  var MAX_ARRAY_LENGTH = 100;
113
- var MAX_NODES = 1e4;
113
+ var MAX_NODES = 2e4;
114
+ var MIN_KEY_BUDGET = 500;
114
115
  function sanitizeInner(value, ctx) {
115
116
  if (ctx.depth > MAX_DEPTH) return "[MaxDepth]";
116
- if (++ctx.budget.n > MAX_NODES) return "[Truncated]";
117
+ if (++ctx.budget.n > ctx.budget.max) return "[Truncated]";
117
118
  if (value === null || value === void 0) return value;
118
119
  if (typeof value === "boolean" || typeof value === "number") return value;
119
120
  if (typeof value === "string") {
@@ -131,6 +132,15 @@ function sanitizeInner(value, ctx) {
131
132
  if (typeof Node !== "undefined" && value instanceof Node) {
132
133
  return `[DOMNode: ${value.tagName ?? value.nodeName}]`;
133
134
  }
135
+ if (!Array.isArray(value) && !(value instanceof Map) && !(value instanceof Set) && typeof value.toJSON === "function") {
136
+ try {
137
+ const json = value.toJSON();
138
+ if (json !== value) {
139
+ return sanitizeInner(json, ctx);
140
+ }
141
+ } catch {
142
+ }
143
+ }
134
144
  if (ctx.seen.has(value)) return "[Circular]";
135
145
  ctx.seen.add(value);
136
146
  const child = { ...ctx, depth: ctx.depth + 1 };
@@ -157,21 +167,24 @@ function sanitizeInner(value, ctx) {
157
167
  return result;
158
168
  }
159
169
  if (typeof value === "object") {
170
+ const entries = Object.entries(value);
160
171
  const result = {};
172
+ const perKey = ctx.depth === 0 && entries.length > 0 ? Math.max(MIN_KEY_BUDGET, Math.floor(MAX_NODES / Math.min(entries.length, MAX_ARRAY_LENGTH))) : 0;
161
173
  let count = 0;
162
- for (const [k, v] of Object.entries(value)) {
174
+ for (const [k, v] of entries) {
163
175
  if (count++ >= MAX_ARRAY_LENGTH) {
164
176
  result["\u2026"] = "[truncated]";
165
177
  break;
166
178
  }
167
- result[k] = sanitizeInner(v, child);
179
+ const kctx = perKey ? { ...child, budget: { n: 0, max: perKey } } : child;
180
+ result[k] = sanitizeInner(v, kctx);
168
181
  }
169
182
  return result;
170
183
  }
171
184
  return String(value);
172
185
  }
173
186
  function sanitize(value) {
174
- return sanitizeInner(value, { depth: 0, budget: { n: 0 }, seen: /* @__PURE__ */ new WeakSet() });
187
+ return sanitizeInner(value, { depth: 0, budget: { n: 0, max: MAX_NODES }, seen: /* @__PURE__ */ new WeakSet() });
175
188
  }
176
189
 
177
190
  // src/core.ts
@@ -1 +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\n// XState v5 higher-order guards (`and`/`or`/`not`) resolve to a named function\n// carrying `.check` and `.guards` (an array of the inner guards). Flattening\n// them to the bare combinator name drops the actual conditions, so recurse and\n// compose a readable label — e.g. `or(not(hasNegativeBasketValue), and(a, b))` —\n// mirroring the static parser's guard labels.\nfunction serializeGuard(guard: unknown): string | undefined {\n if (!guard) return undefined\n if (typeof guard === 'string') return guard\n if (typeof guard === 'function') {\n const fn = guard as any\n if (Array.isArray(fn.guards) && typeof fn.check === 'function') {\n const parts = (fn.guards as unknown[]).map(g => serializeGuard(g) ?? '(inline)')\n return `${fn.name || '(combinator)'}(${parts.join(', ')})`\n }\n return fn.name || '(inline)'\n }\n if (typeof guard === 'object') {\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":[]}
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\n// XState v5 higher-order guards (`and`/`or`/`not`) resolve to a named function\n// carrying `.check` and `.guards` (an array of the inner guards). Flattening\n// them to the bare combinator name drops the actual conditions, so recurse and\n// compose a readable label — e.g. `or(not(hasNegativeBasketValue), and(a, b))` —\n// mirroring the static parser's guard labels.\nfunction serializeGuard(guard: unknown): string | undefined {\n if (!guard) return undefined\n if (typeof guard === 'string') return guard\n if (typeof guard === 'function') {\n const fn = guard as any\n if (Array.isArray(fn.guards) && typeof fn.check === 'function') {\n const parts = (fn.guards as unknown[]).map(g => serializeGuard(g) ?? '(inline)')\n return `${fn.name || '(combinator)'}(${parts.join(', ')})`\n }\n return fn.name || '(inline)'\n }\n if (typeof guard === 'object') {\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// Node budget. The per-level caps above still allow multiplicative blow-up\n// (100^depth) on wide+deep or cross-linked objects, which can produce a string\n// too large for JSON.stringify to handle. This bounds the output regardless of\n// shape. Each TOP-LEVEL key of the root value gets its OWN slice of this budget\n// (see the object branch) so one huge value — a store, an actor ref, a logger —\n// can't spend it all depth-first and leave the rest of the context as \"[Truncated]\".\nconst MAX_NODES = 20000\nconst MIN_KEY_BUDGET = 500\n\ninterface Ctx {\n depth: number\n /** Mutable node counter + ceiling — per top-level key at the root, shared below it. */\n budget: { n: number; max: 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 > ctx.budget.max) 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 // Respect toJSON, like JSON.stringify — critical for XState ActorRefs held in\n // context (e.g. `receiver`/spawned children): their toJSON is a tiny\n // { xstate$$type, id } marker, whereas recursing into the raw ref walks the\n // whole actor system and eats the node budget, truncating everything else.\n // Not for Map/Set/Array (handled below) or plain objects (no toJSON).\n if (!Array.isArray(value) && !(value instanceof Map) && !(value instanceof Set) &&\n typeof (value as { toJSON?: unknown }).toJSON === 'function') {\n try {\n const json = (value as { toJSON: () => unknown }).toJSON()\n if (json !== value) { return sanitizeInner(json, ctx) }\n } catch { /* fall through to normal object handling */ }\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 entries = Object.entries(value as Record<string, unknown>)\n const result: Record<string, unknown> = {}\n // At the root, fair-share the budget across top-level keys so a giant value\n // can't starve the rest into \"[Truncated]\" (depth-first would spend it early).\n const perKey = ctx.depth === 0 && entries.length > 0\n ? Math.max(MIN_KEY_BUDGET, Math.floor(MAX_NODES / Math.min(entries.length, MAX_ARRAY_LENGTH)))\n : 0\n let count = 0\n for (const [k, v] of entries) {\n if (count++ >= MAX_ARRAY_LENGTH) { result['…'] = '[truncated]'; break }\n const kctx = perKey ? { ...child, budget: { n: 0, max: perKey } } : child\n result[k] = sanitizeInner(v, kctx)\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, max: MAX_NODES }, 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":[]}
package/dist/server.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createInspector
3
- } from "./chunk-M4XORXVP.js";
3
+ } from "./chunk-YSEN6P3B.js";
4
4
 
5
5
  // src/server.ts
6
6
  var OPEN_STATE = 1;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xstate-devtools/adapter",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "Inspect XState v5 actors from a running app (browser, Node/SSR, or React) and stream them to the XState DevTools / VS Code live debugger.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/serialize.ts","../src/sanitize.ts","../src/core.ts"],"sourcesContent":["// packages/adapter/src/serialize.ts\nimport type { AnyStateMachine } from 'xstate'\nimport type { SerializedMachine, SerializedStateNode, SerializedTransition, SerializedInvoke } from '@xstate-devtools/protocol'\n\n// XState v5 higher-order guards (`and`/`or`/`not`) resolve to a named function\n// carrying `.check` and `.guards` (an array of the inner guards). Flattening\n// them to the bare combinator name drops the actual conditions, so recurse and\n// compose a readable label — e.g. `or(not(hasNegativeBasketValue), and(a, b))` —\n// mirroring the static parser's guard labels.\nfunction serializeGuard(guard: unknown): string | undefined {\n if (!guard) return undefined\n if (typeof guard === 'string') return guard\n if (typeof guard === 'function') {\n const fn = guard as any\n if (Array.isArray(fn.guards) && typeof fn.check === 'function') {\n const parts = (fn.guards as unknown[]).map(g => serializeGuard(g) ?? '(inline)')\n return `${fn.name || '(combinator)'}(${parts.join(', ')})`\n }\n return fn.name || '(inline)'\n }\n if (typeof guard === 'object') {\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":[]}