@typeonce/effect-machine-devtools 0.24.0 → 0.26.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 (82) hide show
  1. package/NOTICE +4 -0
  2. package/README.md +13 -13
  3. package/dist/DevToolsProtocol.d.ts +66 -630
  4. package/dist/DevToolsProtocol.d.ts.map +1 -1
  5. package/dist/DevToolsProtocol.js +0 -190
  6. package/dist/DevToolsProtocol.js.map +1 -1
  7. package/dist/MachineDocument.d.ts +38 -18
  8. package/dist/MachineDocument.d.ts.map +1 -1
  9. package/dist/MachineDocument.js +14 -12
  10. package/dist/MachineDocument.js.map +1 -1
  11. package/dist/MachineRegistry.d.ts +22 -2
  12. package/dist/MachineRegistry.d.ts.map +1 -1
  13. package/dist/MachineWalkthrough.d.ts +171 -0
  14. package/dist/MachineWalkthrough.d.ts.map +1 -0
  15. package/dist/MachineWalkthrough.js +98 -0
  16. package/dist/MachineWalkthrough.js.map +1 -0
  17. package/dist/ProjectInspector.d.ts +0 -2
  18. package/dist/ProjectInspector.d.ts.map +1 -1
  19. package/dist/ProjectInspector.js.map +1 -1
  20. package/dist/client/assets/index-BsorPSDS.css +1 -0
  21. package/dist/client/assets/index-eiptehRd.js +37 -0
  22. package/dist/client/index.html +4 -4
  23. package/dist/index.d.ts +2 -2
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +2 -2
  26. package/dist/index.js.map +1 -1
  27. package/dist/internal/devServer.d.ts.map +1 -1
  28. package/dist/internal/devServer.js +4 -64
  29. package/dist/internal/devServer.js.map +1 -1
  30. package/dist/internal/evaluationWorker.d.ts.map +1 -1
  31. package/dist/internal/evaluationWorker.js +7 -263
  32. package/dist/internal/evaluationWorker.js.map +1 -1
  33. package/dist/internal/machineDocument.d.ts.map +1 -1
  34. package/dist/internal/machineDocument.js +3 -1
  35. package/dist/internal/machineDocument.js.map +1 -1
  36. package/dist/internal/machineWalkthrough.d.ts +26 -0
  37. package/dist/internal/machineWalkthrough.d.ts.map +1 -0
  38. package/dist/internal/machineWalkthrough.js +256 -0
  39. package/dist/internal/machineWalkthrough.js.map +1 -0
  40. package/dist/internal/projectInspector.d.ts.map +1 -1
  41. package/dist/internal/projectInspector.js +1 -11
  42. package/dist/internal/projectInspector.js.map +1 -1
  43. package/index.html +2 -2
  44. package/package.json +8 -7
  45. package/src/DevToolsProtocol.ts +0 -285
  46. package/src/MachineDocument.ts +21 -19
  47. package/src/MachineWalkthrough.ts +199 -0
  48. package/src/ProjectInspector.ts +0 -5
  49. package/src/index.ts +2 -2
  50. package/src/internal/browser/chart-layout-policy.ts +206 -0
  51. package/src/internal/browser/chart-layout.ts +686 -0
  52. package/src/internal/browser/chart-model.ts +244 -0
  53. package/src/internal/browser/chart-renderer.ts +774 -0
  54. package/src/internal/browser/example-machine.ts +15 -6
  55. package/src/internal/browser/input-form.ts +1 -418
  56. package/src/internal/browser/invoke-outcomes-example.ts +231 -0
  57. package/src/internal/browser/parallel-completion-example.ts +199 -0
  58. package/src/internal/browser/planner-example.ts +2 -0
  59. package/src/internal/browser/protocol-events-example.ts +200 -0
  60. package/src/internal/browser/styles.css +974 -342
  61. package/src/internal/browser/transition-semantics-example.ts +245 -0
  62. package/src/internal/browser/visualizer-analysis.ts +52 -0
  63. package/src/internal/browser/visualizer-app.ts +874 -706
  64. package/src/internal/browser/visualizer-model.ts +104 -0
  65. package/src/internal/devServer.ts +4 -82
  66. package/src/internal/evaluationWorker.ts +7 -371
  67. package/src/internal/machineDocument.ts +3 -1
  68. package/src/internal/machineWalkthrough.ts +355 -0
  69. package/src/internal/projectInspector.ts +3 -31
  70. package/dist/MachineSimulator.d.ts +0 -169
  71. package/dist/MachineSimulator.d.ts.map +0 -1
  72. package/dist/MachineSimulator.js +0 -98
  73. package/dist/MachineSimulator.js.map +0 -1
  74. package/dist/client/assets/index-B49Tjawc.js +0 -14
  75. package/dist/client/assets/index-BKH0cOG2.css +0 -1
  76. package/dist/internal/machineSimulator.d.ts +0 -5
  77. package/dist/internal/machineSimulator.d.ts.map +0 -1
  78. package/dist/internal/machineSimulator.js +0 -156
  79. package/dist/internal/machineSimulator.js.map +0 -1
  80. package/src/MachineSimulator.ts +0 -154
  81. package/src/internal/browser/simulation-client.ts +0 -20
  82. package/src/internal/machineSimulator.ts +0 -199
