@owlmeans/flow 0.1.18-rc.7 → 0.1.18-rc.9

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.
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
3
  "package": "@owlmeans/flow",
4
- "version": "0.1.18-rc.7",
5
- "generatedAt": "2026-08-24T21:14:00.138Z",
4
+ "version": "0.1.18-rc.8",
5
+ "generatedAt": "2026-08-27T21:16:47.143Z",
6
6
  "canonicalRepo": "https://github.com/owlmeans/common",
7
7
  "entries": [
8
8
  {
@@ -1,46 +1,114 @@
1
1
  ---
2
2
  name: flow
3
- description: How to use @owlmeans/flow — state-machine / workflow execution framework with typed state, transitions, and flow definitions. Auto-invoked when importing from this package or implementing multi-step workflows.
3
+ description: How to use @owlmeans/flow — a serializable step/transition state machine whose whole state collapses to one string. Auto-invoked when importing from this package, driving a multi-step workflow, or restoring one from a token.
4
4
  user-invocable: false
5
5
  ---
6
6
  <!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
7
7
 
8
8
  # @owlmeans/flow
9
9
 
10
- **Layer:** Core
11
- **Install:** `"@owlmeans/flow": "^0.1.18-rc.7"` in `dependencies`
10
+ **Layer:** Cross-cutting domain
11
+ **Install:** `"@owlmeans/flow": "^0.1.18-rc.8"` in `dependencies`
12
12
 
13
- ## Key Exports
13
+ A flow is a set of named **steps**, each offering named **transitions** to other steps. What makes
14
+ it worth using over a hand-rolled switch is that the whole live state — flow, step, previous step,
15
+ entity, payload, message, ok — serializes to a single compact string and restores from it. That is
16
+ what lets a workflow survive a redirect, a page load, or a process.
17
+
18
+ ## Key exports
14
19
 
15
20
  | Export | Description |
16
- |--------|-------------|
17
- | `Flow` types | Flow definition shape (states, transitions, payload) |
18
- | `FlowState` | State management primitives |
19
- | Errors | Flow execution errors |
20
- | Constants | Built-in state names, transition types |
21
- | Helpers | Flow construction and validation |
22
- | `flows` submodule | Built-in flow definitions |
23
- | i18n | Translatable error messages |
21
+ |---|---|
22
+ | `makeFlowModel(flow, provider?)` | Build a driver. `flow` is a `ShallowFlow` **object** (no provider needed) or a **string** — tried as a flow name first, then as a serialized token. |
23
+ | `FlowModel` | `target` `entity` `enter` `steps` `state` `setState` `payload` `updatePayload` `step` `transitions` `transition` `next` `transit` `serialize` |
24
+ | `ShallowFlow` / `FlowStep` / `FlowTransition` / `FlowState` / `FlowPayload` | The definition and state shapes |
25
+ | `FlowProvider` | `(flow: string) => Promise<Flow>` — resolves a flow by name |
26
+ | `flow(cfg, shallowFlow)` · `configureFlows(cfg, config)` | Register a flow as a config record / set `FlowConfig` |
27
+ | `stdStabFlow`, `stdAuthFlow` (deprecated), the OIDC/OIDP flows | Built-in flows |
28
+ | `FlowError`, `UnknownFlow`, `UnknownFlowStep`, `UnknownTransition`, … | The error family |
24
29
 
25
- ## Usage
30
+ ## Defining a flow
26
31
 
27
- Define a flow with typed states, then drive it from `@owlmeans/client-flow` (cross-platform) or `@owlmeans/web-flow` (web):
32
+ A definition is data, not a class. Each step carries an `index`, its own `step` name, the `service`
33
+ it belongs to, and a map of transitions keyed by transition name:
28
34
 
29
35
  ```typescript
30
- import { Flow, FlowState } from '@owlmeans/flow'
31
-
32
- const onboardingFlow: Flow = {
33
- alias: 'onboarding',
34
- initial: 'welcome',
35
- states: {
36
- welcome: { on: { NEXT: 'profile' } },
37
- profile: { on: { NEXT: 'done', BACK: 'welcome' } },
38
- done: { type: 'final' }
39
- }
36
+ import type { ShallowFlow } from '@owlmeans/flow'
37
+
38
+ export const onboardingFlow: ShallowFlow = {
39
+ flow: 'onboarding',
40
+ initialStep: 'welcome',
41
+ steps: {
42
+ welcome: {
43
+ index: 0,
44
+ step: 'welcome',
45
+ service: 'onboarding',
46
+ initial: true,
47
+ transitions: {
48
+ next: { transition: 'next', step: 'profile' },
49
+ },
50
+ },
51
+ profile: {
52
+ index: 1,
53
+ step: 'profile',
54
+ service: 'onboarding',
55
+ transitions: {
56
+ next: { transition: 'next', step: 'done' },
57
+ back: { transition: 'back', step: 'welcome', explicit: true, reversible: true },
58
+ },
59
+ },
60
+ done: { index: 2, step: 'done', service: 'onboarding', transitions: {} },
61
+ },
40
62
  }
41
63
  ```
42
64
 
43
- ## Depends On
65
+ ## Driving it
66
+
67
+ ```typescript
68
+ const model = await makeFlowModel(onboardingFlow) // an object needs no provider
69
+ model.transit('next', true) // → 'profile'
70
+ const token = model.transit('next', true) // → 'done'; returns the SERIALIZED state
71
+
72
+ const restored = await makeFlowModel(token, provider) // a token DOES need a provider
73
+ restored.step().step // 'done'
74
+ ```
75
+
76
+ ## Rules
77
+
78
+ **`transit()` returns the serialized state, not the model.** It is the natural place to persist or
79
+ hand off from — a caller that ignores the return and calls `serialize()` afterwards gets the same
80
+ string, but the return is the signal that a transition is a checkpoint.
81
+
82
+ **A string argument is a flow name FIRST and a token second.** `makeFlowModel` asks the provider,
83
+ and only re-reads the string as a serialized token once the provider **throws**. A provider that
84
+ returns `null`/`undefined` for an unknown name therefore breaks every restore — it must throw
85
+ (`UnknownFlow` is what the built-ins raise).
86
+
87
+ **Passing a `ShallowFlow` object needs no provider at all.** That is the server-friendly path: a
88
+ runtime whose flows are code it declares itself needs no registry to start one, only to restore one.
89
+
90
+ **`next()` requires exactly one non-explicit outgoing transition.** It is what lets a driver advance
91
+ without knowing the vocabulary; mark every user-chosen or exceptional edge `explicit` so it can
92
+ never become the automatic answer.
93
+
94
+ **`FlowPayload` holds flat scalars only** — `string | number | boolean | null | undefined`. Anything
95
+ richer belongs in a record the payload points at. Payload is projected through the step's
96
+ `payloadMap` on serialization, so an unmapped key does not survive a round trip.
97
+
98
+ **`reversible` is what keeps `previous`**, and is what a "back" transition needs to return to where
99
+ it came from.
100
+
101
+ ## Where it runs
102
+
103
+ Client drivers are `@owlmeans/client-flow` (`makeFlowService`) and `@owlmeans/web-flow`; they load
104
+ definitions from `FLOW_RECORD` config records through the config resource and carry the serialized
105
+ state in a query parameter (`FlowConfig.queryParam`).
106
+
107
+ There is **no server-side driver in this package**. A server or worker builds models directly from
108
+ `ShallowFlow` objects and supplies its own `FlowProvider` for restores — `@owlmeans/agent`'s
109
+ `makeStaticFlowProvider` is the reference implementation of one.
110
+
111
+ ## Depends on
44
112
 
45
- - `@owlmeans/error` — flow errors
46
- - `@owlmeans/i18n` — translatable error messages
113
+ `@owlmeans/auth`, `@owlmeans/config`, `@owlmeans/error`, `@owlmeans/i18n`, `@owlmeans/resource`,
114
+ `@scure/base` (the token codec).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owlmeans/flow",
3
- "version": "0.1.18-rc.7",
3
+ "version": "0.1.18-rc.9",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {