@pikku/core 0.12.72 → 0.12.74

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 (811) hide show
  1. package/CHANGELOG.md +793 -0
  2. package/dist/crypto-utils.d.ts +30 -5
  3. package/dist/crypto-utils.js +146 -41
  4. package/dist/dev/hot-reload.js +11 -30
  5. package/dist/dev/module-runner.d.ts +3 -7
  6. package/dist/dev/module-runner.js +4 -10
  7. package/dist/dev/reload-meta.d.ts +8 -20
  8. package/dist/dev/reload-meta.js +9 -29
  9. package/dist/errors/error-handler.d.ts +5 -30
  10. package/dist/errors/error-handler.js +16 -32
  11. package/dist/errors/errors.d.ts +32 -151
  12. package/dist/errors/errors.js +55 -157
  13. package/dist/function/abort-scope.d.ts +47 -0
  14. package/dist/function/abort-scope.js +63 -0
  15. package/dist/function/function-runner.js +37 -32
  16. package/dist/function/functions.types.d.ts +44 -136
  17. package/dist/function/functions.types.js +0 -58
  18. package/dist/function/list.types.d.ts +12 -62
  19. package/dist/function/list.types.js +4 -25
  20. package/dist/handle-error.d.ts +0 -13
  21. package/dist/handle-error.js +0 -18
  22. package/dist/index.d.ts +5 -2
  23. package/dist/index.js +4 -1
  24. package/dist/middleware/auth-apikey.d.ts +3 -18
  25. package/dist/middleware/auth-apikey.js +0 -17
  26. package/dist/middleware/auth-bearer.d.ts +6 -41
  27. package/dist/middleware/auth-bearer.js +3 -40
  28. package/dist/middleware/auth-cookie.d.ts +5 -27
  29. package/dist/middleware/auth-cookie.js +2 -26
  30. package/dist/middleware/cors.d.ts +7 -34
  31. package/dist/middleware/cors.js +7 -34
  32. package/dist/middleware/remote-auth.d.ts +3 -1
  33. package/dist/middleware/remote-auth.js +3 -2
  34. package/dist/middleware/telemetry.d.ts +8 -33
  35. package/dist/middleware/telemetry.js +2 -31
  36. package/dist/middleware-runner.d.ts +4 -55
  37. package/dist/middleware-runner.js +5 -74
  38. package/dist/permissions.d.ts +3 -44
  39. package/dist/permissions.js +19 -71
  40. package/dist/pikku-request.d.ts +0 -6
  41. package/dist/pikku-request.js +0 -6
  42. package/dist/pikku-state.d.ts +0 -26
  43. package/dist/pikku-state.js +2 -30
  44. package/dist/remote.d.ts +3 -5
  45. package/dist/remote.js +8 -7
  46. package/dist/schema.d.ts +5 -39
  47. package/dist/schema.js +5 -39
  48. package/dist/scopes.d.ts +4 -23
  49. package/dist/scopes.js +7 -48
  50. package/dist/services/ai-agent-runner-service.d.ts +20 -0
  51. package/dist/services/ai-embedding-service.d.ts +2 -25
  52. package/dist/services/audit-service.js +1 -2
  53. package/dist/services/content-service.d.ts +1 -46
  54. package/dist/services/credential-service.d.ts +3 -40
  55. package/dist/services/deployment-service.d.ts +3 -9
  56. package/dist/services/gateway-service.d.ts +0 -15
  57. package/dist/services/http-personas.d.ts +80 -0
  58. package/dist/services/http-personas.js +233 -0
  59. package/dist/services/in-memory-queue-service.d.ts +0 -14
  60. package/dist/services/in-memory-queue-service.js +1 -15
  61. package/dist/services/in-memory-trigger-service.d.ts +0 -18
  62. package/dist/services/in-memory-trigger-service.js +1 -18
  63. package/dist/services/in-memory-workflow-service.d.ts +0 -16
  64. package/dist/services/in-memory-workflow-service.js +4 -33
  65. package/dist/services/index.d.ts +5 -6
  66. package/dist/services/index.js +2 -5
  67. package/dist/services/istanbul-coverage-service.d.ts +1 -5
  68. package/dist/services/istanbul-coverage-service.js +2 -8
  69. package/dist/services/jwt-service.d.ts +1 -16
  70. package/dist/services/local-content.d.ts +13 -2
  71. package/dist/services/local-content.js +40 -13
  72. package/dist/services/local-gateway-service.d.ts +0 -16
  73. package/dist/services/local-gateway-service.js +2 -17
  74. package/dist/services/local-secrets.d.ts +0 -4
  75. package/dist/services/local-secrets.js +0 -4
  76. package/dist/services/logger-console.d.ts +3 -7
  77. package/dist/services/logger-console.js +3 -7
  78. package/dist/services/logger.d.ts +2 -37
  79. package/dist/services/meta-service.d.ts +23 -26
  80. package/dist/services/meta-service.js +22 -36
  81. package/dist/services/personas-service.d.ts +134 -0
  82. package/dist/services/personas-service.js +40 -0
  83. package/dist/services/pikku-user-id.js +0 -4
  84. package/dist/services/queue-webhook-service.d.ts +2 -36
  85. package/dist/services/queue-webhook-service.js +9 -41
  86. package/dist/services/scheduler-service.d.ts +1 -50
  87. package/dist/services/scheduler-service.js +0 -10
  88. package/dist/services/schema-service.d.ts +1 -24
  89. package/dist/services/scope-service.d.ts +49 -34
  90. package/dist/services/scoped-secret-service.d.ts +0 -4
  91. package/dist/services/scoped-secret-service.js +0 -4
  92. package/dist/services/secret-host-binding.d.ts +8 -0
  93. package/dist/services/secret-host-binding.js +36 -0
  94. package/dist/services/secret-service.d.ts +5 -33
  95. package/dist/services/secretless.d.ts +6 -0
  96. package/dist/services/secretless.js +21 -0
  97. package/dist/services/stub-tracker.d.ts +7 -18
  98. package/dist/services/stub-tracker.js +8 -18
  99. package/dist/services/system-role-guard.d.ts +33 -0
  100. package/dist/services/system-role-guard.js +38 -0
  101. package/dist/services/trigger-service.d.ts +0 -12
  102. package/dist/services/typed-secret-service.d.ts +0 -7
  103. package/dist/services/typed-secret-service.js +1 -7
  104. package/dist/services/v8-coverage-service.d.ts +2 -3
  105. package/dist/services/v8-coverage-service.js +1 -2
  106. package/dist/services/variables-service.d.ts +1 -8
  107. package/dist/services/webhook-service.d.ts +19 -63
  108. package/dist/services/webhook-service.js +6 -20
  109. package/dist/services/workflow-service.d.ts +3 -15
  110. package/dist/testing/service-tests.js +0 -17
  111. package/dist/time-utils.d.ts +0 -16
  112. package/dist/time-utils.js +1 -19
  113. package/dist/types/core.types.d.ts +99 -219
  114. package/dist/types/core.types.js +0 -42
  115. package/dist/types/state.types.d.ts +4 -9
  116. package/dist/utils/hmac.d.ts +4 -10
  117. package/dist/utils/hmac.js +4 -10
  118. package/dist/utils/safe-fetch.d.ts +7 -35
  119. package/dist/utils/safe-fetch.js +13 -53
  120. package/dist/utils.d.ts +1 -6
  121. package/dist/utils.js +6 -15
  122. package/dist/wirings/actor-flow/actor-flow.types.d.ts +1 -34
  123. package/dist/wirings/actor-flow/index.d.ts +0 -9
  124. package/dist/wirings/actor-flow/run-conversation.d.ts +5 -5
  125. package/dist/wirings/actor-flow/run-conversation.js +14 -7
  126. package/dist/wirings/ai-agent/ai-agent-agui.d.ts +0 -5
  127. package/dist/wirings/ai-agent/ai-agent-agui.js +34 -12
  128. package/dist/wirings/ai-agent/ai-agent-helpers.d.ts +7 -0
  129. package/dist/wirings/ai-agent/ai-agent-helpers.js +7 -0
  130. package/dist/wirings/ai-agent/ai-agent-interrupt.d.ts +153 -0
  131. package/dist/wirings/ai-agent/ai-agent-interrupt.js +256 -0
  132. package/dist/wirings/ai-agent/ai-agent-memory.js +0 -2
  133. package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +0 -9
  134. package/dist/wirings/ai-agent/ai-agent-model-config.js +1 -9
  135. package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +10 -99
  136. package/dist/wirings/ai-agent/ai-agent-prepare.js +58 -131
  137. package/dist/wirings/ai-agent/ai-agent-registry.d.ts +2 -1
  138. package/dist/wirings/ai-agent/ai-agent-registry.js +5 -1
  139. package/dist/wirings/ai-agent/ai-agent-runner.js +49 -20
  140. package/dist/wirings/ai-agent/ai-agent-stream.d.ts +25 -2
  141. package/dist/wirings/ai-agent/ai-agent-stream.js +153 -63
  142. package/dist/wirings/ai-agent/ai-agent.types.d.ts +84 -4
  143. package/dist/wirings/ai-agent/index.d.ts +6 -4
  144. package/dist/wirings/ai-agent/index.js +5 -4
  145. package/dist/wirings/ai-agent/voice-input.d.ts +39 -1
  146. package/dist/wirings/ai-agent/voice-input.js +46 -3
  147. package/dist/wirings/ai-agent/voice-output.d.ts +54 -1
  148. package/dist/wirings/ai-agent/voice-output.js +153 -50
  149. package/dist/wirings/channel/channel-common.d.ts +7 -20
  150. package/dist/wirings/channel/channel-common.js +7 -21
  151. package/dist/wirings/channel/channel-handler.js +25 -6
  152. package/dist/wirings/channel/channel-host-rpc.d.ts +25 -0
  153. package/dist/wirings/channel/channel-host-rpc.js +38 -0
  154. package/dist/wirings/channel/channel-middleware-runner.d.ts +0 -12
  155. package/dist/wirings/channel/channel-middleware-runner.js +0 -12
  156. package/dist/wirings/channel/channel-rpc-registry.d.ts +31 -0
  157. package/dist/wirings/channel/channel-rpc-registry.js +89 -0
  158. package/dist/wirings/channel/channel-rpc-responder.d.ts +15 -0
  159. package/dist/wirings/channel/channel-rpc-responder.js +71 -0
  160. package/dist/wirings/channel/channel-rpc-service.d.ts +40 -0
  161. package/dist/wirings/channel/channel-rpc-service.js +106 -0
  162. package/dist/wirings/channel/channel-rpc-validators.d.ts +14 -0
  163. package/dist/wirings/channel/channel-rpc-validators.js +30 -0
  164. package/dist/wirings/channel/channel-rpc.d.ts +5 -0
  165. package/dist/wirings/channel/channel-rpc.js +5 -0
  166. package/dist/wirings/channel/channel-rpc.types.d.ts +90 -0
  167. package/dist/wirings/channel/channel-rpc.types.js +50 -0
  168. package/dist/wirings/channel/channel-runner.d.ts +0 -4
  169. package/dist/wirings/channel/channel-runner.js +0 -14
  170. package/dist/wirings/channel/channel-store.d.ts +0 -10
  171. package/dist/wirings/channel/channel.types.d.ts +12 -1
  172. package/dist/wirings/channel/define-channel-routes.d.ts +0 -20
  173. package/dist/wirings/channel/define-channel-routes.js +0 -20
  174. package/dist/wirings/channel/eventhub-service.d.ts +0 -18
  175. package/dist/wirings/channel/index.d.ts +4 -1
  176. package/dist/wirings/channel/index.js +2 -0
  177. package/dist/wirings/channel/local/local-channel-runner.js +3 -1
  178. package/dist/wirings/channel/local/local-eventhub-service.d.ts +0 -33
  179. package/dist/wirings/channel/local/local-eventhub-service.js +2 -36
  180. package/dist/wirings/channel/log-channels.d.ts +0 -4
  181. package/dist/wirings/channel/log-channels.js +0 -4
  182. package/dist/wirings/channel/pikku-abstract-channel-handler.js +6 -0
  183. package/dist/wirings/channel/serverless/serverless-channel-runner.js +2 -5
  184. package/dist/wirings/cli/channel/cli-approval.d.ts +41 -0
  185. package/dist/wirings/cli/channel/cli-approval.js +81 -0
  186. package/dist/wirings/cli/channel/cli-channel-runner.d.ts +0 -4
  187. package/dist/wirings/cli/channel/cli-channel-runner.js +3 -25
  188. package/dist/wirings/cli/channel/cli-raw-channel-runner.d.ts +47 -9
  189. package/dist/wirings/cli/channel/cli-raw-channel-runner.js +24 -16
  190. package/dist/wirings/cli/channel/cli-raw-client-runner.d.ts +20 -0
  191. package/dist/wirings/cli/channel/cli-raw-client-runner.js +121 -0
  192. package/dist/wirings/cli/channel/index.d.ts +4 -0
  193. package/dist/wirings/cli/channel/index.js +2 -0
  194. package/dist/wirings/cli/cli-runner.d.ts +20 -20
  195. package/dist/wirings/cli/cli-runner.js +28 -89
  196. package/dist/wirings/cli/cli.types.d.ts +14 -3
  197. package/dist/wirings/cli/command-parser.d.ts +1 -10
  198. package/dist/wirings/cli/command-parser.js +10 -87
  199. package/dist/wirings/cli/define-cli-commands.d.ts +1 -17
  200. package/dist/wirings/cli/define-cli-commands.js +1 -17
  201. package/dist/wirings/credential/credential.types.d.ts +0 -12
  202. package/dist/wirings/credential/define-credential.d.ts +48 -0
  203. package/dist/wirings/credential/define-credential.js +47 -0
  204. package/dist/wirings/credential/index.d.ts +1 -1
  205. package/dist/wirings/credential/index.js +1 -1
  206. package/dist/wirings/credential/validate-credential-definitions.d.ts +2 -4
  207. package/dist/wirings/gateway/gateway-runner.d.ts +1 -20
  208. package/dist/wirings/gateway/gateway-runner.js +8 -105
  209. package/dist/wirings/gateway/gateway.types.d.ts +7 -80
  210. package/dist/wirings/http/http-routes.d.ts +0 -63
  211. package/dist/wirings/http/http-routes.js +0 -63
  212. package/dist/wirings/http/http-runner.d.ts +0 -99
  213. package/dist/wirings/http/http-runner.js +9 -165
  214. package/dist/wirings/http/http.types.d.ts +14 -55
  215. package/dist/wirings/http/log-http-routes.d.ts +0 -4
  216. package/dist/wirings/http/log-http-routes.js +0 -4
  217. package/dist/wirings/http/pikku-fetch-http-request.d.ts +0 -40
  218. package/dist/wirings/http/pikku-fetch-http-request.js +0 -58
  219. package/dist/wirings/http/pikku-fetch-http-response.js +0 -3
  220. package/dist/wirings/http/routers/path-to-regex.js +2 -13
  221. package/dist/wirings/http/web-request.d.ts +0 -8
  222. package/dist/wirings/http/web-request.js +25 -17
  223. package/dist/wirings/mcp/mcp-runner.d.ts +1 -4
  224. package/dist/wirings/mcp/mcp-runner.js +1 -14
  225. package/dist/wirings/mcp/mcp.types.d.ts +2 -35
  226. package/dist/wirings/oauth2/oauth2.types.d.ts +0 -28
  227. package/dist/wirings/oauth2/oauth2.types.js +0 -3
  228. package/dist/wirings/persona/define-personas.d.ts +28 -0
  229. package/dist/wirings/persona/define-personas.js +27 -0
  230. package/dist/wirings/persona/index.d.ts +21 -0
  231. package/dist/wirings/persona/index.js +17 -0
  232. package/dist/wirings/persona/persona-email.d.ts +37 -0
  233. package/dist/wirings/persona/persona-email.js +69 -0
  234. package/dist/wirings/persona/persona-environments.d.ts +45 -0
  235. package/dist/wirings/persona/persona-environments.js +81 -0
  236. package/dist/wirings/persona/persona-mailbox.d.ts +101 -0
  237. package/dist/wirings/persona/persona-mailbox.js +53 -0
  238. package/dist/wirings/persona/persona.types.d.ts +125 -0
  239. package/dist/wirings/persona/persona.types.js +1 -0
  240. package/dist/wirings/persona/validate-personas.d.ts +53 -0
  241. package/dist/wirings/persona/validate-personas.js +94 -0
  242. package/dist/wirings/queue/index.d.ts +3 -0
  243. package/dist/wirings/queue/index.js +2 -3
  244. package/dist/wirings/queue/queue-identity.d.ts +28 -0
  245. package/dist/wirings/queue/queue-identity.js +102 -0
  246. package/dist/wirings/queue/queue-runner.d.ts +0 -19
  247. package/dist/wirings/queue/queue-runner.js +9 -30
  248. package/dist/wirings/queue/queue.types.d.ts +18 -89
  249. package/dist/wirings/queue/register-queue-helper.d.ts +0 -12
  250. package/dist/wirings/queue/register-queue-helper.js +0 -11
  251. package/dist/wirings/queue/signed-queue-service.d.ts +16 -0
  252. package/dist/wirings/queue/signed-queue-service.js +42 -0
  253. package/dist/wirings/queue/validate-worker-config.d.ts +2 -23
  254. package/dist/wirings/queue/validate-worker-config.js +0 -14
  255. package/dist/wirings/role/define-system-role.d.ts +32 -0
  256. package/dist/wirings/role/define-system-role.js +31 -0
  257. package/dist/wirings/role/index.d.ts +3 -0
  258. package/dist/wirings/role/index.js +2 -0
  259. package/dist/wirings/role/role.types.d.ts +43 -0
  260. package/dist/wirings/role/role.types.js +1 -0
  261. package/dist/wirings/role/validate-role-definitions.d.ts +21 -0
  262. package/dist/wirings/role/validate-role-definitions.js +71 -0
  263. package/dist/wirings/rpc/addon-runner.d.ts +0 -19
  264. package/dist/wirings/rpc/addon-runner.js +0 -51
  265. package/dist/wirings/rpc/remote-addon-auth.d.ts +1 -12
  266. package/dist/wirings/rpc/remote-addon-auth.js +1 -9
  267. package/dist/wirings/rpc/rpc-runner.d.ts +11 -18
  268. package/dist/wirings/rpc/rpc-runner.js +88 -105
  269. package/dist/wirings/rpc/rpc-types.d.ts +7 -6
  270. package/dist/wirings/rpc/wire-addon.d.ts +25 -0
  271. package/dist/wirings/rpc/wire-addon.js +62 -0
  272. package/dist/wirings/rpc/wire-remote-addon.d.ts +3 -28
  273. package/dist/wirings/rpc/wire-remote-addon.js +0 -8
  274. package/dist/wirings/scheduler/log-schedulers.d.ts +0 -4
  275. package/dist/wirings/scheduler/log-schedulers.js +0 -4
  276. package/dist/wirings/scheduler/scheduler-runner.d.ts +0 -1
  277. package/dist/wirings/scheduler/scheduler-runner.js +0 -1
  278. package/dist/wirings/scheduler/scheduler.types.d.ts +1 -14
  279. package/dist/wirings/scope/define-scope.d.ts +32 -0
  280. package/dist/wirings/scope/define-scope.js +31 -0
  281. package/dist/wirings/scope/index.d.ts +1 -1
  282. package/dist/wirings/scope/index.js +1 -1
  283. package/dist/wirings/scope/scope.types.d.ts +7 -9
  284. package/dist/wirings/scope/validate-scope-definitions.d.ts +2 -21
  285. package/dist/wirings/scope/validate-scope-definitions.js +3 -21
  286. package/dist/wirings/secret/index.d.ts +1 -1
  287. package/dist/wirings/secret/index.js +1 -1
  288. package/dist/wirings/secret/secret.types.d.ts +19 -15
  289. package/dist/wirings/secret/secret.types.js +1 -1
  290. package/dist/wirings/secret/validate-secret-definitions.d.ts +2 -4
  291. package/dist/wirings/trigger/trigger-runner.d.ts +0 -27
  292. package/dist/wirings/trigger/trigger-runner.js +1 -24
  293. package/dist/wirings/trigger/trigger.types.d.ts +1 -82
  294. package/dist/wirings/trigger/trigger.types.js +0 -34
  295. package/dist/wirings/variable/index.d.ts +1 -1
  296. package/dist/wirings/variable/index.js +1 -1
  297. package/dist/wirings/variable/validate-variable-definitions.d.ts +2 -4
  298. package/dist/wirings/variable/variable.types.d.ts +1 -13
  299. package/dist/wirings/variable/variable.types.js +1 -1
  300. package/dist/wirings/virtual-user/index.d.ts +27 -0
  301. package/dist/wirings/virtual-user/index.js +8 -0
  302. package/dist/wirings/virtual-user/run-virtual-user.d.ts +92 -0
  303. package/dist/wirings/virtual-user/run-virtual-user.js +478 -0
  304. package/dist/wirings/virtual-user/virtual-user-agents.d.ts +38 -0
  305. package/dist/wirings/virtual-user/virtual-user-agents.js +24 -0
  306. package/dist/wirings/virtual-user/virtual-user-catalogue.d.ts +92 -0
  307. package/dist/wirings/virtual-user/virtual-user-catalogue.js +134 -0
  308. package/dist/wirings/virtual-user/virtual-user-derive.d.ts +26 -0
  309. package/dist/wirings/virtual-user/virtual-user-derive.js +137 -0
  310. package/dist/wirings/virtual-user/virtual-user-dispositions.d.ts +79 -0
  311. package/dist/wirings/virtual-user/virtual-user-dispositions.js +128 -0
  312. package/dist/wirings/virtual-user/virtual-user-intents.d.ts +78 -0
  313. package/dist/wirings/virtual-user/virtual-user-intents.js +142 -0
  314. package/dist/wirings/virtual-user/virtual-user-rng.d.ts +24 -0
  315. package/dist/wirings/virtual-user/virtual-user-rng.js +44 -0
  316. package/dist/wirings/virtual-user/virtual-user-target.d.ts +21 -0
  317. package/dist/wirings/virtual-user/virtual-user-target.js +34 -0
  318. package/dist/wirings/virtual-user/virtual-user.types.d.ts +199 -0
  319. package/dist/wirings/virtual-user/virtual-user.types.js +8 -0
  320. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +5 -5
  321. package/dist/wirings/workflow/dsl/workflow-runner.d.ts +0 -4
  322. package/dist/wirings/workflow/dsl/workflow-runner.js +0 -4
  323. package/dist/wirings/workflow/feature.d.ts +0 -19
  324. package/dist/wirings/workflow/feature.js +0 -19
  325. package/dist/wirings/workflow/graph/graph-node.d.ts +0 -98
  326. package/dist/wirings/workflow/graph/graph-node.js +0 -34
  327. package/dist/wirings/workflow/graph/graph-runner.js +6 -41
  328. package/dist/wirings/workflow/graph/wire-workflow-graph.d.ts +0 -4
  329. package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +0 -58
  330. package/dist/wirings/workflow/graph/workflow-graph.types.js +0 -6
  331. package/dist/wirings/workflow/index.d.ts +5 -7
  332. package/dist/wirings/workflow/index.js +3 -17
  333. package/dist/wirings/workflow/pikku-scenario-service.d.ts +87 -5
  334. package/dist/wirings/workflow/pikku-scenario-service.js +204 -42
  335. package/dist/wirings/workflow/pikku-workflow-service.d.ts +7 -459
  336. package/dist/wirings/workflow/pikku-workflow-service.js +58 -551
  337. package/dist/wirings/workflow/run-timeline.d.ts +0 -47
  338. package/dist/wirings/workflow/run-timeline.js +0 -22
  339. package/dist/wirings/workflow/scenario-cookie-jar.d.ts +0 -23
  340. package/dist/wirings/workflow/scenario-cookie-jar.js +0 -16
  341. package/dist/wirings/workflow/scenario-poll.d.ts +0 -15
  342. package/dist/wirings/workflow/scenario-poll.js +0 -12
  343. package/dist/wirings/workflow/scenario-prose.d.ts +0 -28
  344. package/dist/wirings/workflow/scenario-prose.js +0 -18
  345. package/dist/wirings/workflow/scenario-step-guards.d.ts +0 -13
  346. package/dist/wirings/workflow/scenario-step-guards.js +1 -14
  347. package/dist/wirings/workflow/scenario-step.types.d.ts +72 -6
  348. package/dist/wirings/workflow/scenario-step.types.js +5 -1
  349. package/dist/wirings/workflow/scenario-surface.d.ts +16 -0
  350. package/dist/wirings/workflow/scenario-surface.js +56 -0
  351. package/dist/wirings/workflow/workflow-invocation-id.d.ts +0 -18
  352. package/dist/wirings/workflow/workflow-invocation-id.js +2 -22
  353. package/dist/wirings/workflow/workflow-queue-workers.d.ts +0 -20
  354. package/dist/wirings/workflow/workflow-queue-workers.js +0 -19
  355. package/dist/wirings/workflow/workflow.types.d.ts +0 -197
  356. package/knowledge/decisions/index.md +19 -0
  357. package/knowledge/decisions/internals/a-secret-that-fails-to-decrypt-fails-the-whole-read.md +49 -0
  358. package/knowledge/decisions/internals/actor-flow-conversations-seed-a-hidden-kickoff-message.md +23 -0
  359. package/knowledge/decisions/internals/actor-flow-drives-the-target-through-a-transport-seam.md +24 -0
  360. package/knowledge/decisions/internals/actor-flow-verdicts-are-llm-self-evaluations.md +25 -0
  361. package/knowledge/decisions/internals/addon-package-roots-resolve-by-walking-node-module-search-paths.md +26 -0
  362. package/knowledge/decisions/internals/addon-singleton-services-are-cached-per-namespace-not-per-package.md +33 -0
  363. package/knowledge/decisions/internals/addon-workflow-names-are-prefixed-with-the-consumer-namespace.md +28 -0
  364. package/knowledge/decisions/internals/ai-agent-agui-bridge-obeys-the-client-ordering-contract.md +29 -0
  365. package/knowledge/decisions/internals/ai-agent-audio-chunks-carry-the-format-the-provider-returned.md +20 -0
  366. package/knowledge/decisions/internals/ai-agent-credential-suspensions-hide-the-tool-result.md +26 -0
  367. package/knowledge/decisions/internals/ai-agent-delegate-and-supervise-hide-different-text.md +26 -0
  368. package/knowledge/decisions/internals/ai-agent-llm-tool-arguments-have-nulls-stripped.md +23 -0
  369. package/knowledge/decisions/internals/ai-agent-model-config-stays-a-single-resolution-seam.md +25 -0
  370. package/knowledge/decisions/internals/ai-agent-onerror-hooks-cannot-change-the-failure.md +22 -0
  371. package/knowledge/decisions/internals/ai-agent-runner-methods-must-keep-their-receiver.md +22 -0
  372. package/knowledge/decisions/internals/ai-agent-stream-persistence-is-best-effort.md +27 -0
  373. package/knowledge/decisions/internals/ai-agent-sub-agents-inherit-the-parent-context-block.md +26 -0
  374. package/knowledge/decisions/internals/ai-agent-tool-execute-failures-are-logged-unconditionally.md +25 -0
  375. package/knowledge/decisions/internals/ai-agent-voice-input-transcribes-audio-parts-in-place.md +22 -0
  376. package/knowledge/decisions/internals/ai-agent-working-memory-is-persisted-only-when-valid.md +25 -0
  377. package/knowledge/decisions/internals/channel-message-handlers-accept-three-config-shapes.md +30 -0
  378. package/knowledge/decisions/internals/channel-middleware-caches-only-statically-resolved-middleware.md +31 -0
  379. package/knowledge/decisions/internals/channel-state-is-per-socket-session-state-is-per-user.md +29 -0
  380. package/knowledge/decisions/internals/channel-user-id-is-persisted-after-onconnect-middleware-runs.md +28 -0
  381. package/knowledge/decisions/internals/cli-option-names-are-camelcase-in-state-and-kebab-on-the-command-line.md +27 -0
  382. package/knowledge/decisions/internals/cli-parse-errors-are-routed-by-message-prefix.md +28 -0
  383. package/knowledge/decisions/internals/cli-stdout-is-reserved-for-machine-readable-output.md +34 -0
  384. package/knowledge/decisions/internals/cli-unknown-long-options-warn-instead-of-failing.md +29 -0
  385. package/knowledge/decisions/internals/core-data-classification-brand-is-an-optional-property.md +34 -0
  386. package/knowledge/decisions/internals/core-function-runner-restores-the-wire-fields-it-overwrites.md +44 -0
  387. package/knowledge/decisions/internals/core-hot-reload-merges-generated-meta-never-replaces-it.md +39 -0
  388. package/knowledge/decisions/internals/core-hot-reload-owns-its-module-registry.md +42 -0
  389. package/knowledge/decisions/internals/core-middleware-order-is-scope-then-priority.md +39 -0
  390. package/knowledge/decisions/internals/core-schema-defaults-apply-on-every-transport.md +43 -0
  391. package/knowledge/decisions/internals/core-scopes-are-an-and-gate-separate-from-permissions.md +38 -0
  392. package/knowledge/decisions/internals/core-state-is-a-global-map-written-only-at-registration-time.md +44 -0
  393. package/knowledge/decisions/internals/email-meta-is-read-uncached-because-codegen-rewrites-it-mid-session.md +27 -0
  394. package/knowledge/decisions/internals/gateway-adapters-resolve-lazily-and-are-promise-cached.md +32 -0
  395. package/knowledge/decisions/internals/gateway-webhook-challenges-echo-bytes-not-json.md +28 -0
  396. package/knowledge/decisions/internals/gateway-wiring-is-a-meta-wiring-over-http-and-channels.md +31 -0
  397. package/knowledge/decisions/internals/generated-src-paths-in-pikku-meta-are-absolute.md +26 -0
  398. package/knowledge/decisions/internals/http-request-bodies-are-read-once-and-shared.md +32 -0
  399. package/knowledge/decisions/internals/http-route-groups-cascade-config-in-a-fixed-order.md +28 -0
  400. package/knowledge/decisions/internals/http-router-matches-normalized-paths-but-returns-registered-ones.md +30 -0
  401. package/knowledge/decisions/internals/http-runner-logs-through-a-trace-scoped-logger-functions-do-not.md +26 -0
  402. package/knowledge/decisions/internals/http-set-cookie-headers-are-appended-never-joined.md +28 -0
  403. package/knowledge/decisions/internals/http-sse-streams-flush-headers-only-after-middleware.md +32 -0
  404. package/knowledge/decisions/internals/http-wiring-without-metadata-is-skipped-not-fatal.md +26 -0
  405. package/knowledge/decisions/internals/in-a-scenario-a-4xx-is-data-not-an-exception.md +25 -0
  406. package/knowledge/decisions/internals/in-memory-workflow-history-aliases-the-live-step-object.md +26 -0
  407. package/knowledge/decisions/internals/index.md +113 -0
  408. package/knowledge/decisions/internals/istanbul-statement-counts-attach-to-the-start-line-only.md +25 -0
  409. package/knowledge/decisions/internals/local-trigger-and-gateway-services-assume-a-single-process.md +26 -0
  410. package/knowledge/decisions/internals/node-only-builtins-are-imported-dynamically.md +24 -0
  411. package/knowledge/decisions/internals/queue-group-concurrency-keeps-one-shared-queue-fair.md +28 -0
  412. package/knowledge/decisions/internals/queue-jobs-always-carry-an-explicit-attempts-count.md +27 -0
  413. package/knowledge/decisions/internals/remote-addons-dispatch-over-http-instead-of-local-meta.md +31 -0
  414. package/knowledge/decisions/internals/rpc-names-resolve-through-package-scope-before-root.md +32 -0
  415. package/knowledge/decisions/internals/scenario-agent-calls-sign-in-on-401-only.md +27 -0
  416. package/knowledge/decisions/internals/scenario-meta-lives-apart-from-app-meta-but-merges-when-read-off-disk.md +26 -0
  417. package/knowledge/decisions/internals/scenario-steps-return-drained-response-records.md +27 -0
  418. package/knowledge/decisions/internals/scope-roots-may-be-co-declared-by-an-addon-and-its-host-app.md +30 -0
  419. package/knowledge/decisions/internals/serverless-channel-disconnect-must-tolerate-a-missing-channel.md +28 -0
  420. package/knowledge/decisions/internals/the-dev-queue-copies-prod-timing-and-serialization-semantics.md +30 -0
  421. package/knowledge/decisions/internals/the-embedding-model-is-pinned-per-service-and-doc-query-embedding-is-split.md +29 -0
  422. package/knowledge/decisions/internals/the-in-memory-workflow-service-is-inline-only-and-single-process.md +27 -0
  423. package/knowledge/decisions/internals/the-kek-salt-is-scoped-to-the-key-version.md +40 -0
  424. package/knowledge/decisions/internals/the-schema-service-is-never-stubbed.md +26 -0
  425. package/knowledge/decisions/internals/trigger-declaration-is-split-from-trigger-source.md +33 -0
  426. package/knowledge/decisions/internals/typed-secret-service-caches-for-the-process-lifetime.md +26 -0
  427. package/knowledge/decisions/internals/webhook-delivery-history-records-every-attempt-best-effort.md +26 -0
  428. package/knowledge/decisions/internals/webhook-service-collaborators-are-constructor-args-not-locator-lookups.md +25 -0
  429. package/knowledge/decisions/internals/whether-a-run-is-inline-is-read-from-the-run-record.md +58 -0
  430. package/knowledge/decisions/internals/workflow-approval-expiry-is-decided-from-a-recorded-deadline.md +34 -0
  431. package/knowledge/decisions/internals/workflow-core-never-imports-a-browser-driver.md +42 -0
  432. package/knowledge/decisions/internals/workflow-dsl-meta-separates-runtime-expressions-from-literals.md +38 -0
  433. package/knowledge/decisions/internals/workflow-features-resolve-scenarios-by-object-identity.md +29 -0
  434. package/knowledge/decisions/internals/workflow-graph-inline-and-queued-runs-share-one-planner.md +42 -0
  435. package/knowledge/decisions/internals/workflow-graph-node-notes-are-excluded-from-the-graph-hash.md +25 -0
  436. package/knowledge/decisions/internals/workflow-inline-runs-report-their-run-id-before-they-can-fail.md +29 -0
  437. package/knowledge/decisions/internals/workflow-invocation-id-is-the-dedupe-key-not-step-id.md +43 -0
  438. package/knowledge/decisions/internals/workflow-queued-step-dispatch-requires-an-explicit-opt-in.md +29 -0
  439. package/knowledge/decisions/internals/workflow-queues-are-per-workflow-by-default.md +42 -0
  440. package/knowledge/decisions/internals/workflow-repeated-step-names-get-an-ordinal-suffix.md +33 -0
  441. package/knowledge/decisions/internals/workflow-replay-reads-its-steps-once-and-caches-only-the-immutable-half.md +32 -0
  442. package/knowledge/decisions/internals/workflow-retries-are-owned-by-the-workflow-not-the-queue.md +31 -0
  443. package/knowledge/decisions/internals/workflow-run-capabilities-are-extensions-not-subclasses.md +39 -0
  444. package/knowledge/decisions/internals/workflow-run-mirror-is-never-a-source-of-truth.md +29 -0
  445. package/knowledge/decisions/internals/workflow-run-polling-backs-off-to-the-callers-ceiling.md +33 -0
  446. package/knowledge/decisions/internals/workflow-run-timeline-is-a-pure-fold-over-durable-history.md +37 -0
  447. package/knowledge/decisions/internals/workflow-scenario-assertions-never-retry-and-record-one-step.md +50 -0
  448. package/knowledge/decisions/internals/workflow-scenario-hooks-are-a-scenario-only-affordance.md +43 -0
  449. package/knowledge/decisions/internals/workflow-scenario-prose-is-rendered-from-typed-calls-not-parsed-from-english.md +32 -0
  450. package/knowledge/decisions/internals/workflow-scenario-quarantine-reason-lives-in-code.md +18 -0
  451. package/knowledge/decisions/internals/workflow-scenario-step-targets-are-string-literals-for-the-inspector.md +34 -0
  452. package/knowledge/decisions/internals/workflow-step-compensation-runs-as-its-own-durable-step.md +26 -0
  453. package/knowledge/decisions/internals/workflow-step-dispatch-failure-is-transient-not-a-run-failure.md +33 -0
  454. package/knowledge/decisions/internals/workflow-step-lock-is-held-only-to-claim-the-step.md +27 -0
  455. package/knowledge/decisions/internals/workflow-step-rpc-name-is-provenance-only.md +34 -0
  456. package/knowledge/decisions/internals/workflow-suspend-and-approval-reasons-are-durable-step-identities.md +38 -0
  457. package/knowledge/decisions/internals/workflow-suspended-runs-keep-their-in-process-context.md +30 -0
  458. package/knowledge/decisions/security/a-dropped-audit-write-is-always-logged.md +26 -0
  459. package/knowledge/decisions/security/actor-flow-missing-approval-decisions-default-to-denied.md +22 -0
  460. package/knowledge/decisions/security/actor-sign-in-is-proven-by-set-cookie-not-a-non-empty-jar.md +27 -0
  461. package/knowledge/decisions/security/actor-sign-in-only-works-for-actor-flagged-users.md +27 -0
  462. package/knowledge/decisions/security/addon-auth-and-tags-only-tighten.md +43 -0
  463. package/knowledge/decisions/security/addon-config-gates-apply-only-at-the-namespaced-rpc-boundary.md +52 -0
  464. package/knowledge/decisions/security/addon-scopes-are-resolved-where-the-function-runs.md +46 -0
  465. package/knowledge/decisions/security/ai-agent-approval-forwarding-requires-a-symbol-brand.md +27 -0
  466. package/knowledge/decisions/security/ai-agent-credential-requests-are-symbol-branded.md +37 -0
  467. package/knowledge/decisions/security/ai-agent-gate-requires-a-session-only-when-auth-is-true.md +31 -0
  468. package/knowledge/decisions/security/ai-agent-ownership-failures-never-echo-the-resource.md +23 -0
  469. package/knowledge/decisions/security/ai-agent-resume-re-runs-the-authorization-gate.md +22 -0
  470. package/knowledge/decisions/security/ai-agent-sessionless-deployments-have-no-thread-ownership.md +39 -0
  471. package/knowledge/decisions/security/ai-agent-thread-ownership-composes-the-session-principal.md +30 -0
  472. package/knowledge/decisions/security/ai-agent-tool-filtering-reads-the-live-function-config.md +24 -0
  473. package/knowledge/decisions/security/an-empty-owners-constraint-matches-nothing.md +30 -0
  474. package/knowledge/decisions/security/an-exposed-ungated-function-is-a-codegen-warning.md +49 -0
  475. package/knowledge/decisions/security/console-addon-privileged-functions-gate-themselves.md +76 -0
  476. package/knowledge/decisions/security/core-safe-fetch-blocks-ssrf-by-host-literal-not-dns.md +39 -0
  477. package/knowledge/decisions/security/core-secrets-use-a-per-secret-dek-wrapped-by-a-kek.md +37 -0
  478. package/knowledge/decisions/security/gateway-handlers-run-through-the-function-runner-gate.md +31 -0
  479. package/knowledge/decisions/security/gateway-middleware-sessions-must-be-bridged-onto-the-wire.md +30 -0
  480. package/knowledge/decisions/security/global-permissions-and-function-permissions-are-independent-gates.md +40 -0
  481. package/knowledge/decisions/security/http-error-detail-is-withheld-from-clients-in-production.md +33 -0
  482. package/knowledge/decisions/security/http-request-bodies-are-bounded-before-they-are-buffered.md +46 -0
  483. package/knowledge/decisions/security/index.md +55 -0
  484. package/knowledge/decisions/security/mcp-internal-error-details-are-double-gated-on-production.md +27 -0
  485. package/knowledge/decisions/security/passphrases-are-stretched-key-material-is-expanded.md +40 -0
  486. package/knowledge/decisions/security/permission-auth-filtering-requires-live-permission-functions.md +31 -0
  487. package/knowledge/decisions/security/pikku-carries-actor-scopes-as-data-and-the-app-grants-them.md +26 -0
  488. package/knowledge/decisions/security/queue-job-identities-are-signed-at-enqueue.md +69 -0
  489. package/knowledge/decisions/security/queue-jobs-carry-the-producers-pikku-user-id.md +39 -0
  490. package/knowledge/decisions/security/remote-addon-tokens-are-client-credentials-not-mesh-trust.md +34 -0
  491. package/knowledge/decisions/security/scaffold-features-are-authenticated-unless-opted-out.md +49 -0
  492. package/knowledge/decisions/security/scenario-step-functions-are-never-externally-invocable.md +30 -0
  493. package/knowledge/decisions/security/scope-resolution-happens-at-the-session-boundary-and-sync-never-deletes.md +28 -0
  494. package/knowledge/decisions/security/self-authentication-is-declared-not-detected.md +34 -0
  495. package/knowledge/decisions/security/signed-content-urls-bind-the-request-path.md +37 -0
  496. package/knowledge/decisions/security/webhook-bodies-are-signed-before-they-are-enqueued.md +25 -0
  497. package/knowledge/decisions/security/workflow-actor-steps-always-use-the-real-transport.md +34 -0
  498. package/knowledge/decisions/security/workflow-approval-payloads-are-validated-on-replay-inside-the-workflow.md +40 -0
  499. package/knowledge/decisions/security/workflow-queued-steps-rehydrate-their-session-from-the-run-wire.md +32 -0
  500. package/knowledge/decisions/security/workflow-scenario-sessions-are-isolated-per-actor-and-per-scenario.md +32 -0
  501. package/knowledge/decisions/security/workflow-scenario-steps-are-never-network-invocable.md +31 -0
  502. package/knowledge/index.md +24 -0
  503. package/knowledge/questions/index.md +15 -0
  504. package/package.json +4 -1
  505. package/run-tests.sh +0 -0
  506. package/src/crypto-utils.test.ts +460 -19
  507. package/src/crypto-utils.ts +283 -55
  508. package/src/data-classification.ts +1 -7
  509. package/src/dev/hot-reload.test.ts +0 -4
  510. package/src/dev/hot-reload.ts +11 -30
  511. package/src/dev/module-runner.ts +7 -32
  512. package/src/dev/reload-meta.ts +9 -29
  513. package/src/errors/error-handler.ts +20 -35
  514. package/src/errors/error.test.ts +30 -1
  515. package/src/errors/errors.ts +73 -157
  516. package/src/function/abort-scope.test.ts +97 -0
  517. package/src/function/abort-scope.ts +80 -0
  518. package/src/function/function-runner.test.ts +0 -7
  519. package/src/function/function-runner.ts +62 -32
  520. package/src/function/functions.types.ts +56 -136
  521. package/src/function/list.types.test.ts +3 -25
  522. package/src/function/list.types.ts +12 -62
  523. package/src/handle-error.ts +0 -18
  524. package/src/index.ts +60 -1
  525. package/src/middleware/auth-apikey.test.ts +0 -1
  526. package/src/middleware/auth-apikey.ts +0 -17
  527. package/src/middleware/auth-bearer.test.ts +0 -3
  528. package/src/middleware/auth-bearer.ts +3 -40
  529. package/src/middleware/auth-cookie.test.ts +0 -6
  530. package/src/middleware/auth-cookie.ts +2 -26
  531. package/src/middleware/cors.test.ts +34 -0
  532. package/src/middleware/cors.ts +12 -33
  533. package/src/middleware/remote-auth.test.ts +24 -9
  534. package/src/middleware/remote-auth.ts +10 -2
  535. package/src/middleware/telemetry.ts +2 -31
  536. package/src/middleware-runner.test.ts +0 -2
  537. package/src/middleware-runner.ts +5 -74
  538. package/src/permissions.test.ts +30 -0
  539. package/src/permissions.ts +24 -74
  540. package/src/pikku-request.ts +0 -6
  541. package/src/pikku-state.ts +2 -30
  542. package/src/production-barrels-stay-lean.test.ts +110 -0
  543. package/src/remote.test.ts +172 -0
  544. package/src/remote.ts +17 -7
  545. package/src/schema.ts +5 -39
  546. package/src/scopes.ts +7 -48
  547. package/src/services/ai-agent-runner-service.ts +20 -0
  548. package/src/services/ai-embedding-service.ts +3 -25
  549. package/src/services/audit-service.ts +1 -2
  550. package/src/services/content-service.ts +1 -46
  551. package/src/services/credential-service.ts +3 -40
  552. package/src/services/credential-wire-service.test.ts +0 -2
  553. package/src/services/deployment-service.ts +3 -9
  554. package/src/services/gateway-service.ts +0 -15
  555. package/src/services/{http-scenario-actors-converse.test.ts → http-personas-converse.test.ts} +38 -9
  556. package/src/services/{http-scenario-actors.test.ts → http-personas.test.ts} +39 -22
  557. package/src/services/{http-scenario-actors.ts → http-personas.ts} +85 -45
  558. package/src/services/in-memory-queue-service.ts +1 -15
  559. package/src/services/in-memory-trigger-service.ts +1 -18
  560. package/src/services/in-memory-workflow-service.test.ts +0 -13
  561. package/src/services/in-memory-workflow-service.ts +4 -38
  562. package/src/services/index.ts +20 -15
  563. package/src/services/istanbul-coverage-service.ts +2 -8
  564. package/src/services/jwt-service.ts +1 -16
  565. package/src/services/local-content.test.ts +159 -27
  566. package/src/services/local-content.ts +55 -23
  567. package/src/services/local-gateway-service.ts +2 -17
  568. package/src/services/local-secrets.ts +0 -4
  569. package/src/services/logger-console.test.ts +0 -1
  570. package/src/services/logger-console.ts +3 -7
  571. package/src/services/logger.ts +2 -37
  572. package/src/services/meta-service.test.ts +1 -5
  573. package/src/services/meta-service.ts +41 -61
  574. package/src/services/{scenario-actors-service.ts → personas-service.ts} +48 -43
  575. package/src/services/pikku-user-id.ts +0 -4
  576. package/src/services/queue-webhook-service.ts +9 -41
  577. package/src/services/scheduler-service.ts +1 -50
  578. package/src/services/schema-service.ts +1 -24
  579. package/src/services/scope-service.ts +50 -34
  580. package/src/services/scoped-secret-service.ts +0 -4
  581. package/src/services/secret-host-binding.test.ts +138 -0
  582. package/src/services/secret-host-binding.ts +51 -0
  583. package/src/services/secret-service.ts +5 -33
  584. package/src/services/secretless.test.ts +54 -0
  585. package/src/services/secretless.ts +29 -0
  586. package/src/services/stub-tracker.ts +8 -18
  587. package/src/services/system-role-guard.test.ts +93 -0
  588. package/src/services/system-role-guard.ts +71 -0
  589. package/src/services/trigger-service.ts +0 -12
  590. package/src/services/typed-secret-service.ts +1 -7
  591. package/src/services/v8-coverage-service.ts +3 -6
  592. package/src/services/variables-service.ts +1 -8
  593. package/src/services/webhook-service.ts +19 -63
  594. package/src/services/workflow-service.ts +3 -20
  595. package/src/testing/service-tests.ts +0 -26
  596. package/src/time-utils.ts +1 -19
  597. package/src/types/core.types.ts +116 -229
  598. package/src/types/state.types.ts +7 -9
  599. package/src/utils/hmac.ts +4 -10
  600. package/src/utils/safe-fetch.ts +13 -54
  601. package/src/utils.test.ts +11 -2
  602. package/src/utils.ts +6 -15
  603. package/src/wirings/actor-flow/actor-flow.types.ts +1 -34
  604. package/src/wirings/actor-flow/index.ts +0 -9
  605. package/src/wirings/actor-flow/run-conversation.test.ts +11 -6
  606. package/src/wirings/actor-flow/run-conversation.ts +19 -12
  607. package/src/wirings/ai-agent/ai-agent-agui.test.ts +75 -10
  608. package/src/wirings/ai-agent/ai-agent-agui.ts +36 -17
  609. package/src/wirings/ai-agent/ai-agent-helpers.ts +20 -0
  610. package/src/wirings/ai-agent/ai-agent-interrupt.test.ts +842 -0
  611. package/src/wirings/ai-agent/ai-agent-interrupt.ts +399 -0
  612. package/src/wirings/ai-agent/ai-agent-memory.ts +0 -2
  613. package/src/wirings/ai-agent/ai-agent-model-config.ts +1 -9
  614. package/src/wirings/ai-agent/ai-agent-prepare.test.ts +202 -31
  615. package/src/wirings/ai-agent/ai-agent-prepare.ts +82 -138
  616. package/src/wirings/ai-agent/ai-agent-registry.test.ts +191 -6
  617. package/src/wirings/ai-agent/ai-agent-registry.ts +18 -1
  618. package/src/wirings/ai-agent/ai-agent-resume-authorization.test.ts +0 -2
  619. package/src/wirings/ai-agent/ai-agent-runner.test.ts +11 -9
  620. package/src/wirings/ai-agent/ai-agent-runner.ts +67 -33
  621. package/src/wirings/ai-agent/ai-agent-stream.test.ts +205 -103
  622. package/src/wirings/ai-agent/ai-agent-stream.ts +192 -75
  623. package/src/wirings/ai-agent/ai-agent-thread-ownership.test.ts +301 -0
  624. package/src/wirings/ai-agent/ai-agent.types.ts +85 -4
  625. package/src/wirings/ai-agent/index.ts +35 -3
  626. package/src/wirings/ai-agent/voice-input.test.ts +72 -7
  627. package/src/wirings/ai-agent/voice-input.ts +48 -3
  628. package/src/wirings/ai-agent/voice-output.test.ts +422 -0
  629. package/src/wirings/ai-agent/voice-output.ts +216 -56
  630. package/src/wirings/channel/channel-common.ts +15 -20
  631. package/src/wirings/channel/channel-handler.test.ts +50 -0
  632. package/src/wirings/channel/channel-handler.ts +32 -11
  633. package/src/wirings/channel/channel-host-rpc.test.ts +150 -0
  634. package/src/wirings/channel/channel-host-rpc.ts +69 -0
  635. package/src/wirings/channel/channel-middleware-runner.test.ts +0 -1
  636. package/src/wirings/channel/channel-middleware-runner.ts +0 -12
  637. package/src/wirings/channel/channel-rpc-registry.ts +116 -0
  638. package/src/wirings/channel/channel-rpc-responder.ts +117 -0
  639. package/src/wirings/channel/channel-rpc-service.ts +146 -0
  640. package/src/wirings/channel/channel-rpc-validators.ts +65 -0
  641. package/src/wirings/channel/channel-rpc.test.ts +820 -0
  642. package/src/wirings/channel/channel-rpc.ts +5 -0
  643. package/src/wirings/channel/channel-rpc.types.ts +150 -0
  644. package/src/wirings/channel/channel-runner.ts +0 -14
  645. package/src/wirings/channel/channel-store.ts +0 -10
  646. package/src/wirings/channel/channel.types.ts +19 -8
  647. package/src/wirings/channel/define-channel-routes.ts +0 -20
  648. package/src/wirings/channel/eventhub-service.ts +0 -18
  649. package/src/wirings/channel/index.ts +35 -0
  650. package/src/wirings/channel/local/local-channel-handler.ts +3 -1
  651. package/src/wirings/channel/local/local-channel-runner.test.ts +0 -10
  652. package/src/wirings/channel/local/local-channel-runner.ts +3 -1
  653. package/src/wirings/channel/local/local-eventhub-service.test.ts +0 -13
  654. package/src/wirings/channel/local/local-eventhub-service.ts +2 -37
  655. package/src/wirings/channel/log-channels.ts +0 -4
  656. package/src/wirings/channel/pikku-abstract-channel-handler.test.ts +83 -2
  657. package/src/wirings/channel/pikku-abstract-channel-handler.ts +7 -0
  658. package/src/wirings/channel/serverless/serverless-channel-runner.ts +2 -5
  659. package/src/wirings/cli/channel/cli-approval.test.ts +177 -0
  660. package/src/wirings/cli/channel/cli-approval.ts +135 -0
  661. package/src/wirings/cli/channel/cli-channel-runner.ts +4 -26
  662. package/src/wirings/cli/channel/cli-raw-channel-runner.test.ts +169 -0
  663. package/src/wirings/cli/channel/cli-raw-channel-runner.ts +59 -16
  664. package/src/wirings/cli/channel/cli-raw-client-runner.test.ts +480 -0
  665. package/src/wirings/cli/channel/cli-raw-client-runner.ts +155 -0
  666. package/src/wirings/cli/channel/index.ts +9 -0
  667. package/src/wirings/cli/cli-runner.test.ts +0 -1
  668. package/src/wirings/cli/cli-runner.ts +46 -88
  669. package/src/wirings/cli/cli.types.ts +14 -3
  670. package/src/wirings/cli/command-parser.test.ts +0 -4
  671. package/src/wirings/cli/command-parser.ts +11 -91
  672. package/src/wirings/cli/define-cli-commands.ts +1 -17
  673. package/src/wirings/credential/credential.types.ts +0 -12
  674. package/src/wirings/credential/{wire-credential.ts → define-credential.ts} +7 -7
  675. package/src/wirings/credential/index.ts +1 -1
  676. package/src/wirings/credential/validate-credential-definitions.ts +2 -4
  677. package/src/wirings/gateway/gateway-runner.test.ts +1 -21
  678. package/src/wirings/gateway/gateway-runner.ts +8 -110
  679. package/src/wirings/gateway/gateway.types.ts +7 -80
  680. package/src/wirings/http/http-routes.test.ts +0 -3
  681. package/src/wirings/http/http-routes.ts +0 -86
  682. package/src/wirings/http/http-runner.test.ts +0 -1
  683. package/src/wirings/http/http-runner.ts +8 -167
  684. package/src/wirings/http/http.types.ts +15 -62
  685. package/src/wirings/http/log-http-routes.ts +0 -4
  686. package/src/wirings/http/pikku-fetch-http-request.test.ts +2 -10
  687. package/src/wirings/http/pikku-fetch-http-request.ts +0 -58
  688. package/src/wirings/http/pikku-fetch-http-response.test.ts +1 -1
  689. package/src/wirings/http/pikku-fetch-http-response.ts +0 -3
  690. package/src/wirings/http/routers/path-to-regex.test.ts +4 -17
  691. package/src/wirings/http/routers/path-to-regex.ts +2 -13
  692. package/src/wirings/http/web-request.test.ts +33 -2
  693. package/src/wirings/http/web-request.ts +30 -17
  694. package/src/wirings/mcp/mcp-endpoint-registry.test.ts +0 -1
  695. package/src/wirings/mcp/mcp-runner.ts +2 -17
  696. package/src/wirings/mcp/mcp.types.ts +7 -42
  697. package/src/wirings/oauth2/oauth2.types.ts +0 -30
  698. package/src/wirings/persona/define-personas.ts +29 -0
  699. package/src/wirings/persona/index.ts +62 -0
  700. package/src/wirings/persona/persona-email.ts +87 -0
  701. package/src/wirings/persona/persona-environments.test.ts +183 -0
  702. package/src/wirings/persona/persona-environments.ts +138 -0
  703. package/src/wirings/persona/persona-mailbox.ts +156 -0
  704. package/src/wirings/persona/persona.test.ts +220 -0
  705. package/src/wirings/persona/persona.types.ts +131 -0
  706. package/src/wirings/persona/validate-personas.ts +133 -0
  707. package/src/wirings/queue/index.ts +13 -3
  708. package/src/wirings/queue/queue-identity.test.ts +453 -0
  709. package/src/wirings/queue/queue-identity.ts +173 -0
  710. package/src/wirings/queue/queue-runner.ts +12 -31
  711. package/src/wirings/queue/queue.types.ts +19 -89
  712. package/src/wirings/queue/register-queue-helper.ts +0 -14
  713. package/src/wirings/queue/signed-queue-service.ts +59 -0
  714. package/src/wirings/queue/validate-worker-config.ts +2 -28
  715. package/src/wirings/role/define-system-role.ts +33 -0
  716. package/src/wirings/role/index.ts +13 -0
  717. package/src/wirings/role/role.test.ts +104 -0
  718. package/src/wirings/role/role.types.ts +47 -0
  719. package/src/wirings/role/validate-role-definitions.ts +93 -0
  720. package/src/wirings/rpc/addon-auth-tags.test.ts +223 -0
  721. package/src/wirings/rpc/addon-runner.ts +0 -56
  722. package/src/wirings/rpc/addon-scopes.test.ts +225 -0
  723. package/src/wirings/rpc/remote-addon-auth.ts +1 -13
  724. package/src/wirings/rpc/rpc-runner.test.ts +186 -2
  725. package/src/wirings/rpc/rpc-runner.ts +145 -127
  726. package/src/wirings/rpc/rpc-types.ts +11 -6
  727. package/src/wirings/rpc/wire-addon.test.ts +43 -1
  728. package/src/wirings/rpc/wire-addon.ts +99 -0
  729. package/src/wirings/rpc/wire-remote-addon.ts +9 -29
  730. package/src/wirings/scheduler/log-schedulers.ts +0 -4
  731. package/src/wirings/scheduler/scheduler-runner.test.ts +1 -8
  732. package/src/wirings/scheduler/scheduler-runner.ts +0 -2
  733. package/src/wirings/scheduler/scheduler.types.ts +1 -14
  734. package/src/wirings/scope/{wire-scope.ts → define-scope.ts} +5 -6
  735. package/src/wirings/scope/index.ts +1 -1
  736. package/src/wirings/scope/scope.test.ts +1 -2
  737. package/src/wirings/scope/scope.types.ts +7 -9
  738. package/src/wirings/scope/validate-scope-definitions.ts +3 -21
  739. package/src/wirings/secret/index.ts +1 -1
  740. package/src/wirings/secret/secret.types.ts +19 -15
  741. package/src/wirings/secret/validate-secret-definitions.ts +2 -4
  742. package/src/wirings/trigger/trigger-runner.ts +1 -27
  743. package/src/wirings/trigger/trigger.types.ts +1 -82
  744. package/src/wirings/variable/index.ts +1 -1
  745. package/src/wirings/variable/validate-variable-definitions.ts +2 -4
  746. package/src/wirings/variable/variable.types.ts +1 -13
  747. package/src/wirings/virtual-user/index.ts +76 -0
  748. package/src/wirings/virtual-user/run-virtual-user.test.ts +765 -0
  749. package/src/wirings/virtual-user/run-virtual-user.ts +671 -0
  750. package/src/wirings/virtual-user/virtual-user-agents.test.ts +65 -0
  751. package/src/wirings/virtual-user/virtual-user-agents.ts +57 -0
  752. package/src/wirings/virtual-user/virtual-user-catalogue.test.ts +215 -0
  753. package/src/wirings/virtual-user/virtual-user-catalogue.ts +184 -0
  754. package/src/wirings/virtual-user/virtual-user-derive.test.ts +398 -0
  755. package/src/wirings/virtual-user/virtual-user-derive.ts +173 -0
  756. package/src/wirings/virtual-user/virtual-user-dispositions.test.ts +63 -0
  757. package/src/wirings/virtual-user/virtual-user-dispositions.ts +213 -0
  758. package/src/wirings/virtual-user/virtual-user-intents.test.ts +208 -0
  759. package/src/wirings/virtual-user/virtual-user-intents.ts +185 -0
  760. package/src/wirings/virtual-user/virtual-user-rng.test.ts +72 -0
  761. package/src/wirings/virtual-user/virtual-user-rng.ts +50 -0
  762. package/src/wirings/virtual-user/virtual-user-target.ts +47 -0
  763. package/src/wirings/virtual-user/virtual-user.types.ts +219 -0
  764. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +5 -4
  765. package/src/wirings/workflow/dsl/workflow-runner.ts +0 -4
  766. package/src/wirings/workflow/feature.ts +0 -19
  767. package/src/wirings/workflow/graph/graph-node.ts +0 -136
  768. package/src/wirings/workflow/graph/graph-runner.test.ts +20 -19
  769. package/src/wirings/workflow/graph/graph-runner.ts +6 -41
  770. package/src/wirings/workflow/graph/wire-workflow-graph.ts +0 -4
  771. package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -58
  772. package/src/wirings/workflow/index.ts +10 -44
  773. package/src/wirings/workflow/pikku-scenario-service.ts +235 -52
  774. package/src/wirings/workflow/pikku-workflow-service.test.ts +0 -39
  775. package/src/wirings/workflow/pikku-workflow-service.ts +77 -674
  776. package/src/wirings/workflow/run-timeline.test.ts +7 -19
  777. package/src/wirings/workflow/run-timeline.ts +0 -56
  778. package/src/wirings/workflow/scenario-cookie-jar.test.ts +0 -1
  779. package/src/wirings/workflow/scenario-cookie-jar.ts +0 -25
  780. package/src/wirings/workflow/scenario-expectations.test.ts +2 -7
  781. package/src/wirings/workflow/scenario-hooks.test.ts +2 -7
  782. package/src/wirings/workflow/scenario-poll.test.ts +0 -2
  783. package/src/wirings/workflow/scenario-poll.ts +0 -15
  784. package/src/wirings/workflow/scenario-prose.ts +0 -28
  785. package/src/wirings/workflow/scenario-service.test.ts +2 -9
  786. package/src/wirings/workflow/scenario-step-guards.ts +1 -14
  787. package/src/wirings/workflow/scenario-step.test.ts +159 -14
  788. package/src/wirings/workflow/scenario-step.types.ts +82 -6
  789. package/src/wirings/workflow/scenario-surface.test.ts +145 -0
  790. package/src/wirings/workflow/scenario-surface.ts +71 -0
  791. package/src/wirings/workflow/workflow-dispatch-durability.test.ts +14 -15
  792. package/src/wirings/workflow/workflow-dispatch-payload.test.ts +0 -4
  793. package/src/wirings/workflow/workflow-inline-authority.test.ts +169 -0
  794. package/src/wirings/workflow/workflow-invocation-id.test.ts +0 -2
  795. package/src/wirings/workflow/workflow-invocation-id.ts +2 -22
  796. package/src/wirings/workflow/workflow-mirror.test.ts +0 -7
  797. package/src/wirings/workflow/workflow-on-error.test.ts +0 -9
  798. package/src/wirings/workflow/workflow-queue-workers.ts +0 -21
  799. package/src/wirings/workflow/workflow-replay-snapshot.test.ts +8 -7
  800. package/src/wirings/workflow/workflow-retry-policy.test.ts +0 -5
  801. package/src/wirings/workflow/workflow-run-context.test.ts +5 -10
  802. package/src/wirings/workflow/workflow-run-polling.test.ts +0 -5
  803. package/src/wirings/workflow/workflow-step-ordinal.test.ts +19 -4
  804. package/src/wirings/workflow/workflow-step-session.test.ts +0 -7
  805. package/src/wirings/workflow/workflow.types.ts +0 -203
  806. package/tsconfig.tsbuildinfo +1 -1
  807. package/src/middleware/timeout.ts +0 -22
  808. package/src/pikku-response.ts +0 -5
  809. package/src/wirings/mcp/mcp-endpoint-registry.test.d.ts +0 -1
  810. package/src/wirings/workflow/dsl/index.ts +0 -36
  811. package/src/wirings/workflow/graph/index.ts +0 -15
