@pikku/core 0.12.72 → 0.12.77

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 (848) hide show
  1. package/CHANGELOG.md +1171 -0
  2. package/dist/column-form.d.ts +32 -0
  3. package/dist/column-form.js +42 -0
  4. package/dist/crypto-utils.d.ts +43 -7
  5. package/dist/crypto-utils.js +163 -42
  6. package/dist/data-classification.d.ts +44 -0
  7. package/dist/dev/hot-reload.js +11 -30
  8. package/dist/dev/module-runner.d.ts +3 -7
  9. package/dist/dev/module-runner.js +4 -10
  10. package/dist/dev/reload-meta.d.ts +8 -20
  11. package/dist/dev/reload-meta.js +9 -29
  12. package/dist/errors/error-handler.d.ts +5 -30
  13. package/dist/errors/error-handler.js +16 -32
  14. package/dist/errors/errors.d.ts +32 -151
  15. package/dist/errors/errors.js +55 -157
  16. package/dist/function/abort-scope.d.ts +47 -0
  17. package/dist/function/abort-scope.js +63 -0
  18. package/dist/function/function-runner.js +37 -32
  19. package/dist/function/functions.types.d.ts +57 -136
  20. package/dist/function/functions.types.js +0 -58
  21. package/dist/function/index.d.ts +1 -1
  22. package/dist/function/list.types.d.ts +12 -62
  23. package/dist/function/list.types.js +4 -25
  24. package/dist/handle-error.d.ts +0 -13
  25. package/dist/handle-error.js +0 -18
  26. package/dist/index.d.ts +11 -5
  27. package/dist/index.js +7 -2
  28. package/dist/middleware/auth-apikey.d.ts +3 -18
  29. package/dist/middleware/auth-apikey.js +0 -17
  30. package/dist/middleware/auth-bearer.d.ts +6 -41
  31. package/dist/middleware/auth-bearer.js +5 -41
  32. package/dist/middleware/auth-cookie.d.ts +5 -27
  33. package/dist/middleware/auth-cookie.js +2 -26
  34. package/dist/middleware/cors.d.ts +7 -34
  35. package/dist/middleware/cors.js +7 -34
  36. package/dist/middleware/remote-auth.d.ts +3 -1
  37. package/dist/middleware/remote-auth.js +4 -3
  38. package/dist/middleware/telemetry.d.ts +8 -33
  39. package/dist/middleware/telemetry.js +2 -31
  40. package/dist/middleware-runner.d.ts +4 -55
  41. package/dist/middleware-runner.js +5 -74
  42. package/dist/permissions.d.ts +3 -44
  43. package/dist/permissions.js +19 -71
  44. package/dist/pikku-request.d.ts +0 -6
  45. package/dist/pikku-request.js +0 -6
  46. package/dist/pikku-state.d.ts +0 -26
  47. package/dist/pikku-state.js +2 -30
  48. package/dist/remote.d.ts +3 -5
  49. package/dist/remote.js +9 -8
  50. package/dist/schema.d.ts +5 -39
  51. package/dist/schema.js +5 -39
  52. package/dist/scopes.d.ts +4 -23
  53. package/dist/scopes.js +7 -48
  54. package/dist/secret-value.d.ts +56 -0
  55. package/dist/secret-value.js +46 -0
  56. package/dist/services/ai-agent-runner-service.d.ts +20 -0
  57. package/dist/services/ai-embedding-service.d.ts +2 -25
  58. package/dist/services/audit-service.d.ts +74 -4
  59. package/dist/services/audit-service.js +8 -7
  60. package/dist/services/content-service.d.ts +1 -46
  61. package/dist/services/credential-service.d.ts +3 -40
  62. package/dist/services/credential-wire-service.d.ts +5 -0
  63. package/dist/services/credential-wire-service.js +9 -1
  64. package/dist/services/deployment-service.d.ts +3 -9
  65. package/dist/services/email-service.d.ts +2 -1
  66. package/dist/services/gateway-service.d.ts +0 -15
  67. package/dist/services/http-personas.d.ts +80 -0
  68. package/dist/services/http-personas.js +233 -0
  69. package/dist/services/in-memory-queue-service.d.ts +0 -14
  70. package/dist/services/in-memory-queue-service.js +1 -15
  71. package/dist/services/in-memory-trigger-service.d.ts +0 -18
  72. package/dist/services/in-memory-trigger-service.js +1 -18
  73. package/dist/services/in-memory-workflow-service.d.ts +0 -16
  74. package/dist/services/in-memory-workflow-service.js +4 -33
  75. package/dist/services/index.d.ts +8 -9
  76. package/dist/services/index.js +3 -6
  77. package/dist/services/istanbul-coverage-service.d.ts +1 -5
  78. package/dist/services/istanbul-coverage-service.js +2 -8
  79. package/dist/services/jwt-service.d.ts +1 -16
  80. package/dist/services/local-content-request-handler.d.ts +29 -0
  81. package/dist/services/local-content-request-handler.js +176 -0
  82. package/dist/services/local-content.d.ts +13 -2
  83. package/dist/services/local-content.js +40 -13
  84. package/dist/services/local-gateway-service.d.ts +0 -16
  85. package/dist/services/local-gateway-service.js +2 -17
  86. package/dist/services/local-secrets.d.ts +4 -7
  87. package/dist/services/local-secrets.js +7 -7
  88. package/dist/services/logger-console.d.ts +3 -7
  89. package/dist/services/logger-console.js +3 -7
  90. package/dist/services/logger.d.ts +22 -40
  91. package/dist/services/meta-service.d.ts +23 -26
  92. package/dist/services/meta-service.js +22 -36
  93. package/dist/services/personas-service.d.ts +134 -0
  94. package/dist/services/personas-service.js +40 -0
  95. package/dist/services/pikku-user-id.js +0 -4
  96. package/dist/services/queue-webhook-service.d.ts +2 -36
  97. package/dist/services/queue-webhook-service.js +10 -42
  98. package/dist/services/scheduler-service.d.ts +1 -50
  99. package/dist/services/scheduler-service.js +0 -10
  100. package/dist/services/schema-service.d.ts +1 -24
  101. package/dist/services/scope-service.d.ts +49 -34
  102. package/dist/services/scoped-secret-service.d.ts +4 -7
  103. package/dist/services/scoped-secret-service.js +0 -4
  104. package/dist/services/secret-host-binding.d.ts +8 -0
  105. package/dist/services/secret-host-binding.js +36 -0
  106. package/dist/services/secret-service.d.ts +12 -35
  107. package/dist/services/secretless.d.ts +6 -0
  108. package/dist/services/secretless.js +21 -0
  109. package/dist/services/stub-tracker.d.ts +7 -18
  110. package/dist/services/stub-tracker.js +8 -18
  111. package/dist/services/system-role-guard.d.ts +33 -0
  112. package/dist/services/system-role-guard.js +38 -0
  113. package/dist/services/trigger-service.d.ts +0 -12
  114. package/dist/services/typed-secret-service.d.ts +5 -11
  115. package/dist/services/typed-secret-service.js +1 -7
  116. package/dist/services/v8-coverage-service.d.ts +2 -3
  117. package/dist/services/v8-coverage-service.js +1 -2
  118. package/dist/services/variables-service.d.ts +1 -8
  119. package/dist/services/webhook-service.d.ts +21 -64
  120. package/dist/services/webhook-service.js +6 -20
  121. package/dist/services/workflow-service.d.ts +3 -15
  122. package/dist/testing/service-tests.js +6 -23
  123. package/dist/time-utils.d.ts +0 -16
  124. package/dist/time-utils.js +1 -19
  125. package/dist/types/core.types.d.ts +120 -219
  126. package/dist/types/core.types.js +0 -42
  127. package/dist/types/state.types.d.ts +4 -9
  128. package/dist/utils/hmac.d.ts +4 -10
  129. package/dist/utils/hmac.js +4 -10
  130. package/dist/utils/safe-fetch.d.ts +7 -35
  131. package/dist/utils/safe-fetch.js +13 -53
  132. package/dist/utils.d.ts +1 -6
  133. package/dist/utils.js +6 -15
  134. package/dist/wirings/actor-flow/actor-flow.types.d.ts +1 -34
  135. package/dist/wirings/actor-flow/index.d.ts +0 -9
  136. package/dist/wirings/actor-flow/run-conversation.d.ts +5 -5
  137. package/dist/wirings/actor-flow/run-conversation.js +14 -7
  138. package/dist/wirings/ai-agent/ai-agent-agui.d.ts +0 -5
  139. package/dist/wirings/ai-agent/ai-agent-agui.js +46 -12
  140. package/dist/wirings/ai-agent/ai-agent-helpers.d.ts +7 -0
  141. package/dist/wirings/ai-agent/ai-agent-helpers.js +7 -0
  142. package/dist/wirings/ai-agent/ai-agent-interrupt.d.ts +153 -0
  143. package/dist/wirings/ai-agent/ai-agent-interrupt.js +256 -0
  144. package/dist/wirings/ai-agent/ai-agent-memory.js +0 -2
  145. package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +0 -9
  146. package/dist/wirings/ai-agent/ai-agent-model-config.js +1 -9
  147. package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +10 -99
  148. package/dist/wirings/ai-agent/ai-agent-prepare.js +65 -132
  149. package/dist/wirings/ai-agent/ai-agent-registry.d.ts +2 -1
  150. package/dist/wirings/ai-agent/ai-agent-registry.js +5 -1
  151. package/dist/wirings/ai-agent/ai-agent-runner.js +63 -22
  152. package/dist/wirings/ai-agent/ai-agent-stream.d.ts +25 -2
  153. package/dist/wirings/ai-agent/ai-agent-stream.js +180 -64
  154. package/dist/wirings/ai-agent/ai-agent.types.d.ts +124 -4
  155. package/dist/wirings/ai-agent/index.d.ts +6 -4
  156. package/dist/wirings/ai-agent/index.js +5 -4
  157. package/dist/wirings/ai-agent/voice-input.d.ts +59 -1
  158. package/dist/wirings/ai-agent/voice-input.js +90 -12
  159. package/dist/wirings/ai-agent/voice-output.d.ts +69 -1
  160. package/dist/wirings/ai-agent/voice-output.js +162 -50
  161. package/dist/wirings/channel/channel-common.d.ts +7 -20
  162. package/dist/wirings/channel/channel-common.js +7 -21
  163. package/dist/wirings/channel/channel-handler.js +25 -6
  164. package/dist/wirings/channel/channel-host-rpc.d.ts +25 -0
  165. package/dist/wirings/channel/channel-host-rpc.js +38 -0
  166. package/dist/wirings/channel/channel-middleware-runner.d.ts +0 -12
  167. package/dist/wirings/channel/channel-middleware-runner.js +0 -12
  168. package/dist/wirings/channel/channel-rpc-registry.d.ts +31 -0
  169. package/dist/wirings/channel/channel-rpc-registry.js +89 -0
  170. package/dist/wirings/channel/channel-rpc-responder.d.ts +15 -0
  171. package/dist/wirings/channel/channel-rpc-responder.js +71 -0
  172. package/dist/wirings/channel/channel-rpc-service.d.ts +40 -0
  173. package/dist/wirings/channel/channel-rpc-service.js +106 -0
  174. package/dist/wirings/channel/channel-rpc-validators.d.ts +14 -0
  175. package/dist/wirings/channel/channel-rpc-validators.js +30 -0
  176. package/dist/wirings/channel/channel-rpc.d.ts +5 -0
  177. package/dist/wirings/channel/channel-rpc.js +5 -0
  178. package/dist/wirings/channel/channel-rpc.types.d.ts +90 -0
  179. package/dist/wirings/channel/channel-rpc.types.js +50 -0
  180. package/dist/wirings/channel/channel-runner.d.ts +0 -4
  181. package/dist/wirings/channel/channel-runner.js +0 -14
  182. package/dist/wirings/channel/channel-store.d.ts +0 -10
  183. package/dist/wirings/channel/channel.types.d.ts +12 -1
  184. package/dist/wirings/channel/define-channel-routes.d.ts +0 -20
  185. package/dist/wirings/channel/define-channel-routes.js +0 -20
  186. package/dist/wirings/channel/eventhub-service.d.ts +0 -18
  187. package/dist/wirings/channel/index.d.ts +4 -1
  188. package/dist/wirings/channel/index.js +2 -0
  189. package/dist/wirings/channel/local/local-channel-runner.js +3 -1
  190. package/dist/wirings/channel/local/local-eventhub-service.d.ts +0 -33
  191. package/dist/wirings/channel/local/local-eventhub-service.js +2 -36
  192. package/dist/wirings/channel/log-channels.d.ts +0 -4
  193. package/dist/wirings/channel/log-channels.js +0 -4
  194. package/dist/wirings/channel/pikku-abstract-channel-handler.js +6 -0
  195. package/dist/wirings/channel/serverless/serverless-channel-runner.js +2 -5
  196. package/dist/wirings/cli/channel/cli-approval.d.ts +41 -0
  197. package/dist/wirings/cli/channel/cli-approval.js +81 -0
  198. package/dist/wirings/cli/channel/cli-channel-runner.d.ts +0 -4
  199. package/dist/wirings/cli/channel/cli-channel-runner.js +3 -25
  200. package/dist/wirings/cli/channel/cli-raw-channel-runner.d.ts +47 -9
  201. package/dist/wirings/cli/channel/cli-raw-channel-runner.js +24 -16
  202. package/dist/wirings/cli/channel/cli-raw-client-runner.d.ts +38 -0
  203. package/dist/wirings/cli/channel/cli-raw-client-runner.js +129 -0
  204. package/dist/wirings/cli/channel/index.d.ts +5 -0
  205. package/dist/wirings/cli/channel/index.js +2 -0
  206. package/dist/wirings/cli/cli-runner.d.ts +20 -20
  207. package/dist/wirings/cli/cli-runner.js +28 -89
  208. package/dist/wirings/cli/cli.types.d.ts +14 -3
  209. package/dist/wirings/cli/command-parser.d.ts +1 -10
  210. package/dist/wirings/cli/command-parser.js +10 -87
  211. package/dist/wirings/cli/define-cli-commands.d.ts +1 -17
  212. package/dist/wirings/cli/define-cli-commands.js +1 -17
  213. package/dist/wirings/credential/credential.types.d.ts +0 -12
  214. package/dist/wirings/credential/define-credential.d.ts +48 -0
  215. package/dist/wirings/credential/define-credential.js +47 -0
  216. package/dist/wirings/credential/index.d.ts +1 -1
  217. package/dist/wirings/credential/index.js +1 -1
  218. package/dist/wirings/credential/validate-credential-definitions.d.ts +2 -4
  219. package/dist/wirings/gateway/gateway-runner.d.ts +1 -20
  220. package/dist/wirings/gateway/gateway-runner.js +8 -105
  221. package/dist/wirings/gateway/gateway.types.d.ts +7 -80
  222. package/dist/wirings/http/http-routes.d.ts +0 -63
  223. package/dist/wirings/http/http-routes.js +0 -63
  224. package/dist/wirings/http/http-runner.d.ts +0 -99
  225. package/dist/wirings/http/http-runner.js +9 -165
  226. package/dist/wirings/http/http.types.d.ts +14 -55
  227. package/dist/wirings/http/log-http-routes.d.ts +0 -4
  228. package/dist/wirings/http/log-http-routes.js +0 -4
  229. package/dist/wirings/http/pikku-fetch-http-request.d.ts +0 -40
  230. package/dist/wirings/http/pikku-fetch-http-request.js +0 -58
  231. package/dist/wirings/http/pikku-fetch-http-response.js +0 -3
  232. package/dist/wirings/http/routers/path-to-regex.js +2 -13
  233. package/dist/wirings/http/web-request.d.ts +0 -8
  234. package/dist/wirings/http/web-request.js +25 -17
  235. package/dist/wirings/mcp/mcp-runner.d.ts +1 -4
  236. package/dist/wirings/mcp/mcp-runner.js +1 -14
  237. package/dist/wirings/mcp/mcp.types.d.ts +2 -35
  238. package/dist/wirings/oauth2/oauth2.types.d.ts +0 -28
  239. package/dist/wirings/oauth2/oauth2.types.js +0 -3
  240. package/dist/wirings/persona/define-personas.d.ts +32 -0
  241. package/dist/wirings/persona/define-personas.js +31 -0
  242. package/dist/wirings/persona/index.d.ts +21 -0
  243. package/dist/wirings/persona/index.js +17 -0
  244. package/dist/wirings/persona/persona-email.d.ts +37 -0
  245. package/dist/wirings/persona/persona-email.js +69 -0
  246. package/dist/wirings/persona/persona-environments.d.ts +45 -0
  247. package/dist/wirings/persona/persona-environments.js +81 -0
  248. package/dist/wirings/persona/persona-mailbox.d.ts +101 -0
  249. package/dist/wirings/persona/persona-mailbox.js +53 -0
  250. package/dist/wirings/persona/persona.types.d.ts +136 -0
  251. package/dist/wirings/persona/persona.types.js +1 -0
  252. package/dist/wirings/persona/validate-personas.d.ts +53 -0
  253. package/dist/wirings/persona/validate-personas.js +94 -0
  254. package/dist/wirings/queue/index.d.ts +3 -0
  255. package/dist/wirings/queue/index.js +2 -3
  256. package/dist/wirings/queue/queue-identity.d.ts +28 -0
  257. package/dist/wirings/queue/queue-identity.js +103 -0
  258. package/dist/wirings/queue/queue-runner.d.ts +0 -19
  259. package/dist/wirings/queue/queue-runner.js +9 -30
  260. package/dist/wirings/queue/queue.types.d.ts +20 -90
  261. package/dist/wirings/queue/register-queue-helper.d.ts +0 -12
  262. package/dist/wirings/queue/register-queue-helper.js +0 -11
  263. package/dist/wirings/queue/signed-queue-service.d.ts +17 -0
  264. package/dist/wirings/queue/signed-queue-service.js +42 -0
  265. package/dist/wirings/queue/validate-worker-config.d.ts +2 -23
  266. package/dist/wirings/queue/validate-worker-config.js +0 -14
  267. package/dist/wirings/role/define-system-role.d.ts +32 -0
  268. package/dist/wirings/role/define-system-role.js +31 -0
  269. package/dist/wirings/role/index.d.ts +3 -0
  270. package/dist/wirings/role/index.js +2 -0
  271. package/dist/wirings/role/role.types.d.ts +43 -0
  272. package/dist/wirings/role/role.types.js +1 -0
  273. package/dist/wirings/role/validate-role-definitions.d.ts +21 -0
  274. package/dist/wirings/role/validate-role-definitions.js +71 -0
  275. package/dist/wirings/rpc/addon-runner.d.ts +0 -19
  276. package/dist/wirings/rpc/addon-runner.js +0 -51
  277. package/dist/wirings/rpc/remote-addon-auth.d.ts +3 -13
  278. package/dist/wirings/rpc/remote-addon-auth.js +7 -11
  279. package/dist/wirings/rpc/rpc-runner.d.ts +11 -18
  280. package/dist/wirings/rpc/rpc-runner.js +88 -105
  281. package/dist/wirings/rpc/rpc-types.d.ts +7 -6
  282. package/dist/wirings/rpc/wire-addon.d.ts +25 -0
  283. package/dist/wirings/rpc/wire-addon.js +62 -0
  284. package/dist/wirings/rpc/wire-remote-addon.d.ts +3 -28
  285. package/dist/wirings/rpc/wire-remote-addon.js +0 -8
  286. package/dist/wirings/scheduler/log-schedulers.d.ts +0 -4
  287. package/dist/wirings/scheduler/log-schedulers.js +0 -4
  288. package/dist/wirings/scheduler/scheduler-runner.d.ts +0 -1
  289. package/dist/wirings/scheduler/scheduler-runner.js +0 -1
  290. package/dist/wirings/scheduler/scheduler.types.d.ts +1 -14
  291. package/dist/wirings/scope/define-scope.d.ts +32 -0
  292. package/dist/wirings/scope/define-scope.js +31 -0
  293. package/dist/wirings/scope/index.d.ts +1 -1
  294. package/dist/wirings/scope/index.js +1 -1
  295. package/dist/wirings/scope/scope.types.d.ts +7 -9
  296. package/dist/wirings/scope/validate-scope-definitions.d.ts +2 -21
  297. package/dist/wirings/scope/validate-scope-definitions.js +3 -21
  298. package/dist/wirings/secret/index.d.ts +1 -1
  299. package/dist/wirings/secret/index.js +1 -1
  300. package/dist/wirings/secret/secret.types.d.ts +19 -15
  301. package/dist/wirings/secret/secret.types.js +1 -1
  302. package/dist/wirings/secret/validate-secret-definitions.d.ts +2 -4
  303. package/dist/wirings/trigger/trigger-runner.d.ts +0 -27
  304. package/dist/wirings/trigger/trigger-runner.js +1 -24
  305. package/dist/wirings/trigger/trigger.types.d.ts +1 -82
  306. package/dist/wirings/trigger/trigger.types.js +0 -34
  307. package/dist/wirings/variable/index.d.ts +1 -1
  308. package/dist/wirings/variable/index.js +1 -1
  309. package/dist/wirings/variable/validate-variable-definitions.d.ts +2 -4
  310. package/dist/wirings/variable/variable.types.d.ts +1 -13
  311. package/dist/wirings/variable/variable.types.js +1 -1
  312. package/dist/wirings/virtual-user/index.d.ts +30 -0
  313. package/dist/wirings/virtual-user/index.js +10 -0
  314. package/dist/wirings/virtual-user/prepare-virtual-user-run.d.ts +54 -0
  315. package/dist/wirings/virtual-user/prepare-virtual-user-run.js +49 -0
  316. package/dist/wirings/virtual-user/run-virtual-user.d.ts +92 -0
  317. package/dist/wirings/virtual-user/run-virtual-user.js +478 -0
  318. package/dist/wirings/virtual-user/virtual-user-agents.d.ts +38 -0
  319. package/dist/wirings/virtual-user/virtual-user-agents.js +24 -0
  320. package/dist/wirings/virtual-user/virtual-user-catalogue.d.ts +92 -0
  321. package/dist/wirings/virtual-user/virtual-user-catalogue.js +134 -0
  322. package/dist/wirings/virtual-user/virtual-user-derive.d.ts +26 -0
  323. package/dist/wirings/virtual-user/virtual-user-derive.js +137 -0
  324. package/dist/wirings/virtual-user/virtual-user-dispositions.d.ts +79 -0
  325. package/dist/wirings/virtual-user/virtual-user-dispositions.js +128 -0
  326. package/dist/wirings/virtual-user/virtual-user-intents.d.ts +78 -0
  327. package/dist/wirings/virtual-user/virtual-user-intents.js +142 -0
  328. package/dist/wirings/virtual-user/virtual-user-rng.d.ts +24 -0
  329. package/dist/wirings/virtual-user/virtual-user-rng.js +44 -0
  330. package/dist/wirings/virtual-user/virtual-user-run-store.d.ts +90 -0
  331. package/dist/wirings/virtual-user/virtual-user-run-store.js +1 -0
  332. package/dist/wirings/virtual-user/virtual-user-target.d.ts +21 -0
  333. package/dist/wirings/virtual-user/virtual-user-target.js +34 -0
  334. package/dist/wirings/virtual-user/virtual-user.types.d.ts +199 -0
  335. package/dist/wirings/virtual-user/virtual-user.types.js +8 -0
  336. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +19 -15
  337. package/dist/wirings/workflow/dsl/workflow-runner.d.ts +0 -4
  338. package/dist/wirings/workflow/dsl/workflow-runner.js +0 -4
  339. package/dist/wirings/workflow/feature.d.ts +0 -19
  340. package/dist/wirings/workflow/feature.js +0 -19
  341. package/dist/wirings/workflow/graph/graph-node.d.ts +0 -98
  342. package/dist/wirings/workflow/graph/graph-node.js +0 -34
  343. package/dist/wirings/workflow/graph/graph-runner.js +6 -41
  344. package/dist/wirings/workflow/graph/wire-workflow-graph.d.ts +0 -4
  345. package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +0 -58
  346. package/dist/wirings/workflow/graph/workflow-graph.types.js +0 -6
  347. package/dist/wirings/workflow/index.d.ts +5 -7
  348. package/dist/wirings/workflow/index.js +3 -17
  349. package/dist/wirings/workflow/pikku-scenario-service.d.ts +87 -5
  350. package/dist/wirings/workflow/pikku-scenario-service.js +204 -43
  351. package/dist/wirings/workflow/pikku-workflow-service.d.ts +7 -459
  352. package/dist/wirings/workflow/pikku-workflow-service.js +58 -551
  353. package/dist/wirings/workflow/run-timeline.d.ts +0 -47
  354. package/dist/wirings/workflow/run-timeline.js +0 -22
  355. package/dist/wirings/workflow/scenario-cookie-jar.d.ts +0 -23
  356. package/dist/wirings/workflow/scenario-cookie-jar.js +0 -16
  357. package/dist/wirings/workflow/scenario-poll.d.ts +0 -15
  358. package/dist/wirings/workflow/scenario-poll.js +0 -12
  359. package/dist/wirings/workflow/scenario-prose.d.ts +0 -28
  360. package/dist/wirings/workflow/scenario-prose.js +1 -19
  361. package/dist/wirings/workflow/scenario-step-guards.d.ts +0 -13
  362. package/dist/wirings/workflow/scenario-step-guards.js +1 -14
  363. package/dist/wirings/workflow/scenario-step.types.d.ts +84 -12
  364. package/dist/wirings/workflow/scenario-step.types.js +5 -1
  365. package/dist/wirings/workflow/scenario-surface.d.ts +16 -0
  366. package/dist/wirings/workflow/scenario-surface.js +56 -0
  367. package/dist/wirings/workflow/workflow-invocation-id.d.ts +0 -18
  368. package/dist/wirings/workflow/workflow-invocation-id.js +2 -22
  369. package/dist/wirings/workflow/workflow-queue-workers.d.ts +0 -20
  370. package/dist/wirings/workflow/workflow-queue-workers.js +0 -19
  371. package/dist/wirings/workflow/workflow.types.d.ts +5 -195
  372. package/knowledge/decisions/index.md +19 -0
  373. package/knowledge/decisions/internals/a-secret-that-fails-to-decrypt-fails-the-whole-read.md +49 -0
  374. package/knowledge/decisions/internals/a-virtual-user-run-is-not-a-workflow-and-not-a-queued-job.md +48 -0
  375. package/knowledge/decisions/internals/actor-flow-conversations-seed-a-hidden-kickoff-message.md +23 -0
  376. package/knowledge/decisions/internals/actor-flow-drives-the-target-through-a-transport-seam.md +24 -0
  377. package/knowledge/decisions/internals/actor-flow-verdicts-are-llm-self-evaluations.md +25 -0
  378. package/knowledge/decisions/internals/addon-package-roots-resolve-by-walking-node-module-search-paths.md +26 -0
  379. package/knowledge/decisions/internals/addon-singleton-services-are-cached-per-namespace-not-per-package.md +33 -0
  380. package/knowledge/decisions/internals/addon-workflow-names-are-prefixed-with-the-consumer-namespace.md +28 -0
  381. package/knowledge/decisions/internals/ai-agent-agui-bridge-obeys-the-client-ordering-contract.md +29 -0
  382. package/knowledge/decisions/internals/ai-agent-audio-chunks-carry-the-format-the-provider-returned.md +20 -0
  383. package/knowledge/decisions/internals/ai-agent-credential-suspensions-hide-the-tool-result.md +26 -0
  384. package/knowledge/decisions/internals/ai-agent-delegate-and-supervise-hide-different-text.md +26 -0
  385. package/knowledge/decisions/internals/ai-agent-llm-tool-arguments-have-nulls-stripped.md +23 -0
  386. package/knowledge/decisions/internals/ai-agent-model-config-stays-a-single-resolution-seam.md +25 -0
  387. package/knowledge/decisions/internals/ai-agent-onerror-hooks-cannot-change-the-failure.md +22 -0
  388. package/knowledge/decisions/internals/ai-agent-runner-methods-must-keep-their-receiver.md +22 -0
  389. package/knowledge/decisions/internals/ai-agent-stream-persistence-is-best-effort.md +27 -0
  390. package/knowledge/decisions/internals/ai-agent-sub-agents-inherit-the-parent-context-block.md +26 -0
  391. package/knowledge/decisions/internals/ai-agent-tool-execute-failures-are-logged-unconditionally.md +25 -0
  392. package/knowledge/decisions/internals/ai-agent-voice-input-transcribes-audio-parts-in-place.md +22 -0
  393. package/knowledge/decisions/internals/ai-agent-working-memory-is-persisted-only-when-valid.md +25 -0
  394. package/knowledge/decisions/internals/channel-message-handlers-accept-three-config-shapes.md +30 -0
  395. package/knowledge/decisions/internals/channel-middleware-caches-only-statically-resolved-middleware.md +31 -0
  396. package/knowledge/decisions/internals/channel-state-is-per-socket-session-state-is-per-user.md +29 -0
  397. package/knowledge/decisions/internals/channel-user-id-is-persisted-after-onconnect-middleware-runs.md +28 -0
  398. package/knowledge/decisions/internals/cli-option-names-are-camelcase-in-state-and-kebab-on-the-command-line.md +27 -0
  399. package/knowledge/decisions/internals/cli-parse-errors-are-routed-by-message-prefix.md +28 -0
  400. package/knowledge/decisions/internals/cli-stdout-is-reserved-for-machine-readable-output.md +34 -0
  401. package/knowledge/decisions/internals/cli-unknown-long-options-warn-instead-of-failing.md +29 -0
  402. package/knowledge/decisions/internals/core-column-form-is-an-axis-of-its-own.md +84 -0
  403. package/knowledge/decisions/internals/core-data-classification-brand-is-an-optional-property.md +41 -0
  404. package/knowledge/decisions/internals/core-function-runner-restores-the-wire-fields-it-overwrites.md +44 -0
  405. package/knowledge/decisions/internals/core-hot-reload-merges-generated-meta-never-replaces-it.md +39 -0
  406. package/knowledge/decisions/internals/core-hot-reload-owns-its-module-registry.md +42 -0
  407. package/knowledge/decisions/internals/core-middleware-order-is-scope-then-priority.md +39 -0
  408. package/knowledge/decisions/internals/core-schema-defaults-apply-on-every-transport.md +43 -0
  409. package/knowledge/decisions/internals/core-scopes-are-an-and-gate-separate-from-permissions.md +38 -0
  410. package/knowledge/decisions/internals/core-state-is-a-global-map-written-only-at-registration-time.md +44 -0
  411. package/knowledge/decisions/internals/email-meta-is-read-uncached-because-codegen-rewrites-it-mid-session.md +27 -0
  412. package/knowledge/decisions/internals/gateway-adapters-resolve-lazily-and-are-promise-cached.md +32 -0
  413. package/knowledge/decisions/internals/gateway-webhook-challenges-echo-bytes-not-json.md +28 -0
  414. package/knowledge/decisions/internals/gateway-wiring-is-a-meta-wiring-over-http-and-channels.md +31 -0
  415. package/knowledge/decisions/internals/generated-src-paths-in-pikku-meta-are-absolute.md +26 -0
  416. package/knowledge/decisions/internals/http-request-bodies-are-read-once-and-shared.md +32 -0
  417. package/knowledge/decisions/internals/http-route-groups-cascade-config-in-a-fixed-order.md +28 -0
  418. package/knowledge/decisions/internals/http-router-matches-normalized-paths-but-returns-registered-ones.md +30 -0
  419. package/knowledge/decisions/internals/http-runner-logs-through-a-trace-scoped-logger-functions-do-not.md +26 -0
  420. package/knowledge/decisions/internals/http-set-cookie-headers-are-appended-never-joined.md +28 -0
  421. package/knowledge/decisions/internals/http-sse-streams-flush-headers-only-after-middleware.md +32 -0
  422. package/knowledge/decisions/internals/http-wiring-without-metadata-is-skipped-not-fatal.md +26 -0
  423. package/knowledge/decisions/internals/in-a-scenario-a-4xx-is-data-not-an-exception.md +25 -0
  424. package/knowledge/decisions/internals/in-memory-workflow-history-aliases-the-live-step-object.md +26 -0
  425. package/knowledge/decisions/internals/index.md +117 -0
  426. package/knowledge/decisions/internals/istanbul-statement-counts-attach-to-the-start-line-only.md +25 -0
  427. package/knowledge/decisions/internals/local-trigger-and-gateway-services-assume-a-single-process.md +26 -0
  428. package/knowledge/decisions/internals/node-only-builtins-are-imported-dynamically.md +24 -0
  429. package/knowledge/decisions/internals/one-project-shape-check-two-validators.md +53 -0
  430. package/knowledge/decisions/internals/queue-group-concurrency-keeps-one-shared-queue-fair.md +28 -0
  431. package/knowledge/decisions/internals/queue-jobs-always-carry-an-explicit-attempts-count.md +27 -0
  432. package/knowledge/decisions/internals/remote-addons-dispatch-over-http-instead-of-local-meta.md +31 -0
  433. package/knowledge/decisions/internals/rpc-names-resolve-through-package-scope-before-root.md +32 -0
  434. package/knowledge/decisions/internals/scenario-agent-calls-sign-in-on-401-only.md +27 -0
  435. package/knowledge/decisions/internals/scenario-meta-lives-apart-from-app-meta-but-merges-when-read-off-disk.md +26 -0
  436. package/knowledge/decisions/internals/scenario-steps-return-drained-response-records.md +27 -0
  437. package/knowledge/decisions/internals/scenarios-live-in-files-named-for-them.md +48 -0
  438. package/knowledge/decisions/internals/scope-roots-may-be-co-declared-by-an-addon-and-its-host-app.md +30 -0
  439. package/knowledge/decisions/internals/serverless-channel-disconnect-must-tolerate-a-missing-channel.md +28 -0
  440. package/knowledge/decisions/internals/the-dev-queue-copies-prod-timing-and-serialization-semantics.md +30 -0
  441. package/knowledge/decisions/internals/the-embedding-model-is-pinned-per-service-and-doc-query-embedding-is-split.md +29 -0
  442. package/knowledge/decisions/internals/the-in-memory-workflow-service-is-inline-only-and-single-process.md +27 -0
  443. package/knowledge/decisions/internals/the-kek-salt-is-scoped-to-the-key-version.md +40 -0
  444. package/knowledge/decisions/internals/the-schema-service-is-never-stubbed.md +26 -0
  445. package/knowledge/decisions/internals/trigger-declaration-is-split-from-trigger-source.md +33 -0
  446. package/knowledge/decisions/internals/typed-secret-service-caches-for-the-process-lifetime.md +26 -0
  447. package/knowledge/decisions/internals/validate-checks-personas-through-a-shared-module.md +43 -0
  448. package/knowledge/decisions/internals/webhook-delivery-history-records-every-attempt-best-effort.md +26 -0
  449. package/knowledge/decisions/internals/webhook-service-collaborators-are-constructor-args-not-locator-lookups.md +25 -0
  450. package/knowledge/decisions/internals/whether-a-run-is-inline-is-read-from-the-run-record.md +58 -0
  451. package/knowledge/decisions/internals/workflow-approval-expiry-is-decided-from-a-recorded-deadline.md +34 -0
  452. package/knowledge/decisions/internals/workflow-core-never-imports-a-browser-driver.md +42 -0
  453. package/knowledge/decisions/internals/workflow-dsl-meta-separates-runtime-expressions-from-literals.md +38 -0
  454. package/knowledge/decisions/internals/workflow-features-resolve-scenarios-by-object-identity.md +29 -0
  455. package/knowledge/decisions/internals/workflow-graph-inline-and-queued-runs-share-one-planner.md +42 -0
  456. package/knowledge/decisions/internals/workflow-graph-node-notes-are-excluded-from-the-graph-hash.md +25 -0
  457. package/knowledge/decisions/internals/workflow-inline-runs-report-their-run-id-before-they-can-fail.md +29 -0
  458. package/knowledge/decisions/internals/workflow-invocation-id-is-the-dedupe-key-not-step-id.md +43 -0
  459. package/knowledge/decisions/internals/workflow-queued-step-dispatch-requires-an-explicit-opt-in.md +29 -0
  460. package/knowledge/decisions/internals/workflow-queues-are-per-workflow-by-default.md +42 -0
  461. package/knowledge/decisions/internals/workflow-repeated-step-names-get-an-ordinal-suffix.md +33 -0
  462. package/knowledge/decisions/internals/workflow-replay-reads-its-steps-once-and-caches-only-the-immutable-half.md +32 -0
  463. package/knowledge/decisions/internals/workflow-retries-are-owned-by-the-workflow-not-the-queue.md +31 -0
  464. package/knowledge/decisions/internals/workflow-run-capabilities-are-extensions-not-subclasses.md +39 -0
  465. package/knowledge/decisions/internals/workflow-run-mirror-is-never-a-source-of-truth.md +29 -0
  466. package/knowledge/decisions/internals/workflow-run-polling-backs-off-to-the-callers-ceiling.md +33 -0
  467. package/knowledge/decisions/internals/workflow-run-timeline-is-a-pure-fold-over-durable-history.md +37 -0
  468. package/knowledge/decisions/internals/workflow-scenario-assertions-never-retry-and-record-one-step.md +50 -0
  469. package/knowledge/decisions/internals/workflow-scenario-hooks-are-a-scenario-only-affordance.md +43 -0
  470. package/knowledge/decisions/internals/workflow-scenario-prose-is-rendered-from-typed-calls-not-parsed-from-english.md +32 -0
  471. package/knowledge/decisions/internals/workflow-scenario-quarantine-reason-lives-in-code.md +18 -0
  472. package/knowledge/decisions/internals/workflow-scenario-step-targets-are-string-literals-for-the-inspector.md +34 -0
  473. package/knowledge/decisions/internals/workflow-step-compensation-runs-as-its-own-durable-step.md +26 -0
  474. package/knowledge/decisions/internals/workflow-step-dispatch-failure-is-transient-not-a-run-failure.md +33 -0
  475. package/knowledge/decisions/internals/workflow-step-lock-is-held-only-to-claim-the-step.md +27 -0
  476. package/knowledge/decisions/internals/workflow-step-rpc-name-is-provenance-only.md +34 -0
  477. package/knowledge/decisions/internals/workflow-suspend-and-approval-reasons-are-durable-step-identities.md +38 -0
  478. package/knowledge/decisions/internals/workflow-suspended-runs-keep-their-in-process-context.md +30 -0
  479. package/knowledge/decisions/security/a-dropped-audit-write-is-always-logged.md +26 -0
  480. package/knowledge/decisions/security/actor-flow-missing-approval-decisions-default-to-denied.md +22 -0
  481. package/knowledge/decisions/security/actor-sign-in-is-proven-by-set-cookie-not-a-non-empty-jar.md +27 -0
  482. package/knowledge/decisions/security/actor-sign-in-only-works-for-actor-flagged-users.md +27 -0
  483. package/knowledge/decisions/security/addon-auth-and-tags-only-tighten.md +43 -0
  484. package/knowledge/decisions/security/addon-config-gates-apply-only-at-the-namespaced-rpc-boundary.md +52 -0
  485. package/knowledge/decisions/security/addon-scopes-are-resolved-where-the-function-runs.md +46 -0
  486. package/knowledge/decisions/security/ai-agent-approval-forwarding-requires-a-symbol-brand.md +27 -0
  487. package/knowledge/decisions/security/ai-agent-credential-requests-are-symbol-branded.md +37 -0
  488. package/knowledge/decisions/security/ai-agent-gate-requires-a-session-only-when-auth-is-true.md +31 -0
  489. package/knowledge/decisions/security/ai-agent-ownership-failures-never-echo-the-resource.md +23 -0
  490. package/knowledge/decisions/security/ai-agent-resume-re-runs-the-authorization-gate.md +22 -0
  491. package/knowledge/decisions/security/ai-agent-sessionless-deployments-have-no-thread-ownership.md +39 -0
  492. package/knowledge/decisions/security/ai-agent-thread-ownership-composes-the-session-principal.md +30 -0
  493. package/knowledge/decisions/security/ai-agent-tool-filtering-reads-the-live-function-config.md +24 -0
  494. package/knowledge/decisions/security/an-empty-owners-constraint-matches-nothing.md +30 -0
  495. package/knowledge/decisions/security/an-exposed-ungated-function-is-a-codegen-warning.md +49 -0
  496. package/knowledge/decisions/security/console-addon-privileged-functions-gate-themselves.md +76 -0
  497. package/knowledge/decisions/security/core-safe-fetch-blocks-ssrf-by-host-literal-not-dns.md +39 -0
  498. package/knowledge/decisions/security/core-secrets-use-a-per-secret-dek-wrapped-by-a-kek.md +37 -0
  499. package/knowledge/decisions/security/gateway-handlers-run-through-the-function-runner-gate.md +31 -0
  500. package/knowledge/decisions/security/gateway-middleware-sessions-must-be-bridged-onto-the-wire.md +30 -0
  501. package/knowledge/decisions/security/global-permissions-and-function-permissions-are-independent-gates.md +40 -0
  502. package/knowledge/decisions/security/http-error-detail-is-withheld-from-clients-in-production.md +33 -0
  503. package/knowledge/decisions/security/http-request-bodies-are-bounded-before-they-are-buffered.md +46 -0
  504. package/knowledge/decisions/security/index.md +55 -0
  505. package/knowledge/decisions/security/mcp-internal-error-details-are-double-gated-on-production.md +27 -0
  506. package/knowledge/decisions/security/passphrases-are-stretched-key-material-is-expanded.md +40 -0
  507. package/knowledge/decisions/security/permission-auth-filtering-requires-live-permission-functions.md +31 -0
  508. package/knowledge/decisions/security/pikku-carries-actor-scopes-as-data-and-the-app-grants-them.md +26 -0
  509. package/knowledge/decisions/security/queue-job-identities-are-signed-at-enqueue.md +69 -0
  510. package/knowledge/decisions/security/queue-jobs-carry-the-producers-pikku-user-id.md +39 -0
  511. package/knowledge/decisions/security/remote-addon-tokens-are-client-credentials-not-mesh-trust.md +34 -0
  512. package/knowledge/decisions/security/scaffold-features-are-authenticated-unless-opted-out.md +49 -0
  513. package/knowledge/decisions/security/scenario-step-functions-are-never-externally-invocable.md +30 -0
  514. package/knowledge/decisions/security/scope-resolution-happens-at-the-session-boundary-and-sync-never-deletes.md +28 -0
  515. package/knowledge/decisions/security/self-authentication-is-declared-not-detected.md +34 -0
  516. package/knowledge/decisions/security/signed-content-urls-bind-the-request-path.md +37 -0
  517. package/knowledge/decisions/security/webhook-bodies-are-signed-before-they-are-enqueued.md +25 -0
  518. package/knowledge/decisions/security/workflow-actor-steps-always-use-the-real-transport.md +34 -0
  519. package/knowledge/decisions/security/workflow-approval-payloads-are-validated-on-replay-inside-the-workflow.md +40 -0
  520. package/knowledge/decisions/security/workflow-queued-steps-rehydrate-their-session-from-the-run-wire.md +32 -0
  521. package/knowledge/decisions/security/workflow-scenario-sessions-are-isolated-per-actor-and-per-scenario.md +32 -0
  522. package/knowledge/decisions/security/workflow-scenario-steps-are-never-network-invocable.md +31 -0
  523. package/knowledge/index.md +24 -0
  524. package/knowledge/questions/index.md +15 -0
  525. package/package.json +6 -2
  526. package/run-tests.sh +0 -0
  527. package/src/column-form.test.ts +97 -0
  528. package/src/column-form.ts +58 -0
  529. package/src/crypto-utils.test.ts +460 -19
  530. package/src/crypto-utils.ts +306 -59
  531. package/src/data-classification.ts +45 -7
  532. package/src/dev/hot-reload.test.ts +0 -4
  533. package/src/dev/hot-reload.ts +11 -30
  534. package/src/dev/module-runner.ts +7 -32
  535. package/src/dev/reload-meta.ts +9 -29
  536. package/src/errors/error-handler.ts +20 -35
  537. package/src/errors/error.test.ts +30 -1
  538. package/src/errors/errors.ts +73 -157
  539. package/src/function/abort-scope.test.ts +97 -0
  540. package/src/function/abort-scope.ts +80 -0
  541. package/src/function/function-runner.test.ts +0 -7
  542. package/src/function/function-runner.ts +62 -32
  543. package/src/function/functions.types.ts +95 -138
  544. package/src/function/index.ts +1 -0
  545. package/src/function/list.types.test.ts +3 -25
  546. package/src/function/list.types.ts +12 -62
  547. package/src/handle-error.ts +0 -18
  548. package/src/index.ts +84 -3
  549. package/src/middleware/auth-apikey.test.ts +0 -1
  550. package/src/middleware/auth-apikey.ts +0 -17
  551. package/src/middleware/auth-bearer.test.ts +3 -5
  552. package/src/middleware/auth-bearer.ts +5 -41
  553. package/src/middleware/auth-cookie.test.ts +0 -6
  554. package/src/middleware/auth-cookie.ts +2 -26
  555. package/src/middleware/cors.test.ts +34 -0
  556. package/src/middleware/cors.ts +12 -33
  557. package/src/middleware/remote-auth.test.ts +26 -10
  558. package/src/middleware/remote-auth.ts +11 -3
  559. package/src/middleware/telemetry.ts +2 -31
  560. package/src/middleware-runner.test.ts +0 -2
  561. package/src/middleware-runner.ts +5 -74
  562. package/src/permissions.test.ts +30 -0
  563. package/src/permissions.ts +24 -74
  564. package/src/pikku-request.ts +0 -6
  565. package/src/pikku-state.ts +2 -30
  566. package/src/production-barrels-stay-lean.test.ts +110 -0
  567. package/src/remote.test.ts +173 -0
  568. package/src/remote.ts +18 -8
  569. package/src/schema.ts +5 -39
  570. package/src/scopes.ts +7 -48
  571. package/src/secret-value.test.ts +204 -0
  572. package/src/secret-value.ts +111 -0
  573. package/src/services/ai-agent-runner-service.ts +20 -0
  574. package/src/services/ai-embedding-service.ts +3 -25
  575. package/src/services/audit-service.ts +88 -11
  576. package/src/services/content-service.ts +1 -46
  577. package/src/services/credential-service.ts +3 -40
  578. package/src/services/credential-wire-service.test.ts +0 -2
  579. package/src/services/credential-wire-service.ts +9 -1
  580. package/src/services/deployment-service.ts +3 -9
  581. package/src/services/email-service.ts +3 -1
  582. package/src/services/gateway-service.ts +0 -15
  583. package/src/services/{http-scenario-actors-converse.test.ts → http-personas-converse.test.ts} +38 -9
  584. package/src/services/{http-scenario-actors.test.ts → http-personas.test.ts} +39 -22
  585. package/src/services/{http-scenario-actors.ts → http-personas.ts} +85 -45
  586. package/src/services/in-memory-queue-service.ts +1 -15
  587. package/src/services/in-memory-trigger-service.ts +1 -18
  588. package/src/services/in-memory-workflow-service.test.ts +0 -13
  589. package/src/services/in-memory-workflow-service.ts +4 -38
  590. package/src/services/index.ts +23 -18
  591. package/src/services/istanbul-coverage-service.ts +2 -8
  592. package/src/services/jwt-service.ts +1 -16
  593. package/src/services/local-content-request-handler.test.ts +202 -0
  594. package/src/services/local-content-request-handler.ts +267 -0
  595. package/src/services/local-content.test.ts +159 -27
  596. package/src/services/local-content.ts +55 -23
  597. package/src/services/local-gateway-service.ts +2 -17
  598. package/src/services/local-secrets.test.ts +20 -5
  599. package/src/services/local-secrets.ts +15 -11
  600. package/src/services/logger-console.test.ts +0 -1
  601. package/src/services/logger-console.ts +3 -7
  602. package/src/services/logger.ts +31 -46
  603. package/src/services/meta-service.test.ts +1 -5
  604. package/src/services/meta-service.ts +41 -61
  605. package/src/services/{scenario-actors-service.ts → personas-service.ts} +48 -43
  606. package/src/services/pikku-user-id.ts +0 -4
  607. package/src/services/queue-webhook-service.test.ts +2 -1
  608. package/src/services/queue-webhook-service.ts +10 -42
  609. package/src/services/scheduler-service.ts +1 -50
  610. package/src/services/schema-service.ts +1 -24
  611. package/src/services/scope-service.ts +50 -34
  612. package/src/services/scoped-secret-service.ts +4 -7
  613. package/src/services/secret-host-binding.test.ts +138 -0
  614. package/src/services/secret-host-binding.ts +51 -0
  615. package/src/services/secret-service.ts +12 -35
  616. package/src/services/secretless.test.ts +54 -0
  617. package/src/services/secretless.ts +29 -0
  618. package/src/services/stub-tracker.ts +8 -18
  619. package/src/services/system-role-guard.test.ts +93 -0
  620. package/src/services/system-role-guard.ts +71 -0
  621. package/src/services/trigger-service.ts +0 -12
  622. package/src/services/typed-secret-service.ts +12 -14
  623. package/src/services/v8-coverage-service.ts +3 -6
  624. package/src/services/variables-service.ts +1 -8
  625. package/src/services/webhook-service.ts +23 -64
  626. package/src/services/workflow-service.ts +3 -20
  627. package/src/testing/service-tests.ts +6 -32
  628. package/src/time-utils.ts +1 -19
  629. package/src/types/core.types.ts +137 -229
  630. package/src/types/state.types.ts +7 -9
  631. package/src/utils/hmac.ts +4 -10
  632. package/src/utils/safe-fetch.ts +13 -54
  633. package/src/utils.test.ts +11 -2
  634. package/src/utils.ts +6 -15
  635. package/src/wirings/actor-flow/actor-flow.types.ts +1 -34
  636. package/src/wirings/actor-flow/index.ts +0 -9
  637. package/src/wirings/actor-flow/run-conversation.test.ts +11 -6
  638. package/src/wirings/actor-flow/run-conversation.ts +19 -12
  639. package/src/wirings/ai-agent/ai-agent-agui.test.ts +91 -10
  640. package/src/wirings/ai-agent/ai-agent-agui.ts +49 -17
  641. package/src/wirings/ai-agent/ai-agent-helpers.ts +20 -0
  642. package/src/wirings/ai-agent/ai-agent-interrupt.test.ts +842 -0
  643. package/src/wirings/ai-agent/ai-agent-interrupt.ts +399 -0
  644. package/src/wirings/ai-agent/ai-agent-memory.ts +0 -2
  645. package/src/wirings/ai-agent/ai-agent-model-config.ts +1 -9
  646. package/src/wirings/ai-agent/ai-agent-prepare.test.ts +202 -31
  647. package/src/wirings/ai-agent/ai-agent-prepare.ts +89 -139
  648. package/src/wirings/ai-agent/ai-agent-registry.test.ts +191 -6
  649. package/src/wirings/ai-agent/ai-agent-registry.ts +18 -1
  650. package/src/wirings/ai-agent/ai-agent-resume-authorization.test.ts +0 -2
  651. package/src/wirings/ai-agent/ai-agent-runner.test.ts +11 -9
  652. package/src/wirings/ai-agent/ai-agent-runner.ts +85 -35
  653. package/src/wirings/ai-agent/ai-agent-stream.test.ts +205 -103
  654. package/src/wirings/ai-agent/ai-agent-stream.ts +224 -76
  655. package/src/wirings/ai-agent/ai-agent-thread-ownership.test.ts +301 -0
  656. package/src/wirings/ai-agent/ai-agent.types.ts +130 -5
  657. package/src/wirings/ai-agent/index.ts +37 -3
  658. package/src/wirings/ai-agent/voice-input.test.ts +137 -7
  659. package/src/wirings/ai-agent/voice-input.ts +96 -12
  660. package/src/wirings/ai-agent/voice-output.test.ts +512 -0
  661. package/src/wirings/ai-agent/voice-output.ts +243 -56
  662. package/src/wirings/channel/channel-common.ts +15 -20
  663. package/src/wirings/channel/channel-handler.test.ts +50 -0
  664. package/src/wirings/channel/channel-handler.ts +32 -11
  665. package/src/wirings/channel/channel-host-rpc.test.ts +150 -0
  666. package/src/wirings/channel/channel-host-rpc.ts +69 -0
  667. package/src/wirings/channel/channel-middleware-runner.test.ts +0 -1
  668. package/src/wirings/channel/channel-middleware-runner.ts +0 -12
  669. package/src/wirings/channel/channel-rpc-registry.ts +116 -0
  670. package/src/wirings/channel/channel-rpc-responder.ts +117 -0
  671. package/src/wirings/channel/channel-rpc-service.ts +146 -0
  672. package/src/wirings/channel/channel-rpc-validators.ts +65 -0
  673. package/src/wirings/channel/channel-rpc.test.ts +820 -0
  674. package/src/wirings/channel/channel-rpc.ts +5 -0
  675. package/src/wirings/channel/channel-rpc.types.ts +150 -0
  676. package/src/wirings/channel/channel-runner.ts +0 -14
  677. package/src/wirings/channel/channel-store.ts +0 -10
  678. package/src/wirings/channel/channel.types.ts +19 -8
  679. package/src/wirings/channel/define-channel-routes.ts +0 -20
  680. package/src/wirings/channel/eventhub-service.ts +0 -18
  681. package/src/wirings/channel/index.ts +35 -0
  682. package/src/wirings/channel/local/local-channel-handler.ts +3 -1
  683. package/src/wirings/channel/local/local-channel-runner.test.ts +0 -10
  684. package/src/wirings/channel/local/local-channel-runner.ts +3 -1
  685. package/src/wirings/channel/local/local-eventhub-service.test.ts +0 -13
  686. package/src/wirings/channel/local/local-eventhub-service.ts +2 -37
  687. package/src/wirings/channel/log-channels.ts +0 -4
  688. package/src/wirings/channel/pikku-abstract-channel-handler.test.ts +83 -2
  689. package/src/wirings/channel/pikku-abstract-channel-handler.ts +7 -0
  690. package/src/wirings/channel/serverless/serverless-channel-runner.ts +2 -5
  691. package/src/wirings/cli/channel/cli-approval.test.ts +177 -0
  692. package/src/wirings/cli/channel/cli-approval.ts +135 -0
  693. package/src/wirings/cli/channel/cli-channel-runner.ts +4 -26
  694. package/src/wirings/cli/channel/cli-raw-channel-runner.test.ts +169 -0
  695. package/src/wirings/cli/channel/cli-raw-channel-runner.ts +59 -16
  696. package/src/wirings/cli/channel/cli-raw-client-runner.test.ts +480 -0
  697. package/src/wirings/cli/channel/cli-raw-client-runner.ts +185 -0
  698. package/src/wirings/cli/channel/index.ts +13 -0
  699. package/src/wirings/cli/cli-runner.test.ts +0 -1
  700. package/src/wirings/cli/cli-runner.ts +46 -88
  701. package/src/wirings/cli/cli.types.ts +14 -3
  702. package/src/wirings/cli/command-parser.test.ts +0 -4
  703. package/src/wirings/cli/command-parser.ts +11 -91
  704. package/src/wirings/cli/define-cli-commands.ts +1 -17
  705. package/src/wirings/credential/credential.types.ts +0 -12
  706. package/src/wirings/credential/{wire-credential.ts → define-credential.ts} +7 -7
  707. package/src/wirings/credential/index.ts +1 -1
  708. package/src/wirings/credential/validate-credential-definitions.ts +2 -4
  709. package/src/wirings/gateway/gateway-runner.test.ts +1 -21
  710. package/src/wirings/gateway/gateway-runner.ts +8 -110
  711. package/src/wirings/gateway/gateway.types.ts +7 -80
  712. package/src/wirings/http/http-routes.test.ts +0 -3
  713. package/src/wirings/http/http-routes.ts +0 -86
  714. package/src/wirings/http/http-runner.test.ts +0 -1
  715. package/src/wirings/http/http-runner.ts +8 -167
  716. package/src/wirings/http/http.types.ts +15 -62
  717. package/src/wirings/http/log-http-routes.ts +0 -4
  718. package/src/wirings/http/pikku-fetch-http-request.test.ts +2 -10
  719. package/src/wirings/http/pikku-fetch-http-request.ts +0 -58
  720. package/src/wirings/http/pikku-fetch-http-response.test.ts +1 -1
  721. package/src/wirings/http/pikku-fetch-http-response.ts +0 -3
  722. package/src/wirings/http/routers/path-to-regex.test.ts +4 -17
  723. package/src/wirings/http/routers/path-to-regex.ts +2 -13
  724. package/src/wirings/http/web-request.test.ts +33 -2
  725. package/src/wirings/http/web-request.ts +30 -17
  726. package/src/wirings/mcp/mcp-endpoint-registry.test.ts +0 -1
  727. package/src/wirings/mcp/mcp-runner.ts +2 -17
  728. package/src/wirings/mcp/mcp.types.ts +7 -42
  729. package/src/wirings/oauth2/oauth2.types.ts +0 -30
  730. package/src/wirings/persona/define-personas.ts +33 -0
  731. package/src/wirings/persona/index.ts +62 -0
  732. package/src/wirings/persona/persona-email.ts +87 -0
  733. package/src/wirings/persona/persona-environments.test.ts +183 -0
  734. package/src/wirings/persona/persona-environments.ts +138 -0
  735. package/src/wirings/persona/persona-mailbox.ts +156 -0
  736. package/src/wirings/persona/persona.test.ts +220 -0
  737. package/src/wirings/persona/persona.types.ts +142 -0
  738. package/src/wirings/persona/validate-personas.ts +133 -0
  739. package/src/wirings/queue/index.ts +13 -3
  740. package/src/wirings/queue/queue-identity.test.ts +454 -0
  741. package/src/wirings/queue/queue-identity.ts +176 -0
  742. package/src/wirings/queue/queue-runner.ts +12 -31
  743. package/src/wirings/queue/queue.types.ts +25 -90
  744. package/src/wirings/queue/register-queue-helper.ts +0 -14
  745. package/src/wirings/queue/signed-queue-service.ts +60 -0
  746. package/src/wirings/queue/validate-worker-config.ts +2 -28
  747. package/src/wirings/role/define-system-role.ts +33 -0
  748. package/src/wirings/role/index.ts +13 -0
  749. package/src/wirings/role/role.test.ts +104 -0
  750. package/src/wirings/role/role.types.ts +47 -0
  751. package/src/wirings/role/validate-role-definitions.ts +93 -0
  752. package/src/wirings/rpc/addon-auth-tags.test.ts +223 -0
  753. package/src/wirings/rpc/addon-runner.ts +0 -56
  754. package/src/wirings/rpc/addon-scopes.test.ts +225 -0
  755. package/src/wirings/rpc/remote-addon-auth.ts +9 -16
  756. package/src/wirings/rpc/rpc-runner.test.ts +192 -6
  757. package/src/wirings/rpc/rpc-runner.ts +145 -127
  758. package/src/wirings/rpc/rpc-types.ts +11 -6
  759. package/src/wirings/rpc/wire-addon.test.ts +43 -1
  760. package/src/wirings/rpc/wire-addon.ts +99 -0
  761. package/src/wirings/rpc/wire-remote-addon.ts +9 -29
  762. package/src/wirings/scheduler/log-schedulers.ts +0 -4
  763. package/src/wirings/scheduler/scheduler-runner.test.ts +1 -8
  764. package/src/wirings/scheduler/scheduler-runner.ts +0 -2
  765. package/src/wirings/scheduler/scheduler.types.ts +1 -14
  766. package/src/wirings/scope/{wire-scope.ts → define-scope.ts} +5 -6
  767. package/src/wirings/scope/index.ts +1 -1
  768. package/src/wirings/scope/scope.test.ts +1 -2
  769. package/src/wirings/scope/scope.types.ts +7 -9
  770. package/src/wirings/scope/validate-scope-definitions.ts +3 -21
  771. package/src/wirings/secret/index.ts +1 -1
  772. package/src/wirings/secret/secret.types.ts +19 -15
  773. package/src/wirings/secret/validate-secret-definitions.ts +2 -4
  774. package/src/wirings/trigger/trigger-runner.ts +1 -27
  775. package/src/wirings/trigger/trigger.types.ts +1 -82
  776. package/src/wirings/variable/index.ts +1 -1
  777. package/src/wirings/variable/validate-variable-definitions.ts +2 -4
  778. package/src/wirings/variable/variable.types.ts +1 -13
  779. package/src/wirings/virtual-user/index.ts +88 -0
  780. package/src/wirings/virtual-user/prepare-virtual-user-run.test.ts +115 -0
  781. package/src/wirings/virtual-user/prepare-virtual-user-run.ts +95 -0
  782. package/src/wirings/virtual-user/run-virtual-user.test.ts +765 -0
  783. package/src/wirings/virtual-user/run-virtual-user.ts +671 -0
  784. package/src/wirings/virtual-user/virtual-user-agents.test.ts +65 -0
  785. package/src/wirings/virtual-user/virtual-user-agents.ts +57 -0
  786. package/src/wirings/virtual-user/virtual-user-catalogue.test.ts +215 -0
  787. package/src/wirings/virtual-user/virtual-user-catalogue.ts +184 -0
  788. package/src/wirings/virtual-user/virtual-user-derive.test.ts +398 -0
  789. package/src/wirings/virtual-user/virtual-user-derive.ts +173 -0
  790. package/src/wirings/virtual-user/virtual-user-dispositions.test.ts +63 -0
  791. package/src/wirings/virtual-user/virtual-user-dispositions.ts +213 -0
  792. package/src/wirings/virtual-user/virtual-user-intents.test.ts +208 -0
  793. package/src/wirings/virtual-user/virtual-user-intents.ts +185 -0
  794. package/src/wirings/virtual-user/virtual-user-rng.test.ts +72 -0
  795. package/src/wirings/virtual-user/virtual-user-rng.ts +50 -0
  796. package/src/wirings/virtual-user/virtual-user-run-store.ts +98 -0
  797. package/src/wirings/virtual-user/virtual-user-target.ts +47 -0
  798. package/src/wirings/virtual-user/virtual-user.types.ts +219 -0
  799. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +19 -20
  800. package/src/wirings/workflow/dsl/workflow-runner.ts +0 -4
  801. package/src/wirings/workflow/feature.ts +0 -19
  802. package/src/wirings/workflow/graph/graph-node.ts +0 -136
  803. package/src/wirings/workflow/graph/graph-runner.test.ts +20 -19
  804. package/src/wirings/workflow/graph/graph-runner.ts +6 -41
  805. package/src/wirings/workflow/graph/wire-workflow-graph.ts +0 -4
  806. package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -58
  807. package/src/wirings/workflow/index.ts +10 -44
  808. package/src/wirings/workflow/pikku-scenario-service.ts +235 -61
  809. package/src/wirings/workflow/pikku-workflow-service.test.ts +0 -39
  810. package/src/wirings/workflow/pikku-workflow-service.ts +77 -674
  811. package/src/wirings/workflow/run-timeline.test.ts +7 -19
  812. package/src/wirings/workflow/run-timeline.ts +0 -56
  813. package/src/wirings/workflow/scenario-cookie-jar.test.ts +0 -1
  814. package/src/wirings/workflow/scenario-cookie-jar.ts +0 -25
  815. package/src/wirings/workflow/scenario-expectations.test.ts +2 -7
  816. package/src/wirings/workflow/scenario-hooks.test.ts +2 -7
  817. package/src/wirings/workflow/scenario-poll.test.ts +0 -2
  818. package/src/wirings/workflow/scenario-poll.ts +0 -15
  819. package/src/wirings/workflow/scenario-prose.test.ts +5 -7
  820. package/src/wirings/workflow/scenario-prose.ts +1 -29
  821. package/src/wirings/workflow/scenario-service.test.ts +2 -10
  822. package/src/wirings/workflow/scenario-step-guards.ts +1 -14
  823. package/src/wirings/workflow/scenario-step.test.ts +163 -19
  824. package/src/wirings/workflow/scenario-step.types.ts +94 -12
  825. package/src/wirings/workflow/scenario-surface.test.ts +146 -0
  826. package/src/wirings/workflow/scenario-surface.ts +71 -0
  827. package/src/wirings/workflow/workflow-dispatch-durability.test.ts +14 -15
  828. package/src/wirings/workflow/workflow-dispatch-payload.test.ts +0 -4
  829. package/src/wirings/workflow/workflow-inline-authority.test.ts +169 -0
  830. package/src/wirings/workflow/workflow-invocation-id.test.ts +0 -2
  831. package/src/wirings/workflow/workflow-invocation-id.ts +2 -22
  832. package/src/wirings/workflow/workflow-mirror.test.ts +0 -7
  833. package/src/wirings/workflow/workflow-on-error.test.ts +0 -9
  834. package/src/wirings/workflow/workflow-queue-workers.ts +0 -21
  835. package/src/wirings/workflow/workflow-replay-snapshot.test.ts +8 -7
  836. package/src/wirings/workflow/workflow-retry-policy.test.ts +0 -5
  837. package/src/wirings/workflow/workflow-run-context.test.ts +5 -10
  838. package/src/wirings/workflow/workflow-run-polling.test.ts +0 -5
  839. package/src/wirings/workflow/workflow-step-ordinal.test.ts +19 -4
  840. package/src/wirings/workflow/workflow-step-session.test.ts +0 -7
  841. package/src/wirings/workflow/workflow.types.ts +5 -201
  842. package/tsconfig.tsbuildinfo +1 -1
  843. package/tsconfig.type-tests.json +12 -0
  844. package/src/middleware/timeout.ts +0 -22
  845. package/src/pikku-response.ts +0 -5
  846. package/src/wirings/mcp/mcp-endpoint-registry.test.d.ts +0 -1
  847. package/src/wirings/workflow/dsl/index.ts +0 -36
  848. package/src/wirings/workflow/graph/index.ts +0 -15
