xstate 6.0.0-alpha.2 → 6.0.0-alpha.21

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.
Files changed (54) hide show
  1. package/README.md +19 -17
  2. package/bin/xstate.js +36 -0
  3. package/dist/{StateMachine-64813f46.cjs.js → StateMachine-1b155670.cjs.js} +182 -40
  4. package/dist/{StateMachine-2dcdb1f5.esm.js → StateMachine-3c17fe3e.esm.js} +182 -40
  5. package/dist/{StateMachine-8d22a79c.development.cjs.js → StateMachine-550ff7f2.development.cjs.js} +193 -36
  6. package/dist/{StateMachine-2ea0a7fa.development.esm.js → StateMachine-e25dd61f.development.esm.js} +193 -36
  7. package/dist/declarations/src/State.d.ts +13 -2
  8. package/dist/declarations/src/StateMachine.d.ts +23 -13
  9. package/dist/declarations/src/actions.d.ts +2 -1
  10. package/dist/declarations/src/actors/promise.d.ts +4 -2
  11. package/dist/declarations/src/createActor.d.ts +9 -11
  12. package/dist/declarations/src/createMachine.d.ts +14 -11
  13. package/dist/declarations/src/createMachineFromConfig.d.ts +61 -28
  14. package/dist/declarations/src/fsm.d.ts +74 -0
  15. package/dist/declarations/src/graph/graph.d.ts +3 -3
  16. package/dist/declarations/src/graph/shortestPaths.d.ts +2 -2
  17. package/dist/declarations/src/graph/simplePaths.d.ts +2 -2
  18. package/dist/declarations/src/index.d.ts +6 -5
  19. package/dist/declarations/src/serialize.d.ts +10 -18
  20. package/dist/declarations/src/setup.d.ts +277 -65
  21. package/dist/declarations/src/spawn.d.ts +3 -3
  22. package/dist/declarations/src/stateUtils.d.ts +4 -1
  23. package/dist/declarations/src/system.d.ts +1 -1
  24. package/dist/declarations/src/transition.d.ts +8 -5
  25. package/dist/declarations/src/transitionActions.d.ts +12 -0
  26. package/dist/declarations/src/types.d.ts +237 -102
  27. package/dist/declarations/src/types.v6.d.ts +132 -58
  28. package/dist/declarations/src/utils.d.ts +4 -3
  29. package/dist/{index-93edd3bd.esm.js → index-3f87408c.esm.js} +936 -1389
  30. package/dist/{index-e61170ba.development.esm.js → index-d39fb138.development.esm.js} +968 -1421
  31. package/dist/{index-9cb3b3a0.cjs.js → index-e694228c.cjs.js} +945 -1394
  32. package/dist/{index-f6ef20d1.development.cjs.js → index-ec7c7a2d.development.cjs.js} +977 -1426
  33. package/dist/xstate-actors.cjs.js +1 -1
  34. package/dist/xstate-actors.development.cjs.js +1 -1
  35. package/dist/xstate-actors.development.esm.js +1 -1
  36. package/dist/xstate-actors.esm.js +1 -1
  37. package/dist/xstate-actors.umd.min.js +1 -1
  38. package/dist/xstate-actors.umd.min.js.map +1 -1
  39. package/dist/xstate-graph.cjs.js +2 -2
  40. package/dist/xstate-graph.development.cjs.js +2 -2
  41. package/dist/xstate-graph.development.esm.js +2 -2
  42. package/dist/xstate-graph.esm.js +2 -2
  43. package/dist/xstate-graph.umd.min.js +1 -1
  44. package/dist/xstate-graph.umd.min.js.map +1 -1
  45. package/dist/xstate.cjs.js +1100 -182
  46. package/dist/xstate.cjs.mjs +3 -5
  47. package/dist/xstate.development.cjs.js +1100 -182
  48. package/dist/xstate.development.cjs.mjs +3 -5
  49. package/dist/xstate.development.esm.js +1101 -181
  50. package/dist/xstate.esm.js +1101 -181
  51. package/dist/xstate.umd.min.js +1 -1
  52. package/dist/xstate.umd.min.js.map +1 -1
  53. package/package.json +6 -2
  54. package/dist/declarations/src/atom.d.ts +0 -81
@@ -2,8 +2,8 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var dist_xstateActors = require('./index-9cb3b3a0.cjs.js');
6
- var StateMachine = require('./StateMachine-64813f46.cjs.js');
5
+ var dist_xstateActors = require('./index-e694228c.cjs.js');
6
+ var StateMachine = require('./StateMachine-1b155670.cjs.js');
7
7
 
