@pikku/cli 0.12.54 → 0.12.56

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.
Files changed (267) hide show
  1. package/cli.schema.json +1 -1
  2. package/console-app/assets/{index-DYnbceYg.js → index-xN8LW0II.js} +155 -155
  3. package/console-app/index.html +1 -1
  4. package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +1 -1
  5. package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +3 -3
  6. package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
  7. package/dist/.pikku/cli/pikku-cli-channel.d.ts +6 -6
  8. package/dist/.pikku/cli/pikku-cli-channel.js +11 -1
  9. package/dist/.pikku/cli/pikku-cli-client.gen.d.ts +1 -1
  10. package/dist/.pikku/cli/pikku-cli-client.gen.js +1 -1
  11. package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.d.ts +1 -1
  12. package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.js +1 -1
  13. package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.json +14 -0
  14. package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
  15. package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
  16. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
  17. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.json +29 -0
  18. package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
  19. package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
  20. package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
  21. package/dist/.pikku/cli/pikku-cli.gen.js +1 -1
  22. package/dist/.pikku/console/pikku-node-types.gen.d.ts +1 -1
  23. package/dist/.pikku/function/pikku-function-types.gen.d.ts +8 -31
  24. package/dist/.pikku/function/pikku-function-types.gen.js +1 -1
  25. package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
  26. package/dist/.pikku/function/pikku-functions-meta.gen.json +1420 -1384
  27. package/dist/.pikku/function/pikku-functions.gen.js +3 -1
  28. package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
  29. package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
  30. package/dist/.pikku/http/pikku-http-wirings-meta.gen.js +1 -1
  31. package/dist/.pikku/http/pikku-http-wirings.gen.d.ts +1 -1
  32. package/dist/.pikku/http/pikku-http-wirings.gen.js +1 -1
  33. package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
  34. package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
  35. package/dist/.pikku/pikku-bootstrap.gen.d.ts +1 -1
  36. package/dist/.pikku/pikku-bootstrap.gen.js +1 -1
  37. package/dist/.pikku/pikku-meta-service.gen.d.ts +1 -1
  38. package/dist/.pikku/pikku-meta-service.gen.js +1 -1
  39. package/dist/.pikku/pikku-services.gen.d.ts +4 -2
  40. package/dist/.pikku/pikku-services.gen.js +2 -0
  41. package/dist/.pikku/pikku-types.gen.d.ts +1 -1
  42. package/dist/.pikku/pikku-types.gen.js +1 -1
  43. package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
  44. package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
  45. package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.js +1 -1
  46. package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.json +0 -248
  47. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.d.ts +1 -1
  48. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.js +1 -1
  49. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
  50. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.json +69 -67
  51. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
  52. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
  53. package/dist/.pikku/schemas/register.gen.js +191 -185
  54. package/dist/.pikku/schemas/schemas/FabricAddonVerifyInput.schema.json +1 -0
  55. package/dist/.pikku/schemas/schemas/FabricAddonVerifyOutput.schema.json +1 -0
  56. package/dist/.pikku/schemas/schemas/PikkuAuthInput.schema.json +1 -0
  57. package/dist/.pikku/schemas/schemas/PikkuCLIConfig.schema.json +1 -1
  58. package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +1 -1
  59. package/dist/.pikku/secrets/pikku-secret-types.gen.js +1 -1
  60. package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
  61. package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
  62. package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
  63. package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
  64. package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +1 -1
  65. package/dist/.pikku/variables/pikku-variable-types.gen.js +1 -1
  66. package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
  67. package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
  68. package/dist/.pikku/workflow/meta/allWorkflow.gen.json +9 -3
  69. package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +1 -1
  70. package/dist/.pikku/workflow/pikku-workflow-types.gen.js +1 -1
  71. package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
  72. package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
  73. package/dist/bin/pikku-bin.mjs +2 -2
  74. package/dist/src/cli.wiring.js +15 -1
  75. package/dist/src/deploy/analyzer/analyzer.d.ts +6 -0
  76. package/dist/src/deploy/analyzer/analyzer.js +5 -4
  77. package/dist/src/deploy/build-pipeline.d.ts +5 -1
  78. package/dist/src/deploy/build-pipeline.js +5 -5
  79. package/dist/src/deploy/bundler/bun-bundler.d.ts +14 -0
  80. package/dist/src/deploy/bundler/bun-bundler.js +121 -0
  81. package/dist/src/deploy/bundler/bundler.d.ts +25 -30
  82. package/dist/src/deploy/bundler/bundler.interface.d.ts +54 -0
  83. package/dist/src/deploy/bundler/bundler.interface.js +11 -0
  84. package/dist/src/deploy/bundler/bundler.js +120 -190
  85. package/dist/src/deploy/bundler/dep-extractor.d.ts +11 -3
  86. package/dist/src/deploy/bundler/dep-extractor.js +12 -6
  87. package/dist/src/deploy/bundler/index.d.ts +5 -2
  88. package/dist/src/deploy/bundler/index.js +4 -2
  89. package/dist/src/deploy/bundler/node-bundler.d.ts +13 -0
  90. package/dist/src/deploy/bundler/node-bundler.js +80 -0
  91. package/dist/src/deploy/provider-adapter.d.ts +11 -0
  92. package/dist/src/deploy/server-entry.js +3 -1
  93. package/dist/src/fabric/fabric-commands.d.ts +109 -72
  94. package/dist/src/fabric/fabric-commands.js +8 -0
  95. package/dist/src/fabric/functions/add.function.d.ts +3 -3
  96. package/dist/src/fabric/functions/addon-verify.function.d.ts +54 -0
  97. package/dist/src/fabric/functions/addon-verify.function.js +153 -0
  98. package/dist/src/fabric/functions/db-schema.function.d.ts +3 -3
  99. package/dist/src/fabric/functions/deploy-list.function.d.ts +3 -3
  100. package/dist/src/fabric/functions/deploy-units.function.d.ts +3 -3
  101. package/dist/src/fabric/functions/deploy.function.d.ts +6 -6
  102. package/dist/src/fabric/functions/domains-add.function.d.ts +3 -3
  103. package/dist/src/fabric/functions/domains-list.function.d.ts +3 -3
  104. package/dist/src/fabric/functions/domains-remove.function.d.ts +3 -3
  105. package/dist/src/fabric/functions/errors.function.d.ts +3 -3
  106. package/dist/src/fabric/functions/init.function.d.ts +3 -3
  107. package/dist/src/fabric/functions/link.function.d.ts +3 -3
  108. package/dist/src/fabric/functions/llm-key.function.d.ts +3 -3
  109. package/dist/src/fabric/functions/llm-key.function.js +1 -1
  110. package/dist/src/fabric/functions/login.function.d.ts +3 -3
  111. package/dist/src/fabric/functions/logs.function.d.ts +3 -3
  112. package/dist/src/fabric/functions/metrics.function.d.ts +3 -3
  113. package/dist/src/fabric/functions/publish.function.d.ts +3 -3
  114. package/dist/src/fabric/functions/publish.function.js +8 -3
  115. package/dist/src/fabric/functions/rollback.function.d.ts +3 -3
  116. package/dist/src/fabric/functions/secrets-list.function.d.ts +3 -3
  117. package/dist/src/fabric/functions/secrets-set.function.d.ts +3 -3
  118. package/dist/src/fabric/functions/smoke.function.d.ts +3 -3
  119. package/dist/src/fabric/functions/status.function.d.ts +3 -3
  120. package/dist/src/fabric/functions/trace.function.d.ts +3 -3
  121. package/dist/src/fabric/functions/validate.function.d.ts +3 -3
  122. package/dist/src/functions/commands/all.d.ts +1 -1
  123. package/dist/src/functions/commands/all.js +19 -2
  124. package/dist/src/functions/commands/binary.d.ts +3 -3
  125. package/dist/src/functions/commands/bootstrap.d.ts +1 -1
  126. package/dist/src/functions/commands/bootstrap.js +3 -0
  127. package/dist/src/functions/commands/console.d.ts +3 -3
  128. package/dist/src/functions/commands/db-audit.d.ts +1 -1
  129. package/dist/src/functions/commands/db-generate.d.ts +1 -1
  130. package/dist/src/functions/commands/db-migrate.d.ts +1 -1
  131. package/dist/src/functions/commands/db-reset.d.ts +1 -1
  132. package/dist/src/functions/commands/db-seed.d.ts +1 -1
  133. package/dist/src/functions/commands/deploy-apply.d.ts +3 -3
  134. package/dist/src/functions/commands/deploy-apply.js +32 -1
  135. package/dist/src/functions/commands/deploy-info.d.ts +1 -1
  136. package/dist/src/functions/commands/deploy-plan.d.ts +3 -3
  137. package/dist/src/functions/commands/deploy-plan.js +3 -1
  138. package/dist/src/functions/commands/dev.d.ts +3 -3
  139. package/dist/src/functions/commands/dev.js +17 -45
  140. package/dist/src/functions/commands/emails-init.d.ts +1 -1
  141. package/dist/src/functions/commands/enable.d.ts +6 -5
  142. package/dist/src/functions/commands/enable.js +4 -0
  143. package/dist/src/functions/commands/info.d.ts +4 -4
  144. package/dist/src/functions/commands/login.d.ts +7 -7
  145. package/dist/src/functions/commands/meta.d.ts +31 -31
  146. package/dist/src/functions/commands/new-addon.d.ts +3 -3
  147. package/dist/src/functions/commands/new-function.d.ts +3 -3
  148. package/dist/src/functions/commands/new-middleware.d.ts +3 -3
  149. package/dist/src/functions/commands/new-permission.d.ts +3 -3
  150. package/dist/src/functions/commands/new-wiring.d.ts +3 -3
  151. package/dist/src/functions/commands/pikku-command-bootstrap.d.ts +1 -1
  152. package/dist/src/functions/commands/pikku-command-summary.d.ts +1 -1
  153. package/dist/src/functions/commands/pikku-command-summary.js +6 -1
  154. package/dist/src/functions/commands/skills.d.ts +6 -6
  155. package/dist/src/functions/commands/tests-coverage.d.ts +3 -3
  156. package/dist/src/functions/commands/tests-init.d.ts +3 -3
  157. package/dist/src/functions/commands/versions-check.d.ts +1 -1
  158. package/dist/src/functions/commands/versions-init.d.ts +3 -3
  159. package/dist/src/functions/commands/versions-update.d.ts +1 -1
  160. package/dist/src/functions/commands/watch.d.ts +3 -3
  161. package/dist/src/functions/commands/workspace-validate.d.ts +3 -3
  162. package/dist/src/functions/db/db-codegen.js +14 -0
  163. package/dist/src/functions/db/sqlite/sqlite-runtime-bun.js +10 -0
  164. package/dist/src/functions/runtimes/fetch/index.d.ts +1 -1
  165. package/dist/src/functions/runtimes/nextjs/pikku-command-nextjs.d.ts +1 -1
  166. package/dist/src/functions/runtimes/tanstack-start/pikku-command-tanstack-start.d.ts +1 -1
  167. package/dist/src/functions/runtimes/websocket/pikku-command-websocket-typed.d.ts +1 -1
  168. package/dist/src/functions/wirings/ai-agent/pikku-command-ai-agent-types.d.ts +1 -1
  169. package/dist/src/functions/wirings/ai-agent/pikku-command-ai-agent.d.ts +1 -1
  170. package/dist/src/functions/wirings/ai-agent/pikku-command-public-agent.d.ts +1 -1
  171. package/dist/src/functions/wirings/auth/pikku-command-auth.d.ts +7 -1
  172. package/dist/src/functions/wirings/auth/pikku-command-auth.js +14 -2
  173. package/dist/src/functions/wirings/auth/serialize-auth-types.d.ts +10 -0
  174. package/dist/src/functions/wirings/auth/serialize-auth-types.js +15 -0
  175. package/dist/src/functions/wirings/channels/pikku-channels.d.ts +1 -1
  176. package/dist/src/functions/wirings/channels/pikku-command-channel-types.d.ts +1 -1
  177. package/dist/src/functions/wirings/channels/pikku-command-channels-map.d.ts +1 -1
  178. package/dist/src/functions/wirings/channels/pikku-command-channels.d.ts +1 -1
  179. package/dist/src/functions/wirings/cli/pikku-command-cli-entry.d.ts +1 -1
  180. package/dist/src/functions/wirings/cli/pikku-command-cli-types.d.ts +1 -1
  181. package/dist/src/functions/wirings/cli/pikku-command-cli.d.ts +1 -1
  182. package/dist/src/functions/wirings/console/pikku-command-console-functions.d.ts +1 -1
  183. package/dist/src/functions/wirings/console/pikku-command-node-types.d.ts +1 -1
  184. package/dist/src/functions/wirings/console/pikku-command-nodes-meta.d.ts +1 -1
  185. package/dist/src/functions/wirings/credentials/pikku-command-credentials.d.ts +1 -1
  186. package/dist/src/functions/wirings/emails/pikku-command-emails.d.ts +1 -1
  187. package/dist/src/functions/wirings/functions/pikku-command-addon-types.d.ts +1 -1
  188. package/dist/src/functions/wirings/functions/pikku-command-function-types-split.d.ts +3 -3
  189. package/dist/src/functions/wirings/functions/pikku-command-function-types.d.ts +3 -3
  190. package/dist/src/functions/wirings/functions/pikku-command-function-types.js +10 -3
  191. package/dist/src/functions/wirings/functions/pikku-command-functions.d.ts +1 -1
  192. package/dist/src/functions/wirings/functions/pikku-command-services.d.ts +1 -1
  193. package/dist/src/functions/wirings/functions/schemas.d.ts +1 -1
  194. package/dist/src/functions/wirings/functions/serialize-function-types.js +6 -29
  195. package/dist/src/functions/wirings/gateway/pikku-command-gateway.d.ts +1 -1
  196. package/dist/src/functions/wirings/http/pikku-command-http-map.d.ts +1 -1
  197. package/dist/src/functions/wirings/http/pikku-command-http-routes.d.ts +1 -1
  198. package/dist/src/functions/wirings/http/pikku-command-http-types.d.ts +1 -1
  199. package/dist/src/functions/wirings/http/pikku-command-openapi.d.ts +1 -1
  200. package/dist/src/functions/wirings/http/pikku-http-routes.d.ts +1 -1
  201. package/dist/src/functions/wirings/mcp/pikku-command-mcp-json.d.ts +1 -1
  202. package/dist/src/functions/wirings/mcp/pikku-command-mcp-types.d.ts +1 -1
  203. package/dist/src/functions/wirings/mcp/pikku-command-mcp.d.ts +1 -1
  204. package/dist/src/functions/wirings/middleware/pikku-command-middleware.d.ts +1 -1
  205. package/dist/src/functions/wirings/package/pikku-command-package-types.d.ts +2 -2
  206. package/dist/src/functions/wirings/package/pikku-command-package.d.ts +1 -1
  207. package/dist/src/functions/wirings/permissions/pikku-command-permissions.d.ts +1 -1
  208. package/dist/src/functions/wirings/queue/pikku-command-queue-map.d.ts +1 -1
  209. package/dist/src/functions/wirings/queue/pikku-command-queue-service.d.ts +1 -1
  210. package/dist/src/functions/wirings/queue/pikku-command-queue-types.d.ts +1 -1
  211. package/dist/src/functions/wirings/queue/pikku-command-queue.d.ts +1 -1
  212. package/dist/src/functions/wirings/queue/pikku-queue-map.d.ts +1 -1
  213. package/dist/src/functions/wirings/queue/pikku-queue.d.ts +1 -1
  214. package/dist/src/functions/wirings/realtime/pikku-command-events-scaffold.d.ts +1 -1
  215. package/dist/src/functions/wirings/realtime/pikku-command-realtime.d.ts +1 -1
  216. package/dist/src/functions/wirings/rpc/pikku-command-public-rpc.d.ts +1 -1
  217. package/dist/src/functions/wirings/rpc/pikku-command-react-query.d.ts +1 -1
  218. package/dist/src/functions/wirings/rpc/pikku-command-remote-rpc.d.ts +1 -1
  219. package/dist/src/functions/wirings/rpc/pikku-command-rpc-client.d.ts +1 -1
  220. package/dist/src/functions/wirings/rpc/pikku-command-rpc-map.d.ts +2 -2
  221. package/dist/src/functions/wirings/rpc/pikku-command-rpc.d.ts +1 -1
  222. package/dist/src/functions/wirings/scheduler/pikku-command-scheduler-types.d.ts +1 -1
  223. package/dist/src/functions/wirings/scheduler/pikku-command-scheduler.d.ts +1 -1
  224. package/dist/src/functions/wirings/secrets/pikku-command-secrets.d.ts +1 -1
  225. package/dist/src/functions/wirings/triggers/pikku-command-trigger-types.d.ts +3 -3
  226. package/dist/src/functions/wirings/triggers/pikku-command-trigger.d.ts +1 -1
  227. package/dist/src/functions/wirings/variables/pikku-command-variables.d.ts +1 -1
  228. package/dist/src/functions/wirings/workflow/pikku-command-workflow-routes.d.ts +1 -1
  229. package/dist/src/functions/wirings/workflow/pikku-command-workflow.d.ts +1 -1
  230. package/dist/src/functions/workflows/all.workflow.js +6 -1
  231. package/dist/src/scaffold/rpc-remote.gen.d.ts +3 -3
  232. package/dist/src/scaffold/rpc-remote.gen.js +1 -1
  233. package/dist/src/server/bun-server-runner.d.ts +17 -0
  234. package/dist/src/server/bun-server-runner.js +25 -0
  235. package/dist/src/server/dev-server-runner.interface.d.ts +31 -0
  236. package/dist/src/server/dev-server-runner.interface.js +11 -0
  237. package/dist/src/server/node-server-runner.d.ts +12 -0
  238. package/dist/src/server/node-server-runner.js +30 -0
  239. package/dist/src/services/cli-logger.service.js +7 -1
  240. package/dist/src/services.js +18 -0
  241. package/dist/src/utils/detect-better-auth.d.ts +7 -0
  242. package/dist/src/utils/detect-better-auth.js +29 -0
  243. package/dist/src/utils/parse-cli-filters.d.ts +1 -0
  244. package/dist/src/utils/parse-cli-filters.js +1 -0
  245. package/dist/src/utils/pikku-cli-config.js +1 -1
  246. package/dist/src/utils/serialize-schemas.js +5 -1
  247. package/dist/tsconfig.tsbuildinfo +1 -1
  248. package/package.json +4 -4
  249. package/skills/pikku-addon/SKILL.md +25 -117
  250. package/skills/pikku-addon/references/addon-package-manifest.md +63 -0
  251. package/skills/pikku-cli/SKILL.md +7 -93
  252. package/skills/pikku-cli/references/complete-example.md +82 -0
  253. package/skills/pikku-concepts/SKILL.md +17 -69
  254. package/skills/pikku-concepts/references/concept-mapping.md +37 -13
  255. package/skills/pikku-concepts/references/packages.md +29 -0
  256. package/skills/pikku-http/SKILL.md +14 -105
  257. package/skills/pikku-http/references/http-options.md +57 -0
  258. package/skills/pikku-middleware/SKILL.md +11 -68
  259. package/skills/pikku-middleware/references/middleware-patterns.md +61 -0
  260. package/skills/pikku-realtime/SKILL.md +56 -105
  261. package/skills/pikku-realtime/references/other-routes.md +23 -0
  262. package/skills/pikku-services/SKILL.md +25 -108
  263. package/skills/pikku-services/references/audit-wire-service.md +34 -0
  264. package/skills/pikku-testing/SKILL.md +51 -359
  265. package/skills/pikku-testing/references/cucumber-bdd-testing.md +176 -0
  266. package/skills/pikku-workflow/SKILL.md +93 -259
  267. package/skills/pikku-workflow/references/workflow-reference.md +63 -0