@@ -0,0 +1,31 @@
1
+ ---
2
+ type: decision
3
+ title: An agent requires a session only when auth is true, but always enforces scopes and permissions
4
+ description: Agents follow pikkuSessionlessFunc semantics so crons and queue workers can run them; scopes are an AND gate checked before any permission I/O
5
+ tags: ai-agent
6
+ ---
7
+
8
+ # An agent requires a session only when auth is true, but always enforces scopes and permissions
9
+
10
+ `assertAgentAuthorized` in
11
+ `packages/core/src/wirings/ai-agent/ai-agent-prepare.ts` enforces, in order:
12
+ session presence (only when `CoreAIAgent.auth === true`), then `scopes`, then
13
+ `permissions`. The ordering mirrors the function runner — scopes AND together so
14
+ they can only narrow access, and a missing scope short-circuits before any
15
+ permission function does I/O. Declared `scopes` are narrowed to the generated
16
+ `ScopeId` union in a project's `pikku-types.gen.ts`, so an undeclared scope is a
17
+ compile error.
18
+
19
+ `auth` defaults to `false` (i.e. `pikkuSessionlessFunc`, not `pikkuFunc`) because
20
+ an agent is normally reached from a function that already enforced its own auth,
21
+ and is also run from genuinely sessionless contexts such as crons and queue
22
+ workers. Requiring a session by default would reject those without adding a real
23
+ gate. Global permissions are evaluated here too rather than assumed to have
24
+ already run, because an agent is reachable from entry points that never pass
25
+ through the function runner; re-evaluating an AND gate of side-effect-free
26
+ predicates is idempotent.
27
+
28
+ **What this rules out:** making `auth: true` the default; checking permissions
29
+ before scopes; skipping globals on the assumption a caller already ran them; and
30
+ moving the gate into the individual run/stream/resume entry points, where a new
31
+ entry point would silently miss it.
@@ -0,0 +1,23 @@
1
+ ---
2
+ type: decision
3
+ title: An agent ownership failure never echoes the resource it refused
4
+ description: assertResourceOwner throws a bare ForbiddenError so the error cannot be used as an existence oracle, at the cost of thinner debugging output
5
+ tags: ai-agent
6
+ ---
7
+
8
+ # An agent ownership failure never echoes the resource it refused
9
+
10
+ `assertResourceOwner` in
11
+ `packages/core/src/wirings/ai-agent/ai-agent-prepare.ts` compares a stored
12
+ thread/run `resourceId` against the caller's composed owner key and throws
13
+ `ForbiddenError('Not authorized to access this thread' | '… run')` on a
14
+ mismatch. The message deliberately carries no id.
15
+
16
+ Including the id would turn the endpoint into an existence oracle: a caller
17
+ enumerating thread ids could tell "exists but is not yours" apart from "does not
18
+ exist", which leaks the shape of other tenants' data even though no content is
19
+ returned.
20
+
21
+ **What this rules out:** improving the error message by interpolating the
22
+ `threadId`, `runId`, or owner key into it, and distinguishing not-found from
23
+ not-authorized on the read paths.
@@ -0,0 +1,22 @@
1
+ ---
2
+ type: decision
3
+ title: Resuming a suspended agent run re-runs the agent's authorization gate
4
+ description: Ownership of the run is not enough — a grant revoked while the run was suspended must block the approval
5
+ tags: ai-agent
6
+ ---
7
+
8
+ # Resuming a suspended agent run re-runs the agent's authorization gate
9
+
10
+ Both `resumeAIAgent` (`ai-agent-stream.ts`) and `resumeAIAgentSync`
11
+ (`ai-agent-runner.ts`) call `assertAgentAuthorized` after asserting run
12
+ ownership and before touching `aiRunState.resolveApproval`.
13
+
14
+ Ownership proves the run belongs to the caller, not that the caller may still
15
+ act on it: a suspension can outlive the permission that created it, and the whole
16
+ point of an approval gate is that the person approving is authorized at the
17
+ moment of approval. Resolving an approval is a persisted side effect, so the
18
+ gate must run before it, not after.
19
+
20
+ **What this rules out:** treating the ownership assertion as the complete
21
+ authorization check on the resume paths, and moving `assertAgentAuthorized`
22
+ below `resolveApproval` for convenience.
@@ -0,0 +1,39 @@
1
+ ---
2
+ type: decision
3
+ title: Agent thread ownership fails closed when there is no principal
4
+ description: A sessionless caller gets an ephemeral owner and reaches no stored thread, rather than reaching all of them
5
+ tags: ai-agent
6
+ ---
7
+
8
+ # Agent thread ownership fails closed when there is no principal
9
+
10
+ `canAccessThread` returns `false` and `threadOwnerConstraint` returns `[]` when
11
+ the session carries neither `userId` nor `orgId`
12
+ (`packages/core/src/wirings/ai-agent/ai-agent-prepare.ts`).
13
+ `resolveOwnerResourceId` never accepts the client-supplied `resourceId` as an
14
+ ownership key; without a principal it mints an ephemeral `anon-<uuid>` owner
15
+ memoized on the request's params object.
16
+
17
+ Agent wirings default to `auth: false`, so "no session" is the common case
18
+ rather than an exotic one. Treating it as "no ownership model to enforce" made
19
+ every ownership check vacuous: a caller named any `resourceId` and reached that
20
+ thread, and because `undefined` on `AgentRunService.listThreads` means *no
21
+ filter* rather than *no rows*, a sessionless `getAgentThreads` returned every
22
+ thread in the deployment. The ephemeral owner is what keeps one-shot
23
+ conversations working while denying continuity — it is unguessable, so nothing
24
+ stored can be reached, and it is stable within a request, so a sub-agent
25
+ re-entering `resolveOwnerResourceId` reuses its parent's thread.
26
+
27
+ Memoizing on the params object rather than a module-level Map is what keeps this
28
+ serverless-safe: the identity dies with the request and is never shared between
29
+ instances. `canAccessThread` stays a predicate rather than an assertion so it can
30
+ back a `pikkuPermission` — authorization belongs in a function's `permissions`
31
+ field, never in its body.
32
+
33
+ **What this rules out:** returning `undefined` from `threadOwnerConstraint` for
34
+ any caller; deriving `owners` from request input instead of the session; reading
35
+ `auth: false` as permission to skip ownership on a *stored* thread; and
36
+ persisting the anonymous owner anywhere, which would turn an ephemeral identity
37
+ into a forgeable one. Cross-request thread continuity without a session is not
38
+ available by design — wire a session to get it back. See
39
+ [[an-empty-owners-constraint-matches-nothing]].
@@ -0,0 +1,30 @@
1
+ ---
2
+ type: decision
3
+ title: An agent thread key is always prefixed with the trusted principal
4
+ description: Ownership keys are composed as principal:resourceId, so a client id can sub-divide its own boundary but never widen it
5
+ tags: ai-agent
6
+ ---
7
+
8
+ # An agent thread key is always prefixed with the trusted principal
9
+
10
+ `resolveOwnerResourceId` in `packages/core/src/wirings/ai-agent/ai-agent-prepare.ts`
11
+ composes the ownership key for a thread or run as `principal:resourceId`. The
12
+ principal is the trusted one — `session.userId` for the default `'user'`
13
+ `SessionScope`, `session.orgId` for `'org'` — and the client-supplied
14
+ `resourceId` is only ever a sub-partition inside it. Composition is idempotent:
15
+ a value already inside the caller's namespace (top-level re-entry, sub-agent
16
+ recursion, resume — all of which pass an already-composite id) is returned
17
+ unchanged rather than composed twice.
18
+
19
+ `'org'` scope with no org on the session throws `ForbiddenError` instead of
20
+ falling back to a bare or shared key, because a shared key leaks threads across
21
+ organizations. A sessionless `'user'` wiring has no trusted principal at all and
22
+ falls back to the requested `resourceId` as a best-effort partition.
23
+ `isOwnedByPrincipal` requires the `:` separator when matching sub-partitions so
24
+ that a principal `alice` does not match a lookalike `alice-evil:…` key.
25
+
26
+ **What this rules out:** storing threads under the client's `resourceId`
27
+ directly; making the composition non-idempotent (resume and sub-agent recursion
28
+ would double-prefix and lose their own threads); testing ownership with a bare
29
+ `startsWith(principal)` that omits the separator; and letting `'org'` scope
30
+ degrade to a shared key when the session carries no organization.
@@ -0,0 +1,24 @@
1
+ ---
2
+ type: decision
3
+ title: Agent tool permission filtering reads the live function config, not the metadata
4
+ description: The pikkuAuth brand survives only on live permission objects, so a metadata-driven check would silently admit every gated tool
5
+ tags: ai-agent
6
+ ---
7
+
8
+ # Agent tool permission filtering reads the live function config, not the metadata
9
+
10
+ `buildToolDefs` in `packages/core/src/wirings/ai-agent/ai-agent-prepare.ts`
11
+ decides which tools and sub-agents to expose to the model by calling
12
+ `checkAuthPermissions` against the permission objects held in the live function
13
+ (or agent) config in `pikkuState`, using the metadata only to learn that a
14
+ permission exists at all.
15
+
16
+ The `pikkuAuth` brand that marks a permission as an authorization gate exists
17
+ only on those live objects. The metadata's by-name permission registry is never
18
+ populated, so resolving names through it collects no predicates — and a filter
19
+ that collects no predicates admits everything. The failure is silent: every gated
20
+ tool would be handed to the model for any session.
21
+
22
+ **What this rules out:** simplifying the filter to read
23
+ `fnMeta.permissions` / `subMeta.permissions` directly, and caching a
24
+ name-to-predicate map derived from metadata.
@@ -0,0 +1,30 @@
1
+ ---
2
+ type: decision
3
+ title: An empty owners constraint matches nothing
4
+ description: owners is an authorization boundary, so every storage backend must treat [] as no rows rather than no filter
5
+ tags: ai-agent, storage
6
+ ---
7
+
8
+ # An empty owners constraint matches nothing
9
+
10
+ Every `AgentRunService.listThreads` implementation returns `[]` immediately when
11
+ `owners` is present and empty — `kysely-ai-agent-run-service.ts`,
12
+ `redis-agent-run-service.ts`, `mongodb-agent-run-service.ts`. The conformance
13
+ suite in `packages/core/src/testing/service-tests.ts` pins it, so a new backend
14
+ inherits the requirement instead of rediscovering it.
15
+
16
+ `owners` is an authorization boundary, not an optional filter. The natural way
17
+ to write a query builder is to skip a clause when its list is empty, which
18
+ silently converts "this caller may see nothing" into "this caller may see
19
+ everything" — the failure is invisible in review because the omitted clause
20
+ looks like an optimization. Placing the guard before the query is built, in
21
+ every backend, means the dangerous shape never exists.
22
+
23
+ This is what makes the sessionless `[]` from `threadOwnerConstraint` safe to
24
+ return; the two decisions only hold together.
25
+
26
+ **What this rules out:** folding the empty case into the query builder's normal
27
+ `if (owners)` path; treating `owners: []` as equivalent to `owners: undefined`
28
+ at any layer; and adding a backend without the conformance suite.
29
+
30
+ See [[ai-agent-sessionless-deployments-have-no-thread-ownership]].
@@ -0,0 +1,49 @@
1
+ ---
2
+ type: decision
3
+ title: An exposed function with no gate is reported at codegen, not at boot
4
+ description: The check runs in the inspector where function meta and every wireAddon declaration are both in hand, because neither source alone can tell a gated function from an ungated one
5
+ tags: authorization, inspector, addon, rpc
6
+ ---
7
+
8
+ # An exposed function with no gate is reported at codegen, not at boot
9
+
10
+ The generated `POST /rpc/:rpcName` dispatcher forwards to `rpc.exposed`, which
11
+ refuses anything without `expose: true`. That makes the reachable set small and
12
+ deliberate — someone typed it. What it does not do is check whether the target
13
+ is gated, because a dispatcher cannot know what it is dispatching to. The
14
+ console shipped ~54 privileged functions through exactly this gap, and nothing
15
+ in the toolchain said so.
16
+
17
+ The check belongs next to `validateAuthSessionless`, in the inspector, for one
18
+ reason: it needs two sources that only meet there.
19
+
20
+ `sessionless` records the baseline — a `pikkuFunc` always requires a session —
21
+ but a `pikkuSessionlessFunc` may still tighten itself with `auth: true`, which
22
+ the inspector previously discarded. It is now recorded on function meta, so
23
+ "sessionless and ungated" is distinguishable from "sessionless and
24
+ self-gated" without running anything.
25
+
26
+ The second source is `wireAddon`. Its `scopes` and `auth` apply to every
27
+ function in the package on every wiring path (see
28
+ [addon scopes](./addon-scopes-are-resolved-where-the-function-runs.md)), so a
29
+ function with no gate of its own may still be fully covered. The inspector
30
+ already parsed `wireAddon` for its endpoint and its secret, variable and
31
+ credential overrides, and dropped `scopes`, `auth` and `tags` — the addon's
32
+ plumbing was recorded in full and its authorization was not. Reading function
33
+ meta alone would have reported every console function as open.
34
+
35
+ An addon whose gates are not statically knowable — a spread, a const reference —
36
+ is recorded as absent, and absent is read as **gated**. This is deliberately the
37
+ wrong way round from how a runtime gate fails: a false negative costs one
38
+ missing warning, while a false positive on a correctly-secured addon costs
39
+ confidence in every warning the tool emits, which is worth more than the one
40
+ case it would catch.
41
+
42
+ Severity is `warn`, not `critical`. `expose: true` on an ungated sessionless
43
+ function is legitimate for a genuinely public endpoint — a health check, a
44
+ sign-up — so this cannot block a build without breaking correct programs. It
45
+ fails a build only under `--fail-on-warn`.
46
+
47
+ **What this rules out:** checking at boot, where the report arrives after
48
+ deployment; checking in `pikku validate` from `.pikku` JSON, which does not
49
+ carry `wireAddon` at all; and treating an unparseable addon gate as no gate.
@@ -0,0 +1,76 @@
1
+ ---
2
+ type: decision
3
+ title: The console addon's privileged functions gate themselves
4
+ description: Thread listing is owner-scoped unless the caller holds admin, and addon installation requires an admin session, rather than trusting the host to register a global permission
5
+ tags: addon, ai-agent, rpc
6
+ ---
7
+
8
+ # The console addon's privileged functions gate themselves
9
+
10
+ `@pikku/addon-console` is wired into the consuming application by the generated
11
+ `console.gen.ts` that `scaffold.console` produces — `wireAddon({ name:
12
+ 'console', package: '@pikku/addon-console' })`. That file is compiled into the
13
+ app and ships wherever the app ships, so every `expose: true` console function
14
+ is reachable over the app's own `POST /rpc/:rpcName` route in production, not
15
+ only from `pikku dev`. `pikku serve --console` binds `127.0.0.1` and adds a
16
+ static SPA mount; it wires no functions. The console UI being a development tool
17
+ is a convention about who opens the browser tab; it is not a deployment
18
+ boundary.
19
+
20
+ The transport in front of that route is configured separately from the console:
21
+ `scaffold.rpc` defaults to `"no-auth"` in `templates/functions/pikku.config.json`
22
+ and in `e2e/pikku.config.json`, which generates `wireHTTP({ route:
23
+ '/rpc/:rpcName', auth: false })`. `scaffold.console: "auth"` does not raise it,
24
+ and the generated `wireAddon` carries no `auth` key, so `addonConfig.auth` is
25
+ undefined at the addon boundary too. The remaining session check is the function
26
+ runner's, which for a `pikkuSessionlessFunc` fires only when the function itself
27
+ sets `auth: true`.
28
+
29
+ The addon's original authorization story was a single package-scoped
30
+ `addGlobalPermission([isAdmin], '@pikku/addon-console')` that the *host*
31
+ registered, which `runPermissions` resolves in the callee's package namespace and
32
+ applies to every function at once. Nothing generated that call — the scaffold
33
+ emitted only a comment recommending it, and `resolveGlobalPermissions` returns an
34
+ empty list when the host registered none, which `runPermissions` treats as
35
+ allow. An app that followed the scaffold and stopped there had a fully open
36
+ console surface. The scaffold now emits `wireAddon({ …, scopes: ['admin'] })`
37
+ instead, which the function runner enforces on every function in the package.
38
+
39
+ The two functions whose failure mode is worst still do not depend on any
40
+ package-wide gate:
41
+
42
+ `getAgentThreads` derives `owners` from the session with core's
43
+ `threadOwnerConstraint` and passes it on every call, omitting it only when the
44
+ session holds the `admin` scope root — listing every thread is the legitimate
45
+ purpose of an admin console, and `hasScopes` accepts the umbrella grant and its
46
+ wildcards. The `owners` value is never read from input, so a caller cannot name
47
+ someone else's principal. A session with no principal yields `[]`, which every
48
+ storage backend already treats as no rows.
49
+
50
+ `installAddon` and `installOpenapiAddon` run a package manager against an
51
+ attacker-chosen package name and write a wiring file into the project. They were
52
+ `pikkuSessionlessFunc` with `auth: false`, which — behind a `no-auth` RPC route
53
+ and with no host global permission — meant an unauthenticated POST reached
54
+ `execFileSync`. They now declare `auth: true` and `scopes: ['admin']`, enforced
55
+ by `verifyScopes` in the function runner before the body runs. Both gates are
56
+ checked whether or not the host registered a global permission, and whether or
57
+ not the addon itself was wired with scopes — an app that hand-wires
58
+ `wireAddon({ name: 'console', package: '@pikku/addon-console' })` without them
59
+ still cannot reach `execFileSync` unauthenticated.
60
+
61
+ `admin` is spelled as a literal here because it is a scope id in the addon's own
62
+ `wireScope` tree, the same tree the `pikku:scopes:*` gates on the scope-admin
63
+ functions come from.
64
+
65
+ **What this rules out:** treating the host's `addGlobalPermission` as the only
66
+ gate in front of an operation that installs code or reads another principal's
67
+ data; deriving `owners` from request input; returning `owners: undefined` for a
68
+ caller who simply has no principal; and gating these functions on a
69
+ `metaService.basePath` check — that is a filesystem-availability test which the
70
+ generated `PikkuMetaService` satisfies in any unbundled Node deployment, not an
71
+ is-this-localhost test.
72
+
73
+ See [[addon-scopes-are-resolved-where-the-function-runs]],
74
+ [[an-empty-owners-constraint-matches-nothing]],
75
+ [[ai-agent-sessionless-deployments-have-no-thread-ownership]] and
76
+ [[global-permissions-and-function-permissions-are-independent-gates]].
@@ -0,0 +1,39 @@
1
+ ---
2
+ type: decision
3
+ title: Core's SSRF guard matches host literals because edge runtimes have no DNS
4
+ description: safeFetch rejects internal address literals and re-validates every redirect hop; it cannot stop DNS rebinding
5
+ tags: core
6
+ ---
7
+
8
+ # Core's SSRF guard matches host literals because edge runtimes have no DNS
9
+
10
+ `packages/core/src/utils/safe-fetch.ts` guards every outbound fetch that core
11
+ makes on a caller-supplied URL. `@pikku/core` runs in edge runtimes (Cloudflare
12
+ Workers) that have no Node `dns` module, so the guard cannot resolve a hostname
13
+ and inspect the resulting address. It instead rejects address *literals* that are
14
+ obviously internal — loopback, `10/8`, `172.16/12`, `192.168/16`, `0.0.0.0/8`,
15
+ link-local `169.254/16` (the cloud metadata endpoint), IPv6 `::`, `::1`,
16
+ `fe80::/10` and `fc00::/7` — plus the alias forms that reach the same targets:
17
+ trailing-dot FQDNs, the reserved `*.localhost` names, IPv4-mapped IPv6, and the
18
+ `inet_aton`-style octal/hex/32-bit-integer encodings that `fetch` and `undici`
19
+ accept (`0177.0.0.1`, `0x7f000001`, `2130706433`).
20
+
21
+ Literal matching alone is not enough, because the classic bypass is a public URL
22
+ that 302s to `169.254.169.254`. So `safeFetch` sets `redirect: 'manual'` and
23
+ re-validates every hop through `assertFetchableUrl` before following it, follows
24
+ only the statuses in `REDIRECT_STATUSES` (301/302/303/307/308 — `300`, `304`,
25
+ `305` and `306` are returned to the caller as-is), applies the WHATWG
26
+ method/body transform per hop, cancels each intermediate response body, and
27
+ strips `Authorization` and `Cookie` whenever a hop crosses origin. What it
28
+ deliberately does **not** cover is DNS rebinding: a public hostname that itself
29
+ resolves to a private IP passes, because catching that needs resolution the
30
+ runtime does not offer.
31
+
32
+ **What this rules out:** "simplifying" `isPrivateHost` down to a `localhost` /
33
+ `127.0.0.1` string check — the octal, hex, integer and IPv4-mapped-IPv6 branches
34
+ are each a live bypass, not defensive noise. It equally rules out replacing the
35
+ manual redirect loop with `redirect: 'follow'` to shorten the function: the
36
+ platform would then follow a `Location` into the internal network with no
37
+ validation and no credential stripping, which is the entire attack this file
38
+ exists to block. Do not add DNS-based checks either without gating them —
39
+ importing `node:dns` breaks the Workers build.
@@ -0,0 +1,37 @@
1
+ ---
2
+ type: decision
3
+ title: Core secrets are encrypted with a per-secret DEK wrapped by a KEK
4
+ description: Envelope encryption keeps ciphertext untouched during key rotation, at the cost of storing two blobs per secret
5
+ tags: core
6
+ ---
7
+
8
+ # Core secrets are encrypted with a per-secret DEK wrapped by a KEK
9
+
10
+ `packages/core/src/crypto-utils.ts` exposes two layers. `encryptJSON` /
11
+ `decryptJSON` are the direct layer: a passphrase is hashed to an AES-GCM key and
12
+ the output is `base64url(iv || ciphertext)` with a 12-byte IV. On top of that sit
13
+ `envelopeEncrypt`, `envelopeDecrypt` and `envelopeRewrap`, which give every stored
14
+ secret its own random 32-byte DEK (data encryption key). The secret is encrypted
15
+ with the DEK; the DEK is then encrypted with a KEK (key encryption key) — in
16
+ practice an environment variable or platform secret — and the pair
17
+ `{ ciphertext, wrappedDEK }` is what gets persisted.
18
+
19
+ The split exists so that rotating the KEK is cheap and non-destructive.
20
+ `envelopeRewrap` unwraps the DEK under the old KEK and re-wraps it under the new
21
+ one; the ciphertext of the secret itself is never read, never re-encrypted, and
22
+ never re-written. A store holding a million secrets rotates by touching a million
23
+ short blobs rather than re-encrypting every payload, and a rotation that fails
24
+ part-way leaves both halves independently decryptable by whichever KEK still
25
+ wraps them. The `keyVersion` / `previousKey` / `rotateKEK` shape that
26
+ `ServiceTestConfig` requires of every `SecretService` and `CredentialService`
27
+ implementation (`packages/core/src/testing/service-tests.ts`) is the storage-side
28
+ contract that falls out of this.
29
+
30
+ **What this rules out:** collapsing the envelope back to a single
31
+ `encryptJSON(kek, secret)` call, or deriving the DEK from the KEK rather than
32
+ generating it randomly. Either change makes the ciphertext depend on the KEK, so
33
+ rotation becomes a full re-encrypt of every stored secret and `envelopeRewrap`
34
+ stops being correct. It also rules out changing the `iv || ciphertext` layout or
35
+ the 12-byte IV length in either layer — the length is hard-coded on the decrypt
36
+ side (`data.slice(0, 12)`, minimum length 13), so any change silently fails to
37
+ read every previously stored value.
@@ -0,0 +1,31 @@
1
+ ---
2
+ type: decision
3
+ title: Gateway handlers run through the function runner gate
4
+ description: A gateway's handler is registered as a real pikku function and invoked via runPikkuFunc, because calling it directly skips auth, scopes and permissions
5
+ tags: gateway
6
+ ---
7
+
8
+ # Gateway handlers run through the function runner gate
9
+
10
+ `registerGatewayHandler` in
11
+ `packages/core/src/wirings/gateway/gateway-runner.ts` registers `config.func`
12
+ under a synthetic function id (`gateway__<name>__handler`) and every transport —
13
+ webhook POST, websocket message, listener callback — invokes it via
14
+ `runPikkuFunc`. This looks like an unnecessary indirection: the handler is right
15
+ there in the config and could be awaited directly. It cannot. The function
16
+ runner's gate is the only thing that evaluates a function's declared `auth`,
17
+ `scopes` and `permissions`; a direct call runs the handler with none of them
18
+ checked.
19
+
20
+ The handler is registered with `sessionless: true`. Gateway inbound traffic is
21
+ authenticated by the platform adapter (webhook signature verification, platform
22
+ tokens), not by a user session, so defaulting to session-required would reject
23
+ every legitimate webhook. `CoreGateway.auth` and the handler's own `auth: true`
24
+ opt back into requiring a session. `scopes` and `permissions` are enforced
25
+ whenever declared, session or not.
26
+
27
+ **What this rules out:** invoking `config.func` directly from any gateway
28
+ transport as an optimisation, and "simplifying" the synthetic function
29
+ registration away. It also rules out flipping the sessionless default to
30
+ session-required as a hardening measure — that breaks every webhook rather than
31
+ securing it; require auth per gateway via `CoreGateway.auth` instead.
@@ -0,0 +1,30 @@
1
+ ---
2
+ type: decision
3
+ title: Gateway middleware sessions must be bridged onto the wire
4
+ description: Gateway middleware calling wire.setSession writes to a session service the handler's invocation never reads, so the session is copied onto wire.session before the gate runs
5
+ tags: gateway
6
+ ---
7
+
8
+ # Gateway middleware sessions must be bridged onto the wire
9
+
10
+ `bridgeMiddlewareSession` in
11
+ `packages/core/src/wirings/gateway/gateway-runner.ts` runs immediately before
12
+ every `runPikkuFunc` call in the gateway runner, copying `await wire.getSession()`
13
+ onto `wire.session` when the latter is unset. Gateway middleware is the only
14
+ place a webhook can acquire a session at all — typically by mapping a verified
15
+ platform sender id to a user. Middleware that assigns `wire.session` directly
16
+ needs no help, but the idiomatic `wire.setSession()` writes into the *enclosing
17
+ wiring's* session service, and the handler's own invocation does not read that
18
+ service.
19
+
20
+ Without the bridge, the failure mode is silent and it fails open in the way that
21
+ matters: `auth` and `scopes` on the handler see no session, so a gateway whose
22
+ middleware successfully authenticated the sender still evaluates its gate as
23
+ unauthenticated. Nothing throws; the session is simply invisible.
24
+
25
+ **What this rules out:** removing the `bridgeMiddlewareSession` call from any of
26
+ the three transports (webhook POST, websocket message, listener) on the grounds
27
+ that middleware "already set the session", and adding a fourth gateway transport
28
+ that calls `runPikkuFunc` without bridging first. It also rules out relying on
29
+ `wire.setSession()` alone anywhere the callee is a separately-registered pikku
30
+ function.
@@ -0,0 +1,40 @@
1
+ ---
2
+ type: decision
3
+ title: Global permissions and function permissions are independent gates
4
+ description: Globals AND together and can only narrow access; a function's own group ORs internally and is never satisfied by a global
5
+ tags: permissions
6
+ ---
7
+
8
+ # Global permissions and function permissions are independent gates
9
+
10
+ `runPermissions` in `packages/core/src/permissions.ts` runs two gates and both
11
+ must pass. Every requirement registered through `addGlobalPermission` is checked
12
+ in turn and any failure throws `ForbiddenError` — globals AND, so a global can
13
+ only ever narrow access, never grant it. The function's own `permissions` group
14
+ is then evaluated by `verifyPermissions`, which ORs the group's branches and ANDs
15
+ the entries within a branch: the group passes if at least one branch is
16
+ satisfied.
17
+
18
+ That OR inside `verifyPermissions` is the only OR in authorization. Everything
19
+ cross-cutting — globals, scopes, auth — ANDs. A function's own group is the sole
20
+ place where "owner OR admin"-style alternatives belong. Crucially, a global that
21
+ passed contributes nothing to the function gate: a broad `signedIn` global cannot
22
+ satisfy an admin-only function's requirements, because the two gates are
23
+ evaluated independently against separate inputs. An empty or absent group passes,
24
+ so declaring no permissions means "globals only", not "deny".
25
+
26
+ Globals are bucketed per package, and a function reads *both* the root bucket and
27
+ its own package's — root first. The generated `addGlobalPermission` wrapper takes
28
+ no package argument, so an application's rules only ever land in the root bucket;
29
+ resolving the package bucket alone meant a host rule like "every request needs a
30
+ signed-in user" silently stopped at the addon boundary, while the bucket an
31
+ addon's functions actually read was one no host could write to. Unioning is safe
32
+ in a way that nothing else here would be: globals AND, so adding the root ones
33
+ can only tighten. Package buckets stay one-way — a package's globals never apply
34
+ to root functions, or an installed addon could gate the whole application.
35
+
36
+ **What this rules out:** short-circuiting the function gate when the globals
37
+ passed, merging the global requirements into the function group (which would turn
38
+ AND into OR and let any global satisfy any function), and giving
39
+ `verifyPermissions` AND-across-branches semantics to "make it consistent" with
40
+ the global gate.
@@ -0,0 +1,33 @@
1
+ ---
2
+ type: decision
3
+ title: HTTP error detail is withheld from clients in production
4
+ description: 5xx bodies carry only a trace id in production; exposeErrors can widen that in development but never in production
5
+ tags: http
6
+ ---
7
+
8
+ # HTTP error detail is withheld from clients in production
9
+
10
+ `fetchData` in `packages/core/src/wirings/http/http-runner.ts` defaults
11
+ `exposeErrors` to `!isProduction()`, and `handleHTTPError` in
12
+ `packages/core/src/handle-error.ts` computes `clientFacing` as
13
+ `errorResponse.status < 500 || (exposeErrors && !isProduction())`. Registered
14
+ errors below 500 always return their own message and `payload`, because they
15
+ describe something the caller did. Anything 500 and above returns only the
16
+ registered generic message and the `errorId` trace id; the original `e.message`,
17
+ `e.stack` and `payload` are dropped. The unregistered-error path is stricter
18
+ still — it emits `{ errorId }` alone and attaches `message`/`stack` only when
19
+ `exposeErrors && !isProduction()`.
20
+
21
+ Unexpected 5xx messages are the ones that leak: driver errors carrying
22
+ connection strings, ORM errors quoting rows, assertion text naming internal
23
+ services. The trace id is the deliberate substitute — the operator correlates it
24
+ with the logged error, which does carry the full message.
25
+
26
+ Note the double gate. `exposeErrors` is re-checked against `isProduction()`
27
+ inside `handleHTTPError` even though its default already accounts for it, so a
28
+ runtime that passes `exposeErrors: true` explicitly still cannot open up a
29
+ production deployment.
30
+
31
+ **What this rules out:** collapsing the two `isProduction()` checks into the
32
+ default value, letting a caller-supplied `exposeErrors` win in production, and
33
+ "improving" the 5xx body by echoing `e.message` unconditionally.
@@ -0,0 +1,46 @@
1
+ ---
2
+ type: decision
3
+ title: HTTP request bodies are bounded before they are buffered
4
+ description: Content-Length is rejected up front and the stream is measured as it arrives, because that header is optional and attacker-controlled
5
+ tags: http
6
+ ---
7
+
8
+ # HTTP request bodies are bounded before they are buffered
9
+
10
+ `PikkuFetchHTTPRequest.#readBoundedBuffer` in
11
+ `packages/core/src/wirings/http/pikku-fetch-http-request.ts` enforces
12
+ `maxBodySize` twice. A declared `content-length` above the limit is rejected
13
+ before a single byte is transferred, which is the cheap path. The body stream is
14
+ then measured chunk by chunk anyway, cancelling the reader and throwing
15
+ `PayloadTooLargeError` the moment the running total crosses the limit — because
16
+ `content-length` is optional (chunked encoding omits it) and, when present, is
17
+ whatever the client chose to write. Trusting it alone would let a request declare
18
+ 1 KB and stream a gigabyte.
19
+
20
+ `DEFAULT_MAX_BODY_SIZE` is 10 MB: ample for JSON APIs and ordinary uploads while
21
+ keeping one request's memory footprint bounded, since the whole body is
22
+ materialised in memory.
23
+
24
+ Every adapter enforces the same limit and the same `PayloadTooLargeError`, but
25
+ they divide into two kinds, and the difference is what can actually be
26
+ prevented rather than merely reported:
27
+
28
+ - **Prevention.** uWebSockets drives `res.onData` itself, so it counts bytes and
29
+ *drops* chunks past the limit rather than concatenating, replying 413 before
30
+ routing — the only point at which the buffering can be stopped, which is why
31
+ it deviates from the fetch adapter's 404-an-unmatched-route order. Fastify
32
+ delegates to native `bodyLimit`, set only when `maxBodySize` is configured so
33
+ the default never *loosens* fastify's stricter 1 MB. `PikkuExpressServer`
34
+ feeds the limit into `express.json`/`text`/`urlencoded`.
35
+ - **Rejection only.** `express-middleware` is handed an already-parsed body, so
36
+ its guard makes the rejection uniform but cannot reclaim the memory; a
37
+ deployment mounting it on its own app must bound its own parser. Next server
38
+ actions receive a decoded JS value with no wire size left to measure — the
39
+ limit there is `experimental.serverActions.bodySizeLimit`.
40
+
41
+ **What this rules out:** dropping the streaming measurement once the
42
+ `content-length` check exists; raising the default because "10 MB is small" —
43
+ raise it per-route via `maxBodySize` instead; reading the body with a plain
44
+ `request.arrayBuffer()` anywhere that bypasses this method; and adding an
45
+ adapter that buffers a body without a bound, on the assumption that some layer
46
+ downstream will catch it.