@@ -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.
@@ -0,0 +1,28 @@
1
+ ---
2
+ type: decision
3
+ title: HTTP route groups cascade config in a fixed, per-field order
4
+ description: basePath concatenates, tags and middleware merge outward-in, auth is overridden by the innermost group
5
+ tags: http
6
+ ---
7
+
8
+ # HTTP route groups cascade config in a fixed, per-field order
9
+
10
+ `wireHTTPRoutes` in `packages/core/src/wirings/http/http-routes.ts` walks a
11
+ nested route map and merges group config at each level through
12
+ `mergeGroupConfig`. Each field cascades differently, and the differences are the
13
+ contract callers write against:
14
+
15
+ - `basePath` concatenates, outer prefix first, so nesting composes URLs.
16
+ - `tags` merge, parent then child; nothing is replaced.
17
+ - `middleware` merges with the parent's entries first, so outer middleware always
18
+ runs before inner middleware.
19
+ - `auth` is a single value and the innermost declaration wins, which is what lets
20
+ one public route sit inside an authenticated group.
21
+
22
+ `registerRoute` then applies the same rules once more between the group config
23
+ and the individual route before calling `wireHTTP`.
24
+
25
+ **What this rules out:** collapsing `mergeGroupConfig` into an object spread or a
26
+ generic deep-merge. A spread would make the child replace the parent's `tags` and
27
+ `middleware` instead of extending them, and a deep-merge would concatenate `auth`
28
+ or reorder middleware — silently changing which middleware sees a request first.
@@ -0,0 +1,30 @@
1
+ ---
2
+ type: decision
3
+ title: The HTTP router matches normalized paths but returns the registered path
4
+ description: Matching normalizes the leading slash while the match result carries the original key, because pikkuState is keyed by the registered string
5
+ tags: http
6
+ ---
7
+
8
+ # The HTTP router matches normalized paths but returns the registered path
9
+
10
+ `PathToRegexRouter` in `packages/core/src/wirings/http/routers/path-to-regex.ts`
11
+ normalizes every route and every incoming path to a leading `/` before matching,
12
+ so a route registered as `'todos'` still answers a request for `/todos`. The
13
+ `route` field it stores alongside each matcher and static entry is the
14
+ *un-normalized* original, and that is what `MatchResult.route` returns.
15
+
16
+ That asymmetry is load-bearing. `getMatchingRoute` in `http-runner.ts` takes the
17
+ returned route and uses it as a key into `pikkuState(null, 'http', 'routes')` and
18
+ into the HTTP meta record — both of which are keyed by exactly the string the
19
+ author passed to `wireHTTP`. Returning the normalized path instead would miss
20
+ those lookups for any route registered without a leading slash.
21
+
22
+ The same router also compiles channel routes, registered under the `get` method,
23
+ because a WebSocket connection arrives as an HTTP GET upgrade;
24
+ `getMatchingChannelConfig` in `channel-runner.ts` matches through
25
+ `httpRouter.match('get', path)`. Channels and HTTP GET routes therefore share one
26
+ path namespace and can collide with each other.
27
+
28
+ **What this rules out:** simplifying the compile step to store
29
+ `normalizedRoutePath` in both places, and treating the channel routes compiled
30
+ into the GET table as stray entries to be removed from the HTTP router.
@@ -0,0 +1,26 @@
1
+ ---
2
+ type: decision
3
+ title: The HTTP runner logs through a trace-scoped logger, functions do not
4
+ description: Only runner-internal logging is scoped to the request id; functions keep the singleton logger for compatibility
5
+ tags: http
6
+ ---
7
+
8
+ # The HTTP runner logs through a trace-scoped logger, functions do not
9
+
10
+ `fetchData` in `packages/core/src/wirings/http/http-runner.ts` derives
11
+ `scopedLogger` from `singletonServices.logger.scope?.(requestId)` and uses it for
12
+ route-matching and error-handling output only. Functions and middleware continue
13
+ to receive `singletonServices.logger` unscoped, via the services object.
14
+
15
+ The split is deliberate, not an oversight. `scope` is optional on the `Logger`
16
+ interface, so a runtime supplying a plain logger still works — the runner falls
17
+ back to the singleton. Threading the scoped logger into the services object
18
+ instead would change the logger identity that every existing function and
19
+ middleware sees, which breaks implementations that compare or wrap
20
+ `services.logger`, and would make user code depend on an optional method.
21
+
22
+ **What this rules out:** "unifying" the two by overwriting `services.logger` with
23
+ `scopedLogger` before the handler runs, and equally the reverse cleanup of
24
+ dropping `scopedLogger` and logging runner internals through the singleton —
25
+ that loses the request-id correlation on 404s and unhandled errors, which is the
26
+ only place the trace id is attached automatically.
@@ -0,0 +1,28 @@
1
+ ---
2
+ type: decision
3
+ title: Set-Cookie headers are appended individually, never joined
4
+ description: Every cookie gets its own header line, because Set-Cookie is the one header comma-joining corrupts
5
+ tags: http
6
+ ---
7
+
8
+ # Set-Cookie headers are appended individually, never joined
9
+
10
+ `PikkuFetchHTTPResponse.toResponse` in
11
+ `packages/core/src/wirings/http/pikku-fetch-http-response.ts` serializes each
12
+ cookie separately and calls `headers.append('Set-Cookie', cookie)` per value
13
+ rather than setting one joined string. `collectSetCookieHeaders` in
14
+ `web-request.ts` mirrors this when copying a web `Response` back onto a
15
+ `PikkuHTTPResponse`: it prefers `Headers.getSetCookie()` where the runtime
16
+ provides it, falls back to scanning for the header by name, de-duplicates, and
17
+ passes the values through as an array.
18
+
19
+ RFC 6265 makes `Set-Cookie` the exception to the "fold repeated headers with
20
+ commas" rule — cookie attributes such as `Expires` contain commas themselves, so
21
+ a joined header is parsed as a single malformed cookie and every cookie after the
22
+ first is lost. `Headers.set()` with a joined value, or a generic header-copy loop
23
+ that treats `set-cookie` like any other header, produces exactly that.
24
+
25
+ **What this rules out:** replacing the append loop with a single
26
+ `set('Set-Cookie', cookies.join(', '))`, and dropping the special-cased
27
+ `set-cookie` branch in `applyWebResponse` in favour of the generic
28
+ `headers.forEach` copy.
@@ -0,0 +1,32 @@
1
+ ---
2
+ type: decision
3
+ title: HTTP SSE streams flush headers only after middleware has run
4
+ description: SSE responses defer the header flush and register with the eventHub, at the cost of a stricter ordering the runner must preserve
5
+ tags: http
6
+ ---
7
+
8
+ # HTTP SSE streams flush headers only after middleware has run
9
+
10
+ `executeRoute` in `packages/core/src/wirings/http/http-runner.ts` puts the
11
+ response into `'stream'` mode and sets the SSE content-type up front, but calls
12
+ `http.response.flushHeaders()` only after `runPikkuFunc` returns. Middleware runs
13
+ inside `runPikkuFunc`, and middleware is where CORS, auth and cookie headers are
14
+ set — flushing earlier would send the response head before those headers exist,
15
+ and they can never be added afterwards. `PikkuFetchHTTPResponse.createStream` in
16
+ `pikku-fetch-http-response.ts` enqueues a bare `:\n\n` comment frame on start for
17
+ the same reason on the client side: proxies and browsers do not surface the
18
+ stream until some body bytes arrive.
19
+
20
+ The SSE channel is also registered with `singletonServices.eventHub` when the
21
+ service exposes `onChannelOpened`, wrapped in a minimal object that satisfies
22
+ `PikkuChannelHandler`. That is what makes `eventHub.publish()` reach SSE
23
+ subscribers and not just WebSocket ones, and `channel.close` is rewrapped so the
24
+ eventHub is told about the close. On the delivery side,
25
+ `LocalEventHubService.publish` treats a throwing `channel.send` as a disconnect
26
+ and calls `onChannelClosed` — an SSE `ReadableStream` controller that the browser
27
+ has already abandoned throws rather than reporting closure.
28
+
29
+ **What this rules out:** hoisting `flushHeaders()` next to the other SSE header
30
+ calls; dropping the `:\n\n` priming frame as dead output; treating the eventHub
31
+ registration as WebSocket-only bookkeeping; and letting `publish` propagate a
32
+ send error instead of unregistering the channel.