@@ -0,0 +1,176 @@
1
+ # Cucumber / BDD Testing with `@pikku/cucumber`
2
+
3
+ ## Personas and Named Data — Never Inline JSON
4
+
5
+ **Never put JSON, inline tables, or raw values inside `.feature` files.** Feature files are for human-readable scenarios; all test data belongs in typed maps that step definitions look up by name.
6
+
7
+ `@pikku/cucumber` exports `PersonaData<T>` — a typed map that throws a clear error when a name is missing.
8
+
9
+ ### Personas
10
+
11
+ A **persona** is a named user: login credentials plus the session held after authenticating. Define all personas in one file:
12
+
13
+ ```ts
14
+ // tests/tests/support/personas.ts
15
+ import { PersonaData } from '@pikku/cucumber'
16
+
17
+ export const logins = new PersonaData({
18
+ yasser: { email: 'yasser@example.com', password: 'hunter2' },
19
+ guest: { email: 'guest@example.com', password: 'guest123' },
20
+ })
21
+ ```
22
+
23
+ A persona step logs in and stores the session in the world so every subsequent call by that persona carries it automatically:
24
+
25
+ ```ts
26
+ // tests/tests/support/steps/auth.steps.ts
27
+ import { Given } from '@cucumber/cucumber'
28
+ import { logins } from '../personas.js'
29
+
30
+ Given('{string} logs in', async function (name: string) {
31
+ await this.call(name, 'auth:login', logins.get(name))
32
+ const { token } = this.lastResult as { token: string }
33
+ this.setSession(name, { token })
34
+ })
35
+ ```
36
+
37
+ ### Named Domain Data
38
+
39
+ Use a separate `PersonaData` map per domain concept. Name entries after real-world meaning, not technical fields:
40
+
41
+ ```ts
42
+ // tests/tests/support/data/cards.ts
43
+ import { PersonaData } from '@pikku/cucumber'
44
+
45
+ export const cards = new PersonaData({
46
+ 'writing a blog post': { title: 'Writing a blog post', columnId: 'backlog' },
47
+ 'fix the login bug': { title: 'Fix the login bug', columnId: 'in-progress' },
48
+ })
49
+ ```
50
+
51
+ Steps resolve the name and make the call — the feature file never sees raw data:
52
+
53
+ ```ts
54
+ // tests/tests/support/steps/card.steps.ts
55
+ import { When, Then } from '@cucumber/cucumber'
56
+ import assert from 'node:assert/strict'
57
+ import { cards } from '../data/cards.js'
58
+
59
+ When('{string} creates a card for {string}', async function (persona: string, cardName: string) {
60
+ await this.call(persona, 'kanban:createCard', cards.get(cardName))
61
+ })
62
+
63
+ When('{string} gets the card {string}', async function (persona: string, cardName: string) {
64
+ const { title } = cards.get(cardName)
65
+ await this.call(persona, 'kanban:getCard', { title })
66
+ })
67
+
68
+ // "the newly created card" — checks the live result against the data map entry
69
+ // AND any server-assigned fields (id, createdAt) are present
70
+ Then('the result is the newly created card {string}', function (cardName: string) {
71
+ const expected = cards.get(cardName)
72
+ const result = this.lastResult as typeof expected & { id: string; createdAt: string }
73
+ assert.equal(result.title, expected.title)
74
+ assert.equal(result.columnId, expected.columnId)
75
+ assert.ok(result.id, 'expected server-assigned id')
76
+ assert.ok(result.createdAt, 'expected server-assigned createdAt')
77
+ })
78
+ ```
79
+
80
+ The feature file reads naturally:
81
+
82
+ ```gherkin
83
+ Feature: Card management
84
+
85
+ Scenario: Create and retrieve a card
86
+ Given 'yasser' logs in
87
+ When 'yasser' creates a card for 'writing a blog post'
88
+ And 'yasser' gets the card 'writing a blog post'
89
+ Then the result is the newly created card 'writing a blog post'
90
+ ```
91
+
92
+ ### File layout
93
+
94
+ ```
95
+ tests/tests/support/
96
+ personas.ts ← logins PersonaData (one per project)
97
+ data/
98
+ cards.ts ← cards PersonaData
99
+ users.ts ← users PersonaData
100
+ steps/
101
+ auth.steps.ts ← login / logout steps
102
+ card.steps.ts ← card CRUD steps
103
+ ```
104
+
105
+ Keep one `PersonaData` instance per domain concept. Steps import only what they need — no cross-domain coupling.
106
+
107
+ ## Anti-Patterns
108
+
109
+ ### Inline data in feature files
110
+
111
+ Raw values/JSON in `.feature` files make scenarios brittle and unreadable. Use named references resolved by step definitions instead.
112
+
113
+ ```gherkin
114
+ # Wrong
115
+ When I call 'kanban:createCard' with {"title": "My card", "columnId": "backlog"}
116
+ Then the result title is "My card"
117
+
118
+ # Right
119
+ When 'yasser' creates a card for 'writing a blog post'
120
+ Then the result is the newly created card 'writing a blog post'
121
+ ```
122
+
123
+ ### Feature-coupled step definitions
124
+
125
+ Steps tied to one feature can't be reused and cause duplication. Organise by **domain concept**, not by feature. Name step files after the domain they cover — a login step belongs in `auth.steps.ts` regardless of which feature needs it.
126
+
127
+ ```
128
+ Wrong: Right:
129
+ steps/ steps/
130
+ edit_work_experience.ts auth.steps.ts
131
+ edit_languages.ts profile.steps.ts
132
+ edit_education.ts card.steps.ts
133
+ ```
134
+
135
+ ### Conjunction steps
136
+
137
+ Don't combine multiple actions into a single step — it makes reuse impossible. Use `And` / `But`: each step does exactly one thing.
138
+
139
+ ```gherkin
140
+ # Wrong — two actions in one step
141
+ Given 'yasser' is logged in and has created a card
142
+
143
+ # Right — atomic, composable
144
+ Given 'yasser' logs in
145
+ And 'yasser' creates a card for 'writing a blog post'
146
+ ```
147
+
148
+ ### Asserting in When steps
149
+
150
+ `When` steps perform actions; `Then` steps assert outcomes. Mixing them hides intent.
151
+
152
+ ```gherkin
153
+ # Wrong
154
+ When 'yasser' creates a card and the title is 'writing a blog post'
155
+
156
+ # Right
157
+ When 'yasser' creates a card for 'writing a blog post'
158
+ Then the call succeeds
159
+ ```
160
+
161
+ ### Hard-coding persona data in step definitions
162
+
163
+ Credentials/test inputs embedded in step code can't be reused and break when data changes — look them up from `PersonaData`.
164
+
165
+ ```ts
166
+ // Wrong
167
+ Given('{string} logs in', async function (name: string) {
168
+ await this.call(name, 'auth:login', { email: 'yasser@example.com', password: 'hunter2' })
169
+ })
170
+
171
+ // Right
172
+ Given('{string} logs in', async function (name: string) {
173
+ await this.call(name, 'auth:login', logins.get(name))
174
+ this.setSession(name, (this.lastResult as { token: string }))
175
+ })
176
+ ```
@@ -12,247 +12,129 @@ installGroups: [core]
12
12
 
