@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,29 @@
1
+ ---
2
+ type: decision
3
+ title: CLI unknown long options warn instead of failing
4
+ description: Unrecognised --long options are accepted, warned about and dropped so older binaries tolerate newer invocations, while unknown short flags stay hard errors
5
+ tags: cli
6
+ ---
7
+
8
+ # CLI unknown long options warn instead of failing
9
+
10
+ `warnUnknownOption` in `packages/core/src/wirings/cli/command-parser.ts` pushes
11
+ onto `ParsedCommand.warnings`, not `ParsedCommand.errors`, so an unrecognised
12
+ `--long` option does not abort the command. The value is still parsed into
13
+ `optionArgs`, but `pluckCLIData` in `cli-runner.ts` drops anything absent from
14
+ the function's input schema — so the option is silently ignored at execution
15
+ time. The warning exists precisely so that dropping is not silent.
16
+
17
+ The reason is forward compatibility: a script or wrapper written against a newer
18
+ command version may pass options an older installed binary does not know, and
19
+ failing hard there turns a harmless extra flag into a broken pipeline.
20
+ `RESERVED_OPTIONS` exempts flags the runner handles itself (`help`) from the
21
+ warning. Unknown *short* flags are treated differently — they go to
22
+ `result.errors` and do fail — because a bundled short-flag cluster like `-abc`
23
+ cannot be reliably attributed, and a typo'd short flag is far more likely than a
24
+ version skew.
25
+
26
+ **What this rules out:** promoting unknown long options to errors "for
27
+ strictness", and removing the warning on the grounds that the schema pluck
28
+ already handles it — that restores the silent drop this was added to end. It also
29
+ rules out making unknown short flags non-fatal for symmetry.
@@ -0,0 +1,84 @@
1
+ ---
2
+ type: decision
3
+ title: A column's at-rest form is an axis of its own
4
+ description: How a value is stored is independent of how sensitive it is, so form carries a required nominal brand on writes while classification stays optional on reads
5
+ tags: core
6
+ ---
7
+
8
+ # A column's at-rest form is an axis of its own
9
+
10
+ `ColumnForm` in `packages/core/src/data-classification.ts` is a second,
11
+ independent annotation on a column: `plain | hashed | wrapped | sealed`. It
12
+ answers "how are these bytes held?", where `Classification` answers "may this
13
+ value leave the process?".
14
+
15
+ The two axes were one field before this, with `security: 'encrypted'` sitting
16
+ alongside `secret` as though they were alternatives. They are not, and the
17
+ conflation made the field unanswerable: a token hash and a live bearer token are
18
+ both `secret`, one must never be encrypted — the digest *is* the lookup key —
19
+ and the other must always be. Nothing in a single enum could tell them apart, so
20
+ nothing could check either.
21
+
22
+ ## Why `wrapped` and `sealed` rather than `encrypted`
23
+
24
+ Sealed values *are* encrypted, so an `encrypted` member sitting beside `sealed`
25
+ would be a supertype posing as a sibling, and every new column would be an
26
+ even-odds guess. What actually separates them is who can read the value back:
27
+ `wrapped` is symmetric and the application holds the key; `sealed` is asymmetric
28
+ and the application holds only the public half. Writing one where the other
29
+ belongs produces a row nobody can ever open, which is why the type system is
30
+ made to know the difference.
31
+
32
+ ## Why these brands are required when `Secret<T>` is optional
33
+
34
+ `WrappedValue`, `SealedValue` and `HashedValue` are `string & { readonly [sym]:
35
+ true }` with a `unique symbol` — nominal, and **required**, which
36
+ [the classification-brand decision](core-data-classification-brand-is-an-optional-property.md)
37
+ explicitly rules out for `Private`/`Pii`/`Secret`. That decision still stands and
38
+ this does not weaken it. It applies to a different side of a different set of
39
+ columns:
40
+
41
+ - `Secret<T>` brands **every** classified column's SELECT type. A required brand
42
+ there would break `where('email', '=', someString)` in every downstream
43
+ project.
44
+ - A form brands **only** the INSERT/UPDATE type, and only on the columns that
45
+ opt in by declaring a form. There is nothing to break, because a column
46
+ without a form generates exactly what it generated before.
47
+
48
+ The brands compose rather than compete: a wrapped secret column selects as
49
+ `Secret<WrappedValue>`, so the inspector's PKU910 check still finds
50
+ `__classification__`, while a row read back is already a `WrappedValue` and
51
+ flows into a rewrap or re-seal without a cast.
52
+
53
+ Each brand widens to `string`, so query operands, serialization and template
54
+ literals are unaffected. The constraint is on **construction**: the only way to
55
+ produce one is `envelopeEncrypt`/`envelopeRewrap`/`wrapDEK` (wrapped) or
56
+ `hashToken` (hashed), or the deliberately-named `unsafeAs*` assertions in
57
+ `column-form.ts` for the three cases a bare string legitimately arrives —
58
+ backfill migrations, test fixtures, and values sealed by another service.
59
+
60
+ ## What is deliberately NOT enforced
61
+
62
+ `envelopeDecrypt` and `unwrapDEK` take plain `string`, not the brand. Requiring
63
+ it would buy nothing — feeding in the wrong string already fails at the AEAD tag
64
+ — while forcing a cast into every path that reads ciphertext out of a row or off
65
+ the wire, which is where casts are least reviewable.
66
+
67
+ The brand proves *provenance*, not correctness. It cannot know a value was
68
+ wrapped under the right key, and making it know would mean phantom-typing key
69
+ ids per scope, which the multi-recipient path would fight constantly.
70
+
71
+ ## The plain-secret diagnostic
72
+
73
+ A `secret` column with no declared form raises **PKU483** as a warning, not an
74
+ error. Every project predating the axis has such columns, and failing their next
75
+ `db migrate` would be a breaking change for a diagnosis they have not had a
76
+ chance to act on. `pikku db --fail-on-warn` is how a project opts into the
77
+ ratchet. An explicit `form: 'plain'` silences it — that is the acknowledgement
78
+ that reading the row is *meant* to yield a usable credential.
79
+
80
+ **What this rules out:** collapsing `wrapped` and `sealed` back into one
81
+ `encrypted`; making the form brands optional (they would enforce nothing);
82
+ re-declaring them in generated schema files, since a local `unique symbol` is a
83
+ distinct nominal type and core's own ciphertext would not be assignable to the
84
+ column it belongs in — `db-codegen` imports them from `@pikku/core` instead.
@@ -0,0 +1,41 @@
1
+ ---
2
+ type: decision
3
+ title: The data-classification brand is an optional property
4
+ description: Making __classification__ required would break ordinary Kysely operands, so the brand only constrains values flowing out
5
+ tags: core
6
+ ---
7
+
8
+ # The data-classification brand is an optional property
9
+
10
+ `Private<T>`, `Pii<T>` and `Secret<T>` in
11
+ `packages/core/src/data-classification.ts` brand a type with
12
+ `{ readonly __classification__?: 'private' | 'pii' | 'secret' }` — and the
13
+ marker is **optional on purpose**.
14
+
15
+ A required property would make a plain value unassignable to a branded column: a
16
+ `string` could no longer be passed where `Private<string>` is expected, which
17
+ breaks every ordinary Kysely query operand — `where('email', '=', someString)`,
18
+ inserts, and `.set(...)`. Making it optional keeps the brand structurally present
19
+ so static analysis still sees it, while letting plain values flow *in*. The
20
+ asymmetry is the point: the brand constrains what comes out of a query, not what
21
+ goes into one.
22
+
23
+ The consumer is `@pikku/inspector`, whose `findPiiPaths` reads the level union
24
+ directly and whose PKU910 output check detects the brand on a function's return
25
+ type. The brands are populated from the hand-authored `db/annotations.ts`
26
+ (`DbClassificationMap`) via `pikku db migrate`, which regenerates
27
+ `outDir/db/schema.d.ts` and `outDir/db/classification.gen.ts`.
28
+
29
+ A column's **at-rest form** is a separate axis making the opposite trade — see
30
+ [form is an axis of its own](core-column-form-is-an-axis-of-its-own.md). Its
31
+ brands are nominal and required, which is safe precisely because they land on
32
+ the INSERT/UPDATE side of the columns that opt in, rather than on the SELECT
33
+ side of every classified column. That is not an exception to the rule below; it
34
+ is a different rule about a different side.
35
+
36
+ **What this rules out:** making `__classification__` required to get stronger
37
+ guarantees, or replacing the optional property with a unique symbol / nominal
38
+ brand that behaves like a required one. Either change compiles here and then
39
+ breaks every generated Kysely call site in every downstream project. It also
40
+ rules out renaming the property or narrowing its literal union without updating
41
+ `findPiiPaths` in the inspector, which matches on both.
@@ -0,0 +1,44 @@
1
+ ---
2
+ type: decision
3
+ title: The function runner restores the wire fields it overwrites
4
+ description: One wire object is reused across nested calls, so functionId, audit, addonNamespace and rpc are saved and put back in a finally
5
+ tags: core
6
+ ---
7
+
8
+ # The function runner restores the wire fields it overwrites
9
+
10
+ `runPikkuFunc` in `packages/core/src/function/function-runner.ts` does not build a
11
+ fresh wire per call. Nested invocations — an RPC from inside a function, an addon
12
+ sibling call, a workflow step — reuse the *same* wire object the outer transport
13
+ created. So before it runs, the runner captures `functionId`, `audit`,
14
+ `addonNamespace` and the property descriptor for `rpc`, overwrites them for the
15
+ duration of this function, and restores or `delete`s them in a `finally`. Both
16
+ the middleware path and the direct path carry that restore block. Without it, an
17
+ inner call would leave its identity on the wire and every subsequent outer step
18
+ would be attributed to the wrong function.
19
+
20
+ The same reuse is why the audit binding is re-gated inside `executeFunction`
21
+ rather than trusted from `createWireServices`. The audit *gate* is per-function
22
+ but the `auditLog` wire service is created per-transport-invocation. A nested or
23
+ exposed-RPC call would otherwise inherit an `auditLog` built while the outer
24
+ wire's audit config was unset (the generated `rpcCaller` declares none), and
25
+ every write from the audited inner function would be silently dropped. The runner
26
+ compares config identity (`services.auditLog?.config !== resolvedAuditConfig`)
27
+ and binds a fresh invocation audit when they differ, then closes it in the
28
+ `finally` before wire services are closed.
29
+
30
+ Authorization order in `executeFunction` is also deliberate: session resolution,
31
+ then the auth/readonly checks, then `verifyScopes` — all of which depend only on
32
+ the session — and only then `await data()`, schema defaults, coercion, validation
33
+ and `runPermissions`. A request denied by scope never pays to parse or validate
34
+ its body. `rpc` is installed as a lazily-evaluating accessor that replaces itself
35
+ with the resolved value on first read, capturing the *caller's* package name in
36
+ the closure so an addon's RPCs resolve in its own namespace.
37
+
38
+ **What this rules out:** dropping the save/restore blocks as duplicated
39
+ boilerplate, or "hoisting" them into a single wrapper that only runs on the
40
+ outermost call. It rules out moving `verifyScopes` down next to `runPermissions`
41
+ for tidiness — that reintroduces body parsing for denied requests. And it rules
42
+ out taking `services.auditLog` at face value when the function declares audit;
43
+ the identity check is the only thing distinguishing an inherited disabled
44
+ instance from one built for this invocation.
@@ -0,0 +1,39 @@
1
+ ---
2
+ type: decision
3
+ title: Hot reload merges generated meta and never replaces it
4
+ description: Reloading codegen output must preserve runtime-registered meta, which no generated JSON contains
5
+ tags: core
6
+ ---
7
+
8
+ # Hot reload merges generated meta and never replaces it
9
+
10
+ `reloadGeneratedMeta` in `packages/core/src/dev/reload-meta.ts` re-reads the
11
+ codegen output (`.pikku/**/​*.gen.json`) straight into `pikkuState` after each dev
12
+ codegen pass. It reads the JSON directly rather than re-importing the generated
13
+ `*-meta.gen.ts` wrappers because the ESM cache pins both the wrapper and its JSON
14
+ import, so a re-import returns the stale value.
15
+
16
+ For `function.meta` and `queue.meta` it merges over the existing map instead of
17
+ assigning. Framework internals are registered at service-init time and appear in
18
+ no generated file: `pikkuWorkflowOrchestrator` and the per-workflow
19
+ `wf-orchestrator-*` / `wf-step-*` queue workers are added by
20
+ `pikku-workflow-service.ts`. A wholesale replace drops them, and the next
21
+ workflow job fails with `Function meta not found: pikkuWorkflowOrchestrator`.
22
+ `dev/reload-meta.test.ts` pins this. Meta maps that only codegen ever writes
23
+ (`http`, `rpc`, `agent`) are assigned outright.
24
+
25
+ Two limits are inherent rather than incidental. Routes registered by a *new*
26
+ `wireHTTP` file are not picked up here — those modules were never imported — which
27
+ is why `hot-reload.ts` keeps a `postCodegenQueue` and exposes `reimportPending()`
28
+ for the dev server to drain after codegen, so registrations that were skipped for
29
+ missing meta run again against fresh meta. And `reconcileAddonRegistry` has to
30
+ prune `addons.packages` explicitly, because hot reload only ever re-imports files
31
+ that still exist, so a deleted `*.addon.ts` would otherwise leave its `wireAddon`
32
+ entry stranded until a restart.
33
+
34
+ **What this rules out:** replacing the two merges with plain
35
+ `pikkuState(null, 'function', 'meta', functionsMeta)` assignments on the grounds
36
+ that codegen output is authoritative — it is authoritative only for what codegen
37
+ emits. It also rules out folding `reimportPending()` back into the debounced
38
+ reload (the whole point is that it runs *after* codegen), and dropping
39
+ `reconcileAddonRegistry` as dead code.
@@ -0,0 +1,42 @@
1
+ ---
2
+ type: decision
3
+ title: Hot reload owns its module registry instead of re-importing
4
+ description: Dev reload transpiles to CJS and runs modules through vm.compileFunction, because the native ESM loader map cannot be evicted
5
+ tags: core
6
+ ---
7
+
8
+ # Hot reload owns its module registry instead of re-importing
9
+
10
+ `packages/core/src/dev/module-runner.ts` re-runs a changed user file by
11
+ transpiling it to CJS with esbuild, executing it via `vm.compileFunction`, and
12
+ storing the resulting exports under a **stable absolute-path key**. A reload
13
+ overwrites that one registry slot, so the previous module becomes unreachable and
14
+ is collected. `packages/core/src/dev/hot-reload.ts` drives it from the file
15
+ watcher.
16
+
17
+ The obvious alternative — re-`import()`ing the file under a fresh URL (a `data:`
18
+ URL on Node, a uniquely-named temp sibling on Bun) — is unbounded. The native ESM
19
+ loader keeps a `Map<url, moduleRecord>` for the life of the realm with no
20
+ eviction API, so every reload permanently leaks a module record; measured at
21
+ roughly 0.3–1.3 MB per edit, which is ~84 MB on Node and ~222 MB on Bun over 200
22
+ edits, and eventually OOMs a long editing session. `dev/module-runner.test.ts`
23
+ asserts both the single-slot guarantee and bounded heap growth.
24
+
25
+ Two details keep the mechanism honest. `import`s inside the user file are
26
+ delegated to `createRequire`, whose resolution matches the native loader *and*
27
+ returns the same live singletons (Node and Bun share the require/import cache) —
28
+ that is what lets a reloaded file's top-level `wireHTTP` side effects mutate the
29
+ services the running server is already using. And esbuild is invoked with no
30
+ sourcemap: an inline sourcemap embeds a base64 copy of the source that the engine
31
+ retains per compile, reintroducing exactly the linear growth this runner exists
32
+ to remove. The known limitation is that a file using top-level `await` cannot be
33
+ emitted as CJS; `run` returns `null` and the caller keeps the previously loaded
34
+ code.
35
+
36
+ **What this rules out:** "simplifying" the reloader back to `await
37
+ import(url + '?t=' + Date.now())` or any fresh-URL variant, and turning
38
+ sourcemaps back on for nicer stack traces (`filename` already anchors traces to
39
+ the user file). It also rules out swapping `createRequire` for a fresh `import()`
40
+ inside the compiled module — resolution would produce a *distinct* copy of every
41
+ dependency, and the reloaded file would then wire itself into services nobody is
42
+ serving from.
@@ -0,0 +1,39 @@
1
+ ---
2
+ type: decision
3
+ title: Middleware order is resolution scope first, then priority
4
+ description: Middleware is collected global to function, then stably sorted by priority, deduped, frozen and cached per wire
5
+ tags: core
6
+ ---
7
+
8
+ # Middleware order is resolution scope first, then priority
9
+
10
+ `combineMiddleware` in `packages/core/src/middleware-runner.ts` builds the chain
11
+ for a wire by appending, in this order: global middleware
12
+ (`addGlobalMiddleware`), then wire-inherited entries (the HTTP route group, then
13
+ tag groups resolved parent-first by `getTagGroups`, then named wire middleware),
14
+ then inline wire middleware, then function-inherited tag groups, then inline
15
+ function middleware. That collected array is then stably sorted by
16
+ `MiddlewarePriority` — `highest` (0) runs first and outermost, `lowest` (4) runs
17
+ last and innermost, closest to the function, with `medium` the default — and
18
+ finally passed through `freezeDedupe` and cached in `middlewareCache` keyed by
19
+ wire type and wire id.
20
+
21
+ Two properties fall out of that and both are load-bearing. Because the sort is
22
+ stable, priority is a coarse band and registration order breaks ties *within* a
23
+ band, so declaration order still means something. And because the result is
24
+ deduped by function identity, a middleware reachable through both a tag group and
25
+ a direct wire registration runs exactly once — a fact several tests assert
26
+ directly. `runMiddleware` re-sorts only when `isSortedByPriority` says the input
27
+ is not already ordered, which is why the cached array must never be handed back
28
+ unsorted.
29
+
30
+ The cache is why `clearMiddlewareCache()` exists and why dev hot-reload calls it
31
+ alongside `clearPermissionsCache()`, `clearChannelMiddlewareCache()` and
32
+ `httpRouter.reset()` on every reload.
33
+
34
+ **What this rules out:** switching `sortByPriority` to a comparator that is not
35
+ stable, or to a sort that runs before the scope-ordered collection — either one
36
+ silently reorders same-priority middleware and breaks the "declaration order
37
+ wins within a band" contract. It also rules out dropping `freezeDedupe` as
38
+ redundant (a tag-plus-wire registration would then run twice), and rules out
39
+ caching by wire id alone without clearing on reload.
@@ -0,0 +1,43 @@
1
+ ---
2
+ type: decision
3
+ title: Schema defaults are applied on every transport, not just HTTP
4
+ description: Defaults belong to the schema rather than the call's encoding, so they run unconditionally and are cloned per request
5
+ tags: core
6
+ ---
7
+
8
+ # Schema defaults are applied on every transport, not just HTTP
9
+
10
+ `applyDefaultsFromSchema` in `packages/core/src/schema.ts` fills in absent
11
+ top-level properties from their JSON Schema `default`, and the function runner
12
+ calls it **unconditionally** — before coercion, before validation, on every wire
13
+ type.
14
+
15
+ It exists because a `default` reaches the generated JSON Schema and keeps the
16
+ property out of `required`, so omitting it validates. But JSON Schema validators
17
+ are pure by specification, and none of the ones Pikku ships with
18
+ (`@cfworker/json-schema`, and Ajv unless `useDefaults` is set) annotate the
19
+ instance. The function therefore received `undefined` for a property its
20
+ generated TypeScript type declares as present — the worst shape a mismatch can
21
+ take: validation permits the omission, the type promises the value, the body
22
+ reads `undefined`.
23
+
24
+ It is deliberately *not* gated on the `coerceDataFromSchema` flag that guards
25
+ `coerceTopLevelDataFromSchema`. That flag is about decoding transport-encoded
26
+ values — a query string's `"1,2"` into an array, an ISO string into a `Date` —
27
+ and is set only by transports that need it. Defaults are a property of the
28
+ schema, not of how the call arrived, so gating them on that flag would apply them
29
+ over HTTP and skip them on a direct RPC invocation. Two smaller rules follow: a
30
+ non-null primitive body is returned untouched for the validator to reject rather
31
+ than reshaped into something that would pass; and each value is
32
+ `structuredClone`d, so an object or array default (`[]`, `{}`) is never shared as
33
+ one mutable instance across every request. The result object is allocated only
34
+ once a default is actually found, which is what lets a call made with no
35
+ arguments at all still receive them.
36
+
37
+ **What this rules out:** moving the `applyDefaultsFromSchema` call inside the
38
+ `if (coerceDataFromSchema)` branch next to the coercion call, or reordering it
39
+ after validation. It also rules out dropping the `structuredClone` as an
40
+ allocation — the shared-mutable-default bug it prevents is cross-request and
41
+ `schema.test.ts` pins it — and rules out replacing the `'default' in property`
42
+ presence check with a truthiness check, since `false` and `0` are exactly the
43
+ defaults a truthiness check silently discards.
@@ -0,0 +1,38 @@
1
+ ---
2
+ type: decision
3
+ title: Scopes are an AND gate, separate from permissions
4
+ description: Every declared scope must be held, so adding one can only narrow access — permissions OR, and can only widen it
5
+ tags: core
6
+ ---
7
+
8
+ # Scopes are an AND gate, separate from permissions
9
+
10
+ `packages/core/src/scopes.ts` implements the scope check that
11
+ `runPikkuFunc` performs before permissions. Every entry in a function's `scopes`
12
+ must be satisfied by the session's grants — an AND gate — and the check fails
13
+ closed: a session without a `scopes` field, or no session at all, satisfies
14
+ nothing. An empty `required` is the only thing anything satisfies.
15
+
16
+ This is deliberately the opposite composition from `permissions`, whose groups OR
17
+ together. Because permissions OR, adding a permission group can only *widen*
18
+ access; because scopes AND, adding a scope can only *narrow* it. That is the
19
+ whole reason the two are separate mechanisms and separate code paths rather than
20
+ one merged authorization step, and it is why a passing global or function
21
+ permission must never be allowed to satisfy a scope.
22
+
23
+ Satisfaction itself is hierarchical, computed by `satisfyingGrants`: a grant
24
+ matches when it is the scope itself, a plain ancestor (`admin` covers
25
+ `admin:invoices:create`), a wildcard at or above it (`admin:*`, or the bare `*`),
26
+ or a wildcard directly beneath it. Narrower never satisfies broader —
27
+ `admin:invoices` does not grant `admin`. Core only ever *reads*
28
+ `session.scopes`; whoever builds the session populates it (better-auth's
29
+ `mapSession` resolving through a `ScopeService`, for instance), and the runner
30
+ never fetches. `hasScopes` is the non-throwing counterpart of `verifyScopes`, for
31
+ gates that fall back to another check rather than rejecting outright.
32
+
33
+ **What this rules out:** folding the scope check into `runPermissions` so there
34
+ is "one authorization step", or making an OR of scopes so a session holding any
35
+ one of them passes. Either turns a narrowing gate into a widening one, which is a
36
+ privilege escalation and not a refactor. It also rules out defaulting an absent
37
+ `session.scopes` to "all" for convenience, and rules out having core resolve
38
+ scopes itself at call time.
@@ -0,0 +1,44 @@
1
+ ---
2
+ type: decision
3
+ title: Pikku state is a global map written only at registration time
4
+ description: A symbol-keyed globalThis map holds the wiring registry; nothing per-request may ever be written to it
5
+ tags: core
6
+ ---
7
+
8
+ # Pikku state is a global map written only at registration time
9
+
10
+ `packages/core/src/pikku-state.ts` keeps every registry Pikku has —
11
+ functions, HTTP routes, channels, schedulers, queues, workflows, triggers, MCP
12
+ tools, agents, gateways, CLI programs, middleware groups, permissions, schemas
13
+ and error definitions — in a single `Map<string, PikkuPackageState>` hung off
14
+ `globalThis` under `Symbol('@pikku/core/state')`. `pikkuState(packageName, type,
15
+ content, value?)` is the only accessor; `PikkuPackageState` in
16
+ `packages/core/src/types/state.types.ts` is its shape.
17
+
18
+ It is on `globalThis` rather than in a module-level `const` because a bundled
19
+ app can end up with more than one copy of `@pikku/core` in the module graph
20
+ (workspace links, addon packages that depend on their own core, a runtime
21
+ adapter pulling a second instance). Module-level state would give each copy its
22
+ own empty registry and functions would go missing at call time; a symbol on the
23
+ realm global is shared by every copy in that realm. The package-name dimension
24
+ is what keeps addon registries from colliding with the host project's.
25
+
26
+ Everything written here is written **once, at import time**, by `wireHTTP`,
27
+ `addFunction`, `addTagMiddleware`, `addError`, `addSchema` and friends — that is,
28
+ by the top-level side effects of the generated and user modules. It is
29
+ registration data, not request data. Pikku must stay stateless and
30
+ serverless-compatible: the same process serves concurrent invocations on Lambda,
31
+ Workers and multi-instance containers, and nothing in a request may outlive it.
32
+ The file reads like a violation of that rule until you know the writes are all
33
+ registration-time. The one exception is deliberate and narrow:
34
+ `resetPikkuState()` preserves the `misc.errors` map across a reset, because error
35
+ definitions are registered by module-import side effects that will not re-run.
36
+
37
+ **What this rules out:** using `pikkuState` as a convenient place to stash
38
+ anything derived from an invocation — a session, a request-scoped cache, a
39
+ pending workflow, a "current user". Any such write is shared across every
40
+ concurrent request in the process and lost entirely on the next cold start. It
41
+ also rules out replacing the `globalThis` symbol with a module-scoped `Map` "for
42
+ cleanliness", and rules out making the state per-request (an `AsyncLocalStorage`
43
+ context, say) — the registry is read on hot paths by the function runner and the
44
+ routers, and it must be identical for every caller.
@@ -0,0 +1,27 @@
1
+ ---
2
+ type: decision
3
+ title: Email meta is read uncached because codegen rewrites it mid-session
4
+ description: getEmailMeta re-reads its file on every call, unlike every other meta accessor, because the file appears and changes during a long-lived session
5
+ tags: services
6
+ ---
7
+
8
+ # Email meta is read uncached because codegen rewrites it mid-session
9
+
10
+ `LocalMetaService.getEmailMeta` (`packages/core/src/services/meta-service.ts`)
11
+ reads `email/pikku-emails-meta.gen.json` fresh on every call. Every other
12
+ `getXMeta` on that class memoises into a private cache field; this one
13
+ deliberately does not.
14
+
15
+ The email meta file is written by `pikku all` / `pikku emails generate`, and in a
16
+ long-lived session it is regenerated underneath a running process — the sandbox
17
+ boots the orchestrator before the user project's codegen has produced it. When
18
+ this accessor was cached, the first call landed before the file existed, cached
19
+ the empty `{ templates: {} }` fallback, and the console's emails screen stayed
20
+ blank for the rest of the session even after the file appeared. A local JSON
21
+ read is essentially free, so re-reading is the cheaper mistake.
22
+
23
+ **What this rules out:** "consistency" refactors that give every meta accessor
24
+ the same caching treatment, including the one that collapses the ~25 hand-written
25
+ `getXMeta` methods and their cache fields into a single generic
26
+ `cached(key, loader)` helper. Email meta must stay outside whatever cache that
27
+ introduces.
@@ -0,0 +1,32 @@
1
+ ---
2
+ type: decision
3
+ title: Gateway adapters resolve lazily and are promise-cached
4
+ description: wireGateway accepts an adapter factory because real adapters need boot-time secrets, which forces the webhook GET route to be registered unconditionally
5
+ tags: gateway
6
+ ---
7
+
8
+ # Gateway adapters resolve lazily and are promise-cached
9
+
10
+ `wireGateway` runs at module load, before secrets and services exist. Real
11
+ platform adapters (WhatsApp Cloud API, Slack, …) need both, so
12
+ `CoreGateway.adapter` accepts a `GatewayAdapterFactory` as well as an instance.
13
+ `resolveGatewayAdapter` in
14
+ `packages/core/src/wirings/gateway/gateway-runner.ts` invokes the factory on the
15
+ first inbound request (webhook/websocket) or on gateway start (listener). The
16
+ `resolvedAdapters` WeakMap caches the *promise*, not the resolved adapter, so
17
+ concurrent first requests share one construction instead of racing to build two
18
+ adapters — which for a stateful adapter would mean two platform connections.
19
+
20
+ The lazy resolution has one visible consequence in `wireWebhookGateway`: a
21
+ factory cannot be probed for `verifyWebhook` at wiring time, because it has not
22
+ run yet. The GET verification route is therefore registered unconditionally
23
+ whenever the adapter is a function, and only conditionally
24
+ (`adapter.verifyWebhook`) when it is a concrete instance. The GET handler throws
25
+ `NotFoundError` at request time if the resolved adapter turns out not to support
26
+ verification.
27
+
28
+ **What this rules out:** calling the factory eagerly inside `wireGateway` to
29
+ "simplify" route registration, caching the resolved adapter instead of the
30
+ promise, and narrowing the GET route registration to `adapter.verifyWebhook` for
31
+ all adapters — the last silently drops webhook verification for every
32
+ factory-based gateway.
@@ -0,0 +1,28 @@
1
+ ---
2
+ type: decision
3
+ title: Gateway webhook challenges echo bytes not JSON
4
+ description: String verification challenges are returned raw with returnsJSON false, because platforms byte-compare the echo and JSON quoting fails the handshake
5
+ tags: gateway
6
+ ---
7
+
8
+ # Gateway webhook challenges echo bytes not JSON
9
+
10
+ Webhook verification handshakes (WhatsApp's `hub.challenge`, similar GET
11
+ challenges elsewhere) are validated by the platform doing a byte-for-byte
12
+ comparison of the response body against the challenge it sent. JSON-encoding a
13
+ string challenge adds surrounding quotes and fails the handshake, and the gateway
14
+ is then never activated.
15
+
16
+ `wireWebhookGateway` in
17
+ `packages/core/src/wirings/gateway/gateway-runner.ts` therefore registers the GET
18
+ verification route with `returnsJSON: false`, and
19
+ `createWebhookVerifyHandler` returns `String(response)` when the adapter's
20
+ `WebhookVerificationResult.response` is a string or number. Object responses
21
+ (Slack's `url_verification` style) still go out as JSON, with the
22
+ `content-type: application/json` header set explicitly by the handler, since the
23
+ route no longer does it.
24
+
25
+ **What this rules out:** setting `returnsJSON: true` on the gateway GET route for
26
+ consistency with other routes, and routing the challenge response through the
27
+ normal JSON serializer. Any change that makes the string branch serialize as JSON
28
+ breaks webhook activation on every platform that byte-compares.
@@ -0,0 +1,31 @@
1
+ ---
2
+ type: decision
3
+ title: Gateway wiring is a meta-wiring over HTTP and channels
4
+ description: wireGateway writes handler implementations into the HTTP and channel state directly while the inspector compiles the corresponding meta, so runtime registration deliberately writes no meta
5
+ tags: gateway
6
+ ---
7
+
8
+ # Gateway wiring is a meta-wiring over HTTP and channels
9
+
10
+ `wireGateway` in `packages/core/src/wirings/gateway/gateway-runner.ts` is not a
11
+ transport of its own. It composes the existing primitives: a `webhook` gateway
12
+ pushes entries straight into `pikkuState(null, 'http', 'routes')`, a `websocket`
13
+ gateway pushes into `pikkuState(null, 'channel', 'meta')` and `'channels'`, and a
14
+ `listener` gateway registers no route at all and is driven by a
15
+ `GatewayService` calling `createListenerMessageHandler`. Each mutation is
16
+ followed by `httpRouter.reset()` because the router caches its match table.
17
+
18
+ The wrapper functions and routes created here look like they are missing their
19
+ metadata. They are not: the inspector projects a `wireGateway` call into the
20
+ generated HTTP and function meta at build time, so only the handler
21
+ *implementations* register at runtime — the same split every other wire uses.
22
+ This is why `wireWebhookGateway` writes route entries but no `CommonWireMeta`,
23
+ and why the websocket path sets `channels.set(name, …)` with empty
24
+ `onConnect`/`onMessage` stubs while the real handlers live under the
25
+ `gateway__<name>__connect` / `__message` function ids named in the channel meta.
26
+
27
+ **What this rules out:** adding runtime meta generation inside `wireGateway` to
28
+ "fix" the apparently missing metadata — it would duplicate or conflict with the
29
+ compiled meta. It also rules out replacing the empty channel `onConnect` /
30
+ `onMessage` stubs with the real handler functions; the channel runner dispatches
31
+ through the meta's `pikkuFuncId`, not through those fields.
@@ -0,0 +1,26 @@
1
+ ---
2
+ type: decision
3
+ title: Generated src paths in pikku meta are absolute
4
+ description: emailsMeta.src is resolved by the CLI at generation time, so reading through the project-relative helpers produces a wrong compound path
5
+ tags: services
6
+ ---
7
+
8
+ # Generated src paths in pikku meta are absolute
9
+
10
+ `emailsMeta.src` is written by the CLI at generation time and is already an
11
+ absolute filesystem path. `LocalMetaService.getEmailTemplateAssets`
12
+ (`packages/core/src/services/meta-service.ts`) therefore calls `readFile` on
13
+ `join(baseDir, rel)` directly instead of going through its own
14
+ `readProjectFile`, which is the helper every other read in that class uses.
15
+
16
+ `readProjectFile` prepends the project root (`join(basePath, '..', relativePath)`).
17
+ Handing it an already-absolute `src` yields a compound path that points nowhere,
18
+ and the failure is silent — the helpers return `null` on a missing file, so the
19
+ symptom is a template that reports itself as having no assets rather than an
20
+ error naming the path.
21
+
22
+ **What this rules out:** routing the email asset reads through `readProjectFile`
23
+ or `readFile` "for consistency", and assuming that any `src` field appearing in a
24
+ `.gen.json` is relative to the project. If a remote `MetaService` ever needs to
25
+ serve these assets, it has to translate the absolute path rather than pass it
26
+ through.
@@ -0,0 +1,32 @@
1
+ ---
2
+ type: decision
3
+ title: HTTP request bodies are read once and shared between consumers
4
+ description: The fetch request wrapper memoises the single-use body and builds web Requests lazily, at the cost of holding the whole body in memory
5
+ tags: http
6
+ ---
7
+
8
+ # HTTP request bodies are read once and shared between consumers
9
+
10
+ A fetch `Request` body is a single-use stream: the second reader gets "Body has
11
+ already been used". `PikkuFetchHTTPRequest` in
12
+ `packages/core/src/wirings/http/pikku-fetch-http-request.ts` therefore funnels
13
+ `json()`, `arrayBuffer()`, `data()` and everything reached through
14
+ `toWebRequest()` into `#readRawBuffer`, which memoises both the in-flight promise
15
+ and the resolved buffer. A second consumer arriving while the first read is still
16
+ running is served the same promise — and warned, because a duplicate consumer is
17
+ a bug to remove at the source rather than a case to lean on the cache for.
18
+
19
+ `toWebRequest` in `packages/core/src/wirings/http/web-request.ts` builds its body
20
+ stream with `pull` rather than `start`, so the underlying body is touched only
21
+ when the stream is actually consumed. A caller that constructs a web `Request`
22
+ purely to read headers — session middleware calling `getSession({ headers })` is
23
+ the common case — performs zero body I/O and cannot race the route handler's own
24
+ read. Its fallback path exists because some runtimes (Express with a body-parser
25
+ in front) hand pikku a request whose raw body is already drained; there
26
+ `arrayBuffer()` is empty and the body has to be reconstructed from the parsed
27
+ form or JSON.
28
+
29
+ **What this rules out:** calling `request.arrayBuffer()`/`request.json()` on the
30
+ underlying fetch `Request` directly anywhere in the runner; switching the
31
+ `toWebRequest` stream to `start` for eagerness; and deleting the empty-buffer
32
+ reconstruction branch as an impossible case.