blokctl 0.6.21 → 1.0.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/dist/__tests__/modular-observability.capstone.e2e.test.js +72 -0
- package/dist/commands/create/node.js +46 -66
- package/dist/commands/create/project.js +60 -9
- package/dist/commands/create/utils/Examples.d.ts +11 -23
- package/dist/commands/create/utils/Examples.js +206 -421
- package/dist/commands/dev/index.js +40 -1
- package/dist/commands/generate/NodeGenerator.d.ts +0 -2
- package/dist/commands/generate/NodeGenerator.js +0 -20
- package/dist/commands/generate/RuntimeGenerator.d.ts +0 -2
- package/dist/commands/generate/RuntimeGenerator.js +0 -19
- package/dist/commands/generate/RuntimeGenerator.test.js +0 -29
- package/dist/commands/generate/TriggerGenerator.d.ts +0 -2
- package/dist/commands/generate/TriggerGenerator.js +0 -19
- package/dist/commands/generate/WorkflowGenerator.d.ts +0 -2
- package/dist/commands/generate/WorkflowGenerator.js +4 -23
- package/dist/commands/generate/WorkflowGenerator.test.js +2 -2
- package/dist/commands/generate/e2e/NodeGenerator.e2e.test.js +0 -12
- package/dist/commands/generate/e2e/RuntimeGenerator.e2e.test.js +0 -12
- package/dist/commands/generate/e2e/TriggerGenerator.e2e.test.js +0 -14
- package/dist/commands/generate/prompts/create-fn-node.system.js +10 -17
- package/dist/commands/generate/prompts/create-workflow.system.js +114 -375
- package/dist/commands/generate/validators/WorkflowValidator.js +80 -5
- package/dist/commands/generate/validators/WorkflowValidator.test.js +66 -0
- package/dist/commands/monitor/monitor-component.js +5 -5
- package/dist/commands/observability/add.d.ts +2 -0
- package/dist/commands/observability/add.js +113 -0
- package/dist/commands/observability/alerting-module.test.js +43 -0
- package/dist/commands/observability/apply.d.ts +10 -0
- package/dist/commands/observability/apply.js +11 -0
- package/dist/commands/observability/descriptor.d.ts +37 -0
- package/dist/commands/observability/descriptor.js +203 -0
- package/dist/commands/observability/descriptor.test.d.ts +1 -0
- package/dist/commands/observability/descriptor.test.js +40 -0
- package/dist/commands/observability/index.d.ts +1 -0
- package/dist/commands/observability/index.js +53 -0
- package/dist/commands/observability/list.d.ts +2 -0
- package/dist/commands/observability/list.js +45 -0
- package/dist/commands/observability/logging-module.test.d.ts +1 -0
- package/dist/commands/observability/logging-module.test.js +43 -0
- package/dist/commands/observability/obs-stack-module.test.d.ts +1 -0
- package/dist/commands/observability/obs-stack-module.test.js +33 -0
- package/dist/commands/observability/remove.d.ts +2 -0
- package/dist/commands/observability/remove.js +62 -0
- package/dist/commands/observability/shared.d.ts +6 -0
- package/dist/commands/observability/shared.js +23 -0
- package/dist/commands/observability/status.d.ts +2 -0
- package/dist/commands/observability/status.js +36 -0
- package/dist/commands/observability/tracing-module.test.d.ts +1 -0
- package/dist/commands/observability/tracing-module.test.js +42 -0
- package/dist/commands/profile/index.js +7 -10
- package/dist/commands/watch/format.d.ts +23 -0
- package/dist/commands/watch/format.js +60 -0
- package/dist/commands/watch/index.d.ts +1 -0
- package/dist/commands/watch/index.js +53 -0
- package/dist/commands/watch/sse.d.ts +16 -0
- package/dist/commands/watch/sse.js +82 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +4 -0
- package/dist/services/obs-setup.d.ts +5 -0
- package/dist/services/obs-setup.js +68 -0
- package/dist/services/obs-setup.test.d.ts +1 -0
- package/dist/services/obs-setup.test.js +71 -0
- package/dist/services/obs-tiers.d.ts +9 -0
- package/dist/services/obs-tiers.js +16 -0
- package/dist/services/observability-mutations.d.ts +4 -0
- package/dist/services/observability-mutations.js +46 -0
- package/dist/services/observability-mutations.test.d.ts +1 -0
- package/dist/services/observability-mutations.test.js +57 -0
- package/dist/services/runtime-setup.d.ts +12 -1
- package/dist/services/runtime-setup.js +274 -14
- package/dist/studio-dist/assets/{index-BD8_9YPN.js → index-CnFqCRQe.js} +17 -17
- package/dist/studio-dist/index.html +1 -1
- package/package.json +3 -3
- package/dist/commands/generate/GenerationAnalytics.d.ts +0 -61
- package/dist/commands/generate/GenerationAnalytics.js +0 -163
- package/dist/commands/generate/GenerationAnalytics.test.js +0 -407
- package/dist/commands/generate/PromptVersioning.d.ts +0 -25
- package/dist/commands/generate/PromptVersioning.js +0 -71
- package/dist/commands/generate/PromptVersioning.test.js +0 -120
- /package/dist/{commands/generate/GenerationAnalytics.test.d.ts → __tests__/modular-observability.capstone.e2e.test.d.ts} +0 -0
- /package/dist/commands/{generate/PromptVersioning.test.d.ts → observability/alerting-module.test.d.ts} +0 -0
|
@@ -1,443 +1,183 @@
|
|
|
1
1
|
const createWorkflowSystemPrompt = {
|
|
2
|
-
prompt: `You are a senior backend engineer specializing in the Blok (blok) workflow framework. Your task is to generate a fully working **Workflow JSON configuration file** that implements the described logic.
|
|
2
|
+
prompt: `You are a senior backend engineer specializing in the Blok (blok) workflow framework. Your task is to generate a fully working **v2 Workflow JSON configuration file** that implements the described logic.
|
|
3
3
|
|
|
4
4
|
What to return:
|
|
5
5
|
|
|
6
6
|
* Return only a complete JSON object representing a workflow configuration, ready to be saved directly into \`workflows/json/<workflow-name>.json\`.
|
|
7
7
|
* The JSON object MUST include:
|
|
8
8
|
|
|
9
|
-
1. \`name\`: A descriptive name for the workflow
|
|
9
|
+
1. \`name\`: A descriptive name for the workflow (3+ characters)
|
|
10
10
|
2. \`description\`: A short human-readable description of what the workflow does
|
|
11
11
|
3. \`version\`: Semantic version string (e.g., "1.0.0")
|
|
12
12
|
4. \`trigger\`: An object with exactly ONE trigger type and its configuration
|
|
13
|
-
5. \`steps\`: An ordered array of
|
|
14
|
-
6. \`nodes\`: A map of node configurations keyed by step names
|
|
13
|
+
5. \`steps\`: An ordered array of step objects — each step carries its own \`inputs\` INLINE
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
**There is NO \`nodes\` map in v2.** Inputs live directly on each step. (Old v1 workflows used a separate \`nodes{}\` map keyed by step name — do NOT generate that shape.)
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
## Step Shape (v2)
|
|
19
18
|
|
|
20
|
-
### HTTP Trigger
|
|
21
19
|
\`\`\`json
|
|
22
|
-
|
|
23
|
-
"
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
"accept": "application/json"
|
|
27
|
-
}
|
|
20
|
+
{
|
|
21
|
+
"id": "fetch-user",
|
|
22
|
+
"use": "@blokjs/api-call",
|
|
23
|
+
"inputs": { "url": "https://api.example.com/users/1", "method": "GET" }
|
|
28
24
|
}
|
|
29
25
|
\`\`\`
|
|
30
|
-
- \`method\`: "GET", "POST", "PUT", "DELETE", "PATCH", or "*" (any method)
|
|
31
|
-
- \`path\`: Express-style route with optional params (e.g., "/:id", "/:function?/:id?")
|
|
32
|
-
- \`accept\`: Content type accepted
|
|
33
26
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
- \`topic\`: Queue/topic name to consume from
|
|
49
|
-
- \`consumerGroup\`: Consumer group ID (for Kafka)
|
|
50
|
-
- \`ack\`: Whether to acknowledge after processing (default: true)
|
|
27
|
+
- \`id\` (required): unique identifier for the step. Every step's output is auto-persisted to \`ctx.state[<id>]\` on success — reference it later as \`"$.state.<id>"\`.
|
|
28
|
+
- \`use\` (required): the node to run — a package name (\`"@blokjs/api-call"\`) or a local node name (\`"fetch-user"\`).
|
|
29
|
+
- \`inputs\` (optional): the node's input object (see Input Value Patterns).
|
|
30
|
+
- \`type\` (optional): inferred from \`use\` when omitted. Use \`"runtime.<lang>"\` (e.g. \`"runtime.go"\`, \`"runtime.python3"\`) for cross-runtime nodes.
|
|
31
|
+
|
|
32
|
+
### Persistence knobs (optional, per-step)
|
|
33
|
+
|
|
34
|
+
- \`"as": "name"\` — store the output at \`ctx.state[name]\` instead of \`ctx.state[id]\`.
|
|
35
|
+
- \`"spread": true\` — shallow-merge the node's \`result.data\` keys into \`ctx.state\` (multi-output nodes). Mutually exclusive with \`as\`.
|
|
36
|
+
- \`"ephemeral": true\` — skip persistence (only the immediately next step can read it via \`$.prev\`). Use for logging / response-only steps.
|
|
37
|
+
|
|
38
|
+
## Conditional Routing (branch)
|
|
39
|
+
|
|
40
|
+
A conditional is a SINGLE step with a \`branch\` object — NOT a \`conditions\` array, NOT an \`@blokjs/if-else\` node.
|
|
51
41
|
|
|
52
|
-
### Pub/Sub Trigger
|
|
53
42
|
\`\`\`json
|
|
54
|
-
|
|
55
|
-
"
|
|
56
|
-
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"maxMessages": 10
|
|
43
|
+
{
|
|
44
|
+
"id": "route",
|
|
45
|
+
"branch": {
|
|
46
|
+
"when": "ctx.req.method === 'POST'",
|
|
47
|
+
"then": [{ "id": "create", "use": "@blokjs/api-call", "inputs": { "url": "..." } }],
|
|
48
|
+
"else": [{ "id": "read", "use": "@blokjs/api-call", "inputs": { "url": "..." } }]
|
|
61
49
|
}
|
|
62
50
|
}
|
|
63
51
|
\`\`\`
|
|
64
|
-
- \`provider\`: "gcp", "aws", or "azure"
|
|
65
|
-
- \`topic\`: Topic name
|
|
66
|
-
- \`subscription\`: Subscription name
|
|
67
52
|
|
|
68
|
-
|
|
53
|
+
- \`when\` is a RAW JavaScript expression over \`ctx.*\` — e.g. \`"ctx.state.user.active === true"\`, \`"ctx.req.body.amount > 100"\`. **Never** prefix it with \`js/\` or \`$.\` (those throw at runtime).
|
|
54
|
+
- \`then\` (required) and \`else\` (optional) are arrays of steps, same shape as top-level steps.
|
|
55
|
+
- Step ids are FLAT across the whole workflow, including branch arms — every id must be unique.
|
|
56
|
+
|
|
57
|
+
## Input Value Patterns
|
|
58
|
+
|
|
59
|
+
1. **Static values**: \`"message": "Hello World"\`, \`"retries": 3\`, \`"headers": { "Accept": "application/json" }\`
|
|
60
|
+
2. **Reference another step's output**: \`"$.state.<step-id>"\` — e.g. \`"body": "$.state.fetch-user"\`. Access a field with dot paths: \`"$.state.fetch-user.user.id"\`.
|
|
61
|
+
3. **Request data**: \`"$.req.body"\`, \`"$.req.params.id"\`, \`"$.req.query.search"\`, \`"$.req.headers"\`, \`"$.req.method"\`.
|
|
62
|
+
4. **Previous step (adjacent only)**: \`"$.prev"\` — the immediately previous step's output. For non-adjacent reads always use \`"$.state.<id>"\`.
|
|
63
|
+
5. **Inline JavaScript** (when you need logic): a \`"js/..."\` string — e.g. \`"url": "js/\\\`https://api/users/\\\${ctx.req.params.id}\\\`"\`. \`$.\` strings compile to \`js/ctx.\` automatically; \`js/\` lets you write the expression by hand.
|
|
64
|
+
|
|
65
|
+
(\`$.request\` = \`$.req\`, \`$.response\` = \`$.prev\`, \`$.vars\` = \`$.state\` are legacy aliases — prefer the canonical \`$.req\` / \`$.prev\` / \`$.state\`.)
|
|
66
|
+
|
|
67
|
+
## Controlling the HTTP response
|
|
68
|
+
|
|
69
|
+
End an HTTP workflow with a \`@blokjs/respond\` step for custom status / headers / cookies / redirect / binary. Mark it \`"ephemeral": true\`.
|
|
70
|
+
|
|
69
71
|
\`\`\`json
|
|
70
|
-
"
|
|
71
|
-
"cron": {
|
|
72
|
-
"schedule": "0 * * * *",
|
|
73
|
-
"timezone": "America/New_York",
|
|
74
|
-
"overlap": false
|
|
75
|
-
}
|
|
76
|
-
}
|
|
72
|
+
{ "id": "send", "use": "@blokjs/respond", "inputs": { "status": 201, "body": "$.state.create" }, "ephemeral": true }
|
|
77
73
|
\`\`\`
|
|
78
|
-
- \`schedule\`: Standard cron expression
|
|
79
|
-
- \`timezone\`: IANA timezone name (default: "UTC")
|
|
80
|
-
- \`overlap\`: Allow overlapping executions (default: false)
|
|
81
74
|
|
|
82
|
-
|
|
75
|
+
## Trigger Types (exactly one)
|
|
76
|
+
|
|
77
|
+
### HTTP
|
|
83
78
|
\`\`\`json
|
|
84
|
-
"trigger": {
|
|
85
|
-
"webhook": {
|
|
86
|
-
"source": "github",
|
|
87
|
-
"events": ["push", "pull_request.*"],
|
|
88
|
-
"secret": "\${process.env.GITHUB_WEBHOOK_SECRET}",
|
|
89
|
-
"path": "/webhooks/github"
|
|
90
|
-
}
|
|
91
|
-
}
|
|
79
|
+
"trigger": { "http": { "method": "GET", "path": "/api/resource", "accept": "application/json" } }
|
|
92
80
|
\`\`\`
|
|
93
|
-
- \`
|
|
94
|
-
- \`
|
|
95
|
-
- \`secret\`: Webhook secret for signature verification
|
|
81
|
+
- \`method\`: "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "ANY" (use \`"ANY"\` for any method — NOT \`"*"\`).
|
|
82
|
+
- \`path\`: optional Express-style route (e.g. "/users/:id"). Omit to derive the URL from the file path.
|
|
96
83
|
|
|
97
|
-
###
|
|
84
|
+
### Worker (background jobs / queues)
|
|
98
85
|
\`\`\`json
|
|
99
|
-
"trigger": {
|
|
100
|
-
"websocket": {
|
|
101
|
-
"events": ["message", "join", "leave"],
|
|
102
|
-
"path": "/ws",
|
|
103
|
-
"maxConnections": 10000,
|
|
104
|
-
"heartbeatInterval": 30000
|
|
105
|
-
}
|
|
106
|
-
}
|
|
86
|
+
"trigger": { "worker": { "queue": "background-jobs", "provider": "nats", "concurrency": 5, "retries": 3 } }
|
|
107
87
|
\`\`\`
|
|
88
|
+
- This is the trigger for ANY queued / async / background work. **Never use a \`queue\` trigger — it is dead and throws at construction.**
|
|
89
|
+
- Job payload arrives as \`$.req.body\`; metadata as \`$.req.params.{queue,jobId,attempt}\`.
|
|
108
90
|
|
|
109
|
-
###
|
|
91
|
+
### Cron (scheduled)
|
|
110
92
|
\`\`\`json
|
|
111
|
-
"trigger": {
|
|
112
|
-
"sse": {
|
|
113
|
-
"events": ["update", "notification"],
|
|
114
|
-
"channels": ["feed", "alerts"],
|
|
115
|
-
"path": "/events",
|
|
116
|
-
"heartbeatInterval": 30000
|
|
117
|
-
}
|
|
118
|
-
}
|
|
93
|
+
"trigger": { "cron": { "schedule": "0 8 * * *", "timezone": "America/New_York", "overlap": false } }
|
|
119
94
|
\`\`\`
|
|
120
95
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
Steps are an ordered array of step objects:
|
|
124
|
-
|
|
96
|
+
### Webhook (signed provider callbacks)
|
|
125
97
|
\`\`\`json
|
|
126
|
-
"
|
|
127
|
-
{
|
|
128
|
-
"name": "step-key-name",
|
|
129
|
-
"node": "@blokjs/api-call",
|
|
130
|
-
"type": "module"
|
|
131
|
-
}
|
|
132
|
-
]
|
|
98
|
+
"trigger": { "webhook": { "source": "stripe", "events": ["payment_intent.succeeded"], "secret": "\${process.env.STRIPE_WEBHOOK_SECRET}", "path": "/webhooks/stripe" } }
|
|
133
99
|
\`\`\`
|
|
100
|
+
- \`source\`: "github" | "stripe" | "shopify" | "custom".
|
|
134
101
|
|
|
135
|
-
|
|
136
|
-
- \`node\`: Node package/module name (e.g., "@blokjs/api-call" for module types, or custom node names for local types)
|
|
137
|
-
- \`type\`: "module" (from node_modules), "local" (from src/nodes/), or "runtime.python3" (Python runtime)
|
|
138
|
-
|
|
139
|
-
## Nodes Configuration
|
|
140
|
-
|
|
141
|
-
Each step MUST have a corresponding entry in the \`nodes\` map.
|
|
142
|
-
|
|
143
|
-
### Simple Node (with inputs)
|
|
102
|
+
### Pub/Sub (cloud topics)
|
|
144
103
|
\`\`\`json
|
|
145
|
-
"
|
|
146
|
-
"step-name": {
|
|
147
|
-
"inputs": {
|
|
148
|
-
"url": "https://api.example.com/data",
|
|
149
|
-
"method": "GET",
|
|
150
|
-
"headers": { "Authorization": "Bearer \${ctx.env.API_KEY}" }
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
104
|
+
"trigger": { "pubsub": { "provider": "gcp", "topic": "user-notifications", "subscription": "notification-worker" } }
|
|
154
105
|
\`\`\`
|
|
155
106
|
|
|
156
|
-
###
|
|
107
|
+
### SSE (one-way live stream) / WebSocket (two-way realtime)
|
|
157
108
|
\`\`\`json
|
|
158
|
-
"
|
|
159
|
-
|
|
160
|
-
"conditions": [
|
|
161
|
-
{
|
|
162
|
-
"type": "if",
|
|
163
|
-
"condition": "ctx.request.method.toLowerCase() === \\"get\\" && ctx.request.params.function === undefined",
|
|
164
|
-
"steps": [
|
|
165
|
-
{ "name": "get-data", "node": "fetch-data", "type": "module" }
|
|
166
|
-
]
|
|
167
|
-
},
|
|
168
|
-
{
|
|
169
|
-
"type": "if",
|
|
170
|
-
"condition": "ctx.request.method.toLowerCase() === \\"post\\"",
|
|
171
|
-
"steps": [
|
|
172
|
-
{ "name": "create-data", "node": "save-data", "type": "module" }
|
|
173
|
-
]
|
|
174
|
-
},
|
|
175
|
-
{
|
|
176
|
-
"type": "else",
|
|
177
|
-
"steps": [
|
|
178
|
-
{ "name": "not-allowed", "node": "error", "type": "module" }
|
|
179
|
-
]
|
|
180
|
-
}
|
|
181
|
-
]
|
|
182
|
-
}
|
|
183
|
-
}
|
|
109
|
+
"trigger": { "sse": { "events": ["update"], "channels": ["feed"], "path": "/events" } }
|
|
110
|
+
"trigger": { "websocket": { "events": ["message"], "path": "/ws" } }
|
|
184
111
|
\`\`\`
|
|
185
112
|
|
|
186
|
-
## Input Value Patterns
|
|
187
|
-
|
|
188
|
-
Node inputs support these patterns:
|
|
189
|
-
|
|
190
|
-
1. **Static values**: Direct strings, numbers, objects, arrays
|
|
191
|
-
\`\`\`json
|
|
192
|
-
"message": "Hello World"
|
|
193
|
-
\`\`\`
|
|
194
|
-
|
|
195
|
-
2. **Context interpolation**: Use \${ctx.*} to read from the workflow context
|
|
196
|
-
\`\`\`json
|
|
197
|
-
"userId": "\${ctx.request.params.id}"
|
|
198
|
-
"query": "\${ctx.request.query.search}"
|
|
199
|
-
"body": "\${ctx.request.body}"
|
|
200
|
-
\`\`\`
|
|
201
|
-
|
|
202
|
-
3. **JavaScript expressions**: Prefix with "js/" for dynamic evaluation
|
|
203
|
-
\`\`\`json
|
|
204
|
-
"path": "js/process.env.DATA_PATH + '/files'"
|
|
205
|
-
"data": "js/ctx.response.data"
|
|
206
|
-
"value": "js/JSON.stringify(ctx.request.body)"
|
|
207
|
-
\`\`\`
|
|
208
|
-
|
|
209
|
-
4. **Previous node output**: Use ctx.vars to access outputs from previous steps
|
|
210
|
-
\`\`\`json
|
|
211
|
-
"input": "js/ctx.vars['previous-step-name']"
|
|
212
|
-
\`\`\`
|
|
213
|
-
|
|
214
|
-
## Context Properties Available in Conditions and Inputs
|
|
215
|
-
|
|
216
|
-
- \`ctx.request.method\`: HTTP method (GET, POST, etc.)
|
|
217
|
-
- \`ctx.request.params\`: URL path parameters (e.g., :id, :function)
|
|
218
|
-
- \`ctx.request.query\`: URL query parameters
|
|
219
|
-
- \`ctx.request.body\`: Request body
|
|
220
|
-
- \`ctx.request.headers\`: Request headers
|
|
221
|
-
- \`ctx.response.data\`: Current response data (set by previous nodes)
|
|
222
|
-
- \`ctx.vars['node-name']\`: Output from a specific previous node
|
|
223
|
-
- \`ctx.env.VARIABLE_NAME\`: Environment variables (via process.env)
|
|
224
|
-
- \`ctx.id\`: Unique request ID
|
|
225
|
-
- \`ctx.workflow_name\`: Workflow name
|
|
226
|
-
|
|
227
113
|
## Available Built-in Nodes
|
|
228
114
|
|
|
229
|
-
- \`@blokjs/api-call\`:
|
|
230
|
-
- \`@blokjs/
|
|
231
|
-
- \`@blokjs/react\`:
|
|
232
|
-
|
|
115
|
+
- \`@blokjs/api-call\`: HTTP requests (inputs: url, method, headers, body, responseType)
|
|
116
|
+
- \`@blokjs/respond\`: control the HTTP response (inputs: body, status, headers, cookies, contentType)
|
|
117
|
+
- \`@blokjs/react\`: server-side React rendering (inputs: template, props)
|
|
118
|
+
|
|
119
|
+
(For domain logic, reference a local node by name — e.g. \`"use": "validate-order"\` — and assume it exists or will be created.)
|
|
233
120
|
|
|
234
121
|
## Constraints
|
|
235
122
|
|
|
236
|
-
* The JSON MUST be valid and well-formed
|
|
237
|
-
* Every step
|
|
238
|
-
*
|
|
239
|
-
*
|
|
123
|
+
* The JSON MUST be valid and well-formed (2-space indentation, no trailing commas, no comments)
|
|
124
|
+
* Every step MUST have a unique \`id\` and a \`use\` (or a \`branch\`)
|
|
125
|
+
* Do NOT emit a \`nodes\` object, a \`conditions\` array, \`set_var\`, \`ctx.vars[...] =\`, or \`js/ctx.response\`
|
|
126
|
+
* Branch \`when\` MUST be a raw \`ctx.*\` expression (never \`js/\` or \`$.\`)
|
|
127
|
+
* Use \`"ANY"\` for the wildcard HTTP method (never \`"*"\`)
|
|
128
|
+
* Reference earlier outputs with \`"$.state.<id>"\` and request data with \`"$.req.*"\`
|
|
240
129
|
* The workflow MUST have exactly ONE trigger type
|
|
241
|
-
*
|
|
242
|
-
* Use descriptive step names in kebab-case (e.g., "fetch-user", "validate-input")
|
|
243
|
-
* Use descriptive workflow names
|
|
244
|
-
* Reference environment variables with ctx.env.VARIABLE_NAME (not process.env directly in inputs)
|
|
130
|
+
* Use descriptive kebab-case step ids (e.g. "fetch-user", "validate-input")
|
|
245
131
|
|
|
246
|
-
##
|
|
132
|
+
## Examples
|
|
247
133
|
|
|
248
|
-
### Example 1: Simple API
|
|
134
|
+
### Example 1: Simple API proxy
|
|
249
135
|
\`\`\`json
|
|
250
136
|
{
|
|
251
137
|
"name": "Country Data API",
|
|
252
|
-
"description": "Fetches country data from external API",
|
|
138
|
+
"description": "Fetches country data from an external API",
|
|
253
139
|
"version": "1.0.0",
|
|
254
|
-
"trigger": {
|
|
255
|
-
"http": {
|
|
256
|
-
"method": "GET",
|
|
257
|
-
"path": "/",
|
|
258
|
-
"accept": "application/json"
|
|
259
|
-
}
|
|
260
|
-
},
|
|
140
|
+
"trigger": { "http": { "method": "GET", "path": "/", "accept": "application/json" } },
|
|
261
141
|
"steps": [
|
|
262
|
-
{
|
|
263
|
-
"
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
}
|
|
267
|
-
],
|
|
268
|
-
"nodes": {
|
|
269
|
-
"get-countries": {
|
|
270
|
-
"inputs": {
|
|
271
|
-
"url": "https://countriesnow.space/api/v0.1/countries/capital",
|
|
272
|
-
"method": "GET",
|
|
273
|
-
"headers": { "Content-Type": "application/json" },
|
|
274
|
-
"responseType": "application/json"
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
}
|
|
142
|
+
{ "id": "get-countries", "use": "@blokjs/api-call",
|
|
143
|
+
"inputs": { "url": "https://countriesnow.space/api/v0.1/countries/capital", "method": "GET" } },
|
|
144
|
+
{ "id": "respond", "use": "@blokjs/respond", "inputs": { "body": "$.state.get-countries" }, "ephemeral": true }
|
|
145
|
+
]
|
|
278
146
|
}
|
|
279
147
|
\`\`\`
|
|
280
148
|
|
|
281
|
-
### Example 2:
|
|
149
|
+
### Example 2: Validate then route (branch)
|
|
282
150
|
\`\`\`json
|
|
283
151
|
{
|
|
284
|
-
"name": "
|
|
285
|
-
"description": "
|
|
152
|
+
"name": "Create Order",
|
|
153
|
+
"description": "Validates an order and routes by total",
|
|
286
154
|
"version": "1.0.0",
|
|
287
|
-
"trigger": {
|
|
288
|
-
"http": {
|
|
289
|
-
"method": "*",
|
|
290
|
-
"path": "/:function?/:id?",
|
|
291
|
-
"accept": "application/json"
|
|
292
|
-
}
|
|
293
|
-
},
|
|
155
|
+
"trigger": { "http": { "method": "POST", "path": "/orders" } },
|
|
294
156
|
"steps": [
|
|
295
|
-
{
|
|
296
|
-
|
|
297
|
-
"
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
"nodes": {
|
|
302
|
-
"filter-request": {
|
|
303
|
-
"conditions": [
|
|
304
|
-
{
|
|
305
|
-
"type": "if",
|
|
306
|
-
"condition": "ctx.request.method.toLowerCase() === \\"get\\" && ctx.request.params.function === ''",
|
|
307
|
-
"steps": [
|
|
308
|
-
{ "name": "list-view", "node": "feedback-ui", "type": "module" }
|
|
309
|
-
]
|
|
310
|
-
},
|
|
311
|
-
{
|
|
312
|
-
"type": "if",
|
|
313
|
-
"condition": "ctx.request.method.toLowerCase() === \\"post\\" && ctx.request.params.function === \\"create\\"",
|
|
314
|
-
"steps": [
|
|
315
|
-
{ "name": "process-data", "node": "data-processor", "type": "module" },
|
|
316
|
-
{ "name": "save-data", "node": "storage", "type": "module" }
|
|
317
|
-
]
|
|
318
|
-
},
|
|
319
|
-
{
|
|
320
|
-
"type": "if",
|
|
321
|
-
"condition": "ctx.request.method.toLowerCase() === \\"get\\" && ctx.request.params.function === \\"all\\"",
|
|
322
|
-
"steps": [
|
|
323
|
-
{ "name": "get-all", "node": "storage", "type": "module" }
|
|
324
|
-
]
|
|
325
|
-
},
|
|
326
|
-
{
|
|
327
|
-
"type": "else",
|
|
328
|
-
"steps": [
|
|
329
|
-
{ "name": "not-allowed", "node": "error", "type": "module" }
|
|
330
|
-
]
|
|
331
|
-
}
|
|
332
|
-
]
|
|
333
|
-
},
|
|
334
|
-
"list-view": { "inputs": {} },
|
|
335
|
-
"process-data": {
|
|
336
|
-
"inputs": {
|
|
337
|
-
"id": "\${ctx.request.body.id}",
|
|
338
|
-
"data": "\${ctx.request.body}"
|
|
157
|
+
{ "id": "validate", "use": "order-validator", "inputs": { "order": "$.req.body" } },
|
|
158
|
+
{ "id": "route",
|
|
159
|
+
"branch": {
|
|
160
|
+
"when": "ctx.state.validate.total > 100",
|
|
161
|
+
"then": [{ "id": "vip-save", "use": "order-store", "inputs": { "data": "$.state.validate", "tier": "vip" } }],
|
|
162
|
+
"else": [{ "id": "std-save", "use": "order-store", "inputs": { "data": "$.state.validate", "tier": "std" } }]
|
|
339
163
|
}
|
|
340
|
-
},
|
|
341
|
-
"save-data": {
|
|
342
|
-
"inputs": {
|
|
343
|
-
"action": "set",
|
|
344
|
-
"key": "\${ctx.request.body.id}",
|
|
345
|
-
"value": "js/ctx.response.data"
|
|
346
|
-
}
|
|
347
|
-
},
|
|
348
|
-
"get-all": {
|
|
349
|
-
"inputs": { "action": "get-all" }
|
|
350
164
|
}
|
|
351
|
-
|
|
165
|
+
]
|
|
352
166
|
}
|
|
353
167
|
\`\`\`
|
|
354
168
|
|
|
355
|
-
### Example 3:
|
|
169
|
+
### Example 3: Worker (background job)
|
|
356
170
|
\`\`\`json
|
|
357
171
|
{
|
|
358
|
-
"name": "
|
|
359
|
-
"description": "Processes
|
|
172
|
+
"name": "Process Upload Job",
|
|
173
|
+
"description": "Processes an uploaded file from the queue",
|
|
360
174
|
"version": "1.0.0",
|
|
361
|
-
"trigger": {
|
|
362
|
-
"queue": {
|
|
363
|
-
"provider": "kafka",
|
|
364
|
-
"topic": "user-events",
|
|
365
|
-
"consumerGroup": "event-processor",
|
|
366
|
-
"ack": true
|
|
367
|
-
}
|
|
368
|
-
},
|
|
175
|
+
"trigger": { "worker": { "queue": "uploads", "provider": "nats", "retries": 3 } },
|
|
369
176
|
"steps": [
|
|
370
|
-
{
|
|
371
|
-
|
|
372
|
-
"
|
|
373
|
-
|
|
374
|
-
},
|
|
375
|
-
{
|
|
376
|
-
"name": "notify-user",
|
|
377
|
-
"node": "@blokjs/api-call",
|
|
378
|
-
"type": "module"
|
|
379
|
-
}
|
|
380
|
-
],
|
|
381
|
-
"nodes": {
|
|
382
|
-
"process-event": {
|
|
383
|
-
"inputs": {
|
|
384
|
-
"eventType": "\${ctx.request.body.type}",
|
|
385
|
-
"payload": "\${ctx.request.body.data}"
|
|
386
|
-
}
|
|
387
|
-
},
|
|
388
|
-
"notify-user": {
|
|
389
|
-
"inputs": {
|
|
390
|
-
"url": "https://api.notifications.com/send",
|
|
391
|
-
"method": "POST",
|
|
392
|
-
"headers": { "Authorization": "Bearer \${ctx.env.NOTIFICATION_API_KEY}" },
|
|
393
|
-
"body": "js/ctx.vars['process-event']"
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
\`\`\`
|
|
399
|
-
|
|
400
|
-
### Example 4: Cron-Triggered Workflow
|
|
401
|
-
\`\`\`json
|
|
402
|
-
{
|
|
403
|
-
"name": "Daily Report Generator",
|
|
404
|
-
"description": "Generates and emails daily reports every morning",
|
|
405
|
-
"version": "1.0.0",
|
|
406
|
-
"trigger": {
|
|
407
|
-
"cron": {
|
|
408
|
-
"schedule": "0 8 * * *",
|
|
409
|
-
"timezone": "America/New_York",
|
|
410
|
-
"overlap": false
|
|
411
|
-
}
|
|
412
|
-
},
|
|
413
|
-
"steps": [
|
|
414
|
-
{
|
|
415
|
-
"name": "fetch-metrics",
|
|
416
|
-
"node": "@blokjs/api-call",
|
|
417
|
-
"type": "module"
|
|
418
|
-
},
|
|
419
|
-
{
|
|
420
|
-
"name": "generate-report",
|
|
421
|
-
"node": "report-generator",
|
|
422
|
-
"type": "module"
|
|
423
|
-
}
|
|
424
|
-
],
|
|
425
|
-
"nodes": {
|
|
426
|
-
"fetch-metrics": {
|
|
427
|
-
"inputs": {
|
|
428
|
-
"url": "\${ctx.env.METRICS_API_URL}",
|
|
429
|
-
"method": "GET",
|
|
430
|
-
"headers": { "Authorization": "Bearer \${ctx.env.METRICS_API_KEY}" }
|
|
431
|
-
}
|
|
432
|
-
},
|
|
433
|
-
"generate-report": {
|
|
434
|
-
"inputs": {
|
|
435
|
-
"data": "js/ctx.vars['fetch-metrics']",
|
|
436
|
-
"format": "html",
|
|
437
|
-
"recipients": ["admin@example.com"]
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
}
|
|
177
|
+
{ "id": "process", "use": "file-processor", "inputs": { "payload": "$.req.body", "jobId": "$.req.params.jobId" } },
|
|
178
|
+
{ "id": "notify", "use": "@blokjs/api-call",
|
|
179
|
+
"inputs": { "url": "https://hooks.example.com/done", "method": "POST", "body": "$.state.process" } }
|
|
180
|
+
]
|
|
441
181
|
}
|
|
442
182
|
\`\`\`
|
|
443
183
|
|
|
@@ -448,22 +188,21 @@ Node inputs support these patterns:
|
|
|
448
188
|
* Use 2-space indentation
|
|
449
189
|
* All string values must be properly escaped
|
|
450
190
|
* No trailing commas`,
|
|
451
|
-
updatePrompt: `You are a senior backend engineer specializing in the Blok (blok) workflow framework. Your task is to update an existing workflow JSON configuration with new functionality while preserving its core structure.
|
|
191
|
+
updatePrompt: `You are a senior backend engineer specializing in the Blok (blok) workflow framework. Your task is to update an existing v2 workflow JSON configuration with new functionality while preserving its core structure.
|
|
452
192
|
|
|
453
193
|
Given the existing workflow JSON below, enhance or modify it according to the user's requirements while maintaining:
|
|
454
194
|
|
|
455
|
-
1. Valid JSON structure
|
|
456
|
-
2. Consistent trigger configuration
|
|
457
|
-
3.
|
|
458
|
-
4.
|
|
459
|
-
5.
|
|
195
|
+
1. Valid v2 JSON structure: name, description, version, trigger, steps (inline inputs, NO nodes map)
|
|
196
|
+
2. Consistent trigger configuration (exactly one trigger type)
|
|
197
|
+
3. Unique \`id\` on every step (flat across branch arms)
|
|
198
|
+
4. Branch conditions as raw \`ctx.*\` expressions (never \`js/\` or \`$.\`)
|
|
199
|
+
5. References via \`"$.state.<id>"\` / \`"$.req.*"\` and persistence knobs (\`as\`/\`spread\`/\`ephemeral\`)
|
|
460
200
|
|
|
461
201
|
What to return:
|
|
462
202
|
* Return only the full updated workflow JSON
|
|
463
203
|
* Preserve existing functionality unless explicitly asked to change it
|
|
464
204
|
* Add new functionality as requested
|
|
465
|
-
*
|
|
466
|
-
* Keep input patterns comprehensive and accurate
|
|
205
|
+
* If the input is an old v1 workflow (\`name\`/\`node\` + a \`nodes{}\` map), MIGRATE it to v2 (\`id\`/\`use\` + inline \`inputs\`, no nodes map)
|
|
467
206
|
|
|
468
207
|
Format:
|
|
469
208
|
* No explanations or comments outside the JSON
|