13
13
  Use this skill as an execution checklist, not reference material.
14
14
 
15
- 1. Discover before editing. Prefer OpenCode tools such as `pikku-meta` when available; otherwise run the relevant `pikku meta ... --json` command and inspect only the focused output you need.
16
- 2. Identify the source files that own the behavior. Do not start by reading generated output, `.pikku`, `node_modules`, vendored packages, or broad build artifacts.
17
- 3. Make the smallest source change that satisfies the task. Keep generated files generated, and avoid hand-editing SDKs, schema output, or typegen.
18
- 4. Validate with the narrowest relevant command first, then run `pikku-verify` or `pikku all` when functions, wirings, schemas, or generated clients may have changed.
19
- 5. If validation fails, fix the source cause and rerun validation. Do not paper over generated errors by editing generated files.
20
-
21
- Build durable, multi-step workflows with automatic retry, sleep, suspend/resume, and parallel execution. Steps are cached for replay safety.
22
-
23
- ## Before You Start
24
-
25
- ```bash
26
- pikku info functions --verbose # See existing functions that can be workflow steps
27
- pikku info tags --verbose # Understand project organization
28
- ```
15
+ 1. Capture baseline. Run `pikku-verify` (or `pikku all`) BEFORE writing code; note existing errors only NEW errors are yours to fix.
16
+ 2. Discover before editing. Prefer `pikku-meta` / `pikku info functions --verbose` and `pikku info tags --verbose` to see functions usable as steps and project organization; inspect only the focused output you need.
17
+ 3. Identify the source files that own the behavior. Do not start from generated output, `.pikku`, `node_modules`, vendored packages, or build artifacts.
18
+ 4. Make the smallest source change. Keep generated files generated never hand-edit SDKs, schema output, or typegen to paper over errors; fix the source cause.
19
+ 5. Validate with the narrowest relevant command, then re-run `pikku-verify`. If only files you did not touch still error, those are pre-existing leave them unless asked.
20
+ 6. Call `pikku-workflow-view` only when `pikku-verify` fully passes (codegen AND type check both green) — never after a partial pass.
29
21
 
