@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,8 +1,13 @@
1
- import { SerializedError, CommonWireMeta } from '../../types/core.types.js';
2
- import { CorePikkuFunctionConfig } from '../../function/functions.types.js';
1
+ import type { SerializedError, CommonWireMeta } from '../../types/core.types.js';
2
+ import type { CorePikkuFunctionConfig } from '../../function/functions.types.js';
3
3
  export type { WorkflowService } from '../../services/workflow-service.js';
4
- export type { WorkflowStepOptions, WorkflowWireDoRPC, WorkflowWireDoInline, WorkflowWireSleep, InputSource, OutputBinding, RpcStepMeta, SimpleCondition, Condition, BranchCase, BranchStepMeta, ParallelGroupStepMeta, FanoutStepMeta, ReturnStepMeta, InlineStepMeta, SleepStepMeta, CancelStepMeta, SetStepMeta, SwitchCaseMeta, SwitchStepMeta, FilterStepMeta, ArrayPredicateStepMeta, WorkflowStepMeta, WorkflowStepWire, PikkuWorkflowWire, } from './dsl/workflow-dsl.types.js';
4
+ export type { WorkflowStepOptions, WorkflowWireDoRPC, WorkflowWireDoInline, WorkflowWireSleep, WorkflowWireSuspend, InputSource, OutputBinding, RpcStepMeta, SimpleCondition, Condition, BranchCase, BranchStepMeta, ParallelGroupStepMeta, FanoutStepMeta, ReturnStepMeta, InlineStepMeta, SleepStepMeta, CancelStepMeta, SetStepMeta, SwitchCaseMeta, SwitchStepMeta, FilterStepMeta, ArrayPredicateStepMeta, WorkflowStepMeta, WorkflowStepWire, PikkuWorkflowWire, } from './dsl/workflow-dsl.types.js';
5
5
  import type { WorkflowStepMeta } from './dsl/workflow-dsl.types.js';
