@typeonce/effect-machine 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/README.md +345 -42
  2. package/dist/Machine.d.ts +1273 -347
  3. package/dist/Machine.d.ts.map +1 -1
  4. package/dist/Machine.js +161 -426
  5. package/dist/Machine.js.map +1 -1
  6. package/dist/internal/machine/activities.d.ts +57 -0
  7. package/dist/internal/machine/activities.d.ts.map +1 -0
  8. package/dist/internal/machine/activities.js +49 -0
  9. package/dist/internal/machine/activities.js.map +1 -0
  10. package/dist/internal/machine/atom.d.ts +69 -0
  11. package/dist/internal/machine/atom.d.ts.map +1 -0
  12. package/dist/{AtomMachine.js → internal/machine/atom.js} +19 -94
  13. package/dist/internal/machine/atom.js.map +1 -0
  14. package/dist/internal/machine/cluster.d.ts +63 -0
  15. package/dist/internal/machine/cluster.d.ts.map +1 -0
  16. package/dist/{ClusterMachine.js → internal/machine/cluster.js} +15 -119
  17. package/dist/internal/machine/cluster.js.map +1 -0
  18. package/dist/internal/machine/command.d.ts +16 -0
  19. package/dist/internal/machine/command.d.ts.map +1 -0
  20. package/dist/internal/machine/command.js +45 -0
  21. package/dist/internal/machine/command.js.map +1 -0
  22. package/dist/internal/machine/commandRuntime.d.ts +13 -0
  23. package/dist/internal/machine/commandRuntime.d.ts.map +1 -0
  24. package/dist/internal/machine/commandRuntime.js +16 -0
  25. package/dist/internal/machine/commandRuntime.js.map +1 -0
  26. package/dist/internal/{machineModel.d.ts → machine/configuration.d.ts} +32 -38
  27. package/dist/internal/machine/configuration.d.ts.map +1 -0
  28. package/dist/internal/machine/configuration.js +965 -0
  29. package/dist/internal/machine/configuration.js.map +1 -0
  30. package/dist/internal/{machineErrors.d.ts → machine/errors.d.ts} +3 -3
  31. package/dist/internal/machine/errors.d.ts.map +1 -0
  32. package/dist/internal/{machineErrors.js → machine/errors.js} +1 -1
  33. package/dist/internal/machine/errors.js.map +1 -0
  34. package/dist/internal/machine/executionPlan.d.ts +49 -0
  35. package/dist/internal/machine/executionPlan.d.ts.map +1 -0
  36. package/dist/internal/machine/executionPlan.js +667 -0
  37. package/dist/internal/machine/executionPlan.js.map +1 -0
  38. package/dist/internal/machine/invocation.d.ts +23 -0
  39. package/dist/internal/machine/invocation.d.ts.map +1 -0
  40. package/dist/internal/machine/invocation.js +77 -0
  41. package/dist/internal/machine/invocation.js.map +1 -0
  42. package/dist/internal/machine/machine.d.ts +183 -0
  43. package/dist/internal/machine/machine.d.ts.map +1 -0
  44. package/dist/internal/machine/machine.js +552 -0
  45. package/dist/internal/machine/machine.js.map +1 -0
  46. package/dist/internal/machine/planner.d.ts +182 -0
  47. package/dist/internal/machine/planner.d.ts.map +1 -0
  48. package/dist/internal/machine/planner.js +1082 -0
  49. package/dist/internal/machine/planner.js.map +1 -0
  50. package/dist/internal/{machineProcess.d.ts → machine/process.d.ts} +10 -4
  51. package/dist/internal/machine/process.d.ts.map +1 -0
  52. package/dist/internal/machine/process.js +446 -0
  53. package/dist/internal/machine/process.js.map +1 -0
  54. package/dist/internal/machine/protocol.d.ts +34 -0
  55. package/dist/internal/machine/protocol.d.ts.map +1 -0
  56. package/dist/internal/machine/protocol.js +182 -0
  57. package/dist/internal/machine/protocol.js.map +1 -0
  58. package/dist/internal/machine/readiness.d.ts +4 -0
  59. package/dist/internal/machine/readiness.d.ts.map +1 -0
  60. package/dist/internal/machine/readiness.js +2 -0
  61. package/dist/internal/machine/readiness.js.map +1 -0
  62. package/dist/internal/{machineRuntime.d.ts → machine/runtime.d.ts} +104 -2
  63. package/dist/internal/machine/runtime.d.ts.map +1 -0
  64. package/dist/internal/machine/runtime.js +1381 -0
  65. package/dist/internal/machine/runtime.js.map +1 -0
  66. package/dist/internal/machine/serialization.d.ts +14 -0
  67. package/dist/internal/machine/serialization.d.ts.map +1 -0
  68. package/dist/internal/machine/serialization.js +338 -0
  69. package/dist/internal/machine/serialization.js.map +1 -0
  70. package/dist/internal/machine/stateDefinition.d.ts +15 -0
  71. package/dist/internal/machine/stateDefinition.d.ts.map +1 -0
  72. package/dist/internal/machine/stateDefinition.js +210 -0
  73. package/dist/internal/machine/stateDefinition.js.map +1 -0
  74. package/dist/internal/machine/symbols.d.ts +3 -0
  75. package/dist/internal/machine/symbols.d.ts.map +1 -0
  76. package/dist/internal/machine/symbols.js +3 -0
  77. package/dist/internal/machine/symbols.js.map +1 -0
  78. package/dist/internal/machine/topology.d.ts +98 -0
  79. package/dist/internal/machine/topology.d.ts.map +1 -0
  80. package/dist/internal/machine/topology.js +347 -0
  81. package/dist/internal/machine/topology.js.map +1 -0
  82. package/dist/internal/testing/machine/arbitrary.d.ts +36 -0
  83. package/dist/internal/testing/machine/arbitrary.d.ts.map +1 -0
  84. package/dist/internal/testing/machine/arbitrary.js +68 -0
  85. package/dist/internal/testing/machine/arbitrary.js.map +1 -0
  86. package/dist/internal/testing/machine/finiteModel.d.ts +322 -0
  87. package/dist/internal/testing/machine/finiteModel.d.ts.map +1 -0
  88. package/dist/internal/testing/machine/finiteModel.js +976 -0
  89. package/dist/internal/testing/machine/finiteModel.js.map +1 -0
  90. package/dist/internal/testing/machine/referenceModel.d.ts +203 -0
  91. package/dist/internal/testing/machine/referenceModel.d.ts.map +1 -0
  92. package/dist/internal/testing/machine/referenceModel.js +1012 -0
  93. package/dist/internal/testing/machine/referenceModel.js.map +1 -0
  94. package/dist/internal/testing/machine/runtime.d.ts +328 -0
  95. package/dist/internal/testing/machine/runtime.d.ts.map +1 -0
  96. package/dist/internal/testing/machine/runtime.js +437 -0
  97. package/dist/internal/testing/machine/runtime.js.map +1 -0
  98. package/dist/internal/testing/machine/verification.d.ts +33 -0
  99. package/dist/internal/testing/machine/verification.d.ts.map +1 -0
  100. package/dist/internal/testing/machine/verification.js +1446 -0
  101. package/dist/internal/testing/machine/verification.js.map +1 -0
  102. package/dist/testing/MachineTest.d.ts +606 -0
  103. package/dist/testing/MachineTest.d.ts.map +1 -0
  104. package/dist/testing/MachineTest.js +102 -0
  105. package/dist/testing/MachineTest.js.map +1 -0
  106. package/dist/testing/index.d.ts +7 -0
  107. package/dist/testing/index.d.ts.map +1 -0
  108. package/dist/testing/index.js +7 -0
  109. package/dist/testing/index.js.map +1 -0
  110. package/dist/{ClusterMachine.d.ts → unstable/cluster/ClusterMachine.d.ts} +22 -30
  111. package/dist/unstable/cluster/ClusterMachine.d.ts.map +1 -0
  112. package/dist/unstable/cluster/ClusterMachine.js +126 -0
  113. package/dist/unstable/cluster/ClusterMachine.js.map +1 -0
  114. package/dist/{cluster.js → unstable/cluster/index.d.ts} +1 -1
  115. package/dist/unstable/cluster/index.d.ts.map +1 -0
  116. package/dist/{cluster.d.ts → unstable/cluster/index.js} +1 -1
  117. package/dist/unstable/cluster/index.js.map +1 -0
  118. package/dist/{AtomMachine.d.ts → unstable/reactivity/AtomMachine.d.ts} +40 -23
  119. package/dist/unstable/reactivity/AtomMachine.d.ts.map +1 -0
  120. package/dist/unstable/reactivity/AtomMachine.js +113 -0
  121. package/dist/unstable/reactivity/AtomMachine.js.map +1 -0
  122. package/dist/{reactivity.js → unstable/reactivity/index.d.ts} +1 -1
  123. package/dist/unstable/reactivity/index.d.ts.map +1 -0
  124. package/dist/{reactivity.d.ts → unstable/reactivity/index.js} +1 -1
  125. package/dist/unstable/reactivity/index.js.map +1 -0
  126. package/docs/agent-guide.md +271 -38
  127. package/package.json +23 -13
  128. package/dist/AtomMachine.d.ts.map +0 -1
  129. package/dist/AtomMachine.js.map +0 -1
  130. package/dist/ClusterMachine.d.ts.map +0 -1
  131. package/dist/ClusterMachine.js.map +0 -1
  132. package/dist/cluster.d.ts.map +0 -1
  133. package/dist/cluster.js.map +0 -1
  134. package/dist/internal/machineErrors.d.ts.map +0 -1
  135. package/dist/internal/machineErrors.js.map +0 -1
  136. package/dist/internal/machineModel.d.ts.map +0 -1
  137. package/dist/internal/machineModel.js +0 -766
  138. package/dist/internal/machineModel.js.map +0 -1
  139. package/dist/internal/machinePlanner.d.ts +0 -74
  140. package/dist/internal/machinePlanner.d.ts.map +0 -1
  141. package/dist/internal/machinePlanner.js +0 -621
  142. package/dist/internal/machinePlanner.js.map +0 -1
  143. package/dist/internal/machineProcess.d.ts.map +0 -1
  144. package/dist/internal/machineProcess.js +0 -181
  145. package/dist/internal/machineProcess.js.map +0 -1
  146. package/dist/internal/machineRuntime.d.ts.map +0 -1
  147. package/dist/internal/machineRuntime.js +0 -365
  148. package/dist/internal/machineRuntime.js.map +0 -1
  149. package/dist/reactivity.d.ts.map +0 -1
  150. package/dist/reactivity.js.map +0 -1
