@xstate-devtools/adapter 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -1
- package/dist/chunk-QLRTDBT5.js +300 -0
- package/dist/chunk-QLRTDBT5.js.map +1 -0
- package/dist/chunk-SUDAY5H3.js +34 -0
- package/dist/chunk-SUDAY5H3.js.map +1 -0
- package/dist/index.cjs +168 -569
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -10
- package/dist/index.d.ts +2 -10
- package/dist/index.js +2 -2
- package/dist/react.cjs +223 -588
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +31 -5
- package/dist/react.d.ts +31 -5
- package/dist/react.js +61 -13
- package/dist/react.js.map +1 -1
- package/dist/server.cjs +236 -679
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +10 -7
- package/dist/server.d.ts +10 -7
- package/dist/server.js +75 -146
- package/dist/server.js.map +1 -1
- package/package.json +12 -3
- package/dist/chunk-3GM2SFT4.js +0 -680
- package/dist/chunk-3GM2SFT4.js.map +0 -1
- package/dist/chunk-MHHRMHW5.js +0 -62
- package/dist/chunk-MHHRMHW5.js.map +0 -1
package/dist/react.cjs
CHANGED
|
@@ -22,114 +22,15 @@ var react_exports = {};
|
|
|
22
22
|
__export(react_exports, {
|
|
23
23
|
InspectorProvider: () => InspectorProvider,
|
|
24
24
|
useInspectedActorRef: () => useInspectedActorRef,
|
|
25
|
-
useInspectedMachine: () => useInspectedMachine
|
|
25
|
+
useInspectedMachine: () => useInspectedMachine,
|
|
26
|
+
useRestorableInspectedMachine: () => useRestorableInspectedMachine
|
|
26
27
|
});
|
|
27
28
|
module.exports = __toCommonJS(react_exports);
|
|
28
|
-
var import_react = require("
|
|
29
|
-
var import_react2 = require("react");
|
|
30
|
-
|
|
31
|
-
// src/logging.ts
|
|
32
|
-
function hasProcessEnv() {
|
|
33
|
-
return typeof process !== "undefined" && typeof process.env !== "undefined";
|
|
34
|
-
}
|
|
35
|
-
function isLoggingEnabled() {
|
|
36
|
-
if (globalThis.__XSTATE_DEVTOOLS_LOGGING__ === true) return true;
|
|
37
|
-
if (!hasProcessEnv()) return false;
|
|
38
|
-
const value = process.env.XSTATE_DEVTOOLS_LOGGING;
|
|
39
|
-
return value === "1" || value === "true";
|
|
40
|
-
}
|
|
41
|
-
function log(level, scope, message, details) {
|
|
42
|
-
if (!isLoggingEnabled()) return;
|
|
43
|
-
if (details === void 0) {
|
|
44
|
-
console[level](`[xstate-devtools:${scope}] ${message}`);
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
console[level](`[xstate-devtools:${scope}] ${message}`, details);
|
|
48
|
-
}
|
|
49
|
-
function debugLog(scope, message, details) {
|
|
50
|
-
log("debug", scope, message, details);
|
|
51
|
-
}
|
|
52
|
-
function infoLog(scope, message, details) {
|
|
53
|
-
log("info", scope, message, details);
|
|
54
|
-
}
|
|
55
|
-
function warnLog(scope, message, details) {
|
|
56
|
-
log("warn", scope, message, details);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// src/sanitize.ts
|
|
60
|
-
var MAX_DEPTH = 10;
|
|
61
|
-
var MAX_STRING_LENGTH = 500;
|
|
62
|
-
var MAX_ARRAY_LENGTH = 100;
|
|
63
|
-
function sanitizeValue(value, depth, seen) {
|
|
64
|
-
if (depth > MAX_DEPTH) return "[MaxDepth]";
|
|
65
|
-
if (value === null || value === void 0) return value;
|
|
66
|
-
if (typeof value === "boolean" || typeof value === "number") return value;
|
|
67
|
-
if (typeof value === "string") {
|
|
68
|
-
return value.length > MAX_STRING_LENGTH ? `${value.slice(0, MAX_STRING_LENGTH)}\u2026` : value;
|
|
69
|
-
}
|
|
70
|
-
if (typeof value === "function") return `[Function: ${value.name || "(anonymous)"}]`;
|
|
71
|
-
if (typeof value === "symbol") return `[Symbol: ${value.description ?? ""}]`;
|
|
72
|
-
if (typeof value === "bigint") return `[BigInt: ${value}]`;
|
|
73
|
-
if (value instanceof Error) return { __type: "Error", name: value.name, message: value.message };
|
|
74
|
-
if (value instanceof Date) return { __type: "Date", iso: value.toISOString() };
|
|
75
|
-
if (value instanceof RegExp) return { __type: "RegExp", source: value.source, flags: value.flags };
|
|
76
|
-
if (typeof value === "object") {
|
|
77
|
-
if (seen.has(value)) return "[Circular]";
|
|
78
|
-
seen.add(value);
|
|
79
|
-
}
|
|
80
|
-
if (value instanceof Map) {
|
|
81
|
-
const entries = [];
|
|
82
|
-
for (const [k, v] of value) {
|
|
83
|
-
if (entries.length >= MAX_ARRAY_LENGTH) break;
|
|
84
|
-
entries.push([sanitizeValue(k, depth + 1, seen), sanitizeValue(v, depth + 1, seen)]);
|
|
85
|
-
}
|
|
86
|
-
return { __type: "Map", entries };
|
|
87
|
-
}
|
|
88
|
-
if (value instanceof Set) {
|
|
89
|
-
const values = [];
|
|
90
|
-
for (const v of value) {
|
|
91
|
-
if (values.length >= MAX_ARRAY_LENGTH) break;
|
|
92
|
-
values.push(sanitizeValue(v, depth + 1, seen));
|
|
93
|
-
}
|
|
94
|
-
return { __type: "Set", values };
|
|
95
|
-
}
|
|
96
|
-
if (value instanceof Promise) return "[Promise]";
|
|
97
|
-
if (value instanceof WeakMap || value instanceof WeakSet) return "[WeakCollection]";
|
|
98
|
-
if (ArrayBuffer.isView(value)) return `[TypedArray: ${value.constructor.name}]`;
|
|
99
|
-
if (typeof Node !== "undefined" && value instanceof Node) {
|
|
100
|
-
return `[DOMNode: ${value.tagName ?? value.nodeName}]`;
|
|
101
|
-
}
|
|
102
|
-
if (Array.isArray(value)) {
|
|
103
|
-
const sliced = value.slice(0, MAX_ARRAY_LENGTH);
|
|
104
|
-
const result = sliced.map((v) => sanitizeValue(v, depth + 1, seen));
|
|
105
|
-
if (value.length > MAX_ARRAY_LENGTH) result.push(`[\u2026${value.length - MAX_ARRAY_LENGTH} more]`);
|
|
106
|
-
return result;
|
|
107
|
-
}
|
|
108
|
-
if (typeof value === "object") {
|
|
109
|
-
const result = {};
|
|
110
|
-
let count = 0;
|
|
111
|
-
for (const [k, v] of Object.entries(value)) {
|
|
112
|
-
if (count++ >= MAX_ARRAY_LENGTH) {
|
|
113
|
-
result["\u2026"] = "[truncated]";
|
|
114
|
-
break;
|
|
115
|
-
}
|
|
116
|
-
result[k] = sanitizeValue(v, depth + 1, seen);
|
|
117
|
-
}
|
|
118
|
-
return result;
|
|
119
|
-
}
|
|
120
|
-
return String(value);
|
|
121
|
-
}
|
|
122
|
-
function sanitize(value, depth = 0) {
|
|
123
|
-
return sanitizeValue(value, depth, /* @__PURE__ */ new WeakSet());
|
|
124
|
-
}
|
|
29
|
+
var import_react = require("react");
|
|
30
|
+
var import_react2 = require("@xstate/react");
|
|
31
|
+
var import_xstate = require("xstate");
|
|
125
32
|
|
|
126
33
|
// src/serialize.ts
|
|
127
|
-
var MAX_SERIALIZED_NODES = 500;
|
|
128
|
-
var MAX_TRANSITIONS_PER_NODE = 100;
|
|
129
|
-
var MAX_CHILD_STATES = 100;
|
|
130
|
-
var MAX_ACTIONS_PER_TRANSITION = 20;
|
|
131
|
-
var MAX_ENTRY_EXIT_ACTIONS = 20;
|
|
132
|
-
var MAX_INVOKES_PER_NODE = 20;
|
|
133
34
|
function serializeGuard(guard) {
|
|
134
35
|
if (!guard) return void 0;
|
|
135
36
|
if (typeof guard === "string") return guard;
|
|
@@ -150,214 +51,133 @@ function serializeAction(action) {
|
|
|
150
51
|
return String(action);
|
|
151
52
|
}
|
|
152
53
|
function serializeTransitionList(transitions) {
|
|
153
|
-
return transitions.
|
|
54
|
+
return transitions.map((t) => ({
|
|
154
55
|
eventType: t.eventType ?? "",
|
|
155
56
|
targets: (t.target ?? []).map((n) => n?.id ?? String(n)).filter(Boolean),
|
|
156
57
|
guard: serializeGuard(t.guard),
|
|
157
|
-
actions: (t.actions ?? []).
|
|
58
|
+
actions: (t.actions ?? []).map(serializeAction).filter(Boolean)
|
|
158
59
|
}));
|
|
159
60
|
}
|
|
160
61
|
function serializeInvokes(node) {
|
|
161
|
-
return node.invoke.
|
|
62
|
+
return node.invoke.map((inv) => ({
|
|
162
63
|
id: inv.id ?? "(unknown)",
|
|
163
64
|
src: typeof inv.src === "string" ? inv.src : inv.src?.id ?? inv.src?.name ?? "(inline)"
|
|
164
65
|
}));
|
|
165
66
|
}
|
|
166
|
-
function serializeNode(node
|
|
167
|
-
if (!node || typeof node !== "object") {
|
|
168
|
-
return {
|
|
169
|
-
id: "(unknown)",
|
|
170
|
-
key: "(unknown)",
|
|
171
|
-
type: "atomic",
|
|
172
|
-
states: {},
|
|
173
|
-
on: [],
|
|
174
|
-
always: [],
|
|
175
|
-
entry: [],
|
|
176
|
-
exit: [],
|
|
177
|
-
invoke: []
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
if (state.count >= MAX_SERIALIZED_NODES) {
|
|
181
|
-
return {
|
|
182
|
-
id: node.id ?? "(truncated)",
|
|
183
|
-
key: node.key ?? "(truncated)",
|
|
184
|
-
type: node.type ?? "atomic",
|
|
185
|
-
states: {},
|
|
186
|
-
on: [],
|
|
187
|
-
always: [],
|
|
188
|
-
entry: [],
|
|
189
|
-
exit: [],
|
|
190
|
-
invoke: []
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
if (state.seen.has(node)) {
|
|
194
|
-
return {
|
|
195
|
-
id: node.id ?? "(circular)",
|
|
196
|
-
key: node.key ?? "(circular)",
|
|
197
|
-
type: node.type ?? "atomic",
|
|
198
|
-
states: {},
|
|
199
|
-
on: [],
|
|
200
|
-
always: [],
|
|
201
|
-
entry: [],
|
|
202
|
-
exit: [],
|
|
203
|
-
invoke: []
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
state.seen.add(node);
|
|
207
|
-
state.count += 1;
|
|
67
|
+
function serializeNode(node) {
|
|
208
68
|
const allTransitions = [];
|
|
209
69
|
if (node.transitions instanceof Map) {
|
|
210
70
|
for (const [, tList] of node.transitions) {
|
|
211
|
-
if (allTransitions.length >= MAX_TRANSITIONS_PER_NODE) break;
|
|
212
71
|
allTransitions.push(...serializeTransitionList(tList));
|
|
213
|
-
if (allTransitions.length >= MAX_TRANSITIONS_PER_NODE) {
|
|
214
|
-
allTransitions.length = MAX_TRANSITIONS_PER_NODE;
|
|
215
|
-
break;
|
|
216
|
-
}
|
|
217
72
|
}
|
|
218
73
|
}
|
|
219
74
|
const always = Array.isArray(node.always) ? serializeTransitionList(node.always) : [];
|
|
220
|
-
const childEntries = Object.entries(node.states ?? {}).slice(0, MAX_CHILD_STATES);
|
|
221
75
|
return {
|
|
222
76
|
id: node.id,
|
|
223
77
|
key: node.key,
|
|
224
78
|
type: node.type,
|
|
225
79
|
initial: node.initial?.target?.[0]?.key,
|
|
226
|
-
states: Object.fromEntries(
|
|
80
|
+
states: Object.fromEntries(
|
|
81
|
+
Object.entries(node.states ?? {}).map(([k, v]) => [k, serializeNode(v)])
|
|
82
|
+
),
|
|
227
83
|
on: allTransitions,
|
|
228
84
|
always,
|
|
229
|
-
entry: (node.entry ?? []).
|
|
230
|
-
exit: (node.exit ?? []).
|
|
231
|
-
invoke: serializeInvokes(node)
|
|
232
|
-
sourceLocation: node.config?.__xstateDevtoolsSource ?? void 0,
|
|
233
|
-
description: node.config?.description ?? void 0
|
|
85
|
+
entry: (node.entry ?? []).map(serializeAction).filter(Boolean),
|
|
86
|
+
exit: (node.exit ?? []).map(serializeAction).filter(Boolean),
|
|
87
|
+
invoke: serializeInvokes(node)
|
|
234
88
|
};
|
|
235
89
|
}
|
|
236
90
|
function serializeMachine(machine, sourceLocation) {
|
|
237
91
|
return {
|
|
238
92
|
id: machine.id,
|
|
239
|
-
root: serializeNode(machine.root
|
|
93
|
+
root: serializeNode(machine.root),
|
|
240
94
|
sourceLocation
|
|
241
95
|
};
|
|
242
96
|
}
|
|
243
97
|
|
|
244
|
-
// src/
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
98
|
+
// src/sanitize.ts
|
|
99
|
+
var MAX_DEPTH = 10;
|
|
100
|
+
var MAX_STRING_LENGTH = 500;
|
|
101
|
+
var MAX_ARRAY_LENGTH = 100;
|
|
102
|
+
var MAX_NODES = 1e4;
|
|
103
|
+
function sanitizeInner(value, ctx) {
|
|
104
|
+
if (ctx.depth > MAX_DEPTH) return "[MaxDepth]";
|
|
105
|
+
if (++ctx.budget.n > MAX_NODES) return "[Truncated]";
|
|
106
|
+
if (value === null || value === void 0) return value;
|
|
107
|
+
if (typeof value === "boolean" || typeof value === "number") return value;
|
|
108
|
+
if (typeof value === "string") {
|
|
109
|
+
return value.length > MAX_STRING_LENGTH ? value.slice(0, MAX_STRING_LENGTH) + "\u2026" : value;
|
|
251
110
|
}
|
|
252
|
-
if ("
|
|
253
|
-
if ("
|
|
254
|
-
if (
|
|
255
|
-
|
|
111
|
+
if (typeof value === "function") return `[Function: ${value.name || "(anonymous)"}]`;
|
|
112
|
+
if (typeof value === "symbol") return `[Symbol: ${value.description ?? ""}]`;
|
|
113
|
+
if (typeof value === "bigint") return `[BigInt: ${value}]`;
|
|
114
|
+
if (value instanceof Error) return { __type: "Error", name: value.name, message: value.message };
|
|
115
|
+
if (value instanceof Date) return { __type: "Date", iso: value.toISOString() };
|
|
116
|
+
if (value instanceof RegExp) return { __type: "RegExp", source: value.source, flags: value.flags };
|
|
117
|
+
if (value instanceof Promise) return "[Promise]";
|
|
118
|
+
if (value instanceof WeakMap || value instanceof WeakSet) return "[WeakCollection]";
|
|
119
|
+
if (ArrayBuffer.isView(value)) return `[TypedArray: ${value.constructor.name}]`;
|
|
120
|
+
if (typeof Node !== "undefined" && value instanceof Node) {
|
|
121
|
+
return `[DOMNode: ${value.tagName ?? value.nodeName}]`;
|
|
256
122
|
}
|
|
257
|
-
return
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
}
|
|
266
|
-
function debugLog2(source, message, details) {
|
|
267
|
-
debugLog(`${source}:adapter`, message, details);
|
|
268
|
-
}
|
|
269
|
-
function infoLog2(source, message, details) {
|
|
270
|
-
infoLog(`${source}:adapter`, message, details);
|
|
271
|
-
}
|
|
272
|
-
function warnLog2(source, message, details) {
|
|
273
|
-
warnLog(`${source}:adapter`, message, details);
|
|
274
|
-
}
|
|
275
|
-
function isLibraryStackFrame(line) {
|
|
276
|
-
const normalized = line.replace(/\\/g, "/").toLowerCase();
|
|
277
|
-
return normalized.includes("/node_modules/xstate/") || normalized.includes("/node_modules/@xstate/") || normalized.includes("/@xstate-devtools/adapter/") || normalized.includes("/packages/adapter/");
|
|
278
|
-
}
|
|
279
|
-
function normalizeStackFrame(line) {
|
|
280
|
-
return line.trim().replace(/^at\s+/, "");
|
|
281
|
-
}
|
|
282
|
-
function extractStackFrameLocation(frame) {
|
|
283
|
-
return frame.match(/\((.*)\)$/)?.[1] ?? frame;
|
|
284
|
-
}
|
|
285
|
-
function isAnonymousOrEvalLocation(location) {
|
|
286
|
-
const normalized = location.trim().toLowerCase().replace(/^[./\\]+/, "");
|
|
287
|
-
return normalized === "<anonymous>" || normalized === "anonymous" || normalized === "(anonymous)" || normalized === "eval" || normalized === "<eval>" || normalized === "[native code]";
|
|
288
|
-
}
|
|
289
|
-
function hasFilesystemBackedPath(location) {
|
|
290
|
-
const trimmed = location.trim();
|
|
291
|
-
if (!trimmed) return false;
|
|
292
|
-
const match = trimmed.match(/^(.*?)(?::\d+)?(?::\d+)?$/);
|
|
293
|
-
const rawPath = (match?.[1] ?? trimmed).trim();
|
|
294
|
-
if (!rawPath || isAnonymousOrEvalLocation(rawPath)) return false;
|
|
295
|
-
if (/^[a-zA-Z]:[\\/]/.test(rawPath)) return true;
|
|
296
|
-
if (rawPath.startsWith("/") || rawPath.startsWith("./") || rawPath.startsWith("../")) return true;
|
|
297
|
-
if (/^[a-zA-Z][a-zA-Z\d+.-]*:\/\//.test(rawPath)) {
|
|
298
|
-
try {
|
|
299
|
-
const url = new URL(rawPath);
|
|
300
|
-
if (url.protocol === "file:") return true;
|
|
301
|
-
return url.pathname.startsWith("/@fs/");
|
|
302
|
-
} catch {
|
|
303
|
-
return false;
|
|
123
|
+
if (ctx.seen.has(value)) return "[Circular]";
|
|
124
|
+
ctx.seen.add(value);
|
|
125
|
+
const child = { ...ctx, depth: ctx.depth + 1 };
|
|
126
|
+
if (value instanceof Map) {
|
|
127
|
+
const entries = [];
|
|
128
|
+
for (const [k, v] of value) {
|
|
129
|
+
if (entries.length >= MAX_ARRAY_LENGTH) break;
|
|
130
|
+
entries.push([sanitizeInner(k, child), sanitizeInner(v, child)]);
|
|
304
131
|
}
|
|
132
|
+
return { __type: "Map", entries };
|
|
305
133
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
if (!rawPath || !/^https?:\/\//.test(rawPath)) return location;
|
|
314
|
-
try {
|
|
315
|
-
const url = new URL(rawPath);
|
|
316
|
-
const pathname = decodeURIComponent(url.pathname);
|
|
317
|
-
if (!pathname.startsWith("/app/")) return location;
|
|
318
|
-
const root = options.webSourceRoot.replace(/\/+$/, "");
|
|
319
|
-
const filePath = `${root}${pathname}`;
|
|
320
|
-
const suffix = line ? `:${line}${column ? `:${column}` : ""}` : "";
|
|
321
|
-
return `${filePath}${suffix}`;
|
|
322
|
-
} catch {
|
|
323
|
-
return location;
|
|
134
|
+
if (value instanceof Set) {
|
|
135
|
+
const values = [];
|
|
136
|
+
for (const v of value) {
|
|
137
|
+
if (values.length >= MAX_ARRAY_LENGTH) break;
|
|
138
|
+
values.push(sanitizeInner(v, child));
|
|
139
|
+
}
|
|
140
|
+
return { __type: "Set", values };
|
|
324
141
|
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
const
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
if (wrapped) {
|
|
341
|
-
return normalizedFrame.replace(wrapped[1], location);
|
|
142
|
+
if (Array.isArray(value)) {
|
|
143
|
+
const sliced = value.slice(0, MAX_ARRAY_LENGTH);
|
|
144
|
+
const result = sliced.map((v) => sanitizeInner(v, child));
|
|
145
|
+
if (value.length > MAX_ARRAY_LENGTH) result.push(`[\u2026${value.length - MAX_ARRAY_LENGTH} more]`);
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
if (typeof value === "object") {
|
|
149
|
+
const result = {};
|
|
150
|
+
let count = 0;
|
|
151
|
+
for (const [k, v] of Object.entries(value)) {
|
|
152
|
+
if (count++ >= MAX_ARRAY_LENGTH) {
|
|
153
|
+
result["\u2026"] = "[truncated]";
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
result[k] = sanitizeInner(v, child);
|
|
342
157
|
}
|
|
343
|
-
return
|
|
158
|
+
return result;
|
|
344
159
|
}
|
|
345
|
-
return
|
|
160
|
+
return String(value);
|
|
161
|
+
}
|
|
162
|
+
function sanitize(value) {
|
|
163
|
+
return sanitizeInner(value, { depth: 0, budget: { n: 0 }, seen: /* @__PURE__ */ new WeakSet() });
|
|
346
164
|
}
|
|
347
|
-
|
|
165
|
+
|
|
166
|
+
// src/core.ts
|
|
167
|
+
function getSourceLocation() {
|
|
348
168
|
try {
|
|
349
|
-
const
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
return
|
|
169
|
+
const lines = new Error().stack?.split("\n") ?? [];
|
|
170
|
+
const callerLine = lines.find(
|
|
171
|
+
(l, i) => i > 3 && !l.includes("xstate") && !l.includes("adapter")
|
|
172
|
+
);
|
|
173
|
+
return callerLine?.trim().replace(/^at\s+/, "");
|
|
354
174
|
} catch {
|
|
355
175
|
return void 0;
|
|
356
176
|
}
|
|
357
177
|
}
|
|
358
178
|
function serializeSnapshot(snapshot) {
|
|
359
179
|
return {
|
|
360
|
-
value: snapshot?.value ?? null,
|
|
180
|
+
value: sanitize(snapshot?.value ?? null),
|
|
361
181
|
context: sanitize(snapshot?.context),
|
|
362
182
|
status: snapshot?.status ?? "active",
|
|
363
183
|
error: snapshot?.error ? sanitize(snapshot.error) : void 0
|
|
@@ -370,125 +190,18 @@ function safeSerializeSnapshot(actorRef) {
|
|
|
370
190
|
return { value: null, context: void 0, status: "active" };
|
|
371
191
|
}
|
|
372
192
|
}
|
|
373
|
-
function
|
|
374
|
-
const
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
if (typeof actor.logic?.id === "string" && actor.logic.id.length > 0) return actor.logic.id;
|
|
378
|
-
if (typeof actor.logic?.name === "string" && actor.logic.name.length > 0) return actor.logic.name;
|
|
379
|
-
if (src && typeof src === "object") {
|
|
380
|
-
const namedSrc = src;
|
|
381
|
-
if (typeof namedSrc.id === "string" && namedSrc.id.length > 0) return namedSrc.id;
|
|
382
|
-
if (typeof namedSrc.name === "string" && namedSrc.name.length > 0) return namedSrc.name;
|
|
383
|
-
}
|
|
384
|
-
return void 0;
|
|
385
|
-
}
|
|
386
|
-
function getNodeInitialChild(node) {
|
|
387
|
-
if (!node.states) return null;
|
|
388
|
-
if (typeof node.initial === "string") {
|
|
389
|
-
return node.states[node.initial] ?? null;
|
|
193
|
+
function safePersistedSnapshot(actorRef) {
|
|
194
|
+
const getPersisted = actorRef.getPersistedSnapshot;
|
|
195
|
+
if (typeof getPersisted !== "function") {
|
|
196
|
+
return { error: "Actor does not support getPersistedSnapshot." };
|
|
390
197
|
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
return
|
|
397
|
-
}
|
|
398
|
-
return { [child.key]: childValue };
|
|
399
|
-
}
|
|
400
|
-
function getDefaultStateValue(node) {
|
|
401
|
-
if (node.type === "parallel") {
|
|
402
|
-
const value = {};
|
|
403
|
-
for (const child of Object.values(node.states ?? {})) {
|
|
404
|
-
value[child.key] = getDefaultSelectionValue(child);
|
|
405
|
-
}
|
|
406
|
-
return value;
|
|
407
|
-
}
|
|
408
|
-
const initialChild = getNodeInitialChild(node);
|
|
409
|
-
if (!initialChild) return {};
|
|
410
|
-
return encodeChildValue(initialChild, getDefaultStateValue(initialChild));
|
|
411
|
-
}
|
|
412
|
-
function getDefaultSelectionValue(node) {
|
|
413
|
-
if (node.type === "atomic" || node.type === "final" || node.type === "history") {
|
|
414
|
-
return node.key;
|
|
415
|
-
}
|
|
416
|
-
return getDefaultStateValue(node);
|
|
417
|
-
}
|
|
418
|
-
function getExistingChildValue(value, childKey) {
|
|
419
|
-
if (!value || typeof value !== "object") return void 0;
|
|
420
|
-
return value[childKey];
|
|
421
|
-
}
|
|
422
|
-
function getPathToRoot(target, root) {
|
|
423
|
-
const path = [];
|
|
424
|
-
let current = target;
|
|
425
|
-
while (current) {
|
|
426
|
-
path.unshift(current);
|
|
427
|
-
if (current.id === root.id) return path;
|
|
428
|
-
current = current.parent;
|
|
429
|
-
}
|
|
430
|
-
throw new Error(`State node '${target.id}' is not part of machine '${root.id}'`);
|
|
431
|
-
}
|
|
432
|
-
function buildTargetStateValue(node, path, currentValue) {
|
|
433
|
-
const [, ...restPath] = path;
|
|
434
|
-
if (restPath.length === 0) {
|
|
435
|
-
if (node.type === "parallel") {
|
|
436
|
-
const next = {};
|
|
437
|
-
for (const child2 of Object.values(node.states ?? {})) {
|
|
438
|
-
next[child2.key] = getExistingChildValue(currentValue, child2.key) ?? getDefaultSelectionValue(child2);
|
|
439
|
-
}
|
|
440
|
-
return next;
|
|
441
|
-
}
|
|
442
|
-
if (node.type === "compound") {
|
|
443
|
-
return getDefaultStateValue(node);
|
|
444
|
-
}
|
|
445
|
-
return node.key;
|
|
446
|
-
}
|
|
447
|
-
const child = restPath[0];
|
|
448
|
-
if (node.type === "parallel") {
|
|
449
|
-
const next = {};
|
|
450
|
-
for (const sibling of Object.values(node.states ?? {})) {
|
|
451
|
-
if (sibling.key === child.key) {
|
|
452
|
-
next[sibling.key] = buildTargetStateValue(
|
|
453
|
-
sibling,
|
|
454
|
-
restPath,
|
|
455
|
-
getExistingChildValue(currentValue, sibling.key)
|
|
456
|
-
);
|
|
457
|
-
} else {
|
|
458
|
-
next[sibling.key] = getExistingChildValue(currentValue, sibling.key) ?? getDefaultSelectionValue(sibling);
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
return next;
|
|
462
|
-
}
|
|
463
|
-
const childValue = buildTargetStateValue(
|
|
464
|
-
child,
|
|
465
|
-
restPath,
|
|
466
|
-
getExistingChildValue(currentValue, child.key)
|
|
467
|
-
);
|
|
468
|
-
return encodeChildValue(child, childValue);
|
|
469
|
-
}
|
|
470
|
-
function setActiveState(actorRef, stateNodeId) {
|
|
471
|
-
const mutableActorRef = actorRef;
|
|
472
|
-
const machine = mutableActorRef.logic;
|
|
473
|
-
if (!machine?.getStateNodeById || !machine.resolveState || typeof mutableActorRef.update !== "function") {
|
|
474
|
-
throw new Error("Actor does not expose machine state mutation internals");
|
|
198
|
+
try {
|
|
199
|
+
const raw = getPersisted.call(actorRef);
|
|
200
|
+
if (raw === void 0) return { error: "No persisted snapshot available." };
|
|
201
|
+
return { persisted: JSON.parse(JSON.stringify(raw)) };
|
|
202
|
+
} catch (e) {
|
|
203
|
+
return { error: `Snapshot is not JSON-serializable: ${e.message}` };
|
|
475
204
|
}
|
|
476
|
-
const currentSnapshot = actorRef.getSnapshot();
|
|
477
|
-
const targetNode = machine.getStateNodeById(stateNodeId);
|
|
478
|
-
const path = getPathToRoot(targetNode, machine.root);
|
|
479
|
-
const targetValue = buildTargetStateValue(machine.root, path, currentSnapshot?.value);
|
|
480
|
-
const nextSnapshot = machine.resolveState({
|
|
481
|
-
value: targetValue,
|
|
482
|
-
context: currentSnapshot?.context,
|
|
483
|
-
status: currentSnapshot?.status,
|
|
484
|
-
output: currentSnapshot?.output,
|
|
485
|
-
error: currentSnapshot?.error,
|
|
486
|
-
historyValue: currentSnapshot?.historyValue
|
|
487
|
-
});
|
|
488
|
-
mutableActorRef.update(nextSnapshot, {
|
|
489
|
-
type: "xstate.devtools.set-active-state",
|
|
490
|
-
stateNodeId
|
|
491
|
-
});
|
|
492
205
|
}
|
|
493
206
|
var SEQ_KEY = "__xstate_devtools_global_seq__";
|
|
494
207
|
function nextSeq() {
|
|
@@ -498,10 +211,10 @@ function nextSeq() {
|
|
|
498
211
|
g[SEQ_KEY] = next;
|
|
499
212
|
return next;
|
|
500
213
|
}
|
|
501
|
-
function createInspector(transport, source
|
|
214
|
+
function createInspector(transport, source) {
|
|
502
215
|
const actorRefs = /* @__PURE__ */ new Map();
|
|
503
|
-
const
|
|
504
|
-
const prefix =
|
|
216
|
+
const restoreHandlers = /* @__PURE__ */ new Map();
|
|
217
|
+
const prefix = source + ":";
|
|
505
218
|
const tag = (sessionId) => prefix + sessionId;
|
|
506
219
|
const tagOptional = (id) => id ? prefix + id : void 0;
|
|
507
220
|
const stripIfMine = (id) => id.startsWith(prefix) ? id.slice(prefix.length) : null;
|
|
@@ -513,278 +226,200 @@ function createInspector(transport, source, options = {}) {
|
|
|
513
226
|
return;
|
|
514
227
|
}
|
|
515
228
|
if (snap?.status !== "active") {
|
|
516
|
-
|
|
517
|
-
type: "XSTATE_ACTOR_STOPPED",
|
|
518
|
-
sessionId: tag(actorRef.sessionId)
|
|
519
|
-
};
|
|
520
|
-
debugLog2(source, "actor stopped; notifying transport", summarizeMessage(message));
|
|
521
|
-
transport.send(message);
|
|
229
|
+
transport.send({ type: "XSTATE_ACTOR_STOPPED", sessionId: tag(actorRef.sessionId) });
|
|
522
230
|
actorRefs.delete(actorRef.sessionId);
|
|
523
|
-
actorMachines.delete(actorRef.sessionId);
|
|
524
231
|
}
|
|
525
232
|
}
|
|
526
233
|
const unsubscribe = transport.subscribe((message) => {
|
|
527
|
-
debugLog2(source, "received message from transport", summarizeMessage(message));
|
|
528
|
-
if (message.type === "XSTATE_PANEL_CONNECTED") {
|
|
529
|
-
infoLog2(source, "panel connected; resyncing actors", { actorCount: actorRefs.size });
|
|
530
|
-
actorRefs.forEach((actorRef, sessionId) => {
|
|
531
|
-
const machine = actorMachines.get(sessionId) ?? null;
|
|
532
|
-
const resyncMessage = {
|
|
533
|
-
type: "XSTATE_ACTOR_REGISTERED",
|
|
534
|
-
sessionId: tag(sessionId),
|
|
535
|
-
parentSessionId: tagOptional(actorRef._parent?.sessionId),
|
|
536
|
-
displayName: getActorDisplayName(actorRef),
|
|
537
|
-
machine,
|
|
538
|
-
snapshot: safeSerializeSnapshot(actorRef),
|
|
539
|
-
globalSeq: nextSeq(),
|
|
540
|
-
timestamp: Date.now()
|
|
541
|
-
};
|
|
542
|
-
debugLog2(source, "resyncing actor", summarizeMessage(resyncMessage));
|
|
543
|
-
transport.send(resyncMessage);
|
|
544
|
-
});
|
|
545
|
-
return;
|
|
546
|
-
}
|
|
547
234
|
if (message.type === "XSTATE_DISPATCH") {
|
|
548
235
|
const local = stripIfMine(message.sessionId);
|
|
549
|
-
if (local === null)
|
|
550
|
-
debugLog2(source, "ignoring dispatch for different source", summarizeMessage(message));
|
|
551
|
-
return;
|
|
552
|
-
}
|
|
236
|
+
if (local === null) return;
|
|
553
237
|
const ref = actorRefs.get(local);
|
|
554
238
|
if (ref) {
|
|
555
239
|
try {
|
|
556
|
-
debugLog2(source, "dispatching event to actor", {
|
|
557
|
-
sessionId: local,
|
|
558
|
-
eventType: message.event && typeof message.event === "object" && "type" in message.event ? message.event.type : void 0
|
|
559
|
-
});
|
|
560
240
|
ref.send(message.event);
|
|
561
241
|
} catch (e) {
|
|
562
|
-
|
|
242
|
+
console.warn("[xstate-devtools] dispatch error:", e);
|
|
563
243
|
}
|
|
564
|
-
} else {
|
|
565
|
-
warnLog2(source, "received dispatch for unknown actor", {
|
|
566
|
-
sessionId: local,
|
|
567
|
-
knownActors: actorRefs.size
|
|
568
|
-
});
|
|
569
244
|
}
|
|
570
|
-
|
|
571
|
-
}
|
|
572
|
-
if (message.type === "XSTATE_SET_ACTIVE_STATE") {
|
|
245
|
+
} else if (message.type === "XSTATE_REQUEST_PERSISTED") {
|
|
573
246
|
const local = stripIfMine(message.sessionId);
|
|
574
|
-
if (local === null)
|
|
575
|
-
debugLog2(
|
|
576
|
-
source,
|
|
577
|
-
"ignoring state activation for different source",
|
|
578
|
-
summarizeMessage(message)
|
|
579
|
-
);
|
|
580
|
-
return;
|
|
581
|
-
}
|
|
247
|
+
if (local === null) return;
|
|
582
248
|
const ref = actorRefs.get(local);
|
|
583
|
-
if (!ref)
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
249
|
+
if (!ref) return;
|
|
250
|
+
const { persisted, error } = safePersistedSnapshot(ref);
|
|
251
|
+
transport.send({
|
|
252
|
+
type: "XSTATE_PERSISTED_SNAPSHOT",
|
|
253
|
+
sessionId: tag(local),
|
|
254
|
+
persisted,
|
|
255
|
+
error,
|
|
256
|
+
timestamp: Date.now()
|
|
257
|
+
});
|
|
258
|
+
} else if (message.type === "XSTATE_RESTORE") {
|
|
259
|
+
const local = stripIfMine(message.sessionId);
|
|
260
|
+
if (local === null) return;
|
|
261
|
+
const handler = restoreHandlers.get(local);
|
|
262
|
+
if (handler) {
|
|
263
|
+
try {
|
|
264
|
+
handler(message.persisted);
|
|
265
|
+
} catch (e) {
|
|
266
|
+
console.warn("[xstate-devtools] restore error:", e);
|
|
267
|
+
}
|
|
589
268
|
}
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
const inspect = (inspectionEvent) => {
|
|
272
|
+
try {
|
|
273
|
+
if (inspectionEvent.type === "@xstate.actor") {
|
|
274
|
+
const actorRef = inspectionEvent.actorRef;
|
|
275
|
+
const sessionId = actorRef.sessionId;
|
|
276
|
+
actorRefs.set(sessionId, actorRef);
|
|
277
|
+
const logic = actorRef.logic;
|
|
278
|
+
const machine = logic?.root ? serializeMachine(logic, getSourceLocation()) : null;
|
|
279
|
+
transport.send({
|
|
280
|
+
type: "XSTATE_ACTOR_REGISTERED",
|
|
281
|
+
sessionId: tag(sessionId),
|
|
282
|
+
parentSessionId: tagOptional(actorRef._parent?.sessionId),
|
|
283
|
+
// actorRef.id is the invoke `id` for invoked actors — lets the debugger
|
|
284
|
+
// nest non-machine actors (promise/callback) under their state.
|
|
285
|
+
actorId: actorRef.id,
|
|
286
|
+
machine,
|
|
287
|
+
snapshot: safeSerializeSnapshot(actorRef),
|
|
288
|
+
globalSeq: nextSeq(),
|
|
289
|
+
timestamp: Date.now()
|
|
290
|
+
});
|
|
291
|
+
} else if (inspectionEvent.type === "@xstate.snapshot") {
|
|
292
|
+
transport.send({
|
|
594
293
|
type: "XSTATE_SNAPSHOT",
|
|
595
|
-
sessionId: tag(
|
|
596
|
-
snapshot:
|
|
294
|
+
sessionId: tag(inspectionEvent.actorRef.sessionId),
|
|
295
|
+
snapshot: serializeSnapshot(inspectionEvent.snapshot),
|
|
597
296
|
timestamp: Date.now(),
|
|
598
297
|
globalSeq: nextSeq()
|
|
599
|
-
};
|
|
600
|
-
debugLog2(
|
|
601
|
-
source,
|
|
602
|
-
"sending snapshot after state activation",
|
|
603
|
-
summarizeMessage(snapshotMessage)
|
|
604
|
-
);
|
|
605
|
-
transport.send(snapshotMessage);
|
|
606
|
-
} catch (error) {
|
|
607
|
-
warnLog2(source, "failed to set active state", {
|
|
608
|
-
error,
|
|
609
|
-
sessionId: local,
|
|
610
|
-
stateNodeId: message.stateNodeId
|
|
611
298
|
});
|
|
299
|
+
checkAndNotifyStop(inspectionEvent.actorRef);
|
|
300
|
+
} else if (inspectionEvent.type === "@xstate.event") {
|
|
301
|
+
transport.send({
|
|
302
|
+
type: "XSTATE_EVENT",
|
|
303
|
+
sessionId: tag(inspectionEvent.actorRef.sessionId),
|
|
304
|
+
event: inspectionEvent.event,
|
|
305
|
+
snapshotAfter: safeSerializeSnapshot(inspectionEvent.actorRef),
|
|
306
|
+
timestamp: Date.now(),
|
|
307
|
+
globalSeq: nextSeq()
|
|
308
|
+
});
|
|
309
|
+
checkAndNotifyStop(inspectionEvent.actorRef);
|
|
612
310
|
}
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
transport.send({ type: "XSTATE_ADAPTER_READY" });
|
|
616
|
-
infoLog2(source, "inspector created");
|
|
617
|
-
const inspect = (inspectionEvent) => {
|
|
618
|
-
debugLog2(source, "inspect callback invoked", summarizeInspectionEvent(inspectionEvent));
|
|
619
|
-
if (inspectionEvent.type === "@xstate.actor") {
|
|
620
|
-
const actorRef = inspectionEvent.actorRef;
|
|
621
|
-
const sessionId = actorRef.sessionId;
|
|
622
|
-
const actorLogic = actorRef.logic;
|
|
623
|
-
const machine = actorLogic?.root ? serializeMachine(
|
|
624
|
-
actorLogic,
|
|
625
|
-
actorLogic.config?.__xstateDevtoolsSource ?? getSourceLocation(source, options)
|
|
626
|
-
) : null;
|
|
627
|
-
actorRefs.set(sessionId, actorRef);
|
|
628
|
-
actorMachines.set(sessionId, machine);
|
|
629
|
-
const notifyStop = () => {
|
|
630
|
-
if (actorRefs.has(sessionId)) {
|
|
631
|
-
actorRefs.delete(sessionId);
|
|
632
|
-
actorMachines.delete(sessionId);
|
|
633
|
-
const stopMsg = {
|
|
634
|
-
type: "XSTATE_ACTOR_STOPPED",
|
|
635
|
-
sessionId: tag(sessionId)
|
|
636
|
-
};
|
|
637
|
-
debugLog2(source, "actor stopped; notifying transport", summarizeMessage(stopMsg));
|
|
638
|
-
transport.send(stopMsg);
|
|
639
|
-
}
|
|
640
|
-
};
|
|
641
|
-
try {
|
|
642
|
-
actorRef.subscribe({ complete: notifyStop, error: notifyStop });
|
|
643
|
-
} catch {
|
|
644
|
-
}
|
|
645
|
-
const message = {
|
|
646
|
-
type: "XSTATE_ACTOR_REGISTERED",
|
|
647
|
-
sessionId: tag(sessionId),
|
|
648
|
-
parentSessionId: tagOptional(actorRef._parent?.sessionId),
|
|
649
|
-
displayName: getActorDisplayName(actorRef),
|
|
650
|
-
machine,
|
|
651
|
-
snapshot: safeSerializeSnapshot(actorRef),
|
|
652
|
-
globalSeq: nextSeq(),
|
|
653
|
-
timestamp: Date.now()
|
|
654
|
-
};
|
|
655
|
-
infoLog2(source, "registering actor with transport", {
|
|
656
|
-
message: summarizeMessage(message),
|
|
657
|
-
actorCount: actorRefs.size,
|
|
658
|
-
hasMachine: machine !== null
|
|
659
|
-
});
|
|
660
|
-
transport.send(message);
|
|
661
|
-
} else if (inspectionEvent.type === "@xstate.snapshot") {
|
|
662
|
-
const message = {
|
|
663
|
-
type: "XSTATE_SNAPSHOT",
|
|
664
|
-
sessionId: tag(inspectionEvent.actorRef.sessionId),
|
|
665
|
-
snapshot: serializeSnapshot(inspectionEvent.snapshot),
|
|
666
|
-
timestamp: Date.now(),
|
|
667
|
-
globalSeq: nextSeq()
|
|
668
|
-
};
|
|
669
|
-
debugLog2(source, "sending snapshot to transport", summarizeMessage(message));
|
|
670
|
-
transport.send(message);
|
|
671
|
-
checkAndNotifyStop(inspectionEvent.actorRef);
|
|
672
|
-
} else if (inspectionEvent.type === "@xstate.event") {
|
|
673
|
-
const message = {
|
|
674
|
-
type: "XSTATE_EVENT",
|
|
675
|
-
sessionId: tag(inspectionEvent.actorRef.sessionId),
|
|
676
|
-
// sanitize() returns unknown; the inspected event keeps its { type, ... }
|
|
677
|
-
// shape, so it is a SerializedEvent after deep-sanitizing.
|
|
678
|
-
event: sanitize(inspectionEvent.event),
|
|
679
|
-
snapshotAfter: safeSerializeSnapshot(inspectionEvent.actorRef),
|
|
680
|
-
timestamp: Date.now(),
|
|
681
|
-
globalSeq: nextSeq()
|
|
682
|
-
};
|
|
683
|
-
debugLog2(source, "sending event to transport", summarizeMessage(message));
|
|
684
|
-
transport.send(message);
|
|
685
|
-
checkAndNotifyStop(inspectionEvent.actorRef);
|
|
686
|
-
} else {
|
|
687
|
-
debugLog2(
|
|
688
|
-
source,
|
|
689
|
-
"ignoring unsupported inspection event",
|
|
690
|
-
summarizeInspectionEvent(inspectionEvent)
|
|
691
|
-
);
|
|
311
|
+
} catch (e) {
|
|
312
|
+
console.warn("[xstate-devtools] inspection failed, dropping event:", e.message);
|
|
692
313
|
}
|
|
693
314
|
};
|
|
315
|
+
function registerRestore(sessionId, handler) {
|
|
316
|
+
restoreHandlers.set(sessionId, handler);
|
|
317
|
+
return () => {
|
|
318
|
+
if (restoreHandlers.get(sessionId) === handler) restoreHandlers.delete(sessionId);
|
|
319
|
+
};
|
|
320
|
+
}
|
|
694
321
|
function dispose() {
|
|
695
|
-
infoLog2(source, "disposing inspector", { actorCount: actorRefs.size });
|
|
696
322
|
unsubscribe();
|
|
697
323
|
actorRefs.clear();
|
|
698
|
-
|
|
324
|
+
restoreHandlers.clear();
|
|
699
325
|
}
|
|
700
|
-
return { inspect, dispose };
|
|
326
|
+
return { inspect, dispose, registerRestore };
|
|
701
327
|
}
|
|
702
328
|
|
|
703
329
|
// src/index.ts
|
|
704
|
-
function createAdapter(
|
|
330
|
+
function createAdapter() {
|
|
705
331
|
if (typeof window === "undefined") {
|
|
706
|
-
infoLog("web:adapter", "createAdapter called without window; returning no-op adapter");
|
|
707
332
|
return { inspect: () => {
|
|
708
333
|
}, dispose: () => {
|
|
334
|
+
}, registerRestore: () => () => {
|
|
709
335
|
} };
|
|
710
336
|
}
|
|
711
|
-
infoLog("web:adapter", "creating browser adapter", {
|
|
712
|
-
hookInstalled: Boolean(window.__XSTATE_DEVTOOLS__)
|
|
713
|
-
});
|
|
714
|
-
let warnedMissingHook = false;
|
|
715
337
|
const transport = {
|
|
716
338
|
send(message) {
|
|
717
|
-
|
|
718
|
-
debugLog("web:adapter", "sending message via page hook", {
|
|
719
|
-
type: message.type,
|
|
720
|
-
sessionId: "sessionId" in message ? message.sessionId : void 0
|
|
721
|
-
});
|
|
722
|
-
if (window.__XSTATE_DEVTOOLS__) {
|
|
723
|
-
window.__XSTATE_DEVTOOLS__.send(payload);
|
|
724
|
-
return;
|
|
725
|
-
}
|
|
726
|
-
if (!warnedMissingHook) {
|
|
727
|
-
warnedMissingHook = true;
|
|
728
|
-
warnLog("web:adapter", "page hook missing; using direct window.postMessage fallback");
|
|
729
|
-
}
|
|
730
|
-
window.postMessage(payload, "*");
|
|
339
|
+
window.__XSTATE_DEVTOOLS__?.send({ ...message, __xstateDevtools: true });
|
|
731
340
|
},
|
|
732
341
|
subscribe(handler) {
|
|
733
|
-
infoLog("web:adapter", "subscribing to window messages");
|
|
734
342
|
const onMessage = (evt) => {
|
|
735
343
|
if (evt.source !== window) return;
|
|
736
344
|
const data = evt.data;
|
|
737
345
|
if (!data?.__xstateDevtools) return;
|
|
738
|
-
debugLog("web:adapter", "received message from window bridge", {
|
|
739
|
-
type: data.type,
|
|
740
|
-
sessionId: "sessionId" in data ? data.sessionId : void 0
|
|
741
|
-
});
|
|
742
346
|
handler(data);
|
|
743
347
|
};
|
|
744
348
|
window.addEventListener("message", onMessage);
|
|
745
|
-
return () =>
|
|
746
|
-
infoLog("web:adapter", "unsubscribing from window messages");
|
|
747
|
-
window.removeEventListener("message", onMessage);
|
|
748
|
-
};
|
|
349
|
+
return () => window.removeEventListener("message", onMessage);
|
|
749
350
|
}
|
|
750
351
|
};
|
|
751
|
-
return createInspector(transport, "web"
|
|
352
|
+
return createInspector(transport, "web");
|
|
752
353
|
}
|
|
753
354
|
|
|
754
355
|
// src/react.tsx
|
|
755
356
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
756
|
-
var InspectorContext = (0,
|
|
757
|
-
function InspectorProvider({
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
357
|
+
var InspectorContext = (0, import_react.createContext)(null);
|
|
358
|
+
function InspectorProvider({
|
|
359
|
+
children,
|
|
360
|
+
adapter
|
|
361
|
+
}) {
|
|
362
|
+
const ownRef = (0, import_react.useRef)(null);
|
|
363
|
+
const useOwn = adapter == null;
|
|
364
|
+
if (useOwn && !ownRef.current && typeof window !== "undefined") {
|
|
365
|
+
ownRef.current = createAdapter();
|
|
366
|
+
}
|
|
367
|
+
const resolved = adapter ?? ownRef.current;
|
|
368
|
+
(0, import_react.useEffect)(() => {
|
|
369
|
+
if (!useOwn) return;
|
|
763
370
|
return () => {
|
|
764
|
-
|
|
765
|
-
|
|
371
|
+
ownRef.current?.dispose();
|
|
372
|
+
ownRef.current = null;
|
|
766
373
|
};
|
|
767
|
-
}, []);
|
|
768
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InspectorContext.Provider, { value:
|
|
374
|
+
}, [useOwn]);
|
|
375
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InspectorContext.Provider, { value: resolved, children });
|
|
769
376
|
}
|
|
770
377
|
function useInspectedMachine(machine, options) {
|
|
771
|
-
const adapter = (0,
|
|
772
|
-
return (0,
|
|
378
|
+
const adapter = (0, import_react.useContext)(InspectorContext);
|
|
379
|
+
return (0, import_react2.useMachine)(machine, {
|
|
773
380
|
...options,
|
|
774
381
|
inspect: adapter?.inspect
|
|
775
382
|
});
|
|
776
383
|
}
|
|
777
384
|
function useInspectedActorRef(machine, options) {
|
|
778
|
-
const adapter = (0,
|
|
779
|
-
return (0,
|
|
385
|
+
const adapter = (0, import_react.useContext)(InspectorContext);
|
|
386
|
+
return (0, import_react2.useActorRef)(machine, {
|
|
780
387
|
...options,
|
|
781
388
|
inspect: adapter?.inspect
|
|
782
389
|
});
|
|
783
390
|
}
|
|
391
|
+
function useRestorableInspectedMachine(machine, options) {
|
|
392
|
+
const adapter = (0, import_react.useContext)(InspectorContext);
|
|
393
|
+
const restoreSnapshotRef = (0, import_react.useRef)(options?.snapshot);
|
|
394
|
+
const [generation, setGeneration] = (0, import_react.useState)(0);
|
|
395
|
+
const actorRef = (0, import_react.useMemo)(() => {
|
|
396
|
+
return (0, import_xstate.createActor)(machine, {
|
|
397
|
+
...options,
|
|
398
|
+
snapshot: restoreSnapshotRef.current,
|
|
399
|
+
inspect: adapter?.inspect
|
|
400
|
+
});
|
|
401
|
+
}, [generation, adapter]);
|
|
402
|
+
(0, import_react.useEffect)(() => {
|
|
403
|
+
actorRef.start();
|
|
404
|
+
return () => {
|
|
405
|
+
actorRef.stop();
|
|
406
|
+
};
|
|
407
|
+
}, [actorRef]);
|
|
408
|
+
(0, import_react.useEffect)(() => {
|
|
409
|
+
if (!adapter?.registerRestore) return;
|
|
410
|
+
return adapter.registerRestore(actorRef.sessionId, (persisted) => {
|
|
411
|
+
restoreSnapshotRef.current = persisted;
|
|
412
|
+
setGeneration((g) => g + 1);
|
|
413
|
+
});
|
|
414
|
+
}, [adapter, actorRef]);
|
|
415
|
+
const snapshot = (0, import_react2.useSelector)(actorRef, (s) => s);
|
|
416
|
+
return [snapshot, actorRef.send, actorRef];
|
|
417
|
+
}
|
|
784
418
|
// Annotate the CommonJS export names for ESM import in node:
|
|
785
419
|
0 && (module.exports = {
|
|
786
420
|
InspectorProvider,
|
|
787
421
|
useInspectedActorRef,
|
|
788
|
-
useInspectedMachine
|
|
422
|
+
useInspectedMachine,
|
|
423
|
+
useRestorableInspectedMachine
|
|
789
424
|
});
|
|
790
425
|
//# sourceMappingURL=react.cjs.map
|