30
22
  See `pikku-concepts` for the core mental model.
31
23
 
32
- ## API Reference
24
+ Build durable, multi-step workflows with automatic retry, sleep, suspend/resume, and parallel execution. Steps are cached for replay safety.
33
25
 
34
- ### `pikkuWorkflowFunc<TInput, TOutput>(fn)`
26
+ ## Choosing the right factory
35
27
 
36
- ```typescript
37
- import { pikkuWorkflowFunc } from '#pikku'
28
+ | Factory | When to use | Step-graph view? |
29
+ |---|---|---|
30
+ | `pikkuWorkflowFunc` | **Default for all new workflows.** Sequential + conditional logic; DSL mode (serialisable, replay-safe). ALL `const`/`let` declarations must be at the top level of the function body (not inside blocks). | ✅ Yes |
31
+ | `pikkuWorkflowGraph` | DAG / fan-out with nodes and typed refs between them. | ✅ Yes |
32
+ | `pikkuWorkflowComplexFunc` | Escape hatch only — arbitrary TypeScript, no top-level restriction (e.g. dynamic inline functions the DSL extractor cannot handle). | ❌ No (loses step-graph view) |
38
33
 
39
- const myWorkflow = pikkuWorkflowFunc<InputType, OutputType>(
40
- async (services, data, { workflow }) => {
41
- // workflow.do(), workflow.sleep(), workflow.suspend()
42
- return result
43
- }
44
- )
45
- ```
34
+ **Default to `pikkuWorkflowFunc`.** Use `pikkuWorkflowGraph` ONLY with explicit user approval AND only for a genuine cyclic dependency or Node.js-only import DSL cannot express. Use `pikkuWorkflowComplexFunc` ONLY with explicit user approval — a last-resort escape hatch. Never switch to either just to dodge a PKU641 error; restructure the code instead.
35
+
36
+ ### PKU641 DSL static analysis error
46
37
 