@@ -0,0 +1,231 @@
1
+ import { Machine } from "@typeonce/effect-machine"
2
+ import { Effect, Schema, Stream } from "effect"
3
+
4
+ class ChildWorking extends Schema.TaggedClass<ChildWorking>("InvokeGalleryChildWorking")("Working", {
5
+ task: Schema.String
6
+ }) {}
7
+ class ChildDone extends Schema.TaggedClass<ChildDone>("InvokeGalleryChildDone")("Done", {
8
+ result: Schema.String
9
+ }) {}
10
+ class FinishChild extends Schema.TaggedClass<FinishChild>("InvokeGalleryFinishChild")("FinishChild", {}) {}
11
+
12
+ const ChildStates = Machine.states({
13
+ Working: ChildWorking,
14
+ Done: { schema: ChildDone, type: "final", output: Schema.String }
15
+ })
16
+
17
+ export const invokeGalleryChildMachine = Machine.make({
18
+ id: "invoke-gallery-child",
19
+ states: ChildStates.states,
20
+ events: Machine.events(FinishChild),
21
+ initial: (to) => to.Working().resolve(({ target }) => target.decoded(new ChildWorking({ task: "render-preview" })))
22
+ }).handle({
23
+ Working: {
24
+ on: {
25
+ FinishChild: (to) =>
26
+ to.full.Done().resolve(({ state, target }) =>
27
+ target.decoded(new ChildDone({ result: `${state.task}:complete` }))
28
+ )
29
+ }
30
+ },
31
+ Done: {
32
+ output: ({ state }) => state.result
33
+ }
34
+ })
35
+
36
+ const InvokedChild = Machine.child("preview-worker", invokeGalleryChildMachine)
37
+
38
+ class Gallery extends Schema.TaggedClass<Gallery>("InvokeGallery")("Gallery", {
39
+ selectedDemo: Schema.NullOr(Schema.String)
40
+ }) {}
41
+ class Choose extends Schema.TaggedClass<Choose>("InvokeGalleryChoose")("Choose", {}) {}
42
+ class LoadingDocument extends Schema.TaggedClass<LoadingDocument>("InvokeGalleryLoadingDocument")(
43
+ "LoadingDocument",
44
+ { request: Schema.String }
45
+ ) {}
46
+ class StreamingUpdates extends Schema.TaggedClass<StreamingUpdates>("InvokeGalleryStreamingUpdates")(
47
+ "StreamingUpdates",
48
+ { values: Schema.Array(Schema.Number) }
49
+ ) {}
50
+ class WaitingForTimeout extends Schema.TaggedClass<WaitingForTimeout>("InvokeGalleryWaitingForTimeout")(
51
+ "WaitingForTimeout",
52
+ { delay: Schema.Literal("2 seconds") }
53
+ ) {}
54
+ class WatchingProcess extends Schema.TaggedClass<WatchingProcess>("InvokeGalleryWatchingProcess")(
55
+ "WatchingProcess",
56
+ { revision: Schema.Number }
57
+ ) {}
58
+ class RunningChild extends Schema.TaggedClass<RunningChild>("InvokeGalleryRunningChild")("RunningChild", {}) {}
59
+ class Completed extends Schema.TaggedClass<Completed>("InvokeGalleryCompleted")("Completed", {
60
+ source: Schema.String,
61
+ result: Schema.String
62
+ }) {}
63
+ class Failed extends Schema.TaggedClass<Failed>("InvokeGalleryFailed")("Failed", {
64
+ source: Schema.String,
65
+ message: Schema.String
66
+ }) {}
67
+
68
+ class RunEffect extends Schema.TaggedClass<RunEffect>("InvokeGalleryRunEffect")("RunEffect", {
69
+ request: Schema.String
70
+ }) {}
71
+ class RunStream extends Schema.TaggedClass<RunStream>("InvokeGalleryRunStream")("RunStream", {}) {}
72
+ class RunTimer extends Schema.TaggedClass<RunTimer>("InvokeGalleryRunTimer")("RunTimer", {}) {}
73
+ class RunProcess extends Schema.TaggedClass<RunProcess>("InvokeGalleryRunProcess")("RunProcess", {}) {}
74
+ class RunChild extends Schema.TaggedClass<RunChild>("InvokeGalleryRunChild")("RunChild", {}) {}
75
+ class Reset extends Schema.TaggedClass<Reset>("InvokeGalleryReset")("Reset", {}) {}
76
+ class StreamValue extends Schema.TaggedClass<StreamValue>("InvokeGalleryStreamValue")("StreamValue", {
77
+ value: Schema.Number
78
+ }) {}
79
+
80
+ const GalleryEvents = Machine.events(RunEffect, RunStream, RunTimer, RunProcess, RunChild, Reset)
81
+ const GalleryInternalEvents = Machine.internalEvents(StreamValue)
82
+ const processLogic = Machine.logic({
83
+ initial: "starting" as "starting" | "ready",
84
+ run: () => Effect.fail("process stopped")
85
+ })
86
+
87
+ const GalleryStates = Machine.states({
88
+ Gallery: {
89
+ schema: Gallery,
90
+ initial: "Choose",
91
+ states: {
92
+ Choose,
93
+ LoadingDocument,
94
+ StreamingUpdates,
95
+ WaitingForTimeout,
96
+ WatchingProcess,
97
+ RunningChild
98
+ }
99
+ },
100
+ Completed,
101
+ Failed
102
+ })
103
+
104
+ export const invokeOutcomesMachine = Machine.make({
105
+ id: "invoke-outcomes",
106
+ states: GalleryStates.states,
107
+ events: GalleryEvents,
108
+ internalEvents: GalleryInternalEvents,
109
+ initial: (to) =>
110
+ to.Gallery.initial.resolve(({ target }) =>
111
+ target.decoded(
112
+ new Gallery({ selectedDemo: null }),
113
+ (gallery) => gallery.Choose.decoded(new Choose({}))
114
+ )
115
+ )
116
+ }).handle({
117
+ Gallery: {
118
+ initialize: ({ builder }) => builder.decoded(new Choose({})),
119
+ on: {
120
+ Reset: (to) => to.local.Choose().resolve(({ target }) => target.decoded(new Choose({})))
121
+ },
122
+ states: {
123
+ Choose: {
124
+ on: {
125
+ RunEffect: (to) =>
126
+ to.local.LoadingDocument().resolve(({ event, target }) =>
127
+ target.decoded(new LoadingDocument({ request: event.request }))
128
+ ),
129
+ RunStream: (to) =>
130
+ to.local.StreamingUpdates().resolve(({ target }) => target.decoded(new StreamingUpdates({ values: [] }))),
131
+ RunTimer: (to) =>
132
+ to.local.WaitingForTimeout().resolve(({ target }) =>
133
+ target.decoded(new WaitingForTimeout({ delay: "2 seconds" }))
134
+ ),
135
+ RunProcess: (to) =>
136
+ to.local.WatchingProcess().resolve(({ target }) => target.decoded(new WatchingProcess({ revision: 1 }))),
137
+ RunChild: (to) => to.local.RunningChild().resolve(({ target }) => target.decoded(new RunningChild({})))
138
+ }
139
+ },
140
+ LoadingDocument: {
141
+ invoke: (from) =>
142
+ from.effect(
143
+ "load-document",
144
+ ({ state }) =>
145
+ state.request === "fail" ? Effect.fail("document unavailable") : Effect.succeed("document loaded")
146
+ ).onDone((to) =>
147
+ to.full.Completed().resolve(({ output, target }) =>
148
+ target.decoded(new Completed({ source: "effect", result: output }))
149
+ )
150
+ ).onFailure((to) =>
151
+ to.full.Failed().resolve(({ error, target }) =>
152
+ target.decoded(new Failed({ source: "effect", message: error }))
153
+ )
154
+ )
155
+ },
156
+ StreamingUpdates: {
157
+ invoke: (from) =>
158
+ from.stream(
159
+ "document-updates",
160
+ () => Stream.fromIterable([1, 2, 3]).pipe(Stream.concat(Stream.fail("stream disconnected")))
161
+ ).onElement((to) =>
162
+ to.none.resolve(({ element }, enqueue) => {
163
+ enqueue.raise(GalleryInternalEvents.StreamValue({ value: element }))
164
+ })
165
+ ).onDone((to) =>
166
+ to.full.Completed().resolve(({ state, target }) =>
167
+ target.decoded(new Completed({ source: "stream", result: state.values.join(", ") }))
168
+ )
169
+ ).onFailure((to) =>
170
+ to.full.Failed().resolve(({ error, target }) =>
171
+ target.decoded(new Failed({ source: "stream", message: error }))
172
+ )
173
+ ),
174
+ on: {
175
+ StreamValue: (to) =>
176
+ to.local.StreamingUpdates().resolve(({ event, state, target }) =>
177
+ target.decoded(new StreamingUpdates({ values: [...state.values, event.value] }))
178
+ )
179
+ }
180
+ },
181
+ WaitingForTimeout: {
182
+ invoke: (from) =>
183
+ from.timer("request-timeout", "2 seconds").onDone((to) =>
184
+ to.full.Completed().resolve(({ target }) =>
185
+ target.decoded(new Completed({ source: "timer", result: "timeout elapsed" }))
186
+ )
187
+ )
188
+ },
189
+ WatchingProcess: {
190
+ invoke: (from) =>
191
+ from.logic("status-worker", {
192
+ address: Machine.childAddress("status-worker"),
193
+ logic: processLogic
194
+ }).onFailure((to) =>
195
+ to.full.Failed().resolve(({ error, target }) =>
196
+ target.decoded(new Failed({ source: "process", message: String(error) }))
197
+ )
198
+ ).onSnapshot((to) =>
199
+ to.branches({
200
+ ready: { title: "Worker reports ready", target: to.full.Completed() },
201
+ waiting: { title: "Worker is still starting", target: to.none }
202
+ }).resolve(({ select, snapshot }) =>
203
+ snapshot.state === "ready"
204
+ ? select.ready.decoded(new Completed({ source: "process", result: "ready" }))
205
+ : select.waiting()
206
+ )
207
+ )
208
+ },
209
+ RunningChild: {
210
+ invoke: (from) =>
211
+ from.child(InvokedChild).onDone((to) =>
212
+ to.full.Completed().resolve(({ output, target }) =>
213
+ target.decoded(new Completed({ source: "child machine", result: output }))
214
+ )
215
+ )
216
+ }
217
+ }
218
+ },
219
+ Completed: {
220
+ on: {
221
+ Reset: (to) =>
222
+ to.full.Gallery.initial.resolve(({ target }) => target.decoded(new Gallery({ selectedDemo: null })))
223
+ }
224
+ },
225
+ Failed: {
226
+ on: {
227
+ Reset: (to) =>
228
+ to.full.Gallery.initial.resolve(({ target }) => target.decoded(new Gallery({ selectedDemo: null })))
229
+ }
230
+ }
231
+ })
@@ -0,0 +1,199 @@
1
+ import { Machine } from "@typeonce/effect-machine"
2
+ import { Schema } from "effect"
3
+
4
+ class Cart extends Schema.TaggedClass<Cart>("ParallelCart")("Cart", {
5
+ items: Schema.Number
6
+ }) {}
7
+ class Order extends Schema.TaggedClass<Order>("ParallelOrder")("Order", {
8
+ orderId: Schema.String,
9
+ total: Schema.Number
10
+ }) {}
11
+ class Payment extends Schema.TaggedClass<Payment>("ParallelPayment")("Payment", {
12
+ attempts: Schema.Number
13
+ }) {}
14
+ class AwaitingAuthorization extends Schema.TaggedClass<AwaitingAuthorization>("ParallelAwaitingAuthorization")(
15
+ "AwaitingAuthorization",
16
+ {}
17
+ ) {}
18
+ class Authorized extends Schema.TaggedClass<Authorized>("ParallelAuthorized")("Authorized", {
19
+ authorizationId: Schema.String
20
+ }) {}
21
+ class Fulfillment extends Schema.TaggedClass<Fulfillment>("ParallelFulfillment")("Fulfillment", {
22
+ warehouse: Schema.String
23
+ }) {}
24
+ class WaitingForPayment extends Schema.TaggedClass<WaitingForPayment>("ParallelWaitingForPayment")(
25
+ "WaitingForPayment",
26
+ {}
27
+ ) {}
28
+ class Packing extends Schema.TaggedClass<Packing>("ParallelPacking")("Packing", {
29
+ packageCount: Schema.Number
30
+ }) {}
31
+ class Shipped extends Schema.TaggedClass<Shipped>("ParallelShipped")("Shipped", {
32
+ trackingCode: Schema.String
33
+ }) {}
34
+ class OrderComplete extends Schema.TaggedClass<OrderComplete>("ParallelOrderComplete")("OrderComplete", {
35
+ orderId: Schema.String
36
+ }) {}
37
+ class OrderCancelled extends Schema.TaggedClass<OrderCancelled>("ParallelOrderCancelled")(
38
+ "OrderCancelled",
39
+ { reason: Schema.String }
40
+ ) {}
41
+
42
+ class Checkout extends Schema.TaggedClass<Checkout>("ParallelCheckout")("Checkout", {
43
+ orderId: Schema.String,
44
+ total: Schema.Number
45
+ }) {}
46
+ class Authorize extends Schema.TaggedClass<Authorize>("ParallelAuthorize")("Authorize", {
47
+ authorizationId: Schema.String
48
+ }) {}
49
+ class DeclinePayment extends Schema.TaggedClass<DeclinePayment>("ParallelDeclinePayment")(
50
+ "DeclinePayment",
51
+ { reason: Schema.String }
52
+ ) {}
53
+ class Pack extends Schema.TaggedClass<Pack>("ParallelPack")("Pack", { packages: Schema.Number }) {}
54
+ class Ship extends Schema.TaggedClass<Ship>("ParallelShip")("Ship", { trackingCode: Schema.String }) {}
55
+ class CompleteAll extends Schema.TaggedClass<CompleteAll>("ParallelCompleteAll")("CompleteAll", {
56
+ authorizationId: Schema.String,
57
+ trackingCode: Schema.String
58
+ }) {}
59
+ class CancelOrder extends Schema.TaggedClass<CancelOrder>("ParallelCancelOrder")("CancelOrder", {
60
+ reason: Schema.String
61
+ }) {}
62
+ class RetryOrder extends Schema.TaggedClass<RetryOrder>("ParallelRetryOrder")("RetryOrder", {}) {}
63
+ class AutoShip extends Schema.TaggedClass<AutoShip>("ParallelAutoShip")("AutoShip", {}) {}
64
+
65
+ const ParallelInternalEvents = Machine.internalEvents(AutoShip)
66
+ const ParallelStates = Machine.states({
67
+ Cart,
68
+ Order: {
69
+ schema: Order,
70
+ type: "parallel",
71
+ states: {
72
+ payment: {
73
+ schema: Payment,
74
+ initial: "AwaitingAuthorization",
75
+ states: {
76
+ AwaitingAuthorization,
77
+ Authorized: { schema: Authorized, type: "final" }
78
+ }
79
+ },
80
+ fulfillment: {
81
+ schema: Fulfillment,
82
+ initial: "WaitingForPayment",
83
+ states: {
84
+ WaitingForPayment,
85
+ Packing,
86
+ Shipped: { schema: Shipped, type: "final" }
87
+ }
88
+ }
89
+ }
90
+ },
91
+ Complete: { schema: OrderComplete, type: "final", output: Schema.String },
92
+ Cancelled: OrderCancelled
93
+ })
94
+
95
+ export const parallelCompletionMachine = Machine.make({
96
+ id: "parallel-completion",
97
+ states: ParallelStates.states,
98
+ events: Machine.events(
99
+ Checkout,
100
+ Authorize,
101
+ DeclinePayment,
102
+ Pack,
103
+ Ship,
104
+ CompleteAll,
105
+ CancelOrder,
106
+ RetryOrder
107
+ ),
108
+ internalEvents: ParallelInternalEvents,
109
+ initial: (to) => to.Cart().resolve(({ target }) => target.decoded(new Cart({ items: 2 })))
110
+ }).handle({
111
+ Cart: {
112
+ on: {
113
+ Checkout: (to) =>
114
+ to.full.Order.initial.resolve(({ event, target }) =>
115
+ target.decoded(new Order({ orderId: event.orderId, total: event.total }))
116
+ )
117
+ }
118
+ },
119
+ Order: {
120
+ initialize: ({ builder }) => builder.payment.from({ attempts: 0 }).fulfillment.from({ warehouse: "north" }),
121
+ on: {
122
+ CancelOrder: (to) =>
123
+ to.full.Cancelled().resolve(({ event, target }) => target.decoded(new OrderCancelled({ reason: event.reason })))
124
+ },
125
+ onDone: (to) =>
126
+ to.full.Complete().resolve(({ target }) => target.decoded(new OrderComplete({ orderId: "completed-order" }))),
127
+ states: {
128
+ payment: {
129
+ initialize: ({ builder }) => builder.from(),
130
+ states: {
131
+ AwaitingAuthorization: {
132
+ on: {
133
+ Authorize: (to) =>
134
+ to.local.Authorized().resolve(({ event, target }) =>
135
+ target.decoded(new Authorized({ authorizationId: event.authorizationId }))
136
+ ),
137
+ CompleteAll: (to) =>
138
+ to.local.Authorized().resolve(({ event, target }) =>
139
+ target.decoded(new Authorized({ authorizationId: event.authorizationId }))
140
+ ),
141
+ DeclinePayment: (to) =>
142
+ to.full.Cancelled().resolve(({ event, target }) =>
143
+ target.decoded(new OrderCancelled({ reason: event.reason }))
144
+ )
145
+ }
146
+ }
147
+ }
148
+ },
149
+ fulfillment: {
150
+ initialize: ({ builder }) => builder.from(),
151
+ states: {
152
+ WaitingForPayment: {
153
+ on: {
154
+ Authorize: (to) =>
155
+ to.local.Packing().resolve(({ target }) => target.decoded(new Packing({ packageCount: 1 }))),
156
+ Pack: (to) =>
157
+ to.local.Packing().resolve(({ event, target }) =>
158
+ target.decoded(new Packing({ packageCount: event.packages }))
159
+ ),
160
+ CompleteAll: (to) =>
161
+ to.local.Shipped().resolve(({ event, target }) =>
162
+ target.decoded(new Shipped({ trackingCode: event.trackingCode }))
163
+ )
164
+ }
165
+ },
166
+ Packing: {
167
+ invoke: (from) =>
168
+ from.timer("packing-sla", "5 seconds").onDone((to) =>
169
+ to.none.resolve((_, enqueue) => {
170
+ enqueue.raise(ParallelInternalEvents.AutoShip())
171
+ })
172
+ ),
173
+ on: {
174
+ AutoShip: (to) =>
175
+ to.local.Shipped().resolve(({ target }) => target.decoded(new Shipped({ trackingCode: "automatic" }))),
176
+ Ship: (to) =>
177
+ to.local.Shipped().resolve(({ event, target }) =>
178
+ target.decoded(new Shipped({ trackingCode: event.trackingCode }))
179
+ ),
180
+ CompleteAll: (to) =>
181
+ to.local.Shipped().resolve(({ event, target }) =>
182
+ target.decoded(new Shipped({ trackingCode: event.trackingCode }))
183
+ )
184
+ }
185
+ }
186
+ }
187
+ }
188
+ }
189
+ },
190
+ Complete: {
191
+ output: ({ state }) => state.orderId
192
+ },
193
+ Cancelled: {
194
+ on: {
195
+ RetryOrder: (to) =>
196
+ to.full.Order.initial.resolve(({ target }) => target.decoded(new Order({ orderId: "retry", total: 0 })))
197
+ }
198
+ }
199
+ })
@@ -1,5 +1,6 @@
1
1
  import { Machine } from "@typeonce/effect-machine"