8
8
  /**
9
9
  * Asserts that the given event object is of the specified type or types. Throws
@@ -91,11 +91,354 @@ function createStateConfig(config) {
91
91
  return config;
92
92
  }
93
93
 
94
+ const emptyImplementations = {
95
+ actions: {},
96
+ actorSources: {},
97
+ guards: {},
98
+ delays: {}
99
+ };
100
+ const emptyExecutableActions = [];
101
+ const emptyRawActions = [];
102
+ const builtInActionSet = new Set(Object.values(dist_xstateActors.builtInActions));
103
+ function toArray(value) {
104
+ return value === undefined ? [] : Array.isArray(value) ? value : [value];
105
+ }
106
+ function resolveContext(context, input) {
107
+ return typeof context === 'function' ? context({
108
+ input
109
+ }) : context ?? {};
110
+ }
111
+ function resolveTransitionContext(context, args) {
112
+ return typeof context === 'function' ? context(args) : context;
113
+ }
114
+ function resolveInput(input, context, event) {
115
+ return typeof input === 'function' ? input({
116
+ context,
117
+ event
118
+ }) : input;
119
+ }
120
+ function mergeContextPatch(context, patch) {
121
+ for (const key of Object.keys(patch)) {
122
+ if (!Object.prototype.hasOwnProperty.call(context, key) || !Object.is(context[key], patch[key])) {
123
+ return {
124
+ ...context,
125
+ ...patch
126
+ };
127
+ }
128
+ }
129
+ return context;
130
+ }
131
+ function createSnapshot(value, context, input, machine, stateInput) {
132
+ return {
133
+ status: 'active',
134
+ output: undefined,
135
+ error: undefined,
136
+ value,
137
+ context,
138
+ input,
139
+ children: {},
140
+ _stateInput: stateInput,
141
+ machine
142
+ };
143
+ }
144
+ function cloneSnapshot(snapshot, value, context, stateInput) {
145
+ return {
146
+ status: snapshot.status,
147
+ output: snapshot.output,
148
+ error: snapshot.error,
149
+ value,
150
+ context,
151
+ input: snapshot.input,
152
+ children: snapshot.children,
153
+ _stateInput: stateInput,
154
+ machine: snapshot.machine
155
+ };
156
+ }
157
+ function stopSnapshot(snapshot) {
158
+ return {
159
+ status: 'stopped',
160
+ output: undefined,
161
+ error: undefined,
162
+ value: snapshot.value,
163
+ context: snapshot.context,
164
+ input: undefined,
165
+ children: snapshot.children,
166
+ _stateInput: snapshot._stateInput,
167
+ machine: snapshot.machine
168
+ };
169
+ }
170
+ function assertNoStringTransitions(config) {
171
+ for (const [stateKey, stateConfig] of Object.entries(config.states)) {
172
+ for (const [eventType, transitionConfig] of Object.entries(stateConfig.on ?? {})) {
173
+ for (const transition of toArray(transitionConfig)) {
174
+ if (typeof transition === 'string') {
175
+ const target = transition;
176
+ throw new Error(`Invalid transition for "${stateKey}.${eventType}": use { target: "${target}" } instead of a string target.`);
177
+ }
178
+ }
179
+ }
180
+ }
181
+ }
182
+ function resolveSimpleEnqueuedActions(rawActions) {
183
+ const executableActions = [];
184
+ for (const action of rawActions) {
185
+ if (!action || typeof action !== 'object' || !('action' in action) || typeof action.action !== 'function' || builtInActionSet.has(action.action) || '_special' in action.action) {
186
+ return undefined;
187
+ }
188
+ executableActions.push({
189
+ type: action.action.name || '(anonymous)',
190
+ params: undefined,
191
+ args: action.args,
192
+ exec: action.args.length ? action.action.bind(null, ...action.args) : action.action
193
+ });
194
+ }
195
+ return executableActions;
196
+ }
197
+ function createFSM(config) {
198
+ const machine = {
199
+ id: config.id ?? '(fsm)',
200
+ implementations: emptyImplementations
201
+ };
202
+ assertNoStringTransitions(config);
203
+ const runActions = (snapshot, event, actorScope, rawActions) => {
204
+ if (!rawActions?.length) {
205
+ return [snapshot, emptyExecutableActions];
206
+ }
207
+ const simpleExecutableActions = resolveSimpleEnqueuedActions(rawActions);
208
+ if (simpleExecutableActions) {
209
+ return [snapshot, simpleExecutableActions];
210
+ }
211
+ return dist_xstateActors.resolveActionsWithContext(snapshot, event, actorScope, rawActions);
212
+ };
213
+ const runStateActions = (snapshot, event, actorScope, actionsConfig, stateInput, internalQueue) => {
214
+ if (!actionsConfig) {
215
+ return [snapshot, emptyExecutableActions];
216
+ }
217
+ const actions = [];
218
+ const enq = dist_xstateActors.createTransitionEnqueue(actorScope, actions, internalQueue, true);
219
+ let context;
220
+ const actionCount = Array.isArray(actionsConfig) ? actionsConfig.length : 1;
221
+ for (let i = 0; i < actionCount; i++) {
222
+ const action = Array.isArray(actionsConfig) ? actionsConfig[i] : actionsConfig;
223
+ const result = action({
224
+ context: context ?? snapshot.context,
225
+ event: event,
226
+ input: stateInput,
227
+ value: snapshot.value,
228
+ self: actorScope.self,
229
+ system: actorScope.system,
230
+ parent: actorScope.self._parent,
231
+ children: snapshot.children
232
+ }, enq);
233
+ if (result?.context !== undefined) {
234
+ const currentContext = context ?? snapshot.context;
235
+ const nextContext = mergeContextPatch(currentContext, result.context);
236
+ if (nextContext !== currentContext) {
237
+ context = nextContext;
238
+ }
239
+ }
240
+ }
241
+ const nextSnapshot = context !== undefined ? cloneSnapshot(snapshot, snapshot.value, context, snapshot._stateInput) : snapshot;
242
+ return runActions(nextSnapshot, event, actorScope, actions);
243
+ };
244
+ const selectTransition = (snapshot, event, actorScope, internalQueue) => {
245
+ const state = config.states[snapshot.value];
246
+ const transitionsConfig = state?.on?.[event.type];
247
+ if (!transitionsConfig) {
248
+ return undefined;
249
+ }
250
+ const transitionCount = Array.isArray(transitionsConfig) ? transitionsConfig.length : 1;
251
+ for (let i = 0; i < transitionCount; i++) {
252
+ const transition = Array.isArray(transitionsConfig) ? transitionsConfig[i] : transitionsConfig;
253
+ const args = {
254
+ context: snapshot.context,
255
+ event,
256
+ input: snapshot.input,
257
+ value: snapshot.value,
258
+ self: actorScope.self,
259
+ system: actorScope.system,
260
+ parent: actorScope.self._parent,
261
+ children: snapshot.children
262
+ };
263
+ if (typeof transition === 'function') {
264
+ const actions = [];
265
+ const enq = dist_xstateActors.createTransitionEnqueue(actorScope, actions, internalQueue, true);
266
+ const result = transition(args, enq);
267
+ if (!result) {
268
+ if (actions.length) {
269
+ return {
270
+ actions
271
+ };
272
+ }
273
+ continue;
274
+ }
275
+ return {
276
+ target: result.target,
277
+ context: result.context,
278
+ input: result.input,
279
+ actions
280
+ };
281
+ }
282
+ if ('guard' in transition && transition.guard && !transition.guard(args)) {
283
+ continue;
284
+ }
285
+ return {
286
+ target: transition.target,
287
+ context: resolveTransitionContext(transition.context, args),
288
+ input: transition.input,
289
+ actions: 'actions' in transition && transition.actions ? toArray(transition.actions) : emptyRawActions
290
+ };
291
+ }
292
+ return undefined;
293
+ };
294
+ const transitionCore = (snapshot, event, actorScope) => {
295
+ if (snapshot.status !== 'active') {
296
+ return [snapshot, []];
297
+ }
298
+ if (event.type === dist_xstateActors.XSTATE_STOP) {
299
+ return [stopSnapshot(snapshot), emptyExecutableActions];
300
+ }
301
+ const stateConfig = config.states[snapshot.value];
302
+ const directTransition = stateConfig?.on?.[event.type];
303
+ if (!directTransition) {
304
+ return [snapshot, emptyExecutableActions];
305
+ }
306
+ if (!Array.isArray(directTransition) && typeof directTransition !== 'function' && !('guard' in directTransition) && !('actions' in directTransition && directTransition.actions) && typeof directTransition.input !== 'function') {
307
+ const target = directTransition.target ?? snapshot.value;
308
+ const stateChanged = target !== snapshot.value;
309
+ if (stateChanged && (stateConfig.exit || config.states[target]?.entry)) ; else {
310
+ const hasContext = directTransition.context !== undefined;
311
+ const hasInput = directTransition.input !== undefined;
312
+ const resolvedContext = resolveTransitionContext(directTransition.context, {
313
+ context: snapshot.context,
314
+ event,
315
+ input: snapshot.input,
316
+ value: snapshot.value,
317
+ self: actorScope.self,
318
+ system: actorScope.system,
319
+ parent: actorScope.self._parent,
320
+ children: snapshot.children
321
+ });
322
+ const context = hasContext && resolvedContext ? mergeContextPatch(snapshot.context, resolvedContext) : snapshot.context;
323
+ if (!stateChanged && context === snapshot.context && !hasInput && snapshot._stateInput === undefined) {
324
+ return [snapshot, emptyExecutableActions];
325
+ }
326
+ return [cloneSnapshot(snapshot, target, context, hasInput ? resolveInput(directTransition.input, context, event) : undefined), emptyExecutableActions];
327
+ }
328
+ }
329
+ if (typeof directTransition === 'function' && directTransition.length < 2 && !stateConfig?.exit) {
330
+ const result = directTransition({
331
+ context: snapshot.context,
332
+ event,
333
+ input: snapshot.input,
334
+ value: snapshot.value,
335
+ self: actorScope.self,
336
+ system: actorScope.system,
337
+ parent: actorScope.self._parent,
338
+ children: snapshot.children
339
+ }, undefined);
340
+ if (result) {
341
+ const target = result.target ?? snapshot.value;
342
+ if (!config.states[target]?.entry) {
343
+ const hasContext = result.context !== undefined;
344
+ const hasInput = result.input !== undefined;
345
+ const context = hasContext && result.context ? mergeContextPatch(snapshot.context, result.context) : snapshot.context;
346
+ if (target === snapshot.value && context === snapshot.context && !hasInput && snapshot._stateInput === undefined) {
347
+ return [snapshot, emptyExecutableActions];
348
+ }
349
+ return [cloneSnapshot(snapshot, target, context, hasInput ? resolveInput(result.input, context, event) : undefined), emptyExecutableActions];
350
+ }
351
+ }
352
+ }
353
+ let nextSnapshot = snapshot;
354
+ const executableActions = [];
355
+ const internalQueue = [event];
356
+ let iterations = 0;
357
+ while (internalQueue.length) {
358
+ if (++iterations > 1000) {
359
+ throw new Error('FSM microstep count exceeded 1000');
360
+ }
361
+ const nextEvent = internalQueue.shift();
362
+ const selected = selectTransition(nextSnapshot, nextEvent, actorScope, internalQueue);
363
+ if (!selected) {
364
+ continue;
365
+ }
366
+ const nextValue = selected.target ?? nextSnapshot.value;
367
+ const stateChanged = nextValue !== nextSnapshot.value;
368
+ if (stateChanged) {
369
+ const [exited, exitActions] = runStateActions(nextSnapshot, nextEvent, actorScope, config.states[nextSnapshot.value]?.exit, nextSnapshot._stateInput, internalQueue);
370
+ nextSnapshot = exited;
371
+ executableActions.push(...exitActions);
372
+ }
373
+ let context = nextSnapshot.context;
374
+ if (selected.context !== undefined) {
375
+ context = mergeContextPatch(context, selected.context);
376
+ }
377
+ const hasInput = selected.input !== undefined;
378
+ const stateInput = hasInput ? resolveInput(selected.input, context, nextEvent) : undefined;
379
+ if (stateChanged || context !== nextSnapshot.context || hasInput || nextSnapshot._stateInput !== undefined) {
380
+ nextSnapshot = cloneSnapshot(nextSnapshot, nextValue, context, stateInput);
381
+ }
382
+ const [afterTransition, transitionActions] = runActions(nextSnapshot, nextEvent, actorScope, selected.actions);
383
+ nextSnapshot = afterTransition;
384
+ executableActions.push(...transitionActions);
385
+ if (stateChanged) {
386
+ const [entered, entryActions] = runStateActions(nextSnapshot, nextEvent, actorScope, config.states[nextValue]?.entry, stateInput, internalQueue);
387
+ nextSnapshot = entered;
388
+ executableActions.push(...entryActions);
389
+ }
390
+ }
391
+ return [nextSnapshot, executableActions];
392
+ };
393
+ const transition = (...args) => {
394
+ const [nextSnapshot, effects] = transitionCore(...args);
395
+ return [nextSnapshot, [...effects, ...dist_xstateActors.deriveDeferredStarts(effects)]];
396
+ };
397
+ const logic = {
398
+ id: config.id,
399
+ config,
400
+ transition,
401
+ initialTransition: (input, actorScope) => {
402
+ const context = resolveContext(config.context, input);
403
+ const snapshot = createSnapshot(config.initial, context, input, machine);
404
+ const internalQueue = [];
405
+ let [nextSnapshot, actions] = runStateActions(snapshot, {
406
+ type: dist_xstateActors.XSTATE_INIT
407
+ }, actorScope, config.states[config.initial]?.entry, undefined, internalQueue);
408
+ if (!actions.length) {
409
+ actions = [];
410
+ }
411
+ while (internalQueue.length) {
412
+ const [raisedSnapshot, raisedActions] = transitionCore(nextSnapshot, internalQueue.shift(), actorScope);
413
+ nextSnapshot = raisedSnapshot;
414
+ actions.push(...raisedActions);
415
+ }
416
+ return [nextSnapshot, [...actions, ...dist_xstateActors.deriveDeferredStarts(actions)]];
417
+ },
418
+ getInitialSnapshot: (actorScope, input) => logic.initialTransition(input, actorScope)[0],
419
+ getPersistedSnapshot: ({
420
+ machine: _,
421
+ ...snapshot
422
+ }) => snapshot,
423
+ restoreSnapshot: snapshot => ({
424
+ ...snapshot,
425
+ machine: machine
426
+ })
427
+ };
428
+ return logic;
429
+ }
430
+
94
431
  function delayToMs(delay) {
95
432
  const parsedDelay = dist_xstateActors.parseDelayToMilliseconds(delay);
96
433
  if (parsedDelay !== undefined) return parsedDelay;
97
434
  return typeof delay === 'string' ? parseFloat(delay) || 0 : delay;
98
435
  }
436
+ function normalizeScxmlEventType(eventType) {
437
+ return /^error(\.|$)/.test(eventType) ? `xstate.${eventType}` : eventType;
438
+ }
439
+ function toScxmlEventName(eventType) {
440
+ return eventType.startsWith('xstate.error.') ? eventType.slice('xstate.'.length) : eventType;
441
+ }
99
442
 
100
443
  /**
101
444
  * Isolated executable-content block. Errors in nested actions stop this block
@@ -103,48 +446,23 @@ function delayToMs(delay) {
103
446
  * separate <onentry>/<onexit> blocks: each is its own block per spec.
104
447
  */
105
448
 