@@ -1,766 +0,0 @@
1
- /**
2
- * Internal machine representation helpers.
3
- *
4
- * @since 4.0.0
5
- */
6
- import * as Cause from "effect/Cause";
7
- import * as Effect from "effect/Effect";
8
- import * as Option from "effect/Option";
9
- import { hasProperty } from "effect/Predicate";
10
- import * as Schema from "effect/Schema";
11
- import { MachineSchemaDecodeError, MachineSchemaEncodeError } from "./machineErrors.js";
12
- export const TargetTypeId = "~effect/Machine/Target";
13
- export const getStateNodeDefinition = (path, definition) => {
14
- if (Schema.isSchema(definition)) {
15
- return {
16
- schema: definition,
17
- output: undefined,
18
- type: "atomic",
19
- initial: undefined,
20
- states: undefined
21
- };
22
- }
23
- if (!hasProperty(definition, "schema") || !Schema.isSchema(definition.schema)) {
24
- throw new Error(`Machine.make expected state "${path}" to be a tagged schema or state node config`);
25
- }
26
- if (definition.type === "parallel" && !hasProperty(definition, "states")) {
27
- throw new Error(`Machine.make expected parallel state "${path}" to declare child regions`);
28
- }
29
- if (hasProperty(definition, "states")) {
30
- if (definition.type === "final") {
31
- throw new Error(`Machine.make expected compound state "${path}" to be active`);
32
- }
33
- if (definition.type === "parallel") {
34
- return {
35
- schema: definition.schema,
36
- output: Schema.isSchema(definition.output) ? definition.output : undefined,
37
- type: "parallel",
38
- initial: undefined,
39
- states: definition.states
40
- };
41
- }
42
- if (typeof definition.initial !== "string") {
43
- throw new Error(`Machine.make expected compound state "${path}" to declare an initial child`);
44
- }
45
- return {
46
- schema: definition.schema,
47
- output: undefined,
48
- type: "compound",
49
- initial: definition.initial,
50
- states: definition.states
51
- };
52
- }
53
- return {
54
- schema: definition.schema,
55
- output: Schema.isSchema(definition.output) ? definition.output : undefined,
56
- type: definition.type === "final" ? "final" : "atomic",
57
- initial: undefined,
58
- states: undefined
59
- };
60
- };
61
- export const compileStateNodes = (states) => {
62
- const byPath = new Map();
63
- let order = 0;
64
- const compile = (tree, parent) => {
65
- const paths = [];
66
- for (const key of Object.keys(tree)) {
67
- if (key.includes(".")) {
68
- throw new Error(`Machine state keys cannot contain ".": "${key}"`);
69
- }
70
- const path = parent === undefined ? key : `${parent}.${key}`;
71
- const definition = getStateNodeDefinition(path, tree[key]);
72
- const node = {
73
- path,
74
- key,
75
- schema: definition.schema,
76
- output: definition.output,
77
- type: definition.type,
78
- parent,
79
- children: [],
80
- initial: definition.initial === undefined ? undefined : `${path}.${definition.initial}`,
81
- order
82
- };
83
- byPath.set(path, node);
84
- paths.push(path);
85
- order += 1;
86
- if (definition.states !== undefined) {
87
- const children = compile(definition.states, path);
88
- if (node.type === "compound" && (node.initial === undefined || !children.includes(node.initial))) {
89
- throw new Error(`Machine.make expected compound state "${path}" initial child to exist`);
90
- }
91
- ;
92
- node.children = children;
93
- }
94
- }
95
- return paths;
96
- };
97
- return {
98
- byPath,
99
- roots: compile(states, undefined)
100
- };
101
- };
102
- export const makeTarget = (path, value, options) => ({
103
- [TargetTypeId]: TargetTypeId,
104
- path,
105
- value,
106
- values: options?.values
107
- });
108
- export const isTarget = (u) => hasProperty(u, TargetTypeId);
109
- export const isSnapshot = (u) => hasProperty(u, "path") && hasProperty(u, "value");
110
- export const getSnapshotByPath = (snapshot, path, parents) => {
111
- if (snapshot.path === path) {
112
- return Option.some(snapshot);
113
- }
114
- if (!path.startsWith(`${snapshot.path}.`)) {
115
- return Option.none();
116
- }
117
- if (parents !== undefined) {
118
- parents[snapshot.path] = snapshot.value;
119
- }
120
- if (hasProperty(snapshot, "state") && isSnapshot(snapshot.state)) {
121
- return getSnapshotByPath(snapshot.state, path, parents);
122
- }
123
- if (hasProperty(snapshot, "states") && typeof snapshot.states === "object" && snapshot.states !== null) {
124
- for (const child of Object.values(snapshot.states)) {
125
- if (isSnapshot(child)) {
126
- const result = getSnapshotByPath(child, path, parents);
127
- if (Option.isSome(result)) {
128
- return result;
129
- }
130
- }
131
- }
132
- }
133
- return Option.none();
134
- };
135
- const MachineProtocolTypeId = Symbol.for("effect/Machine/protocol");
136
- const getProtocolSchemas = (machine) => {
137
- const protocol = machine[MachineProtocolTypeId];
138
- if (protocol === undefined) {
139
- throw new Error("Machine protocol is unavailable");
140
- }
141
- return protocol;
142
- };
143
- const setProtocolSchemas = (machine, protocol) => {
144
- Object.defineProperty(machine, MachineProtocolTypeId, {
145
- value: protocol,
146
- enumerable: false
147
- });
148
- };
149
- export const setProtocol = (machine) => {
150
- setProtocolSchemas(machine, {
151
- event: Schema.Union([...machine.events, ...machine.internalEvents]),
152
- emit: Schema.Union(machine.emits)
153
- });
154
- };
155
- export const copyProtocol = (source, target) => setProtocolSchemas(target, getProtocolSchemas(source));
156
- export const getEventName = (event) => hasProperty(event, "_tag") ? String(event._tag) : undefined;
157
- export const decodeBoundary = (machine, schema, value, options) => Schema.decodeUnknownEffect(Schema.toType(schema))(value).pipe(Effect.mapError((cause) => new MachineSchemaDecodeError({
158
- machineId: machine.id,
159
- boundary: options.boundary,
160
- cause,
161
- ...(options.state === undefined ? {} : { state: options.state }),
162
- ...(options.event === undefined ? {} : { event: options.event })
163
- })));
164
- export const decodeInput = (machine, schema, value) => decodeBoundary(machine, schema, value, { boundary: "input" });
165
- export const decodeEvent = (machine, event) => {
166
- const eventName = getEventName(event);
167
- return decodeBoundary(machine, getProtocolSchemas(machine).event, event, eventName === undefined ? { boundary: "event" } : { boundary: "event", event: eventName });
168
- };
169
- export const decodeEmit = (machine, event) => {
170
- const eventName = getEventName(event);
171
- return decodeBoundary(machine, getProtocolSchemas(machine).emit, event, eventName === undefined ? { boundary: "emit" } : { boundary: "emit", event: eventName });
172
- };
173
- export const decodeStateValue = (machine, node, value) => decodeBoundary(machine, node.schema, value, { boundary: "state", state: node.path });
174
- export const decodeOutputValue = (machine, node, value) => node.output === undefined
175
- ? Effect.succeed(value)
176
- : decodeBoundary(machine, node.output, value, { boundary: "output", state: node.path });
177
- export const getNode = (machine, path) => {
178
- const node = machine.stateNodes.byPath.get(path);
179
- if (node === undefined) {
180
- throw new Error(`Machine expected state path "${path}" to exist`);
181
- }
182
- return node;
183
- };
184
- export const hasOwn = (u, key) => Object.prototype.hasOwnProperty.call(u, key);
185
- export const isDescendantOf = (path, ancestor) => path.startsWith(`${ancestor}.`);
186
- export const isPathInSubtree = (path, ancestor) => path === ancestor || isDescendantOf(path, ancestor);
187
- export const getPathToRoot = (machine, path) => {
188
- const paths = [];
189
- let current = path;
190
- while (current !== undefined) {
191
- paths.unshift(current);
192
- current = getNode(machine, current).parent;
193
- }
194
- return paths;
195
- };
196
- export const pathDepth = (machine, path) => getPathToRoot(machine, path).length;
197
- export const compareDocumentOrder = (machine, left, right) => getNode(machine, left).order - getNode(machine, right).order;
198
- export const hasActiveChild = (machine, configuration, path) => getNode(machine, path).children.some((child) => configuration.active.has(child));
199
- export const getActiveLeafPaths = (machine, configuration) => {
200
- const leaves = Array.from(configuration.active)
201
- .filter((path) => !hasActiveChild(machine, configuration, path))
202
- .sort((left, right) => compareDocumentOrder(machine, left, right));
203
- if (leaves.length === 0) {
204
- throw new Error("Machine expected an active leaf state");
205
- }
206
- return leaves;
207
- };
208
- export const getLeafPath = (machine, configuration) => getActiveLeafPaths(machine, configuration)[0];
209
- export const getActiveLeafPathFrom = (machine, configuration, path) => {
210
- const leaves = getActiveLeafPaths(machine, configuration)
211
- .filter((leaf) => isPathInSubtree(leaf, path));
212
- if (leaves.length === 0) {
213
- throw new Error(`Machine expected state "${path}" to have an active leaf state`);
214
- }
215
- return leaves[0];
216
- };
217
- export const getRootPath = (machine, configuration) => {
218
- for (const path of configuration.active) {
219
- if (getNode(machine, path).parent === undefined) {
220
- return path;
221
- }
222
- }
223
- throw new Error("Machine expected an active root state");
224
- };
225
- export const getActiveValue = (configuration, path) => {
226
- if (!configuration.values.has(path)) {
227
- throw new Error(`Machine expected active state "${path}" to have a value`);
228
- }
229
- return configuration.values.get(path);
230
- };
231
- export const getParentValues = (machine, configuration, path) => {
232
- const parents = {};
233
- const paths = getPathToRoot(machine, path);
234
- for (let index = 0; index < paths.length - 1; index++) {
235
- const parent = paths[index];
236
- parents[parent] = getActiveValue(configuration, parent);
237
- }
238
- return parents;
239
- };
240
- export const getParentValue = (machine, configuration, path) => {
241
- const parent = getNode(machine, path).parent;
242
- return parent === undefined ? undefined : getActiveValue(configuration, parent);
243
- };
244
- export const getInitialEntryPaths = (machine, configuration) => {
245
- const visit = (path) => {
246
- if (!configuration.active.has(path)) {
247
- return [];
248
- }
249
- const node = getNode(machine, path);
250
- return [
251
- path,
252
- ...node.children.flatMap(visit)
253
- ];
254
- };
255
- return machine.stateNodes.roots.flatMap(visit);
256
- };
257
- export const snapshotFromPath = (machine, configuration, path) => {
258
- const node = getNode(machine, path);
259
- const snapshot = {
260
- path,
261
- value: getActiveValue(configuration, path)
262
- };
263
- if (node.type === "compound") {
264
- const child = node.children.find((child) => configuration.active.has(child));
265
- if (child === undefined) {
266
- throw new Error(`Machine expected compound state "${path}" to have an active child`);
267
- }
268
- snapshot.state = snapshotFromPath(machine, configuration, child);
269
- }
270
- if (node.type === "parallel") {
271
- const states = {};
272
- for (const child of node.children) {
273
- if (!configuration.active.has(child)) {
274
- throw new Error(`Machine expected parallel state "${path}" to have active child region "${child}"`);
275
- }
276
- const childNode = getNode(machine, child);
277
- states[childNode.key] = snapshotFromPath(machine, configuration, child);
278
- }
279
- snapshot.states = states;
280
- }
281
- return snapshot;
282
- };
283
- export const snapshotFromConfiguration = (machine, configuration) => {
284
- const snapshot = snapshotFromPath(machine, configuration, getRootPath(machine, configuration));
285
- const completed = Array.from(configuration.outputs)
286
- .map(([path, output]) => ({ path, output }));
287
- if (completed.length > 0) {
288
- ;
289
- snapshot.completed = completed;
290
- }
291
- return snapshot;
292
- };
293
- export const configurationFromSnapshot = (machine, snapshot) => {
294
- const active = new Set();
295
- const values = new Map();
296
- const snapshotOutputs = snapshot.completed;
297
- const visit = (current) => {
298
- const node = getNode(machine, String(current.path));
299
- if (!Schema.is(node.schema)(current.value)) {
300
- throw new Error(`Machine expected snapshot for "${node.path}" to match its schema`);
301
- }
302
- active.add(node.path);
303
- values.set(node.path, current.value);
304
- if (node.type === "compound") {
305
- if (!hasProperty(current, "state") || !isSnapshot(current.state)) {
306
- throw new Error(`Machine expected compound snapshot "${node.path}" to include an active child state`);
307
- }
308
- const child = getNode(machine, String(current.state.path));
309
- if (child.parent !== node.path) {
310
- throw new Error(`Machine expected snapshot "${child.path}" to be a child of "${node.path}"`);
311
- }
312
- visit(current.state);
313
- }
314
- if (node.type === "parallel") {
315
- if (!hasProperty(current, "states") || typeof current.states !== "object" || current.states === null) {
316
- throw new Error(`Machine expected parallel snapshot "${node.path}" to include active child regions`);
317
- }
318
- const states = current.states;
319
- for (const childPath of node.children) {
320
- const child = getNode(machine, childPath);
321
- const childSnapshot = states[child.key];
322
- if (!hasOwn(states, child.key) || !isSnapshot(childSnapshot)) {
323
- throw new Error(`Machine expected parallel snapshot "${node.path}" to include region "${child.key}"`);
324
- }
325
- const snapshotChild = getNode(machine, String(childSnapshot.path));
326
- if (snapshotChild.path !== child.path) {
327
- throw new Error(`Machine expected snapshot "${snapshotChild.path}" to be region "${child.path}"`);
328
- }
329
- visit(childSnapshot);
330
- }
331
- }
332
- };
333
- visit(snapshot);
334
- const outputs = new Map();
335
- if (snapshotOutputs !== undefined) {
336
- for (const { output, path } of snapshotOutputs) {
337
- if (active.has(path)) {
338
- outputs.set(path, output);
339
- }
340
- }
341
- }
342
- return { active, values, outputs };
343
- };
344
- export const normalizeConfiguration = (machine, state) => configurationFromSnapshot(machine, state);
345
- export const configurationFromSnapshotEffect = Effect.fnUntraced(function* (machine, snapshot) {
346
- const active = new Set();
347
- const values = new Map();
348
- const snapshotOutputs = snapshot.completed;
349
- const visit = Effect.fnUntraced(function* (current) {
350
- const node = getNode(machine, String(current.path));
351
- const value = yield* decodeStateValue(machine, node, current.value);
352
- active.add(node.path);
353
- values.set(node.path, value);
354
- if (node.type === "compound") {
355
- if (!hasProperty(current, "state") || !isSnapshot(current.state)) {
356
- throw new Error(`Machine expected compound snapshot "${node.path}" to include an active child state`);
357
- }
358
- const child = getNode(machine, String(current.state.path));
359
- if (child.parent !== node.path) {
360
- throw new Error(`Machine expected snapshot "${child.path}" to be a child of "${node.path}"`);
361
- }
362
- yield* visit(current.state);
363
- }
364
- if (node.type === "parallel") {
365
- if (!hasProperty(current, "states") || typeof current.states !== "object" || current.states === null) {
366
- throw new Error(`Machine expected parallel snapshot "${node.path}" to include active child regions`);
367
- }
368
- const states = current.states;
369
- for (const childPath of node.children) {
370
- const child = getNode(machine, childPath);
371
- const childSnapshot = states[child.key];
372
- if (!hasOwn(states, child.key) || !isSnapshot(childSnapshot)) {
373
- throw new Error(`Machine expected parallel snapshot "${node.path}" to include region "${child.key}"`);
374
- }
375
- const snapshotChild = getNode(machine, String(childSnapshot.path));
376
- if (snapshotChild.path !== child.path) {
377
- throw new Error(`Machine expected snapshot "${snapshotChild.path}" to be region "${child.path}"`);
378
- }
379
- yield* visit(childSnapshot);
380
- }
381
- }
382
- });
383
- yield* visit(snapshot);
384
- const outputs = new Map();
385
- if (snapshotOutputs !== undefined) {
386
- for (const { output, path } of snapshotOutputs) {
387
- if (active.has(path)) {
388
- outputs.set(path, output);
389
- }
390
- }
391
- }
392
- return { active, values, outputs };
393
- });
394
- export const normalizeConfigurationEffect = (machine, state) => configurationFromSnapshotEffect(machine, state).pipe(Effect.catchCause((cause) => {
395
- const error = Cause.findErrorOption(cause);
396
- return Option.isSome(error) && error.value instanceof MachineSchemaDecodeError
397
- ? Effect.fail(error.value)
398
- : Effect.fail(new MachineSchemaDecodeError({
399
- machineId: machine.id,
400
- boundary: "configuration",
401
- cause
402
- }));
403
- }));
404
- export const validateInitialConfiguration = (machine, configuration) => {
405
- for (const path of configuration.active) {
406
- const node = getNode(machine, path);
407
- if (node.type === "compound") {
408
- const child = node.children.find((child) => configuration.active.has(child));
409
- if (child !== node.initial) {
410
- throw new Error(`Machine initial state "${node.path}" must enter initial child "${node.initial}"`);
411
- }
412
- }
413
- if (node.type === "parallel") {
414
- for (const child of node.children) {
415
- if (!configuration.active.has(child)) {
416
- throw new Error(`Machine initial state "${node.path}" must enter child region "${child}"`);
417
- }
418
- }
419
- }
420
- }
421
- };
422
- export const configurationFromTargetPathEffect = Effect.fnUntraced(function* (machine, current, path, value, providedValues) {
423
- const node = getNode(machine, path);
424
- const active = new Set();
425
- const values = new Map();
426
- const outputs = new Map();
427
- const paths = getPathToRoot(machine, node.path);
428
- const pathSet = new Set(paths);
429
- for (const currentPath of paths) {
430
- const currentNode = getNode(machine, currentPath);
431
- active.add(currentPath);
432
- if (currentPath === node.path) {
433
- values.set(currentPath, yield* decodeStateValue(machine, currentNode, value));
434
- }
435
- else if (providedValues !== undefined && hasOwn(providedValues, currentPath)) {
436
- values.set(currentPath, yield* decodeStateValue(machine, currentNode, providedValues[currentPath]));
437
- }
438
- else if (current.values.has(currentPath)) {
439
- values.set(currentPath, current.values.get(currentPath));
440
- }
441
- else {
442
- throw new Error(`Machine target "${node.path}" requires a value for ancestor state "${currentPath}"`);
443
- }
444
- }
445
- for (const ancestor of paths) {
446
- const ancestorNode = getNode(machine, ancestor);
447
- if (ancestorNode.type === "parallel") {
448
- for (const child of ancestorNode.children) {
449
- if (pathSet.has(child) || !current.active.has(child)) {
450
- continue;
451
- }
452
- for (const activePath of current.active) {
453
- if (isPathInSubtree(activePath, child)) {
454
- active.add(activePath);
455
- if (current.values.has(activePath)) {
456
- values.set(activePath, current.values.get(activePath));
457
- }
458
- if (current.outputs.has(activePath)) {
459
- outputs.set(activePath, current.outputs.get(activePath));
460
- }
461
- }
462
- }
463
- }
464
- }
465
- }
466
- if (node.type === "compound" || node.type === "parallel") {
467
- throw new Error(`Machine target "${node.path}" must include an active child state`);
468
- }
469
- return { active, values, outputs };
470
- });
471
- export const normalizeTargetConfigurationEffect = (machine, current, target) => {
472
- if (isTarget(target)) {
473
- return configurationFromTargetPathEffect(machine, current, target.path, target.value, target.values);
474
- }
475
- if (isSnapshot(target)) {
476
- return normalizeConfigurationEffect(machine, target);
477
- }
478
- throw new Error("Machine expected transition target to be a snapshot or target builder result");
479
- };
480
- export const getStateConfigByPath = (machine, path) => machine.handlers[path];
481
- export const getActiveChildPath = (machine, configuration, path) => getNode(machine, path).children.find((child) => configuration.active.has(child));
482
- export const isDirectFinalPath = (machine, path) => getNode(machine, path).type === "final";
483
- export const hasCompletionHandler = (machine, path) => getStateConfigByPath(machine, path)?.onDone !== undefined;
484
- export const isActiveFinalNode = (machine, configuration, path) => {
485
- if (!configuration.active.has(path)) {
486
- return false;
487
- }
488
- const node = getNode(machine, path);
489
- if (node.type === "compound") {
490
- const child = getActiveChildPath(machine, configuration, path);
491
- return child !== undefined && isDirectFinalPath(machine, child);
492
- }
493
- if (node.type === "parallel") {
494
- for (const child of node.children) {
495
- if (!isActiveFinalNode(machine, configuration, child)) {
496
- return false;
497
- }
498
- }
499
- return true;
500
- }
501
- return isDirectFinalPath(machine, path);
502
- };
503
- export const isActiveFinalConfiguration = (machine, configuration) => {
504
- const root = getRootPath(machine, configuration);
505
- return isActiveFinalNode(machine, configuration, root) && !hasCompletionHandler(machine, root);
506
- };
507
- export const setCompletedOutput = (outputs, path, output) => {
508
- if (outputs.has(path)) {
509
- return {
510
- path,
511
- output: outputs.get(path),
512
- isNew: false
513
- };
514
- }
515
- outputs.set(path, output);
516
- return {
517
- path,
518
- output,
519
- isNew: true
520
- };
521
- };
522
- export const resolveFinalOutputEffect = Effect.fnUntraced(function* (machine, configuration, path, event, outputs) {
523
- const node = getNode(machine, path);
524
- const output = getStateConfigByPath(machine, path)?.output?.({
525
- state: getActiveValue(configuration, path),
526
- parent: getParentValue(machine, configuration, path),
527
- parents: getParentValues(machine, configuration, path),
528
- event,
529
- outputs
530
- });
531
- return yield* decodeOutputValue(machine, node, output);
532
- });
533
- export const completeActiveFinalNodeEffect = Effect.fnUntraced(function* (machine, configuration, path, event, outputs, completions) {
534
- if (!configuration.active.has(path)) {
535
- return undefined;
536
- }
537
- if (outputs.has(path)) {
538
- return {
539
- path,
540
- output: outputs.get(path),
541
- isNew: false
542
- };
543
- }
544
- const node = getNode(machine, path);
545
- if (node.type === "compound") {
546
- const child = getActiveChildPath(machine, configuration, path);
547
- if (child === undefined || !isDirectFinalPath(machine, child)) {
548
- return undefined;
549
- }
550
- const childCompletion = yield* completeActiveFinalNodeEffect(machine, configuration, child, event, outputs, completions);
551
- if (childCompletion === undefined) {
552
- return undefined;
553
- }
554
- const completion = setCompletedOutput(outputs, path, childCompletion.output);
555
- if (completion.isNew) {
556
- completions.push(completion);
557
- }
558
- return completion;
559
- }
560
- if (node.type === "parallel") {
561
- const regionOutputs = {};
562
- let completed = true;
563
- for (const child of node.children) {
564
- const childCompletion = yield* completeActiveFinalNodeEffect(machine, configuration, child, event, outputs, completions);
565
- if (childCompletion === undefined) {
566
- completed = false;
567
- }
568
- else {
569
- regionOutputs[getNode(machine, child).key] = childCompletion.output;
570
- }
571
- }
572
- if (!completed) {
573
- return undefined;
574
- }
575
- const completion = setCompletedOutput(outputs, path, yield* resolveFinalOutputEffect(machine, configuration, path, event, regionOutputs));
576
- if (completion.isNew) {
577
- completions.push(completion);
578
- }
579
- return completion;
580
- }
581
- if (!isDirectFinalPath(machine, path)) {
582
- return undefined;
583
- }
584
- const completion = setCompletedOutput(outputs, path, yield* resolveFinalOutputEffect(machine, configuration, path, event));
585
- if (completion.isNew) {
586
- completions.push(completion);
587
- }
588
- return completion;
589
- });
590
- export const completeConfigurationEffect = Effect.fnUntraced(function* (machine, configuration, event) {
591
- const outputs = new Map(configuration.outputs);
592
- const completions = [];
593
- const completed = {
594
- active: configuration.active,
595
- values: configuration.values,
596
- outputs
597
- };
598
- for (const path of Array.from(completed.active).sort((left, right) => {
599
- const depth = pathDepth(machine, right) - pathDepth(machine, left);
600
- return depth === 0 ? compareDocumentOrder(machine, left, right) : depth;
601
- })) {
602
- yield* completeActiveFinalNodeEffect(machine, completed, path, event, outputs, completions);
603
- }
604
- return { configuration: completed, completions };
605
- });
606
- const EncodedSnapshotSchema = Schema.Struct({
607
- _tag: Schema.Literal("MachineSnapshot"),
608
- active: Schema.Array(Schema.Struct({
609
- path: Schema.String,
610
- value: Schema.Unknown
611
- })),
612
- completed: Schema.optional(Schema.Array(Schema.Struct({
613
- path: Schema.String,
614
- output: Schema.optional(Schema.Unknown)
615
- })))
616
- });
617
- const encodeBoundary = (machine, schema, value, options) => Schema.encodeUnknownEffect(schema)(value).pipe(Effect.mapError((cause) => new MachineSchemaEncodeError({
618
- machineId: machine.id,
619
- boundary: options.boundary,
620
- state: options.state,
621
- cause
622
- })));
623
- const decodeEncodedBoundary = (machine, schema, value, options) => Schema.decodeUnknownEffect(schema)(value).pipe(Effect.mapError((cause) => new MachineSchemaDecodeError({
624
- machineId: machine.id,
625
- boundary: options.boundary,
626
- state: options.state,
627
- cause
628
- })));
629
- const getCompletionSchema = (machine, configuration, path) => {
630
- const node = getNode(machine, path);
631
- if (node.type === "compound") {
632
- const child = getActiveChildPath(machine, configuration, path);
633
- if (child === undefined) {
634
- throw new Error(`Machine expected completed state "${path}" to have an active child`);
635
- }
636
- return getCompletionSchema(machine, configuration, child);
637
- }
638
- return node.output ?? Schema.Void;
639
- };
640
- const validateEncodedConfiguration = (machine, configuration) => {
641
- const snapshot = snapshotFromConfiguration(machine, configuration);
642
- const normalized = configurationFromSnapshot(machine, snapshot);
643
- if (normalized.active.size !== configuration.active.size ||
644
- Array.from(configuration.active).some((path) => !normalized.active.has(path))) {
645
- throw new Error("Machine encoded snapshot contains states outside its active configuration");
646
- }
647
- return snapshot;
648
- };
649
- const failEncodeCause = (machine, cause) => {
650
- const error = Cause.findErrorOption(cause);
651
- return Option.isSome(error) && error.value instanceof MachineSchemaEncodeError
652
- ? Effect.fail(error.value)
653
- : Effect.fail(new MachineSchemaEncodeError({
654
- machineId: machine.id,
655
- boundary: "configuration",
656
- cause
657
- }));
658
- };
659
- const failDecodeCause = (machine, cause) => {
660
- const error = Cause.findErrorOption(cause);
661
- return Option.isSome(error) && error.value instanceof MachineSchemaDecodeError
662
- ? Effect.fail(error.value)
663
- : Effect.fail(new MachineSchemaDecodeError({
664
- machineId: machine.id,
665
- boundary: "configuration",
666
- cause
667
- }));
668
- };
669
- export const encodeSnapshot = (machine, snapshot) => Effect.gen(function* () {
670
- const configuration = yield* normalizeConfigurationEffect(machine, snapshot).pipe(Effect.mapError((error) => new MachineSchemaEncodeError({
671
- machineId: machine.id,
672
- boundary: error.boundary === "state" ? "state" : "configuration",
673
- ...(error.state === undefined ? {} : { state: error.state }),
674
- cause: error.cause
675
- })));
676
- const completionPaths = new Set();
677
- for (const completion of snapshot.completed ?? []) {
678
- if (completionPaths.has(completion.path)) {
679
- throw new Error(`Machine snapshot contains duplicate completion "${completion.path}"`);
680
- }
681
- if (!configuration.active.has(completion.path) || !isActiveFinalNode(machine, configuration, completion.path)) {
682
- throw new Error(`Machine snapshot contains invalid completion "${completion.path}"`);
683
- }
684
- completionPaths.add(completion.path);
685
- }
686
- const active = [];
687
- for (const path of Array.from(configuration.active).sort((left, right) => compareDocumentOrder(machine, left, right))) {
688
- const node = getNode(machine, path);
689
- active.push({
690
- path,
691
- value: yield* encodeBoundary(machine, node.schema, getActiveValue(configuration, path), {
692
- boundary: "state",
693
- state: path
694
- })
695
- });
696
- }
697
- const completed = [];
698
- for (const [path, output] of Array.from(configuration.outputs).sort(([left], [right]) => compareDocumentOrder(machine, left, right))) {
699
- if (!configuration.active.has(path) || !isActiveFinalNode(machine, configuration, path)) {
700
- throw new Error(`Machine encoded snapshot contains invalid completion "${path}"`);
701
- }
702
- const encodedOutput = yield* encodeBoundary(machine, getCompletionSchema(machine, configuration, path), output, {
703
- boundary: "output",
704
- state: path
705
- });
706
- completed.push({
707
- path,
708
- ...(encodedOutput === undefined ? {} : { output: encodedOutput })
709
- });
710
- }
711
- return {
712
- _tag: "MachineSnapshot",
713
- active,
714
- ...(completed.length === 0 ? {} : { completed })
715
- };
716
- }).pipe(Effect.catchCause((cause) => failEncodeCause(machine, cause)));
717
- export const decodeSnapshot = (machine, encoded) => Effect.gen(function* () {
718
- const decoded = yield* Schema.decodeUnknownEffect(EncodedSnapshotSchema)(encoded).pipe(Effect.mapError((cause) => new MachineSchemaDecodeError({
719
- machineId: machine.id,
720
- boundary: "configuration",
721
- cause
722
- })));
723
- const active = new Set();
724
- const values = new Map();
725
- for (const entry of decoded.active) {
726
- if (active.has(entry.path)) {
727
- throw new Error(`Machine encoded snapshot contains duplicate state "${entry.path}"`);
728
- }
729
- const node = getNode(machine, entry.path);
730
- active.add(entry.path);
731
- values.set(entry.path, yield* decodeEncodedBoundary(machine, node.schema, entry.value, {
732
- boundary: "state",
733
- state: entry.path
734
- }));
735
- }
736
- const configuration = {
737
- active,
738
- values,
739
- outputs: new Map()
740
- };
741
- const snapshot = validateEncodedConfiguration(machine, configuration);
742
- const completions = [];
743
- const completionPaths = new Set();
744
- for (const completion of decoded.completed ?? []) {
745
- if (completionPaths.has(completion.path)) {
746
- throw new Error(`Machine encoded snapshot contains duplicate completion "${completion.path}"`);
747
- }
748
- if (!active.has(completion.path) || !isActiveFinalNode(machine, configuration, completion.path)) {
749
- throw new Error(`Machine encoded snapshot contains invalid completion "${completion.path}"`);
750
- }
751
- completionPaths.add(completion.path);
752
- completions.push({
753
- path: completion.path,
754
- output: yield* decodeEncodedBoundary(machine, getCompletionSchema(machine, configuration, completion.path), completion.output, {
755
- boundary: "output",
756
- state: completion.path
757
- })
758
- });
759
- }
760
- if (completions.length > 0) {
761
- ;
762
- snapshot.completed = completions;
763
- }
764
- return snapshot;
765
- }).pipe(Effect.catchCause((cause) => failDecodeCause(machine, cause)));
766
- //# sourceMappingURL=machineModel.js.map