@doeixd/machine 0.0.6 → 0.0.8

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.
@@ -20,20 +20,37 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var src_exports = {};
22
22
  __export(src_exports, {
23
+ BoundMachine: () => BoundMachine,
23
24
  META_KEY: () => META_KEY,
24
25
  MachineBase: () => MachineBase,
25
26
  MultiMachineBase: () => MultiMachineBase,
26
27
  RUNTIME_META: () => RUNTIME_META,
27
28
  action: () => action,
29
+ bindTransitions: () => bindTransitions,
30
+ branch: () => branch,
31
+ call: () => call,
32
+ chain: () => chain,
33
+ combine: () => combine,
34
+ combineFactories: () => combineFactories,
35
+ compose: () => compose,
36
+ composeTyped: () => composeTyped,
28
37
  createAsyncMachine: () => createAsyncMachine,
38
+ createCustomMiddleware: () => createCustomMiddleware,
29
39
  createEnsemble: () => createEnsemble,
40
+ createEvent: () => createEvent,
41
+ createFetchMachine: () => createFetchMachine,
30
42
  createFlow: () => createFlow,
31
43
  createMachine: () => createMachine,
32
44
  createMachineBuilder: () => createMachineBuilder,
33
45
  createMachineFactory: () => createMachineFactory,
46
+ createMiddleware: () => createMiddleware,
47
+ createMiddlewareRegistry: () => createMiddlewareRegistry,
34
48
  createMultiMachine: () => createMultiMachine,
35
49
  createMutableMachine: () => createMutableMachine,
50
+ createParallelMachine: () => createParallelMachine,
51
+ createPipeline: () => createPipeline,
36
52
  createRunner: () => createRunner,
53
+ delegateToChild: () => delegateToChild,
37
54
  describe: () => describe,
38
55
  extendTransitions: () => extendTransitions,
39
56
  extractFromInstance: () => extractFromInstance,
@@ -43,13 +60,21 @@ __export(src_exports, {
43
60
  extractStateNode: () => extractStateNode,
44
61
  generateChart: () => generateChart,
45
62
  generateStatechart: () => generateStatechart,
63
+ guard: () => guard,
46
64
  guarded: () => guarded,
47
65
  hasState: () => hasState,
66
+ inDevelopment: () => inDevelopment,
48
67
  invoke: () => invoke,
68
+ isConditionalMiddleware: () => isConditionalMiddleware,
69
+ isMiddlewareFn: () => isMiddlewareFn,
70
+ isState: () => isState,
71
+ logState: () => logState,
49
72
  matchMachine: () => matchMachine,
73
+ mergeContext: () => mergeContext,
50
74
  metadata: () => metadata,
51
75
  next: () => next,
52
76
  overrideTransitions: () => overrideTransitions,
77
+ pipeTransitions: () => pipeTransitions,
53
78
  run: () => run,
54
79
  runAsync: () => runAsync,
55
80
  runMachine: () => runMachine,
@@ -60,7 +85,22 @@ __export(src_exports, {
60
85
  setContext: () => setContext,
61
86
  step: () => step,
62
87
  stepAsync: () => stepAsync,
88
+ toggle: () => toggle,
63
89
  transitionTo: () => transitionTo,
90
+ when: () => when,
91
+ whenContext: () => whenContext,
92
+ whenGuard: () => whenGuard,
93
+ withAnalytics: () => withAnalytics,
94
+ withDebugging: () => withDebugging,
95
+ withErrorReporting: () => withErrorReporting,
96
+ withHistory: () => withHistory,
97
+ withLogging: () => withLogging,
98
+ withPerformanceMonitoring: () => withPerformanceMonitoring,
99
+ withPermissions: () => withPermissions,
100
+ withRetry: () => withRetry,
101
+ withSnapshot: () => withSnapshot,
102
+ withTimeTravel: () => withTimeTravel,
103
+ withValidation: () => withValidation,
64
104
  yieldMachine: () => yieldMachine
65
105
  });
66
106
  module.exports = __toCommonJS(src_exports);
@@ -164,9 +204,9 @@ function describe(_text, transition) {
164
204
  });
165
205
  return transition;
166
206
  }
167
- function guarded(guard, transition) {
207
+ function guarded(guard2, transition) {
168
208
  attachRuntimeMeta(transition, {
169
- guards: [guard]
209
+ guards: [guard2]
170
210
  });
171
211
  return transition;
172
212
  }
@@ -187,6 +227,62 @@ function action(action2, transition) {
187
227
  });
188
228
  return transition;
189
229
  }
230
+ function guard(condition, transition, options = {}) {
231
+ const { onFail = "throw", errorMessage, description } = options;
232
+ const fullOptions = { ...options, onFail, errorMessage, description };
233
+ const guardedTransition = async function(...args) {
234
+ const isMachine = typeof this === "object" && "context" in this;
235
+ const ctx = isMachine ? this.context : this;
236
+ const conditionResult = await Promise.resolve(condition(ctx, ...args));
237
+ if (conditionResult) {
238
+ const contextForTransition = isMachine ? this.context : this;
239
+ return transition.apply(contextForTransition, args);
240
+ } else {
241
+ if (onFail === "throw") {
242
+ const message = errorMessage || "Guard condition failed";
243
+ throw new Error(message);
244
+ } else if (onFail === "ignore") {
245
+ if (isMachine) {
246
+ return this;
247
+ } else {
248
+ throw new Error('Cannot use "ignore" mode with context-only binding. Use full machine binding or provide fallback.');
249
+ }
250
+ } else if (typeof onFail === "function") {
251
+ if (isMachine) {
252
+ return onFail.apply(this, args);
253
+ } else {
254
+ throw new Error("Cannot use function fallback with context-only binding. Use full machine binding.");
255
+ }
256
+ } else {
257
+ return onFail;
258
+ }
259
+ }
260
+ };
261
+ Object.defineProperty(guardedTransition, "__guard", { value: true, enumerable: false });
262
+ Object.defineProperty(guardedTransition, "condition", { value: condition, enumerable: false });
263
+ Object.defineProperty(guardedTransition, "transition", { value: transition, enumerable: false });
264
+ Object.defineProperty(guardedTransition, "options", { value: fullOptions, enumerable: false });
265
+ attachRuntimeMeta(guardedTransition, {
266
+ description: description || "Runtime guarded transition",
267
+ guards: [{ name: "runtime_guard", description: description || "Runtime condition check" }]
268
+ });
269
+ return guardedTransition;
270
+ }
271
+ function whenGuard(condition) {
272
+ return {
273
+ /**
274
+ * Define the transition to execute when the condition passes.
275
+ * Returns a guarded transition that can optionally have an else clause.
276
+ */
277
+ do(transition) {
278
+ const guarded2 = guard(condition, transition);
279
+ guarded2.else = function(fallback) {
280
+ return guard(condition, transition, { onFail: fallback });
281
+ };
282
+ return guarded2;
283
+ }
284
+ };
285
+ }
190
286
  function metadata(_meta, value) {
191
287
  return value;
192
288
  }
@@ -256,17 +352,17 @@ function parseInvokeService(obj) {
256
352
  }
257
353
  return service;
258
354
  }