6
+ export interface WorkflowRunWire {
7
+ type: string;
8
+ id?: string;
9
+ parentRunId?: string;
10
+ }
6
11
  export interface WorkflowServiceConfig {
7
12
  retries: number;
8
13
  retryDelay: number;
@@ -10,99 +15,14 @@ export interface WorkflowServiceConfig {
10
15
  stepWorkerQueueName: string;
11
16
  sleeperRPCName: string;
12
17
  }
13
- /**
14
- * HTTP wire configuration for workflows
15
- */
16
- export interface WorkflowHTTPWire {
17
- route: string;
18
- method: 'get' | 'post' | 'put' | 'patch' | 'delete';
19
- startNode: string;
20
- }
21
- /**
22
- * Channel wire configuration for workflows
23
- */
24
- export interface WorkflowChannelWire {
25
- name: string;
26
- onConnect?: string;
27
- onDisconnect?: string;
28
- onMessage?: string;
29
- }
30
- /**
31
- * Queue wire configuration for workflows
32
- */
33
- export interface WorkflowQueueWire {
34
- name: string;
35
- startNode: string;
36
- }
37
- /**
38
- * CLI wire configuration for workflows
39
- */
40
- export interface WorkflowCliWire {
41
- command: string;
42
- startNode: string;
43
- }
44
- /**
45
- * MCP wire configurations for workflows
46
- */
47
- export interface WorkflowMcpWires {
48
- tool?: Array<{
49
- name: string;
50
- startNode: string;
51
- }>;
52
- prompt?: Array<{
53
- name: string;
54
- startNode: string;
55
- }>;
56
- resource?: Array<{
57
- uri: string;
58
- startNode: string;
59
- }>;
60
- }
61
- /**
62
- * Schedule wire configuration for workflows
63
- */
64
- export interface WorkflowScheduleWire {
65
- cron?: string;
66
- interval?: string;
67
- startNode: string;
68
- }
69
- /**
70
- * Trigger wire configuration for workflows
71
- */
72
- export interface WorkflowTriggerWire {
73
- name: string;
74
- startNode: string;
75
- }
76
- /**
77
- * Wire configuration for workflows
78
- * Defines how a workflow can be triggered
79
- */
80
- export interface WorkflowWires {
81
- /** API entry point - node ID for startWorkflow() calls */
82
- api?: string;
83
- /** HTTP triggers */
84
- http?: WorkflowHTTPWire[];
85
- /** Channel triggers */
86
- channel?: WorkflowChannelWire[];
87
- /** Queue triggers */
88
- queue?: WorkflowQueueWire[];
89
- /** CLI triggers */
90
- cli?: WorkflowCliWire[];
91
- /** MCP triggers (tool, prompt, resource) */
92
- mcp?: WorkflowMcpWires;
93
- /** Schedule triggers */
94
- schedule?: WorkflowScheduleWire[];
95
- /** Named trigger wires */
96
- trigger?: WorkflowTriggerWire[];
97
- }
98
18
  /**
99
19
  * Workflow run status
100
20
  */
101
- export type WorkflowStatus = 'running' | 'completed' | 'failed' | 'cancelled';
21
+ export type WorkflowStatus = 'running' | 'suspended' | 'completed' | 'failed' | 'cancelled';
102
22
  /**
103
23
  * Workflow step status
104
24
  */
105
- export type StepStatus = 'pending' | 'running' | 'scheduled' | 'succeeded' | 'failed';
25
+ export type StepStatus = 'pending' | 'running' | 'scheduled' | 'succeeded' | 'failed' | 'suspended';
106
26
  /**
107
27
  * Workflow run representation
108
28
  */
@@ -121,6 +41,10 @@ export interface WorkflowRun {
121
41
  error?: SerializedError;
122
42
  /** If true, workflow executes inline without queues */
123
43
  inline?: boolean;
44
+ /** Graph hash of the workflow definition at run creation time */
45
+ graphHash?: string;
46
+ /** Wire origin info (how this run was started) */
47
+ wire: WorkflowRunWire;
124
48
  /** Creation timestamp */
125
49
  createdAt: Date;
126
50
  /** Last update timestamp */
@@ -157,6 +81,29 @@ export interface StepState {
157
81
  /** Timestamp when step failed */
158
82
  failedAt?: Date;
159
83
  }
84
+ export interface WorkflowRunService {
85
+ listRuns(options?: {
86
+ workflowName?: string;
87
+ status?: string;
88
+ limit?: number;
89
+ offset?: number;
90
+ }): Promise<WorkflowRun[]>;
91
+ getRun(id: string): Promise<WorkflowRun | null>;
92
+ getRunSteps(runId: string): Promise<Array<StepState & {
93
+ stepName: string;
94
+ rpcName?: string;
95
+ data?: any;
96
+ }>>;
97
+ getRunHistory(runId: string): Promise<Array<StepState & {
98
+ stepName: string;
99
+ }>>;
100
+ getDistinctWorkflowNames(): Promise<string[]>;
101
+ getWorkflowVersion(name: string, graphHash: string): Promise<{
102
+ graph: any;
103
+ source: string;
104
+ } | null>;
105
+ deleteRun(id: string): Promise<boolean>;
106
+ }
160
107
  /**
161
108
  * Core workflow definition
162
109
  */
@@ -204,7 +151,7 @@ export type WorkflowContext = Record<string, ContextVariable>;
204
151
  * Workflows metadata for inspector/CLI (DSL step-based format)
205
152
  */
206
153
  export type WorkflowsMeta = Record<string, CommonWireMeta & {
207
- workflowName: string;
154
+ name: string;
208
155
  steps: WorkflowStepMeta[];
209
156
  context?: WorkflowContext;
210
157
  dsl?: boolean;
@@ -218,19 +165,19 @@ export interface WorkflowRuntimeMeta {
218
165
  /** Workflow name (used as key in registrations) */
219
166
  name: string;
220
167
  /** Pikku function name (for execution) */
221
- pikkuFuncName: string;
168
+ pikkuFuncId: string;
222
169
  /** Source type: 'dsl' (serializable), 'complex' (has inline steps), 'graph' */
223
- source?: 'dsl' | 'complex' | 'graph';
170
+ source: 'dsl' | 'complex' | 'graph';
224
171
  /** Optional description */
225
172
  description?: string;
226
173
  /** Tags for organization */
227
174
  tags?: string[];
228
- /** Wires - how the workflow is triggered */
229
- wires?: WorkflowWires;
230
175
  /** Serialized nodes */
231
176
  nodes?: Record<string, any>;
232
177
  /** Entry node IDs for graph workflows (computed at build time) */
233
178
  entryNodeIds?: string[];
179
+ /** Hash of graph topology (nodes, edges, input mappings) */
180
+ graphHash?: string;
234
181
  }
235
182
  /**
236
183
  * Unified workflow runtime metadata map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikku/core",
3
- "version": "0.11.2",
3
+ "version": "0.12.1",
4
4
  "author": "yasser.fadl@gmail.com",
5
5
  "license": "MIT",
6
6
  "module": "dist/index.js",
@@ -26,35 +26,34 @@
26
26
  "./http": "./dist/wirings/http/index.js",
27
27
  "./queue": "./dist/wirings/queue/index.js",
28
28
  "./scheduler": "./dist/wirings/scheduler/index.js",
29
+ "./trigger": "./dist/wirings/trigger/index.js",
29
30
  "./rpc": "./dist/wirings/rpc/index.js",
30
31
  "./mcp": "./dist/wirings/mcp/index.js",
32
+ "./ai-agent": "./dist/wirings/ai-agent/index.js",
31
33
  "./cli": "./dist/wirings/cli/index.js",
32
34
  "./cli/channel": "./dist/wirings/cli/channel/index.js",
33
- "./forge-node": "./dist/wirings/forge-node/index.js",
35
+ "./node": "./dist/wirings/node/index.js",
36
+ "./secret": "./dist/wirings/secret/index.js",
37
+ "./variable": "./dist/wirings/variable/index.js",
38
+ "./oauth2": "./dist/wirings/oauth2/index.js",
34
39
  "./errors": "./dist/errors/index.js",
35
40
  "./services": "./dist/services/index.js",
36
41
  "./services/local-content": "./dist/services/local-content.js",
37
- "./schema": "./dist/schema.js",
38
- "./types": "./dist/types/index.d.ts"
42
+ "./services/gopass-secrets": "./dist/services/gopass-secrets.js",
43
+ "./internal": "./dist/internal.js",
44
+ "./schema": "./dist/schema.js"
39
45
  },
40
46
  "dependencies": {
41
- "cookie": "^1.0.2",
47
+ "@standard-schema/spec": "^1.1.0",
48
+ "cookie": "^1.1.1",
42
49
  "path-to-regexp": "^8.3.0",
43
50
  "picoquery": "^2.5.0"
44
51
  },
45
52
  "devDependencies": {
46
- "@types/node": "^24.10.1",
47
- "tsx": "^4.20.6",
53
+ "@types/node": "^24.10.12",
54
+ "tsx": "^4.21.0",
48
55
  "typescript": "^5.9"
49
56
  },
50
- "peerDependencies": {
51
- "zod": "^4.0.0"
52
- },
53
- "peerDependenciesMeta": {
54
- "zod": {
55
- "optional": true
56
- }
57
- },
58
57
  "engines": {
59
58
  "node": ">=18"
60
59
  }
package/run-tests.sh CHANGED
@@ -34,6 +34,9 @@ files=($(find src -type f -name "*.test.ts"))
34
34
  # Check if any files matched the pattern
35
35
  if [ ${#files[@]} -eq 0 ]; then
36
36
  echo "No test files found matching pattern: $pattern"
37
+ if [ "${STRICT_TEST_DISCOVERY}" = "1" ] || [ "${CI}" = "true" ]; then
38
+ exit 1
39
+ fi
37
40
  exit 0
38
41
  fi
39
42
 
@@ -50,4 +53,4 @@ if [ "$coverage_mode" = true ]; then
50
53
  fi
51
54
 
52
55
  # Execute the node command with the expanded list of files
53
- $node_cmd "${files[@]}"
56
+ $node_cmd "${files[@]}"
@@ -0,0 +1,116 @@
1
+ import { describe, test } from 'node:test'
2
+ import assert from 'node:assert'
3
+ import { encryptJSON, decryptJSON } from './crypto-utils.js'
4
+
5
+ describe('encryptJSON / decryptJSON', () => {
6
+ const secret = 'test-secret-key-for-encryption'
7
+
8
+ test('should round-trip a simple object', async () => {
9
+ const original = { hello: 'world', num: 42 }
10
+ const encrypted = await encryptJSON(secret, original)
11
+ const decrypted = await decryptJSON(secret, encrypted)
12
+ assert.deepStrictEqual(decrypted, original)
13
+ })
14
+
15
+ test('should round-trip a string value', async () => {
16
+ const original = 'just a string'
17
+ const encrypted = await encryptJSON(secret, original)
18
+ const decrypted = await decryptJSON(secret, encrypted)
19
+ assert.strictEqual(decrypted, original)
20
+ })
21
+
22
+ test('should round-trip a number', async () => {
23
+ const original = 12345
24
+ const encrypted = await encryptJSON(secret, original)
25
+ const decrypted = await decryptJSON(secret, encrypted)
26
+ assert.strictEqual(decrypted, original)
27
+ })
28
+
29
+ test('should round-trip null', async () => {
30
+ const encrypted = await encryptJSON(secret, null)
31
+ const decrypted = await decryptJSON(secret, encrypted)
32
+ assert.strictEqual(decrypted, null)
33
+ })
34
+
35
+ test('should round-trip a boolean', async () => {
36
+ const encrypted = await encryptJSON(secret, true)
37
+ const decrypted = await decryptJSON(secret, encrypted)
38
+ assert.strictEqual(decrypted, true)
39
+ })
40
+
41
+ test('should round-trip a nested object', async () => {
42
+ const original = { user: { id: 1, roles: ['admin', 'user'] }, active: true }
43
+ const encrypted = await encryptJSON(secret, original)
44
+ const decrypted = await decryptJSON(secret, encrypted)
45
+ assert.deepStrictEqual(decrypted, original)
46
+ })
47
+
48
+ test('should round-trip an array', async () => {
49
+ const original = [1, 'two', { three: 3 }]
50
+ const encrypted = await encryptJSON(secret, original)
51
+ const decrypted = await decryptJSON(secret, encrypted)
52
+ assert.deepStrictEqual(decrypted, original)
53
+ })
54
+
55
+ test('should produce different ciphertexts for same input (random IV)', async () => {
56
+ const value = { same: 'data' }
57
+ const enc1 = await encryptJSON(secret, value)
58
+ const enc2 = await encryptJSON(secret, value)
59
+ assert.notStrictEqual(enc1, enc2)
60
+ })
61
+
62
+ test('should produce a base64url string (no +, /, or = characters)', async () => {
63
+ const encrypted = await encryptJSON(secret, { test: 'base64url' })
64
+ assert.ok(!/[+/=]/.test(encrypted), `Expected base64url, got: ${encrypted}`)
65
+ })
66
+
67
+ test('should fail to decrypt with wrong secret', async () => {
68
+ const encrypted = await encryptJSON(secret, { data: 'sensitive' })
69
+ await assert.rejects(
70
+ () => decryptJSON('wrong-secret', encrypted),
71
+ (err: any) => err instanceof Error
72
+ )
73
+ })
74
+
75
+ test('should reject an invalid encrypted payload (too short)', async () => {
76
+ await assert.rejects(() => decryptJSON(secret, 'dG9vc2hvcnQ'), {
77
+ message: 'Invalid encrypted payload',
78
+ })
79
+ })
80
+
81
+ test('should reject empty string', async () => {
82
+ await assert.rejects(() => decryptJSON(secret, ''), {
83
+ message: 'Invalid encrypted payload',
84
+ })
85
+ })
86
+
87
+ test('should reject corrupted ciphertext', async () => {
88
+ const encrypted = await encryptJSON(secret, { data: 'test' })
89
+ const corrupted = encrypted.slice(0, -4) + 'XXXX'
90
+ await assert.rejects(
91
+ () => decryptJSON(secret, corrupted),
92
+ (err: any) => err instanceof Error
93
+ )
94
+ })
95
+
96
+ test('should handle unicode content', async () => {
97
+ const original = { emoji: '🎉', japanese: 'こんにちは', arabic: 'مرحبا' }
98
+ const encrypted = await encryptJSON(secret, original)
99
+ const decrypted = await decryptJSON(secret, encrypted)
100
+ assert.deepStrictEqual(decrypted, original)
101
+ })
102
+
103
+ test('should handle empty object', async () => {
104
+ const original = {}
105
+ const encrypted = await encryptJSON(secret, original)
106
+ const decrypted = await decryptJSON(secret, encrypted)
107
+ assert.deepStrictEqual(decrypted, original)
108
+ })
109
+
110
+ test('should handle large payload', async () => {
111
+ const original = { data: 'x'.repeat(10000) }
112
+ const encrypted = await encryptJSON(secret, original)
113
+ const decrypted = await decryptJSON(secret, encrypted)
114
+ assert.deepStrictEqual(decrypted, original)
115
+ })
116
+ })
@@ -0,0 +1,99 @@
1
+ const encoder = new TextEncoder()
2
+ const decoder = new TextDecoder()
3
+
4
+ const getSubtle = () => {
5
+ const crypto = globalThis.crypto
6
+ if (!crypto?.subtle) {
7
+ throw new Error('WebCrypto not available')
8
+ }
9
+ return crypto.subtle
10
+ }
11
+
12
+ const base64Encode = (bytes: Uint8Array): string => {
13
+ if (typeof Buffer !== 'undefined') {
14
+ return Buffer.from(bytes).toString('base64')
15
+ }
16
+ let binary = ''
17
+ for (let i = 0; i < bytes.length; i++) {
18
+ binary += String.fromCharCode(bytes[i]!)
19
+ }
20
+ return btoa(binary)
21
+ }
22
+
23
+ const base64Decode = (input: string): Uint8Array => {
24
+ if (typeof Buffer !== 'undefined') {
25
+ return new Uint8Array(Buffer.from(input, 'base64'))
26
+ }
27
+ const binary = atob(input)
28
+ const bytes = new Uint8Array(binary.length)
29
+ for (let i = 0; i < binary.length; i++) {
30
+ bytes[i] = binary.charCodeAt(i)
31
+ }
32
+ return bytes
33
+ }
34
+
35
+ const toBase64Url = (bytes: Uint8Array): string => {
36
+ return base64Encode(bytes)
37
+ .replace(/\+/g, '-')
38
+ .replace(/\//g, '_')
39
+ .replace(/=+$/g, '')
40
+ }
41
+
42
+ const fromBase64Url = (input: string): Uint8Array => {
43
+ let base64 = input.replace(/-/g, '+').replace(/_/g, '/')
44
+ while (base64.length % 4 !== 0) base64 += '='
45
+ return base64Decode(base64)
46
+ }
47
+
48
+ const deriveKey = async (secret: string): Promise<CryptoKey> => {
49
+ const subtle = getSubtle()
50
+ const hash = await subtle.digest('SHA-256', encoder.encode(secret))
51
+ return subtle.importKey('raw', hash, { name: 'AES-GCM' }, false, [
52
+ 'encrypt',
53
+ 'decrypt',
54
+ ])
55
+ }
56
+
57
+ export const encryptJSON = async (
58
+ secret: string,
59
+ value: unknown
60
+ ): Promise<string> => {
61
+ const crypto = globalThis.crypto
62
+ if (!crypto?.getRandomValues) {
63
+ throw new Error('WebCrypto not available')
64
+ }
65
+ const subtle = getSubtle()
66
+ const iv = crypto.getRandomValues(new Uint8Array(12))
67
+ const key = await deriveKey(secret)
68
+ const plaintext = encoder.encode(JSON.stringify(value))
69
+ const encrypted = await subtle.encrypt(
70
+ { name: 'AES-GCM', iv },
71
+ key,
72
+ plaintext
73
+ )
74
+ const cipherBytes = new Uint8Array(encrypted)
75
+ const out = new Uint8Array(iv.length + cipherBytes.length)
76
+ out.set(iv, 0)
77
+ out.set(cipherBytes, iv.length)
78
+ return toBase64Url(out)
79
+ }
80
+
81
+ export const decryptJSON = async <T>(
82
+ secret: string,
83
+ token: string
84
+ ): Promise<T> => {
85
+ const subtle = getSubtle()
86
+ const data = fromBase64Url(token)
87
+ if (data.length < 13) {
88
+ throw new Error('Invalid encrypted payload')
89
+ }
90
+ const iv = data.slice(0, 12)
91
+ const ciphertext = data.slice(12)
92
+ const key = await deriveKey(secret)
93
+ const decrypted = await subtle.decrypt(
94
+ { name: 'AES-GCM', iv },
95
+ key,
96
+ ciphertext
97
+ )
98
+ return JSON.parse(decoder.decode(new Uint8Array(decrypted))) as T
99
+ }
@@ -1,7 +1,75 @@
1
1
  import { test, describe } from 'node:test'
2
2
  import assert from 'assert'
3
- import { getErrorResponse, addError } from './error-handler.js'
4
- import { ForbiddenError, BadRequestError, NotFoundError } from './errors.js'
3
+ import {
4
+ getErrorResponse,
5
+ addError,
6
+ addErrors,
7
+ PikkuError,
8
+ } from './error-handler.js'
9
+ import {
10
+ BadRequestError,
11
+ UnauthorizedError,
12
+ MissingSessionError,
13
+ InvalidSessionError,
14
+ PaymentRequiredError,
15
+ ForbiddenError,
16
+ InvalidOriginError,
17
+ NotFoundError,
18
+ MethodNotAllowedError,
19
+ NotAcceptableError,
20
+ ProxyAuthenticationRequiredError,
21
+ RequestTimeoutError,
22
+ ConflictError,
23
+ GoneError,
24
+ LengthRequiredError,
25
+ PreconditionFailedError,
26
+ PayloadTooLargeError,
27
+ URITooLongError,
28
+ UnsupportedMediaTypeError,
29
+ RangeNotSatisfiableError,
30
+ ExpectationFailedError,
31
+ UnprocessableContentError,
32
+ LockedError,
33
+ TooManyRequestsError,
34
+ InternalServerError,
35
+ NotImplementedError,
36
+ BadGatewayError,
37
+ ServiceUnavailableError,
38
+ GatewayTimeoutError,
39
+ HTTPVersionNotSupportedError,
40
+ MaxComputeTimeReachedError,
41
+ MissingSchemaError,
42
+ InvalidMiddlewareWireError,
43
+ PikkuMissingMetaError,
44
+ } from './errors.js'
45
+
46
+ describe('PikkuError', () => {
47
+ test('should create error with default message', () => {
48
+ const error = new PikkuError()
49
+ assert.strictEqual(error.message, 'An error occurred')
50
+ })
51
+
52
+ test('should create error with custom message', () => {
53
+ const error = new PikkuError('custom message')
54
+ assert.strictEqual(error.message, 'custom message')
55
+ })
56
+
57
+ test('should be instance of Error', () => {
58
+ const error = new PikkuError()
59
+ assert.ok(error instanceof Error)
60
+ })
61
+
62
+ test('should be instance of PikkuError', () => {
63
+ const error = new PikkuError()
64
+ assert.ok(error instanceof PikkuError)
65
+ })
66
+
67
+ test('subclasses should be instanceof PikkuError', () => {
68
+ assert.ok(new BadRequestError() instanceof PikkuError)
69
+ assert.ok(new NotFoundError() instanceof PikkuError)
70
+ assert.ok(new ForbiddenError() instanceof PikkuError)
71
+ })
72
+ })
5
73
 
6
74
  describe('getErrorResponse', () => {
7
75
  test('should return the correct error response for BadRequestError', () => {
@@ -52,3 +120,76 @@ describe('getErrorResponse', () => {
52
120
  assert.deepStrictEqual(response, customErrorDetails)
53
121
  })
54
122
  })
123
+
124
+ describe('addErrors', () => {
125
+ test('should register multiple errors at once', () => {
126
+ class ErrA extends Error {}
127
+ class ErrB extends Error {}
128
+ addErrors([
129
+ [ErrA, { status: 450, message: 'Error A' }],
130
+ [ErrB, { status: 451, message: 'Error B' }],
131
+ ])
132
+ assert.deepStrictEqual(getErrorResponse(new ErrA()), {
133
+ status: 450,
134
+ message: 'Error A',
135
+ })
136
+ assert.deepStrictEqual(getErrorResponse(new ErrB()), {
137
+ status: 451,
138
+ message: 'Error B',
139
+ })
140
+ })
141
+ })
142
+
143
+ describe('all built-in error classes', () => {
144
+ const errorCases: [string, any, number][] = [
145
+ ['InvalidMiddlewareWireError', InvalidMiddlewareWireError, 500],
146
+ ['PikkuMissingMetaError', PikkuMissingMetaError, 500],
147
+ ['BadRequestError', BadRequestError, 400],
148
+ ['UnauthorizedError', UnauthorizedError, 401],
149
+ ['MissingSessionError', MissingSessionError, 401],
150
+ ['InvalidSessionError', InvalidSessionError, 401],
151
+ ['PaymentRequiredError', PaymentRequiredError, 402],
152
+ ['ForbiddenError', ForbiddenError, 403],
153
+ ['InvalidOriginError', InvalidOriginError, 403],
154
+ ['NotFoundError', NotFoundError, 404],
155
+ ['MethodNotAllowedError', MethodNotAllowedError, 405],
156
+ ['NotAcceptableError', NotAcceptableError, 406],
157
+ ['ProxyAuthenticationRequiredError', ProxyAuthenticationRequiredError, 407],
158
+ ['RequestTimeoutError', RequestTimeoutError, 408],
159
+ ['ConflictError', ConflictError, 409],
160
+ ['GoneError', GoneError, 410],
161
+ ['LengthRequiredError', LengthRequiredError, 411],
162
+ ['PreconditionFailedError', PreconditionFailedError, 412],
163
+ ['PayloadTooLargeError', PayloadTooLargeError, 413],
164
+ ['URITooLongError', URITooLongError, 414],
165
+ ['UnsupportedMediaTypeError', UnsupportedMediaTypeError, 415],
166
+ ['RangeNotSatisfiableError', RangeNotSatisfiableError, 416],
167
+ ['ExpectationFailedError', ExpectationFailedError, 417],
168
+ ['UnprocessableContentError', UnprocessableContentError, 422],
169
+ ['LockedError', LockedError, 423],
170
+ ['TooManyRequestsError', TooManyRequestsError, 429],
171
+ ['InternalServerError', InternalServerError, 500],
172
+ ['NotImplementedError', NotImplementedError, 501],
173
+ ['BadGatewayError', BadGatewayError, 502],
174
+ ['ServiceUnavailableError', ServiceUnavailableError, 503],
175
+ ['GatewayTimeoutError', GatewayTimeoutError, 504],
176
+ ['HTTPVersionNotSupportedError', HTTPVersionNotSupportedError, 505],
177
+ ['MaxComputeTimeReachedError', MaxComputeTimeReachedError, 524],
178
+ ['MissingSchemaError', MissingSchemaError, 500],
179
+ ]
180
+
181
+ for (const [name, ErrorClass, expectedStatus] of errorCases) {
182
+ test(`${name} should map to status ${expectedStatus}`, () => {
183
+ const error = new ErrorClass()
184
+ const response = getErrorResponse(error)
185
+ assert.ok(response, `Expected error response for ${name}`)
186
+ assert.strictEqual(response!.status, expectedStatus)
187
+ assert.ok(response!.message.length > 0)
188
+ })
189
+
190
+ test(`${name} should be instance of PikkuError`, () => {
191
+ const error = new ErrorClass()
192
+ assert.ok(error instanceof PikkuError)
193
+ })
194
+ }
195
+ })
@@ -9,6 +9,12 @@ addError(InvalidMiddlewareWireError, {
9
9
  message: 'The middleware wire is invalid for the current wiring type.',
10
10
  })
11
11
 
12
+ export class PikkuMissingMetaError extends PikkuError {}
13
+ addError(PikkuMissingMetaError, {
14
+ status: 500,
15
+ message: 'Required metadata is missing',
16
+ })
17
+
12
18
  /**
13
19
  * The server cannot or will not process the request due to client error (e.g., malformed request syntax).
14
20
  * @group Error
@@ -70,6 +76,16 @@ addError(ForbiddenError, {
70
76
  'The client does not have permission to access the requested resource.',
71
77
  })
72
78
 
79
+ /**
80
+ * The session is readonly and cannot access a non-readonly function.
81
+ * @group Error
82
+ */
83
+ export class ReadonlySessionError extends PikkuError {}
84
+ addError(ReadonlySessionError, {
85
+ status: 403,
86
+ message: 'The session is readonly and cannot access this function.',
87
+ })
88
+
73
89
  /**
74
90
  * The request was made from an origin that is not permitted to access this resource.
75
91
  * @group Error
@@ -345,3 +361,14 @@ addError(MaxComputeTimeReachedError, {
345
361
  message:
346
362
  'The server took too long to complete the request, reaching the maximum compute time allowed.',
347
363
  })
364
+
365
+ /**
366
+ * A required schema was not found during validation.
367
+ * @group Error
368
+ */
369
+ export class MissingSchemaError extends PikkuError {}
370
+ addError(MissingSchemaError, {
371
+ status: 500,
372
+ message:
373
+ 'A required schema was not found. Ensure schema generation has been run.',
374
+ })
@@ -1,2 +1,2 @@
1
- export * from './error-handler.js'
2
1
  export * from './errors.js'
2
+ export { PikkuError, addError, addErrors } from './error-handler.js'