@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.
@@ -104,9 +104,9 @@ function describe(_text, transition) {
104
104
  });
105
105
  return transition;
106
106
  }
107
- function guarded(guard, transition) {
107
+ function guarded(guard2, transition) {
108
108
  attachRuntimeMeta(transition, {
109
- guards: [guard]
109
+ guards: [guard2]
110
110
  });
111
111
  return transition;
112
112
  }
@@ -127,6 +127,62 @@ function action(action2, transition) {
127
127
  });
128
128
  return transition;
129
129
  }
130
+ function guard(condition, transition, options = {}) {
131
+ const { onFail = "throw", errorMessage, description } = options;
132
+ const fullOptions = { ...options, onFail, errorMessage, description };
133
+ const guardedTransition = async function(...args) {
134
+ const isMachine = typeof this === "object" && "context" in this;
135
+ const ctx = isMachine ? this.context : this;
136
+ const conditionResult = await Promise.resolve(condition(ctx, ...args));
137
+ if (conditionResult) {
138
+ const contextForTransition = isMachine ? this.context : this;
139
+ return transition.apply(contextForTransition, args);
140
+ } else {
141
+ if (onFail === "throw") {
142
+ const message = errorMessage || "Guard condition failed";
143
+ throw new Error(message);
144
+ } else if (onFail === "ignore") {
145
+ if (isMachine) {
146
+ return this;
147
+ } else {
148
+ throw new Error('Cannot use "ignore" mode with context-only binding. Use full machine binding or provide fallback.');
149
+ }
150
+ } else if (typeof onFail === "function") {
151
+ if (isMachine) {
152
+ return onFail.apply(this, args);
153
+ } else {
154
+ throw new Error("Cannot use function fallback with context-only binding. Use full machine binding.");
155
+ }
156
+ } else {
157
+ return onFail;
158
+ }
159
+ }
160
+ };
161
+ Object.defineProperty(guardedTransition, "__guard", { value: true, enumerable: false });
162
+ Object.defineProperty(guardedTransition, "condition", { value: condition, enumerable: false });
163
+ Object.defineProperty(guardedTransition, "transition", { value: transition, enumerable: false });
164
+ Object.defineProperty(guardedTransition, "options", { value: fullOptions, enumerable: false });
165
+ attachRuntimeMeta(guardedTransition, {
166
+ description: description || "Runtime guarded transition",
167
+ guards: [{ name: "runtime_guard", description: description || "Runtime condition check" }]
168
+ });
169
+ return guardedTransition;
170
+ }
171
+ function whenGuard(condition) {
172
+ return {
173
+ /**
174
+ * Define the transition to execute when the condition passes.
175
+ * Returns a guarded transition that can optionally have an else clause.
176
+ */
177
+ do(transition) {
178
+ const guarded2 = guard(condition, transition);
179
+ guarded2.else = function(fallback) {
180
+ return guard(condition, transition, { onFail: fallback });
181
+ };
182
+ return guarded2;
183
+ }
184
+ };
185
+ }
130
186
  function metadata(_meta, value) {
131
187
  return value;
132
188
  }
@@ -196,17 +252,17 @@ function parseInvokeService(obj) {
196
252
  }
197
253
  return service;
198
254
  }