259
- function extractFromCallExpression(call, verbose = false) {
260
- if (!import_ts_morph.Node.isCallExpression(call)) {
355
+ function extractFromCallExpression(call2, verbose = false) {
356
+ if (!import_ts_morph.Node.isCallExpression(call2)) {
261
357
  return null;
262
358
  }
263
- const expression = call.getExpression();
359
+ const expression = call2.getExpression();
264
360
  const fnName = import_ts_morph.Node.isIdentifier(expression) ? expression.getText() : null;
265
361
  if (!fnName) {
266
362
  return null;
267
363
  }
268
364
  const metadata2 = {};
269
- const args = call.getArguments();
365
+ const args = call2.getArguments();
270
366
  switch (fnName) {
271
367
  case "transitionTo":
272
368
  if (args[0]) {
@@ -286,9 +382,9 @@ function extractFromCallExpression(call, verbose = false) {
286
382
  break;
287
383
  case "guarded":
288
384
  if (args[0]) {
289
- const guard = parseObjectLiteral(args[0]);
290
- if (Object.keys(guard).length > 0) {
291
- metadata2.guards = [guard];
385
+ const guard2 = parseObjectLiteral(args[0]);
386
+ if (Object.keys(guard2).length > 0) {
387
+ metadata2.guards = [guard2];
292
388
  }
293
389
  }
294
390
  if (args[1] && import_ts_morph.Node.isCallExpression(args[1])) {
@@ -406,6 +502,26 @@ function analyzeStateNode(classSymbol, verbose = false) {
406
502
  }
407
503
  return chartNode;
408
504
  }
505
+ function analyzeStateNodeWithNesting(className, classSymbol, sourceFile, childConfig, verbose = false) {
506
+ const stateNode = analyzeStateNode(classSymbol, verbose);
507
+ if (childConfig) {
508
+ if (verbose) {
509
+ console.error(` 👪 Analyzing children for state: ${className}`);
510
+ }
511
+ stateNode.initial = childConfig.initialState;
512
+ stateNode.states = {};
513
+ for (const childClassName of childConfig.classes) {
514
+ const childClassDeclaration = sourceFile.getClass(childClassName);
515
+ if (childClassDeclaration) {
516
+ const childSymbol = childClassDeclaration.getSymbolOrThrow();
517
+ stateNode.states[childClassName] = analyzeStateNode(childSymbol, verbose);
518
+ } else {
519
+ console.warn(`⚠️ Warning: Child class '${childClassName}' not found.`);
520
+ }
521
+ }
522
+ }
523
+ return stateNode;
524
+ }
409
525
  function extractMachine(config, project, verbose = false) {
410
526
  if (verbose) {
411
527
  console.error(`
@@ -416,6 +532,45 @@ function extractMachine(config, project, verbose = false) {
416
532
  if (!sourceFile) {
417
533
  throw new Error(`Source file not found: ${config.input}`);
418
534
  }
535
+ if (config.parallel) {
536
+ if (verbose) {
537
+ console.error(` ⏹️ Parallel machine detected. Analyzing regions.`);
538
+ }
539
+ const parallelChart = {
540
+ id: config.id,
541
+ type: "parallel",
542
+ states: {}
543
+ };
544
+ if (config.description) {
545
+ parallelChart.description = config.description;
546
+ }
547
+ for (const region of config.parallel.regions) {
548
+ if (verbose) {
549
+ console.error(` 📍 Analyzing region: ${region.name}`);
550
+ }
551
+ const regionStates = {};
552
+ for (const className of region.classes) {
553
+ const classDeclaration = sourceFile.getClass(className);
554
+ if (classDeclaration) {
555
+ const classSymbol = classDeclaration.getSymbolOrThrow();
556
+ regionStates[className] = analyzeStateNode(classSymbol, verbose);
557
+ } else {
558
+ console.warn(`⚠️ Warning: Class '${className}' not found for region '${region.name}'.`);
559
+ }
560
+ }
561
+ parallelChart.states[region.name] = {
562
+ initial: region.initialState,
563
+ states: regionStates
564
+ };
565
+ }
566
+ if (verbose) {
567
+ console.error(` ✅ Extracted ${config.parallel.regions.length} parallel regions`);
568
+ }
569
+ return parallelChart;
570
+ }
571
+ if (!config.initialState || !config.classes) {
572
+ throw new Error(`Machine config for '${config.id}' must have either 'parallel' or 'initialState'/'classes'.`);
573
+ }
419
574
  const fullChart = {
420
575
  id: config.id,
421
576
  initial: config.initialState,
@@ -431,7 +586,14 @@ function extractMachine(config, project, verbose = false) {
431
586
  continue;
432
587
  }
433
588
  const classSymbol = classDeclaration.getSymbolOrThrow();
434
- const stateNode = analyzeStateNode(classSymbol, verbose);
589
+ const hasChildren = className === config.initialState && config.children;
590
+ const stateNode = analyzeStateNodeWithNesting(
591
+ className,
592
+ classSymbol,
593
+ sourceFile,
594
+ hasChildren ? config.children : void 0,
595
+ verbose
596
+ );
435
597
  fullChart.states[className] = stateNode;
436
598
  }
437
599
  if (verbose) {
@@ -539,6 +701,16 @@ function extractStateNode(stateInstance) {
539
701
  transition.actions = meta.actions.map((a) => a.name);
540
702
  }
541
703
  stateNode.on[key] = transition;
704
+ } else if (meta.guards && meta.guards.length > 0) {
705
+ const transition = {
706
+ target: "GuardedTransition",
707
+ // Placeholder - actual target determined at runtime
708
+ cond: meta.guards.map((g) => g.name).join(" && ")
709
+ };
710
+ if (meta.description) {
711
+ transition.description = meta.description;
712
+ }
713
+ stateNode.on[key] = transition;
542
714
  }
543
715
  }
544
716
  if (invoke2.length > 0) {
@@ -797,9 +969,1055 @@ function createMutableMachine(sharedContext, factories, getDiscriminant) {
797
969
  });
798
970
  }
799
971
 
972
+ // src/higher-order.ts
973
+ function delegateToChild(actionName) {
974
+ return function(...args) {
975
+ const child = this.context.child;
976
+ if (typeof child[actionName] === "function") {
977
+ const newChildState = child[actionName](...args);
978
+ return setContext(this, { ...this.context, child: newChildState });
979
+ }
980
+ return this;
981
+ };
982
+ }
983
+ function toggle(prop) {
984
+ return function() {
985
+ if (typeof this.context[prop] !== "boolean") {
986
+ console.warn(`[toggle primitive] Property '${String(prop)}' is not a boolean. Toggling may have unexpected results.`);
987
+ }
988
+ return setContext(this, {
989
+ ...this.context,
990
+ [prop]: !this.context[prop]
991
+ });
992
+ };
993
+ }
994
+ var IdleMachine = class extends MachineBase {
995
+ constructor(config) {
996
+ super({ status: "idle" });
997
+ this.config = config;
998
+ this.fetch = (params) => new LoadingMachine(this.config, params != null ? params : this.config.initialParams, 1);
999
+ }
1000
+ };
1001
+ var LoadingMachine = class extends MachineBase {
1002
+ constructor(config, params, attempts) {
1003
+ super({ status: "loading", abortController: new AbortController(), attempts });
1004
+ this.config = config;
1005
+ this.params = params;
1006
+ this.succeed = (data) => {
1007
+ var _a, _b;
1008
+ (_b = (_a = this.config).onSuccess) == null ? void 0 : _b.call(_a, data);
1009
+ return new SuccessMachine(this.config, { status: "success", data });
1010
+ };
1011
+ this.fail = (error) => {
1012
+ var _a, _b, _c;
1013
+ const maxRetries = (_a = this.config.maxRetries) != null ? _a : 3;
1014
+ if (this.context.attempts < maxRetries) {
1015
+ return new RetryingMachine(this.config, this.params, error, this.context.attempts);
1016
+ }
1017
+ (_c = (_b = this.config).onError) == null ? void 0 : _c.call(_b, error);
1018
+ return new ErrorMachine(this.config, { status: "error", error });
1019
+ };
1020
+ this.cancel = () => {
1021
+ this.context.abortController.abort();
1022
+ return new CanceledMachine(this.config);
1023
+ };
1024
+ this.execute();
1025
+ }
1026
+ async execute() {
1027
+ }
1028
+ };
1029
+ var RetryingMachine = class extends MachineBase {
1030
+ constructor(config, params, error, attempts) {
1031
+ super({ status: "retrying", error, attempts });
1032
+ this.config = config;
1033
+ this.params = params;
1034
+ // This would be called after a delay.
1035
+ this.retry = (params) => new LoadingMachine(this.config, params != null ? params : this.params, this.context.attempts + 1);
1036
+ }
1037
+ };
1038
+ var SuccessMachine = class extends MachineBase {
1039
+ constructor(config, context) {
1040
+ super(context);
1041
+ this.config = config;
1042
+ this.refetch = (params) => new LoadingMachine(this.config, params != null ? params : this.config.initialParams, 1);
1043
+ }
1044
+ };
1045
+ var ErrorMachine = class extends MachineBase {
1046
+ constructor(config, context) {
1047
+ super(context);
1048
+ this.config = config;
1049
+ this.retry = (params) => new LoadingMachine(this.config, params != null ? params : this.config.initialParams, 1);
1050
+ }
1051
+ };
1052
+ var CanceledMachine = class extends MachineBase {
1053
+ constructor(config) {
1054
+ super({ status: "canceled" });
1055
+ this.config = config;
1056
+ this.refetch = (params) => new LoadingMachine(this.config, params != null ? params : this.config.initialParams, 1);
1057
+ }
1058
+ };
1059
+ function createFetchMachine(config) {
1060
+ return new IdleMachine(config);
1061
+ }
1062
+ function createParallelMachine(m1, m2) {
1063
+ const combinedContext = { ...m1.context, ...m2.context };
1064
+ const transitions1 = { ...m1 };
1065
+ const transitions2 = { ...m2 };
1066
+ delete transitions1.context;
1067
+ delete transitions2.context;
1068
+ const combinedTransitions = {};
1069
+ for (const key in transitions1) {
1070
+ const transitionFn = transitions1[key];
1071
+ combinedTransitions[key] = (...args) => {
1072
+ const nextM1 = transitionFn.apply(m1.context, args);
1073
+ return createParallelMachine(nextM1, m2);
1074
+ };
1075
+ }
1076
+ for (const key in transitions2) {
1077
+ const transitionFn = transitions2[key];
1078
+ combinedTransitions[key] = (...args) => {
1079
+ const nextM2 = transitionFn.apply(m2.context, args);
1080
+ return createParallelMachine(m1, nextM2);
1081
+ };
1082
+ }
1083
+ return {
1084
+ context: combinedContext,
1085
+ ...combinedTransitions
1086
+ };
1087
+ }
1088
+
1089
+ // src/middleware.ts
1090
+ var CANCEL = Symbol("CANCEL");
1091
+ function createMiddleware(machine, hooks, options = {}) {
1092
+ const { mode = "auto", exclude = ["context"] } = options;
1093
+ const wrapped = {};
1094
+ for (const prop in machine) {
1095
+ if (!Object.prototype.hasOwnProperty.call(machine, prop)) continue;
1096
+ const value = machine[prop];
1097
+ if (prop === "context") {
1098
+ wrapped.context = value;
1099
+ continue;
1100
+ }
1101
+ if (exclude.includes(prop)) {
1102
+ wrapped[prop] = value;
1103
+ continue;
1104
+ }
1105
+ if (typeof value !== "function" || prop.startsWith("_")) {
1106
+ wrapped[prop] = value;
1107
+ continue;
1108
+ }
1109
+ wrapped[prop] = createTransitionWrapper(
1110
+ prop,
1111
+ value,
1112
+ machine,
1113
+ hooks,
1114
+ mode
1115
+ );
1116
+ }
1117
+ return wrapped;
1118
+ }
1119
+ function createTransitionWrapper(transitionName, originalFn, machine, hooks, mode) {
1120
+ return function wrappedTransition(...args) {
1121
+ const context = machine.context;
1122
+ const middlewareCtx = {
1123
+ transitionName,
1124
+ context,
1125
+ args
1126
+ };
1127
+ const executeSyncTransition = () => {
1128
+ try {
1129
+ if (hooks.before) {
1130
+ const beforeResult = hooks.before(middlewareCtx);
1131
+ if (beforeResult === CANCEL) {
1132
+ return machine;
1133
+ }
1134
+ if (beforeResult instanceof Promise) {
1135
+ throw new Error(
1136
+ `Middleware mode is 'sync' but before hook returned Promise for transition: ${transitionName}`
1137
+ );
1138
+ }
1139
+ }
1140
+ const result = originalFn.call(this, ...args);
1141
+ if (result instanceof Promise) {
1142
+ return handleAsyncResult(result, context);
1143
+ }
1144
+ if (hooks.after) {
1145
+ const middlewareResult = {
1146
+ transitionName,
1147
+ prevContext: context,
1148
+ nextContext: result.context,
1149
+ args
1150
+ };
1151
+ const afterResult = hooks.after(middlewareResult);
1152
+ if (afterResult instanceof Promise) {
1153
+ throw new Error(
1154
+ `Middleware mode is 'sync' but after hook returned Promise for transition: ${transitionName}`
1155
+ );
1156
+ }
1157
+ }
1158
+ return result;
1159
+ } catch (err) {
1160
+ if (hooks.error) {
1161
+ const middlewareError = {
1162
+ transitionName,
1163
+ context,
1164
+ args,
1165
+ error: err
1166
+ };
1167
+ const errorResult = hooks.error(middlewareError);
1168
+ if (errorResult instanceof Promise) {
1169
+ errorResult.catch(() => {
1170
+ });
1171
+ throw err;
1172
+ }
1173
+ if (errorResult && typeof errorResult === "object" && "context" in errorResult) {
1174
+ return errorResult;
1175
+ }
1176
+ }
1177
+ throw err;
1178
+ }
1179
+ };
1180
+ const handleAsyncResult = async (resultPromise, ctx) => {
1181
+ try {
1182
+ const result = await resultPromise;
1183
+ if (hooks.after) {
1184
+ const middlewareResult = {
1185
+ transitionName,
1186
+ prevContext: ctx,
1187
+ nextContext: result.context,
1188
+ args
1189
+ };
1190
+ await hooks.after(middlewareResult);
1191
+ }
1192
+ return result;
1193
+ } catch (err) {
1194
+ if (hooks.error) {
1195
+ const middlewareError = {
1196
+ transitionName,
1197
+ context: ctx,
1198
+ args,
1199
+ error: err
1200
+ };
1201
+ const errorResult = await hooks.error(middlewareError);
1202
+ if (errorResult && typeof errorResult === "object" && "context" in errorResult) {
1203
+ return errorResult;
1204
+ }
1205
+ }
1206
+ throw err;
1207
+ }
1208
+ };
1209
+ const executeAsyncTransition = async () => {
1210
+ try {
1211
+ if (hooks.before) {
1212
+ const beforeResult = await hooks.before(middlewareCtx);
1213
+ if (beforeResult === CANCEL) {
1214
+ return machine;
1215
+ }
1216
+ }
1217
+ const result = await originalFn.call(this, ...args);
1218
+ if (hooks.after) {
1219
+ const middlewareResult = {
1220
+ transitionName,
1221
+ prevContext: context,
1222
+ nextContext: result.context,
1223
+ args
1224
+ };
1225
+ await hooks.after(middlewareResult);
1226
+ }
1227
+ return result;
1228
+ } catch (err) {
1229
+ if (hooks.error) {
1230
+ const middlewareError = {
1231
+ transitionName,
1232
+ context,
1233
+ args,
1234
+ error: err
1235
+ };
1236
+ const errorResult = await hooks.error(middlewareError);
1237
+ if (errorResult && typeof errorResult === "object" && "context" in errorResult) {
1238
+ return errorResult;
1239
+ }
1240
+ }
1241
+ throw err;
1242
+ }
1243
+ };
1244
+ if (mode === "async") {
1245
+ return executeAsyncTransition();
1246
+ } else if (mode === "sync") {
1247
+ return executeSyncTransition();
1248
+ } else {
1249
+ return executeSyncTransition();
1250
+ }
1251
+ };
1252
+ }
1253
+ function withLogging(machine, options = {}) {
1254
+ const {
1255
+ logger = console.log,
1256
+ includeContext = true,
1257
+ includeArgs = true
1258
+ } = options;
1259
+ return createMiddleware(machine, {
1260
+ before: ({ transitionName, args }) => {
1261
+ const argsStr = includeArgs && args.length > 0 ? ` ${JSON.stringify(args)}` : "";
1262
+ logger(`→ ${transitionName}${argsStr}`);
1263
+ },
1264
+ after: ({ transitionName, nextContext }) => {
1265
+ const contextStr = includeContext ? ` ${JSON.stringify(nextContext)}` : "";
1266
+ logger(`✓ ${transitionName}${contextStr}`);
1267
+ }
1268
+ });
1269
+ }
1270
+ function withAnalytics(machine, track, options = {}) {
1271
+ const {
1272
+ eventPrefix = "state_transition",
1273
+ includePrevContext = false,
1274
+ includeArgs = true
1275
+ } = options;
1276
+ return createMiddleware(machine, {
1277
+ after: async ({ transitionName, prevContext, nextContext, args }) => {
1278
+ const properties = {
1279
+ transition: transitionName,
1280
+ to: nextContext
1281
+ };
1282
+ if (includePrevContext) {
1283
+ properties.from = prevContext;
1284
+ }
1285
+ if (includeArgs && args.length > 0) {
1286
+ properties.args = args;
1287
+ }
1288
+ await track(`${eventPrefix}.${transitionName}`, properties);
1289
+ }
1290
+ }, { mode: "async" });
1291
+ }
1292
+ function withValidation(machine, validate, options) {
1293
+ return createMiddleware(machine, {
1294
+ before: (ctx) => {
1295
+ const result = validate(ctx);
1296
+ if (result instanceof Promise) {
1297
+ return result.then((r) => {
1298
+ if (r === false) {
1299
+ throw new Error(`Validation failed for transition: ${ctx.transitionName}`);
1300
+ }
1301
+ return void 0;
1302
+ });
1303
+ }
1304
+ if (result === false) {
1305
+ throw new Error(`Validation failed for transition: ${ctx.transitionName}`);
1306
+ }
1307
+ return void 0;
1308
+ }
1309
+ }, { mode: "auto", ...options });
1310
+ }
1311
+ function withPermissions(machine, canPerform, options) {
1312
+ return createMiddleware(machine, {
1313
+ before: (ctx) => {
1314
+ const result = canPerform(ctx);
1315
+ if (result instanceof Promise) {
1316
+ return result.then((allowed) => {
1317
+ if (!allowed) {
1318
+ throw new Error(`Unauthorized transition: ${ctx.transitionName}`);
1319
+ }
1320
+ return void 0;
1321
+ });
1322
+ }
1323
+ if (!result) {
1324
+ throw new Error(`Unauthorized transition: ${ctx.transitionName}`);
1325
+ }
1326
+ return void 0;
1327
+ }
1328
+ }, { mode: "auto", ...options });
1329
+ }
1330
+ function withErrorReporting(machine, captureError, options = {}) {
1331
+ const { includeContext = true, includeArgs = true, mode } = options;
1332
+ return createMiddleware(machine, {
1333
+ error: async ({ transitionName, context, args, error }) => {
1334
+ const errorContext = {
1335
+ transition: transitionName
1336
+ };
1337
+ if (includeContext) {
1338
+ errorContext.context = context;
1339
+ }
1340
+ if (includeArgs && args.length > 0) {
1341
+ errorContext.args = args;
1342
+ }
1343
+ await Promise.resolve(captureError(error, errorContext));
1344
+ }
1345
+ }, { mode });
1346
+ }
1347
+ function withPerformanceMonitoring(machine, onMetric) {
1348
+ const timings = /* @__PURE__ */ new Map();
1349
+ return createMiddleware(machine, {
1350
+ before: ({ transitionName }) => {
1351
+ timings.set(transitionName, performance.now());
1352
+ return void 0;
1353
+ },
1354
+ after: ({ transitionName, nextContext }) => {
1355
+ const startTime = timings.get(transitionName);
1356
+ if (startTime) {
1357
+ const duration = performance.now() - startTime;
1358
+ timings.delete(transitionName);
1359
+ const result = onMetric({ transitionName, duration, context: nextContext });
1360
+ if (result instanceof Promise) {
1361
+ return result;
1362
+ }
1363
+ }
1364
+ return void 0;
1365
+ }
1366
+ }, { mode: "auto" });
1367
+ }
1368
+ function withRetry(machine, options = {}) {
1369
+ const {
1370
+ maxRetries = 3,
1371
+ delay = 1e3,
1372
+ backoffMultiplier = 1,
1373
+ shouldRetry = () => true,
1374
+ onRetry
1375
+ } = options;
1376
+ const wrapped = {};
1377
+ for (const prop in machine) {
1378
+ if (!Object.prototype.hasOwnProperty.call(machine, prop)) continue;
1379
+ const value = machine[prop];
1380
+ if (prop === "context" || typeof value !== "function") {
1381
+ wrapped[prop] = value;
1382
+ continue;
1383
+ }
1384
+ wrapped[prop] = async function retriableTransition(...args) {
1385
+ let lastError;
1386
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
1387
+ try {
1388
+ return await value.call(this, ...args);
1389
+ } catch (error) {
1390
+ lastError = error;
1391
+ if (attempt === maxRetries) {
1392
+ break;
1393
+ }
1394
+ if (!shouldRetry(lastError)) {
1395
+ break;
1396
+ }
1397
+ onRetry == null ? void 0 : onRetry(attempt + 1, lastError);
1398
+ const currentDelay = delay * Math.pow(backoffMultiplier, attempt);
1399
+ await new Promise((resolve) => setTimeout(resolve, currentDelay));
1400
+ }
1401
+ }
1402
+ throw lastError;
1403
+ };
1404
+ }
1405
+ return wrapped;
1406
+ }
1407
+ function withHistory(machine, options = {}) {
1408
+ const {
1409
+ maxSize,
1410
+ serializer,
1411
+ filter,
1412
+ onEntry,
1413
+ _isRewrap = false
1414
+ } = options;
1415
+ const history = [];
1416
+ let entryId = 0;
1417
+ const instrumentedMachine = createMiddleware(machine, {
1418
+ before: ({ transitionName, args }) => {
1419
+ if (filter && !filter(transitionName, args)) {
1420
+ return;
1421
+ }
1422
+ const entry = {
1423
+ id: `entry-${entryId++}`,
1424
+ transitionName,
1425
+ args: [...args],
1426
+ // Shallow clone args (fast, works with any type)
1427
+ timestamp: Date.now()
1428
+ };
1429
+ if (serializer) {
1430
+ try {
1431
+ entry.serializedArgs = serializer.serialize(args);
1432
+ } catch (err) {
1433
+ console.error("Failed to serialize history args:", err);
1434
+ }
1435
+ }
1436
+ history.push(entry);
1437
+ if (maxSize && history.length > maxSize) {
1438
+ history.shift();
1439
+ }
1440
+ onEntry == null ? void 0 : onEntry(entry);
1441
+ }
1442
+ }, { exclude: ["context", "history", "clearHistory"] });
1443
+ if (!_isRewrap) {
1444
+ for (const prop in instrumentedMachine) {
1445
+ if (!Object.prototype.hasOwnProperty.call(instrumentedMachine, prop)) continue;
1446
+ const value = instrumentedMachine[prop];
1447
+ if (typeof value === "function" && !prop.startsWith("_") && prop !== "context" && !["history", "clearHistory"].includes(prop)) {
1448
+ const originalFn = value;
1449
+ instrumentedMachine[prop] = function(...args) {
1450
+ const result = originalFn.apply(this, args);
1451
+ if (result && typeof result === "object" && "context" in result && !("history" in result)) {
1452
+ const rewrappedResult = createMiddleware(result, {
1453
+ before: ({ transitionName, args: transArgs }) => {
1454
+ if (filter && !filter(transitionName, transArgs)) {
1455
+ return;
1456
+ }
1457
+ const entry = {
1458
+ id: `entry-${entryId++}`,
1459
+ transitionName,
1460
+ args: [...transArgs],
1461
+ timestamp: Date.now()
1462
+ };
1463
+ if (serializer) {
1464
+ try {
1465
+ entry.serializedArgs = serializer.serialize(transArgs);
1466
+ } catch (err) {
1467
+ console.error("Failed to serialize history args:", err);
1468
+ }
1469
+ }
1470
+ history.push(entry);
1471
+ if (maxSize && history.length > maxSize) {
1472
+ history.shift();
1473
+ }
1474
+ onEntry == null ? void 0 : onEntry(entry);
1475
+ }
1476
+ }, { exclude: ["context", "history", "clearHistory"] });
1477
+ return Object.assign(rewrappedResult, {
1478
+ history,
1479
+ clearHistory: () => {
1480
+ history.length = 0;
1481
+ entryId = 0;
1482
+ }
1483
+ });
1484
+ }
1485
+ return result;
1486
+ };
1487
+ }
1488
+ }
1489
+ }
1490
+ return Object.assign(instrumentedMachine, {
1491
+ history,
1492
+ clearHistory: () => {
1493
+ history.length = 0;
1494
+ entryId = 0;
1495
+ }
1496
+ });
1497
+ }
1498
+ function withSnapshot(machine, options = {}) {
1499
+ const {
1500
+ maxSize,
1501
+ serializer,
1502
+ captureSnapshot,
1503
+ onlyIfChanged = false,
1504
+ filter,
1505
+ onSnapshot,
1506
+ _extraExclusions = [],
1507
+ _isRewrap = false
1508
+ } = options;
1509
+ const snapshots = [];
1510
+ let snapshotId = 0;
1511
+ const instrumentedMachine = createMiddleware(machine, {
1512
+ after: ({ transitionName, prevContext, nextContext }) => {
1513
+ if (filter && !filter(transitionName)) {
1514
+ return;
1515
+ }
1516
+ if (onlyIfChanged) {
1517
+ const changed = JSON.stringify(prevContext) !== JSON.stringify(nextContext);
1518
+ if (!changed) {
1519
+ return;
1520
+ }
1521
+ }
1522
+ const snapshot = {
1523
+ id: `snapshot-${snapshotId++}`,
1524
+ transitionName,
1525
+ before: { ...prevContext },
1526
+ // Clone
1527
+ after: { ...nextContext },
1528
+ // Clone
1529
+ timestamp: Date.now()
1530
+ };
1531
+ if (serializer) {
1532
+ try {
1533
+ snapshot.serializedBefore = serializer.serialize(prevContext);
1534
+ snapshot.serializedAfter = serializer.serialize(nextContext);
1535
+ } catch (err) {
1536
+ console.error("Failed to serialize snapshot:", err);
1537
+ }
1538
+ }
1539
+ if (captureSnapshot) {
1540
+ try {
1541
+ snapshot.diff = captureSnapshot(prevContext, nextContext);
1542
+ } catch (err) {
1543
+ console.error("Failed to capture snapshot:", err);
1544
+ }
1545
+ }
1546
+ snapshots.push(snapshot);
1547
+ if (maxSize && snapshots.length > maxSize) {
1548
+ snapshots.shift();
1549
+ }
1550
+ onSnapshot == null ? void 0 : onSnapshot(snapshot);
1551
+ }
1552
+ }, { exclude: ["context", "snapshots", "clearSnapshots", "restoreSnapshot", ..._extraExclusions] });
1553
+ const restoreSnapshot = (context) => {
1554
+ const { context: _, ...transitions } = machine;
1555
+ return { context, ...transitions };
1556
+ };
1557
+ if (!_isRewrap) {
1558
+ for (const prop in instrumentedMachine) {
1559
+ if (!Object.prototype.hasOwnProperty.call(instrumentedMachine, prop)) continue;
1560
+ const value = instrumentedMachine[prop];
1561
+ if (typeof value === "function" && !prop.startsWith("_") && prop !== "context" && !["snapshots", "clearSnapshots", "restoreSnapshot", "history", "clearHistory"].includes(prop)) {
1562
+ const originalWrappedFn = value;
1563
+ instrumentedMachine[prop] = function(...args) {
1564
+ const result = originalWrappedFn.apply(this, args);
1565
+ if (result && typeof result === "object" && "context" in result && !("snapshots" in result)) {
1566
+ for (const transProp in result) {
1567
+ if (!Object.prototype.hasOwnProperty.call(result, transProp)) continue;
1568
+ const transValue = result[transProp];
1569
+ if (typeof transValue === "function" && !transProp.startsWith("_") && transProp !== "context" && !["snapshots", "clearSnapshots", "restoreSnapshot", "history", "clearHistory"].includes(transProp)) {
1570
+ const origTransFn = transValue;
1571
+ result[transProp] = function(...transArgs) {
1572
+ const prevCtx = result.context;
1573
+ const transResult = origTransFn.apply(this, transArgs);
1574
+ if (transResult && typeof transResult === "object" && "context" in transResult) {
1575
+ const nextCtx = transResult.context;
1576
+ if (!(filter && !filter(transProp))) {
1577
+ let shouldRecord = true;
1578
+ if (onlyIfChanged) {
1579
+ const changed = JSON.stringify(prevCtx) !== JSON.stringify(nextCtx);
1580
+ shouldRecord = changed;
1581
+ }
1582
+ if (shouldRecord) {
1583
+ const snapshot = {
1584
+ id: `snapshot-${snapshotId++}`,
1585
+ transitionName: transProp,
1586
+ before: { ...prevCtx },
1587
+ after: { ...nextCtx },
1588
+ timestamp: Date.now()
1589
+ };
1590
+ if (serializer) {
1591
+ try {
1592
+ snapshot.serializedBefore = serializer.serialize(prevCtx);
1593
+ snapshot.serializedAfter = serializer.serialize(nextCtx);
1594
+ } catch (err) {
1595
+ console.error("Failed to serialize snapshot:", err);
1596
+ }
1597
+ }
1598
+ if (captureSnapshot) {
1599
+ try {
1600
+ snapshot.diff = captureSnapshot(prevCtx, nextCtx);
1601
+ } catch (err) {
1602
+ console.error("Failed to capture snapshot:", err);
1603
+ }
1604
+ }
1605
+ snapshots.push(snapshot);
1606
+ if (maxSize && snapshots.length > maxSize) {
1607
+ snapshots.shift();
1608
+ }
1609
+ onSnapshot == null ? void 0 : onSnapshot(snapshot);
1610
+ }
1611
+ }
1612
+ }
1613
+ return transResult;
1614
+ };
1615
+ }
1616
+ }
1617
+ const resultWithTracking = Object.assign(result, {
1618
+ snapshots,
1619
+ clearSnapshots: () => {
1620
+ snapshots.length = 0;
1621
+ snapshotId = 0;
1622
+ },
1623
+ restoreSnapshot
1624
+ });
1625
+ if (machine.history) {
1626
+ resultWithTracking.history = machine.history;
1627
+ resultWithTracking.clearHistory = machine.clearHistory;
1628
+ }
1629
+ return resultWithTracking;
1630
+ }
1631
+ return result;
1632
+ };
1633
+ }
1634
+ }
1635
+ }
1636
+ return Object.assign(instrumentedMachine, {
1637
+ snapshots,
1638
+ clearSnapshots: () => {
1639
+ snapshots.length = 0;
1640
+ snapshotId = 0;
1641
+ },
1642
+ restoreSnapshot
1643
+ });
1644
+ }
1645
+ function withTimeTravel(machine, options = {}) {
1646
+ const { maxSize, serializer, onRecord } = options;
1647
+ const history = [];
1648
+ const snapshots = [];
1649
+ let entryId = 0;
1650
+ let snapshotId = 0;
1651
+ const recordHistory = (transitionName, args) => {
1652
+ const entry = {
1653
+ id: `entry-${entryId++}`,
1654
+ transitionName,
1655
+ args: [...args],
1656
+ timestamp: Date.now()
1657
+ };
1658
+ if (serializer) {
1659
+ try {
1660
+ entry.serializedArgs = serializer.serialize(args);
1661
+ } catch (err) {
1662
+ console.error("Failed to serialize history args:", err);
1663
+ }
1664
+ }
1665
+ history.push(entry);
1666
+ if (maxSize && history.length > maxSize) {
1667
+ history.shift();
1668
+ }
1669
+ onRecord == null ? void 0 : onRecord("history", entry);
1670
+ };
1671
+ const recordSnapshot = (transitionName, prevContext, nextContext) => {
1672
+ const snapshot = {
1673
+ id: `snapshot-${snapshotId++}`,
1674
+ transitionName,
1675
+ before: { ...prevContext },
1676
+ after: { ...nextContext },
1677
+ timestamp: Date.now()
1678
+ };
1679
+ if (serializer) {
1680
+ try {
1681
+ snapshot.serializedBefore = serializer.serialize(prevContext);
1682
+ snapshot.serializedAfter = serializer.serialize(nextContext);
1683
+ } catch (err) {
1684
+ console.error("Failed to serialize snapshot:", err);
1685
+ }
1686
+ }
1687
+ snapshots.push(snapshot);
1688
+ if (maxSize && snapshots.length > maxSize) {
1689
+ snapshots.shift();
1690
+ }
1691
+ onRecord == null ? void 0 : onRecord("snapshot", snapshot);
1692
+ };
1693
+ const restoreSnapshot = (context) => {
1694
+ const { context: _, ...transitions } = machine;
1695
+ return Object.assign({ context }, context, transitions);
1696
+ };
1697
+ const replayFrom = (snapshotIndex = 0) => {
1698
+ if (snapshotIndex < 0 || snapshotIndex >= snapshots.length) {
1699
+ throw new Error(`Invalid snapshot index: ${snapshotIndex}`);
1700
+ }
1701
+ let current = restoreSnapshot(snapshots[snapshotIndex].before);
1702
+ const snapshot = snapshots[snapshotIndex];
1703
+ const historyStartIndex = history.findIndex(
1704
+ (entry) => entry.transitionName === snapshot.transitionName && entry.timestamp === snapshot.timestamp
1705
+ );
1706
+ if (historyStartIndex === -1) {
1707
+ throw new Error("Could not find matching history entry for snapshot");
1708
+ }
1709
+ for (let i = historyStartIndex; i < history.length; i++) {
1710
+ const entry = history[i];
1711
+ const transition = current[entry.transitionName];
1712
+ if (typeof transition === "function") {
1713
+ try {
1714
+ current = transition.apply(current.context, entry.args);
1715
+ } catch (err) {
1716
+ console.error(`Replay failed at step ${i}:`, err);
1717
+ throw err;
1718
+ }
1719
+ }
1720
+ }
1721
+ return current;
1722
+ };
1723
+ const wrapMachine = (machine2) => {
1724
+ const wrapped = { ...machine2 };
1725
+ for (const prop in machine2) {
1726
+ if (!Object.prototype.hasOwnProperty.call(machine2, prop)) continue;
1727
+ const value = machine2[prop];
1728
+ if (typeof value === "function" && !prop.startsWith("_") && prop !== "context" && !["history", "snapshots", "clearHistory", "clearSnapshots", "clearTimeTravel", "restoreSnapshot", "replayFrom"].includes(prop)) {
1729
+ wrapped[prop] = function(...args) {
1730
+ recordHistory(prop, args);
1731
+ const prevContext = wrapped.context;
1732
+ const result = value.apply(this, args);
1733
+ if (result && typeof result === "object" && "context" in result) {
1734
+ recordSnapshot(prop, prevContext, result.context);
1735
+ }
1736
+ if (result && typeof result === "object" && "context" in result) {
1737
+ return wrapMachine(result);
1738
+ }
1739
+ return result;
1740
+ };
1741
+ }
1742
+ }
1743
+ return Object.assign(wrapped, {
1744
+ history,
1745
+ snapshots,
1746
+ clearHistory: () => {
1747
+ history.length = 0;
1748
+ entryId = 0;
1749
+ },
1750
+ clearSnapshots: () => {
1751
+ snapshots.length = 0;
1752
+ snapshotId = 0;
1753
+ },
1754
+ clearTimeTravel: () => {
1755
+ history.length = 0;
1756
+ snapshots.length = 0;
1757
+ entryId = 0;
1758
+ snapshotId = 0;
1759
+ },
1760
+ restoreSnapshot,
1761
+ replayFrom
1762
+ });
1763
+ };
1764
+ return wrapMachine(machine);
1765
+ }
1766
+ function compose(machine, ...middlewares) {
1767
+ return middlewares.reduce((acc, middleware) => middleware(acc), machine);
1768
+ }
1769
+ function createCustomMiddleware(hooks, options) {
1770
+ return (machine) => createMiddleware(machine, hooks, options);
1771
+ }
1772
+ function composeTyped(machine, ...middlewares) {
1773
+ return middlewares.reduce((acc, middleware) => middleware(acc), machine);
1774
+ }
1775
+ function chain(machine) {
1776
+ return new MiddlewareChainBuilder(machine);
1777
+ }
1778
+ var MiddlewareChainBuilder = class _MiddlewareChainBuilder {
1779
+ constructor(machine) {
1780
+ this.machine = machine;
1781
+ }
1782
+ /**
1783
+ * Add a middleware to the composition chain.
1784
+ * @param middleware - The middleware function to add
1785
+ * @returns A new composer with the middleware applied
1786
+ */
1787
+ with(middleware) {
1788
+ const result = middleware(this.machine);
1789
+ return new _MiddlewareChainBuilder(result);
1790
+ }
1791
+ /**
1792
+ * Build the final machine with all middlewares applied.
1793
+ */
1794
+ build() {
1795
+ return this.machine;
1796
+ }
1797
+ };
1798
+ function withDebugging(machine) {
1799
+ return withTimeTravel(withSnapshot(withHistory(machine)));
1800
+ }
1801
+ function createPipeline(config = {}) {
1802
+ const {
1803
+ continueOnError = false,
1804
+ logErrors = true,
1805
+ onError
1806
+ } = config;
1807
+ return (machine, ...middlewares) => {
1808
+ let currentMachine = machine;
1809
+ const errors = [];
1810
+ for (let i = 0; i < middlewares.length; i++) {
1811
+ const middleware = middlewares[i];
1812
+ try {
1813
+ if ("middleware" in middleware && "when" in middleware) {
1814
+ if (!middleware.when(currentMachine)) {
1815
+ continue;
1816
+ }
1817
+ currentMachine = middleware.middleware(currentMachine);
1818
+ } else {
1819
+ currentMachine = middleware(currentMachine);
1820
+ }
1821
+ } catch (error) {
1822
+ const err = error instanceof Error ? error : new Error(String(error));
1823
+ errors.push({ error: err, middlewareIndex: i });
1824
+ if (logErrors) {
1825
+ console.error(`Middleware pipeline error at index ${i}:`, err);
1826
+ }
1827
+ onError == null ? void 0 : onError(err, `middleware-${i}`);
1828
+ if (!continueOnError) {
1829
+ break;
1830
+ }
1831
+ }
1832
+ }
1833
+ return {
1834
+ machine: currentMachine,
1835
+ errors,
1836
+ success: errors.length === 0
1837
+ };
1838
+ };
1839
+ }
1840
+ function createMiddlewareRegistry() {
1841
+ const registry = /* @__PURE__ */ new Map();
1842
+ return {
1843
+ /**
1844
+ * Register a middleware with a name and optional metadata.
1845
+ */
1846
+ register(name, middleware, description, priority) {
1847
+ if (registry.has(name)) {
1848
+ throw new Error(`Middleware '${name}' is already registered`);
1849
+ }
1850
+ registry.set(name, { name, middleware, description, priority });
1851
+ return this;
1852
+ },
1853
+ /**
1854
+ * Unregister a middleware by name.
1855
+ */
1856
+ unregister(name) {
1857
+ return registry.delete(name);
1858
+ },
1859
+ /**
1860
+ * Check if a middleware is registered.
1861
+ */
1862
+ has(name) {
1863
+ return registry.has(name);
1864
+ },
1865
+ /**
1866
+ * Get a registered middleware by name.
1867
+ */
1868
+ get(name) {
1869
+ return registry.get(name);
1870
+ },
1871
+ /**
1872
+ * List all registered middlewares.
1873
+ */
1874
+ list() {
1875
+ return Array.from(registry.values()).sort((a, b) => {
1876
+ var _a, _b;
1877
+ return ((_a = a.priority) != null ? _a : 0) - ((_b = b.priority) != null ? _b : 0);
1878
+ });
1879
+ },
1880
+ /**
1881
+ * Apply a selection of registered middlewares to a machine.
1882
+ * Middlewares are applied in priority order (lowest to highest).
1883
+ */
1884
+ apply(machine, middlewareNames) {
1885
+ const middlewares = middlewareNames.map((name) => {
1886
+ const entry = registry.get(name);
1887
+ if (!entry) {
1888
+ throw new Error(`Middleware '${name}' is not registered`);
1889
+ }
1890
+ return entry;
1891
+ }).sort((a, b) => {
1892
+ var _a, _b;
1893
+ return ((_a = a.priority) != null ? _a : 0) - ((_b = b.priority) != null ? _b : 0);
1894
+ });
1895
+ return composeTyped(machine, ...middlewares.map((m) => m.middleware));
1896
+ },
1897
+ /**
1898
+ * Apply all registered middlewares to a machine in priority order.
1899
+ */
1900
+ applyAll(machine) {
1901
+ const middlewares = this.list();
1902
+ return composeTyped(machine, ...middlewares.map((m) => m.middleware));
1903
+ }
1904
+ };
1905
+ }
1906
+ function when(middleware, predicate) {
1907
+ const conditional = function(machine) {
1908
+ return predicate(machine) ? middleware(machine) : machine;
1909
+ };
1910
+ conditional.middleware = middleware;
1911
+ conditional.when = predicate;
1912
+ return conditional;
1913
+ }
1914
+ function inDevelopment(middleware) {
1915
+ return when(middleware, () => {
1916
+ return typeof process !== "undefined" ? true : typeof window !== "undefined" ? !window.location.hostname.includes("production") : false;
1917
+ });
1918
+ }
1919
+ function whenContext(key, value, middleware) {
1920
+ return when(middleware, (machine) => machine.context[key] === value);
1921
+ }
1922
+ function combine(...middlewares) {
1923
+ return (machine) => composeTyped(machine, ...middlewares);
1924
+ }
1925
+ function branch(branches, fallback) {
1926
+ return (machine) => {
1927
+ for (const [predicate, middleware] of branches) {
1928
+ if (predicate(machine)) {
1929
+ return middleware(machine);
1930
+ }
1931
+ }
1932
+ return fallback ? fallback(machine) : machine;
1933
+ };
1934
+ }
1935
+ function isMiddlewareFn(value) {
1936
+ return typeof value === "function" && value.length === 1;
1937
+ }
1938
+ function isConditionalMiddleware(value) {
1939
+ return value !== null && "middleware" in value && "when" in value && isMiddlewareFn(value.middleware) && typeof value.when === "function";
1940
+ }
1941
+
1942
+ // src/utils.ts
1943
+ function isState(machine, machineClass) {
1944
+ return machine instanceof machineClass;
1945
+ }
1946
+ function createEvent(type, ...args) {
1947
+ return { type, args };
1948
+ }
1949
+ function mergeContext(machine, partialContext) {
1950
+ return setContext(machine, (ctx) => ({ ...ctx, ...partialContext }));
1951
+ }
1952
+ async function pipeTransitions(initialMachine, ...transitions) {
1953
+ let current = initialMachine;
1954
+ for (const transitionFn of transitions) {
1955
+ current = await transitionFn(current);
1956
+ }
1957
+ return current;
1958
+ }
1959
+ function logState(machine, label) {
1960
+ if (label) {
1961
+ console.log(label, machine.context);
1962
+ } else {
1963
+ console.log(machine.context);
1964
+ }
1965
+ return machine;
1966
+ }
1967
+ function call(fn, context, ...args) {
1968
+ return fn.apply(context, args);
1969
+ }
1970
+ function bindTransitions(machine) {
1971
+ return new Proxy(machine, {
1972
+ get(target, prop) {
1973
+ const value = target[prop];
1974
+ if (typeof value === "function") {
1975
+ return function(...args) {
1976
+ const result = value.apply(target.context, args);
1977
+ if (result && typeof result === "object" && "context" in result) {
1978
+ return bindTransitions(result);
1979
+ }
1980
+ return result;
1981
+ };
1982
+ }
1983
+ return value;
1984
+ }
1985
+ });
1986
+ }
1987
+ var BoundMachine = class _BoundMachine {
1988
+ constructor(machine) {
1989
+ this.wrappedMachine = machine;
1990
+ return new Proxy(this, {
1991
+ get: (target, prop) => {
1992
+ if (prop === "wrappedMachine") {
1993
+ return Reflect.get(target, prop);
1994
+ }
1995
+ if (prop === "context") {
1996
+ return this.wrappedMachine.context;
1997
+ }
1998
+ const value = this.wrappedMachine[prop];
1999
+ if (typeof value === "function") {
2000
+ return (...args) => {
2001
+ const result = value.apply(this.wrappedMachine.context, args);
2002
+ if (result && typeof result === "object" && "context" in result) {
2003
+ return new _BoundMachine(result);
2004
+ }
2005
+ return result;
2006
+ };
2007
+ }
2008
+ return value;
2009
+ }
2010
+ });
2011
+ }
2012
+ };
2013
+
800
2014
  // src/index.ts
801
2015
  function createMachine(context, fns) {
802
- return Object.assign({ context }, fns);
2016
+ const transitions = "context" in fns ? Object.fromEntries(
2017
+ Object.entries(fns).filter(([key]) => key !== "context")
2018
+ ) : fns;
2019
+ const machine = Object.assign({ context }, transitions);
2020
+ return machine;
803
2021
  }
804
2022
  function createAsyncMachine(context, fns) {
805
2023
  return Object.assign({ context }, fns);
@@ -835,6 +2053,17 @@ function extendTransitions(machine, newTransitions) {
835
2053
  const combinedTransitions = { ...originalTransitions, ...newTransitions };
836
2054
  return createMachine(context, combinedTransitions);
837
2055
  }
2056
+ function combineFactories(factory1, factory2) {
2057
+ return (...args) => {
2058
+ const machine1 = factory1(...args);
2059
+ const machine2 = factory2();
2060
+ const combinedContext = { ...machine1.context, ...machine2.context };
2061
+ const { context: _, ...transitions1 } = machine1;
2062
+ const { context: __, ...transitions2 } = machine2;
2063
+ const combinedTransitions = { ...transitions1, ...transitions2 };
2064
+ return createMachine(combinedContext, combinedTransitions);
2065
+ };
2066
+ }
838
2067
  function createMachineBuilder(templateMachine) {
839
2068
  const { context, ...transitions } = templateMachine;
840
2069
  return (newContext) => {
@@ -854,15 +2083,32 @@ function hasState(machine, key, value) {
854
2083
  }
855
2084
  function runMachine(initial, onChange) {
856
2085
  let current = initial;
2086
+ let activeController = null;
857
2087
  async function dispatch(event) {
2088
+ if (activeController) {
2089
+ activeController.abort();
2090
+ activeController = null;
2091
+ }
858
2092
  const fn = current[event.type];
859
2093
  if (typeof fn !== "function") {
860
2094
  throw new Error(`[Machine] Unknown event type '${String(event.type)}' on current state.`);
861
2095
  }
862
- const nextState = await fn.apply(current.context, event.args);
863
- current = nextState;
864
- onChange == null ? void 0 : onChange(current);
865
- return current;
2096
+ const controller = new AbortController();
2097
+ activeController = controller;
2098
+ try {
2099
+ const nextStatePromise = fn.apply(current.context, [...event.args, { signal: controller.signal }]);
2100
+ const nextState = await nextStatePromise;
2101
+ if (controller.signal.aborted) {
2102
+ return current;
2103
+ }
2104
+ current = nextState;
2105
+ onChange == null ? void 0 : onChange(current);
2106
+ return current;
2107
+ } finally {
2108
+ if (activeController === controller) {
2109
+ activeController = null;
2110
+ }
2111
+ }
866
2112
  }
867
2113
  return {
868
2114
  /** Gets the context of the current state of the machine. */
@@ -870,7 +2116,14 @@ function runMachine(initial, onChange) {
870
2116
  return current.context;
871
2117
  },
872
2118
  /** Dispatches a type-safe event to the machine, triggering a transition. */
873
- dispatch
2119
+ dispatch,
2120
+ /** Stops any pending async operation and cleans up resources. */
2121
+ stop: () => {
2122
+ if (activeController) {
2123
+ activeController.abort();
2124
+ activeController = null;
2125
+ }
2126
+ }
874
2127
  };
875
2128
  }
876
2129
  var MachineBase = class {