@xstate-devtools/adapter 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -0
- 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 +352 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +14 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/react.cjs +425 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +38 -0
- package/dist/react.d.ts +38 -0
- package/dist/react.js +91 -0
- package/dist/react.js.map +1 -0
- package/dist/server.cjs +493 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +32 -0
- package/dist/server.d.ts +32 -0
- package/dist/server.js +164 -0
- package/dist/server.js.map +1 -0
- package/package.json +55 -6
- package/src/core.test.ts +0 -287
- package/src/core.ts +0 -667
- package/src/index.ts +0 -73
- package/src/logging.test.ts +0 -39
- package/src/logging.ts +0 -40
- package/src/react.tsx +0 -50
- package/src/sanitize.test.ts +0 -68
- package/src/sanitize.ts +0 -70
- package/src/serialize.test.ts +0 -170
- package/src/serialize.ts +0 -148
- package/src/server.ts +0 -310
- package/tsconfig.json +0 -14
package/dist/react.cjs
ADDED
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/react.tsx
|
|
21
|
+
var react_exports = {};
|
|
22
|
+
__export(react_exports, {
|
|
23
|
+
InspectorProvider: () => InspectorProvider,
|
|
24
|
+
useInspectedActorRef: () => useInspectedActorRef,
|
|
25
|
+
useInspectedMachine: () => useInspectedMachine,
|
|
26
|
+
useRestorableInspectedMachine: () => useRestorableInspectedMachine
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(react_exports);
|
|
29
|
+
var import_react = require("react");
|
|
30
|
+
var import_react2 = require("@xstate/react");
|
|
31
|
+
var import_xstate = require("xstate");
|
|
32
|
+
|
|
33
|
+
// src/serialize.ts
|
|
34
|
+
function serializeGuard(guard) {
|
|
35
|
+
if (!guard) return void 0;
|
|
36
|
+
if (typeof guard === "string") return guard;
|
|
37
|
+
if (typeof guard === "function") return guard.name || "(inline)";
|
|
38
|
+
if (typeof guard === "object" && guard !== null) {
|
|
39
|
+
const g = guard;
|
|
40
|
+
return g.type ?? g.name ?? "(inline)";
|
|
41
|
+
}
|
|
42
|
+
return "(inline)";
|
|
43
|
+
}
|
|
44
|
+
function serializeAction(action) {
|
|
45
|
+
if (typeof action === "string") return action;
|
|
46
|
+
if (typeof action === "function") return action.name || "(anonymous)";
|
|
47
|
+
if (typeof action === "object" && action !== null) {
|
|
48
|
+
const a = action;
|
|
49
|
+
return a.type ?? a.name ?? String(action);
|
|
50
|
+
}
|
|
51
|
+
return String(action);
|
|
52
|
+
}
|
|
53
|
+
function serializeTransitionList(transitions) {
|
|
54
|
+
return transitions.map((t) => ({
|
|
55
|
+
eventType: t.eventType ?? "",
|
|
56
|
+
targets: (t.target ?? []).map((n) => n?.id ?? String(n)).filter(Boolean),
|
|
57
|
+
guard: serializeGuard(t.guard),
|
|
58
|
+
actions: (t.actions ?? []).map(serializeAction).filter(Boolean)
|
|
59
|
+
}));
|
|
60
|
+
}
|
|
61
|
+
function serializeInvokes(node) {
|
|
62
|
+
return node.invoke.map((inv) => ({
|
|
63
|
+
id: inv.id ?? "(unknown)",
|
|
64
|
+
src: typeof inv.src === "string" ? inv.src : inv.src?.id ?? inv.src?.name ?? "(inline)"
|
|
65
|
+
}));
|
|
66
|
+
}
|
|
67
|
+
function serializeNode(node) {
|
|
68
|
+
const allTransitions = [];
|
|
69
|
+
if (node.transitions instanceof Map) {
|
|
70
|
+
for (const [, tList] of node.transitions) {
|
|
71
|
+
allTransitions.push(...serializeTransitionList(tList));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const always = Array.isArray(node.always) ? serializeTransitionList(node.always) : [];
|
|
75
|
+
return {
|
|
76
|
+
id: node.id,
|
|
77
|
+
key: node.key,
|
|
78
|
+
type: node.type,
|
|
79
|
+
initial: node.initial?.target?.[0]?.key,
|
|
80
|
+
states: Object.fromEntries(
|
|
81
|
+
Object.entries(node.states ?? {}).map(([k, v]) => [k, serializeNode(v)])
|
|
82
|
+
),
|
|
83
|
+
on: allTransitions,
|
|
84
|
+
always,
|
|
85
|
+
entry: (node.entry ?? []).map(serializeAction).filter(Boolean),
|
|
86
|
+
exit: (node.exit ?? []).map(serializeAction).filter(Boolean),
|
|
87
|
+
invoke: serializeInvokes(node)
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function serializeMachine(machine, sourceLocation) {
|
|
91
|
+
return {
|
|
92
|
+
id: machine.id,
|
|
93
|
+
root: serializeNode(machine.root),
|
|
94
|
+
sourceLocation
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
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;
|
|
110
|
+
}
|
|
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}]`;
|
|
122
|
+
}
|
|
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)]);
|
|
131
|
+
}
|
|
132
|
+
return { __type: "Map", entries };
|
|
133
|
+
}
|
|
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 };
|
|
141
|
+
}
|
|
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);
|
|
157
|
+
}
|
|
158
|
+
return result;
|
|
159
|
+
}
|
|
160
|
+
return String(value);
|
|
161
|
+
}
|
|
162
|
+
function sanitize(value) {
|
|
163
|
+
return sanitizeInner(value, { depth: 0, budget: { n: 0 }, seen: /* @__PURE__ */ new WeakSet() });
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// src/core.ts
|
|
167
|
+
function getSourceLocation() {
|
|
168
|
+
try {
|
|
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+/, "");
|
|
174
|
+
} catch {
|
|
175
|
+
return void 0;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
function serializeSnapshot(snapshot) {
|
|
179
|
+
return {
|
|
180
|
+
value: sanitize(snapshot?.value ?? null),
|
|
181
|
+
context: sanitize(snapshot?.context),
|
|
182
|
+
status: snapshot?.status ?? "active",
|
|
183
|
+
error: snapshot?.error ? sanitize(snapshot.error) : void 0
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
function safeSerializeSnapshot(actorRef) {
|
|
187
|
+
try {
|
|
188
|
+
return serializeSnapshot(actorRef.getSnapshot());
|
|
189
|
+
} catch {
|
|
190
|
+
return { value: null, context: void 0, status: "active" };
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function safePersistedSnapshot(actorRef) {
|
|
194
|
+
const getPersisted = actorRef.getPersistedSnapshot;
|
|
195
|
+
if (typeof getPersisted !== "function") {
|
|
196
|
+
return { error: "Actor does not support getPersistedSnapshot." };
|
|
197
|
+
}
|
|
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}` };
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
var SEQ_KEY = "__xstate_devtools_global_seq__";
|
|
207
|
+
function nextSeq() {
|
|
208
|
+
const g = globalThis;
|
|
209
|
+
const cur = g[SEQ_KEY] ?? 0;
|
|
210
|
+
const next = cur + 1;
|
|
211
|
+
g[SEQ_KEY] = next;
|
|
212
|
+
return next;
|
|
213
|
+
}
|
|
214
|
+
function createInspector(transport, source) {
|
|
215
|
+
const actorRefs = /* @__PURE__ */ new Map();
|
|
216
|
+
const restoreHandlers = /* @__PURE__ */ new Map();
|
|
217
|
+
const prefix = source + ":";
|
|
218
|
+
const tag = (sessionId) => prefix + sessionId;
|
|
219
|
+
const tagOptional = (id) => id ? prefix + id : void 0;
|
|
220
|
+
const stripIfMine = (id) => id.startsWith(prefix) ? id.slice(prefix.length) : null;
|
|
221
|
+
function checkAndNotifyStop(actorRef) {
|
|
222
|
+
let snap;
|
|
223
|
+
try {
|
|
224
|
+
snap = actorRef.getSnapshot();
|
|
225
|
+
} catch {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
if (snap?.status !== "active") {
|
|
229
|
+
transport.send({ type: "XSTATE_ACTOR_STOPPED", sessionId: tag(actorRef.sessionId) });
|
|
230
|
+
actorRefs.delete(actorRef.sessionId);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
const unsubscribe = transport.subscribe((message) => {
|
|
234
|
+
if (message.type === "XSTATE_DISPATCH") {
|
|
235
|
+
const local = stripIfMine(message.sessionId);
|
|
236
|
+
if (local === null) return;
|
|
237
|
+
const ref = actorRefs.get(local);
|
|
238
|
+
if (ref) {
|
|
239
|
+
try {
|
|
240
|
+
ref.send(message.event);
|
|
241
|
+
} catch (e) {
|
|
242
|
+
console.warn("[xstate-devtools] dispatch error:", e);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
} else if (message.type === "XSTATE_REQUEST_PERSISTED") {
|
|
246
|
+
const local = stripIfMine(message.sessionId);
|
|
247
|
+
if (local === null) return;
|
|
248
|
+
const ref = actorRefs.get(local);
|
|
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
|
+
}
|
|
268
|
+
}
|
|
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({
|
|
293
|
+
type: "XSTATE_SNAPSHOT",
|
|
294
|
+
sessionId: tag(inspectionEvent.actorRef.sessionId),
|
|
295
|
+
snapshot: serializeSnapshot(inspectionEvent.snapshot),
|
|
296
|
+
timestamp: Date.now(),
|
|
297
|
+
globalSeq: nextSeq()
|
|
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);
|
|
310
|
+
}
|
|
311
|
+
} catch (e) {
|
|
312
|
+
console.warn("[xstate-devtools] inspection failed, dropping event:", e.message);
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
function registerRestore(sessionId, handler) {
|
|
316
|
+
restoreHandlers.set(sessionId, handler);
|
|
317
|
+
return () => {
|
|
318
|
+
if (restoreHandlers.get(sessionId) === handler) restoreHandlers.delete(sessionId);
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
function dispose() {
|
|
322
|
+
unsubscribe();
|
|
323
|
+
actorRefs.clear();
|
|
324
|
+
restoreHandlers.clear();
|
|
325
|
+
}
|
|
326
|
+
return { inspect, dispose, registerRestore };
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// src/index.ts
|
|
330
|
+
function createAdapter() {
|
|
331
|
+
if (typeof window === "undefined") {
|
|
332
|
+
return { inspect: () => {
|
|
333
|
+
}, dispose: () => {
|
|
334
|
+
}, registerRestore: () => () => {
|
|
335
|
+
} };
|
|
336
|
+
}
|
|
337
|
+
const transport = {
|
|
338
|
+
send(message) {
|
|
339
|
+
window.__XSTATE_DEVTOOLS__?.send({ ...message, __xstateDevtools: true });
|
|
340
|
+
},
|
|
341
|
+
subscribe(handler) {
|
|
342
|
+
const onMessage = (evt) => {
|
|
343
|
+
if (evt.source !== window) return;
|
|
344
|
+
const data = evt.data;
|
|
345
|
+
if (!data?.__xstateDevtools) return;
|
|
346
|
+
handler(data);
|
|
347
|
+
};
|
|
348
|
+
window.addEventListener("message", onMessage);
|
|
349
|
+
return () => window.removeEventListener("message", onMessage);
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
return createInspector(transport, "web");
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// src/react.tsx
|
|
356
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
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;
|
|
370
|
+
return () => {
|
|
371
|
+
ownRef.current?.dispose();
|
|
372
|
+
ownRef.current = null;
|
|
373
|
+
};
|
|
374
|
+
}, [useOwn]);
|
|
375
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InspectorContext.Provider, { value: resolved, children });
|
|
376
|
+
}
|
|
377
|
+
function useInspectedMachine(machine, options) {
|
|
378
|
+
const adapter = (0, import_react.useContext)(InspectorContext);
|
|
379
|
+
return (0, import_react2.useMachine)(machine, {
|
|
380
|
+
...options,
|
|
381
|
+
inspect: adapter?.inspect
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
function useInspectedActorRef(machine, options) {
|
|
385
|
+
const adapter = (0, import_react.useContext)(InspectorContext);
|
|
386
|
+
return (0, import_react2.useActorRef)(machine, {
|
|
387
|
+
...options,
|
|
388
|
+
inspect: adapter?.inspect
|
|
389
|
+
});
|
|
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
|
+
}
|
|
418
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
419
|
+
0 && (module.exports = {
|
|
420
|
+
InspectorProvider,
|
|
421
|
+
useInspectedActorRef,
|
|
422
|
+
useInspectedMachine,
|
|
423
|
+
useRestorableInspectedMachine
|
|
424
|
+
});
|
|
425
|
+
//# sourceMappingURL=react.cjs.map
|
|
@@ -0,0 +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\nfunction serializeGuard(guard: unknown): string | undefined {\n if (!guard) return undefined\n if (typeof guard === 'string') return guard\n if (typeof guard === 'function') return (guard as Function).name || '(inline)'\n if (typeof guard === 'object' && guard !== null) {\n const g = guard as any\n return g.type ?? g.name ?? '(inline)'\n }\n return '(inline)'\n}\n\nfunction serializeAction(action: unknown): string {\n if (typeof action === 'string') return action\n if (typeof action === 'function') return (action as Function).name || '(anonymous)'\n if (typeof action === 'object' && action !== null) {\n const a = action as any\n return a.type ?? a.name ?? String(action)\n }\n return String(action)\n}\n\nfunction serializeTransitionList(transitions: any[]): SerializedTransition[] {\n return transitions.map((t: any) => ({\n eventType: t.eventType ?? '',\n targets: (t.target ?? []).map((n: any) => n?.id ?? String(n)).filter(Boolean),\n guard: serializeGuard(t.guard),\n actions: (t.actions ?? []).map(serializeAction).filter(Boolean),\n }))\n}\n\nfunction serializeInvokes(node: any): SerializedInvoke[] {\n return (node.invoke as any[]).map((inv: any) => ({\n id: inv.id ?? '(unknown)',\n src: typeof inv.src === 'string'\n ? inv.src\n : inv.src?.id ?? inv.src?.name ?? '(inline)',\n }))\n}\n\nfunction serializeNode(node: any): SerializedStateNode {\n const allTransitions: SerializedTransition[] = []\n if (node.transitions instanceof Map) {\n for (const [, tList] of node.transitions) {\n allTransitions.push(...serializeTransitionList(tList))\n }\n }\n\n const always = Array.isArray(node.always) ? serializeTransitionList(node.always) : []\n\n return {\n id: node.id,\n key: node.key,\n type: node.type,\n initial: node.initial?.target?.[0]?.key,\n states: Object.fromEntries(\n Object.entries(node.states ?? {}).map(([k, v]) => [k, serializeNode(v)])\n ),\n on: allTransitions,\n always,\n entry: (node.entry ?? []).map(serializeAction).filter(Boolean),\n exit: (node.exit ?? []).map(serializeAction).filter(Boolean),\n invoke: serializeInvokes(node),\n }\n}\n\nexport function serializeMachine(machine: AnyStateMachine, sourceLocation?: string): SerializedMachine {\n return {\n id: machine.id,\n root: serializeNode(machine.root),\n sourceLocation,\n }\n}\n","// packages/adapter/src/sanitize.ts\n\nconst MAX_DEPTH = 10\nconst MAX_STRING_LENGTH = 500\nconst MAX_ARRAY_LENGTH = 100\n// Hard ceiling on total nodes across the whole tree. The per-level caps above\n// still allow multiplicative blow-up (100^depth) on wide+deep or cross-linked\n// objects, which can produce a string too large for JSON.stringify to handle.\n// This bounds the output regardless of shape.\nconst MAX_NODES = 10000\n\ninterface Ctx {\n depth: number\n /** Shared mutable node counter — the global budget. */\n budget: { n: number }\n /** Objects/arrays seen on the current path + elsewhere, to break cycles and DAGs. */\n seen: WeakSet<object>\n}\n\nfunction sanitizeInner(value: unknown, ctx: Ctx): unknown {\n if (ctx.depth > MAX_DEPTH) return '[MaxDepth]'\n if (++ctx.budget.n > MAX_NODES) return '[Truncated]'\n if (value === null || value === undefined) return value\n if (typeof value === 'boolean' || typeof value === 'number') return value\n if (typeof value === 'string') {\n return value.length > MAX_STRING_LENGTH ? value.slice(0, MAX_STRING_LENGTH) + '…' : value\n }\n if (typeof value === 'function') return `[Function: ${value.name || '(anonymous)'}]`\n if (typeof value === 'symbol') return `[Symbol: ${value.description ?? ''}]`\n if (typeof value === 'bigint') return `[BigInt: ${value}]`\n if (value instanceof Error) return { __type: 'Error', name: value.name, message: value.message }\n if (value instanceof Date) return { __type: 'Date', iso: value.toISOString() }\n if (value instanceof RegExp) return { __type: 'RegExp', source: value.source, flags: value.flags }\n if (value instanceof Promise) return '[Promise]'\n if (value instanceof WeakMap || value instanceof WeakSet) return '[WeakCollection]'\n if (ArrayBuffer.isView(value)) return `[TypedArray: ${(value as any).constructor.name}]`\n // Detect DOM nodes (works in browser and is safe to check)\n if (typeof Node !== 'undefined' && value instanceof Node) {\n return `[DOMNode: ${(value as Element).tagName ?? value.nodeName}]`\n }\n\n // From here on we recurse into containers — guard against shared/circular refs.\n if (ctx.seen.has(value as object)) return '[Circular]'\n ctx.seen.add(value as object)\n const child = { ...ctx, depth: ctx.depth + 1 }\n\n if (value instanceof Map) {\n const entries: [unknown, unknown][] = []\n for (const [k, v] of value as Map<unknown, unknown>) {\n if (entries.length >= MAX_ARRAY_LENGTH) break\n entries.push([sanitizeInner(k, child), sanitizeInner(v, child)])\n }\n return { __type: 'Map', entries }\n }\n if (value instanceof Set) {\n const values: unknown[] = []\n for (const v of value as Set<unknown>) {\n if (values.length >= MAX_ARRAY_LENGTH) break\n values.push(sanitizeInner(v, child))\n }\n return { __type: 'Set', values }\n }\n if (Array.isArray(value)) {\n const sliced = value.slice(0, MAX_ARRAY_LENGTH)\n const result = sliced.map((v) => sanitizeInner(v, child))\n if (value.length > MAX_ARRAY_LENGTH) result.push(`[…${value.length - MAX_ARRAY_LENGTH} more]`)\n return result\n }\n if (typeof value === 'object') {\n const result: Record<string, unknown> = {}\n let count = 0\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (count++ >= MAX_ARRAY_LENGTH) { result['…'] = '[truncated]'; break }\n result[k] = sanitizeInner(v, child)\n }\n return result\n }\n return String(value)\n}\n\nexport function sanitize(value: unknown): unknown {\n return sanitizeInner(value, { depth: 0, budget: { n: 0 }, seen: new WeakSet() })\n}\n","// Transport-agnostic XState inspection core.\n// Browser and server entrypoints supply their own transports.\nimport type { AnyActorRef } from 'xstate'\nimport type {\n ExtensionToPageMessage, PageToExtensionMessage, SerializedSnapshot,\n} from '@xstate-devtools/protocol'\nimport { serializeMachine } from './serialize.js'\nimport { sanitize } from './sanitize.js'\n\nexport type Source = 'web' | 'srv'\n\nexport interface Transport {\n /** Send a protocol message outbound (toward the panel). */\n send: (message: PageToExtensionMessage) => void\n /** Subscribe to inbound dispatch messages from the panel. Returns a teardown. */\n subscribe: (handler: (message: ExtensionToPageMessage) => void) => () => void\n}\n\nfunction getSourceLocation(): string | undefined {\n try {\n const lines = new Error().stack?.split('\\n') ?? []\n const callerLine = lines.find(\n (l, i) => i > 3 && !l.includes('xstate') && !l.includes('adapter')\n )\n return callerLine?.trim().replace(/^at\\s+/, '')\n } catch {\n return undefined\n }\n}\n\nfunction serializeSnapshot(snapshot: any): SerializedSnapshot {\n return {\n value: sanitize(snapshot?.value ?? null) as SerializedSnapshot['value'],\n context: sanitize(snapshot?.context),\n status: snapshot?.status ?? 'active',\n error: snapshot?.error ? sanitize(snapshot.error) : undefined,\n }\n}\n\nfunction safeSerializeSnapshot(actorRef: AnyActorRef): SerializedSnapshot {\n try {\n return serializeSnapshot(actorRef.getSnapshot())\n } catch {\n return { value: null, context: undefined, status: 'active' }\n }\n}\n\n/**\n * Capture XState's persisted snapshot for an actor. Unlike the display snapshot,\n * this is meant to be restorable. We JSON round-trip it to guarantee it survives\n * the transport (and stays serializable); a throw here means the snapshot isn't\n * cleanly persistable, which we report as an error rather than silently dropping.\n */\nfunction safePersistedSnapshot(actorRef: AnyActorRef): { persisted?: unknown; error?: string } {\n const getPersisted = (actorRef as any).getPersistedSnapshot\n if (typeof getPersisted !== 'function') {\n return { error: 'Actor does not support getPersistedSnapshot.' }\n }\n try {\n const raw = getPersisted.call(actorRef)\n if (raw === undefined) return { error: 'No persisted snapshot available.' }\n return { persisted: JSON.parse(JSON.stringify(raw)) }\n } catch (e) {\n return { error: `Snapshot is not JSON-serializable: ${(e as Error).message}` }\n }\n}\n\n// Cached on globalThis so HMR re-evaluating this module doesn't reset the\n// monotonic seq counter mid-session. The panel re-numbers messages on ingest\n// to merge multiple sources, but keeping a stable per-process seq still helps\n// when the panel reconnects to an already-running adapter.\nconst SEQ_KEY = '__xstate_devtools_global_seq__'\nfunction nextSeq(): number {\n const g = globalThis as Record<string, unknown>\n const cur = (g[SEQ_KEY] as number | undefined) ?? 0\n const next = cur + 1\n g[SEQ_KEY] = next\n return next\n}\n\nexport function createInspector(transport: Transport, source: Source) {\n const actorRefs = new Map<string, AnyActorRef>()\n // Owner-registered restore handlers, keyed by local (un-prefixed) sessionId.\n // Populated by useRestorableInspectedMachine; an actor without a handler\n // simply can't be restored (live rewind is opt-in).\n const restoreHandlers = new Map<string, (persisted: unknown) => void>()\n const prefix = source + ':'\n const tag = (sessionId: string) => prefix + sessionId\n const tagOptional = (id: string | undefined) => (id ? prefix + id : undefined)\n const stripIfMine = (id: string): string | null =>\n id.startsWith(prefix) ? id.slice(prefix.length) : null\n\n function checkAndNotifyStop(actorRef: AnyActorRef) {\n let snap: any\n try { snap = actorRef.getSnapshot() } catch { return }\n if (snap?.status !== 'active') {\n transport.send({ type: 'XSTATE_ACTOR_STOPPED', sessionId: tag(actorRef.sessionId) })\n actorRefs.delete(actorRef.sessionId)\n }\n }\n\n const unsubscribe = transport.subscribe((message) => {\n if (message.type === 'XSTATE_DISPATCH') {\n const local = stripIfMine(message.sessionId)\n if (local === null) return // not for this transport source\n const ref = actorRefs.get(local)\n if (ref) {\n try { ref.send(message.event) } catch (e) {\n console.warn('[xstate-devtools] dispatch error:', e)\n }\n }\n } else if (message.type === 'XSTATE_REQUEST_PERSISTED') {\n const local = stripIfMine(message.sessionId)\n if (local === null) return // not for this transport source\n const ref = actorRefs.get(local)\n if (!ref) return\n const { persisted, error } = safePersistedSnapshot(ref)\n transport.send({\n type: 'XSTATE_PERSISTED_SNAPSHOT',\n sessionId: tag(local),\n persisted,\n error,\n timestamp: Date.now(),\n })\n } else if (message.type === 'XSTATE_RESTORE') {\n const local = stripIfMine(message.sessionId)\n if (local === null) return // not for this transport source\n const handler = restoreHandlers.get(local)\n if (handler) {\n try { handler(message.persisted) } catch (e) {\n console.warn('[xstate-devtools] restore error:', e)\n }\n }\n }\n })\n\n const inspect = (inspectionEvent: any) => {\n try {\n if (inspectionEvent.type === '@xstate.actor') {\n const actorRef: AnyActorRef = inspectionEvent.actorRef\n const sessionId: string = actorRef.sessionId\n actorRefs.set(sessionId, actorRef)\n\n // `logic` is internal and not on the public AnyActorRef type.\n const logic = (actorRef as any).logic\n const machine = logic?.root\n ? serializeMachine(logic, getSourceLocation())\n : null\n\n transport.send({\n type: 'XSTATE_ACTOR_REGISTERED',\n sessionId: tag(sessionId),\n parentSessionId: tagOptional((actorRef as any)._parent?.sessionId),\n // actorRef.id is the invoke `id` for invoked actors — lets the debugger\n // nest non-machine actors (promise/callback) under their state.\n actorId: (actorRef as any).id,\n machine,\n snapshot: safeSerializeSnapshot(actorRef),\n globalSeq: nextSeq(),\n timestamp: Date.now(),\n })\n } else if (inspectionEvent.type === '@xstate.snapshot') {\n transport.send({\n type: 'XSTATE_SNAPSHOT',\n sessionId: tag(inspectionEvent.actorRef.sessionId),\n snapshot: serializeSnapshot(inspectionEvent.snapshot),\n timestamp: Date.now(),\n globalSeq: nextSeq(),\n })\n checkAndNotifyStop(inspectionEvent.actorRef)\n } else if (inspectionEvent.type === '@xstate.event') {\n transport.send({\n type: 'XSTATE_EVENT',\n sessionId: tag(inspectionEvent.actorRef.sessionId),\n event: inspectionEvent.event,\n snapshotAfter: safeSerializeSnapshot(inspectionEvent.actorRef),\n timestamp: Date.now(),\n globalSeq: nextSeq(),\n })\n checkAndNotifyStop(inspectionEvent.actorRef)\n }\n } catch (e) {\n // Never let an inspection failure (e.g. an un-serializable snapshot too large\n // for JSON.stringify) propagate back into XState's synchronous inspection\n // callback — that would crash the host actor's start(). Drop the event.\n console.warn('[xstate-devtools] inspection failed, dropping event:', (e as Error).message)\n }\n }\n\n /**\n * Register an owner-side restore handler for an actor. Called by\n * useRestorableInspectedMachine. Returns an unregister function.\n */\n function registerRestore(sessionId: string, handler: (persisted: unknown) => void) {\n restoreHandlers.set(sessionId, handler)\n return () => {\n if (restoreHandlers.get(sessionId) === handler) restoreHandlers.delete(sessionId)\n }\n }\n\n function dispose() {\n unsubscribe()\n actorRefs.clear()\n restoreHandlers.clear()\n }\n\n return { inspect, dispose, registerRestore }\n}\n","// 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.d.cts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as xstate from 'xstate';
|
|
2
|
+
import { AnyStateMachine, ActorOptions, Actor, SnapshotFrom } from 'xstate';
|
|
3
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
|
+
import { ReactNode } from 'react';
|
|
5
|
+
import { createAdapter } from './index.cjs';
|
|
6
|
+
|
|
7
|
+
type AdapterContext = ReturnType<typeof createAdapter> | null;
|
|
8
|
+
/**
|
|
9
|
+
* Provides the inspector adapter to {@link useInspectedMachine} and
|
|
10
|
+
* {@link useRestorableInspectedMachine}. By default it creates and owns a browser
|
|
11
|
+
* adapter. Pass `adapter` to reuse an existing instance (e.g. a module singleton
|
|
12
|
+
* shared with components that call `useMachine(machine, { inspect })` directly) —
|
|
13
|
+
* provided adapters are NOT disposed on unmount, since the caller owns them.
|
|
14
|
+
*/
|
|
15
|
+
declare function InspectorProvider({ children, adapter, }: {
|
|
16
|
+
children: ReactNode;
|
|
17
|
+
adapter?: AdapterContext;
|
|
18
|
+
}): react_jsx_runtime.JSX.Element;
|
|
19
|
+
declare function useInspectedMachine<T extends AnyStateMachine>(machine: T, options?: ActorOptions<T>): [xstate.StateFrom<T>, (event: xstate.EventFromLogic<T>) => void, Actor<T>];
|
|
20
|
+
declare function useInspectedActorRef<T extends AnyStateMachine>(machine: T, options?: ActorOptions<T>): Actor<T>;
|
|
21
|
+
/**
|
|
22
|
+
* Like {@link useInspectedMachine}, but opts the actor into **live rewind** from the
|
|
23
|
+
* DevTools panel. When the panel sends a restore command, this hook recreates the actor
|
|
24
|
+
* from the supplied XState persisted snapshot.
|
|
25
|
+
*
|
|
26
|
+
* Caveats (live rewind is experimental):
|
|
27
|
+
* - The actor is *recreated*, not rewound in place — its identity (sessionId) changes and
|
|
28
|
+
* subscriptions re-fire from the restored state.
|
|
29
|
+
* - Already-performed side effects (network calls, spawned children, messages sent to
|
|
30
|
+
* parents) are NOT undone. This restores machine state, not the outside world.
|
|
31
|
+
*
|
|
32
|
+
* Unlike `useInspectedMachine` (which delegates to `@xstate/react`'s `useMachine`), this
|
|
33
|
+
* hook owns the actor instance so it can recreate it — `useMachine` creates its actor once
|
|
34
|
+
* and ignores later `snapshot` changes.
|
|
35
|
+
*/
|
|
36
|
+
declare function useRestorableInspectedMachine<T extends AnyStateMachine>(machine: T, options?: ActorOptions<T>): [SnapshotFrom<T>, Actor<T>['send'], Actor<T>];
|
|
37
|
+
|
|
38
|
+
export { InspectorProvider, useInspectedActorRef, useInspectedMachine, useRestorableInspectedMachine };
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as xstate from 'xstate';
|
|
2
|
+
import { AnyStateMachine, ActorOptions, Actor, SnapshotFrom } from 'xstate';
|
|
3
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
|
+
import { ReactNode } from 'react';
|
|
5
|
+
import { createAdapter } from './index.js';
|
|
6
|
+
|
|
7
|
+
type AdapterContext = ReturnType<typeof createAdapter> | null;
|
|
8
|
+
/**
|
|
9
|
+
* Provides the inspector adapter to {@link useInspectedMachine} and
|
|
10
|
+
* {@link useRestorableInspectedMachine}. By default it creates and owns a browser
|
|
11
|
+
* adapter. Pass `adapter` to reuse an existing instance (e.g. a module singleton
|
|
12
|
+
* shared with components that call `useMachine(machine, { inspect })` directly) —
|
|
13
|
+
* provided adapters are NOT disposed on unmount, since the caller owns them.
|
|
14
|
+
*/
|
|
15
|
+
declare function InspectorProvider({ children, adapter, }: {
|
|
16
|
+
children: ReactNode;
|
|
17
|
+
adapter?: AdapterContext;
|
|
18
|
+
}): react_jsx_runtime.JSX.Element;
|
|
19
|
+
declare function useInspectedMachine<T extends AnyStateMachine>(machine: T, options?: ActorOptions<T>): [xstate.StateFrom<T>, (event: xstate.EventFromLogic<T>) => void, Actor<T>];
|
|
20
|
+
declare function useInspectedActorRef<T extends AnyStateMachine>(machine: T, options?: ActorOptions<T>): Actor<T>;
|
|
21
|
+
/**
|
|
22
|
+
* Like {@link useInspectedMachine}, but opts the actor into **live rewind** from the
|
|
23
|
+
* DevTools panel. When the panel sends a restore command, this hook recreates the actor
|
|
24
|
+
* from the supplied XState persisted snapshot.
|
|
25
|
+
*
|
|
26
|
+
* Caveats (live rewind is experimental):
|
|
27
|
+
* - The actor is *recreated*, not rewound in place — its identity (sessionId) changes and
|
|
28
|
+
* subscriptions re-fire from the restored state.
|
|
29
|
+
* - Already-performed side effects (network calls, spawned children, messages sent to
|
|
30
|
+
* parents) are NOT undone. This restores machine state, not the outside world.
|
|
31
|
+
*
|
|
32
|
+
* Unlike `useInspectedMachine` (which delegates to `@xstate/react`'s `useMachine`), this
|
|
33
|
+
* hook owns the actor instance so it can recreate it — `useMachine` creates its actor once
|
|
34
|
+
* and ignores later `snapshot` changes.
|
|
35
|
+
*/
|
|
36
|
+
declare function useRestorableInspectedMachine<T extends AnyStateMachine>(machine: T, options?: ActorOptions<T>): [SnapshotFrom<T>, Actor<T>['send'], Actor<T>];
|
|
37
|
+
|
|
38
|
+
export { InspectorProvider, useInspectedActorRef, useInspectedMachine, useRestorableInspectedMachine };
|
package/dist/react.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createAdapter
|
|
3
|
+
} from "./chunk-SUDAY5H3.js";
|
|
4
|
+
import "./chunk-QLRTDBT5.js";
|
|
5
|
+
|
|
6
|
+
// src/react.tsx
|
|
7
|
+
import {
|
|
8
|
+
createContext,
|
|
9
|
+
useContext,
|
|
10
|
+
useRef,
|
|
11
|
+
useEffect,
|
|
12
|
+
useMemo,
|
|
13
|
+
useState
|
|
14
|
+
} from "react";
|
|
15
|
+
import {
|
|
16
|
+
useMachine as useXStateMachine,
|
|
17
|
+
useActorRef as useXStateActorRef,
|
|
18
|
+
useSelector
|
|
19
|
+
} from "@xstate/react";
|
|
20
|
+
import {
|
|
21
|
+
createActor
|
|
22
|
+
} from "xstate";
|
|
23
|
+
import { jsx } from "react/jsx-runtime";
|
|
24
|
+
var InspectorContext = createContext(null);
|
|
25
|
+
function InspectorProvider({
|
|
26
|
+
children,
|
|
27
|
+
adapter
|
|
28
|
+
}) {
|
|
29
|
+
const ownRef = useRef(null);
|
|
30
|
+
const useOwn = adapter == null;
|
|
31
|
+
if (useOwn && !ownRef.current && typeof window !== "undefined") {
|
|
32
|
+
ownRef.current = createAdapter();
|
|
33
|
+
}
|
|
34
|
+
const resolved = adapter ?? ownRef.current;
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (!useOwn) return;
|
|
37
|
+
return () => {
|
|
38
|
+
ownRef.current?.dispose();
|
|
39
|
+
ownRef.current = null;
|
|
40
|
+
};
|
|
41
|
+
}, [useOwn]);
|
|
42
|
+
return /* @__PURE__ */ jsx(InspectorContext.Provider, { value: resolved, children });
|
|
43
|
+
}
|
|
44
|
+
function useInspectedMachine(machine, options) {
|
|
45
|
+
const adapter = useContext(InspectorContext);
|
|
46
|
+
return useXStateMachine(machine, {
|
|
47
|
+
...options,
|
|
48
|
+
inspect: adapter?.inspect
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function useInspectedActorRef(machine, options) {
|
|
52
|
+
const adapter = useContext(InspectorContext);
|
|
53
|
+
return useXStateActorRef(machine, {
|
|
54
|
+
...options,
|
|
55
|
+
inspect: adapter?.inspect
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
function useRestorableInspectedMachine(machine, options) {
|
|
59
|
+
const adapter = useContext(InspectorContext);
|
|
60
|
+
const restoreSnapshotRef = useRef(options?.snapshot);
|
|
61
|
+
const [generation, setGeneration] = useState(0);
|
|
62
|
+
const actorRef = useMemo(() => {
|
|
63
|
+
return createActor(machine, {
|
|
64
|
+
...options,
|
|
65
|
+
snapshot: restoreSnapshotRef.current,
|
|
66
|
+
inspect: adapter?.inspect
|
|
67
|
+
});
|
|
68
|
+
}, [generation, adapter]);
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
actorRef.start();
|
|
71
|
+
return () => {
|
|
72
|
+
actorRef.stop();
|
|
73
|
+
};
|
|
74
|
+
}, [actorRef]);
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
if (!adapter?.registerRestore) return;
|
|
77
|
+
return adapter.registerRestore(actorRef.sessionId, (persisted) => {
|
|
78
|
+
restoreSnapshotRef.current = persisted;
|
|
79
|
+
setGeneration((g) => g + 1);
|
|
80
|
+
});
|
|
81
|
+
}, [adapter, actorRef]);
|
|
82
|
+
const snapshot = useSelector(actorRef, (s) => s);
|
|
83
|
+
return [snapshot, actorRef.send, actorRef];
|
|
84
|
+
}
|
|
85
|
+
export {
|
|
86
|
+
InspectorProvider,
|
|
87
|
+
useInspectedActorRef,
|
|
88
|
+
useInspectedMachine,
|
|
89
|
+
useRestorableInspectedMachine
|
|
90
|
+
};
|
|
91
|
+
//# sourceMappingURL=react.js.map
|