2
2
  import { Schema } from "effect"
3
+ import * as Effect from "effect/Effect"
3
4
 
4
5
  class Idle extends Schema.TaggedClass<Idle>("PlannerIdle")("Idle", { owner: Schema.String }) {}
5
6
  class Working extends Schema.TaggedClass<Working>("PlannerWorking")("Working", {
@@ -128,6 +129,7 @@ export const plannerMachine = Machine.make({
128
129
  }
129
130
  },
130
131
  Working: {
132
+ invoke: (from) => from.effect("monitor-job", () => Effect.never),
131
133
  on: {
132
134
  AutoFinish: (to) =>
133
135
  to.full.Finished().resolve(({ state, target }) => target.decoded(new Finished({ job: state.job }))),
@@ -0,0 +1,200 @@
1
+ import { Machine } from "@typeonce/effect-machine"
2
+ import { Schema } from "effect"
3
+
4
+ class ChildProgress extends Schema.TaggedClass<ChildProgress>("ProtocolChildProgress")("ChildProgress", {
5
+ percent: Schema.Number
6
+ }) {}
7
+ class ChildFinished extends Schema.TaggedClass<ChildFinished>("ProtocolChildFinished")("ChildFinished", {
8
+ result: Schema.String
9
+ }) {}
10
+ class ChildProblem extends Schema.TaggedClass<ChildProblem>("ProtocolChildProblem")("ChildProblem", {
11
+ message: Schema.String
12
+ }) {}
13
+
14
+ const ParentEvents = Machine.events(ChildProgress, ChildFinished, ChildProblem)
15
+
16
+ class ChildIdle extends Schema.TaggedClass<ChildIdle>("ProtocolChildIdle")("Idle", {}) {}
17
+ class ChildWorking extends Schema.TaggedClass<ChildWorking>("ProtocolChildWorking")("Working", {
18
+ job: Schema.String,
19
+ progress: Schema.Number
20
+ }) {}
21
+ class ChildDone extends Schema.TaggedClass<ChildDone>("ProtocolChildDone")("Done", {
22
+ result: Schema.String
23
+ }) {}
24
+ class ChildCancelled extends Schema.TaggedClass<ChildCancelled>("ProtocolChildCancelled")("Cancelled", {
25
+ reason: Schema.String
26
+ }) {}
27
+
28
+ class BeginChildWork extends Schema.TaggedClass<BeginChildWork>("ProtocolBeginChildWork")("BeginChildWork", {
29
+ job: Schema.String
30
+ }) {}
31
+ class CancelChildWork extends Schema.TaggedClass<CancelChildWork>("ProtocolCancelChildWork")(
32
+ "CancelChildWork",
33
+ { reason: Schema.String }
34
+ ) {}
35
+ class Heartbeat extends Schema.TaggedClass<Heartbeat>("ProtocolHeartbeat")("Heartbeat", {
36
+ percent: Schema.Number
37
+ }) {}
38
+ class CommitChildWork extends Schema.TaggedClass<CommitChildWork>("ProtocolCommitChildWork")(
39
+ "CommitChildWork",
40
+ {}
41
+ ) {}
42
+ class ChildTrace extends Schema.TaggedClass<ChildTrace>("ProtocolChildTrace")("ChildTrace", {
43
+ message: Schema.String
44
+ }) {}
45
+
46
+ const ChildEvents = Machine.events(BeginChildWork, CancelChildWork)
47
+ const ChildInternalEvents = Machine.internalEvents(Heartbeat, CommitChildWork)
48
+ const ChildEmissions = Machine.emittedEvents(ChildTrace)
49
+ const ChildStates = Machine.states({
50
+ Idle: ChildIdle,
51
+ Working: ChildWorking,
52
+ Done: { schema: ChildDone, type: "final", output: Schema.String },
53
+ Cancelled: { schema: ChildCancelled, type: "final", output: Schema.String }
54
+ })
55
+
56
+ export const requiredParentChildMachine = Machine.make({
57
+ id: "required-parent-child",
58
+ states: ChildStates.states,
59
+ events: ChildEvents,
60
+ internalEvents: ChildInternalEvents,
61
+ emittedEvents: ChildEmissions,
62
+ parent: Machine.parent(ParentEvents),
63
+ initial: (to) => to.Idle().resolve(({ target }) => target.decoded(new ChildIdle({})))
64
+ }).handle({
65
+ Idle: {
66
+ on: {
67
+ BeginChildWork: (to) =>
68
+ to.full.Working().resolve(({ event, target }, enqueue) => {
69
+ enqueue.raise(ChildInternalEvents.Heartbeat({ percent: 25 }))
70
+ enqueue.emit(ChildEmissions.ChildTrace({ message: `started ${event.job}` }))
71
+ return target.decoded(new ChildWorking({ job: event.job, progress: 0 }))
72
+ })
73
+ }
74
+ },
75
+ Working: {
76
+ invoke: (from) =>
77
+ from.effect(
78
+ "report-progress-to-parent",
79
+ ({ parent, state }) => parent.send(ParentEvents.ChildProgress({ percent: state.progress }))
80
+ ).onDone((to) => to.none).onFailure((to) =>
81
+ to.full.Cancelled().resolve(({ error, target }) =>
82
+ target.decoded(new ChildCancelled({ reason: String(error) }))
83
+ )
84
+ ),
85
+ on: {
86
+ Heartbeat: (to) =>
87
+ to.full.Working().resolve(({ event, state, target }, enqueue) => {
88
+ enqueue.raise(ChildInternalEvents.CommitChildWork())
89
+ return target.decoded(new ChildWorking({ job: state.job, progress: event.percent }))
90
+ }),
91
+ CommitChildWork: (to) =>
92
+ to.full.Done().resolve(({ state, target }) =>
93
+ target.decoded(new ChildDone({ result: `${state.job}:complete` }))
94
+ ),
95
+ CancelChildWork: (to) =>
96
+ to.full.Cancelled().resolve(({ event, target }) => target.decoded(new ChildCancelled({ reason: event.reason })))
97
+ }
98
+ },
99
+ Done: {
100
+ output: ({ state }) => state.result
101
+ },
102
+ Cancelled: {
103
+ output: ({ state }) => state.reason
104
+ }
105
+ })
106
+
107
+ const ProtocolChild = Machine.child("protocol-child", requiredParentChildMachine)
108
+
109
+ class ParentIdle extends Schema.TaggedClass<ParentIdle>("ProtocolParentIdle")("Idle", {}) {}
110
+ class Supervising extends Schema.TaggedClass<Supervising>("ProtocolSupervising")("Supervising", {
111
+ latestProgress: Schema.Number
112
+ }) {}
113
+ class ParentComplete extends Schema.TaggedClass<ParentComplete>("ProtocolParentComplete")("Complete", {
114
+ result: Schema.String
115
+ }) {}
116
+ class ParentFailed extends Schema.TaggedClass<ParentFailed>("ProtocolParentFailed")("Failed", {
117
+ message: Schema.String
118
+ }) {}
119
+ class LaunchChild extends Schema.TaggedClass<LaunchChild>("ProtocolLaunchChild")("LaunchChild", {}) {}
120
+ class ResetParent extends Schema.TaggedClass<ResetParent>("ProtocolResetParent")("ResetParent", {}) {}
121
+
122
+ const ParentStates = Machine.states({
123
+ Idle: ParentIdle,
124
+ Supervising,
125
+ Complete: { schema: ParentComplete, type: "final", output: Schema.String },
126
+ Failed: ParentFailed
127
+ })
128
+
129
+ export const parentProtocolMachine = Machine.make({
130
+ id: "parent-child-protocol",
131
+ states: ParentStates.states,
132
+ events: Machine.events(LaunchChild, ResetParent, ParentEvents),
133
+ initial: (to) => to.Idle().resolve(({ target }) => target.decoded(new ParentIdle({})))
134
+ }).handle({
135
+ Idle: {
136
+ on: {
137
+ LaunchChild: (to) =>
138
+ to.full.Supervising().resolve(({ target }) => target.decoded(new Supervising({ latestProgress: 0 })))
139
+ }
140
+ },
141
+ Supervising: {
142
+ invoke: (from) =>
143
+ from.child(ProtocolChild).onDone((to) =>
144
+ to.full.Complete().resolve(({ output, target }) => target.decoded(new ParentComplete({ result: output })))
145
+ ).onFailure((to) =>
146
+ to.full.Failed().resolve(({ error, target }) => target.decoded(new ParentFailed({ message: String(error) })))
147
+ ),
148
+ on: {
149
+ ChildProgress: (to) =>
150
+ to.full.Supervising().resolve(({ event, target }) =>
151
+ target.decoded(new Supervising({ latestProgress: event.percent }))
152
+ ),
153
+ ChildFinished: (to) =>
154
+ to.full.Complete().resolve(({ event, target }) => target.decoded(new ParentComplete({ result: event.result }))),
155
+ ChildProblem: (to) =>
156
+ to.full.Failed().resolve(({ event, target }) => target.decoded(new ParentFailed({ message: event.message }))),
157
+ ResetParent: (to) => to.full.Idle().resolve(({ target }) => target.decoded(new ParentIdle({})))
158
+ }
159
+ },
160
+ Complete: {
161
+ output: ({ state }) => state.result
162
+ },
163
+ Failed: {
164
+ on: {
165
+ ResetParent: (to) => to.full.Idle().resolve(({ target }) => target.decoded(new ParentIdle({})))
166
+ }
167
+ }
168
+ })
169
+
170
+ class Detached extends Schema.TaggedClass<Detached>("OptionalParentDetached")("Detached", {}) {}
171
+ class Published extends Schema.TaggedClass<Published>("OptionalParentPublished")("Published", {
172
+ deliveredToParent: Schema.Boolean
173
+ }) {}
174
+ class PublishOutside extends Schema.TaggedClass<PublishOutside>("OptionalParentPublishOutside")(
175
+ "PublishOutside",
176
+ { result: Schema.String }
177
+ ) {}
178
+
179
+ const OptionalParentStates = Machine.states({ Detached, Published })
180
+
181
+ export const optionalParentMachine = Machine.make({
182
+ id: "optional-parent-protocol",
183
+ states: OptionalParentStates.states,
184
+ events: Machine.events(PublishOutside),
185
+ parent: Machine.optionalParent(ParentEvents),
186
+ initial: (to) => to.Detached().resolve(({ target }) => target.decoded(new Detached({})))
187
+ }).handle({
188
+ Detached: {
189
+ on: {
190
+ PublishOutside: (to) =>
191
+ to.full.Published().resolve(({ event, parent, target }, enqueue) => {
192
+ if (parent !== undefined) {
193
+ enqueue.sendTo(parent, ParentEvents.ChildFinished({ result: event.result }))
194
+ }
195
+ return target.decoded(new Published({ deliveredToParent: parent !== undefined }))
196
+ })
197
+ }
198
+ },
199
+ Published: {}
200
+ })