199
- function extractFromCallExpression(call, verbose = false) {
200
- if (!Node.isCallExpression(call)) {
255
+ function extractFromCallExpression(call2, verbose = false) {
256
+ if (!Node.isCallExpression(call2)) {
201
257
  return null;
202
258
  }
203
- const expression = call.getExpression();
259
+ const expression = call2.getExpression();
204
260
  const fnName = Node.isIdentifier(expression) ? expression.getText() : null;
205
261
  if (!fnName) {
206
262
  return null;
207
263
  }
208
264
  const metadata2 = {};
209
- const args = call.getArguments();
265
+ const args = call2.getArguments();
210
266
  switch (fnName) {
211
267
  case "transitionTo":
212
268
  if (args[0]) {
@@ -226,9 +282,9 @@ function extractFromCallExpression(call, verbose = false) {
226
282
  break;
227
283
  case "guarded":
228
284
  if (args[0]) {
229
- const guard = parseObjectLiteral(args[0]);
230
- if (Object.keys(guard).length > 0) {
231
- metadata2.guards = [guard];
285
+ const guard2 = parseObjectLiteral(args[0]);
286
+ if (Object.keys(guard2).length > 0) {
287
+ metadata2.guards = [guard2];
232
288
  }
233
289
  }
234
290
  if (args[1] && Node.isCallExpression(args[1])) {
@@ -346,6 +402,26 @@ function analyzeStateNode(classSymbol, verbose = false) {
346
402
  }
347
403
  return chartNode;
348
404
  }
405
+ function analyzeStateNodeWithNesting(className, classSymbol, sourceFile, childConfig, verbose = false) {
406
+ const stateNode = analyzeStateNode(classSymbol, verbose);
407
+ if (childConfig) {
408
+ if (verbose) {
409
+ console.error(` 👪 Analyzing children for state: ${className}`);
410
+ }
411
+ stateNode.initial = childConfig.initialState;
412
+ stateNode.states = {};
413
+ for (const childClassName of childConfig.classes) {
414
+ const childClassDeclaration = sourceFile.getClass(childClassName);
415
+ if (childClassDeclaration) {
416
+ const childSymbol = childClassDeclaration.getSymbolOrThrow();
417
+ stateNode.states[childClassName] = analyzeStateNode(childSymbol, verbose);
418
+ } else {
419
+ console.warn(`⚠️ Warning: Child class '${childClassName}' not found.`);
420
+ }
421
+ }
422
+ }
423
+ return stateNode;
424
+ }
349
425
  function extractMachine(config, project, verbose = false) {
350
426
  if (verbose) {
351
427
  console.error(`
@@ -356,6 +432,45 @@ function extractMachine(config, project, verbose = false) {
356
432
  if (!sourceFile) {
357
433
  throw new Error(`Source file not found: ${config.input}`);
358
434
  }
435
+ if (config.parallel) {
436
+ if (verbose) {
437
+ console.error(` ⏹️ Parallel machine detected. Analyzing regions.`);
438
+ }
439
+ const parallelChart = {
440
+ id: config.id,
441
+ type: "parallel",
442
+ states: {}
443
+ };
444
+ if (config.description) {
445
+ parallelChart.description = config.description;
446
+ }
447
+ for (const region of config.parallel.regions) {
448
+ if (verbose) {
449
+ console.error(` 📍 Analyzing region: ${region.name}`);
450
+ }
451
+ const regionStates = {};
452
+ for (const className of region.classes) {
453
+ const classDeclaration = sourceFile.getClass(className);
454
+ if (classDeclaration) {
455
+ const classSymbol = classDeclaration.getSymbolOrThrow();
456
+ regionStates[className] = analyzeStateNode(classSymbol, verbose);
457
+ } else {
458
+ console.warn(`⚠️ Warning: Class '${className}' not found for region '${region.name}'.`);
459
+ }
460
+ }
461
+ parallelChart.states[region.name] = {
462
+ initial: region.initialState,
463
+ states: regionStates
464
+ };
465
+ }
466
+ if (verbose) {
467
+ console.error(` ✅ Extracted ${config.parallel.regions.length} parallel regions`);
468
+ }
469
+ return parallelChart;
470
+ }
471
+ if (!config.initialState || !config.classes) {
472
+ throw new Error(`Machine config for '${config.id}' must have either 'parallel' or 'initialState'/'classes'.`);
473
+ }
359
474
  const fullChart = {
360
475
  id: config.id,
361
476
  initial: config.initialState,
@@ -371,7 +486,14 @@ function extractMachine(config, project, verbose = false) {
371
486
  continue;
372
487
  }
373
488
  const classSymbol = classDeclaration.getSymbolOrThrow();
374
- const stateNode = analyzeStateNode(classSymbol, verbose);
489
+ const hasChildren = className === config.initialState && config.children;
490
+ const stateNode = analyzeStateNodeWithNesting(
491
+ className,
492
+ classSymbol,
493
+ sourceFile,
494
+ hasChildren ? config.children : void 0,
495
+ verbose
496
+ );
375
497
  fullChart.states[className] = stateNode;
376
498
  }
377
499
  if (verbose) {
@@ -479,6 +601,16 @@ function extractStateNode(stateInstance) {
479
601
  transition.actions = meta.actions.map((a) => a.name);
480
602
  }
481
603
  stateNode.on[key] = transition;
604
+ } else if (meta.guards && meta.guards.length > 0) {
605
+ const transition = {
606
+ target: "GuardedTransition",
607
+ // Placeholder - actual target determined at runtime
608
+ cond: meta.guards.map((g) => g.name).join(" && ")
609
+ };
610
+ if (meta.description) {
611
+ transition.description = meta.description;
612
+ }
613
+ stateNode.on[key] = transition;
482
614
  }
483
615
  }
484
616
  if (invoke2.length > 0) {
@@ -737,9 +869,1055 @@ function createMutableMachine(sharedContext, factories, getDiscriminant) {
737
869
  });
738
870
  }
739
871
 
872
+ // src/higher-order.ts
873
+ function delegateToChild(actionName) {
874
+ return function(...args) {
875
+ const child = this.context.child;
876
+ if (typeof child[actionName] === "function") {
877
+ const newChildState = child[actionName](...args);
878
+ return setContext(this, { ...this.context, child: newChildState });
879
+ }
880
+ return this;
881
+ };
882
+ }
883
+ function toggle(prop) {
884
+ return function() {
885
+ if (typeof this.context[prop] !== "boolean") {
886
+ console.warn(`[toggle primitive] Property '${String(prop)}' is not a boolean. Toggling may have unexpected results.`);
887
+ }
888
+ return setContext(this, {
889
+ ...this.context,
890
+ [prop]: !this.context[prop]
891
+ });
892
+ };
893
+ }
894
+ var IdleMachine = class extends MachineBase {
895
+ constructor(config) {
896
+ super({ status: "idle" });
897
+ this.config = config;
898
+ this.fetch = (params) => new LoadingMachine(this.config, params != null ? params : this.config.initialParams, 1);
899
+ }
900
+ };
901
+ var LoadingMachine = class extends MachineBase {
902
+ constructor(config, params, attempts) {
903
+ super({ status: "loading", abortController: new AbortController(), attempts });
904
+ this.config = config;
905
+ this.params = params;
906
+ this.succeed = (data) => {
907
+ var _a, _b;
908
+ (_b = (_a = this.config).onSuccess) == null ? void 0 : _b.call(_a, data);
909
+ return new SuccessMachine(this.config, { status: "success", data });
910
+ };
911
+ this.fail = (error) => {
912
+ var _a, _b, _c;
913
+ const maxRetries = (_a = this.config.maxRetries) != null ? _a : 3;
914
+ if (this.context.attempts < maxRetries) {
915
+ return new RetryingMachine(this.config, this.params, error, this.context.attempts);
916
+ }
917
+ (_c = (_b = this.config).onError) == null ? void 0 : _c.call(_b, error);
918
+ return new ErrorMachine(this.config, { status: "error", error });
919
+ };
920
+ this.cancel = () => {
921
+ this.context.abortController.abort();
922
+ return new CanceledMachine(this.config);
923
+ };
924
+ this.execute();
925
+ }
926
+ async execute() {
927
+ }
928
+ };
929
+ var RetryingMachine = class extends MachineBase {
930
+ constructor(config, params, error, attempts) {
931
+ super({ status: "retrying", error, attempts });
932
+ this.config = config;
933
+ this.params = params;
934
+ // This would be called after a delay.
935
+ this.retry = (params) => new LoadingMachine(this.config, params != null ? params : this.params, this.context.attempts + 1);
936
+ }
937
+ };
938
+ var SuccessMachine = class extends MachineBase {
939
+ constructor(config, context) {
940
+ super(context);
941
+ this.config = config;
942
+ this.refetch = (params) => new LoadingMachine(this.config, params != null ? params : this.config.initialParams, 1);
943
+ }
944
+ };
945
+ var ErrorMachine = class extends MachineBase {
946
+ constructor(config, context) {
947
+ super(context);
948
+ this.config = config;
949
+ this.retry = (params) => new LoadingMachine(this.config, params != null ? params : this.config.initialParams, 1);
950
+ }
951
+ };
952
+ var CanceledMachine = class extends MachineBase {
953
+ constructor(config) {
954
+ super({ status: "canceled" });
955
+ this.config = config;
956
+ this.refetch = (params) => new LoadingMachine(this.config, params != null ? params : this.config.initialParams, 1);
957
+ }
958
+ };
959
+ function createFetchMachine(config) {
960
+ return new IdleMachine(config);
961
+ }
962
+ function createParallelMachine(m1, m2) {
963
+ const combinedContext = { ...m1.context, ...m2.context };
964
+ const transitions1 = { ...m1 };
965
+ const transitions2 = { ...m2 };
966
+ delete transitions1.context;
967
+ delete transitions2.context;
968
+ const combinedTransitions = {};
969
+ for (const key in transitions1) {
970
+ const transitionFn = transitions1[key];
971
+ combinedTransitions[key] = (...args) => {
972
+ const nextM1 = transitionFn.apply(m1.context, args);
973
+ return createParallelMachine(nextM1, m2);
974
+ };
975
+ }
976
+ for (const key in transitions2) {
977
+ const transitionFn = transitions2[key];
978
+ combinedTransitions[key] = (...args) => {
979
+ const nextM2 = transitionFn.apply(m2.context, args);
980
+ return createParallelMachine(m1, nextM2);
981
+ };
982
+ }
983
+ return {
984
+ context: combinedContext,
985
+ ...combinedTransitions
986
+ };
987
+ }
988
+
989
+ // src/middleware.ts
990
+ var CANCEL = Symbol("CANCEL");
991
+ function createMiddleware(machine, hooks, options = {}) {
992
+ const { mode = "auto", exclude = ["context"] } = options;
993
+ const wrapped = {};
994
+ for (const prop in machine) {
995
+ if (!Object.prototype.hasOwnProperty.call(machine, prop)) continue;
996
+ const value = machine[prop];
997
+ if (prop === "context") {
998
+ wrapped.context = value;
999
+ continue;
1000
+ }
1001
+ if (exclude.includes(prop)) {
1002
+ wrapped[prop] = value;
1003
+ continue;
1004
+ }
1005
+ if (typeof value !== "function" || prop.startsWith("_")) {
1006
+ wrapped[prop] = value;
1007
+ continue;
1008
+ }
1009
+ wrapped[prop] = createTransitionWrapper(
1010
+ prop,
1011
+ value,
1012
+ machine,
1013
+ hooks,
1014
+ mode
1015
+ );
1016
+ }
1017
+ return wrapped;
1018
+ }
1019
+ function createTransitionWrapper(transitionName, originalFn, machine, hooks, mode) {
1020
+ return function wrappedTransition(...args) {
1021
+ const context = machine.context;
1022
+ const middlewareCtx = {
1023
+ transitionName,
1024
+ context,
1025
+ args
1026
+ };
1027
+ const executeSyncTransition = () => {
1028
+ try {
1029
+ if (hooks.before) {
1030
+ const beforeResult = hooks.before(middlewareCtx);
1031
+ if (beforeResult === CANCEL) {
1032
+ return machine;
1033
+ }
1034
+ if (beforeResult instanceof Promise) {
1035
+ throw new Error(
1036
+ `Middleware mode is 'sync' but before hook returned Promise for transition: ${transitionName}`
1037
+ );
1038
+ }
1039
+ }
1040
+ const result = originalFn.call(this, ...args);
1041
+ if (result instanceof Promise) {
1042
+ return handleAsyncResult(result, context);
1043
+ }
1044
+ if (hooks.after) {
1045
+ const middlewareResult = {
1046
+ transitionName,
1047
+ prevContext: context,
1048
+ nextContext: result.context,
1049
+ args
1050
+ };
1051
+ const afterResult = hooks.after(middlewareResult);
1052
+ if (afterResult instanceof Promise) {
1053
+ throw new Error(
1054
+ `Middleware mode is 'sync' but after hook returned Promise for transition: ${transitionName}`
1055
+ );
1056
+ }
1057
+ }
1058
+ return result;
1059
+ } catch (err) {
1060
+ if (hooks.error) {
1061
+ const middlewareError = {
1062
+ transitionName,
1063
+ context,
1064
+ args,
1065
+ error: err
1066
+ };
1067
+ const errorResult = hooks.error(middlewareError);
1068
+ if (errorResult instanceof Promise) {
1069
+ errorResult.catch(() => {
1070
+ });
1071
+ throw err;
1072
+ }
1073
+ if (errorResult && typeof errorResult === "object" && "context" in errorResult) {
1074
+ return errorResult;
1075
+ }
1076
+ }
1077
+ throw err;
1078
+ }
1079
+ };
1080
+ const handleAsyncResult = async (resultPromise, ctx) => {
1081
+ try {
1082
+ const result = await resultPromise;
1083
+ if (hooks.after) {
1084
+ const middlewareResult = {
1085
+ transitionName,
1086
+ prevContext: ctx,
1087
+ nextContext: result.context,
1088
+ args
1089
+ };
1090
+ await hooks.after(middlewareResult);
1091
+ }
1092
+ return result;
1093
+ } catch (err) {
1094
+ if (hooks.error) {
1095
+ const middlewareError = {
1096
+ transitionName,
1097
+ context: ctx,
1098
+ args,
1099
+ error: err
1100
+ };
1101
+ const errorResult = await hooks.error(middlewareError);
1102
+ if (errorResult && typeof errorResult === "object" && "context" in errorResult) {
1103
+ return errorResult;
1104
+ }
1105
+ }
1106
+ throw err;
1107
+ }
1108
+ };
1109
+ const executeAsyncTransition = async () => {
1110
+ try {
1111
+ if (hooks.before) {
1112
+ const beforeResult = await hooks.before(middlewareCtx);
1113
+ if (beforeResult === CANCEL) {
1114
+ return machine;
1115
+ }
1116
+ }
1117
+ const result = await originalFn.call(this, ...args);
1118
+ if (hooks.after) {
1119
+ const middlewareResult = {
1120
+ transitionName,
1121
+ prevContext: context,
1122
+ nextContext: result.context,
1123
+ args
1124
+ };
1125
+ await hooks.after(middlewareResult);
1126
+ }
1127
+ return result;
1128
+ } catch (err) {
1129
+ if (hooks.error) {
1130
+ const middlewareError = {
1131
+ transitionName,
1132
+ context,
1133
+ args,
1134
+ error: err
1135
+ };
1136
+ const errorResult = await hooks.error(middlewareError);
1137
+ if (errorResult && typeof errorResult === "object" && "context" in errorResult) {
1138
+ return errorResult;
1139
+ }
1140
+ }
1141
+ throw err;
1142
+ }
1143
+ };
1144
+ if (mode === "async") {
1145
+ return executeAsyncTransition();
1146
+ } else if (mode === "sync") {
1147
+ return executeSyncTransition();
1148
+ } else {
1149
+ return executeSyncTransition();
1150
+ }
1151
+ };
1152
+ }
1153
+ function withLogging(machine, options = {}) {
1154
+ const {
1155
+ logger = console.log,
1156
+ includeContext = true,
1157
+ includeArgs = true
1158
+ } = options;
1159
+ return createMiddleware(machine, {
1160
+ before: ({ transitionName, args }) => {
1161
+ const argsStr = includeArgs && args.length > 0 ? ` ${JSON.stringify(args)}` : "";
1162
+ logger(`→ ${transitionName}${argsStr}`);
1163
+ },
1164
+ after: ({ transitionName, nextContext }) => {
1165
+ const contextStr = includeContext ? ` ${JSON.stringify(nextContext)}` : "";
1166
+ logger(`✓ ${transitionName}${contextStr}`);
1167
+ }
1168
+ });
1169
+ }
1170
+ function withAnalytics(machine, track, options = {}) {
1171
+ const {
1172
+ eventPrefix = "state_transition",
1173
+ includePrevContext = false,
1174
+ includeArgs = true
1175
+ } = options;
1176
+ return createMiddleware(machine, {
1177
+ after: async ({ transitionName, prevContext, nextContext, args }) => {
1178
+ const properties = {
1179
+ transition: transitionName,
1180
+ to: nextContext
1181
+ };
1182
+ if (includePrevContext) {
1183
+ properties.from = prevContext;
1184
+ }
1185
+ if (includeArgs && args.length > 0) {
1186
+ properties.args = args;
1187
+ }
1188
+ await track(`${eventPrefix}.${transitionName}`, properties);
1189
+ }
1190
+ }, { mode: "async" });
1191
+ }
1192
+ function withValidation(machine, validate, options) {
1193
+ return createMiddleware(machine, {
1194
+ before: (ctx) => {
1195
+ const result = validate(ctx);
1196
+ if (result instanceof Promise) {
1197
+ return result.then((r) => {
1198
+ if (r === false) {
1199
+ throw new Error(`Validation failed for transition: ${ctx.transitionName}`);
1200
+ }
1201
+ return void 0;
1202
+ });
1203
+ }
1204
+ if (result === false) {
1205
+ throw new Error(`Validation failed for transition: ${ctx.transitionName}`);
1206
+ }
1207
+ return void 0;
1208
+ }
1209
+ }, { mode: "auto", ...options });
1210
+ }
1211
+ function withPermissions(machine, canPerform, options) {
1212
+ return createMiddleware(machine, {
1213
+ before: (ctx) => {
1214
+ const result = canPerform(ctx);
1215
+ if (result instanceof Promise) {
1216
+ return result.then((allowed) => {
1217
+ if (!allowed) {
1218
+ throw new Error(`Unauthorized transition: ${ctx.transitionName}`);
1219
+ }
1220
+ return void 0;
1221
+ });
1222
+ }
1223
+ if (!result) {
1224
+ throw new Error(`Unauthorized transition: ${ctx.transitionName}`);
1225
+ }
1226
+ return void 0;
1227
+ }
1228
+ }, { mode: "auto", ...options });
1229
+ }
1230
+ function withErrorReporting(machine, captureError, options = {}) {
1231
+ const { includeContext = true, includeArgs = true, mode } = options;
1232
+ return createMiddleware(machine, {
1233
+ error: async ({ transitionName, context, args, error }) => {
1234
+ const errorContext = {
1235
+ transition: transitionName
1236
+ };
1237
+ if (includeContext) {
1238
+ errorContext.context = context;
1239
+ }
1240
+ if (includeArgs && args.length > 0) {
1241
+ errorContext.args = args;
1242
+ }
1243
+ await Promise.resolve(captureError(error, errorContext));
1244
+ }
1245
+ }, { mode });
1246
+ }
1247
+ function withPerformanceMonitoring(machine, onMetric) {
1248
+ const timings = /* @__PURE__ */ new Map();
1249
+ return createMiddleware(machine, {
1250
+ before: ({ transitionName }) => {
1251
+ timings.set(transitionName, performance.now());
1252
+ return void 0;
1253
+ },
1254
+ after: ({ transitionName, nextContext }) => {
1255
+ const startTime = timings.get(transitionName);
1256
+ if (startTime) {
1257
+ const duration = performance.now() - startTime;
1258
+ timings.delete(transitionName);
1259
+ const result = onMetric({ transitionName, duration, context: nextContext });
1260
+ if (result instanceof Promise) {
1261
+ return result;
1262
+ }
1263
+ }
1264
+ return void 0;
1265
+ }
1266
+ }, { mode: "auto" });
1267
+ }
1268
+ function withRetry(machine, options = {}) {
1269
+ const {
1270
+ maxRetries = 3,
1271
+ delay = 1e3,
1272
+ backoffMultiplier = 1,
1273
+ shouldRetry = () => true,
1274
+ onRetry
1275
+ } = options;
1276
+ const wrapped = {};
1277
+ for (const prop in machine) {
1278
+ if (!Object.prototype.hasOwnProperty.call(machine, prop)) continue;
1279
+ const value = machine[prop];
1280
+ if (prop === "context" || typeof value !== "function") {
1281
+ wrapped[prop] = value;
1282
+ continue;
1283
+ }
1284
+ wrapped[prop] = async function retriableTransition(...args) {
1285
+ let lastError;
1286
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
1287
+ try {
1288
+ return await value.call(this, ...args);
1289
+ } catch (error) {
1290
+ lastError = error;
1291
+ if (attempt === maxRetries) {
1292
+ break;
1293
+ }
1294
+ if (!shouldRetry(lastError)) {
1295
+ break;
1296
+ }
1297
+ onRetry == null ? void 0 : onRetry(attempt + 1, lastError);
1298
+ const currentDelay = delay * Math.pow(backoffMultiplier, attempt);
1299
+ await new Promise((resolve) => setTimeout(resolve, currentDelay));
1300
+ }
1301
+ }
1302
+ throw lastError;
1303
+ };
1304
+ }
1305
+ return wrapped;
1306
+ }
1307
+ function withHistory(machine, options = {}) {
1308
+ const {
1309
+ maxSize,
1310
+ serializer,
1311
+ filter,
1312
+ onEntry,
1313
+ _isRewrap = false
1314
+ } = options;
1315
+ const history = [];
1316
+ let entryId = 0;
1317
+ const instrumentedMachine = createMiddleware(machine, {
1318
+ before: ({ transitionName, args }) => {
1319
+ if (filter && !filter(transitionName, args)) {
1320
+ return;
1321
+ }
1322
+ const entry = {
1323
+ id: `entry-${entryId++}`,
1324
+ transitionName,
1325
+ args: [...args],
1326
+ // Shallow clone args (fast, works with any type)
1327
+ timestamp: Date.now()
1328
+ };
1329
+ if (serializer) {
1330
+ try {
1331
+ entry.serializedArgs = serializer.serialize(args);
1332
+ } catch (err) {
1333
+ console.error("Failed to serialize history args:", err);
1334
+ }
1335
+ }
1336
+ history.push(entry);
1337
+ if (maxSize && history.length > maxSize) {
1338
+ history.shift();
1339
+ }
1340
+ onEntry == null ? void 0 : onEntry(entry);
1341
+ }
1342
+ }, { exclude: ["context", "history", "clearHistory"] });
1343
+ if (!_isRewrap) {
1344
+ for (const prop in instrumentedMachine) {
1345
+ if (!Object.prototype.hasOwnProperty.call(instrumentedMachine, prop)) continue;
1346
+ const value = instrumentedMachine[prop];
1347
+ if (typeof value === "function" && !prop.startsWith("_") && prop !== "context" && !["history", "clearHistory"].includes(prop)) {
1348
+ const originalFn = value;
1349
+ instrumentedMachine[prop] = function(...args) {
1350
+ const result = originalFn.apply(this, args);
1351
+ if (result && typeof result === "object" && "context" in result && !("history" in result)) {
1352
+ const rewrappedResult = createMiddleware(result, {
1353
+ before: ({ transitionName, args: transArgs }) => {
1354
+ if (filter && !filter(transitionName, transArgs)) {
1355
+ return;
1356
+ }
1357
+ const entry = {
1358
+ id: `entry-${entryId++}`,
1359
+ transitionName,
1360
+ args: [...transArgs],
1361
+ timestamp: Date.now()
1362
+ };
1363
+ if (serializer) {
1364
+ try {
1365
+ entry.serializedArgs = serializer.serialize(transArgs);
1366
+ } catch (err) {
1367
+ console.error("Failed to serialize history args:", err);
1368
+ }
1369
+ }
1370
+ history.push(entry);
1371
+ if (maxSize && history.length > maxSize) {
1372
+ history.shift();
1373
+ }
1374
+ onEntry == null ? void 0 : onEntry(entry);
1375
+ }
1376
+ }, { exclude: ["context", "history", "clearHistory"] });
1377
+ return Object.assign(rewrappedResult, {
1378
+ history,
1379
+ clearHistory: () => {
1380
+ history.length = 0;
1381
+ entryId = 0;
1382
+ }
1383
+ });
1384
+ }
1385
+ return result;
1386
+ };
1387
+ }
1388
+ }
1389
+ }
1390
+ return Object.assign(instrumentedMachine, {
1391
+ history,
1392
+ clearHistory: () => {
1393
+ history.length = 0;
1394
+ entryId = 0;
1395
+ }
1396
+ });
1397
+ }
1398
+ function withSnapshot(machine, options = {}) {
1399
+ const {
1400
+ maxSize,
1401
+ serializer,
1402
+ captureSnapshot,
1403
+ onlyIfChanged = false,
1404
+ filter,
1405
+ onSnapshot,
1406
+ _extraExclusions = [],
1407
+ _isRewrap = false
1408
+ } = options;
1409
+ const snapshots = [];
1410
+ let snapshotId = 0;
1411
+ const instrumentedMachine = createMiddleware(machine, {
1412
+ after: ({ transitionName, prevContext, nextContext }) => {
1413
+ if (filter && !filter(transitionName)) {
1414
+ return;
1415
+ }
1416
+ if (onlyIfChanged) {
1417
+ const changed = JSON.stringify(prevContext) !== JSON.stringify(nextContext);
1418
+ if (!changed) {
1419
+ return;
1420
+ }
1421
+ }
1422
+ const snapshot = {
1423
+ id: `snapshot-${snapshotId++}`,
1424
+ transitionName,
1425
+ before: { ...prevContext },
1426
+ // Clone
1427
+ after: { ...nextContext },
1428
+ // Clone
1429
+ timestamp: Date.now()
1430
+ };
1431
+ if (serializer) {
1432
+ try {
1433
+ snapshot.serializedBefore = serializer.serialize(prevContext);
1434
+ snapshot.serializedAfter = serializer.serialize(nextContext);
1435
+ } catch (err) {
1436
+ console.error("Failed to serialize snapshot:", err);
1437
+ }
1438
+ }
1439
+ if (captureSnapshot) {
1440
+ try {
1441
+ snapshot.diff = captureSnapshot(prevContext, nextContext);
1442
+ } catch (err) {
1443
+ console.error("Failed to capture snapshot:", err);
1444
+ }
1445
+ }
1446
+ snapshots.push(snapshot);
1447
+ if (maxSize && snapshots.length > maxSize) {
1448
+ snapshots.shift();
1449
+ }
1450
+ onSnapshot == null ? void 0 : onSnapshot(snapshot);
1451
+ }
1452
+ }, { exclude: ["context", "snapshots", "clearSnapshots", "restoreSnapshot", ..._extraExclusions] });
1453
+ const restoreSnapshot = (context) => {
1454
+ const { context: _, ...transitions } = machine;
1455
+ return { context, ...transitions };
1456
+ };
1457
+ if (!_isRewrap) {
1458
+ for (const prop in instrumentedMachine) {
1459
+ if (!Object.prototype.hasOwnProperty.call(instrumentedMachine, prop)) continue;
1460
+ const value = instrumentedMachine[prop];
1461
+ if (typeof value === "function" && !prop.startsWith("_") && prop !== "context" && !["snapshots", "clearSnapshots", "restoreSnapshot", "history", "clearHistory"].includes(prop)) {
1462
+ const originalWrappedFn = value;
1463
+ instrumentedMachine[prop] = function(...args) {
1464
+ const result = originalWrappedFn.apply(this, args);
1465
+ if (result && typeof result === "object" && "context" in result && !("snapshots" in result)) {
1466
+ for (const transProp in result) {
1467
+ if (!Object.prototype.hasOwnProperty.call(result, transProp)) continue;
1468
+ const transValue = result[transProp];
1469
+ if (typeof transValue === "function" && !transProp.startsWith("_") && transProp !== "context" && !["snapshots", "clearSnapshots", "restoreSnapshot", "history", "clearHistory"].includes(transProp)) {
1470
+ const origTransFn = transValue;
1471
+ result[transProp] = function(...transArgs) {
1472
+ const prevCtx = result.context;
1473
+ const transResult = origTransFn.apply(this, transArgs);
1474
+ if (transResult && typeof transResult === "object" && "context" in transResult) {
1475
+ const nextCtx = transResult.context;
1476
+ if (!(filter && !filter(transProp))) {
1477
+ let shouldRecord = true;
1478
+ if (onlyIfChanged) {
1479
+ const changed = JSON.stringify(prevCtx) !== JSON.stringify(nextCtx);
1480
+ shouldRecord = changed;
1481
+ }
1482
+ if (shouldRecord) {
1483
+ const snapshot = {
1484
+ id: `snapshot-${snapshotId++}`,
1485
+ transitionName: transProp,
1486
+ before: { ...prevCtx },
1487
+ after: { ...nextCtx },
1488
+ timestamp: Date.now()
1489
+ };
1490
+ if (serializer) {
1491
+ try {
1492
+ snapshot.serializedBefore = serializer.serialize(prevCtx);
1493
+ snapshot.serializedAfter = serializer.serialize(nextCtx);
1494
+ } catch (err) {
1495
+ console.error("Failed to serialize snapshot:", err);
1496
+ }
1497
+ }
1498
+ if (captureSnapshot) {
1499
+ try {
1500
+ snapshot.diff = captureSnapshot(prevCtx, nextCtx);
1501
+ } catch (err) {
1502
+ console.error("Failed to capture snapshot:", err);
1503
+ }
1504
+ }
1505
+ snapshots.push(snapshot);
1506
+ if (maxSize && snapshots.length > maxSize) {
1507
+ snapshots.shift();
1508
+ }
1509
+ onSnapshot == null ? void 0 : onSnapshot(snapshot);
1510
+ }
1511
+ }
1512
+ }
1513
+ return transResult;
1514
+ };
1515
+ }
1516
+ }
1517
+ const resultWithTracking = Object.assign(result, {
1518
+ snapshots,
1519
+ clearSnapshots: () => {
1520
+ snapshots.length = 0;
1521
+ snapshotId = 0;
1522
+ },
1523
+ restoreSnapshot
1524
+ });
1525
+ if (machine.history) {
1526
+ resultWithTracking.history = machine.history;
1527
+ resultWithTracking.clearHistory = machine.clearHistory;
1528
+ }
1529
+ return resultWithTracking;
1530
+ }
1531
+ return result;
1532
+ };
1533
+ }
1534
+ }
1535
+ }
1536
+ return Object.assign(instrumentedMachine, {
1537
+ snapshots,
1538
+ clearSnapshots: () => {
1539
+ snapshots.length = 0;
1540
+ snapshotId = 0;
1541
+ },
1542
+ restoreSnapshot
1543
+ });
1544
+ }
1545
+ function withTimeTravel(machine, options = {}) {
1546
+ const { maxSize, serializer, onRecord } = options;
1547
+ const history = [];
1548
+ const snapshots = [];
1549
+ let entryId = 0;
1550
+ let snapshotId = 0;
1551
+ const recordHistory = (transitionName, args) => {
1552
+ const entry = {
1553
+ id: `entry-${entryId++}`,
1554
+ transitionName,
1555
+ args: [...args],
1556
+ timestamp: Date.now()
1557
+ };
1558
+ if (serializer) {
1559
+ try {
1560
+ entry.serializedArgs = serializer.serialize(args);
1561
+ } catch (err) {
1562
+ console.error("Failed to serialize history args:", err);
1563
+ }
1564
+ }
1565
+ history.push(entry);
1566
+ if (maxSize && history.length > maxSize) {
1567
+ history.shift();
1568
+ }
1569
+ onRecord == null ? void 0 : onRecord("history", entry);
1570
+ };
1571
+ const recordSnapshot = (transitionName, prevContext, nextContext) => {
1572
+ const snapshot = {
1573
+ id: `snapshot-${snapshotId++}`,
1574
+ transitionName,
1575
+ before: { ...prevContext },
1576
+ after: { ...nextContext },
1577
+ timestamp: Date.now()
1578
+ };
1579
+ if (serializer) {
1580
+ try {
1581
+ snapshot.serializedBefore = serializer.serialize(prevContext);
1582
+ snapshot.serializedAfter = serializer.serialize(nextContext);
1583
+ } catch (err) {
1584
+ console.error("Failed to serialize snapshot:", err);
1585
+ }
1586
+ }
1587
+ snapshots.push(snapshot);
1588
+ if (maxSize && snapshots.length > maxSize) {
1589
+ snapshots.shift();
1590
+ }
1591
+ onRecord == null ? void 0 : onRecord("snapshot", snapshot);
1592
+ };
1593
+ const restoreSnapshot = (context) => {
1594
+ const { context: _, ...transitions } = machine;
1595
+ return Object.assign({ context }, context, transitions);
1596
+ };
1597
+ const replayFrom = (snapshotIndex = 0) => {
1598
+ if (snapshotIndex < 0 || snapshotIndex >= snapshots.length) {
1599
+ throw new Error(`Invalid snapshot index: ${snapshotIndex}`);
1600
+ }
1601
+ let current = restoreSnapshot(snapshots[snapshotIndex].before);
1602
+ const snapshot = snapshots[snapshotIndex];
1603
+ const historyStartIndex = history.findIndex(
1604
+ (entry) => entry.transitionName === snapshot.transitionName && entry.timestamp === snapshot.timestamp
1605
+ );
1606
+ if (historyStartIndex === -1) {
1607
+ throw new Error("Could not find matching history entry for snapshot");
1608
+ }
1609
+ for (let i = historyStartIndex; i < history.length; i++) {
1610
+ const entry = history[i];
1611
+ const transition = current[entry.transitionName];
1612
+ if (typeof transition === "function") {
1613
+ try {
1614
+ current = transition.apply(current.context, entry.args);
1615
+ } catch (err) {
1616
+ console.error(`Replay failed at step ${i}:`, err);
1617
+ throw err;
1618
+ }
1619
+ }
1620
+ }
1621
+ return current;
1622
+ };
1623
+ const wrapMachine = (machine2) => {
1624
+ const wrapped = { ...machine2 };
1625
+ for (const prop in machine2) {
1626
+ if (!Object.prototype.hasOwnProperty.call(machine2, prop)) continue;
1627
+ const value = machine2[prop];
1628
+ if (typeof value === "function" && !prop.startsWith("_") && prop !== "context" && !["history", "snapshots", "clearHistory", "clearSnapshots", "clearTimeTravel", "restoreSnapshot", "replayFrom"].includes(prop)) {
1629
+ wrapped[prop] = function(...args) {
1630
+ recordHistory(prop, args);
1631
+ const prevContext = wrapped.context;
1632
+ const result = value.apply(this, args);
1633
+ if (result && typeof result === "object" && "context" in result) {
1634
+ recordSnapshot(prop, prevContext, result.context);
1635
+ }
1636
+ if (result && typeof result === "object" && "context" in result) {
1637
+ return wrapMachine(result);
1638
+ }
1639
+ return result;
1640
+ };
1641
+ }
1642
+ }
1643
+ return Object.assign(wrapped, {
1644
+ history,
1645
+ snapshots,
1646
+ clearHistory: () => {
1647
+ history.length = 0;
1648
+ entryId = 0;
1649
+ },
1650
+ clearSnapshots: () => {
1651
+ snapshots.length = 0;
1652
+ snapshotId = 0;
1653
+ },
1654
+ clearTimeTravel: () => {
1655
+ history.length = 0;
1656
+ snapshots.length = 0;
1657
+ entryId = 0;
1658
+ snapshotId = 0;
1659
+ },
1660
+ restoreSnapshot,
1661
+ replayFrom
1662
+ });
1663
+ };
1664
+ return wrapMachine(machine);
1665
+ }
1666
+ function compose(machine, ...middlewares) {
1667
+ return middlewares.reduce((acc, middleware) => middleware(acc), machine);
1668
+ }
1669
+ function createCustomMiddleware(hooks, options) {
1670
+ return (machine) => createMiddleware(machine, hooks, options);
1671
+ }
1672
+ function composeTyped(machine, ...middlewares) {
1673
+ return middlewares.reduce((acc, middleware) => middleware(acc), machine);
1674
+ }
1675
+ function chain(machine) {
1676
+ return new MiddlewareChainBuilder(machine);
1677
+ }
1678
+ var MiddlewareChainBuilder = class _MiddlewareChainBuilder {
1679
+ constructor(machine) {
1680
+ this.machine = machine;
1681
+ }
1682
+ /**
1683
+ * Add a middleware to the composition chain.
1684
+ * @param middleware - The middleware function to add
1685
+ * @returns A new composer with the middleware applied
1686
+ */
1687
+ with(middleware) {
1688
+ const result = middleware(this.machine);
1689
+ return new _MiddlewareChainBuilder(result);
1690
+ }
1691
+ /**
1692
+ * Build the final machine with all middlewares applied.
1693
+ */
1694
+ build() {
1695
+ return this.machine;
1696
+ }
1697
+ };
1698
+ function withDebugging(machine) {
1699
+ return withTimeTravel(withSnapshot(withHistory(machine)));
1700
+ }
1701
+ function createPipeline(config = {}) {
1702
+ const {
1703
+ continueOnError = false,
1704
+ logErrors = true,
1705
+ onError
1706
+ } = config;
1707
+ return (machine, ...middlewares) => {
1708
+ let currentMachine = machine;
1709
+ const errors = [];
1710
+ for (let i = 0; i < middlewares.length; i++) {
1711
+ const middleware = middlewares[i];
1712
+ try {
1713
+ if ("middleware" in middleware && "when" in middleware) {
1714
+ if (!middleware.when(currentMachine)) {
1715
+ continue;
1716
+ }
1717
+ currentMachine = middleware.middleware(currentMachine);
1718
+ } else {
1719
+ currentMachine = middleware(currentMachine);
1720
+ }
1721
+ } catch (error) {
1722
+ const err = error instanceof Error ? error : new Error(String(error));
1723
+ errors.push({ error: err, middlewareIndex: i });
1724
+ if (logErrors) {
1725
+ console.error(`Middleware pipeline error at index ${i}:`, err);
1726
+ }
1727
+ onError == null ? void 0 : onError(err, `middleware-${i}`);
1728
+ if (!continueOnError) {
1729
+ break;
1730
+ }
1731
+ }
1732
+ }
1733
+ return {
1734
+ machine: currentMachine,
1735
+ errors,
1736
+ success: errors.length === 0
1737
+ };
1738
+ };
1739
+ }
1740
+ function createMiddlewareRegistry() {
1741
+ const registry = /* @__PURE__ */ new Map();
1742
+ return {
1743
+ /**
1744
+ * Register a middleware with a name and optional metadata.
1745
+ */
1746
+ register(name, middleware, description, priority) {
1747
+ if (registry.has(name)) {
1748
+ throw new Error(`Middleware '${name}' is already registered`);
1749
+ }
1750
+ registry.set(name, { name, middleware, description, priority });
1751
+ return this;
1752
+ },
1753
+ /**
1754
+ * Unregister a middleware by name.
1755
+ */
1756
+ unregister(name) {
1757
+ return registry.delete(name);
1758
+ },
1759
+ /**
1760
+ * Check if a middleware is registered.
1761
+ */
1762
+ has(name) {
1763
+ return registry.has(name);
1764
+ },
1765
+ /**
1766
+ * Get a registered middleware by name.
1767
+ */
1768
+ get(name) {
1769
+ return registry.get(name);
1770
+ },
1771
+ /**
1772
+ * List all registered middlewares.
1773
+ */
1774
+ list() {
1775
+ return Array.from(registry.values()).sort((a, b) => {
1776
+ var _a, _b;
1777
+ return ((_a = a.priority) != null ? _a : 0) - ((_b = b.priority) != null ? _b : 0);
1778
+ });
1779
+ },
1780
+ /**
1781
+ * Apply a selection of registered middlewares to a machine.
1782
+ * Middlewares are applied in priority order (lowest to highest).
1783
+ */
1784
+ apply(machine, middlewareNames) {
1785
+ const middlewares = middlewareNames.map((name) => {
1786
+ const entry = registry.get(name);
1787
+ if (!entry) {
1788
+ throw new Error(`Middleware '${name}' is not registered`);
1789
+ }
1790
+ return entry;
1791
+ }).sort((a, b) => {
1792
+ var _a, _b;
1793
+ return ((_a = a.priority) != null ? _a : 0) - ((_b = b.priority) != null ? _b : 0);
1794
+ });
1795
+ return composeTyped(machine, ...middlewares.map((m) => m.middleware));
1796
+ },
1797
+ /**
1798
+ * Apply all registered middlewares to a machine in priority order.
1799
+ */
1800
+ applyAll(machine) {
1801
+ const middlewares = this.list();
1802
+ return composeTyped(machine, ...middlewares.map((m) => m.middleware));
1803
+ }
1804
+ };
1805
+ }
1806
+ function when(middleware, predicate) {
1807
+ const conditional = function(machine) {
1808
+ return predicate(machine) ? middleware(machine) : machine;
1809
+ };
1810
+ conditional.middleware = middleware;
1811
+ conditional.when = predicate;
1812
+ return conditional;
1813
+ }
1814
+ function inDevelopment(middleware) {
1815
+ return when(middleware, () => {
1816
+ return typeof process !== "undefined" ? true : typeof window !== "undefined" ? !window.location.hostname.includes("production") : false;
1817
+ });
1818
+ }
1819
+ function whenContext(key, value, middleware) {
1820
+ return when(middleware, (machine) => machine.context[key] === value);
1821
+ }
1822
+ function combine(...middlewares) {
1823
+ return (machine) => composeTyped(machine, ...middlewares);
1824
+ }
1825
+ function branch(branches, fallback) {
1826
+ return (machine) => {
1827
+ for (const [predicate, middleware] of branches) {
1828
+ if (predicate(machine)) {
1829
+ return middleware(machine);
1830
+ }
1831
+ }
1832
+ return fallback ? fallback(machine) : machine;
1833
+ };
1834
+ }
1835
+ function isMiddlewareFn(value) {
1836
+ return typeof value === "function" && value.length === 1;
1837
+ }
1838
+ function isConditionalMiddleware(value) {
1839
+ return value !== null && "middleware" in value && "when" in value && isMiddlewareFn(value.middleware) && typeof value.when === "function";
1840
+ }
1841
+
1842
+ // src/utils.ts
1843
+ function isState(machine, machineClass) {
1844
+ return machine instanceof machineClass;
1845
+ }
1846
+ function createEvent(type, ...args) {
1847
+ return { type, args };
1848
+ }
1849
+ function mergeContext(machine, partialContext) {
1850
+ return setContext(machine, (ctx) => ({ ...ctx, ...partialContext }));
1851
+ }
1852
+ async function pipeTransitions(initialMachine, ...transitions) {
1853
+ let current = initialMachine;
1854
+ for (const transitionFn of transitions) {
1855
+ current = await transitionFn(current);
1856
+ }
1857
+ return current;
1858
+ }
1859
+ function logState(machine, label) {
1860
+ if (label) {
1861
+ console.log(label, machine.context);
1862
+ } else {
1863
+ console.log(machine.context);
1864
+ }
1865
+ return machine;
1866
+ }
1867
+ function call(fn, context, ...args) {
1868
+ return fn.apply(context, args);
1869
+ }
1870
+ function bindTransitions(machine) {
1871
+ return new Proxy(machine, {
1872
+ get(target, prop) {
1873
+ const value = target[prop];
1874
+ if (typeof value === "function") {
1875
+ return function(...args) {
1876
+ const result = value.apply(target.context, args);
1877
+ if (result && typeof result === "object" && "context" in result) {
1878
+ return bindTransitions(result);
1879
+ }
1880
+ return result;
1881
+ };
1882
+ }
1883
+ return value;
1884
+ }
1885
+ });
1886
+ }
1887
+ var BoundMachine = class _BoundMachine {
1888
+ constructor(machine) {
1889
+ this.wrappedMachine = machine;
1890
+ return new Proxy(this, {
1891
+ get: (target, prop) => {
1892
+ if (prop === "wrappedMachine") {
1893
+ return Reflect.get(target, prop);
1894
+ }
1895
+ if (prop === "context") {
1896
+ return this.wrappedMachine.context;
1897
+ }
1898
+ const value = this.wrappedMachine[prop];
1899
+ if (typeof value === "function") {
1900
+ return (...args) => {
1901
+ const result = value.apply(this.wrappedMachine.context, args);
1902
+ if (result && typeof result === "object" && "context" in result) {
1903
+ return new _BoundMachine(result);
1904
+ }
1905
+ return result;
1906
+ };
1907
+ }
1908
+ return value;
1909
+ }
1910
+ });
1911
+ }
1912
+ };
1913
+
740
1914
  // src/index.ts
741
1915
  function createMachine(context, fns) {
742
- return Object.assign({ context }, fns);
1916
+ const transitions = "context" in fns ? Object.fromEntries(
1917
+ Object.entries(fns).filter(([key]) => key !== "context")
1918
+ ) : fns;
1919
+ const machine = Object.assign({ context }, transitions);
1920
+ return machine;
743
1921
  }
744
1922
  function createAsyncMachine(context, fns) {
745
1923
  return Object.assign({ context }, fns);
@@ -775,6 +1953,17 @@ function extendTransitions(machine, newTransitions) {
775
1953
  const combinedTransitions = { ...originalTransitions, ...newTransitions };
776
1954
  return createMachine(context, combinedTransitions);
777
1955
  }
1956
+ function combineFactories(factory1, factory2) {
1957
+ return (...args) => {
1958
+ const machine1 = factory1(...args);
1959
+ const machine2 = factory2();
1960
+ const combinedContext = { ...machine1.context, ...machine2.context };
1961
+ const { context: _, ...transitions1 } = machine1;
1962
+ const { context: __, ...transitions2 } = machine2;
1963
+ const combinedTransitions = { ...transitions1, ...transitions2 };
1964
+ return createMachine(combinedContext, combinedTransitions);
1965
+ };
1966
+ }
778
1967
  function createMachineBuilder(templateMachine) {
779
1968
  const { context, ...transitions } = templateMachine;
780
1969
  return (newContext) => {
@@ -794,15 +1983,32 @@ function hasState(machine, key, value) {
794
1983
  }
795
1984
  function runMachine(initial, onChange) {
796
1985
  let current = initial;
1986
+ let activeController = null;
797
1987
  async function dispatch(event) {
1988
+ if (activeController) {
1989
+ activeController.abort();
1990
+ activeController = null;
1991
+ }
798
1992
  const fn = current[event.type];
799
1993
  if (typeof fn !== "function") {
800
1994
  throw new Error(`[Machine] Unknown event type '${String(event.type)}' on current state.`);
801
1995
  }
802
- const nextState = await fn.apply(current.context, event.args);
803
- current = nextState;
804
- onChange == null ? void 0 : onChange(current);
805
- return current;
1996
+ const controller = new AbortController();
1997
+ activeController = controller;
1998
+ try {
1999
+ const nextStatePromise = fn.apply(current.context, [...event.args, { signal: controller.signal }]);
2000
+ const nextState = await nextStatePromise;
2001
+ if (controller.signal.aborted) {
2002
+ return current;
2003
+ }
2004
+ current = nextState;
2005
+ onChange == null ? void 0 : onChange(current);
2006
+ return current;
2007
+ } finally {
2008
+ if (activeController === controller) {
2009
+ activeController = null;
2010
+ }
2011
+ }
806
2012
  }
807
2013
  return {
808
2014
  /** Gets the context of the current state of the machine. */
@@ -810,7 +2016,14 @@ function runMachine(initial, onChange) {
810
2016
  return current.context;
811
2017
  },
812
2018
  /** Dispatches a type-safe event to the machine, triggering a transition. */
813
- dispatch
2019
+ dispatch,
2020
+ /** Stops any pending async operation and cleans up resources. */
2021
+ stop: () => {
2022
+ if (activeController) {
2023
+ activeController.abort();
2024
+ activeController = null;
2025
+ }
2026
+ }
814
2027
  };
815
2028
  }
816
2029
  var MachineBase = class {
@@ -827,20 +2040,37 @@ function next(m, update) {
827
2040
  return createMachine(update(context), transitions);
828
2041
  }
829
2042
  export {
2043
+ BoundMachine,
830
2044
  META_KEY,
831
2045
  MachineBase,
832
2046
  MultiMachineBase,
833
2047
  RUNTIME_META,
834
2048
  action,
2049
+ bindTransitions,
2050
+ branch,
2051
+ call,
2052
+ chain,
2053
+ combine,
2054
+ combineFactories,
2055
+ compose,
2056
+ composeTyped,
835
2057
  createAsyncMachine,
2058
+ createCustomMiddleware,
836
2059
  createEnsemble,
2060
+ createEvent,
2061
+ createFetchMachine,
837
2062
  createFlow,
838
2063
  createMachine,
839
2064
  createMachineBuilder,
840
2065
  createMachineFactory,
2066
+ createMiddleware,
2067
+ createMiddlewareRegistry,
841
2068
  createMultiMachine,
842
2069
  createMutableMachine,
2070
+ createParallelMachine,
2071
+ createPipeline,
843
2072
  createRunner,
2073
+ delegateToChild,
844
2074
  describe,
845
2075
  extendTransitions,
846
2076
  extractFromInstance,
@@ -850,13 +2080,21 @@ export {
850
2080
  extractStateNode,
851
2081
  generateChart,
852
2082
  generateStatechart,
2083
+ guard,
853
2084
  guarded,
854
2085
  hasState,
2086
+ inDevelopment,
855
2087
  invoke,
2088
+ isConditionalMiddleware,
2089
+ isMiddlewareFn,
2090
+ isState,
2091
+ logState,
856
2092
  matchMachine,
2093
+ mergeContext,
857
2094
  metadata,
858
2095
  next,
859
2096
  overrideTransitions,
2097
+ pipeTransitions,
860
2098
  run,
861
2099
  runAsync,
862
2100
  runMachine,
@@ -867,7 +2105,22 @@ export {
867
2105
  setContext,
868
2106
  step,
869
2107
  stepAsync,
2108
+ toggle,
870
2109
  transitionTo,
2110
+ when,
2111
+ whenContext,
2112
+ whenGuard,
2113
+ withAnalytics,
2114
+ withDebugging,
2115
+ withErrorReporting,
2116
+ withHistory,
2117
+ withLogging,
2118
+ withPerformanceMonitoring,
2119
+ withPermissions,
2120
+ withRetry,
2121
+ withSnapshot,
2122
+ withTimeTravel,
2123
+ withValidation,
871
2124
  yieldMachine
872
2125
  };
873
2126
  //# sourceMappingURL=index.js.map