@typeonce/effect-machine-devtools 0.23.0 → 0.25.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 (80) hide show
  1. package/NOTICE +4 -0
  2. package/README.md +14 -8
  3. package/dist/DevServer.d.ts +2 -1
  4. package/dist/DevServer.d.ts.map +1 -1
  5. package/dist/DevServer.js.map +1 -1
  6. package/dist/DevToolsProtocol.d.ts +167 -17
  7. package/dist/DevToolsProtocol.d.ts.map +1 -1
  8. package/dist/DevToolsProtocol.js +1 -1
  9. package/dist/MachineDocument.d.ts +98 -2
  10. package/dist/MachineDocument.d.ts.map +1 -1
  11. package/dist/MachineDocument.js +35 -1
  12. package/dist/MachineDocument.js.map +1 -1
  13. package/dist/MachineRegistry.d.ts +56 -6
  14. package/dist/MachineRegistry.d.ts.map +1 -1
  15. package/dist/MachineWalkthrough.d.ts +171 -0
  16. package/dist/MachineWalkthrough.d.ts.map +1 -0
  17. package/dist/MachineWalkthrough.js +98 -0
  18. package/dist/MachineWalkthrough.js.map +1 -0
  19. package/dist/client/assets/index-BTOAhezX.js +37 -0
  20. package/dist/client/assets/index-Cg7xzSkz.css +1 -0
  21. package/dist/client/index.html +4 -4
  22. package/dist/index.d.ts +2 -2
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +2 -2
  25. package/dist/index.js.map +1 -1
  26. package/dist/internal/devServer.d.ts +2 -1
  27. package/dist/internal/devServer.d.ts.map +1 -1
  28. package/dist/internal/devServer.js +4 -3
  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 +28 -9
  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 +65 -2
  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 +15 -9
  42. package/dist/internal/projectInspector.js.map +1 -1
  43. package/index.html +2 -2
  44. package/package.json +4 -3
  45. package/src/DevServer.ts +6 -2
  46. package/src/DevToolsProtocol.ts +1 -1
  47. package/src/MachineDocument.ts +56 -1
  48. package/src/MachineWalkthrough.ts +199 -0
  49. package/src/index.ts +2 -2
  50. package/src/internal/browser/chart-layout.ts +433 -0
  51. package/src/internal/browser/chart-model.ts +234 -0
  52. package/src/internal/browser/chart-renderer.ts +661 -0
  53. package/src/internal/browser/example-machine.ts +15 -6
  54. package/src/internal/browser/input-form.ts +252 -0
  55. package/src/internal/browser/invoke-outcomes-example.ts +231 -0
  56. package/src/internal/browser/parallel-completion-example.ts +199 -0
  57. package/src/internal/browser/planner-example.ts +145 -0
  58. package/src/internal/browser/protocol-events-example.ts +200 -0
  59. package/src/internal/browser/styles.css +959 -185
  60. package/src/internal/browser/transition-semantics-example.ts +236 -0
  61. package/src/internal/browser/visualizer-app.ts +818 -389
  62. package/src/internal/browser/visualizer-model.ts +104 -0
  63. package/src/internal/browser/visualizer.ts +1 -1
  64. package/src/internal/devServer.ts +9 -4
  65. package/src/internal/evaluationWorker.ts +28 -10
  66. package/src/internal/machineDocument.ts +77 -2
  67. package/src/internal/machineWalkthrough.ts +355 -0
  68. package/src/internal/projectInspector.ts +29 -14
  69. package/dist/MachineSimulator.d.ts +0 -169
  70. package/dist/MachineSimulator.d.ts.map +0 -1
  71. package/dist/MachineSimulator.js +0 -98
  72. package/dist/MachineSimulator.js.map +0 -1
  73. package/dist/client/assets/index-BGOhE3Ng.css +0 -1
  74. package/dist/client/assets/index-DiqGhsGR.js +0 -14
  75. package/dist/internal/machineSimulator.d.ts +0 -5
  76. package/dist/internal/machineSimulator.d.ts.map +0 -1
  77. package/dist/internal/machineSimulator.js +0 -156
  78. package/dist/internal/machineSimulator.js.map +0 -1
  79. package/src/MachineSimulator.ts +0 -154
  80. package/src/internal/machineSimulator.ts +0 -199
