@pikku/core 0.11.2 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (436) hide show
  1. package/CHANGELOG.md +57 -2
  2. package/dist/crypto-utils.d.ts +2 -0
  3. package/dist/crypto-utils.js +78 -0
  4. package/dist/errors/errors.d.ts +14 -0
  5. package/dist/errors/errors.js +26 -0
  6. package/dist/errors/index.d.ts +1 -1
  7. package/dist/errors/index.js +1 -1
  8. package/dist/function/function-runner.d.ts +10 -4
  9. package/dist/function/function-runner.js +126 -45
  10. package/dist/function/functions.types.d.ts +32 -87
  11. package/dist/function/functions.types.js +16 -46
  12. package/dist/function/index.d.ts +2 -2
  13. package/dist/function/index.js +1 -2
  14. package/dist/handle-error.d.ts +2 -2
  15. package/dist/handle-error.js +3 -12
  16. package/dist/index.d.ts +30 -26
  17. package/dist/index.js +19 -29
  18. package/dist/internal.d.ts +3 -0
  19. package/dist/internal.js +2 -0
  20. package/dist/middleware/auth-apikey.d.ts +2 -2
  21. package/dist/middleware/auth-apikey.js +3 -3
  22. package/dist/middleware/auth-bearer.d.ts +3 -3
  23. package/dist/middleware/auth-bearer.js +4 -7
  24. package/dist/middleware/auth-cookie.d.ts +4 -4
  25. package/dist/middleware/auth-cookie.js +7 -9
  26. package/dist/middleware/cors.d.ts +46 -0
  27. package/dist/middleware/cors.js +81 -0
  28. package/dist/middleware/index.d.ts +5 -3
  29. package/dist/middleware/index.js +5 -3
  30. package/dist/middleware/remote-auth.d.ts +5 -0
  31. package/dist/middleware/remote-auth.js +55 -0
  32. package/dist/middleware/timeout.d.ts +2 -2
  33. package/dist/middleware-runner.d.ts +1 -1
  34. package/dist/middleware-runner.js +8 -10
  35. package/dist/permissions.d.ts +2 -2
  36. package/dist/permissions.js +11 -15
  37. package/dist/pikku-state.d.ts +10 -8
  38. package/dist/pikku-state.js +48 -25
  39. package/dist/schema.d.ts +4 -4
  40. package/dist/schema.js +20 -15
  41. package/dist/services/ai-agent-runner-service.d.ts +43 -0
  42. package/dist/services/ai-agent-runner-service.js +1 -0
  43. package/dist/services/ai-run-state-service.d.ts +13 -0
  44. package/dist/services/ai-run-state-service.js +1 -0
  45. package/dist/services/ai-storage-service.d.ts +18 -0
  46. package/dist/services/ai-storage-service.js +1 -0
  47. package/dist/services/content-service.d.ts +6 -0
  48. package/dist/services/deployment-service.d.ts +19 -0
  49. package/dist/services/deployment-service.js +1 -0
  50. package/dist/services/gopass-secrets.d.ts +47 -0
  51. package/dist/services/gopass-secrets.js +97 -0
  52. package/dist/services/in-memory-ai-run-state-service.d.ts +15 -0
  53. package/dist/services/in-memory-ai-run-state-service.js +44 -0
  54. package/dist/services/in-memory-trigger-service.d.ts +22 -0
  55. package/dist/services/in-memory-trigger-service.js +48 -0
  56. package/dist/services/in-memory-workflow-service.d.ts +59 -0
  57. package/dist/services/in-memory-workflow-service.js +287 -0
  58. package/dist/services/index.d.ts +26 -11
  59. package/dist/services/index.js +11 -13
  60. package/dist/services/local-content.d.ts +2 -1
  61. package/dist/services/local-content.js +6 -1
  62. package/dist/services/local-secrets.d.ts +25 -2
  63. package/dist/services/local-secrets.js +45 -0
  64. package/dist/services/local-variables.d.ts +6 -1
  65. package/dist/services/local-variables.js +18 -0
  66. package/dist/services/logger-console.d.ts +2 -1
  67. package/dist/services/scheduler-service.d.ts +9 -1
  68. package/dist/services/scheduler-service.js +8 -0
  69. package/dist/services/schema-service.d.ts +6 -0
  70. package/dist/services/scoped-secret-service.d.ts +16 -0
  71. package/dist/services/scoped-secret-service.js +35 -0
  72. package/dist/services/secret-service.d.ts +25 -4
  73. package/dist/services/trigger-service.d.ts +16 -0
  74. package/dist/services/trigger-service.js +1 -0
  75. package/dist/services/typed-secret-service.d.ts +30 -0
  76. package/dist/services/typed-secret-service.js +40 -0
  77. package/dist/services/typed-variables-service.d.ts +27 -0
  78. package/dist/services/typed-variables-service.js +46 -0
  79. package/dist/services/user-session-service.d.ts +15 -2
  80. package/dist/services/user-session-service.js +17 -0
  81. package/dist/services/variables-service.d.ts +5 -0
  82. package/dist/services/workflow-service.d.ts +9 -5
  83. package/dist/types/core.types.d.ts +67 -25
  84. package/dist/types/core.types.js +8 -1
  85. package/dist/types/state.types.d.ts +53 -59
  86. package/dist/utils.d.ts +7 -6
  87. package/dist/utils.js +27 -12
  88. package/dist/version.d.ts +6 -0
  89. package/dist/version.js +19 -0
  90. package/dist/wirings/ai-agent/ai-agent-assistant-ui.d.ts +5 -0
  91. package/dist/wirings/ai-agent/ai-agent-assistant-ui.js +146 -0
  92. package/dist/wirings/ai-agent/ai-agent-helpers.d.ts +28 -0
  93. package/dist/wirings/ai-agent/ai-agent-helpers.js +40 -0
  94. package/dist/wirings/ai-agent/ai-agent-memory.d.ts +29 -0
  95. package/dist/wirings/ai-agent/ai-agent-memory.js +199 -0
  96. package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +9 -0
  97. package/dist/wirings/ai-agent/ai-agent-model-config.js +36 -0
  98. package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +59 -0
  99. package/dist/wirings/ai-agent/ai-agent-prepare.js +348 -0
  100. package/dist/wirings/ai-agent/ai-agent-registry.d.ts +15 -0
  101. package/dist/wirings/ai-agent/ai-agent-registry.js +47 -0
  102. package/dist/wirings/ai-agent/ai-agent-runner.d.ts +3 -0
  103. package/dist/wirings/ai-agent/ai-agent-runner.js +195 -0
  104. package/dist/wirings/ai-agent/ai-agent-stream.d.ts +12 -0
  105. package/dist/wirings/ai-agent/ai-agent-stream.js +662 -0
  106. package/dist/wirings/ai-agent/ai-agent.types.d.ts +313 -0
  107. package/dist/wirings/ai-agent/ai-agent.types.js +1 -0
  108. package/dist/wirings/ai-agent/index.d.ts +7 -0
  109. package/dist/wirings/ai-agent/index.js +6 -0
  110. package/dist/wirings/channel/channel-common.d.ts +8 -5
  111. package/dist/wirings/channel/channel-common.js +15 -8
  112. package/dist/wirings/channel/channel-handler.d.ts +3 -3
  113. package/dist/wirings/channel/channel-handler.js +15 -6
  114. package/dist/wirings/channel/channel-middleware-runner.d.ts +9 -0
  115. package/dist/wirings/channel/channel-middleware-runner.js +73 -0
  116. package/dist/wirings/channel/channel-runner.d.ts +5 -5
  117. package/dist/wirings/channel/channel-runner.js +10 -9
  118. package/dist/wirings/channel/channel-store.d.ts +1 -1
  119. package/dist/wirings/channel/channel.types.d.ts +9 -7
  120. package/dist/wirings/channel/define-channel-routes.d.ts +21 -0
  121. package/dist/wirings/channel/define-channel-routes.js +23 -0
  122. package/dist/wirings/channel/index.d.ts +10 -8
  123. package/dist/wirings/channel/index.js +7 -8
  124. package/dist/wirings/channel/local/index.d.ts +3 -3
  125. package/dist/wirings/channel/local/index.js +3 -3
  126. package/dist/wirings/channel/local/local-channel-runner.d.ts +7 -2
  127. package/dist/wirings/channel/local/local-channel-runner.js +22 -9
  128. package/dist/wirings/channel/local/local-eventhub-service.d.ts +2 -2
  129. package/dist/wirings/channel/log-channels.d.ts +1 -1
  130. package/dist/wirings/channel/pikku-abstract-channel-handler.d.ts +1 -1
  131. package/dist/wirings/channel/serverless/index.d.ts +1 -1
  132. package/dist/wirings/channel/serverless/index.js +1 -1
  133. package/dist/wirings/channel/serverless/serverless-channel-runner.d.ts +4 -4
  134. package/dist/wirings/channel/serverless/serverless-channel-runner.js +40 -23
  135. package/dist/wirings/cli/channel/cli-channel-runner.d.ts +1 -1
  136. package/dist/wirings/cli/channel/index.d.ts +1 -1
  137. package/dist/wirings/cli/channel/index.js +1 -1
  138. package/dist/wirings/cli/cli-runner.d.ts +3 -3
  139. package/dist/wirings/cli/cli-runner.js +12 -8
  140. package/dist/wirings/cli/cli.types.d.ts +9 -9
  141. package/dist/wirings/cli/command-parser.d.ts +1 -1
  142. package/dist/wirings/cli/define-cli-commands.d.ts +19 -0
  143. package/dist/wirings/cli/define-cli-commands.js +20 -0
  144. package/dist/wirings/cli/index.d.ts +2 -3
  145. package/dist/wirings/cli/index.js +1 -3
  146. package/dist/wirings/http/http-routes.d.ts +69 -0
  147. package/dist/wirings/http/http-routes.js +139 -0
  148. package/dist/wirings/http/http-runner.d.ts +9 -9
  149. package/dist/wirings/http/http-runner.js +79 -34
  150. package/dist/wirings/http/http.types.d.ts +77 -41
  151. package/dist/wirings/http/index.d.ts +5 -4
  152. package/dist/wirings/http/index.js +4 -3
  153. package/dist/wirings/http/log-http-routes.d.ts +1 -1
  154. package/dist/wirings/http/pikku-fetch-http-request.d.ts +1 -1
  155. package/dist/wirings/http/pikku-fetch-http-response.d.ts +2 -2
  156. package/dist/wirings/http/pikku-fetch-http-response.js +6 -1
  157. package/dist/wirings/http/routers/http-router.d.ts +1 -1
  158. package/dist/wirings/http/routers/path-to-regex.d.ts +2 -2
  159. package/dist/wirings/mcp/index.d.ts +4 -3
  160. package/dist/wirings/mcp/index.js +3 -3
  161. package/dist/wirings/mcp/mcp-endpoint-registry.d.ts +1 -1
  162. package/dist/wirings/mcp/mcp-runner.d.ts +1 -6
  163. package/dist/wirings/mcp/mcp-runner.js +28 -40
  164. package/dist/wirings/mcp/mcp.types.d.ts +5 -5
  165. package/dist/wirings/node/index.d.ts +2 -0
  166. package/dist/wirings/node/index.js +1 -0
  167. package/dist/wirings/node/node.types.d.ts +20 -0
  168. package/dist/wirings/node/node.types.js +1 -0
  169. package/dist/wirings/oauth2/index.d.ts +3 -0
  170. package/dist/wirings/oauth2/index.js +2 -0
  171. package/dist/wirings/oauth2/oauth2-client.d.ts +47 -0
  172. package/dist/wirings/oauth2/oauth2-client.js +267 -0
  173. package/dist/wirings/oauth2/oauth2.types.d.ts +65 -0
  174. package/dist/wirings/oauth2/oauth2.types.js +4 -0
  175. package/dist/wirings/oauth2/wire-oauth2-credential.d.ts +20 -0
  176. package/dist/wirings/oauth2/wire-oauth2-credential.js +21 -0
  177. package/dist/wirings/queue/index.d.ts +1 -1
  178. package/dist/wirings/queue/queue-runner.d.ts +1 -5
  179. package/dist/wirings/queue/queue-runner.js +11 -8
  180. package/dist/wirings/queue/queue.types.d.ts +5 -5
  181. package/dist/wirings/queue/register-queue-helper.d.ts +2 -2
  182. package/dist/wirings/queue/register-queue-helper.js +1 -1
  183. package/dist/wirings/queue/validate-worker-config.d.ts +1 -1
  184. package/dist/wirings/rpc/index.d.ts +3 -1
  185. package/dist/wirings/rpc/index.js +2 -1
  186. package/dist/wirings/rpc/rpc-runner.d.ts +58 -8
  187. package/dist/wirings/rpc/rpc-runner.js +177 -31
  188. package/dist/wirings/rpc/rpc-types.d.ts +20 -4
  189. package/dist/wirings/rpc/wire-addon.d.ts +10 -0
  190. package/dist/wirings/rpc/wire-addon.js +9 -0
  191. package/dist/wirings/scheduler/index.d.ts +2 -2
  192. package/dist/wirings/scheduler/index.js +1 -2
  193. package/dist/wirings/scheduler/log-schedulers.d.ts +1 -1
  194. package/dist/wirings/scheduler/scheduler-runner.d.ts +3 -5
  195. package/dist/wirings/scheduler/scheduler-runner.js +11 -14
  196. package/dist/wirings/scheduler/scheduler.types.d.ts +2 -2
  197. package/dist/wirings/secret/index.d.ts +3 -0
  198. package/dist/wirings/secret/index.js +2 -0
  199. package/dist/wirings/secret/secret.types.d.ts +27 -0
  200. package/dist/wirings/secret/secret.types.js +1 -0
  201. package/dist/wirings/secret/validate-secret-definitions.d.ts +6 -0
  202. package/dist/wirings/secret/validate-secret-definitions.js +55 -0
  203. package/dist/wirings/trigger/index.d.ts +3 -2
  204. package/dist/wirings/trigger/index.js +2 -2
  205. package/dist/wirings/trigger/pikku-trigger-service.d.ts +22 -0
  206. package/dist/wirings/trigger/pikku-trigger-service.js +70 -0
  207. package/dist/wirings/trigger/trigger-runner.d.ts +18 -9
  208. package/dist/wirings/trigger/trigger-runner.js +48 -19
  209. package/dist/wirings/trigger/trigger.types.d.ts +99 -11
  210. package/dist/wirings/trigger/trigger.types.js +40 -1
  211. package/dist/wirings/variable/index.d.ts +3 -0
  212. package/dist/wirings/variable/index.js +2 -0
  213. package/dist/wirings/variable/validate-variable-definitions.d.ts +6 -0
  214. package/dist/wirings/variable/validate-variable-definitions.js +45 -0
  215. package/dist/wirings/variable/variable.types.d.ts +18 -0
  216. package/dist/wirings/variable/variable.types.js +1 -0
  217. package/dist/wirings/workflow/dsl/index.d.ts +1 -1
  218. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +7 -1
  219. package/dist/wirings/workflow/dsl/workflow-runner.js +3 -2
  220. package/dist/wirings/workflow/graph/graph-node.d.ts +1 -6
  221. package/dist/wirings/workflow/graph/graph-runner.d.ts +5 -31
  222. package/dist/wirings/workflow/graph/graph-runner.js +384 -296
  223. package/dist/wirings/workflow/graph/index.d.ts +4 -3
  224. package/dist/wirings/workflow/graph/index.js +3 -3
  225. package/dist/wirings/workflow/graph/template.d.ts +15 -0
  226. package/dist/wirings/workflow/graph/template.js +27 -0
  227. package/dist/wirings/workflow/graph/wire-workflow-graph.d.ts +15 -0
  228. package/dist/wirings/workflow/graph/wire-workflow-graph.js +8 -0
  229. package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +0 -13
  230. package/dist/wirings/workflow/index.d.ts +6 -6
  231. package/dist/wirings/workflow/index.js +6 -4
  232. package/dist/wirings/workflow/pikku-workflow-service.d.ts +29 -19
  233. package/dist/wirings/workflow/pikku-workflow-service.js +217 -82
  234. package/dist/wirings/workflow/workflow-helpers.d.ts +36 -0
  235. package/dist/wirings/workflow/workflow-helpers.js +38 -0
  236. package/dist/wirings/workflow/workflow.types.d.ts +42 -95
  237. package/package.json +14 -15
  238. package/run-tests.sh +4 -1
  239. package/src/crypto-utils.test.ts +116 -0
  240. package/src/crypto-utils.ts +99 -0
  241. package/src/errors/error.test.ts +143 -2
  242. package/src/errors/errors.ts +27 -0
  243. package/src/errors/index.ts +1 -1
  244. package/src/factory-functions.test.ts +42 -2
  245. package/src/function/function-runner.test.ts +6 -13
  246. package/src/function/function-runner.ts +161 -53
  247. package/src/function/functions.types.ts +63 -132
  248. package/src/function/index.ts +5 -2
  249. package/src/handle-error.test.ts +361 -0
  250. package/src/handle-error.ts +6 -14
  251. package/src/index.ts +97 -30
  252. package/src/internal.ts +6 -0
  253. package/src/middleware/auth-apikey.test.ts +16 -13
  254. package/src/middleware/auth-apikey.ts +3 -3
  255. package/src/middleware/auth-bearer.test.ts +18 -15
  256. package/src/middleware/auth-bearer.ts +27 -32
  257. package/src/middleware/auth-cookie.test.ts +17 -14
  258. package/src/middleware/auth-cookie.ts +9 -13
  259. package/src/middleware/cors.test.ts +424 -0
  260. package/src/middleware/cors.ts +104 -0
  261. package/src/middleware/index.ts +5 -3
  262. package/src/middleware/remote-auth.test.ts +488 -0
  263. package/src/middleware/remote-auth.ts +68 -0
  264. package/src/middleware-runner.test.ts +123 -1
  265. package/src/middleware-runner.ts +13 -13
  266. package/src/permissions.test.ts +83 -9
  267. package/src/permissions.ts +17 -19
  268. package/src/pikku-state.test.ts +224 -0
  269. package/src/pikku-state.ts +59 -35
  270. package/src/run-tests-script.test.ts +49 -0
  271. package/src/schema.test.ts +198 -6
  272. package/src/schema.ts +28 -21
  273. package/src/services/ai-agent-runner-service.ts +41 -0
  274. package/src/services/ai-run-state-service.ts +20 -0
  275. package/src/services/ai-storage-service.ts +39 -0
  276. package/src/services/content-service.ts +7 -0
  277. package/src/services/deployment-service.ts +22 -0
  278. package/src/services/gopass-secrets.ts +98 -0
  279. package/src/services/in-memory-ai-run-state-service.ts +73 -0
  280. package/src/services/in-memory-trigger-service.ts +64 -0
  281. package/src/services/in-memory-workflow-service.test.ts +351 -0
  282. package/src/services/in-memory-workflow-service.ts +395 -0
  283. package/src/services/index.ts +50 -14
  284. package/src/services/local-content.ts +9 -3
  285. package/src/services/local-secrets.test.ts +80 -0
  286. package/src/services/local-secrets.ts +53 -2
  287. package/src/services/local-variables.test.ts +61 -0
  288. package/src/services/local-variables.ts +23 -1
  289. package/src/services/logger-console.test.ts +118 -0
  290. package/src/services/logger-console.ts +2 -1
  291. package/src/services/scheduler-service.ts +11 -1
  292. package/src/services/schema-service.ts +7 -0
  293. package/src/services/scoped-secret-service.test.ts +74 -0
  294. package/src/services/scoped-secret-service.ts +41 -0
  295. package/src/services/secret-service.ts +25 -4
  296. package/src/services/trigger-service.ts +17 -0
  297. package/src/services/typed-secret-service.test.ts +93 -0
  298. package/src/services/typed-secret-service.ts +70 -0
  299. package/src/services/typed-variables-service.test.ts +73 -0
  300. package/src/services/typed-variables-service.ts +81 -0
  301. package/src/services/user-session-service.test.ts +113 -0
  302. package/src/services/user-session-service.ts +25 -2
  303. package/src/services/variables-service.ts +5 -0
  304. package/src/services/workflow-service.ts +23 -13
  305. package/src/time-utils.test.ts +1 -1
  306. package/src/types/core.types.ts +95 -24
  307. package/src/types/state.types.ts +56 -73
  308. package/src/utils.test.ts +350 -0
  309. package/src/utils.ts +33 -18
  310. package/src/version.test.ts +80 -0
  311. package/src/version.ts +25 -0
  312. package/src/wirings/ai-agent/ai-agent-assistant-ui.test.ts +363 -0
  313. package/src/wirings/ai-agent/ai-agent-assistant-ui.ts +214 -0
  314. package/src/wirings/ai-agent/ai-agent-helpers.test.ts +152 -0
  315. package/src/wirings/ai-agent/ai-agent-helpers.ts +76 -0
  316. package/src/wirings/ai-agent/ai-agent-memory.ts +300 -0
  317. package/src/wirings/ai-agent/ai-agent-model-config.test.ts +115 -0
  318. package/src/wirings/ai-agent/ai-agent-model-config.ts +43 -0
  319. package/src/wirings/ai-agent/ai-agent-prepare.ts +504 -0
  320. package/src/wirings/ai-agent/ai-agent-registry.test.ts +37 -0
  321. package/src/wirings/ai-agent/ai-agent-registry.ts +82 -0
  322. package/src/wirings/ai-agent/ai-agent-runner.test.ts +317 -0
  323. package/src/wirings/ai-agent/ai-agent-runner.ts +251 -0
  324. package/src/wirings/ai-agent/ai-agent-stream.test.ts +652 -0
  325. package/src/wirings/ai-agent/ai-agent-stream.ts +1049 -0
  326. package/src/wirings/ai-agent/ai-agent.types.ts +328 -0
  327. package/src/wirings/ai-agent/index.ts +39 -0
  328. package/src/wirings/channel/channel-common.ts +33 -20
  329. package/src/wirings/channel/channel-handler.ts +26 -9
  330. package/src/wirings/channel/channel-middleware-runner.ts +119 -0
  331. package/src/wirings/channel/channel-runner.ts +15 -16
  332. package/src/wirings/channel/channel-store.ts +1 -1
  333. package/src/wirings/channel/channel.types.ts +21 -9
  334. package/src/wirings/channel/define-channel-routes.ts +25 -0
  335. package/src/wirings/channel/index.ts +23 -8
  336. package/src/wirings/channel/local/index.ts +3 -3
  337. package/src/wirings/channel/local/local-channel-runner.test.ts +57 -7
  338. package/src/wirings/channel/local/local-channel-runner.ts +40 -19
  339. package/src/wirings/channel/local/local-eventhub-service.test.ts +2 -2
  340. package/src/wirings/channel/local/local-eventhub-service.ts +2 -2
  341. package/src/wirings/channel/log-channels.ts +1 -1
  342. package/src/wirings/channel/pikku-abstract-channel-handler.ts +1 -1
  343. package/src/wirings/channel/serverless/index.ts +5 -1
  344. package/src/wirings/channel/serverless/serverless-channel-runner.ts +57 -36
  345. package/src/wirings/cli/channel/cli-channel-runner.ts +1 -1
  346. package/src/wirings/cli/channel/index.ts +1 -1
  347. package/src/wirings/cli/cli-runner.test.ts +10 -10
  348. package/src/wirings/cli/cli-runner.ts +28 -14
  349. package/src/wirings/cli/cli.types.ts +14 -14
  350. package/src/wirings/cli/command-parser.test.ts +9 -9
  351. package/src/wirings/cli/command-parser.ts +1 -1
  352. package/src/wirings/cli/define-cli-commands.ts +24 -0
  353. package/src/wirings/cli/index.ts +10 -4
  354. package/src/wirings/http/http-routes.test.ts +322 -0
  355. package/src/wirings/http/http-routes.ts +198 -0
  356. package/src/wirings/http/http-runner.test.ts +12 -20
  357. package/src/wirings/http/http-runner.ts +101 -51
  358. package/src/wirings/http/http.types.ts +119 -48
  359. package/src/wirings/http/index.ts +16 -4
  360. package/src/wirings/http/log-http-routes.ts +1 -1
  361. package/src/wirings/http/pikku-fetch-http-request.ts +1 -1
  362. package/src/wirings/http/pikku-fetch-http-response.ts +12 -5
  363. package/src/wirings/http/routers/http-router.ts +1 -1
  364. package/src/wirings/http/routers/path-to-regex.test.ts +1 -1
  365. package/src/wirings/http/routers/path-to-regex.ts +4 -3
  366. package/src/wirings/mcp/index.ts +27 -3
  367. package/src/wirings/mcp/mcp-endpoint-registry.test.ts +3 -3
  368. package/src/wirings/mcp/mcp-endpoint-registry.ts +5 -1
  369. package/src/wirings/mcp/mcp-runner.ts +48 -65
  370. package/src/wirings/mcp/mcp.types.ts +5 -5
  371. package/src/wirings/node/index.ts +2 -0
  372. package/src/wirings/node/node.types.ts +23 -0
  373. package/src/wirings/oauth2/index.ts +3 -0
  374. package/src/wirings/oauth2/oauth2-client.test.ts +929 -0
  375. package/src/wirings/oauth2/oauth2-client.ts +335 -0
  376. package/src/wirings/oauth2/oauth2.types.ts +69 -0
  377. package/src/wirings/oauth2/wire-oauth2-credential.ts +23 -0
  378. package/src/wirings/queue/index.ts +13 -2
  379. package/src/wirings/queue/queue-runner.test.ts +142 -73
  380. package/src/wirings/queue/queue-runner.ts +18 -14
  381. package/src/wirings/queue/queue.types.ts +5 -5
  382. package/src/wirings/queue/register-queue-helper.ts +3 -5
  383. package/src/wirings/queue/validate-worker-config.test.ts +108 -0
  384. package/src/wirings/queue/validate-worker-config.ts +4 -1
  385. package/src/wirings/rpc/index.ts +3 -1
  386. package/src/wirings/rpc/rpc-runner.ts +254 -41
  387. package/src/wirings/rpc/rpc-types.ts +28 -4
  388. package/src/wirings/rpc/wire-addon.ts +20 -0
  389. package/src/wirings/scheduler/index.ts +6 -4
  390. package/src/wirings/scheduler/log-schedulers.ts +1 -1
  391. package/src/wirings/scheduler/scheduler-runner.test.ts +78 -45
  392. package/src/wirings/scheduler/scheduler-runner.ts +20 -27
  393. package/src/wirings/scheduler/scheduler.types.ts +2 -2
  394. package/src/wirings/secret/index.ts +9 -0
  395. package/src/wirings/secret/secret.types.ts +32 -0
  396. package/src/wirings/secret/validate-secret-definitions.test.ts +140 -0
  397. package/src/wirings/secret/validate-secret-definitions.ts +82 -0
  398. package/src/wirings/trigger/index.ts +10 -2
  399. package/src/wirings/trigger/pikku-trigger-service.ts +112 -0
  400. package/src/wirings/trigger/trigger-runner.test.ts +79 -0
  401. package/src/wirings/trigger/trigger-runner.ts +80 -41
  402. package/src/wirings/trigger/trigger.types.ts +144 -22
  403. package/src/wirings/variable/index.ts +8 -0
  404. package/src/wirings/variable/validate-variable-definitions.test.ts +91 -0
  405. package/src/wirings/variable/validate-variable-definitions.ts +69 -0
  406. package/src/wirings/variable/variable.types.ts +22 -0
  407. package/src/wirings/workflow/dsl/index.ts +1 -0
  408. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +9 -1
  409. package/src/wirings/workflow/dsl/workflow-runner.ts +4 -3
  410. package/src/wirings/workflow/graph/graph-node.ts +1 -6
  411. package/src/wirings/workflow/graph/graph-runner.test.ts +487 -0
  412. package/src/wirings/workflow/graph/graph-runner.ts +496 -374
  413. package/src/wirings/workflow/graph/index.ts +14 -3
  414. package/src/wirings/workflow/graph/template.test.ts +49 -0
  415. package/src/wirings/workflow/graph/template.ts +42 -0
  416. package/src/wirings/workflow/graph/wire-workflow-graph.ts +29 -0
  417. package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -22
  418. package/src/wirings/workflow/index.ts +21 -10
  419. package/src/wirings/workflow/pikku-workflow-service.test.ts +200 -0
  420. package/src/wirings/workflow/pikku-workflow-service.ts +308 -105
  421. package/src/wirings/workflow/workflow-helpers.test.ts +129 -0
  422. package/src/wirings/workflow/workflow-helpers.ts +79 -0
  423. package/src/wirings/workflow/workflow.types.ts +47 -92
  424. package/tsconfig.tsbuildinfo +1 -1
  425. package/dist/wirings/forge-node/forge-node.types.d.ts +0 -120
  426. package/dist/wirings/forge-node/forge-node.types.js +0 -38
  427. package/dist/wirings/forge-node/index.d.ts +0 -1
  428. package/dist/wirings/forge-node/index.js +0 -1
  429. package/dist/wirings/workflow/wire-workflow.d.ts +0 -42
  430. package/dist/wirings/workflow/wire-workflow.js +0 -53
  431. package/dist/wirings/workflow/workflow-utils.d.ts +0 -23
  432. package/dist/wirings/workflow/workflow-utils.js +0 -66
  433. package/src/wirings/forge-node/forge-node.types.ts +0 -135
  434. package/src/wirings/forge-node/index.ts +0 -1
  435. package/src/wirings/workflow/wire-workflow.ts +0 -94
  436. package/src/wirings/workflow/workflow-utils.ts +0 -120
