@typeonce/effect-machine-devtools 0.27.0 → 0.28.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.
- package/README.md +1 -1
- package/dist/client/assets/index-ZUqYOHbc.css +1 -0
- package/dist/client/assets/index-gxgK_rqB.js +37 -0
- package/dist/client/index.html +2 -2
- package/package.json +2 -2
- package/src/internal/browser/chart-layout-policy.ts +13 -8
- package/src/internal/browser/chart-layout.ts +1050 -429
- package/src/internal/browser/chart-model.ts +0 -57
- package/src/internal/browser/chart-renderer.ts +35 -25
- package/src/internal/browser/hierarchy-routing-example.ts +91 -0
- package/src/internal/browser/machine-index.ts +23 -0
- package/src/internal/browser/shared-terminal-routing-example.ts +141 -0
- package/src/internal/browser/styles.css +72 -41
- package/src/internal/browser/visualizer-app.ts +59 -4
- package/dist/client/assets/index-BFxKU97K.js +0 -37
- package/dist/client/assets/index-BsorPSDS.css +0 -1
|
@@ -5,16 +5,8 @@ import type {
|
|
|
5
5
|
State as VisualizationState,
|
|
6
6
|
Transition as VisualizationTransition
|
|
7
7
|
} from "../../MachineDocument.js"
|
|
8
|
-
import { type InputField, projectInputSchema } from "./input-form.js"
|
|
9
8
|
import { stateLabel, triggerLabel } from "./visualizer-model.js"
|
|
10
9
|
|
|
11
|
-
export interface ChartField {
|
|
12
|
-
readonly key: string
|
|
13
|
-
readonly label: string
|
|
14
|
-
readonly type: string
|
|
15
|
-
readonly required: boolean
|
|
16
|
-
}
|
|
17
|
-
|
|
18
10
|
export interface ChartActivity {
|
|
19
11
|
readonly id: string
|
|
20
12
|
readonly kind: VisualizationActivity["type"]
|
|
@@ -29,7 +21,6 @@ export interface ChartNode {
|
|
|
29
21
|
readonly children: ReadonlyArray<string>
|
|
30
22
|
readonly active: boolean
|
|
31
23
|
readonly initial: boolean
|
|
32
|
-
readonly fields: ReadonlyArray<ChartField>
|
|
33
24
|
readonly activities: ReadonlyArray<ChartActivity>
|
|
34
25
|
}
|
|
35
26
|
|
|
@@ -69,53 +60,6 @@ export interface ChartModel {
|
|
|
69
60
|
readonly initials: ReadonlyArray<ChartInitial>
|
|
70
61
|
}
|
|
71
62
|
|
|
72
|
-
const literalType = (value: string | number | boolean | null): string =>
|
|
73
|
-
typeof value === "string" ? JSON.stringify(value) : String(value)
|
|
74
|
-
|
|
75
|
-
const fieldType = (field: InputField): string => {
|
|
76
|
-
switch (field._tag) {
|
|
77
|
-
case "String":
|
|
78
|
-
return field.format ?? "string"
|
|
79
|
-
case "Number":
|
|
80
|
-
return field.integer ? "integer" : "number"
|
|
81
|
-
case "Boolean":
|
|
82
|
-
return "boolean"
|
|
83
|
-
case "Enum":
|
|
84
|
-
return field.values.map(literalType).join(" | ")
|
|
85
|
-
case "Literal":
|
|
86
|
-
return literalType(field.value)
|
|
87
|
-
case "Object":
|
|
88
|
-
return "object"
|
|
89
|
-
case "Array":
|
|
90
|
-
return `${fieldType(field.item)}[]`
|
|
91
|
-
case "Union":
|
|
92
|
-
return field.alternatives.map(fieldType).join(" | ")
|
|
93
|
-
case "Unsupported":
|
|
94
|
-
return "unknown"
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const stateFields = (state: VisualizationState): ReadonlyArray<ChartField> => {
|
|
99
|
-
if (state.valueSchema === null) return []
|
|
100
|
-
const projected = projectInputSchema(state.valueSchema)
|
|
101
|
-
if (projected._tag !== "Object") {
|
|
102
|
-
return [{
|
|
103
|
-
key: "value",
|
|
104
|
-
label: projected.title ?? "value",
|
|
105
|
-
type: fieldType(projected),
|
|
106
|
-
required: true
|
|
107
|
-
}]
|
|
108
|
-
}
|
|
109
|
-
return projected.fields
|
|
110
|
-
.filter(({ key }) => key !== "_tag")
|
|
111
|
-
.map(({ field, key, required }) => ({
|
|
112
|
-
key,
|
|
113
|
-
label: field.title ?? key,
|
|
114
|
-
type: fieldType(field),
|
|
115
|
-
required
|
|
116
|
-
}))
|
|
117
|
-
}
|
|
118
|
-
|
|
119
63
|
const activityLabel = (activity: VisualizationActivity): string => {
|
|
120
64
|
switch (activity.type) {
|
|
121
65
|
case "machine":
|
|
@@ -177,7 +121,6 @@ export const makeChartModel = (document: VisualizationDocument): ChartModel => {
|
|
|
177
121
|
children: [...state.children],
|
|
178
122
|
active: active.has(state.path),
|
|
179
123
|
initial: initialPaths.has(state.path),
|
|
180
|
-
fields: stateFields(state),
|
|
181
124
|
activities: state.activityIds.flatMap((id): ReadonlyArray<ChartActivity> => {
|
|
182
125
|
const activity = activities.get(id)
|
|
183
126
|
return activity === undefined ? [] : [{ id, kind: activity.type, label: activityLabel(activity) }]
|
|
@@ -6,8 +6,7 @@ import {
|
|
|
6
6
|
type LaidOutChart,
|
|
7
7
|
type LaidOutChartNode,
|
|
8
8
|
layoutChart,
|
|
9
|
-
maxVisibleActivities
|
|
10
|
-
maxVisibleFields
|
|
9
|
+
maxVisibleActivities
|
|
11
10
|
} from "./chart-layout.js"
|
|
12
11
|
import { makeChartModel } from "./chart-model.js"
|
|
13
12
|
|
|
@@ -130,7 +129,7 @@ const statusLabel = (active: boolean, initial: boolean): string => {
|
|
|
130
129
|
const status = (active: boolean, initial: boolean): HTMLSpanElement => {
|
|
131
130
|
const dot = element(
|
|
132
131
|
"span",
|
|
133
|
-
`chart-state-status${active ? " is-active" : ""}
|
|
132
|
+
`chart-state-status${active ? " is-active" : ""}`
|
|
134
133
|
)
|
|
135
134
|
dot.dataset.initial = String(initial)
|
|
136
135
|
dot.setAttribute("aria-label", statusLabel(active, initial))
|
|
@@ -147,26 +146,8 @@ const stateContent = (layout: LaidOutChartNode, stateStatus: HTMLElement): Docum
|
|
|
147
146
|
heading.append(identity)
|
|
148
147
|
fragment.append(heading)
|
|
149
148
|
|
|
150
|
-
if (layout.node.fields.length > 0) {
|
|
151
|
-
const fields = element("div", "chart-state-section")
|
|
152
|
-
fields.append(element("div", "chart-section-label", "value"))
|
|
153
|
-
layout.node.fields.slice(0, maxVisibleFields).forEach((field) => {
|
|
154
|
-
const row = element("div", "chart-field-row")
|
|
155
|
-
row.append(
|
|
156
|
-
element("span", "chart-field-name", `${field.label}${field.required ? "" : "?"}`),
|
|
157
|
-
element("span", "chart-field-type", field.type)
|
|
158
|
-
)
|
|
159
|
-
fields.append(row)
|
|
160
|
-
})
|
|
161
|
-
if (layout.node.fields.length > maxVisibleFields) {
|
|
162
|
-
fields.append(more(layout.node.fields.length - maxVisibleFields))
|
|
163
|
-
}
|
|
164
|
-
fragment.append(fields)
|
|
165
|
-
}
|
|
166
|
-
|
|
167
149
|
if (layout.node.activities.length > 0) {
|
|
168
150
|
const activities = element("div", "chart-state-section")
|
|
169
|
-
activities.append(element("div", "chart-section-label", "invokes"))
|
|
170
151
|
layout.node.activities.slice(0, maxVisibleActivities).forEach((activity) => {
|
|
171
152
|
const row = element("div", `chart-activity-row chart-activity-${activity.kind}`)
|
|
172
153
|
row.append(
|
|
@@ -314,7 +295,19 @@ const render = (
|
|
|
314
295
|
const directionArrow = svgElement("path")
|
|
315
296
|
directionArrow.setAttribute("d", "M 1 1 L 7 4 L 1 7 z")
|
|
316
297
|
directionMarker.append(directionArrow)
|
|
317
|
-
|
|
298
|
+
const initialMarker = svgElement("marker")
|
|
299
|
+
initialMarker.id = "chart-initial-arrow"
|
|
300
|
+
initialMarker.setAttribute("viewBox", "0 0 8 8")
|
|
301
|
+
initialMarker.setAttribute("refX", "7")
|
|
302
|
+
initialMarker.setAttribute("refY", "4")
|
|
303
|
+
initialMarker.setAttribute("markerWidth", "7")
|
|
304
|
+
initialMarker.setAttribute("markerHeight", "7")
|
|
305
|
+
initialMarker.setAttribute("markerUnits", "userSpaceOnUse")
|
|
306
|
+
initialMarker.setAttribute("orient", "auto")
|
|
307
|
+
const initialArrow = svgElement("path")
|
|
308
|
+
initialArrow.setAttribute("d", "M 1 1 L 7 4 L 1 7 z")
|
|
309
|
+
initialMarker.append(initialArrow)
|
|
310
|
+
definitions.append(marker, directionMarker, initialMarker)
|
|
318
311
|
svg.append(definitions)
|
|
319
312
|
const nodesLayer = element("div", "chart-nodes")
|
|
320
313
|
const labelsLayer = element("div", "chart-labels")
|
|
@@ -340,6 +333,7 @@ const render = (
|
|
|
340
333
|
const transitionElements = new Map<string, Array<Element>>()
|
|
341
334
|
const edgeElements = new Map<string, Array<Element>>()
|
|
342
335
|
const transitionControls = new Map<string, Array<HTMLButtonElement>>()
|
|
336
|
+
const parentByState = new Map(layout.nodes.map(({ node }) => [node.path, node.parent]))
|
|
343
337
|
const chartEdges = new Map(
|
|
344
338
|
layout.edges.flatMap((laidOut) => laidOut.kind === "transition" ? [[laidOut.edge.id, laidOut.edge] as const] : [])
|
|
345
339
|
)
|
|
@@ -429,13 +423,15 @@ const render = (
|
|
|
429
423
|
}
|
|
430
424
|
|
|
431
425
|
for (const laidOut of layout.edges) {
|
|
426
|
+
const parentChild = laidOut.kind === "transition" && laidOut.edge.target !== null &&
|
|
427
|
+
parentByState.get(laidOut.edge.target) === laidOut.edge.source
|
|
432
428
|
const group = svgElement(
|
|
433
429
|
"g",
|
|
434
430
|
`chart-edge-group chart-edge-${laidOut.kind}${
|
|
435
431
|
laidOut.kind === "transition"
|
|
436
432
|
? ` chart-transition-${laidOut.edge.kind} chart-edge-trigger-${laidOut.edge.trigger.type}${
|
|
437
433
|
laidOut.edge.activityKind === null ? "" : ` chart-edge-activity-${laidOut.edge.activityKind}`
|
|
438
|
-
}`
|
|
434
|
+
}${parentChild ? " chart-edge-parent-child" : ""}`
|
|
439
435
|
: ""
|
|
440
436
|
}`
|
|
441
437
|
)
|
|
@@ -444,10 +440,23 @@ const render = (
|
|
|
444
440
|
const route = chartEdgePathData(laidOut.points)
|
|
445
441
|
casing.setAttribute("d", route)
|
|
446
442
|
visible.setAttribute("d", route)
|
|
447
|
-
visible.setAttribute(
|
|
443
|
+
visible.setAttribute(
|
|
444
|
+
"marker-end",
|
|
445
|
+
laidOut.kind === "initial" ? "url(#chart-initial-arrow)" : "url(#chart-arrow)"
|
|
446
|
+
)
|
|
448
447
|
const hit = svgElement("path", "chart-edge-hit")
|
|
449
448
|
hit.setAttribute("d", route)
|
|
450
449
|
group.append(casing, visible)
|
|
450
|
+
if (parentChild) {
|
|
451
|
+
const origin = laidOut.points[0]
|
|
452
|
+
if (origin !== undefined) {
|
|
453
|
+
const sourceAnchor = svgElement("circle", "chart-edge-parent-origin")
|
|
454
|
+
sourceAnchor.setAttribute("cx", String(origin.x))
|
|
455
|
+
sourceAnchor.setAttribute("cy", String(origin.y))
|
|
456
|
+
sourceAnchor.setAttribute("r", "4")
|
|
457
|
+
group.append(sourceAnchor)
|
|
458
|
+
}
|
|
459
|
+
}
|
|
451
460
|
if (laidOut.kind === "transition") {
|
|
452
461
|
const cue = chartDirectionCue(laidOut.points)
|
|
453
462
|
if (cue !== null) {
|
|
@@ -467,10 +476,11 @@ const render = (
|
|
|
467
476
|
"button",
|
|
468
477
|
`chart-edge-label chart-edge-label-${laidOut.edge.trigger.type}${
|
|
469
478
|
laidOut.edge.activityKind === null ? "" : ` chart-edge-activity-${laidOut.edge.activityKind}`
|
|
470
|
-
}`,
|
|
479
|
+
}${parentChild ? " chart-edge-label-parent-child" : ""}`,
|
|
471
480
|
laidOut.edge.label
|
|
472
481
|
)
|
|
473
482
|
label.type = "button"
|
|
483
|
+
if (parentChild) label.title = "Transition declared by the parent state"
|
|
474
484
|
label.dataset.transitionId = laidOut.edge.transitionId
|
|
475
485
|
position(label, {
|
|
476
486
|
x: laidOut.label.x - laidOut.labelWidth / 2,
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { Machine } from "@typeonce/effect-machine"
|
|
2
|
+
import { Effect, Schema } from "effect"
|
|
3
|
+
|
|
4
|
+
const ReviewState = Schema.TaggedUnion({
|
|
5
|
+
Review: { title: Schema.String },
|
|
6
|
+
ReviewFailed: { message: Schema.String },
|
|
7
|
+
Complete: { slug: Schema.String }
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
const ReviewStates = Machine.states({
|
|
11
|
+
Workflow: {
|
|
12
|
+
initial: "Review",
|
|
13
|
+
states: {
|
|
14
|
+
Review: {
|
|
15
|
+
schema: ReviewState.cases.Review,
|
|
16
|
+
initial: "Form",
|
|
17
|
+
states: {
|
|
18
|
+
Form: {},
|
|
19
|
+
Failed: ReviewState.cases.ReviewFailed
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
Saving: {},
|
|
23
|
+
Publishing: {},
|
|
24
|
+
Complete: ReviewState.cases.Complete
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
const ReviewEvents = Machine.events(
|
|
30
|
+
Schema.TaggedUnion({
|
|
31
|
+
Submit: { route: Schema.Literals(["save", "invalid"]) }
|
|
32
|
+
})
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
const saveReview: Effect.Effect<string, string> = Effect.succeed("deterministic-chart")
|
|
36
|
+
const publishReview = Effect.succeed("deterministic-chart")
|
|
37
|
+
|
|
38
|
+
export const hierarchyRoutingMachine = Machine.make({
|
|
39
|
+
id: "hierarchy-routing",
|
|
40
|
+
states: ReviewStates.states,
|
|
41
|
+
events: ReviewEvents,
|
|
42
|
+
initial: (to) =>
|
|
43
|
+
to.Workflow.initial.resolve(({ target }) =>
|
|
44
|
+
target.from((workflow) =>
|
|
45
|
+
workflow.Review.from({ title: "A deterministic chart" }, (review) => review.Form.from())
|
|
46
|
+
)
|
|
47
|
+
)
|
|
48
|
+
}).handle({
|
|
49
|
+
Workflow: {
|
|
50
|
+
states: {
|
|
51
|
+
Review: {
|
|
52
|
+
on: {
|
|
53
|
+
Submit: (to) =>
|
|
54
|
+
to.branches({
|
|
55
|
+
save: {
|
|
56
|
+
title: "Save the review",
|
|
57
|
+
target: to.branch.Workflow.Saving()
|
|
58
|
+
},
|
|
59
|
+
invalid: {
|
|
60
|
+
title: "Show validation failure",
|
|
61
|
+
target: to.local.Failed()
|
|
62
|
+
}
|
|
63
|
+
}).resolve(({ event, select }) =>
|
|
64
|
+
event.route === "save"
|
|
65
|
+
? select.save.from()
|
|
66
|
+
: select.invalid.from({ message: "Add a title before continuing." })
|
|
67
|
+
)
|
|
68
|
+
},
|
|
69
|
+
states: {
|
|
70
|
+
Form: {},
|
|
71
|
+
Failed: {}
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
Saving: {
|
|
75
|
+
invoke: (from) =>
|
|
76
|
+
from.effect("save-review", () => saveReview).onDone((to) => to.branch.Workflow.Publishing()).onFailure((to) =>
|
|
77
|
+
to.branch.Workflow.Review.Failed().resolve(({ target }) =>
|
|
78
|
+
target.from({ message: "The review could not be saved." })
|
|
79
|
+
)
|
|
80
|
+
)
|
|
81
|
+
},
|
|
82
|
+
Publishing: {
|
|
83
|
+
invoke: (from) =>
|
|
84
|
+
from.effect("publish-review", () => publishReview).onDone((to) =>
|
|
85
|
+
to.branch.Workflow.Complete().resolve(({ output, target }) => target.from({ slug: output }))
|
|
86
|
+
)
|
|
87
|
+
},
|
|
88
|
+
Complete: {}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
})
|
|
@@ -3,6 +3,19 @@ import { mountVisualizer } from "./visualizer.js"
|
|
|
3
3
|
|
|
4
4
|
let selectedKey: string | undefined
|
|
5
5
|
|
|
6
|
+
export const machineIndexScrollLeft = (
|
|
7
|
+
scrollLeft: number,
|
|
8
|
+
viewportWidth: number,
|
|
9
|
+
selectedLeft: number,
|
|
10
|
+
selectedWidth: number
|
|
11
|
+
): number => {
|
|
12
|
+
if (selectedLeft < scrollLeft) return selectedLeft
|
|
13
|
+
const selectedRight = selectedLeft + selectedWidth
|
|
14
|
+
return selectedRight > scrollLeft + viewportWidth
|
|
15
|
+
? selectedRight - viewportWidth
|
|
16
|
+
: scrollLeft
|
|
17
|
+
}
|
|
18
|
+
|
|
6
19
|
const createElement = <Tag extends keyof HTMLElementTagNameMap>(
|
|
7
20
|
tag: Tag,
|
|
8
21
|
className?: string,
|
|
@@ -36,6 +49,7 @@ const statusLabel = (result: MachineResult): string => {
|
|
|
36
49
|
}
|
|
37
50
|
|
|
38
51
|
export const mountMachineIndex = (root: HTMLElement, snapshot: RegistrySnapshot): void => {
|
|
52
|
+
const previousScrollLeft = root.querySelector<HTMLElement>(".machine-index")?.scrollLeft ?? 0
|
|
39
53
|
const results = [...snapshot.results].sort((left, right) => resultLabel(left).localeCompare(resultLabel(right)))
|
|
40
54
|
if (selectedKey === undefined || !results.some((result) => result.key === selectedKey)) {
|
|
41
55
|
selectedKey = results[0]?.key
|
|
@@ -78,4 +92,13 @@ export const mountMachineIndex = (root: HTMLElement, snapshot: RegistrySnapshot)
|
|
|
78
92
|
|
|
79
93
|
shell.append(index, view)
|
|
80
94
|
root.replaceChildren(shell)
|
|
95
|
+
const selected = index.querySelector<HTMLElement>(".machine-row.is-selected")
|
|
96
|
+
index.scrollLeft = selected === null
|
|
97
|
+
? previousScrollLeft
|
|
98
|
+
: machineIndexScrollLeft(
|
|
99
|
+
previousScrollLeft,
|
|
100
|
+
index.clientWidth,
|
|
101
|
+
selected.offsetLeft,
|
|
102
|
+
selected.offsetWidth
|
|
103
|
+
)
|
|
81
104
|
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { Machine } from "@typeonce/effect-machine"
|
|
2
|
+
import { Effect, Schema } from "effect"
|
|
3
|
+
|
|
4
|
+
const ReplicationStates = Machine.states({
|
|
5
|
+
Connecting: {},
|
|
6
|
+
IdentifyingSource: {},
|
|
7
|
+
ReadingServerInfo: {},
|
|
8
|
+
ReadingSlot: {},
|
|
9
|
+
CreatingSlot: {},
|
|
10
|
+
CopyingSnapshot: {},
|
|
11
|
+
CatchingUp: {},
|
|
12
|
+
ApplyingChanges: {},
|
|
13
|
+
Ready: {},
|
|
14
|
+
SessionUnavailable: {},
|
|
15
|
+
Stopping: {},
|
|
16
|
+
Stopped: {},
|
|
17
|
+
Failed: {}
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const ReplicationEvents = Machine.events(
|
|
21
|
+
Schema.TaggedUnion({
|
|
22
|
+
Retry: {},
|
|
23
|
+
SessionUnavailable: {},
|
|
24
|
+
StopRequested: {}
|
|
25
|
+
})
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
const operation = (): Effect.Effect<void, string> => Effect.succeed(undefined)
|
|
29
|
+
|
|
30
|
+
export const sharedTerminalRoutingMachine = Machine.make({
|
|
31
|
+
id: "shared-terminal-routing",
|
|
32
|
+
states: ReplicationStates.states,
|
|
33
|
+
events: ReplicationEvents,
|
|
34
|
+
initial: (to) => to.Connecting()
|
|
35
|
+
}).handle({
|
|
36
|
+
Connecting: {
|
|
37
|
+
invoke: (from) =>
|
|
38
|
+
from.effect("connect", operation)
|
|
39
|
+
.onDone((to) => to.full.IdentifyingSource())
|
|
40
|
+
.onFailure((to) => to.full.Failed()),
|
|
41
|
+
on: {
|
|
42
|
+
SessionUnavailable: (to) => to.full.SessionUnavailable(),
|
|
43
|
+
StopRequested: (to) => to.full.Stopping()
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
IdentifyingSource: {
|
|
47
|
+
invoke: (from) =>
|
|
48
|
+
from.effect("identify-source", operation)
|
|
49
|
+
.onDone((to) => to.full.ReadingServerInfo())
|
|
50
|
+
.onFailure((to) => to.full.Failed()),
|
|
51
|
+
on: {
|
|
52
|
+
SessionUnavailable: (to) => to.full.SessionUnavailable(),
|
|
53
|
+
StopRequested: (to) => to.full.Stopping()
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
ReadingServerInfo: {
|
|
57
|
+
invoke: (from) =>
|
|
58
|
+
from.effect("read-server-info", operation)
|
|
59
|
+
.onDone((to) => to.full.ReadingSlot())
|
|
60
|
+
.onFailure((to) => to.full.Failed()),
|
|
61
|
+
on: {
|
|
62
|
+
SessionUnavailable: (to) => to.full.SessionUnavailable(),
|
|
63
|
+
StopRequested: (to) => to.full.Stopping()
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
ReadingSlot: {
|
|
67
|
+
invoke: (from) =>
|
|
68
|
+
from.effect("read-slot", operation)
|
|
69
|
+
.onDone((to) => to.full.CreatingSlot())
|
|
70
|
+
.onFailure((to) => to.full.Failed()),
|
|
71
|
+
on: {
|
|
72
|
+
SessionUnavailable: (to) => to.full.SessionUnavailable(),
|
|
73
|
+
StopRequested: (to) => to.full.Stopping()
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
CreatingSlot: {
|
|
77
|
+
invoke: (from) =>
|
|
78
|
+
from.effect("create-slot", operation)
|
|
79
|
+
.onDone((to) => to.full.CopyingSnapshot())
|
|
80
|
+
.onFailure((to) => to.full.Failed()),
|
|
81
|
+
on: {
|
|
82
|
+
SessionUnavailable: (to) => to.full.SessionUnavailable(),
|
|
83
|
+
StopRequested: (to) => to.full.Stopping()
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
CopyingSnapshot: {
|
|
87
|
+
invoke: (from) =>
|
|
88
|
+
from.effect("copy-snapshot", operation)
|
|
89
|
+
.onDone((to) => to.full.CatchingUp())
|
|
90
|
+
.onFailure((to) => to.full.Failed()),
|
|
91
|
+
on: {
|
|
92
|
+
SessionUnavailable: (to) => to.full.SessionUnavailable(),
|
|
93
|
+
StopRequested: (to) => to.full.Stopping()
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
CatchingUp: {
|
|
97
|
+
invoke: (from) =>
|
|
98
|
+
from.effect("catch-up", operation)
|
|
99
|
+
.onDone((to) => to.full.ApplyingChanges())
|
|
100
|
+
.onFailure((to) => to.full.Failed()),
|
|
101
|
+
on: {
|
|
102
|
+
SessionUnavailable: (to) => to.full.SessionUnavailable(),
|
|
103
|
+
StopRequested: (to) => to.full.Stopping()
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
ApplyingChanges: {
|
|
107
|
+
invoke: (from) =>
|
|
108
|
+
from.effect("apply-changes", operation)
|
|
109
|
+
.onDone((to) => to.full.Ready())
|
|
110
|
+
.onFailure((to) => to.full.Failed()),
|
|
111
|
+
on: {
|
|
112
|
+
SessionUnavailable: (to) => to.full.SessionUnavailable(),
|
|
113
|
+
StopRequested: (to) => to.full.Stopping()
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
Ready: {
|
|
117
|
+
on: {
|
|
118
|
+
SessionUnavailable: (to) => to.full.SessionUnavailable(),
|
|
119
|
+
StopRequested: (to) => to.full.Stopping()
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
SessionUnavailable: {
|
|
123
|
+
on: {
|
|
124
|
+
Retry: (to) => to.full.Connecting(),
|
|
125
|
+
StopRequested: (to) => to.full.Stopping()
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
Stopping: {
|
|
129
|
+
invoke: (from) =>
|
|
130
|
+
from.effect("stop-session", operation)
|
|
131
|
+
.onDone((to) => to.full.Stopped())
|
|
132
|
+
.onFailure((to) => to.full.Failed())
|
|
133
|
+
},
|
|
134
|
+
Stopped: {},
|
|
135
|
+
Failed: {
|
|
136
|
+
on: {
|
|
137
|
+
Retry: (to) => to.full.Connecting(),
|
|
138
|
+
StopRequested: (to) => to.full.Stopping()
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
})
|