@typeonce/effect-machine 0.6.0 → 0.6.1

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 (38) hide show
  1. package/package.json +5 -5
  2. package/src/Machine.ts +6873 -0
  3. package/src/index.ts +1 -0
  4. package/src/internal/machine/activities.ts +108 -0
  5. package/src/internal/machine/atom.ts +636 -0
  6. package/src/internal/machine/cluster.ts +394 -0
  7. package/src/internal/machine/command.ts +58 -0
  8. package/src/internal/machine/commandRuntime.ts +43 -0
  9. package/src/internal/machine/configuration.ts +1331 -0
  10. package/src/internal/machine/errors.ts +87 -0
  11. package/src/internal/machine/executionPlan.ts +996 -0
  12. package/src/internal/machine/invocation.ts +119 -0
  13. package/src/internal/machine/machine.ts +1747 -0
  14. package/src/internal/machine/planner.ts +1933 -0
  15. package/src/internal/machine/process.ts +906 -0
  16. package/src/internal/machine/protocol.ts +322 -0
  17. package/src/internal/machine/readiness.ts +10 -0
  18. package/src/internal/machine/runtime.ts +2512 -0
  19. package/src/internal/machine/serialization.ts +498 -0
  20. package/src/internal/machine/stateDefinition.ts +270 -0
  21. package/src/internal/machine/symbols.ts +2 -0
  22. package/src/internal/machine/topology.ts +479 -0
  23. package/src/internal/testing/machine/arbitrary.ts +102 -0
  24. package/src/internal/testing/machine/exploration.ts +331 -0
  25. package/src/internal/testing/machine/finiteModel.ts +1498 -0
  26. package/src/internal/testing/machine/invariant.ts +372 -0
  27. package/src/internal/testing/machine/probe.ts +79 -0
  28. package/src/internal/testing/machine/referenceModel.ts +1505 -0
  29. package/src/internal/testing/machine/runtime.ts +1710 -0
  30. package/src/internal/testing/machine/runtimeInvariant.ts +486 -0
  31. package/src/internal/testing/machine/trace.ts +150 -0
  32. package/src/internal/testing/machine/verification.ts +1890 -0
  33. package/src/testing/MachineTest.ts +2067 -0
  34. package/src/testing/index.ts +7 -0
  35. package/src/unstable/cluster/ClusterMachine.ts +390 -0
  36. package/src/unstable/cluster/index.ts +1 -0
  37. package/src/unstable/reactivity/AtomMachine.ts +649 -0
  38. package/src/unstable/reactivity/index.ts +1 -0
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Property-based testing and planner trace utilities.
3
+ *
4
+ * @since 0.4.0
5
+ */
6
+
7
+ export * as MachineTest from "./MachineTest.js"
@@ -0,0 +1,390 @@
1
+ /**
2
+ * Runs Effect machines as persisted Cluster entities.
3
+ *
4
+ * @since 0.4.0
5
+ */
6
+ import type * as Effect from "effect/Effect"
7
+ import type * as Layer from "effect/Layer"
8
+ import type * as Option from "effect/Option"
9
+ import * as Schema from "effect/Schema"
10
+ import type { Entity, MessageStorage, Sharding, Snowflake } from "effect/unstable/cluster"
11
+ import type { Rpc } from "effect/unstable/rpc"
12
+ import * as internal from "../../internal/machine/cluster.js"
13
+ import { Accepted, Rejected, Storage } from "../../internal/machine/cluster.js"
14
+ import type { EnsureExecutable } from "../../internal/machine/readiness.js"
15
+ import type * as Machine from "../../Machine.js"
16
+
17
+ type Snowflake = Snowflake.Snowflake
18
+
19
+ /**
20
+ * Persisted machine checkpoint owned by the Cluster bridge.
21
+ *
22
+ * **Details**
23
+ *
24
+ * Machine identity and deployment version are stored around the generic
25
+ * encoded snapshot. The request id records the request that produced the
26
+ * checkpoint.
27
+ *
28
+ * @category models
29
+ * @since 0.4.0
30
+ */
31
+ export interface Checkpoint {
32
+ /** Stable identity of the machine definition that produced the snapshot. */
33
+ readonly machineId: string
34
+
35
+ /** Application-controlled deployment or migration version. */
36
+ readonly version: string
37
+
38
+ /** Cluster request whose accepted transition produced this checkpoint. */
39
+ readonly requestId: Snowflake
40
+
41
+ /** Encoded logical machine state and completed outputs. */
42
+ readonly snapshot: Machine.Machine.EncodedSnapshot
43
+ }
44
+
45
+ /**
46
+ * Result of loading a checkpoint for a Cluster machine request.
47
+ *
48
+ * **Details**
49
+ *
50
+ * `processed` reports whether the exact Cluster request id was already
51
+ * committed. Storage implementations must retain enough request ids to detect
52
+ * redelivery even after later requests have advanced the checkpoint.
53
+ *
54
+ * @category models
55
+ * @since 0.4.0
56
+ */
57
+ export interface LoadResult {
58
+ /** Latest checkpoint for the entity, when one has been committed. */
59
+ readonly checkpoint: Option.Option<Checkpoint>
60
+
61
+ /** Whether the requested id has already been committed. */
62
+ readonly processed: boolean
63
+ }
64
+
65
+ /**
66
+ * Result of atomically committing a Cluster machine request.
67
+ *
68
+ * @category models
69
+ * @since 0.4.0
70
+ */
71
+ export type CommitResult = CommitResult.Committed | CommitResult.Duplicate
72
+
73
+ /**
74
+ * Constructors and types for Cluster machine commit results.
75
+ *
76
+ * @category models
77
+ * @since 0.4.0
78
+ */
79
+ export const CommitResult = {
80
+ Committed: (): CommitResult.Committed => ({ _tag: "Committed" }),
81
+ Duplicate: (): CommitResult.Duplicate => ({ _tag: "Duplicate" })
82
+ }
83
+
84
+ /**
85
+ * Types for Cluster machine commit results.
86
+ *
87
+ * @category models
88
+ * @since 0.4.0
89
+ */
90
+ export declare namespace CommitResult {
91
+ /**
92
+ * Indicates that the request id and checkpoint were committed atomically.
93
+ *
94
+ * @category models
95
+ * @since 0.4.0
96
+ */
97
+ export interface Committed {
98
+ readonly _tag: "Committed"
99
+ }
100
+
101
+ /**
102
+ * Indicates that the request id was already committed.
103
+ *
104
+ * @category models
105
+ * @since 0.4.0
106
+ */
107
+ export interface Duplicate {
108
+ readonly _tag: "Duplicate"
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Checkpoint persistence service used by Cluster machines.
114
+ *
115
+ * **When to use**
116
+ *
117
+ * Use to connect `ClusterMachine` to a durable checkpoint store that can
118
+ * atomically deduplicate request ids and replace the current checkpoint.
119
+ *
120
+ * **Gotchas**
121
+ *
122
+ * For checkpoint and emitted-message persistence to commit atomically, this
123
+ * service must join the transaction opened through the configured
124
+ * `MessageStorage`. The reply is persisted after that transaction; storing the
125
+ * request id with the checkpoint makes a redelivery recover that reply without
126
+ * applying the transition again. A separate transaction or database cannot
127
+ * provide checkpoint-and-emission atomicity.
128
+ *
129
+ * @category services
130
+ * @since 0.4.0
131
+ */
132
+ export { Storage }
133
+
134
+ /**
135
+ * Successful result returned after a Cluster machine request is committed or
136
+ * recognized as a redelivery.
137
+ *
138
+ * @category models
139
+ * @since 0.4.0
140
+ */
141
+ export { Accepted }
142
+
143
+ /**
144
+ * Schema for reasons a Cluster machine request can be rejected without
145
+ * advancing its checkpoint.
146
+ *
147
+ * @category models
148
+ * @since 0.4.0
149
+ */
150
+ export const RejectionReason = Schema.Literals([
151
+ "MachineIdMismatch",
152
+ "VersionMismatch",
153
+ "InvalidCheckpoint",
154
+ "UnsupportedProcessLocal",
155
+ "TransitionFailure",
156
+ "PersistenceFailure",
157
+ "EmissionFailure"
158
+ ])
159
+
160
+ /**
161
+ * Type of {@link RejectionReason}.
162
+ *
163
+ * @category models
164
+ * @since 0.4.0
165
+ */
166
+ export type RejectionReason = typeof RejectionReason.Type
167
+
168
+ /**
169
+ * Rejected Cluster machine request. Transaction-participating durable storage
170
+ * leaves the previous checkpoint in place and suppresses emitted events.
171
+ *
172
+ * @category models
173
+ * @since 0.4.0
174
+ */
175
+ export { Rejected }
176
+
177
+ /**
178
+ * Schema for Cluster machine request outcomes.
179
+ *
180
+ * @category schemas
181
+ * @since 0.4.0
182
+ */
183
+ export const SendResult = Schema.Union([Accepted, Rejected])
184
+
185
+ type SendRpc<Events extends ReadonlyArray<Machine.Machine.TaggedSchema>> = Rpc.Rpc<
186
+ "send",
187
+ Schema.Union<Events>,
188
+ typeof SendResult
189
+ >
190
+
191
+ type MachineEvents<M extends Machine.Machine.Any> = Machine.Machine.InputEvents<M>
192
+
193
+ type MachineEmits<M extends Machine.Machine.Any> = Machine.Machine.Emits<M>
194
+
195
+ /**
196
+ * Cluster adapter for one machine definition and entity type.
197
+ *
198
+ * **Details**
199
+ *
200
+ * The adapter exposes one persisted `send` RPC. Entity requests are serialized
201
+ * by the normal Cluster entity concurrency and every accepted request advances
202
+ * the checkpoint at most once.
203
+ *
204
+ * @category models
205
+ * @since 0.4.0
206
+ */
207
+ export interface ClusterMachine<
208
+ in out Type extends string,
209
+ in out M extends Machine.Machine.Any,
210
+ out Services = MachineServices<M>
211
+ > {
212
+ /** Machine definition executed by each entity instance. */
213
+ readonly machine: M
214
+
215
+ /** Cluster entity exposing the persisted, schema-validated `send` RPC. */
216
+ readonly entity: Entity.Entity<Type, SendRpc<MachineEvents<M>>>
217
+
218
+ /**
219
+ * Creates the Cluster entity layer for this machine.
220
+ *
221
+ * **Gotchas**
222
+ *
223
+ * `enqueue` runs after the checkpoint write in the same `MessageStorage`
224
+ * transaction. It must durably enqueue emitted events in that transaction;
225
+ * arbitrary external effects are not atomic with the checkpoint. The reply
226
+ * is persisted after commit and recovered through request-id deduplication if
227
+ * delivery is interrupted. Machines that never emit may omit `enqueue`.
228
+ *
229
+ * @since 0.4.0
230
+ */
231
+ readonly toLayer: <R = never>(options?: {
232
+ readonly enqueue?: (
233
+ event: Machine.Machine.EmitOf<MachineEmits<M>>
234
+ ) => Effect.Effect<void, unknown, R>
235
+ }) => Layer.Layer<never, never, Storage | MessageStorage.MessageStorage | Sharding.Sharding | R | Services>
236
+ }
237
+
238
+ type MachineServices<M extends Machine.Machine.Any> =
239
+ | ExcludeCompatibleRuntime<
240
+ Machine.ExecutionServices<Machine.Machine.Services<M> | Machine.Machine.InitialServices<M>>,
241
+ Machine.Machine.Event<M>,
242
+ Machine.Machine.Emit<M>
243
+ >
244
+ | Machine.Machine.SnapshotDecodingServices<Machine.Machine.States<M>>
245
+ | Machine.Machine.SnapshotEncodingServices<Machine.Machine.States<M>>
246
+
247
+ type IsAny<A> = 0 extends (1 & A) ? true : false
248
+
249
+ type ExcludeCompatibleRuntime<Requirements, Events, Emits> = Requirements extends Machine.Runtime.Requirement<
250
+ infer RequiredEvents,
251
+ infer RequiredEmits
252
+ > ? IsAny<Requirements> extends true ? Requirements
253
+ : [RequiredEvents] extends [Events] ? [RequiredEmits] extends [Emits] ? never : Requirements
254
+ : Requirements
255
+ : Requirements
256
+
257
+ /**
258
+ * Creates an in-memory Cluster machine checkpoint store.
259
+ *
260
+ * **When to use**
261
+ *
262
+ * Use when you test or run a local process that does not require checkpoints
263
+ * to survive a restart.
264
+ *
265
+ * **Gotchas**
266
+ *
267
+ * This store is not durable and does not provide rollback with the in-memory
268
+ * `MessageStorage` transaction marker.
269
+ *
270
+ * @category constructors
271
+ * @since 0.4.0
272
+ */
273
+ export const makeMemory: Effect.Effect<Storage["Service"]> = internal.makeMemory
274
+
275
+ /**
276
+ * Layer providing the in-memory Cluster machine checkpoint store.
277
+ *
278
+ * @category layers
279
+ * @since 0.4.0
280
+ */
281
+ export const layerMemory: Layer.Layer<Storage> = internal.layerMemory
282
+
283
+ /**
284
+ * Creates a persisted Cluster entity adapter for a machine.
285
+ *
286
+ * **When to use**
287
+ *
288
+ * Use when each Cluster entity id should own one durable machine snapshot and
289
+ * accept schema-validated machine events through a persisted `send` RPC.
290
+ *
291
+ * **Details**
292
+ *
293
+ * A missing checkpoint runs initial planning before the first event. Existing
294
+ * checkpoints are identity-checked, version-checked, decoded, and resumed
295
+ * without rerunning initial entry behavior. Final checkpoints accept later
296
+ * requests as no-ops. The stable bridge identity is `machine.id` when present,
297
+ * otherwise the Cluster entity type.
298
+ *
299
+ * **Gotchas**
300
+ *
301
+ * Invoked processes, spawned children, action-time `runtime.raise`, timers,
302
+ * subscriptions, and other process-local state are not durable and are
303
+ * rejected. Planning-time raised events remain part of the current macrostep.
304
+ * Arbitrary action effects may run again after a crash before checkpoint
305
+ * commit, so the bridge does not provide exactly-once external effects.
306
+ *
307
+ * **Example**
308
+ *
309
+ * ```ts
310
+ * import { Schema } from "effect"
311
+ * import { Machine } from "@typeonce/effect-machine"
312
+ * import { ClusterMachine } from "@typeonce/effect-machine/cluster"
313
+ *
314
+ * class Idle extends Schema.TaggedClass<Idle>("Idle")("Idle", {}) {}
315
+ * const States = Machine.defineStates({ Idle })
316
+ * const machine = Machine.make({
317
+ * states: States.states,
318
+ * events: [],
319
+ * initial: () => States.initial.Idle.from()
320
+ * }).handle({ Idle: {} })
321
+ *
322
+ * const adapter = ClusterMachine.make("IdleMachine", machine, { version: "1" })
323
+ * ```
324
+ *
325
+ * @category constructors
326
+ * @since 0.4.0
327
+ */
328
+ export const make: <
329
+ const Type extends string,
330
+ States extends Machine.Machine.StateSchemas,
331
+ Events extends ReadonlyArray<Machine.Machine.TaggedSchema>,
332
+ Input extends Schema.Top,
333
+ UnhandledStates extends Machine.Machine.StateIdentifier<States>,
334
+ E,
335
+ R,
336
+ InitialE,
337
+ InitialR,
338
+ FinalStates extends Machine.Machine.StateIdentifier<States>,
339
+ Output,
340
+ Emits extends ReadonlyArray<Machine.Machine.TaggedSchema>,
341
+ OutputStates extends Machine.Machine.StateIdentifier<States>,
342
+ InputEvents extends ReadonlyArray<Machine.Machine.TaggedSchema> = Events
343
+ >(
344
+ type: Type,
345
+ machine:
346
+ & Machine.Machine<
347
+ States,
348
+ Events,
349
+ Input,
350
+ UnhandledStates,
351
+ E,
352
+ R,
353
+ InitialE,
354
+ InitialR,
355
+ FinalStates,
356
+ Output,
357
+ Emits,
358
+ OutputStates,
359
+ InputEvents
360
+ >
361
+ & EnsureExecutable<States, UnhandledStates, OutputStates>,
362
+ options: {
363
+ readonly version: string
364
+ },
365
+ ...input: [...Machine.Machine.InputArgs<Input>]
366
+ ) => ClusterMachine<
367
+ Type,
368
+ Machine.Machine<
369
+ States,
370
+ Events,
371
+ Input,
372
+ UnhandledStates,
373
+ E,
374
+ R,
375
+ InitialE,
376
+ InitialR,
377
+ FinalStates,
378
+ Output,
379
+ Emits,
380
+ OutputStates,
381
+ InputEvents
382
+ >,
383
+ | ExcludeCompatibleRuntime<
384
+ Machine.ExecutionServices<R | InitialR>,
385
+ Machine.Machine.EventOf<Events>,
386
+ Machine.Machine.EmitOf<Emits>
387
+ >
388
+ | Machine.Machine.SnapshotDecodingServices<States>
389
+ | Machine.Machine.SnapshotEncodingServices<States>
390
+ > = internal.make
@@ -0,0 +1 @@
1
+ export * as ClusterMachine from "./ClusterMachine.js"