@@ -1,25 +1,30 @@
1
1
  import { runPikkuFunc } from '../../function/function-runner.js'
2
- import { pikkuState } from '../../pikku-state.js'
3
- import { getDurationInMilliseconds } from '../../time-utils.js'
4
2
  import {
5
- CoreConfig,
6
- CoreSingletonServices,
7
- CreateWireServices,
8
- PikkuWire,
9
- SerializedError,
10
- } from '../../types/core.types.js'
11
- import { QueueService } from '../queue/queue.types.js'
3
+ getSingletonServices,
4
+ getCreateWireServices,
5
+ pikkuState,
6
+ } from '../../pikku-state.js'
7
+ import { getDurationInMilliseconds } from '../../time-utils.js'
8
+ import type { PikkuWire, SerializedError } from '../../types/core.types.js'
9
+ import type { QueueService } from '../queue/queue.types.js'
12
10
  import type {
13
11
  PikkuWorkflowWire,
14
12
  StepState,
15
13
  WorkflowRun,
14
+ WorkflowRunWire,
16
15
  WorkflowStatus,
17
16
  WorkflowServiceConfig,
18
17
  WorkflowStepOptions,
19
18
  } from './workflow.types.js'
20
- import { executeGraphStep, runWorkflowGraph } from './graph/graph-runner.js'
21
- import { WorkflowService } from '../../services/workflow-service.js'
22
- import { PikkuError } from '../../errors/error-handler.js'
19
+ import {
20
+ continueGraph,
21
+ executeGraphStep,
22
+ runWorkflowGraph,
23
+ runFromMeta,
24
+ } from './graph/graph-runner.js'
25
+ import type { WorkflowService } from '../../services/workflow-service.js'
26
+ import { PikkuError, addError } from '../../errors/error-handler.js'
27
+ import { RPCNotFoundError } from '../rpc/rpc-runner.js'
23
28
 
