x-openapi-flow 1.2.2 → 1.3.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 +212 -18
- package/bin/x-openapi-flow.js +709 -22
- package/examples/swagger-ui/index.html +1 -1
- package/lib/swagger-ui/x-openapi-flow-plugin.js +856 -0
- package/lib/validator.js +36 -3
- package/package.json +3 -2
- package/schema/flow-schema.json +2 -2
- package/examples/swagger-ui/x-openapi-flow-plugin.js +0 -446
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# x-openapi-flow
|
|
2
2
|
|
|
3
|
+

|
|
4
|
+
|
|
3
5
|
CLI and extension contract for documenting and validating resource lifecycle workflows in OpenAPI using `x-openapi-flow`.
|
|
4
6
|
|
|
5
7
|
## Overview
|
|
@@ -10,7 +12,7 @@ CLI and extension contract for documenting and validating resource lifecycle wor
|
|
|
10
12
|
- Lifecycle graph consistency
|
|
11
13
|
- Optional quality checks for transitions and references
|
|
12
14
|
|
|
13
|
-
It also supports a sidecar workflow (`init` + `apply`)
|
|
15
|
+
It also supports a sidecar workflow (`init` + `apply`) so lifecycle metadata stays preserved when OpenAPI source files are regenerated.
|
|
14
16
|
|
|
15
17
|
## Installation
|
|
16
18
|
|
|
@@ -36,7 +38,7 @@ Use a GitHub PAT with `read:packages` (install) and `write:packages` (publish).
|
|
|
36
38
|
## Quick Start
|
|
37
39
|
|
|
38
40
|
```bash
|
|
39
|
-
npx x-openapi-flow init
|
|
41
|
+
npx x-openapi-flow init
|
|
40
42
|
npx x-openapi-flow apply openapi.yaml
|
|
41
43
|
```
|
|
42
44
|
|
|
@@ -44,34 +46,226 @@ Optional checks:
|
|
|
44
46
|
|
|
45
47
|
```bash
|
|
46
48
|
npx x-openapi-flow validate openapi.yaml --profile strict
|
|
49
|
+
npx x-openapi-flow lint openapi.yaml
|
|
47
50
|
npx x-openapi-flow graph openapi.yaml
|
|
48
51
|
```
|
|
49
52
|
|
|
50
53
|
## CLI Commands
|
|
51
54
|
|
|
52
55
|
```bash
|
|
53
|
-
x-openapi-flow validate <openapi-file> [--format pretty|json] [--profile core|relaxed|strict] [--strict-quality] [--config path]
|
|
54
|
-
x-openapi-flow init [
|
|
55
|
-
x-openapi-flow apply [openapi-file] [--flows path] [--out path]
|
|
56
|
-
x-openapi-flow
|
|
57
|
-
x-openapi-flow
|
|
56
|
+
npx x-openapi-flow validate <openapi-file> [--format pretty|json] [--profile core|relaxed|strict] [--strict-quality] [--config path]
|
|
57
|
+
npx x-openapi-flow init [--flows path] [--force] [--dry-run]
|
|
58
|
+
npx x-openapi-flow apply [openapi-file] [--flows path] [--out path]
|
|
59
|
+
npx x-openapi-flow diff [openapi-file] [--flows path] [--format pretty|json]
|
|
60
|
+
npx x-openapi-flow lint [openapi-file] [--format pretty|json] [--config path]
|
|
61
|
+
npx x-openapi-flow graph <openapi-file> [--format mermaid|json]
|
|
62
|
+
npx x-openapi-flow doctor [--config path]
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`diff` now reports field-level changes for operations that already exist in the sidecar.
|
|
66
|
+
In `pretty` format, this appears under `Changed details` with changed paths per operation (for example, `current_state` or `transitions[0].target_state`).
|
|
67
|
+
In `json` format, this appears in `diff.changedOperationDetails`:
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"diff": {
|
|
72
|
+
"changedOperationDetails": [
|
|
73
|
+
{
|
|
74
|
+
"operationId": "listItems",
|
|
75
|
+
"changedPaths": ["current_state"]
|
|
76
|
+
}
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### CI usage (`diff` as a gate)
|
|
83
|
+
|
|
84
|
+
Fail the pipeline when sidecar drift is detected:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
npx x-openapi-flow diff openapi.yaml --format json | node -e '
|
|
88
|
+
const fs = require("fs");
|
|
89
|
+
const payload = JSON.parse(fs.readFileSync(0, "utf8"));
|
|
90
|
+
const diff = payload.diff || {};
|
|
91
|
+
const changes = (diff.added || 0) + (diff.removed || 0) + (diff.changed || 0);
|
|
92
|
+
if (changes > 0) {
|
|
93
|
+
console.error("x-openapi-flow diff detected changes. Run init/apply and commit sidecar updates.");
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
'
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
This keeps `.x` sidecar data aligned with the OpenAPI source in pull requests.
|
|
100
|
+
|
|
101
|
+
## Semantic lint (`lint`)
|
|
102
|
+
|
|
103
|
+
Use `lint` to run semantic checks focused on flow modeling quality.
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
npx x-openapi-flow lint openapi.yaml
|
|
107
|
+
npx x-openapi-flow lint openapi.yaml --format json
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
MVP semantic rules:
|
|
111
|
+
|
|
112
|
+
- `next_operation_id_exists`
|
|
113
|
+
- `prerequisite_operation_ids_exist`
|
|
114
|
+
- `duplicate_transitions`
|
|
115
|
+
- `terminal_path` (states without path to terminal)
|
|
116
|
+
|
|
117
|
+
Disable individual rules with config (`x-openapi-flow.config.json`):
|
|
118
|
+
|
|
119
|
+
```json
|
|
120
|
+
{
|
|
121
|
+
"lint": {
|
|
122
|
+
"rules": {
|
|
123
|
+
"next_operation_id_exists": true,
|
|
124
|
+
"prerequisite_operation_ids_exist": true,
|
|
125
|
+
"duplicate_transitions": false,
|
|
126
|
+
"terminal_path": true
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
58
130
|
```
|
|
59
131
|
|
|
132
|
+
## Graph JSON contract (`graph --format json`)
|
|
133
|
+
|
|
134
|
+
`graph --format json` returns a stable contract for CI/pipeline integrations:
|
|
135
|
+
|
|
136
|
+
- `format_version`: output contract version (currently `"1.0"`).
|
|
137
|
+
- `flowCount`: number of operations with `x-openapi-flow`.
|
|
138
|
+
- `nodes`: sorted state names (deterministic order).
|
|
139
|
+
- `edges`: sorted transitions by `from`, `to`, `next_operation_id`, and prerequisites.
|
|
140
|
+
- `mermaid`: deterministic Mermaid rendering of the same graph.
|
|
141
|
+
|
|
142
|
+
Example:
|
|
143
|
+
|
|
144
|
+
```json
|
|
145
|
+
{
|
|
146
|
+
"format_version": "1.0",
|
|
147
|
+
"flowCount": 3,
|
|
148
|
+
"nodes": ["CONFIRMED", "CREATED", "SHIPPED"],
|
|
149
|
+
"edges": [
|
|
150
|
+
{
|
|
151
|
+
"from": "CONFIRMED",
|
|
152
|
+
"to": "SHIPPED",
|
|
153
|
+
"next_operation_id": "shipOrder",
|
|
154
|
+
"prerequisite_operation_ids": []
|
|
155
|
+
}
|
|
156
|
+
],
|
|
157
|
+
"mermaid": "stateDiagram-v2\n state CONFIRMED\n state CREATED\n state SHIPPED\n CONFIRMED --> SHIPPED: next:shipOrder"
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## HTTP Methods Support
|
|
162
|
+
|
|
163
|
+
`init`, `apply`, and `graph` support all OpenAPI 3 HTTP operation methods:
|
|
164
|
+
|
|
165
|
+
- `get`
|
|
166
|
+
- `put`
|
|
167
|
+
- `post`
|
|
168
|
+
- `delete`
|
|
169
|
+
- `options`
|
|
170
|
+
- `head`
|
|
171
|
+
- `patch`
|
|
172
|
+
- `trace`
|
|
173
|
+
|
|
60
174
|
## Sidecar Workflow
|
|
61
175
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
176
|
+
Behavior summary:
|
|
177
|
+
|
|
178
|
+
- `init` works on an existing OpenAPI source file in your repository.
|
|
179
|
+
- `init` creates/synchronizes `{context}.x.(json|yaml)` as a persistent sidecar for `x-openapi-flow` data.
|
|
180
|
+
- If `{context}.flow.(json|yaml)` does not exist, `init` generates it automatically (same merge result as `apply`).
|
|
181
|
+
- If `{context}.flow.(json|yaml)` already exists, `init` asks in interactive mode whether to recreate it.
|
|
182
|
+
- On confirmation (or with `--force`), `init` creates a sidecar backup as `{context}.x.(json|yaml).backup-N` before regenerating `{context}.flow.(json|yaml)`.
|
|
183
|
+
- In non-interactive mode, `init` fails when flow output already exists unless `--force` is provided.
|
|
184
|
+
- With `--dry-run`, `init` prints a summary of sidecar/flow behavior without writing files.
|
|
185
|
+
- Use `apply` to inject sidecar flows back into regenerated OpenAPI source files.
|
|
186
|
+
- If no OpenAPI/Swagger source file exists yet, generate one first with your framework's official tooling.
|
|
66
187
|
|
|
67
188
|
### Recommended Sequence
|
|
68
189
|
|
|
69
190
|
```bash
|
|
70
|
-
x-openapi-flow init
|
|
71
|
-
|
|
72
|
-
|
|
191
|
+
npx x-openapi-flow init
|
|
192
|
+
npx x-openapi-flow init --dry-run
|
|
193
|
+
# edit {context}.x.(json|yaml)
|
|
194
|
+
npx x-openapi-flow diff openapi.yaml
|
|
195
|
+
npx x-openapi-flow apply openapi.yaml
|
|
73
196
|
```
|
|
74
197
|
|
|
198
|
+
## Sidecar File Contract (all supported fields)
|
|
199
|
+
|
|
200
|
+
Sidecar top-level shape:
|
|
201
|
+
|
|
202
|
+
```yaml
|
|
203
|
+
version: "1.0"
|
|
204
|
+
operations:
|
|
205
|
+
- operationId: createOrder
|
|
206
|
+
x-openapi-flow:
|
|
207
|
+
version: "1.0"
|
|
208
|
+
id: create-order
|
|
209
|
+
current_state: CREATED
|
|
210
|
+
description: Creates an order and starts its lifecycle
|
|
211
|
+
idempotency:
|
|
212
|
+
header: Idempotency-Key
|
|
213
|
+
required: true
|
|
214
|
+
transitions:
|
|
215
|
+
- target_state: PAID
|
|
216
|
+
trigger_type: synchronous
|
|
217
|
+
condition: Payment approved
|
|
218
|
+
next_operation_id: payOrder
|
|
219
|
+
prerequisite_operation_ids:
|
|
220
|
+
- createOrder
|
|
221
|
+
prerequisite_field_refs:
|
|
222
|
+
- createOrder:request.body.customer_id
|
|
223
|
+
propagated_field_refs:
|
|
224
|
+
- createOrder:response.201.body.order_id
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Top-level (sidecar document):
|
|
228
|
+
|
|
229
|
+
- `version` (optional, string): sidecar contract version. Default is `"1.0"`.
|
|
230
|
+
- `operations` (optional, array): entries keyed by operation.
|
|
231
|
+
|
|
232
|
+
Per operation entry:
|
|
233
|
+
|
|
234
|
+
- `operationId` (recommended, string): target operation identifier in OpenAPI.
|
|
235
|
+
- `x-openapi-flow` (object): lifecycle metadata for that operation.
|
|
236
|
+
- `key` (optional, legacy): backward-compatibility fallback key used by apply.
|
|
237
|
+
|
|
238
|
+
`x-openapi-flow` fields:
|
|
239
|
+
|
|
240
|
+
- Required:
|
|
241
|
+
- `version` (string): currently `"1.0"`.
|
|
242
|
+
- `id` (string): unique flow id.
|
|
243
|
+
- `current_state` (string): state represented by this operation.
|
|
244
|
+
- Optional:
|
|
245
|
+
- `description` (string): human-readable purpose.
|
|
246
|
+
- `idempotency` (object):
|
|
247
|
+
- `header` (required, string)
|
|
248
|
+
- `required` (optional, boolean)
|
|
249
|
+
- `transitions` (array of transition objects)
|
|
250
|
+
|
|
251
|
+
Transition object fields:
|
|
252
|
+
|
|
253
|
+
- Required:
|
|
254
|
+
- `target_state` (string)
|
|
255
|
+
- `trigger_type` (enum): `synchronous`, `webhook`, `polling`
|
|
256
|
+
- Optional:
|
|
257
|
+
- `condition` (string)
|
|
258
|
+
- `next_operation_id` (string)
|
|
259
|
+
- `prerequisite_operation_ids` (array of strings)
|
|
260
|
+
- `prerequisite_field_refs` (array of strings)
|
|
261
|
+
- `propagated_field_refs` (array of strings)
|
|
262
|
+
|
|
263
|
+
Field refs format:
|
|
264
|
+
|
|
265
|
+
- `operationId:request.body.field`
|
|
266
|
+
- `operationId:request.path.paramName`
|
|
267
|
+
- `operationId:response.<status>.body.field`
|
|
268
|
+
|
|
75
269
|
## Configuration
|
|
76
270
|
|
|
77
271
|
Create `x-openapi-flow.config.json` in your project directory:
|
|
@@ -106,18 +300,18 @@ Field reference format:
|
|
|
106
300
|
### Swagger UI
|
|
107
301
|
|
|
108
302
|
- There is no Swagger UI-based automated test in this repo today (tests are CLI-only).
|
|
109
|
-
- For UI interpretation of `x-openapi-flow`, use `showExtensions: true`
|
|
303
|
+
- For UI interpretation of `x-openapi-flow`, use `showExtensions: true` with the plugin at `lib/swagger-ui/x-openapi-flow-plugin.js`.
|
|
110
304
|
- A ready HTML example is available at `examples/swagger-ui/index.html`.
|
|
111
305
|
- The plugin renders a global **Flow Overview** (Mermaid image) near the top of the docs, plus operation-level flow cards.
|
|
112
306
|
|
|
113
|
-

|
|
114
308
|
|
|
115
309
|
### Graph Output Example
|
|
116
310
|
|
|
117
311
|
`x-openapi-flow graph` includes transition guidance labels in Mermaid output when present (`next_operation_id`, `prerequisite_operation_ids`).
|
|
118
|
-
The `graph` command accepts both full OpenAPI files and sidecar files (`{context}-openapi-flow.(json|yaml)`).
|
|
312
|
+
The `graph` command accepts both full OpenAPI source files and sidecar files (`{context}.x.(json|yaml)` and legacy `{context}-openapi-flow.(json|yaml)`).
|
|
119
313
|
|
|
120
|
-

|
|
121
315
|
|
|
122
316
|
## Repository and Documentation
|
|
123
317
|
|