@@ -0,0 +1,145 @@
1
+ import { Machine } from "@typeonce/effect-machine"
2
+ import { Schema } from "effect"
3
+ import * as Effect from "effect/Effect"
4
+
5
+ class Idle extends Schema.TaggedClass<Idle>("PlannerIdle")("Idle", { owner: Schema.String }) {}
6
+ class Working extends Schema.TaggedClass<Working>("PlannerWorking")("Working", {
7
+ owner: Schema.String,
8
+ job: Schema.String
9
+ }) {}
10
+ class Finished extends Schema.TaggedClass<Finished>("PlannerFinished")("Finished", { job: Schema.String }) {}
11
+
12
+ const Owner = Schema.NonEmptyString.annotate({
13
+ title: "Owner",
14
+ description: "A non-empty name carried into the initial Idle state."
15
+ })
16
+ const Attempts = Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 5 })).annotate({
17
+ title: "Attempts",
18
+ description: "An integer between one and five."
19
+ })
20
+ const Labels = Schema.Array(Schema.NonEmptyString).check(Schema.isLengthBetween(1, 3)).annotate({
21
+ title: "Labels",
22
+ description: "One to three non-empty labels."
23
+ })
24
+ const Route = Schema.Union([
25
+ Schema.Literal("direct").annotate({ title: "Direct" }),
26
+ Schema.Struct({
27
+ queue: Schema.NonEmptyString.annotate({
28
+ title: "Queue",
29
+ description: "The queue used by the queued route."
30
+ })
31
+ }).annotate({ title: "Queued" })
32
+ ]).annotate({
33
+ title: "Route",
34
+ description: "Choose a literal direct route or provide a queue."
35
+ })
36
+
37
+ class Begin extends Schema.TaggedClass<Begin>("PlannerBegin")("Begin", {
38
+ job: Schema.NonEmptyString.annotate({
39
+ title: "Job",
40
+ description: "A non-empty job name used as the final output."
41
+ }),
42
+ priority: Schema.Literals(["normal", "urgent"]).annotate({
43
+ title: "Priority",
44
+ description: "Urgent jobs raise AutoFinish during the same macrostep."
45
+ }),
46
+ estimate: Schema.Finite.check(Schema.isBetween({ minimum: 0, maximum: 100 })).annotate({
47
+ title: "Estimate",
48
+ description: "A numeric estimate between zero and one hundred."
49
+ }),
50
+ approved: Schema.Boolean.annotate({
51
+ title: "Approved",
52
+ description: "A boolean checkbox included in the event payload."
53
+ }),
54
+ notes: Schema.optionalKey(
55
+ Schema.String.check(Schema.isMaxLength(80)).annotate({
56
+ title: "Notes",
57
+ description: "Optional text limited to eighty characters."
58
+ })
59
+ ),
60
+ labels: Schema.optionalKey(Labels),
61
+ route: Schema.optionalKey(Route)
62
+ }) {}
63
+ class Cancel extends Schema.TaggedClass<Cancel>("PlannerCancel")("Cancel", { reason: Schema.String }) {}
64
+ class AutoFinish extends Schema.TaggedClass<AutoFinish>("PlannerAutoFinish")("AutoFinish", {}) {}
65
+ class Planned extends Schema.TaggedClass<Planned>("PlannerPlanned")("Planned", { job: Schema.String }) {}
66
+
67
+ const Events = Machine.events(Begin, Cancel)
68
+ const InternalEvents = Machine.internalEvents(AutoFinish)
69
+ const Emissions = Machine.emittedEvents(Planned)
70
+ const States = Machine.states({
71
+ Idle,
72
+ Working,
73
+ Finished: { schema: Finished, type: "final", output: Schema.String }
74
+ })
75
+
76
+ export const plannerMachine = Machine.make({
77
+ id: "planner-example",
78
+ states: States.states,
79
+ events: Events,
80
+ internalEvents: InternalEvents,
81
+ emittedEvents: Emissions,
82
+ input: Schema.Struct({
83
+ owner: Owner,
84
+ attempts: Attempts,
85
+ notifications: Schema.Boolean.annotate({
86
+ title: "Notifications",
87
+ description: "A required boolean with false as a valid value."
88
+ }),
89
+ mode: Schema.Literals(["guided", "automatic"]).annotate({
90
+ title: "Mode",
91
+ description: "A fixed set of startup modes."
92
+ }),
93
+ note: Schema.optionalKey(
94
+ Schema.String.check(Schema.isMaxLength(40)).annotate({
95
+ title: "Note",
96
+ description: "Optional startup text limited to forty characters."
97
+ })
98
+ ),
99
+ labels: Schema.optionalKey(Labels),
100
+ preferences: Schema.optionalKey(
101
+ Schema.Struct({
102
+ retries: Schema.Int.check(Schema.isBetween({ minimum: 0, maximum: 3 })).annotate({
103
+ title: "Retries"
104
+ }),
105
+ dryRun: Schema.Boolean.annotate({ title: "Dry run" })
106
+ }).annotate({
107
+ title: "Preferences",
108
+ description: "An optional nested object."
109
+ })
110
+ )
111
+ }),
112
+ initial: (to) => to.Idle().resolve(({ input, target }) => target.decoded(new Idle({ owner: input.owner })))
113
+ }).handle({
114
+ Idle: {
115
+ on: {
116
+ Begin: (to) =>
117
+ to.branches({
118
+ urgent: { title: "Finish immediately", target: to.full.Working() },
119
+ normal: { title: "Wait in working", target: to.full.Working() }
120
+ }).resolve(({ event, self, select, state }, enqueue) => {
121
+ enqueue.emit(new Planned({ job: event.job }))
122
+ enqueue.sendTo(self, Events.Cancel({ reason: "planner command example" }))
123
+ if (event.priority === "urgent") enqueue.raise(InternalEvents.AutoFinish())
124
+ const working = new Working({ owner: state.owner, job: event.job })
125
+ return event.priority === "urgent"
126
+ ? select.urgent.decoded(working)
127
+ : select.normal.decoded(working)
128
+ })
129
+ }
130
+ },
131
+ Working: {
132
+ invoke: (from) => from.effect("monitor-job", () => Effect.never),
133
+ on: {
134
+ AutoFinish: (to) =>
135
+ to.full.Finished().resolve(({ state, target }) => target.decoded(new Finished({ job: state.job }))),
136
+ Cancel: (to) =>
137
+ to.full.Idle().resolve(({ event, state, target }) =>
138
+ target.decoded(new Idle({ owner: `${state.owner} · ${event.reason}` }))
139
+ )
140
+ }
141
+ },
142
+ Finished: {
143
+ output: ({ state }) => state.job
144
+ }
145
+ })
@@ -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
+ })