24
29
  /**
25
30
  * Exception thrown when workflow needs to pause for async step
@@ -47,6 +52,19 @@ export class WorkflowCancelledException extends Error {
47
52
  }
48
53
  }
49
54
 
55
+ /**
56
+ * Exception thrown when workflow is suspended
57
+ */
58
+ export class WorkflowSuspendedException extends Error {
59
+ constructor(
60
+ public readonly runId: string,
61
+ public readonly reason: string
62
+ ) {
63
+ super(reason || 'Workflow suspended')
64
+ this.name = 'WorkflowSuspendedException'
65
+ }
66
+ }
67
+
50
68
  /**
51
69
  * Error class for workflow not found
52
70
  */
@@ -55,15 +73,20 @@ export class WorkflowNotFoundError extends PikkuError {
55
73
  super(`Workflow not found: ${name}`)
56
74
  }
57
75
  }
76
+ addError(WorkflowNotFoundError, {
77
+ status: 404,
78
+ message: 'Workflow not found.',
79
+ })
58
80
 
59
- /**
60
- * Error class for workflow not found
61
- */
62
- export class WorkflowRunNotFound extends PikkuError {
81
+ export class WorkflowRunNotFoundError extends PikkuError {
63
82
  constructor(runId: string) {
64
83
  super(`Workflow run not found: ${runId}`)
65
84
  }
66
85
  }
86
+ addError(WorkflowRunNotFoundError, {
87
+ status: 404,
88
+ message: 'Workflow run not found.',
89
+ })
67
90
 
68
91
  export class WorkflowServiceNotInitialized extends Error {}
69
92
  export class WorkflowStepNameNotString extends Error {
@@ -72,15 +95,19 @@ export class WorkflowStepNameNotString extends Error {
72
95
  }
73
96
  }
74
97
 
98
+ const WORKFLOW_END_STATES: ReadonlySet<string> = new Set([
99
+ 'completed',
100
+ 'failed',
101
+ 'cancelled',
102
+ 'suspended',
103
+ ])
104
+
75
105
  /**
76
106
  * Abstract workflow state service
77
107
  * Implementations provide pluggable storage backends (SQLite, PostgreSQL, etc.)
78
108
  * Combines orchestration and step execution
79
109
  */
80
110
  export abstract class PikkuWorkflowService implements WorkflowService {
81
- private config: WorkflowServiceConfig | undefined
82
- private singletonServices: CoreSingletonServices | undefined
83
- private createWireServices: CreateWireServices | undefined
84
111
  private inlineRuns = new Set<string>()
85
112
 
86
113
  constructor() {}
@@ -106,34 +133,20 @@ export abstract class PikkuWorkflowService implements WorkflowService {
106
133
  this.inlineRuns.delete(runId)
107
134
  }
108
135
 
109
- public setServices(
110
- singletonServices: CoreSingletonServices,
111
- createWireServices: CreateWireServices,
112
- { workflow }: CoreConfig
113
- ) {
114
- this.singletonServices = singletonServices
115
- this.createWireServices = createWireServices
116
- this.config = {
117
- retries: workflow?.retries ?? 0,
118
- retryDelay: workflow?.retryDelay ?? 0,
119
- orchestratorQueueName:
120
- workflow?.orchestratorQueueName ?? 'pikku-workflow-orchestrator',
121
- stepWorkerQueueName:
122
- workflow?.stepWorkerQueueName ?? 'pikku-workflow-step-worker',
123
- sleeperRPCName: workflow?.sleeperRPCName ?? 'pikkuWorkflowSleeper',
136
+ public async registerWorkflowVersions(): Promise<void> {
137
+ const allMeta = pikkuState(null, 'workflows', 'meta')
138
+ for (const [name, meta] of Object.entries(allMeta)) {
139
+ if (!meta.graphHash) continue
140
+ await this.upsertWorkflowVersion(name, meta.graphHash, meta, meta.source)
124
141
  }
125
142
  }
126
143
 
127
- /**
128
- * Create a new workflow run
129
- * @param name - Workflow name
130
- * @param input - Input data for the workflow
131
- * @returns Run ID
132
- */
133
144
  abstract createRun(
134
145
  workflowName: string,
135
146
  input: any,
136
- inline?: boolean
147
+ inline: boolean,
148
+ graphHash: string,
149
+ wire: WorkflowRunWire
137
150
  ): Promise<string>
138
151
 
139
152
  /**
@@ -270,6 +283,7 @@ export abstract class PikkuWorkflowService implements WorkflowService {
270
283
  */
271
284
  abstract getCompletedGraphState(runId: string): Promise<{
272
285
  completedNodeIds: string[]
286
+ failedNodeIds: string[]
273
287
  branchKeys: Record<string, string>
274
288
  }>
275
289
 
@@ -321,6 +335,18 @@ export abstract class PikkuWorkflowService implements WorkflowService {
321
335
  */
322
336
  abstract getRunState(runId: string): Promise<Record<string, unknown>>
323
337
 
338
+ abstract upsertWorkflowVersion(
339
+ name: string,
340
+ graphHash: string,
341
+ graph: any,
342
+ source: string
343
+ ): Promise<void>
344
+
345
+ abstract getWorkflowVersion(
346
+ name: string,
347
+ graphHash: string
348
+ ): Promise<{ graph: any; source: string } | null>
349
+
324
350
  // ============================================================================
325
351
  // Workflow Lifecycle Methods
326
352
  // ============================================================================
@@ -334,6 +360,21 @@ export abstract class PikkuWorkflowService implements WorkflowService {
334
360
  await queueService.add(this.getConfig().orchestratorQueueName, { runId })
335
361
  }
336
362
 
363
+ public async queueStepWorker(
364
+ runId: string,
365
+ stepName: string,
366
+ rpcName: string,
367
+ data: any
368
+ ): Promise<void> {
369
+ const queueService = this.verifyQueueService()
370
+ await queueService.add(this.getConfig().stepWorkerQueueName, {
371
+ runId,
372
+ stepName,
373
+ rpcName,
374
+ data,
375
+ })
376
+ }
377
+
337
378
  /**
338
379
  * Execute a workflow sleep step completion
339
380
  * Sets the step result to null and resumes the workflow
@@ -373,6 +414,7 @@ export abstract class PikkuWorkflowService implements WorkflowService {
373
414
  public async startWorkflow<I>(
374
415
  name: string,
375
416
  input: I,
417
+ wire: WorkflowRunWire,
376
418
  rpcService: any,
377
419
  options?: { inline?: boolean; startNode?: string }
378
420
  ): Promise<{ runId: string }> {
@@ -386,14 +428,16 @@ export abstract class PikkuWorkflowService implements WorkflowService {
386
428
 
387
429
  // Check if this is a graph workflow (source === 'graph')
388
430
  if (workflowMeta.source === 'graph') {
389
- // Graph workflows use the graph scheduler
431
+ const shouldInline =
432
+ options?.inline || !getSingletonServices()?.queueService
390
433
  return runWorkflowGraph(
391
434
  this,
392
435
  name,
393
436
  input,
394
437
  rpcService,
395
- options?.inline,
396
- options?.startNode
438
+ shouldInline,
439
+ options?.startNode,
440
+ wire
397
441
  )
398
442
  }
399
443
 
@@ -405,36 +449,90 @@ export abstract class PikkuWorkflowService implements WorkflowService {
405
449
  throw new WorkflowNotFoundError(name)
406
450
  }
407
451
 
408
- // Create workflow run in state
409
- const runId = await this.createRun(name, input, options?.inline)
452
+ if (!workflowMeta.graphHash) {
453
+ throw new Error(`Missing workflow graphHash for '${name}'`)
454
+ }
455
+
456
+ const runId = await this.createRun(
457
+ name,
458
+ input,
459
+ options?.inline ?? false,
460
+ workflowMeta.graphHash,
461
+ wire
462
+ )
410
463
 
411
- // Register inline run for fast lookup
412
464
  if (options?.inline) {
413
465
  this.inlineRuns.add(runId)
414
466
  }
415
467
 
416
- try {
417
- // If inline mode or no queue service, execute directly
418
- // Otherwise, use remote execution (queue-based)
419
- if (options?.inline || !this.singletonServices?.queueService) {
420
- await this.runWorkflowJob(runId, rpcService)
421
- } else {
422
- await this.resumeWorkflow(runId)
423
- }
468
+ if (options?.inline || !getSingletonServices()?.queueService) {
469
+ this.runWorkflowJob(runId, rpcService)
470
+ .catch(() => {})
471
+ .finally(() => {
472
+ if (options?.inline) {
473
+ this.inlineRuns.delete(runId)
474
+ }
475
+ })
476
+ } else {
477
+ await this.resumeWorkflow(runId)
478
+ }
424
479
 
425
- return { runId }
426
- } finally {
427
- // Clean up inline tracking
428
- if (options?.inline) {
429
- this.inlineRuns.delete(runId)
480
+ return { runId }
481
+ }
482
+
483
+ public async runToCompletion<I>(
484
+ name: string,
485
+ input: I,
486
+ rpcService: any,
487
+ options?: { pollIntervalMs?: number; wire?: WorkflowRunWire }
488
+ ): Promise<any> {
489
+ const pollInterval = options?.pollIntervalMs ?? 1000
490
+ const { runId } = await this.startWorkflow(
491
+ name,
492
+ input,
493
+ options?.wire ?? { type: 'internal' },
494
+ rpcService,
495
+ { inline: true }
496
+ )
497
+ while (true) {
498
+ const run = await this.getRun(runId)
499
+ if (!run) {
500
+ throw new WorkflowRunNotFoundError(runId)
430
501
  }
502
+ if (WORKFLOW_END_STATES.has(run.status)) {
503
+ if (run.status === 'failed') {
504
+ throw new Error(run.error?.message || 'Workflow failed')
505
+ }
506
+ if (run.status === 'cancelled') {
507
+ throw new Error('Workflow was cancelled')
508
+ }
509
+ return run.output
510
+ }
511
+ await new Promise((resolve) => setTimeout(resolve, pollInterval))
431
512
  }
432
513
  }
433
514
 
434
515
  public async runWorkflowJob(runId: string, rpcService: any): Promise<void> {
435
516
  const run = await this.getRun(runId)
436
517
  if (!run) {
437
- throw new WorkflowRunNotFound(runId)
518
+ throw new WorkflowRunNotFoundError(runId)
519
+ }
520
+
521
+ const meta = pikkuState(null, 'workflows', 'meta')
522
+ const workflowMeta = meta[run.workflow]
523
+
524
+ if (
525
+ run.graphHash &&
526
+ workflowMeta?.graphHash &&
527
+ run.graphHash !== workflowMeta.graphHash
528
+ ) {
529
+ await this.runVersionMismatchFallback(run, workflowMeta, rpcService)
530
+ return
531
+ }
532
+
533
+ if (workflowMeta?.source === 'graph') {
534
+ await continueGraph(this, runId, run.workflow)
535
+ return
438
536
  }
439
537
 
440
538
  const registrations = pikkuState(null, 'workflows', 'registrations')
@@ -444,9 +542,6 @@ export abstract class PikkuWorkflowService implements WorkflowService {
444
542
  }
445
543
 
446
544
  await this.withRunLock(runId, async () => {
447
- const meta = pikkuState(null, 'workflows', 'meta')
448
- const workflowMeta = meta[run.workflow]
449
-
450
545
  const workflowWire = this.createWorkflowWire(
451
546
  run.workflow,
452
547
  runId,
@@ -457,11 +552,11 @@ export abstract class PikkuWorkflowService implements WorkflowService {
457
552
  const result = await runPikkuFunc(
458
553
  'workflow',
459
554
  workflowMeta.name,
460
- workflowMeta.pikkuFuncName,
555
+ workflowMeta.pikkuFuncId,
461
556
  {
462
- singletonServices: this.singletonServices!,
557
+ singletonServices: getSingletonServices()!,
463
558
  wire,
464
- createWireServices: this.createWireServices,
559
+ createWireServices: getCreateWireServices(),
465
560
  data: () => run.input,
466
561
  }
467
562
  )
@@ -469,13 +564,10 @@ export abstract class PikkuWorkflowService implements WorkflowService {
469
564
  await this.updateRunStatus(runId, 'completed', result)
470
565
  } catch (error: any) {
471
566
  if (error instanceof WorkflowAsyncException) {
472
- // Normal - workflow paused for step execution
473
567
  throw error
474
568
  }
475
569
 
476
- // Check if it's a WorkflowCancelledException
477
570
  if (error instanceof WorkflowCancelledException) {
478
- // Workflow was cancelled - update status and rethrow
479
571
  await this.updateRunStatus(runId, 'cancelled', undefined, {
480
572
  message: error.message || 'Workflow cancelled',
481
573
  stack: '',
@@ -484,6 +576,15 @@ export abstract class PikkuWorkflowService implements WorkflowService {
484
576
  throw error
485
577
  }
486
578
 
579
+ if (error instanceof WorkflowSuspendedException) {
580
+ await this.updateRunStatus(runId, 'suspended', undefined, {
581
+ message: error.message || 'Workflow suspended',
582
+ stack: '',
583
+ code: 'WORKFLOW_SUSPENDED',
584
+ })
585
+ throw error
586
+ }
587
+
487
588
  await this.updateRunStatus(runId, 'failed', undefined, {
488
589
  message: error.message,
489
590
  stack: error.stack,
@@ -495,6 +596,35 @@ export abstract class PikkuWorkflowService implements WorkflowService {
495
596
  })
496
597
  }
497
598
 
599
+ private async runVersionMismatchFallback(
600
+ run: WorkflowRun,
601
+ currentMeta: { source: string },
602
+ rpcService: any
603
+ ): Promise<void> {
604
+ const source = currentMeta.source
605
+
606
+ if (source === 'complex') {
607
+ await this.updateRunStatus(run.id, 'failed', undefined, {
608
+ message: `Workflow '${run.workflow}' definition changed. Complex workflows with inline steps cannot be migrated.`,
609
+ stack: '',
610
+ code: 'VERSION_CONFLICT',
611
+ })
612
+ return
613
+ }
614
+
615
+ const version = await this.getWorkflowVersion(run.workflow, run.graphHash!)
616
+ if (!version) {
617
+ await this.updateRunStatus(run.id, 'failed', undefined, {
618
+ message: `Workflow '${run.workflow}' version '${run.graphHash}' not found. Cannot resume with changed definition.`,
619
+ stack: '',
620
+ code: 'VERSION_NOT_FOUND',
621
+ })
622
+ return
623
+ }
624
+
625
+ await runFromMeta(this, run.id, version.graph, rpcService)
626
+ }
627
+
498
628
  /**
499
629
  * Execute a single workflow step (called by worker)
500
630
  * Handles idempotency, RPC execution, result storage, retry logic, and orchestrator triggering
@@ -527,24 +657,23 @@ export abstract class PikkuWorkflowService implements WorkflowService {
527
657
  stepState = await this.createRetryAttempt(stepState.stepId, 'running')
528
658
  }
529
659
 
530
- if (stepState.status !== 'pending') {
531
- // Mark step as running (pending or failed status)
660
+ if (stepState.status === 'pending') {
661
+ // Mark pending step as running before execution
532
662
  await this.setStepRunning(stepState.stepId)
533
663
  }
534
664
 
535
665
  try {
536
666
  let result: any
537
667
 
538
- // Check if this is a graph node step (step name starts with 'node:')
539
- if (stepName.startsWith('node:')) {
540
- // Get the graph name from the workflow run
541
- const run = await this.getRun(runId)
542
- if (!run) {
543
- throw new Error(`Workflow run not found: ${runId}`)
544
- }
545
- const graphName = run.workflow
668
+ const run = await this.getRun(runId)
669
+ if (!run) {
670
+ throw new Error(`Workflow run not found: ${runId}`)
671
+ }
672
+
673
+ const meta = pikkuState(null, 'workflows', 'meta')
674
+ const workflowMeta = meta[run.workflow]
546
675
 
547
- // Execute as graph step with graph wire context
676
+ if (workflowMeta?.nodes && stepName in workflowMeta.nodes) {
548
677
  result = await executeGraphStep(
549
678
  this,
550
679
  rpcService,
@@ -553,10 +682,9 @@ export abstract class PikkuWorkflowService implements WorkflowService {
553
682
  stepName,
554
683
  rpcName,
555
684
  data,
556
- graphName
685
+ run.workflow
557
686
  )
558
687
  } else {
559
- // Execute RPC with workflow step context (regular workflow)
560
688
  result = await rpcService.rpcWithWire(rpcName, data, {
561
689
  workflowStep: {
562
690
  runId,
@@ -572,6 +700,15 @@ export abstract class PikkuWorkflowService implements WorkflowService {
572
700
  // Resume orchestrator to continue workflow
573
701
  await this.resumeWorkflow(runId)
574
702
  } catch (error: any) {
703
+ if (error instanceof RPCNotFoundError) {
704
+ await this.setStepError(stepState.stepId, error)
705
+ await this.updateRunStatus(runId, 'suspended', undefined, {
706
+ message: `RPC '${rpcName}' not found. Deploy the missing function and resume.`,
707
+ code: 'RPC_NOT_FOUND',
708
+ })
709
+ return
710
+ }
711
+
575
712
  // Store error and mark failed
576
713
  await this.setStepError(stepState.stepId, error)
577
714
 
@@ -603,7 +740,8 @@ export abstract class PikkuWorkflowService implements WorkflowService {
603
740
  } catch (error: any) {
604
741
  if (
605
742
  error.name === 'WorkflowAsyncException' ||
606
- error.name === 'WorkflowCancelledException'
743
+ error.name === 'WorkflowCancelledException' ||
744
+ error.name === 'WorkflowSuspendedException'
607
745
  ) {
608
746
  return
609
747
  }
@@ -619,13 +757,13 @@ export abstract class PikkuWorkflowService implements WorkflowService {
619
757
  }
620
758
 
621
759
  private verifyQueueService(): QueueService {
622
- if (!this.singletonServices?.queueService) {
760
+ if (!getSingletonServices()?.queueService) {
623
761
  throw new Error(
624
762
  'QueueService not configured. Remote workflows require a queue service.'
625
763
  )
626
764
  }
627
765
 
628
- return this.singletonServices!.queueService
766
+ return getSingletonServices()!.queueService!
629
767
  }
630
768
 
631
769
  private async rpcStep(
@@ -678,12 +816,12 @@ export abstract class PikkuWorkflowService implements WorkflowService {
678
816
  await this.setStepScheduled(stepState.stepId)
679
817
 
680
818
  // Enqueue step worker (unless inline mode)
681
- if (!this.isInline(runId) && this.singletonServices!.queueService) {
819
+ if (!this.isInline(runId) && getSingletonServices()!.queueService) {
682
820
  // Map step retry options to queue job options
683
821
  const retries = stepOptions?.retries ?? 0
684
822
  const retryDelay = stepOptions?.retryDelay
685
823
 
686
- await this.singletonServices!.queueService.add(
824
+ await getSingletonServices()!.queueService!.add(
687
825
  this.getConfig().stepWorkerQueueName,
688
826
  {
689
827
  runId,
@@ -724,6 +862,14 @@ export abstract class PikkuWorkflowService implements WorkflowService {
724
862
  await this.setStepResult(currentStepState.stepId, result)
725
863
  return result
726
864
  } catch (error: any) {
865
+ if (error instanceof RPCNotFoundError) {
866
+ await this.updateRunStatus(runId, 'suspended', undefined, {
867
+ message: `RPC '${rpcName}' not found. Deploy the missing function and resume.`,
868
+ code: 'RPC_NOT_FOUND',
869
+ })
870
+ throw error
871
+ }
872
+
727
873
  // Record the error (marks step as failed)
728
874
  await this.setStepError(currentStepState.stepId, error)
729
875
 
@@ -766,8 +912,8 @@ export abstract class PikkuWorkflowService implements WorkflowService {
766
912
  stepState = await this.insertStepState(
767
913
  runId,
768
914
  stepName,
769
- null, // No RPC for inline steps
770
- null, // No data for inline steps
915
+ null,
916
+ null,
771
917
  stepOptions
772
918
  )
773
919
  }
@@ -852,13 +998,9 @@ export abstract class PikkuWorkflowService implements WorkflowService {
852
998
  stepState = await this.getStepState(runId, stepName)
853
999
  } catch {
854
1000
  // Step doesn't exist - create it (sleep step, no RPC)
855
- stepState = await this.insertStepState(
856
- runId,
857
- stepName,
858
- null, // No RPC for sleep steps
859
- { duration }, // Store duration as data
860
- undefined // No retry options for sleep
861
- )
1001
+ stepState = await this.insertStepState(runId, stepName, null, {
1002
+ duration,
1003
+ })
862
1004
  }
863
1005
 
864
1006
  if (stepState.status === 'succeeded') {
@@ -875,9 +1017,9 @@ export abstract class PikkuWorkflowService implements WorkflowService {
875
1017
  await this.setStepScheduled(stepState.stepId)
876
1018
 
877
1019
  // Check if inline mode or no scheduler service
878
- if (!this.isInline(runId) && this.singletonServices!.schedulerService) {
1020
+ if (!this.isInline(runId) && getSingletonServices()!.schedulerService) {
879
1021
  // Remote mode - schedule sleep via scheduler service
880
- await this.singletonServices!.schedulerService.scheduleRPC(
1022
+ await getSingletonServices()!.schedulerService!.scheduleRPC(
881
1023
  duration,
882
1024
  this.getConfig().sleeperRPCName,
883
1025
  {
@@ -897,13 +1039,63 @@ export abstract class PikkuWorkflowService implements WorkflowService {
897
1039
  }
898
1040
  }
899
1041
 
1042
+ private getSuspendStepName(reason: string): string {
1043
+ if (!reason) {
1044
+ return '__workflow_suspend'
1045
+ }
1046
+ return '__workflow_suspend'
1047
+ }
1048
+
1049
+ private async suspendStep(runId: string, reason: string): Promise<void> {
1050
+ const stepName = this.getSuspendStepName(reason)
1051
+ await this.withStepLock(runId, stepName, async () => {
1052
+ let stepState: StepState
1053
+ try {
1054
+ stepState = await this.getStepState(runId, stepName)
1055
+ } catch {
1056
+ stepState = await this.insertStepState(
1057
+ runId,
1058
+ stepName,
1059
+ 'pikkuWorkflowSuspend',
1060
+ {
1061
+ reason,
1062
+ }
1063
+ )
1064
+ }
1065
+ if (!stepState.stepId) {
1066
+ stepState = await this.insertStepState(
1067
+ runId,
1068
+ stepName,
1069
+ 'pikkuWorkflowSuspend',
1070
+ {
1071
+ reason,
1072
+ }
1073
+ )
1074
+ }
1075
+
1076
+ if (stepState.status === 'succeeded') {
1077
+ return
1078
+ }
1079
+
1080
+ if (stepState.status === 'pending') {
1081
+ await this.setStepRunning(stepState.stepId)
1082
+ }
1083
+
1084
+ await this.setStepResult(stepState.stepId, {
1085
+ reason,
1086
+ suspendedAt: new Date().toISOString(),
1087
+ })
1088
+ throw new WorkflowSuspendedException(runId, reason)
1089
+ })
1090
+ }
1091
+
900
1092
  private createWorkflowWire(
901
- workflowName: string,
1093
+ name: string,
902
1094
  runId: string,
903
1095
  rpcService: any
904
1096
  ): PikkuWorkflowWire {
905
1097
  const workflowWire: PikkuWorkflowWire = {
906
- workflowName,
1098
+ name,
907
1099
  runId,
908
1100
  getRun: async () => (await this.getRun(runId)) as WorkflowRun,
909
1101
 
@@ -943,6 +1135,10 @@ export abstract class PikkuWorkflowService implements WorkflowService {
943
1135
  getDurationInMilliseconds(duration)
944
1136
  )
945
1137
  },
1138
+
1139
+ suspend: async (reason: string) => {
1140
+ await this.suspendStep(runId, reason || 'Workflow suspended')
1141
+ },
946
1142
  }
947
1143
  return workflowWire
948
1144
  }
@@ -953,10 +1149,17 @@ export abstract class PikkuWorkflowService implements WorkflowService {
953
1149
  }
954
1150
  }
955
1151
 
956
- private getConfig() {
957
- if (!this.singletonServices || !this.config) {
958
- throw new WorkflowServiceNotInitialized()
1152
+ private getConfig(): WorkflowServiceConfig {
1153
+ const singletonServices = getSingletonServices()
1154
+ const workflow = singletonServices.config?.workflow
1155
+ return {
1156
+ retries: workflow?.retries ?? 0,
1157
+ retryDelay: workflow?.retryDelay ?? 0,
1158
+ orchestratorQueueName:
1159
+ workflow?.orchestratorQueueName ?? 'pikku-workflow-orchestrator',
1160
+ stepWorkerQueueName:
1161
+ workflow?.stepWorkerQueueName ?? 'pikku-workflow-step-worker',
1162
+ sleeperRPCName: workflow?.sleeperRPCName ?? 'pikkuWorkflowSleeper',
959
1163
  }
960
- return this.config
961
1164
  }
962
1165
  }