@xstate-devtools/adapter 0.1.4 → 0.1.6
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-M4XORXVP.js +307 -0
- package/dist/chunk-M4XORXVP.js.map +1 -0
- package/dist/chunk-W5QGSHOC.js +34 -0
- package/dist/chunk-W5QGSHOC.js.map +1 -0
- package/dist/index.cjs +177 -571
- 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 +232 -590
- 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 +245 -681
- 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 +13 -4
- 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,119 +22,27 @@ 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;
|
|
136
|
-
if (typeof guard === "function")
|
|
137
|
-
|
|
37
|
+
if (typeof guard === "function") {
|
|
38
|
+
const fn = guard;
|
|
39
|
+
if (Array.isArray(fn.guards) && typeof fn.check === "function") {
|
|
40
|
+
const parts = fn.guards.map((g) => serializeGuard(g) ?? "(inline)");
|
|
41
|
+
return `${fn.name || "(combinator)"}(${parts.join(", ")})`;
|
|
42
|
+
}
|
|
43
|
+
return fn.name || "(inline)";
|
|
44
|
+
}
|
|
45
|
+
if (typeof guard === "object") {
|
|
138
46
|
const g = guard;
|
|
139
47
|
return g.type ?? g.name ?? "(inline)";
|
|
140
48
|
}
|
|
@@ -150,214 +58,133 @@ function serializeAction(action) {
|
|
|
150
58
|
return String(action);
|
|
151
59
|
}
|
|
152
60
|
function serializeTransitionList(transitions) {
|
|
153
|
-
return transitions.
|
|
61
|
+
return transitions.map((t) => ({
|
|
154
62
|
eventType: t.eventType ?? "",
|
|
155
63
|
targets: (t.target ?? []).map((n) => n?.id ?? String(n)).filter(Boolean),
|
|
156
64
|
guard: serializeGuard(t.guard),
|
|
157
|
-
actions: (t.actions ?? []).
|
|
65
|
+
actions: (t.actions ?? []).map(serializeAction).filter(Boolean)
|
|
158
66
|
}));
|
|
159
67
|
}
|
|
160
68
|
function serializeInvokes(node) {
|
|
161
|
-
return node.invoke.
|
|
69
|
+
return node.invoke.map((inv) => ({
|
|
162
70
|
id: inv.id ?? "(unknown)",
|
|
163
71
|
src: typeof inv.src === "string" ? inv.src : inv.src?.id ?? inv.src?.name ?? "(inline)"
|
|
164
72
|
}));
|
|
165
73
|
}
|
|
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;
|
|
74
|
+
function serializeNode(node) {
|
|
208
75
|
const allTransitions = [];
|
|
209
76
|
if (node.transitions instanceof Map) {
|
|
210
77
|
for (const [, tList] of node.transitions) {
|
|
211
|
-
if (allTransitions.length >= MAX_TRANSITIONS_PER_NODE) break;
|
|
212
78
|
allTransitions.push(...serializeTransitionList(tList));
|
|
213
|
-
if (allTransitions.length >= MAX_TRANSITIONS_PER_NODE) {
|
|
214
|
-
allTransitions.length = MAX_TRANSITIONS_PER_NODE;
|
|
215
|
-
break;
|
|
216
|
-
}
|
|
217
79
|
}
|
|
218
80
|
}
|
|
219
81
|
const always = Array.isArray(node.always) ? serializeTransitionList(node.always) : [];
|
|
220
|
-
const childEntries = Object.entries(node.states ?? {}).slice(0, MAX_CHILD_STATES);
|
|
221
82
|
return {
|
|
222
83
|
id: node.id,
|
|
223
84
|
key: node.key,
|
|
224
85
|
type: node.type,
|
|
225
86
|
initial: node.initial?.target?.[0]?.key,
|
|
226
|
-
states: Object.fromEntries(
|
|
87
|
+
states: Object.fromEntries(
|
|
88
|
+
Object.entries(node.states ?? {}).map(([k, v]) => [k, serializeNode(v)])
|
|
89
|
+
),
|
|
227
90
|
on: allTransitions,
|
|
228
91
|
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
|
|
92
|
+
entry: (node.entry ?? []).map(serializeAction).filter(Boolean),
|
|
93
|
+
exit: (node.exit ?? []).map(serializeAction).filter(Boolean),
|
|
94
|
+
invoke: serializeInvokes(node)
|
|
234
95
|
};
|
|
235
96
|
}
|
|
236
97
|
function serializeMachine(machine, sourceLocation) {
|
|
237
98
|
return {
|
|
238
99
|
id: machine.id,
|
|
239
|
-
root: serializeNode(machine.root
|
|
100
|
+
root: serializeNode(machine.root),
|
|
240
101
|
sourceLocation
|
|
241
102
|
};
|
|
242
103
|
}
|
|
243
104
|
|
|
244
|
-
// src/
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
105
|
+
// src/sanitize.ts
|
|
106
|
+
var MAX_DEPTH = 10;
|
|
107
|
+
var MAX_STRING_LENGTH = 500;
|
|
108
|
+
var MAX_ARRAY_LENGTH = 100;
|
|
109
|
+
var MAX_NODES = 1e4;
|
|
110
|
+
function sanitizeInner(value, ctx) {
|
|
111
|
+
if (ctx.depth > MAX_DEPTH) return "[MaxDepth]";
|
|
112
|
+
if (++ctx.budget.n > MAX_NODES) return "[Truncated]";
|
|
113
|
+
if (value === null || value === void 0) return value;
|
|
114
|
+
if (typeof value === "boolean" || typeof value === "number") return value;
|
|
115
|
+
if (typeof value === "string") {
|
|
116
|
+
return value.length > MAX_STRING_LENGTH ? value.slice(0, MAX_STRING_LENGTH) + "\u2026" : value;
|
|
251
117
|
}
|
|
252
|
-
if ("
|
|
253
|
-
if ("
|
|
254
|
-
if (
|
|
255
|
-
|
|
118
|
+
if (typeof value === "function") return `[Function: ${value.name || "(anonymous)"}]`;
|
|
119
|
+
if (typeof value === "symbol") return `[Symbol: ${value.description ?? ""}]`;
|
|
120
|
+
if (typeof value === "bigint") return `[BigInt: ${value}]`;
|
|
121
|
+
if (value instanceof Error) return { __type: "Error", name: value.name, message: value.message };
|
|
122
|
+
if (value instanceof Date) return { __type: "Date", iso: value.toISOString() };
|
|
123
|
+
if (value instanceof RegExp) return { __type: "RegExp", source: value.source, flags: value.flags };
|
|
124
|
+
if (value instanceof Promise) return "[Promise]";
|
|
125
|
+
if (value instanceof WeakMap || value instanceof WeakSet) return "[WeakCollection]";
|
|
126
|
+
if (ArrayBuffer.isView(value)) return `[TypedArray: ${value.constructor.name}]`;
|
|
127
|
+
if (typeof Node !== "undefined" && value instanceof Node) {
|
|
128
|
+
return `[DOMNode: ${value.tagName ?? value.nodeName}]`;
|
|
256
129
|
}
|
|
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;
|
|
130
|
+
if (ctx.seen.has(value)) return "[Circular]";
|
|
131
|
+
ctx.seen.add(value);
|
|
132
|
+
const child = { ...ctx, depth: ctx.depth + 1 };
|
|
133
|
+
if (value instanceof Map) {
|
|
134
|
+
const entries = [];
|
|
135
|
+
for (const [k, v] of value) {
|
|
136
|
+
if (entries.length >= MAX_ARRAY_LENGTH) break;
|
|
137
|
+
entries.push([sanitizeInner(k, child), sanitizeInner(v, child)]);
|
|
304
138
|
}
|
|
139
|
+
return { __type: "Map", entries };
|
|
305
140
|
}
|
|
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;
|
|
141
|
+
if (value instanceof Set) {
|
|
142
|
+
const values = [];
|
|
143
|
+
for (const v of value) {
|
|
144
|
+
if (values.length >= MAX_ARRAY_LENGTH) break;
|
|
145
|
+
values.push(sanitizeInner(v, child));
|
|
146
|
+
}
|
|
147
|
+
return { __type: "Set", values };
|
|
324
148
|
}
|
|
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);
|
|
149
|
+
if (Array.isArray(value)) {
|
|
150
|
+
const sliced = value.slice(0, MAX_ARRAY_LENGTH);
|
|
151
|
+
const result = sliced.map((v) => sanitizeInner(v, child));
|
|
152
|
+
if (value.length > MAX_ARRAY_LENGTH) result.push(`[\u2026${value.length - MAX_ARRAY_LENGTH} more]`);
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
155
|
+
if (typeof value === "object") {
|
|
156
|
+
const result = {};
|
|
157
|
+
let count = 0;
|
|
158
|
+
for (const [k, v] of Object.entries(value)) {
|
|
159
|
+
if (count++ >= MAX_ARRAY_LENGTH) {
|
|
160
|
+
result["\u2026"] = "[truncated]";
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
result[k] = sanitizeInner(v, child);
|
|
342
164
|
}
|
|
343
|
-
return
|
|
165
|
+
return result;
|
|
344
166
|
}
|
|
345
|
-
return
|
|
167
|
+
return String(value);
|
|
168
|
+
}
|
|
169
|
+
function sanitize(value) {
|
|
170
|
+
return sanitizeInner(value, { depth: 0, budget: { n: 0 }, seen: /* @__PURE__ */ new WeakSet() });
|
|
346
171
|
}
|
|
347
|
-
|
|
172
|
+
|
|
173
|
+
// src/core.ts
|
|
174
|
+
function getSourceLocation() {
|
|
348
175
|
try {
|
|
349
|
-
const
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
return
|
|
176
|
+
const lines = new Error().stack?.split("\n") ?? [];
|
|
177
|
+
const callerLine = lines.find(
|
|
178
|
+
(l, i) => i > 3 && !l.includes("xstate") && !l.includes("adapter")
|
|
179
|
+
);
|
|
180
|
+
return callerLine?.trim().replace(/^at\s+/, "");
|
|
354
181
|
} catch {
|
|
355
182
|
return void 0;
|
|
356
183
|
}
|
|
357
184
|
}
|
|
358
185
|
function serializeSnapshot(snapshot) {
|
|
359
186
|
return {
|
|
360
|
-
value: snapshot?.value ?? null,
|
|
187
|
+
value: sanitize(snapshot?.value ?? null),
|
|
361
188
|
context: sanitize(snapshot?.context),
|
|
362
189
|
status: snapshot?.status ?? "active",
|
|
363
190
|
error: snapshot?.error ? sanitize(snapshot.error) : void 0
|
|
@@ -370,125 +197,18 @@ function safeSerializeSnapshot(actorRef) {
|
|
|
370
197
|
return { value: null, context: void 0, status: "active" };
|
|
371
198
|
}
|
|
372
199
|
}
|
|
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;
|
|
200
|
+
function safePersistedSnapshot(actorRef) {
|
|
201
|
+
const getPersisted = actorRef.getPersistedSnapshot;
|
|
202
|
+
if (typeof getPersisted !== "function") {
|
|
203
|
+
return { error: "Actor does not support getPersistedSnapshot." };
|
|
390
204
|
}
|
|
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");
|
|
205
|
+
try {
|
|
206
|
+
const raw = getPersisted.call(actorRef);
|
|
207
|
+
if (raw === void 0) return { error: "No persisted snapshot available." };
|
|
208
|
+
return { persisted: JSON.parse(JSON.stringify(raw)) };
|
|
209
|
+
} catch (e) {
|
|
210
|
+
return { error: `Snapshot is not JSON-serializable: ${e.message}` };
|
|
475
211
|
}
|
|
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
212
|
}
|
|
493
213
|
var SEQ_KEY = "__xstate_devtools_global_seq__";
|
|
494
214
|
function nextSeq() {
|
|
@@ -498,10 +218,10 @@ function nextSeq() {
|
|
|
498
218
|
g[SEQ_KEY] = next;
|
|
499
219
|
return next;
|
|
500
220
|
}
|
|
501
|
-
function createInspector(transport, source
|
|
221
|
+
function createInspector(transport, source) {
|
|
502
222
|
const actorRefs = /* @__PURE__ */ new Map();
|
|
503
|
-
const
|
|
504
|
-
const prefix =
|
|
223
|
+
const restoreHandlers = /* @__PURE__ */ new Map();
|
|
224
|
+
const prefix = source + ":";
|
|
505
225
|
const tag = (sessionId) => prefix + sessionId;
|
|
506
226
|
const tagOptional = (id) => id ? prefix + id : void 0;
|
|
507
227
|
const stripIfMine = (id) => id.startsWith(prefix) ? id.slice(prefix.length) : null;
|
|
@@ -513,278 +233,200 @@ function createInspector(transport, source, options = {}) {
|
|
|
513
233
|
return;
|
|
514
234
|
}
|
|
515
235
|
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);
|
|
236
|
+
transport.send({ type: "XSTATE_ACTOR_STOPPED", sessionId: tag(actorRef.sessionId) });
|
|
522
237
|
actorRefs.delete(actorRef.sessionId);
|
|
523
|
-
actorMachines.delete(actorRef.sessionId);
|
|
524
238
|
}
|
|
525
239
|
}
|
|
526
240
|
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
241
|
if (message.type === "XSTATE_DISPATCH") {
|
|
548
242
|
const local = stripIfMine(message.sessionId);
|
|
549
|
-
if (local === null)
|
|
550
|
-
debugLog2(source, "ignoring dispatch for different source", summarizeMessage(message));
|
|
551
|
-
return;
|
|
552
|
-
}
|
|
243
|
+
if (local === null) return;
|
|
553
244
|
const ref = actorRefs.get(local);
|
|
554
245
|
if (ref) {
|
|
555
246
|
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
247
|
ref.send(message.event);
|
|
561
248
|
} catch (e) {
|
|
562
|
-
|
|
249
|
+
console.warn("[xstate-devtools] dispatch error:", e);
|
|
563
250
|
}
|
|
564
|
-
} else {
|
|
565
|
-
warnLog2(source, "received dispatch for unknown actor", {
|
|
566
|
-
sessionId: local,
|
|
567
|
-
knownActors: actorRefs.size
|
|
568
|
-
});
|
|
569
251
|
}
|
|
570
|
-
|
|
571
|
-
}
|
|
572
|
-
if (message.type === "XSTATE_SET_ACTIVE_STATE") {
|
|
252
|
+
} else if (message.type === "XSTATE_REQUEST_PERSISTED") {
|
|
573
253
|
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
|
-
}
|
|
254
|
+
if (local === null) return;
|
|
582
255
|
const ref = actorRefs.get(local);
|
|
583
|
-
if (!ref)
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
256
|
+
if (!ref) return;
|
|
257
|
+
const { persisted, error } = safePersistedSnapshot(ref);
|
|
258
|
+
transport.send({
|
|
259
|
+
type: "XSTATE_PERSISTED_SNAPSHOT",
|
|
260
|
+
sessionId: tag(local),
|
|
261
|
+
persisted,
|
|
262
|
+
error,
|
|
263
|
+
timestamp: Date.now()
|
|
264
|
+
});
|
|
265
|
+
} else if (message.type === "XSTATE_RESTORE") {
|
|
266
|
+
const local = stripIfMine(message.sessionId);
|
|
267
|
+
if (local === null) return;
|
|
268
|
+
const handler = restoreHandlers.get(local);
|
|
269
|
+
if (handler) {
|
|
270
|
+
try {
|
|
271
|
+
handler(message.persisted);
|
|
272
|
+
} catch (e) {
|
|
273
|
+
console.warn("[xstate-devtools] restore error:", e);
|
|
274
|
+
}
|
|
589
275
|
}
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
const inspect = (inspectionEvent) => {
|
|
279
|
+
try {
|
|
280
|
+
if (inspectionEvent.type === "@xstate.actor") {
|
|
281
|
+
const actorRef = inspectionEvent.actorRef;
|
|
282
|
+
const sessionId = actorRef.sessionId;
|
|
283
|
+
actorRefs.set(sessionId, actorRef);
|
|
284
|
+
const logic = actorRef.logic;
|
|
285
|
+
const machine = logic?.root ? serializeMachine(logic, getSourceLocation()) : null;
|
|
286
|
+
transport.send({
|
|
287
|
+
type: "XSTATE_ACTOR_REGISTERED",
|
|
288
|
+
sessionId: tag(sessionId),
|
|
289
|
+
parentSessionId: tagOptional(actorRef._parent?.sessionId),
|
|
290
|
+
// actorRef.id is the invoke `id` for invoked actors — lets the debugger
|
|
291
|
+
// nest non-machine actors (promise/callback) under their state.
|
|
292
|
+
actorId: actorRef.id,
|
|
293
|
+
machine,
|
|
294
|
+
snapshot: safeSerializeSnapshot(actorRef),
|
|
295
|
+
globalSeq: nextSeq(),
|
|
296
|
+
timestamp: Date.now()
|
|
297
|
+
});
|
|
298
|
+
} else if (inspectionEvent.type === "@xstate.snapshot") {
|
|
299
|
+
transport.send({
|
|
594
300
|
type: "XSTATE_SNAPSHOT",
|
|
595
|
-
sessionId: tag(
|
|
596
|
-
snapshot:
|
|
301
|
+
sessionId: tag(inspectionEvent.actorRef.sessionId),
|
|
302
|
+
snapshot: serializeSnapshot(inspectionEvent.snapshot),
|
|
597
303
|
timestamp: Date.now(),
|
|
598
304
|
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
305
|
});
|
|
306
|
+
checkAndNotifyStop(inspectionEvent.actorRef);
|
|
307
|
+
} else if (inspectionEvent.type === "@xstate.event") {
|
|
308
|
+
transport.send({
|
|
309
|
+
type: "XSTATE_EVENT",
|
|
310
|
+
sessionId: tag(inspectionEvent.actorRef.sessionId),
|
|
311
|
+
event: inspectionEvent.event,
|
|
312
|
+
snapshotAfter: safeSerializeSnapshot(inspectionEvent.actorRef),
|
|
313
|
+
timestamp: Date.now(),
|
|
314
|
+
globalSeq: nextSeq()
|
|
315
|
+
});
|
|
316
|
+
checkAndNotifyStop(inspectionEvent.actorRef);
|
|
612
317
|
}
|
|
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
|
-
);
|
|
318
|
+
} catch (e) {
|
|
319
|
+
console.warn("[xstate-devtools] inspection failed, dropping event:", e.message);
|
|
692
320
|
}
|
|
693
321
|
};
|
|
322
|
+
function registerRestore(sessionId, handler) {
|
|
323
|
+
restoreHandlers.set(sessionId, handler);
|
|
324
|
+
return () => {
|
|
325
|
+
if (restoreHandlers.get(sessionId) === handler) restoreHandlers.delete(sessionId);
|
|
326
|
+
};
|
|
327
|
+
}
|
|
694
328
|
function dispose() {
|
|
695
|
-
infoLog2(source, "disposing inspector", { actorCount: actorRefs.size });
|
|
696
329
|
unsubscribe();
|
|
697
330
|
actorRefs.clear();
|
|
698
|
-
|
|
331
|
+
restoreHandlers.clear();
|
|
699
332
|
}
|
|
700
|
-
return { inspect, dispose };
|
|
333
|
+
return { inspect, dispose, registerRestore };
|
|
701
334
|
}
|
|
702
335
|
|
|
703
336
|
// src/index.ts
|
|
704
|
-
function createAdapter(
|
|
337
|
+
function createAdapter() {
|
|
705
338
|
if (typeof window === "undefined") {
|
|
706
|
-
infoLog("web:adapter", "createAdapter called without window; returning no-op adapter");
|
|
707
339
|
return { inspect: () => {
|
|
708
340
|
}, dispose: () => {
|
|
341
|
+
}, registerRestore: () => () => {
|
|
709
342
|
} };
|
|
710
343
|
}
|
|
711
|
-
infoLog("web:adapter", "creating browser adapter", {
|
|
712
|
-
hookInstalled: Boolean(window.__XSTATE_DEVTOOLS__)
|
|
713
|
-
});
|
|
714
|
-
let warnedMissingHook = false;
|
|
715
344
|
const transport = {
|
|
716
345
|
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, "*");
|
|
346
|
+
window.__XSTATE_DEVTOOLS__?.send({ ...message, __xstateDevtools: true });
|
|
731
347
|
},
|
|
732
348
|
subscribe(handler) {
|
|
733
|
-
infoLog("web:adapter", "subscribing to window messages");
|
|
734
349
|
const onMessage = (evt) => {
|
|
735
350
|
if (evt.source !== window) return;
|
|
736
351
|
const data = evt.data;
|
|
737
352
|
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
353
|
handler(data);
|
|
743
354
|
};
|
|
744
355
|
window.addEventListener("message", onMessage);
|
|
745
|
-
return () =>
|
|
746
|
-
infoLog("web:adapter", "unsubscribing from window messages");
|
|
747
|
-
window.removeEventListener("message", onMessage);
|
|
748
|
-
};
|
|
356
|
+
return () => window.removeEventListener("message", onMessage);
|
|
749
357
|
}
|
|
750
358
|
};
|
|
751
|
-
return createInspector(transport, "web"
|
|
359
|
+
return createInspector(transport, "web");
|
|
752
360
|
}
|
|
753
361
|
|
|
754
362
|
// src/react.tsx
|
|
755
363
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
756
|
-
var InspectorContext = (0,
|
|
757
|
-
function InspectorProvider({
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
364
|
+
var InspectorContext = (0, import_react.createContext)(null);
|
|
365
|
+
function InspectorProvider({
|
|
366
|
+
children,
|
|
367
|
+
adapter
|
|
368
|
+
}) {
|
|
369
|
+
const ownRef = (0, import_react.useRef)(null);
|
|
370
|
+
const useOwn = adapter == null;
|
|
371
|
+
if (useOwn && !ownRef.current && typeof window !== "undefined") {
|
|
372
|
+
ownRef.current = createAdapter();
|
|
373
|
+
}
|
|
374
|
+
const resolved = adapter ?? ownRef.current;
|
|
375
|
+
(0, import_react.useEffect)(() => {
|
|
376
|
+
if (!useOwn) return;
|
|
763
377
|
return () => {
|
|
764
|
-
|
|
765
|
-
|
|
378
|
+
ownRef.current?.dispose();
|
|
379
|
+
ownRef.current = null;
|
|
766
380
|
};
|
|
767
|
-
}, []);
|
|
768
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InspectorContext.Provider, { value:
|
|
381
|
+
}, [useOwn]);
|
|
382
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InspectorContext.Provider, { value: resolved, children });
|
|
769
383
|
}
|
|
770
384
|
function useInspectedMachine(machine, options) {
|
|
771
|
-
const adapter = (0,
|
|
772
|
-
return (0,
|
|
385
|
+
const adapter = (0, import_react.useContext)(InspectorContext);
|
|
386
|
+
return (0, import_react2.useMachine)(machine, {
|
|
773
387
|
...options,
|
|
774
388
|
inspect: adapter?.inspect
|
|
775
389
|
});
|
|
776
390
|
}
|
|
777
391
|
function useInspectedActorRef(machine, options) {
|
|
778
|
-
const adapter = (0,
|
|
779
|
-
return (0,
|
|
392
|
+
const adapter = (0, import_react.useContext)(InspectorContext);
|
|
393
|
+
return (0, import_react2.useActorRef)(machine, {
|
|
780
394
|
...options,
|
|
781
395
|
inspect: adapter?.inspect
|
|
782
396
|
});
|
|
783
397
|
}
|
|
398
|
+
function useRestorableInspectedMachine(machine, options) {
|
|
399
|
+
const adapter = (0, import_react.useContext)(InspectorContext);
|
|
400
|
+
const restoreSnapshotRef = (0, import_react.useRef)(options?.snapshot);
|
|
401
|
+
const [generation, setGeneration] = (0, import_react.useState)(0);
|
|
402
|
+
const actorRef = (0, import_react.useMemo)(() => {
|
|
403
|
+
return (0, import_xstate.createActor)(machine, {
|
|
404
|
+
...options,
|
|
405
|
+
snapshot: restoreSnapshotRef.current,
|
|
406
|
+
inspect: adapter?.inspect
|
|
407
|
+
});
|
|
408
|
+
}, [generation, adapter]);
|
|
409
|
+
(0, import_react.useEffect)(() => {
|
|
410
|
+
actorRef.start();
|
|
411
|
+
return () => {
|
|
412
|
+
actorRef.stop();
|
|
413
|
+
};
|
|
414
|
+
}, [actorRef]);
|
|
415
|
+
(0, import_react.useEffect)(() => {
|
|
416
|
+
if (!adapter?.registerRestore) return;
|
|
417
|
+
return adapter.registerRestore(actorRef.sessionId, (persisted) => {
|
|
418
|
+
restoreSnapshotRef.current = persisted;
|
|
419
|
+
setGeneration((g) => g + 1);
|
|
420
|
+
});
|
|
421
|
+
}, [adapter, actorRef]);
|
|
422
|
+
const snapshot = (0, import_react2.useSelector)(actorRef, (s) => s);
|
|
423
|
+
return [snapshot, actorRef.send, actorRef];
|
|
424
|
+
}
|
|
784
425
|
// Annotate the CommonJS export names for ESM import in node:
|
|
785
426
|
0 && (module.exports = {
|
|
786
427
|
InspectorProvider,
|
|
787
428
|
useInspectedActorRef,
|
|
788
|
-
useInspectedMachine
|
|
429
|
+
useInspectedMachine,
|
|
430
|
+
useRestorableInspectedMachine
|
|
789
431
|
});
|
|
790
432
|
//# sourceMappingURL=react.cjs.map
|