@ai-digital-factory/state-flow 0.0.0-stage → 0.1.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.
- package/LICENSE +18 -0
- package/README.md +126 -2
- package/dist/index.d.ts +188 -0
- package/dist/index.js +1721 -0
- package/dist/state-flow.css +781 -0
- package/package.json +65 -3
- package/tsconfig.flows.json +11 -0
- package/types/index.d.ts +46 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
Copyright (c) 2026 coupleaddagaming@gmail.com. All rights reserved.
|
|
2
|
+
|
|
3
|
+
State Flow is proprietary software. No license is granted by downloading,
|
|
4
|
+
accessing, or receiving this software or its documentation. All third-party
|
|
5
|
+
use, including personal, noncommercial and commercial use, requires prior
|
|
6
|
+
written permission from the copyright holder. Copying, modifying, distributing,
|
|
7
|
+
sublicensing or incorporating this software into another product also requires
|
|
8
|
+
prior written permission. Request permission at coupleaddagaming@gmail.com.
|
|
9
|
+
|
|
10
|
+
Any permission granted separately is governed by its written terms. This notice
|
|
11
|
+
does not alter the licenses of third-party dependencies or bundled third-party
|
|
12
|
+
materials; their respective licenses continue to apply.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
|
16
|
+
PURPOSE AND NONINFRINGEMENT. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW,
|
|
17
|
+
THE COPYRIGHT HOLDER IS NOT LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
|
|
18
|
+
ARISING FROM THE SOFTWARE OR ITS USE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,127 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @ai-digital-factory/state-flow
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
React library for flow-style state (states, transitions, and related UI). See repository `CONTEXT.md` for domain vocabulary.
|
|
4
|
+
|
|
5
|
+
## Flow authoring (TSX, no React app)
|
|
6
|
+
|
|
7
|
+
Flow-only projects declare flows as `.tsx` modules using `Flow`, `State`, `FinalState`, `Transition` and `To`, plus `ParallelState`, `Region` and `FlowList` for composition. They do not install `react` or `@types/react`.
|
|
8
|
+
|
|
9
|
+
A Flow is a static graph (ADR 0087). Each Transition lists its allowed destinations as `<To>` children, each describing when that destination is selected:
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import {
|
|
13
|
+
FinalState,
|
|
14
|
+
Flow,
|
|
15
|
+
State,
|
|
16
|
+
To,
|
|
17
|
+
Transition,
|
|
18
|
+
} from "@ai-digital-factory/state-flow";
|
|
19
|
+
|
|
20
|
+
export default function PlaceOrder() {
|
|
21
|
+
return (
|
|
22
|
+
<Flow name="place-order" description="One broker order." default="idle">
|
|
23
|
+
<State name="idle" description="Not yet submitted.">
|
|
24
|
+
<Transition name="submit-order" description="Send the order.">
|
|
25
|
+
<To state="placed" description="The broker accepted it." />
|
|
26
|
+
<To state="rejected" description="The broker rejected it." />
|
|
27
|
+
</Transition>
|
|
28
|
+
</State>
|
|
29
|
+
<State name="placed" description="Open at the broker.">
|
|
30
|
+
<Transition name="record-fill" description="The order filled.">
|
|
31
|
+
<To state="filled" description="Always." />
|
|
32
|
+
</Transition>
|
|
33
|
+
</State>
|
|
34
|
+
<FinalState name="rejected" description="Refused by the broker." />
|
|
35
|
+
<FinalState name="filled" description="Filled." />
|
|
36
|
+
</Flow>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
- One `<To>` makes a fixed destination; its `onTransition` handler is optional. Several make the Transition branch; its handler module must export `onTransition` returning one of the destination names.
|
|
42
|
+
- `<FinalState>` has no outgoing Transitions and no handlers. Reaching it completes the instance.
|
|
43
|
+
- Flow check and the `state-flow/flow-module` ESLint rule reject Transitions without a `<To>`, unknown or repeated destinations, empty To descriptions, Transitions on a FinalState, and graphs that are not static JSX (conditional children, `.map(...)`, computed props or elements built outside the Flow).
|
|
44
|
+
- The diagram draws a branching Transition as one named segment into a split, with one branch per `<To>` labelled by its description. Final states use a distinct colour and a `FINAL` tag.
|
|
45
|
+
|
|
46
|
+
### Composition: compound, parallel and FlowList (ADR 0095, 0096)
|
|
47
|
+
|
|
48
|
+
Larger lifecycles compose Flows declaratively. Nested States, regions and placed Flows are all part of the static graph; handlers never start child Flows.
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
<State name="signed-in" description="A user is signed in." default="dashboard">
|
|
52
|
+
<State name="dashboard" description="Overview.">
|
|
53
|
+
<Transition name="start-upload-batch" description="Upload files.">
|
|
54
|
+
<To state="uploading" description="Always." />
|
|
55
|
+
</Transition>
|
|
56
|
+
</State>
|
|
57
|
+
<State name="uploading" description="Each file uploads independently.">
|
|
58
|
+
<FlowList name="uploads" flow="file-upload" description="One per file." />
|
|
59
|
+
<Transition name="batch-finished" description="All done." trigger="done">
|
|
60
|
+
<To state="dashboard" description="Always." />
|
|
61
|
+
</Transition>
|
|
62
|
+
</State>
|
|
63
|
+
<ParallelState name="order-desk" description="Order and watchlist together.">
|
|
64
|
+
<Region name="order" description="One order." flow="place-order" />
|
|
65
|
+
<Region name="watchlist" description="Prices." default="watching">
|
|
66
|
+
<State name="watching" description="Live prices." />
|
|
67
|
+
</Region>
|
|
68
|
+
</ParallelState>
|
|
69
|
+
<Transition name="sign-out" description="Busy while work runs.">
|
|
70
|
+
<To state="signed-out" description="Always." />
|
|
71
|
+
</Transition>
|
|
72
|
+
<Transition
|
|
73
|
+
name="force-sign-out"
|
|
74
|
+
description="Interrupt work."
|
|
75
|
+
childWork="interrupt"
|
|
76
|
+
>
|
|
77
|
+
<To state="signed-out" description="Always." />
|
|
78
|
+
</Transition>
|
|
79
|
+
</State>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
- A `<State>` with nested States and a `default` is compound; `<State flow="x">` places one execution of Flow `x` from the same flows package. A `<ParallelState>` activates every `<Region>` and `<FlowList>` it contains.
|
|
83
|
+
- Transitions reach only siblings in their own region. Declare a Transition that leaves a containing State on that State; it is available from every nested configuration.
|
|
84
|
+
- `childWork="block"` (default) answers `busy` while descendant work is running or unresolved; `childWork="interrupt"` cancels it and proceeds. Neither undoes an external effect.
|
|
85
|
+
- `trigger="done"` fires once every region completes, with each region's FinalState (and each FlowList member's) as payload. Completing a child never completes the root.
|
|
86
|
+
- State and Transition names are unique across the whole flow file. The diagram tags composite States `COMPOUND` or `PARALLEL`, lists placed Flows and FlowList templates, and brackets nested States under their parent.
|
|
87
|
+
|
|
88
|
+
In the handlers package, a child Flow declares its input in `src/<flow-id>/input.ts` (`export const inputSchema = z.strictObject({...})`), read as `context.input`. A composite State's handler exports `children: { run, recovery }`, which receives the entering Transition's payload and returns child inputs and FlowList members (`{ uploads: [{ key, input }] }`). Generated `ChildInputs_<state>` and `Completion_<state>` types describe both.
|
|
89
|
+
|
|
90
|
+
### Migrating from the `to` prop
|
|
91
|
+
|
|
92
|
+
The `to` prop on `Transition` has been removed. Move the target into a `<To>` child and describe when it applies:
|
|
93
|
+
|
|
94
|
+
```diff
|
|
95
|
+
-<Transition to="present" name="unlock-succeeds" description="Correct credentials." />
|
|
96
|
+
+<Transition name="unlock-succeeds" description="Correct credentials.">
|
|
97
|
+
+ <To state="present" description="Always." />
|
|
98
|
+
+</Transition>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Recompile the flows package and its handlers package together: compiled flow artifacts move to schema version 2, generated `TransitionContext` types expose `destinations` instead of `toState`, and callback contexts expose `dependencies` instead of `config`. In each handlers package, rename `src/<flow-id>/config.ts` to `dependencies.ts` and its `Config` type to `Dependencies`; services import `Dependencies` instead of `FlowConfig` from the compiled module. Runtime types also lose their `Durable` prefix (ADR 0089), for example `TransitionCallback` instead of `DurableTransitionCallback`. Durable definition identities of flows without branching or final states are unchanged, so existing instances reopen.
|
|
102
|
+
|
|
103
|
+
The same release (ADRs 0089 and 0090) also renames and removes, without aliases:
|
|
104
|
+
|
|
105
|
+
- `@ai-digital-factory/state-flow-chart` is now `@ai-digital-factory/state-flow-definition`; update dependencies and imports.
|
|
106
|
+
- Presets: extend `@ai-digital-factory/state-flow/tsconfig.flows.json` and import `eslint.flows.config.js` (formerly `tsconfig.charts.json`, `eslint.charts.config.js`). The ESLint rule is `state-flow/flow-module`.
|
|
107
|
+
- Rule IDs in `state-flow.rules.json`: `state-chart.*` is `flow.*`, `application-hook.*` is `handler.*`, and `transition.name-unique-across-chart` is `transition.name-unique-across-flow`.
|
|
108
|
+
- Identifiers drop `Application` and use Flow/Handler, for example `FlowDefinition`, `defineFlow`, `HandlerContext`; data fields `chartName`/`chartId` are `flowName`/`flowId`, and compile output is under `dist/flows/`.
|
|
109
|
+
- Services: `await runtime.createFlow(compiled, dependencies)`, `await flow.ensureInstance({ instanceId })`, then `when(state).handle(outcomes).dispatch(input)`. The builder `.handleFailure(...).run()`, `runtime.flow`, `handleCreate`/`handleOpen`/`handleEnsure`, direct `when(state).dispatch` and `DispatchError`/`OperationError` are gone.
|
|
110
|
+
|
|
111
|
+
Extend the flow preset (TypeScript requires `jsx` for `.tsx`; the preset supplies it):
|
|
112
|
+
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"extends": "@ai-digital-factory/state-flow/tsconfig.flows.json",
|
|
116
|
+
"include": ["src/**/*.tsx"]
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Or set the same options yourself, including `"types": ["@ai-digital-factory/state-flow/types"]` and `"jsx": "react-jsx"`.
|
|
121
|
+
|
|
122
|
+
Preview and in-app rendering supply React at runtime via the State Flow CLI or your React consumer.
|
|
123
|
+
|
|
124
|
+
## License
|
|
125
|
+
|
|
126
|
+
Proprietary software. All third-party use requires prior written permission from
|
|
127
|
+
coupleaddagaming@gmail.com. See LICENSE.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { ReactElement, ReactNode } from 'react';
|
|
2
|
+
import { FlowDefinition, ParsedState, ParsedTransition, ParsedFlow } from '@ai-digital-factory/state-flow-definition';
|
|
3
|
+
export { DEFAULT_TRANSITION_NAME, DefaultTransitionName, HandlerContext, STATE_HANDLER_EXPORT_NAMES, TRANSITION_HANDLER_EXPORT_NAMES, TransitionHandlerContext } from '@ai-digital-factory/state-flow-definition';
|
|
4
|
+
|
|
5
|
+
declare function StateFlowPlaceholder(): ReactElement;
|
|
6
|
+
|
|
7
|
+
type FlowProps = {
|
|
8
|
+
/** Lowercase kebab-case flow identifier (e.g. `visitor-access`). Enforced by flow check. */
|
|
9
|
+
name: string;
|
|
10
|
+
description: string;
|
|
11
|
+
default: string;
|
|
12
|
+
children?: ReactNode;
|
|
13
|
+
};
|
|
14
|
+
declare function Flow({ name, description, default: defaultStateName, children, }: FlowProps): ReactElement;
|
|
15
|
+
declare namespace Flow {
|
|
16
|
+
var displayName: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
type StateProps = {
|
|
20
|
+
id?: string;
|
|
21
|
+
name: string;
|
|
22
|
+
description: string;
|
|
23
|
+
/**
|
|
24
|
+
* Compound State (ADR 0095, 0096): the nested child State entered with this State. Required
|
|
25
|
+
* when the State contains nested `<State>` / `<FinalState>` children.
|
|
26
|
+
*/
|
|
27
|
+
default?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Compound State whose child is one placement of a reusable Flow of the same flows package.
|
|
30
|
+
* Its completion fires this State's `trigger="done"` Transition.
|
|
31
|
+
*/
|
|
32
|
+
flow?: string;
|
|
33
|
+
/** Transitions, nested States, or one `<FlowList>`. */
|
|
34
|
+
children?: ReactNode;
|
|
35
|
+
};
|
|
36
|
+
/** Declares a flow state; rendered by `Flow`, not directly. */
|
|
37
|
+
declare function State(_props: StateProps): null;
|
|
38
|
+
declare namespace State {
|
|
39
|
+
var displayName: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
type ParallelStateProps = {
|
|
43
|
+
id?: string;
|
|
44
|
+
name: string;
|
|
45
|
+
description: string;
|
|
46
|
+
/** `<Region>` and `<FlowList>` children, all active together, plus Transitions. */
|
|
47
|
+
children?: ReactNode;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Declares a parallel State (ADR 0095, 0096): entering it activates every declared region.
|
|
51
|
+
* It completes, firing its `trigger="done"` Transition, when every region completes.
|
|
52
|
+
*/
|
|
53
|
+
declare function ParallelState(_props: ParallelStateProps): null;
|
|
54
|
+
declare namespace ParallelState {
|
|
55
|
+
var displayName: string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
type RegionProps = {
|
|
59
|
+
/** Lowercase kebab-case; addressed as `state:region` from the parallel State. */
|
|
60
|
+
name: string;
|
|
61
|
+
description: string;
|
|
62
|
+
/** For nested States: the child entered with the region. */
|
|
63
|
+
default?: string;
|
|
64
|
+
/** Instead of nested States: one placement of a reusable Flow of the same flows package. */
|
|
65
|
+
flow?: string;
|
|
66
|
+
/** Nested `<State>` / `<FinalState>` children of an inline region. */
|
|
67
|
+
children?: ReactNode;
|
|
68
|
+
};
|
|
69
|
+
/** One region of a `ParallelState`; rendered by `Flow`, not directly. */
|
|
70
|
+
declare function Region(_props: RegionProps): null;
|
|
71
|
+
declare namespace Region {
|
|
72
|
+
var displayName: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
type FlowListProps = {
|
|
76
|
+
/** Lowercase kebab-case region name. */
|
|
77
|
+
name: string;
|
|
78
|
+
description: string;
|
|
79
|
+
/** The reusable child Flow every member executes, from the same flows package. */
|
|
80
|
+
flow: string;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Declares a FlowList (ADR 0095, 0096): one keyed execution of a reusable Flow per member. The
|
|
84
|
+
* containing State's `children` handler returns the members when the State is entered; the
|
|
85
|
+
* membership is fixed for that activation. Use inside a `<State>` or a `<ParallelState>`.
|
|
86
|
+
*/
|
|
87
|
+
declare function FlowList(_props: FlowListProps): null;
|
|
88
|
+
declare namespace FlowList {
|
|
89
|
+
var displayName: string;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
type FinalStateProps = {
|
|
93
|
+
id?: string;
|
|
94
|
+
name: string;
|
|
95
|
+
description: string;
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Declares a terminal State: no outgoing Transitions and no callbacks. Reaching it completes the
|
|
99
|
+
* flow instance (ADR 0087). Rendered by `Flow`, not directly.
|
|
100
|
+
*/
|
|
101
|
+
declare function FinalState(_props: FinalStateProps): null;
|
|
102
|
+
declare namespace FinalState {
|
|
103
|
+
var displayName: string;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
type TransitionProps = {
|
|
107
|
+
name: string;
|
|
108
|
+
description: string;
|
|
109
|
+
/**
|
|
110
|
+
* When this Transition leaves a composite State while descendant work is running or
|
|
111
|
+
* unresolved (ADR 0095): `block` (default) answers `busy`; `interrupt` cancels that work
|
|
112
|
+
* cooperatively and proceeds without waiting for it.
|
|
113
|
+
*/
|
|
114
|
+
childWork?: "block" | "interrupt";
|
|
115
|
+
/**
|
|
116
|
+
* `done`: fired by the runtime when the State's children complete, with their completion
|
|
117
|
+
* result as payload. Allowed once per composite State. Omitted: dispatched by the application.
|
|
118
|
+
*/
|
|
119
|
+
trigger?: "dispatch" | "done";
|
|
120
|
+
/**
|
|
121
|
+
* One or more `<To state="..." description="..." />` children. A single destination is fixed;
|
|
122
|
+
* several make the Transition branch, and its `onTransition` selects one (ADR 0087).
|
|
123
|
+
*/
|
|
124
|
+
children?: ReactNode;
|
|
125
|
+
};
|
|
126
|
+
/** Declares an allowed transition; rendered by `Flow`, not directly. */
|
|
127
|
+
declare function Transition(_props: TransitionProps): null;
|
|
128
|
+
declare namespace Transition {
|
|
129
|
+
var displayName: string;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
type ToProps = {
|
|
133
|
+
/** Destination State name. */
|
|
134
|
+
state: string;
|
|
135
|
+
/** When this destination is selected, for example "Broker accepted the order." */
|
|
136
|
+
description: string;
|
|
137
|
+
};
|
|
138
|
+
/** Declares one allowed destination of its parent `Transition`; rendered by `Flow`, not directly. */
|
|
139
|
+
declare function To(_props: ToProps): null;
|
|
140
|
+
declare namespace To {
|
|
141
|
+
var displayName: string;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
type FlowRendererProps = {
|
|
145
|
+
flow: FlowDefinition;
|
|
146
|
+
};
|
|
147
|
+
declare function FlowRenderer({ flow }: FlowRendererProps): ReactElement;
|
|
148
|
+
|
|
149
|
+
type FlowPageHeaderProps = {
|
|
150
|
+
title: string;
|
|
151
|
+
description: string;
|
|
152
|
+
/** Lowercase kebab-case flow id; picks a header icon when set. */
|
|
153
|
+
flowId?: string;
|
|
154
|
+
};
|
|
155
|
+
declare function FlowPageHeader({ title, description, flowId, }: FlowPageHeaderProps): ReactElement;
|
|
156
|
+
|
|
157
|
+
declare function FlowHeaderIcon({ flowId }: {
|
|
158
|
+
flowId?: string;
|
|
159
|
+
}): ReactElement;
|
|
160
|
+
declare function flowNavIcon(flowId: string): string;
|
|
161
|
+
|
|
162
|
+
type DiagramOverviewProps = {
|
|
163
|
+
svgHtml: string;
|
|
164
|
+
states: ParsedState[];
|
|
165
|
+
edges: ParsedTransition[];
|
|
166
|
+
/** When set, sync zoom, pan, and diagram focus to the page URL query string. */
|
|
167
|
+
viewPersistenceKey?: string;
|
|
168
|
+
/** Highlight a transition edge after a guard blocks (simulate). */
|
|
169
|
+
guardBlockedEdgeIndex?: number | null;
|
|
170
|
+
/** Stack detail below the diagram, or show state/transition aside (tool viewers). */
|
|
171
|
+
detailLayout?: "inline" | "split";
|
|
172
|
+
/** When set with `detailLayout="split"`, pre-select this state in the aside. */
|
|
173
|
+
initialStateId?: string;
|
|
174
|
+
};
|
|
175
|
+
declare function DiagramOverview({ svgHtml, states, edges, viewPersistenceKey, guardBlockedEdgeIndex, detailLayout, initialStateId, }: DiagramOverviewProps): ReactElement;
|
|
176
|
+
|
|
177
|
+
/** Forward edges run above the states; return edges run below them. */
|
|
178
|
+
declare function diagramSvg(flow: ParsedFlow, title: string, instanceId: string): string;
|
|
179
|
+
|
|
180
|
+
declare function parseScrollYFromSearch(search: string): number | null;
|
|
181
|
+
declare function mergeScrollYIntoSearch(search: string, scrollY: number): string;
|
|
182
|
+
declare function replaceBrowserUrlSearch(search: string): void;
|
|
183
|
+
|
|
184
|
+
declare function extractFlowDefinition(node: ReactNode): FlowDefinition;
|
|
185
|
+
type FlowComponent = () => ReactNode;
|
|
186
|
+
declare function extractFlowDefinitionFromComponent(component: FlowComponent): FlowDefinition;
|
|
187
|
+
|
|
188
|
+
export { DiagramOverview, type DiagramOverviewProps, FinalState, type FinalStateProps, Flow, type FlowComponent, FlowHeaderIcon, FlowList, type FlowListProps, FlowPageHeader, type FlowPageHeaderProps, type FlowProps, FlowRenderer, type FlowRendererProps, ParallelState, type ParallelStateProps, Region, type RegionProps, State, StateFlowPlaceholder, type StateProps, To, type ToProps, Transition, type TransitionProps, diagramSvg, extractFlowDefinition, extractFlowDefinitionFromComponent, flowNavIcon, mergeScrollYIntoSearch, parseScrollYFromSearch, replaceBrowserUrlSearch };
|