106
- function isUnserializableMarker(value) {
107
- return !!value && typeof value === 'object' && '$unserializable' in value && typeof value.$unserializable === 'string';
449
+ function isExpression(value) {
450
+ return !!value && typeof value === 'object' && typeof value['@expr'] === 'string';
108
451
  }
109
- function assertNoUnresolvedMarkers(value, path = '$') {
110
- if (isUnserializableMarker(value)) {
111
- if (value.$unserializable === 'actor' && path.endsWith('.src')) {
112
- return;
113
- }
114
- throw new Error(`Unresolved ${value.$unserializable} at ${path}`);
115
- }
116
- if (!value || typeof value !== 'object') {
117
- return;
118
- }
119
- if (Array.isArray(value)) {
120
- value.forEach((item, index) => assertNoUnresolvedMarkers(item, `${path}[${index}]`));
121
- return;
122
- }
123
- for (const key of Object.keys(value)) {
124
- const child = value[key];
125
- const isImplementationMarker = path === '$' && (key === 'actions' || key === 'guards' || key === 'actors' || key === 'delays' || key === 'schemas');
126
- if (isImplementationMarker) {
127
- continue;
128
- }
129
- assertNoUnresolvedMarkers(child, `${path}.${key}`);
130
- }
452
+ function isCode(value) {
453
+ return !!value && typeof value === 'object' && typeof value['@code'] === 'string';
131
454
  }
132
- function assertRootImplementationMarkers(json, implementations) {
133
- for (const kind of ['actions', 'guards', 'actors', 'delays']) {
134
- const map = json[kind];
135
- if (!map) {
136
- continue;
137
- }
138
- for (const key of Object.keys(map)) {
139
- const value = map[key];
140
- if (!isUnserializableMarker(value)) {
141
- continue;
142
- }
143
- if (!implementations[kind]?.[key]) {
144
- throw new Error(`Missing ${kind}.${key}`);
145
- }
146
- }
147
- }
455
+ function isResolvable(value) {
456
+ return isExpression(value) || isCode(value);
457
+ }
458
+ function isBuiltInActionType(type) {
459
+ return type.startsWith('@xstate.');
460
+ }
461
+ function isScxmlActionType(type) {
462
+ return type.startsWith('scxml.');
463
+ }
464
+ function toPath(parent, key) {
465
+ return typeof key === 'number' ? `${parent}[${key}]` : `${parent}.${key}`;
148
466
  }
149
467
  function extractSerializableDelays(delays) {
150
468
  const result = {};
@@ -155,6 +473,8 @@ function extractSerializableDelays(delays) {
155
473
  const value = delays[key];
156
474
  if (typeof value === 'number') {
157
475
  result[key] = value;
476
+ } else if (value && typeof value === 'object' && typeof value.duration === 'number') {
477
+ result[key] = value.duration;
158
478
  }
159
479
  }
160
480
  return result;
@@ -163,14 +483,254 @@ function mergeImplementations(json, implementations) {
163
483
  return {
164
484
  actions: implementations.actions ?? {},
165
485
  guards: implementations.guards ?? {},
166
- actors: implementations.actors ?? {},
486
+ actorSources: implementations.actorSources ?? {},
167
487
  delays: {
168
488
  ...extractSerializableDelays(json.delays),
169
489
  ...(implementations.delays ?? {})
490
+ },
491
+ evaluators: implementations.evaluators ?? {}
492
+ };
493
+ }
494
+ function createExpressionResolver(expressionLanguage, implementations) {
495
+ function getEvaluator(value, path) {
496
+ const lang = value['@lang'] ?? expressionLanguage;
497
+ if (!lang) {
498
+ throw new Error(`Missing @exprLang for expression at ${path}`);
499
+ }
500
+ const evaluator = implementations.evaluators[lang];
501
+ if (!evaluator) {
502
+ throw new Error(`Missing evaluator for @lang '${lang}' at ${path}`);
503
+ }
504
+ return evaluator;
505
+ }
506
+ function evaluateResolvable(value, slot, scope, path) {
507
+ const kind = isExpression(value) ? 'expr' : 'code';
508
+ const source = isExpression(value) ? value['@expr'] : value['@code'];
509
+ return getEvaluator(value, path)({
510
+ source,
511
+ kind,
512
+ slot,
513
+ scope,
514
+ path
515
+ });
516
+ }
517
+ function resolveValue(value, slot, scope, path) {
518
+ if (isResolvable(value)) {
519
+ return evaluateResolvable(value, slot, scope, path);
520
+ }
521
+ if (Array.isArray(value)) {
522
+ return value.map((item, index) => resolveValue(item, slot, scope, toPath(path, index)));
523
+ }
524
+ if (!value || typeof value !== 'object') {
525
+ return value;
526
+ }
527
+ const result = {};
528
+ for (const key of Object.keys(value)) {
529
+ result[key] = resolveValue(value[key], slot, scope, toPath(path, key));
170
530
  }
531
+ return result;
532
+ }
533
+ function makeScope(x, extra) {
534
+ return {
535
+ context: x.context,
536
+ event: x.event,
537
+ input: x.input,
538
+ self: x.self,
539
+ children: x.children,
540
+ params: x.params,
541
+ ...extra
542
+ };
543
+ }
544
+ function getDurationConfig(value, path) {
545
+ if (!isResolvable(value)) {
546
+ return value;
547
+ }
548
+ return args => delayToMs(resolveValue(value, 'delay', makeScope(args), path));
549
+ }
550
+ function assertResolvable(value, path) {
551
+ if (isResolvable(value)) {
552
+ getEvaluator(value, path);
553
+ return;
554
+ }
555
+ if (Array.isArray(value)) {
556
+ value.forEach((item, index) => assertResolvable(item, toPath(path, index)));
557
+ return;
558
+ }
559
+ if (!value || typeof value !== 'object') {
560
+ return;
561
+ }
562
+ for (const key of Object.keys(value)) {
563
+ assertResolvable(value[key], toPath(path, key));
564
+ }
565
+ }
566
+ return {
567
+ evaluateResolvable,
568
+ resolveValue,
569
+ makeScope,
570
+ getDurationConfig,
571
+ assertResolvable
171
572
  };
172
573
  }
173
- let _scxmlSessionId = 'session_' + Math.random().toString(36).slice(2);
574
+ function toActionArray(actions) {
575
+ return actions === undefined ? [] : Array.isArray(actions) ? actions : [actions];
576
+ }
577
+ function validateChoiceConfig(choice, path) {
578
+ if (!Array.isArray(choice)) {
579
+ return;
580
+ }
581
+ choice.forEach((branch, index) => {
582
+ if (branch.when === undefined && index !== choice.length - 1) {
583
+ throw new Error(`Choice fallback branch at ${path}[${index}] must be last.`);
584
+ }
585
+ });
586
+ }
587
+ function assertMachineJSON(json, resolvedImplementations, expressionResolver) {
588
+ const {
589
+ assertResolvable
590
+ } = expressionResolver;
591
+ function assertCondition(condition, path) {
592
+ if (!condition) {
593
+ return;
594
+ }
595
+ if (isResolvable(condition)) {
596
+ assertResolvable(condition, path);
597
+ return;
598
+ }
599
+ assertResolvable(condition.params, `${path}.params`);
600
+ if (json.guards?.[condition.type]) {
601
+ assertCondition(json.guards[condition.type].when, `$.guards.${condition.type}.when`);
602
+ return;
603
+ }
604
+ if (!resolvedImplementations.guards[condition.type] && !['scxml.cond', 'xstate.stateIn', 'xstate.not'].includes(condition.type)) {
605
+ throw new Error(`Missing guard implementation "${condition.type}"`);
606
+ }
607
+ }
608
+ function assertAction(action, path, stack = []) {
609
+ if (isResolvable(action)) {
610
+ assertResolvable(action, path);
611
+ return;
612
+ }
613
+ if (!action || typeof action.type !== 'string') {
614
+ throw new Error(`Invalid action at ${path}`);
615
+ }
616
+ assertResolvable(action.params, `${path}.params`);
617
+ if (isBuiltInActionType(action.type) || isScxmlActionType(action.type)) {
618
+ assertResolvable(action, path);
619
+ return;
620
+ }
621
+ const definition = json.actions?.[action.type];
622
+ if (definition) {
623
+ if (stack.includes(action.type)) {
624
+ throw new Error(`Circular action reference: ${stack.concat(action.type).join(' -> ')}`);
625
+ }
626
+ const definitions = Array.isArray(definition) ? definition : [definition];
627
+ definitions.forEach((item, index) => assertAction(item, `${path}.actions.${action.type}${definitions.length > 1 ? `[${index}]` : ''}`, stack.concat(action.type)));
628
+ return;
629
+ }
630
+ if (!resolvedImplementations.actions[action.type]) {
631
+ throw new Error(`Missing action implementation "${action.type}"`);
632
+ }
633
+ }
634
+ function assertActions(actions, path) {
635
+ toActionArray(actions).forEach((action, index) => assertAction(action, `${path}[${index}]`));
636
+ }
637
+ function assertTransition(transition, path) {
638
+ const transitions = Array.isArray(transition) ? transition : transition ? [transition] : [];
639
+ transitions.forEach((t, index) => {
640
+ const transitionPath = Array.isArray(transition) ? `${path}[${index}]` : path;
641
+ if (isResolvable(t)) {
642
+ assertResolvable(t, transitionPath);
643
+ return;
644
+ }
645
+ assertCondition(t.guard, `${transitionPath}.guard`);
646
+ assertActions(t.actions, `${transitionPath}.actions`);
647
+ assertResolvable(t.context, `${transitionPath}.context`);
648
+ assertResolvable(t.input, `${transitionPath}.input`);
649
+ });
650
+ }
651
+ function assertStateNode(node, path) {
652
+ assertResolvable(node.context, `${path}.context`);
653
+ assertResolvable(node.input, `${path}.input`);
654
+ assertResolvable(node.output, `${path}.output`);
655
+ assertResolvable(node.timeout, `${path}.timeout`);
656
+ assertActions(node.entry, `${path}.entry`);
657
+ assertActions(node.exit, `${path}.exit`);
658
+ if (node.type === 'choice') {
659
+ if (!node.choice) {
660
+ throw new Error(`Choice state at ${path} must declare choice.`);
661
+ }
662
+ if (Array.isArray(node.choice)) {
663
+ validateChoiceConfig(node.choice, `${path}.choice`);
664
+ node.choice.forEach((branch, index) => {
665
+ assertCondition(branch.when, `${path}.choice[${index}].when`);
666
+ assertResolvable(branch.context, `${path}.choice[${index}].context`);
667
+ assertResolvable(branch.input, `${path}.choice[${index}].input`);
668
+ });
669
+ } else {
670
+ assertResolvable(node.choice, `${path}.choice`);
671
+ }
672
+ }
673
+ if (isResolvable(node.route)) {
674
+ assertResolvable(node.route, `${path}.route`);
675
+ }
676
+ if (node.invoke) {
677
+ const invokes = Array.isArray(node.invoke) ? node.invoke : [node.invoke];
678
+ invokes.forEach((invoke, index) => {
679
+ const invokePath = `${path}.invoke${Array.isArray(node.invoke) ? `[${index}]` : ''}`;
680
+ const extInv = invoke;
681
+ if (!extInv._nestedMachineJSON && !resolvedImplementations.actorSources[invoke.src]) {
682
+ throw new Error(`Missing actorSource implementation "${invoke.src}"`);
683
+ }
684
+ assertResolvable(invoke.input, `${invokePath}.input`);
685
+ assertResolvable(invoke.timeout, `${invokePath}.timeout`);
686
+ assertTransition(invoke.onDone, `${invokePath}.onDone`);
687
+ assertTransition(invoke.onError, `${invokePath}.onError`);
688
+ assertTransition(invoke.onSnapshot, `${invokePath}.onSnapshot`);
689
+ assertTransition(invoke.onTimeout, `${invokePath}.onTimeout`);
690
+ });
691
+ }
692
+ if (node.on) {
693
+ for (const descriptor of Object.keys(node.on)) {
694
+ assertTransition(node.on[descriptor], `${path}.on.${descriptor}`);
695
+ }
696
+ }
697
+ if (node.after) {
698
+ for (const delay of Object.keys(node.after)) {
699
+ if (Number.isNaN(Number(delay)) && dist_xstateActors.parseDelayToMilliseconds(delay) === undefined && !json.delays?.[delay] && !resolvedImplementations.delays[delay]) {
700
+ throw new Error(`Missing delay implementation "${delay}"`);
701
+ }
702
+ assertTransition(node.after[delay], `${path}.after.${delay}`);
703
+ }
704
+ }
705
+ assertTransition(node.always, `${path}.always`);
706
+ assertTransition(node.onError, `${path}.onError`);
707
+ assertTransition(node.onTimeout, `${path}.onTimeout`);
708
+ if (node.states) {
709
+ for (const key of Object.keys(node.states)) {
710
+ assertStateNode(node.states[key], `${path}.states.${key}`);
711
+ }
712
+ }
713
+ }
714
+ if (json.actions) {
715
+ for (const key of Object.keys(json.actions)) {
716
+ const actions = Array.isArray(json.actions[key]) ? json.actions[key] : [json.actions[key]];
717
+ actions.forEach((action, index) => assertAction(action, `$.actions.${key}${actions.length > 1 ? `[${index}]` : ''}`, [key]));
718
+ }
719
+ }
720
+ if (json.guards) {
721
+ for (const key of Object.keys(json.guards)) {
722
+ assertCondition(json.guards[key].when, `$.guards.${key}.when`);
723
+ }
724
+ }
725
+ if (json.delays) {
726
+ for (const key of Object.keys(json.delays)) {
727
+ const delay = json.delays[key];
728
+ assertResolvable(delay && typeof delay === 'object' && 'duration' in delay ? delay.duration : delay, `$.delays.${key}`);
729
+ }
730
+ }
731
+ assertStateNode(json, '$');
732
+ }
733
+ let _scxmlSessionId = 'session_scxml';
174
734
  let _scxmlMachineName = '';
175
735
 
176
736
  /** Evaluates an SCXML expression with context variables available via `with`. */
@@ -195,7 +755,7 @@ with (context) {
195
755
  }
196
756
  return false;
197
757
  };
198
- const SCXML_ORIGIN = '#_scxml_session';
758
+ const SCXML_ORIGIN = `#_scxml_${_scxmlSessionId}`;
199
759
  const SCXML_ORIGIN_TYPE = 'http://www.w3.org/TR/scxml/#SCXMLEventProcessor';
200
760
  const isExternal = event && event._scxmlExternal;
201
761
  const isInitEvent = event && event.type === '@xstate.init';
@@ -207,7 +767,7 @@ with (context) {
207
767
  const isDoneEvent = event && typeof event.type === 'string' && event.type.startsWith('xstate.done.');
208
768
  const explicitType = event && event._scxmlEventType;
209
769
  const scxmlEvent = event && !isInitEvent ? {
210
- name: event.type,
770
+ name: event._scxmlEventName ?? toScxmlEventName(event.type),
211
771
  type: explicitType || (isExternal ? 'external' : 'internal'),
212
772
  sendid: event._scxmlSendId,
213
773
  origin: isExternal ? SCXML_ORIGIN : undefined,
@@ -243,9 +803,64 @@ return updates;
243
803
  return fn(context, updates);
244
804
  }
245
805
  function createMachineFromConfig(json, implementations = {}) {
246
- assertRootImplementationMarkers(json, implementations);
247
- assertNoUnresolvedMarkers(json);
248
806
  const resolvedImplementations = mergeImplementations(json, implementations);
807
+ const expressionResolver = createExpressionResolver(json['@exprLang'], resolvedImplementations);
808
+ const {
809
+ evaluateResolvable,
810
+ resolveValue,
811
+ makeScope,
812
+ getDurationConfig
813
+ } = expressionResolver;
814
+ function resolveCondition(condition, slot, path) {
815
+ if (!condition) {
816
+ return undefined;
817
+ }
818
+ if (isResolvable(condition)) {
819
+ return args => !!evaluateResolvable(condition, slot, makeScope(args), path);
820
+ }
821
+ return args => {
822
+ const params = resolveValue(condition.params, slot, makeScope(args), `${path}.params`);
823
+ const declarativeGuard = json.guards?.[condition.type];
824
+ if (declarativeGuard) {
825
+ const guard = resolveCondition(declarativeGuard.when, 'guard', `$.guards.${condition.type}.when`);
826
+ return !!guard?.({
827
+ ...args,
828
+ params
829
+ });
830
+ }
831
+ const guardImpl = args.guards?.[condition.type];
832
+ if (!guardImpl) {
833
+ throw new Error(getMissingGuardMessage(condition.type, args.guards ?? {}));
834
+ }
835
+ return guardImpl(args, params);
836
+ };
837
+ }
838
+ function makeChoiceConfig(choice, path) {
839
+ if (!choice) {
840
+ return undefined;
841
+ }
842
+ if (isResolvable(choice)) {
843
+ return args => evaluateResolvable(choice, 'choice', makeScope(args), path);
844
+ }
845
+ validateChoiceConfig(choice, path);
846
+ return args => {
847
+ for (let index = 0; index < choice.length; index++) {
848
+ const branch = choice[index];
849
+ const guard = resolveCondition(branch.when, 'choice', `${path}[${index}].when`);
850
+ if (!guard || guard(args)) {
851
+ return {
852
+ target: branch.target,
853
+ context: branch.context ? resolveValue(branch.context, 'transitionContext', makeScope(args), `${path}[${index}].context`) : undefined,
854
+ input: branch.input !== undefined ? resolveValue(branch.input, 'input', makeScope(args), `${path}[${index}].input`) : undefined,
855
+ description: branch.description,
856
+ reenter: branch.reenter,
857
+ meta: branch.meta
858
+ };
859
+ }
860
+ }
861
+ throw new Error(`Choice state at ${path} did not match any branch.`);
862
+ };
863
+ }
249
864
 
250
865
  // Pending transition actions: set by .to functions, consumed by entry functions.
251
866
  // This bridges SCXML's exit→transition→entry action ordering with XState's
@@ -265,8 +880,30 @@ function createMachineFromConfig(json, implementations = {}) {
265
880
  // <transition cond>). Drained by the next state's entry into the internal
266
881
  // event queue so they're processed before any external events.
267
882
  const pendingPlatformErrors = [];
883
+ function getMissingGuardMessage(type, guards) {
884
+ return `Guard '${type}' is not implemented in machine '${json.id ?? '(machine)'}'. Available guards: ${Object.keys(guards).map(key => `'${key}'`).join(', ') || '(none)'}.`;
885
+ }
886
+ function resolveRouteConfig(route, path) {
887
+ if (!route || typeof route === 'function') {
888
+ return route;
889
+ }
890
+ if (isResolvable(route)) {
891
+ return args => evaluateResolvable(route, 'transition', makeScope(args), path);
892
+ }
893
+ const {
894
+ guard,
895
+ ...routeConfig
896
+ } = route;
897
+ if (!guard) {
898
+ return routeConfig;
899
+ }
900
+ const resolvedGuard = resolveCondition({
901
+ type: guard
902
+ }, 'guard', path);
903
+ return args => resolvedGuard(args) ? routeConfig : undefined;
904
+ }
268
905
  function iterNode(node, nodeKey) {
269
- const originalEntryActions = node.entry;
906
+ const originalEntryActions = toActionArray(node.entry);
270
907
  const stateId = node.id || nodeKey;
271
908
 
272
909
  // Wrap entry to first execute any pending transition actions, then normal entry.
@@ -280,8 +917,10 @@ function createMachineFromConfig(json, implementations = {}) {
280
917
  while (pendingPlatformErrors.length) {
281
918
  const err = pendingPlatformErrors.shift();
282
919
  enq.raise({
283
- type: 'error.execution',
920
+ type: 'xstate.error.execution',
921
+ error: err,
284
922
  _scxmlEventType: 'platform',
923
+ _scxmlEventName: 'error.execution',
285
924
  _scxmlEventData: err
286
925
  });
287
926
  }
@@ -329,7 +968,7 @@ function createMachineFromConfig(json, implementations = {}) {
329
968
  }
330
969
 
331
970
  // Execute normal entry actions
332
- if (originalEntryActions?.length) {
971
+ if (originalEntryActions.length) {
333
972
  const mergedX = context ? {
334
973
  ...x,
335
974
  context
@@ -352,7 +991,7 @@ function createMachineFromConfig(json, implementations = {}) {
352
991
  description: node.description,
353
992
  tags: node.tags,
354
993
  input: node.input,
355
- timeout: node.timeout,
994
+ timeout: getDurationConfig(node.timeout, `$.states.${nodeKey}.timeout`),
356
995
  states: node.states ? Object.entries(node.states).reduce((acc, [key, value]) => {
357
996
  acc[key] = iterNode(value, key);
358
997
  return acc;
@@ -362,18 +1001,27 @@ function createMachineFromConfig(json, implementations = {}) {
362
1001
  return acc;
363
1002
  }, {}) : undefined,
364
1003
  always: node.always ? getTransitionConfig(node.always) : undefined,
365
- choice: node.choice ? getTransitionConfig(node.choice) : undefined,
366
- route: node.route,
1004
+ onError: node.onError ? getTransitionConfig(node.onError) : undefined,
1005
+ choice: makeChoiceConfig(node.choice, `$.states.${nodeKey}.choice`),
1006
+ route: resolveRouteConfig(node.route, `$.states.${nodeKey}.route`),
367
1007
  after: node.after ? Object.entries(node.after).reduce((acc, [key, value]) => {
368
1008
  acc[key] = getTransitionConfig(value);
369
1009
  return acc;
370
1010
  }, {}) : undefined,
371
1011
  onTimeout: node.onTimeout ? getTransitionConfig(node.onTimeout) : undefined,
372
- entry: entryFn,
373
- exit: node.exit ? iterActions(node.exit) : undefined,
1012
+ entry: node.type === 'choice' ? undefined : entryFn,
1013
+ exit: node.exit ? iterActions(toActionArray(node.exit)) : undefined,
374
1014
  invoke: node.invoke ? iterInvokeConfigs(node.invoke) : undefined,
375
1015
  meta: node.meta,
376
- output: node._scxmlDonedata ? makeDonedataOutput(node._scxmlDonedata) : node.output
1016
+ output: node._scxmlDonedata ? makeDonedataOutput(node._scxmlDonedata) : isResolvable(node.output) ? ({
1017
+ context,
1018
+ event,
1019
+ self
1020
+ }) => evaluateResolvable(node.output, 'output', {
1021
+ context,
1022
+ event,
1023
+ self
1024
+ }, `$.states.${nodeKey}.output`) : node.output
377
1025
  };
378
1026
  return nodeConfig;
379
1027
  }
@@ -426,23 +1074,18 @@ function createMachineFromConfig(json, implementations = {}) {
426
1074
  let src;
427
1075
  if (extInv._nestedMachineJSON) {
428
1076
  src = createMachineFromConfig(extInv._nestedMachineJSON, resolvedImplementations);
429
- } else if (isUnserializableMarker(inv.src)) {
430
- src = inv.src.id ? resolvedImplementations.actors[inv.src.id] : undefined;
431
- if (!src) {
432
- throw new Error(`Missing actors.${inv.src.id ?? ''}`);
433
- }
434
1077
  } else {
435
- src = inv.src;
1078
+ src = resolvedImplementations.actorSources[inv.src] ?? inv.src;
436
1079
  }
437
1080
  return {
438
1081
  src,
439
1082
  id: inv.id,
440
- systemId: inv.systemId,
441
- input: inv.input,
1083
+ registryKey: inv.registryKey,
1084
+ input: inv.input !== undefined ? args => resolveValue(inv.input, 'input', makeScope(args), '$.invoke.input') : undefined,
442
1085
  onDone: inv.onDone ? getTransitionConfig(inv.onDone) : undefined,
443
1086
  onError: inv.onError ? getTransitionConfig(inv.onError) : undefined,
444
1087
  onSnapshot: inv.onSnapshot ? getTransitionConfig(inv.onSnapshot) : undefined,
445
- timeout: inv.timeout,
1088
+ timeout: getDurationConfig(inv.timeout, '$.invoke.timeout'),
446
1089
  onTimeout: inv.onTimeout ? getTransitionConfig(inv.onTimeout) : undefined
447
1090
  };
448
1091
  });
@@ -456,8 +1099,16 @@ function createMachineFromConfig(json, implementations = {}) {
456
1099
  function raiseErrorExecution(state, tagname, err) {
457
1100
  const message = err instanceof Error ? err.message : typeof err === 'string' ? err : 'unknown error';
458
1101
  state.enq.raise({
459
- type: 'error.execution',
1102
+ type: 'xstate.error.execution',
1103
+ error: {
1104
+ tagname,
1105
+ message,
1106
+ line: NaN,
1107
+ column: NaN,
1108
+ reason: message
1109
+ },
460
1110
  _scxmlEventType: 'platform',
1111
+ _scxmlEventName: 'error.execution',
461
1112
  _scxmlEventData: {
462
1113
  tagname,
463
1114
  message,
@@ -468,8 +1119,31 @@ function createMachineFromConfig(json, implementations = {}) {
468
1119
  });
469
1120
  state.errored = true;
470
1121
  }
1122
+ function executeActionDefinition(action, x, enq, params, parentState, stack) {
1123
+ const definition = json.actions?.[action.type];
1124
+ if (!definition) {
1125
+ enq(x.actions[action.type], params);
1126
+ return {
1127
+ context: undefined,
1128
+ errored: parentState.errored
1129
+ };
1130
+ }
1131
+ if (stack.includes(action.type)) {
1132
+ raiseErrorExecution(parentState, 'action', new Error(`Circular action reference: ${stack.concat(action.type).join(' -> ')}`));
1133
+ return {
1134
+ context: undefined,
1135
+ errored: true
1136
+ };
1137
+ }
1138
+ const definitions = Array.isArray(definition) ? definition : [definition];
1139
+ return executeActions(definitions, {
1140
+ ...x,
1141
+ params
1142
+ }, enq, parentState, stack.concat(action.type));
1143
+ }
1144
+
471
1145
  /** Execute an array of SCXML action JSON descriptors with context and enqueue. */
472
- function executeActions(actions, x, enq, parentState) {
1146
+ function executeActions(actions, x, enq, parentState, stack = []) {
473
1147
  const state = parentState ?? {
474
1148
  enq,
475
1149
  errored: false
@@ -477,22 +1151,34 @@ function createMachineFromConfig(json, implementations = {}) {
477
1151
  let context;
478
1152
  for (const action of actions) {
479
1153
  if (state.errored) break;
480
- if (isBuiltInActionJSON(action)) {
1154
+ if (isResolvable(action)) {
1155
+ const result = evaluateResolvable(action, 'action', makeScope(x, {
1156
+ params: x.params,
1157
+ enq
1158
+ }), '$.actions');
1159
+ if (result && typeof result === 'object' && 'context' in result && result.context) {
1160
+ context ??= {};
1161
+ Object.assign(context, result.context);
1162
+ }
1163
+ } else if (isBuiltInActionJSON(action)) {
481
1164
  switch (action.type) {
482
1165
  case '@xstate.raise':
483
1166
  {
484
1167
  // Tag as external if it has a delay (from <send>, not <raise>).
485
1168
  // Attach _scxmlSendId so _event.sendid can be read in expressions.
486
1169
  const isExternal = action.delay !== undefined;
1170
+ const resolvedEvent = resolveValue(action.event, 'actionParams', makeScope(x, {
1171
+ params: x.params
1172
+ }), '$.actions.event');
487
1173
  const event = isExternal || action.id !== undefined ? {
488
- ...action.event,
1174
+ ...resolvedEvent,
489
1175
  ...(isExternal ? {
490
1176
  _scxmlExternal: true
491
1177
  } : {}),
492
1178
  ...(action.id !== undefined ? {
493
1179
  _scxmlSendId: action.id
494
1180
  } : {})
495
- } : action.event;
1181
+ } : resolvedEvent;
496
1182
  enq.raise(event, {
497
1183
  id: action.id,
498
1184
  delay: action.delay
@@ -506,11 +1192,15 @@ function createMachineFromConfig(json, implementations = {}) {
506
1192
  enq.log(...action.args);
507
1193
  break;
508
1194
  case '@xstate.emit':
509
- enq.emit(action.event);
1195
+ enq.emit(resolveValue(action.event, 'actionParams', makeScope(x, {
1196
+ params: x.params
1197
+ }), '$.actions.event'));
510
1198
  break;
511
1199
  case '@xstate.assign':
512
1200
  context ??= {};
513
- Object.assign(context, action.context);
1201
+ Object.assign(context, resolveValue(action.context, 'transitionContext', makeScope(x, {
1202
+ params: x.params
1203
+ }), '$.actions.context'));
514
1204
  break;
515
1205
  default:
516
1206
  throw new Error(`Unknown built-in action: ${action.type}`);
@@ -549,8 +1239,10 @@ function createMachineFromConfig(json, implementations = {}) {
549
1239
  let delay;
550
1240
  try {
551
1241
  eventType = scxmlAction.eventexpr ? evaluateExpr(mergedContext, scxmlAction.eventexpr, x.event, x.self) : scxmlAction.event || 'unknown';
1242
+ eventType = normalizeScxmlEventType(eventType);
552
1243
  eventData = {
553
- type: eventType
1244
+ type: eventType,
1245
+ _scxmlEventName: toScxmlEventName(eventType)
554
1246
  };
555
1247
  if (scxmlAction.params) {
556
1248
  for (const param of scxmlAction.params) {
@@ -590,25 +1282,50 @@ function createMachineFromConfig(json, implementations = {}) {
590
1282
  const childRef = x.children?.[childId];
591
1283
  if (childRef) {
592
1284
  enq.sendTo(childRef, eventData);
1285
+ } else if (childId.startsWith('scxml_') && childId !== `scxml_${_scxmlSessionId}`) {
1286
+ const message = `Unable to dispatch event to target: ${target}`;
1287
+ enq.raise({
1288
+ type: 'xstate.error.communication',
1289
+ error: {
1290
+ tagname: 'send',
1291
+ message,
1292
+ line: NaN,
1293
+ column: NaN,
1294
+ reason: message
1295
+ },
1296
+ _scxmlEventType: 'platform',
1297
+ _scxmlEventName: 'error.communication',
1298
+ _scxmlEventData: {
1299
+ tagname: 'send',
1300
+ message,
1301
+ line: NaN,
1302
+ column: NaN,
1303
+ reason: message
1304
+ }
1305
+ });
593
1306
  } else {
594
- // Not a known child (e.g. #_scxml_sessionid) → self-raise
595
- if (delay !== undefined) {
596
- eventData._scxmlExternal = true;
597
- }
598
- enq.raise(eventData, {
1307
+ // This SCXML session id uses the external event queue.
1308
+ eventData._scxmlExternal = true;
1309
+ enq.sendTo(x.self, eventData, {
599
1310
  id: scxmlAction.id,
600
1311
  delay
601
1312
  });
602
1313
  }
603
1314
  } else {
604
- // Self-send or no special target: raise as external event
605
- if (delay !== undefined) {
1315
+ // #_internal uses the internal queue; self-send/no target use the
1316
+ // external event queue.
1317
+ if (isInternalTarget) {
1318
+ enq.raise(eventData, {
1319
+ id: scxmlAction.id,
1320
+ delay
1321
+ });
1322
+ } else {
606
1323
  eventData._scxmlExternal = true;
1324
+ enq.sendTo(x.self, eventData, {
1325
+ id: scxmlAction.id,
1326
+ delay
1327
+ });
607
1328
  }
608
- enq.raise(eventData, {
609
- id: scxmlAction.id,
610
- delay
611
- });
612
1329
  }
613
1330
  } else if (action.type === 'scxml.cancel') {
614
1331
  const scxmlAction = action;
@@ -738,7 +1455,14 @@ function createMachineFromConfig(json, implementations = {}) {
738
1455
  }
739
1456
  }
740
1457
  } else {
741
- enq(x.actions[action.type], action.params);
1458
+ const params = resolveValue(action.params, 'actionParams', makeScope(x, {
1459
+ params: x.params
1460
+ }), '$.actions.params');
1461
+ const result = executeActionDefinition(action, x, enq, params, state, stack);
1462
+ if (result.context) {
1463
+ context ??= {};
1464
+ Object.assign(context, result.context);
1465
+ }
742
1466
  }
743
1467
  }
744
1468
  return {
@@ -759,30 +1483,63 @@ function createMachineFromConfig(json, implementations = {}) {
759
1483
  // a separate XState transition with its own guard and optional .to.
760
1484
  // This ensures guards are evaluated by XState's evaluateCandidate (once,
761
1485
  // with pre-exit context) and NOT re-evaluated in computeEntrySet.
762
- return transitions.map(t => {
1486
+ return transitions.map((t, index) => {
1487
+ if (isResolvable(t)) {
1488
+ return (x, enq) => evaluateResolvable(t, 'transition', makeScope(x, {
1489
+ enq
1490
+ }), `$.transition${transitions.length > 1 ? `[${index}]` : ''}`);
1491
+ }
763
1492
  const target = Array.isArray(t.target) ? t.target[0] : t.target;
764
1493
  const targetConfig = t.target;
1494
+ const guard = resolveCondition(t.guard, 'guard', '$.transition.guard');
1495
+ const resolveTransitionContext = x => t.context ? resolveValue(t.context, 'transitionContext', makeScope(x), '$.transition.context') : undefined;
1496
+ const resolveTransitionInput = x => t.input !== undefined ? resolveValue(t.input, 'input', makeScope(x), '$.transition.input') : undefined;
765
1497
 
766
1498
  // No guard and no actions: simple static config
767
- if (!t.guard && !t.actions?.length) {
1499
+ if (!guard && !t.actions?.length) {
1500
+ if (t.context) {
1501
+ return {
1502
+ to: x => ({
1503
+ target: targetConfig,
1504
+ context: resolveTransitionContext(x),
1505
+ reenter: t.reenter
1506
+ }),
1507
+ description: t.description,
1508
+ meta: t.meta,
1509
+ input: t.input !== undefined ? resolveTransitionInput : undefined
1510
+ };
1511
+ }
768
1512
  return {
769
1513
  target: targetConfig,
770
1514
  description: t.description,
771
1515
  reenter: t.reenter,
772
1516
  meta: t.meta,
773
- input: t.input
1517
+ input: t.input !== undefined ? resolveTransitionInput : undefined
774
1518
  };
775
1519
  }
776
1520
 
777
1521
  // Guard but no actions: static config with guard
778
- if (t.guard && !t.actions?.length) {
1522
+ if (guard && !t.actions?.length) {
1523
+ if (t.context) {
1524
+ return {
1525
+ guard,
1526
+ to: x => ({
1527
+ target: targetConfig,
1528
+ context: resolveTransitionContext(x),
1529
+ reenter: t.reenter
1530
+ }),
1531
+ description: t.description,
1532
+ meta: t.meta,
1533
+ input: t.input !== undefined ? resolveTransitionInput : undefined
1534
+ };
1535
+ }
779
1536
  return {
780
1537
  target: targetConfig,
781
- guard: t.guard,
1538
+ guard,
782
1539
  description: t.description,
783
1540
  reenter: t.reenter,
784
1541
  meta: t.meta,
785
- input: t.input
1542
+ input: t.input !== undefined ? resolveTransitionInput : undefined
786
1543
  };
787
1544
  }
788
1545
 
@@ -791,12 +1548,13 @@ function createMachineFromConfig(json, implementations = {}) {
791
1548
  // For parallel (entries exist), first entry re-executes all in document order.
792
1549
  if (!target) {
793
1550
  return {
794
- guard: t.guard,
1551
+ guard,
795
1552
  description: t.description,
796
1553
  reenter: t.reenter,
797
1554
  meta: t.meta,
798
- input: t.input,
1555
+ input: t.input !== undefined ? resolveTransitionInput : undefined,
799
1556
  to: (x, enq) => {
1557
+ const context = resolveTransitionContext(x);
800
1558
  if (t.actions?.length) {
801
1559
  // Track for parallel re-execution (dedup by reference)
802
1560
  if (!allTransitionActions.includes(t.actions)) {
@@ -808,11 +1566,16 @@ function createMachineFromConfig(json, implementations = {}) {
808
1566
  const result = executeActions(t.actions, x, enq);
809
1567
  if (result.context) {
810
1568
  return {
811
- context: result.context
1569
+ context: {
1570
+ ...context,
1571
+ ...result.context
1572
+ }
812
1573
  };
813
1574
  }
814
1575
  }
815
- return {};
1576
+ return context ? {
1577
+ context
1578
+ } : {};
816
1579
  }
817
1580
  };
818
1581
  }
@@ -822,12 +1585,13 @@ function createMachineFromConfig(json, implementations = {}) {
822
1585
  // already validated it. The .to just stores actions for entry to execute.
823
1586
  // Map by target state ID so parallel transitions each get their own actions.
824
1587
  return {
825
- guard: t.guard,
1588
+ guard,
826
1589
  description: t.description,
827
1590
  reenter: t.reenter,
828
1591
  meta: t.meta,
829
- input: t.input,
1592
+ input: t.input !== undefined ? resolveTransitionInput : undefined,
830
1593
  to: (_x, _enq) => {
1594
+ const context = resolveTransitionContext(_x);
831
1595
  if (t.actions?.length) {
832
1596
  const targetId = target.replace(/^#/, '');
833
1597
  pendingTransitionActionsMap[targetId] = t.actions;
@@ -838,18 +1602,32 @@ function createMachineFromConfig(json, implementations = {}) {
838
1602
  }
839
1603
  return {
840
1604
  target: targetConfig,
1605
+ context,
841
1606
  reenter: t.reenter
842
1607
  };
843
1608
  }
844
1609
  };
845
1610
  });
846
1611
  }
1612
+ if (json.delays) {
1613
+ for (const key of Object.keys(json.delays)) {
1614
+ const delay = json.delays[key];
1615
+ if (typeof delay === 'number') {
1616
+ resolvedImplementations.delays[key] = delay;
1617
+ } else if (typeof delay === 'string') {
1618
+ resolvedImplementations.delays[key] = delayToMs(delay);
1619
+ } else if (delay && typeof delay === 'object') {
1620
+ resolvedImplementations.delays[key] = args => delayToMs(resolveValue(delay.duration, 'delay', makeScope(args), `$.delays.${key}.duration`));
1621
+ }
1622
+ }
1623
+ }
1624
+ assertMachineJSON(json, resolvedImplementations, expressionResolver);
847
1625
  const rootNodeConfig = iterNode(json);
848
1626
  const contextConfig = json.context ? {
849
- context: json.context
1627
+ context: args => resolveValue(json.context, 'context', args, '$.context')
850
1628
  } : {};
851
1629
  _scxmlMachineName = json.id || '';
852
- _scxmlSessionId = 'session_' + Math.random().toString(36).slice(2);
1630
+ _scxmlSessionId = 'session_scxml';
853
1631
  const machine = createMachine({
854
1632
  ...rootNodeConfig,
855
1633
  ...contextConfig,
@@ -894,7 +1672,7 @@ function createMachineFromConfig(json, implementations = {}) {
894
1672
  },
895
1673
  'xstate.not': (args, params) => {
896
1674
  const inner = params?.guard;
897
- const innerImpl = inner && providedGuards[inner.type];
1675
+ const innerImpl = inner && args.guards?.[inner.type];
898
1676
  if (!innerImpl) {
899
1677
  throw new Error(`Guard '${inner?.type}' referenced by 'xstate.not' is not implemented.`);
900
1678
  }
@@ -903,7 +1681,7 @@ function createMachineFromConfig(json, implementations = {}) {
903
1681
  };
904
1682
  const provided = machine.provide({
905
1683
  actions: resolvedImplementations.actions,
906
- actors: resolvedImplementations.actors,
1684
+ actorSources: resolvedImplementations.actorSources,
907
1685
  guards: {
908
1686
  ...providedGuards,
909
1687
  ...resolvedImplementations.guards
@@ -917,7 +1695,7 @@ function createMachineFromConfig(json, implementations = {}) {
917
1695
  return provided;
918
1696
  }
919
1697
  function isBuiltInActionJSON(action) {
920
- return action.type.startsWith('@xstate.');
1698
+ return !isResolvable(action) && action.type.startsWith('@xstate.');
921
1699
  }
922
1700
 
923
1701
  /**
@@ -925,24 +1703,17 @@ function isBuiltInActionJSON(action) {
925
1703
  *
926
1704
  * `machineConfigToJSON` converts a machine config into a JSON-safe structure
927
1705
  * (the `MachineJSON` shape accepted by `createMachineFromConfig`). The boundary
928
- * between serializable structure and runtime implementations is explicit: any
929
- * value that cannot be represented as data (inline functions, actor logic,
930
- * runtime schemas) is replaced with an `{ "$unserializable": <kind> }` marker
931
- * rather than silently dropped.
932
- *
933
- * A machine definition is fully portable iff its JSON contains no
934
- * `$unserializable` markers; reviving a definition that has markers requires
935
- * re-providing those implementations (e.g. via `machine.provide(...)` or the
936
- * `actions`/`guards`/`actors` maps on `createMachineFromConfig` revival).
1706
+ * between serializable structure and runtime implementations is explicit:
1707
+ * functions are represented as `@code` source objects, while actor logic,
1708
+ * runtime schemas, and other non-data runtime values are omitted.
937
1709
  */
938
1710
 
939
1711
  /**
940
1712
  * Returns the JSON-serializable definition of a machine.
941
1713
  *
942
- * Inline functions, actor logic, and runtime schemas cannot be represented as
943
- * data; they appear as `{ "$unserializable": ... }` markers. A machine created
944
- * via `createMachineFromConfig` returns its original JSON config (lossless
945
- * round-trip):
1714
+ * Inline functions are represented as `{ "@code": string, "@lang": "ts" }`. A
1715
+ * machine created via `createMachineFromConfig` returns its original JSON
1716
+ * config (lossless round-trip):
946
1717
  *
947
1718
  * ```ts
948
1719
  * import { serializeMachine, createMachineFromConfig } from 'xstate';
@@ -957,48 +1728,57 @@ function serializeMachine(machine) {
957
1728
  return machine._json ?? machineConfigToJSON(machine.config);
958
1729
  }
959
1730
 
960
- /**
961
- * State-node config keys that are part of the serializable definition. Keys
962
- * outside this list (unknown/internal properties) are dropped.
963
- */
964
- const STATE_NODE_KEYS = ['id', 'key', 'type', 'history', 'description', 'target', 'version', 'initial', 'context', 'on', 'after', 'always', 'choice', 'route', 'onTimeout', 'timeout', 'entry', 'exit', 'meta', 'output', 'tags', 'input', '_scxmlDonedata'];
965
- function marker(kind, id) {
966
- const m = {
967
- $unserializable: kind
1731
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
1732
+ function codeExpression(fn) {
1733
+ return {
1734
+ '@code': fn.toString(),
1735
+ '@lang': 'ts'
968
1736
  };
969
- if (id) {
970
- m.id = id;
971
- }
972
- return m;
1737
+ }
1738
+ function isActorLogic(value) {
1739
+ return !!value && typeof value === 'object' && typeof value.transition === 'function' && typeof value.getInitialSnapshot === 'function';
1740
+ }
1741
+ function isRuntimeSchema(value) {
1742
+ return !!value && typeof value === 'object' && '~standard' in value;
973
1743
  }
974
1744
 
975
- /** JSON-safe deep copy of a plain value; functions become markers. */
1745
+ /** JSON-safe deep copy of a plain value; functions become code expressions. */
976
1746
  function valueToJSON(value) {
977
1747
  if (typeof value === 'function') {
978
- return marker('function', value.name || undefined);
1748
+ return codeExpression(value);
979
1749
  }
980
1750
  if (value === null || typeof value !== 'object') {
981
- return typeof value === 'bigint' || typeof value === 'symbol' ? marker('value') : value;
1751
+ return typeof value === 'bigint' || typeof value === 'symbol' ? undefined : value;
1752
+ }
1753
+ if (isActorLogic(value)) {
1754
+ return undefined;
1755
+ }
1756
+ if (isRuntimeSchema(value)) {
1757
+ return undefined;
982
1758
  }
983
1759
  if (Array.isArray(value)) {
984
- return value.map(valueToJSON);
1760
+ return value.map(valueToJSON).filter(item => item !== undefined);
985
1761
  }
986
1762
  if (value.constructor !== Object && value.constructor !== undefined) {
987
1763
  // Class instances (actor logic, schemas, dates, ...) are not portable.
988
- return marker('value');
1764
+ return undefined;
989
1765
  }
990
1766
  const result = {};
991
1767
  for (const key of Object.keys(value)) {
992
1768
  const v = value[key];
993
1769
  if (v !== undefined) {
994
- result[key] = valueToJSON(v);
1770
+ const jsonValue = valueToJSON(v);
1771
+ if (jsonValue !== undefined) {
1772
+ result[key] = jsonValue;
1773
+ }
995
1774
  }
996
1775
  }
997
1776
  return result;
998
1777
  }
999
1778
  function invokeToJSON(invoke) {
1000
1779
  if (Array.isArray(invoke)) {
1001
- return invoke.map(invokeToJSON);
1780
+ const values = invoke.map(invokeToJSON).filter(value => value !== undefined);
1781
+ return values.length ? values : undefined;
1002
1782
  }
1003
1783
  const def = invoke;
1004
1784
  const result = {};
@@ -1007,37 +1787,47 @@ function invokeToJSON(invoke) {
1007
1787
  if (value === undefined) {
1008
1788
  continue;
1009
1789
  }
1010
- result[key] = key === 'src' && typeof value !== 'string' ?
1011
- // Actor logic keeps its dedicated marker kind so revival knows the
1012
- // contract is an actor, not a plain function.
1013
- marker('actor', value.id) : valueToJSON(value);
1790
+ result[key] = key === 'src' && typeof value !== 'string' ? value.id : valueToJSON(value);
1791
+ if (result[key] === undefined) {
1792
+ delete result[key];
1793
+ }
1014
1794
  }
1015
- return result;
1795
+ return result.src === undefined ? undefined : result;
1016
1796
  }
1017
- function implementationsToJSON(map, kind) {
1797
+ function implementationsToJSON(map) {
1018
1798
  if (!map) {
1019
1799
  return undefined;
1020
1800
  }
1021
- // Keys are preserved — they are the contract a revived machine must
1022
- // fulfill via provide() — while values become markers (or stay, for
1023
- // JSON-safe values like numeric delays).
1024
1801
  const result = {};
1025
1802
  for (const key of Object.keys(map)) {
1026
1803
  const value = map[key];
1027
- result[key] = typeof value === 'function' ? marker('function', key) : value && typeof value === 'object' ? marker(kind, key) : value;
1804
+ if (typeof value === 'function') {
1805
+ result[key] = undefined;
1806
+ } else {
1807
+ result[key] = valueToJSON(value);
1808
+ }
1809
+ if (result[key] === undefined) {
1810
+ delete result[key];
1811
+ }
1028
1812
  }
1029
1813
  return result;
1030
1814
  }
1031
1815
  function stateNodeConfigToJSON(config) {
1032
1816
  const result = {};
1033
- for (const key of STATE_NODE_KEYS) {
1817
+ for (const key of Object.keys(config)) {
1818
+ if (key === 'states' || key === 'invoke') {
1819
+ continue;
1820
+ }
1034
1821
  const value = config[key];
1035
1822
  if (value !== undefined) {
1036
1823
  result[key] = valueToJSON(value);
1037
1824
  }
1038
1825
  }
1039
1826
  if (config.invoke !== undefined) {
1040
- result.invoke = invokeToJSON(config.invoke);
1827
+ const invoke = invokeToJSON(config.invoke);
1828
+ if (invoke !== undefined) {
1829
+ result.invoke = invoke;
1830
+ }
1041
1831
  }
1042
1832
  if (config.states) {
1043
1833
  const states = {};
@@ -1051,7 +1841,7 @@ function stateNodeConfigToJSON(config) {
1051
1841
 
1052
1842
  /**
1053
1843
  * Converts a machine config (as passed to `createMachine`) to its JSON-safe
1054
- * definition. See module docs for the `$unserializable` marker contract.
1844
+ * definition.
1055
1845
  */
1056
1846
  function machineConfigToJSON(config) {
1057
1847
  const result = stateNodeConfigToJSON(config);
@@ -1064,16 +1854,24 @@ function machineConfigToJSON(config) {
1064
1854
  const value = config.schemas[key];
1065
1855
  if (value && typeof value === 'object' && !('~standard' in value)) {
1066
1856
  // Map-form schemas (events/emitted): preserve event-type keys.
1067
- schemas[key] = implementationsToJSON(value, 'schema');
1857
+ schemas[key] = implementationsToJSON(value);
1068
1858
  } else {
1069
- schemas[key] = marker('schema', key);
1859
+ schemas[key] = valueToJSON(value);
1860
+ }
1861
+ if (schemas[key] === undefined) {
1862
+ delete schemas[key];
1070
1863
  }
1071
1864
  }
1072
1865
  result.schemas = schemas;
1073
1866
  }
1074
- for (const key of ['actions', 'guards', 'actors', 'delays']) {
1867
+ for (const key of ['actions', 'guards', 'actorSources', 'delays']) {
1075
1868
  if (config[key]) {
1076
- result[key] = implementationsToJSON(config[key], key === 'actors' ? 'actor' : 'function');
1869
+ const value = implementationsToJSON(config[key]);
1870
+ if (value && Object.keys(value).length) {
1871
+ result[key] = value;
1872
+ } else {
1873
+ delete result[key];
1874
+ }
1077
1875
  }
1078
1876
  }
1079
1877
  return result;
@@ -1176,6 +1974,28 @@ function isTypeSchema(value) {
1176
1974
 
1177
1975
  /** State schema with optional schemas.input and nested states */
1178
1976
 
1977
+ /**
1978
+ * The sibling state schemas of a dotted path: the children of the path's
1979
+ * parent. A bare transition target resolves relative to the parent, so the
1980
+ * valid targets for a path's config are its siblings. For a dotless (top-level)
1981
+ * path the siblings are the root states.
1982
+ */
1983
+
1984
+ // dotless path: siblings are the current level's states
1985
+
1986
+ /**
1987
+ * Resolves a dotted state path (e.g. `'parent.child'`) into the leaf
1988
+ * `SetupStateSchema` it addresses, or `never` if any segment is missing.
1989
+ */
1990
+
1991
+ /** Union of every addressable dotted path into a setup states tree */
1992
+
1993
+ /**
1994
+ * Shared body of both `createStateConfig` overloads: the
1995
+ * `StateNodeConfigWithNestedInput` instantiation whose only varying parts are
1996
+ * the leading sibling-schemas and state-schema arguments.
1997
+ */
1998
+
1179
1999
  /** Extracts input type from a state schema */
1180
2000
 
1181
2001
  /**
@@ -1231,33 +2051,142 @@ function isTypeSchema(value) {
1231
2051
  * });
1232
2052
  * ```
1233
2053
  */
2054
+
1234
2055
  function setup(config = {}) {
1235
2056
  const {
1236
2057
  states = {},
1237
- schemas
2058
+ schemas,
2059
+ actions,
2060
+ actorSources,
2061
+ guards,
2062
+ delays
1238
2063
  } = config;
1239
2064
  return {
2065
+ extend(extension) {
2066
+ return setup(mergeSetupConfigs(config, extension));
2067
+ },
1240
2068
  createMachine(machineConfig) {
1241
2069
  const configSchemas = machineConfig.schemas;
1242
- const mergedSchemas = schemas || configSchemas ? {
1243
- ...configSchemas,
1244
- ...schemas
1245
- } : undefined;
1246
- return new StateMachine.StateMachine(mergedSchemas ? {
2070
+ const mergedSchemas = mergeSchemas(configSchemas, schemas);
2071
+ const mergedActions = mergeMaps(actions, machineConfig.actions);
2072
+ const mergedActorSources = mergeMaps(actorSources, machineConfig.actorSources);
2073
+ const mergedGuards = mergeMaps(guards, machineConfig.guards);
2074
+ const mergedDelays = mergeMaps(delays, machineConfig.delays);
2075
+ return new StateMachine.StateMachine({
1247
2076
  ...machineConfig,
1248
- schemas: mergedSchemas
1249
- } : machineConfig);
2077
+ ...(mergedSchemas ? {
2078
+ schemas: mergedSchemas
2079
+ } : undefined),
2080
+ ...(mergedActions ? {
2081
+ actions: mergedActions
2082
+ } : undefined),
2083
+ ...(mergedActorSources ? {
2084
+ actorSources: mergedActorSources
2085
+ } : undefined),
2086
+ ...(mergedGuards ? {
2087
+ guards: mergedGuards
2088
+ } : undefined),
2089
+ ...(mergedDelays ? {
2090
+ delays: mergedDelays
2091
+ } : undefined)
2092
+ });
2093
+ },
2094
+ createStateConfig(...args) {
2095
+ return args.length > 1 ? args[1] : args[0];
2096
+ },
2097
+ states,
2098
+ schemas: schemas ?? {}
2099
+ };
2100
+ }
2101
+ function createSystem(_config = {}) {
2102
+ const runtimeRef = {};
2103
+ const pendingObservers = [];
2104
+ const flushObservers = () => {
2105
+ const runtime = runtimeRef.current;
2106
+ if (!runtime) {
2107
+ return;
2108
+ }
2109
+ for (const entry of pendingObservers) {
2110
+ if (entry.active && !entry.subscription) {
2111
+ entry.subscription = runtime.inspect(entry.observer);
2112
+ }
2113
+ }
2114
+ };
2115
+ return {
2116
+ createActor(logic, options) {
2117
+ const actor = dist_xstateActors.createActor(logic, {
2118
+ ...options,
2119
+ _systemRef: runtimeRef
2120
+ });
2121
+ flushObservers();
2122
+ return actor;
2123
+ },
2124
+ get(key) {
2125
+ return runtimeRef.current?.get(key);
1250
2126
  },
1251
- createStateConfig(stateConfig) {
1252
- return stateConfig;
2127
+ getAll() {
2128
+ return runtimeRef.current?.getAll() ?? {};
2129
+ },
2130
+ inspect(observer) {
2131
+ const runtime = runtimeRef.current;
2132
+ if (runtime) {
2133
+ return runtime.inspect(observer);
2134
+ }
2135
+ const entry = {
2136
+ observer: observer,
2137
+ active: true
2138
+ };
2139
+ pendingObservers.push(entry);
2140
+ return {
2141
+ unsubscribe() {
2142
+ entry.active = false;
2143
+ entry.subscription?.unsubscribe();
2144
+ }
2145
+ };
1253
2146
  },
1254
- states
2147
+ setup(config) {
2148
+ return config ? setup(config) : setup();
2149
+ }
2150
+ };
2151
+ }
2152
+ function mergeMaps(left, right) {
2153
+ return left || right ? {
2154
+ ...left,
2155
+ ...right
2156
+ } : undefined;
2157
+ }
2158
+ function mergeSchemas(left, right) {
2159
+ if (!left && !right) {
2160
+ return undefined;
2161
+ }
2162
+ return {
2163
+ ...left,
2164
+ ...right,
2165
+ events: mergeMaps(left?.events, right?.events),
2166
+ actions: mergeMaps(left?.actions, right?.actions),
2167
+ guards: mergeMaps(left?.guards, right?.guards),
2168
+ emitted: mergeMaps(left?.emitted, right?.emitted),
2169
+ children: mergeMaps(left?.children, right?.children)
2170
+ };
2171
+ }
2172
+ function mergeSetupConfigs(base, extension) {
2173
+ return {
2174
+ ...base,
2175
+ ...extension,
2176
+ schemas: mergeSchemas(base.schemas, extension.schemas),
2177
+ states: mergeMaps(base.states, extension.states),
2178
+ actions: mergeMaps(base.actions, extension.actions),
2179
+ actorSources: mergeMaps(base.actorSources, extension.actorSources),
2180
+ guards: mergeMaps(base.guards, extension.guards),
2181
+ delays: mergeMaps(base.delays, extension.delays)
1255
2182
  };
1256
2183
  }
1257
2184
 
1258
2185
  /** @internal */
1259
2186
  function createInertActorScope(actorLogic) {
1260
- const self = dist_xstateActors.createActor(actorLogic);
2187
+ const self = dist_xstateActors.createActor(actorLogic, {
2188
+ _inert: true
2189
+ });
1261
2190
  const inertActorScope = {
1262
2191
  self: self,
1263
2192
  defer: () => {},
@@ -1275,7 +2204,7 @@ function createInertActorScope(actorLogic) {
1275
2204
  /** @deprecated Use `initialTransition(…)` instead. */
1276
2205
  function getInitialSnapshot(actorLogic, ...[input]) {
1277
2206
  const actorScope = createInertActorScope(actorLogic);
1278
- return actorLogic.getInitialSnapshot(actorScope, input);
2207
+ return actorLogic.initialTransition(input, actorScope)[0];
1279
2208
  }
1280
2209
 
1281
2210
  /**
@@ -1565,14 +2494,9 @@ let SpecialTargets = /*#__PURE__*/function (SpecialTargets) {
1565
2494
  * This is a pure function that does not execute `actions`.
1566
2495
  */
1567
2496
  function transition(logic, snapshot, event) {
1568
- const executableActions = [];
1569
2497
  const actorScope = createInertActorScope(logic);
1570
- actorScope.actionExecutor = action => {
1571
- executableActions.push(action);
1572
- };
1573
- const transitionResult = logic.transition(snapshot, event, actorScope);
1574
- const [nextSnapshot, effects] = Array.isArray(transitionResult) ? transitionResult : [transitionResult, []];
1575
- return [nextSnapshot, executableActions.concat(effects)];
2498
+ const [nextSnapshot, effects] = logic.transition(snapshot, event, actorScope);
2499
+ return [nextSnapshot, effects];
1576
2500
  }
1577
2501
 
1578
2502
  /**
@@ -1583,12 +2507,8 @@ function transition(logic, snapshot, event) {
1583
2507
  * This is a pure function that does not execute `actions`.
1584
2508
  */
1585
2509
  function initialTransition(logic, ...[input]) {
1586
- const executableActions = [];
1587
2510
  const actorScope = createInertActorScope(logic);
1588
- actorScope.actionExecutor = action => {
1589
- executableActions.push(action);
1590
- };
1591
- const nextSnapshot = logic.getInitialSnapshot(actorScope, input);
2511
+ const [nextSnapshot, executableActions] = logic.initialTransition(input, actorScope);
1592
2512
  return [nextSnapshot, executableActions];
1593
2513
  }
1594
2514
 
@@ -1787,20 +2707,16 @@ exports.TimeoutError = dist_xstateActors.TimeoutError;
1787
2707
  exports.__unsafe_getAllOwnEventDescriptors = dist_xstateActors.getAllOwnEventDescriptors;
1788
2708
  exports.checkStateIn = dist_xstateActors.checkStateIn;
1789
2709
  exports.createActor = dist_xstateActors.createActor;
1790
- exports.createAsyncAtom = dist_xstateActors.createAsyncAtom;
1791
2710
  exports.createAsyncLogic = dist_xstateActors.createAsyncLogic;
1792
- exports.createAtom = dist_xstateActors.createAtom;
1793
- exports.createAtomConfig = dist_xstateActors.createAtomConfig;
1794
2711
  exports.createCallbackLogic = dist_xstateActors.createCallbackLogic;
1795
2712
  exports.createEmptyActor = dist_xstateActors.createEmptyActor;
1796
2713
  exports.createEventObservableLogic = dist_xstateActors.createEventObservableLogic;
1797
2714
  exports.createListenerLogic = dist_xstateActors.createListenerLogic;
1798
2715
  exports.createLogic = dist_xstateActors.createLogic;
1799
2716
  exports.createObservableLogic = dist_xstateActors.createObservableLogic;
1800
- exports.createReducerAtom = dist_xstateActors.createReducerAtom;
1801
2717
  exports.createSubscriptionLogic = dist_xstateActors.createSubscriptionLogic;
1802
2718
  exports.getStateNodes = dist_xstateActors.getStateNodes;
1803
- exports.isAtom = dist_xstateActors.isAtom;
2719
+ exports.isBuiltInExecutableAction = dist_xstateActors.isBuiltInExecutableAction;
1804
2720
  exports.isMachineSnapshot = dist_xstateActors.isMachineSnapshot;
1805
2721
  exports.listenerLogic = dist_xstateActors.listenerLogic;
1806
2722
  exports.matchesState = dist_xstateActors.matchesState;
@@ -1812,9 +2728,11 @@ exports.StateNode = StateMachine.StateNode;
1812
2728
  exports.SimulatedClock = SimulatedClock;
1813
2729
  exports.SpecialTargets = SpecialTargets;
1814
2730
  exports.assertEvent = assertEvent;
2731
+ exports.createFSM = createFSM;
1815
2732
  exports.createMachine = createMachine;
1816
2733
  exports.createMachineFromConfig = createMachineFromConfig;
1817
2734
  exports.createStateConfig = createStateConfig;
2735
+ exports.createSystem = createSystem;
1818
2736
  exports.getInitialMicrosteps = getInitialMicrosteps;
1819
2737
  exports.getInitialSnapshot = getInitialSnapshot;
1820
2738
  exports.getMicrosteps = getMicrosteps;