47
- ### Workflow Step Types
38
+ `pikkuWorkflowFunc` statically analyzes the body: **every `const`/`let` must be top-level, not inside any block (`if`, `for`, `while`, …).** Assignments inside blocks are fine — only declarations trigger it.
48
39
 
49
40
  ```typescript
50
- // RPC steprun a named Pikku function as a step
51
- // workflow.do(stepName, funcName, data, options?)
52
- const result = await workflow.do(
53
- 'Create profile',
54
- 'createUserProfile',
55
- {
56
- email: data.email,
57
- },
58
- { retries: 3, retryDelay: '1s' }
59
- )
41
+ // PKU641declaration inside block
42
+ if (priority === 'high') {
43
+ const bugCard = await workflow.do(...)
44
+ }
60
45
 
61
- // Inline closure step immediate execution, cached for replay
62
- // workflow.do(stepName, asyncFn)
63
- const result = await workflow.do('Generate message', async () => {
64
- return `Welcome, ${data.email}!`
65
- })
46
+ // hoist the declaration, assign inside the block
47
+ let bugCard: Awaited<ReturnType<typeof workflow.do>>
48
+ if (priority === 'high') {
49
+ bugCard = await workflow.do(...)
50
+ }
66
51
  ```
67
52
 
68
- ### Step execution: inline vs queue dispatch
69
-
70
- Whether a step runs **inline** (same process/session, no queue round-trip) or is **dispatched to the queue** is decided **purely by the step's function** — there is no workflow-level or per-call `inline` flag.
71
-
72
- - **Steps default to inline.** Most steps don't need their own worker; running them inline avoids a queue round-trip per step, so a normally-started workflow executes its whole chain in one orchestrator pass.
73
- - **`inline: false` opts a function out.** Set `inline: false` on the **function config** (`pikkuFunc` / `pikkuSessionlessFunc`, same level as `auth`/`expose`) to dispatch that step via the queue — for expensive/long-running steps that deserve their own worker, retry isolation, and concurrency limits. It is **not** a `workflow.do(...)` option (those are only `retries`/`retryDelay`/`description`).
74
-
75
- The rule (`dispatchStep`):
76
-
77
- | Function `inline` | `queueService` present? | Result |
78
- |---|---|---|
79
- | default / `true` | any | **inline** |
80
- | `false` | yes | **queued** (own worker) |
81
- | `false` | no | **inline + a `logger.warn`** (misconfiguration: can't dispatch) |
53
+ ## Import path
82
54
 
83
55
  ```typescript
84
- // Push this one expensive step onto the queue; every other step stays inline:
85
- export const renderLargeReport = pikkuSessionlessFunc({
86
- inline: false, // dispatch via queue instead of running inline
87
- input: ReportInput,
88
- output: ReportOutput,
89
- func: async (services, data) => { /* ... */ },
90
- })
91
- ```
56
+ // CORRECT workflow factories come from the generated types file
57
+ import { pikkuWorkflowFunc, pikkuWorkflowGraph, pikkuWorkflowComplexFunc } from '#pikku/workflow/pikku-workflow-types.gen.js'
92
58
 
93
- - **Run-level `inline` is separate** and only controls whether the *whole run* executes in-process without queue infrastructure (it's set automatically when there is no `queueService`, or via `startWorkflow(..., { inline: true })`). It governs sleep handling, **not** per-step dispatch — step dispatch is always per-function.
94
- - `inline: false` requires a `queueService`; without one the step still runs (so the workflow progresses) but emits a `logger.warn` so the misconfiguration is visible.
95
-
96
- // Sleep — durable pause (duration: '5min', '1h', '30s', '1d')
97
- await workflow.sleep('Wait 5 minutes', '5min')
98
-
99
- // Suspend — pause until externally resumed
100
- await workflow.suspend('Awaiting approval')
59
+ // WRONG '#pikku' does not re-export them (TS2305)
60
+ import { pikkuWorkflowFunc } from '#pikku'
101
61
  ```
102
62
 
103
- ### Choosing the right wrapper
63
+ ## Defining a workflow
104
64
 
105
- | Wrapper | When to use |
106
- |---|---|
107
- | `pikkuWorkflowFunc` | **Default.** Use for all new workflows. DSL mode — serialisable, replay-safe. |
108
- | `pikkuWorkflowComplexFunc` | **Only with explicit user approval.** For workflows with patterns the DSL extractor cannot handle (e.g. dynamic inline functions). Not a general escape hatch — restructure first. |
109
- | `pikkuWorkflowGraph` | **Only with explicit user approval.** For genuine DAGs where there is a cyclic dependency between nodes or a Node.js-only import DSL cannot express. |
110
-
111
- **Conditional results** — the correct DSL pattern when a step only runs under some condition:
65
+ Declare input/output as Zod schemas (like any function) — never TypeScript generic params (no `pikkuWorkflowFunc<In, Out>(...)`; that skips runtime validation). `data` is typed from the input schema.
112
66
 
113
67
  ```typescript
114
- // Declare at top level, assign inside block
115
- let result: { id: string } | null = null
116
- if (input.createFoo) {
117
- result = await workflow.do('Create foo', 'createFoo', { ... })
118
- }
119
- // Use result?.id downstream
120
-
121
- // Do NOT declare const inside a block — DSL forbids block-scoped declarations
122
- // ❌ Do NOT switch to pikkuWorkflowComplexFunc to avoid the restriction
123
- ```
124
-
125
- ### `pikkuWorkflowGraph(config)` DAG Workflows
68
+ import { z } from 'zod'
69
+ import { pikkuWorkflowFunc } from '#pikku/workflow/pikku-workflow-types.gen.js'
70
+
71
+ const ProcessOrderInput = z.object({ orderId: z.string(), amount: z.number() })
72
+ const ProcessOrderOutput = z.object({ status: z.string(), discount: z.number().optional() })
73
+
74
+ export const processOrder = pikkuWorkflowFunc({
75
+ description: 'Process an order through payment and fulfillment',
76
+ tags: ['orders'],
77
+ input: ProcessOrderInput,
78
+ output: ProcessOrderOutput,
79
+ func: async (services, data, { workflow }) => {
80
+ // Declare ALL variables at top level — even those only assigned in branches (PKU641)
81
+ let discount: number | undefined
82
+ let status: string
83
+
84
+ if (data.amount > 1000) {
85
+ const d = await workflow.do('Apply bulk discount', 'calcDiscount', { amount: data.amount })
86
+ discount = d.discountPercent
87
+ }
88
+
89
+ const payment = await workflow.do('Charge', 'chargePayment', {
90
+ orderId: data.orderId,
91
+ amount: discount ? data.amount * (1 - discount / 100) : data.amount,
92
+ })
126
93
 
127
- ```typescript
128
- import { pikkuWorkflowGraph } from '#pikku'
94
+ if (payment.success) {
95
+ await workflow.do('Fulfill', 'fulfillOrder', { orderId: data.orderId })
96
+ status = 'fulfilled'
97
+ } else {
98
+ status = 'payment-failed'
99
+ }
129
100
 
130
- pikkuWorkflowGraph({
131
- description: 'Onboard a new user',
132
- nodes: {
133
- createProfile: 'createUserProfile', // nodeName → Pikku function name
134
- sendWelcome: 'sendEmail',
135
- },
136
- config: {
137
- createProfile: {
138
- next: ['sendWelcome'], // Nodes to run after this one (parallel)
139
- },
140
- sendWelcome: {
141
- input: (ref) => ({
142
- // Transform input using refs to prior node outputs
143
- to: ref('createProfile', 'email'),
144
- subject: 'Welcome!',
145
- }),
146
- },
101
+ return { status, discount }
147
102
  },
148
103
  })
149
104
  ```
150
105
 
151
- ### HTTP Workflow Wiring
106
+ ### Workflow step types
152
107
 
153
108
  ```typescript
154
- // Start a workflow
155
- wireHTTP({
156
- method: 'post',
157
- route: '/workflow/onboard',
158
- func: workflowStart('workflowName'),
159
- })
160
-
161
- // Execute workflow steps (called by orchestrator)
162
- wireHTTP({
163
- method: 'post',
164
- route: '/workflow/onboard/run',
165
- func: workflow('workflowName'),
166
- })
167
-
168
- // Check workflow status
169
- wireHTTP({
170
- method: 'get',
171
- route: '/workflow/status/:runId',
172
- func: workflowStatus('workflowName'),
173
- })
174
- ```
109
+ // RPC step — run a registered Pikku function as a step (opts: retries, retryDelay, description)
110
+ const result = await workflow.do('Step name', 'rpcFunctionName', { ...data }, { retries: 3, retryDelay: '1s' })
175
111
 
176
- ## Usage Patterns
112
+ // Inline closure step — immediate execution, cached for replay
113
+ const msg = await workflow.do('Generate', async () => `Welcome, ${data.email}!`)
177
114
 
178
- ### Sequential Workflow
115
+ // Sleep — durable pause (duration: '30s', '5min', '1h', '1d')
116
+ await workflow.sleep('Wait 5 minutes', '5min')
179
117
 
180
- ```typescript
181
- const onboardUser = pikkuWorkflowFunc<
182
- { email: string; userId: string },
183
- { success: boolean }
184
- >(async ({}, data, { workflow }) => {
185
- const user = await workflow.do('Create profile', 'createUserProfile', {
186
- email: data.email,
187
- userId: data.userId,
188
- })
189
-
190
- const message = await workflow.do(
191
- 'Generate welcome',
192
- async () => `Welcome, ${data.email}!`
193
- )
194
-
195
- await workflow.sleep('Wait 5 minutes', '5min')
196
-
197
- await workflow.do('Send email', 'sendEmail', {
198
- to: data.email,
199
- subject: 'Welcome!',
200
- body: message,
201
- })
202
-
203
- return { success: true }
204
- })
118
+ // Suspend — pause until externally resumed (e.g. awaiting approval), then continue
119
+ await workflow.suspend('Awaiting approval')
205
120
  ```
206
121
 
207
- ### Parallel Execution (Fan-out)
122
+ ### Parallel fan-out
208
123
 
209
124
  ```typescript
210
125
  const users = await Promise.all(
211
- data.userIds.map(
212
- async (userId) =>
213
- await workflow.do(`Get user ${userId}`, 'userGet', { userId })
214
- )
215
- )
216
- ```
217
-
218
- ### Retry with Backoff
219
-
220
- ```typescript
221
- const payment = await workflow.do(
222
- 'Process payment',
223
- 'processPayment',
224
- { amount: 100 },
225
- { retries: 3, retryDelay: '1s' }
126
+ data.userIds.map((userId) => workflow.do(`Fetch user ${userId}`, 'getUser', { userId }))
226
127
  )
227
128
  ```
228
129
 
229
- ### Conditional Branching
230
-
231
- ```typescript
232
- if (user.plan === 'pro') {
233
- await workflow.do('Apply discount', 'applyDiscount', { userId })
234
- }
235
- ```
130
+ ### Graph workflow (DAG)
236
131
 
237
- ### Suspend and Resume
132
+ `pikkuWorkflowGraph` derives types from the RPC map — no explicit `input`/`output`. Nodes map `nodeName → Pikku function name`; `config.<node>.next` lists nodes to run after it (in parallel); `config.<node>.input: (ref) => ...` transforms input using refs to prior node outputs.
238
133
 
239
134
  ```typescript
240
- const approval = pikkuWorkflowFunc<
241
- { requestId: string },
242
- { approved: boolean }
243
- >(async ({}, data, { workflow }) => {
244
- await workflow.do('Submit request', 'submitRequest', data)
245
- await workflow.suspend('Awaiting approval')
246
- // Workflow pauses here until externally resumed
247
- const result = await workflow.do('Check result', 'getApprovalResult', data)
248
- return { approved: result.approved }
249
- })
250
- ```
251
-
252
- ### Graph Workflow (DAG)
135
+ import { pikkuWorkflowGraph } from '#pikku/workflow/pikku-workflow-types.gen.js'
253
136
 
254
- ```typescript
255
- const userOnboarding = pikkuWorkflowGraph({
137
+ export const userOnboarding = pikkuWorkflowGraph({
256
138
  description: 'Onboard a new user',
257
139
  nodes: {
258
140
  createProfile: 'createUserProfile',
@@ -260,75 +142,27 @@ const userOnboarding = pikkuWorkflowGraph({
260
142
  setupDefaults: 'createDefaultTodos',
261
143
  },
262
144
  config: {
263
- createProfile: {
264
- next: ['sendWelcome', 'setupDefaults'], // Run in parallel
265
- },
145
+ createProfile: { next: ['sendWelcome', 'setupDefaults'] }, // run in parallel
266
146
  sendWelcome: {
267
- input: (ref) => ({
268
- to: ref('createProfile', 'email'),
269
- subject: 'Welcome!',
270
- }),
147
+ input: (ref) => ({ to: ref('createProfile', 'email'), subject: 'Welcome!' }),
271
148
  },
272
149
  },
273
150
  })
274
151
  ```
275
152
 
276
- ## Complete Example
153
+ ## File conventions
277
154
 
278
- ```typescript
279
- // functions/onboarding.workflow.ts
280
- export const onboardUser = pikkuWorkflowFunc<
281
- { email: string; userId: string; plan: string },
282
- { success: boolean }
283
- >(async ({}, data, { workflow }) => {
284
- // Step 1: Create user profile
285
- const user = await workflow.do('Create profile', 'createUserProfile', {
286
- email: data.email,
287
- userId: data.userId,
288
- })
289
-
290
- // Step 2: Set up defaults based on plan
291
- if (data.plan === 'pro') {
292
- await workflow.do('Apply pro features', 'enableProFeatures', {
293
- userId: data.userId,
294
- })
295
- }
296
-
297
- // Step 3: Send welcome email
298
- await workflow.do('Send welcome', 'sendEmail', {
299
- to: data.email,
300
- subject: 'Welcome!',
301
- body: `Welcome to our platform, ${user.name}!`,
302
- })
303
-
304
- // Step 4: Wait then send follow-up
305
- await workflow.sleep('Wait 1 day', '1d')
306
-
307
- await workflow.do('Send follow-up', 'sendEmail', {
308
- to: data.email,
309
- subject: 'Getting started',
310
- body: 'Here are some tips to get started...',
311
- })
155
+ - Place workflows in `packages/functions/src/wirings/*.workflow.ts`; export the variable so the inspector discovers it (no manual registration).
156
+ - HTTP start/run/status routes are auto-scaffolded via `scaffold.workflow` in `pikku.config.json`.
312
157
 
313
- return { success: true }
314
- })
158
+ ## Step dispatch & HTTP wiring
315
159
 
316
- // wirings/workflow.wiring.ts
317
- wireHTTP({
318
- method: 'post',
319
- route: '/onboard',
320
- func: workflowStart('onboardUser'),
321
- })
160
+ For per-step inline-vs-queue dispatch (`inline: false` and the `dispatchStep` rules), the manual `workflowStart`/`workflow`/`workflowStatus` HTTP wirings, and a suspend/resume example, read `references/workflow-reference.md`.
322
161
 
323
- wireHTTP({
324
- method: 'post',
325
- route: '/onboard/run',
326
- func: workflow('onboardUser'),
327
- })
162
+ ## After writing
328
163
 
329
- wireHTTP({
330
- method: 'get',
331
- route: '/onboard/status/:runId',
332
- func: workflowStatus('onboardUser'),
333
- })
334
- ```
164
+ 1. `pikku-verify` (codegen + tsc).
165
+ 2. PKU641 → a `const`/`let` is inside a block; hoist it to the top of the function body.
166
+ 3. Import errors → use `#pikku/workflow/pikku-workflow-types.gen.js`, not `#pikku`.
167
+ 4. Type errors only in files you did not touch → pre-existing template errors; safe to ignore.
168
+ 5. Both green → call `pikku-workflow-view` with the workflow name.
@@ -0,0 +1,63 @@
1
+ # Pikku Workflow Reference
2
+
3
+ ## Step execution: inline vs queue dispatch
4
+
5
+ Whether a step runs **inline** (same process/session, no queue round-trip) or is **dispatched to the queue** is decided **purely by the step's function** — there is no workflow-level or per-call `inline` flag. `workflow.do(...)` options are only `retries`/`retryDelay`/`description`.
6
+
7
+ - **Steps default to inline.** Most steps don't need their own worker; running them inline avoids a queue round-trip per step, so a normally-started workflow executes its whole chain in one orchestrator pass.
8
+ - **`inline: false` opts a function out.** Set `inline: false` on the **function config** (`pikkuFunc` / `pikkuSessionlessFunc`, same level as `auth`/`expose`) to dispatch that step via the queue — for expensive/long-running steps that deserve their own worker, retry isolation, and concurrency limits.
9
+ - **Run-level `inline` is separate** and only controls whether the *whole run* executes in-process without queue infrastructure (set automatically when there is no `queueService`, or via `startWorkflow(..., { inline: true })`). It governs sleep handling, not per-step dispatch.
10
+
11
+ The rule (`dispatchStep`):
12
+
13
+ | Function `inline` | `queueService` present? | Result |
14
+ |---|---|---|
15
+ | default / `true` | any | **inline** |
16
+ | `false` | yes | **queued** (own worker) |
17
+ | `false` | no | **inline + a `logger.warn`** (misconfiguration: can't dispatch) |
18
+
19
+ ```typescript
20
+ // Push this one expensive step onto the queue; every other step stays inline:
21
+ export const renderLargeReport = pikkuSessionlessFunc({
22
+ inline: false, // dispatch via queue instead of running inline
23
+ input: ReportInput,
24
+ output: ReportOutput,
25
+ func: async (services, data) => { /* ... */ },
26
+ })
27
+ ```
28
+
29
+ `inline: false` requires a `queueService`; without one the step still runs (so the workflow progresses) but emits a `logger.warn` so the misconfiguration is visible.
30
+
31
+ ## HTTP workflow wiring (manual)
32
+
33
+ Usually auto-scaffolded via `scaffold.workflow`. To wire by hand:
34
+
35
+ ```typescript
36
+ // Start a workflow
37
+ wireHTTP({ method: 'post', route: '/onboard', func: workflowStart('onboardUser') })
38
+
39
+ // Execute workflow steps (called by the orchestrator)
40
+ wireHTTP({ method: 'post', route: '/onboard/run', func: workflow('onboardUser') })
41
+
42
+ // Check workflow status
43
+ wireHTTP({ method: 'get', route: '/onboard/status/:runId', func: workflowStatus('onboardUser') })
44
+ ```
45
+
46
+ ## Suspend / resume example
47
+
48
+ ```typescript
49
+ import { z } from 'zod'
50
+ import { pikkuWorkflowFunc } from '#pikku/workflow/pikku-workflow-types.gen.js'
51
+
52
+ export const approval = pikkuWorkflowFunc({
53
+ description: 'Submit a request and wait for approval',
54
+ input: z.object({ requestId: z.string() }),
55
+ output: z.object({ approved: z.boolean() }),
56
+ func: async (services, data, { workflow }) => {
57
+ await workflow.do('Submit request', 'submitRequest', data)
58
+ await workflow.suspend('Awaiting approval') // pauses here until externally resumed
59
+ const result = await workflow.do('Check result', 'getApprovalResult', data)
60
+ return { approved: result.approved }
61
+ },
62
+ })
63
+ ```