@pikku/core 0.12.78 → 0.12.80

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 (341) hide show
  1. package/CHANGELOG.md +234 -0
  2. package/dist/dev/hot-reload.js +1 -6
  3. package/dist/ecosystem.d.ts +27 -0
  4. package/dist/ecosystem.js +26 -0
  5. package/dist/errors/error-handler.js +4 -2
  6. package/dist/function/function-runner.js +20 -42
  7. package/dist/function/functions.types.d.ts +9 -5
  8. package/dist/index.d.ts +4 -9
  9. package/dist/index.js +3 -8
  10. package/dist/middleware/auth-cookie.d.ts +0 -4
  11. package/dist/middleware/auth-cookie.js +38 -2
  12. package/dist/middleware/cors.js +1 -0
  13. package/dist/middleware/index.d.ts +1 -1
  14. package/dist/middleware/index.js +1 -1
  15. package/dist/middleware/remote-auth.js +14 -3
  16. package/dist/permissions.d.ts +8 -10
  17. package/dist/permissions.js +0 -11
  18. package/dist/pikku-state.js +12 -5
  19. package/dist/schema.js +35 -1
  20. package/dist/services/ai-run-state-service.d.ts +7 -1
  21. package/dist/services/in-memory-ai-run-state-service.d.ts +1 -1
  22. package/dist/services/in-memory-ai-run-state-service.js +2 -1
  23. package/dist/services/in-memory-workflow-service.d.ts +10 -0
  24. package/dist/services/in-memory-workflow-service.js +25 -0
  25. package/dist/services/local-content-request-handler.d.ts +21 -0
  26. package/dist/services/local-content-request-handler.js +72 -53
  27. package/dist/services/local-content.d.ts +6 -0
  28. package/dist/services/local-content.js +14 -1
  29. package/dist/services/workflow-service.d.ts +4 -2
  30. package/dist/testing/service-tests/agent-run-service-tests.d.ts +10 -0
  31. package/dist/testing/service-tests/agent-run-service-tests.js +72 -0
  32. package/dist/testing/service-tests/ai-storage-service-tests.d.ts +3 -0
  33. package/dist/testing/service-tests/ai-storage-service-tests.js +226 -0
  34. package/dist/testing/service-tests/channel-store-tests.d.ts +3 -0
  35. package/dist/testing/service-tests/channel-store-tests.js +72 -0
  36. package/dist/testing/service-tests/credential-service-tests.d.ts +3 -0
  37. package/dist/testing/service-tests/credential-service-tests.js +109 -0
  38. package/dist/testing/service-tests/deployment-service-tests.d.ts +3 -0
  39. package/dist/testing/service-tests/deployment-service-tests.js +21 -0
  40. package/dist/testing/service-tests/event-hub-store-tests.d.ts +3 -0
  41. package/dist/testing/service-tests/event-hub-store-tests.js +34 -0
  42. package/dist/testing/service-tests/secret-service-tests.d.ts +3 -0
  43. package/dist/testing/service-tests/secret-service-tests.js +80 -0
  44. package/dist/testing/service-tests/session-store-tests.d.ts +3 -0
  45. package/dist/testing/service-tests/session-store-tests.js +43 -0
  46. package/dist/testing/service-tests/workflow-run-service-tests.d.ts +3 -0
  47. package/dist/testing/service-tests/workflow-run-service-tests.js +42 -0
  48. package/dist/testing/service-tests/workflow-service-tests.d.ts +3 -0
  49. package/dist/testing/service-tests/workflow-service-tests.js +150 -0
  50. package/dist/testing/service-tests.d.ts +6 -0
  51. package/dist/testing/service-tests.js +26 -791
  52. package/dist/types/core.types.d.ts +11 -1
  53. package/dist/types/state.types.d.ts +1 -1
  54. package/dist/utils/node-host-resolver.d.ts +12 -0
  55. package/dist/utils/node-host-resolver.js +16 -0
  56. package/dist/utils/safe-fetch.d.ts +18 -0
  57. package/dist/utils/safe-fetch.js +167 -29
  58. package/dist/wirings/actor-flow/run-conversation.js +1 -6
  59. package/dist/wirings/ai-agent/agent-rpc.d.ts +15 -0
  60. package/dist/wirings/ai-agent/agent-rpc.js +53 -0
  61. package/dist/wirings/ai-agent/ai-agent-agui.js +1 -5
  62. package/dist/wirings/ai-agent/ai-agent-memory.js +3 -1
  63. package/dist/wirings/ai-agent/ai-agent-prepare.js +3 -9
  64. package/dist/wirings/ai-agent/ai-agent-runner.js +28 -107
  65. package/dist/wirings/ai-agent/ai-agent-stream.js +20 -61
  66. package/dist/wirings/ai-agent/ai-agent-turn.d.ts +56 -0
  67. package/dist/wirings/ai-agent/ai-agent-turn.js +81 -0
  68. package/dist/wirings/ai-agent/ai-agent.types.d.ts +1 -1
  69. package/dist/wirings/ai-agent/voice-input.js +1 -6
  70. package/dist/wirings/ai-agent/voice-output.js +2 -12
  71. package/dist/wirings/channel/channel-common.js +1 -0
  72. package/dist/wirings/channel/channel-handler.js +3 -5
  73. package/dist/wirings/channel/channel-rpc-service.d.ts +0 -6
  74. package/dist/wirings/channel/channel-rpc-service.js +0 -8
  75. package/dist/wirings/channel/channel-rpc.types.d.ts +6 -0
  76. package/dist/wirings/channel/channel-rpc.types.js +8 -0
  77. package/dist/wirings/channel/channel-runner.d.ts +1 -3
  78. package/dist/wirings/channel/channel-runner.js +16 -8
  79. package/dist/wirings/channel/channel.types.d.ts +2 -0
  80. package/dist/wirings/channel/pikku-abstract-channel-handler.js +1 -0
  81. package/dist/wirings/channel/serverless/serverless-channel-runner.js +3 -0
  82. package/dist/wirings/cli/channel/cli-channel-runner.js +2 -0
  83. package/dist/wirings/cli/cli-runner.js +4 -2
  84. package/dist/wirings/cli/cli.types.d.ts +0 -8
  85. package/dist/wirings/cli/command-parser.js +13 -0
  86. package/dist/wirings/gateway/gateway-runner.js +41 -5
  87. package/dist/wirings/http/http-routes.js +2 -0
  88. package/dist/wirings/http/http-runner.d.ts +0 -10
  89. package/dist/wirings/http/http-runner.js +6 -13
  90. package/dist/wirings/http/http.types.d.ts +0 -10
  91. package/dist/wirings/http/index.d.ts +1 -1
  92. package/dist/wirings/http/index.js +1 -1
  93. package/dist/wirings/mcp/mcp-runner.d.ts +0 -7
  94. package/dist/wirings/mcp/mcp-runner.js +0 -6
  95. package/dist/wirings/rpc/rpc-runner.d.ts +8 -51
  96. package/dist/wirings/rpc/rpc-runner.js +53 -86
  97. package/dist/wirings/rpc/rpc-types.d.ts +3 -0
  98. package/dist/wirings/secret/validate-secret-definitions.js +2 -0
  99. package/dist/wirings/trigger/pikku-trigger-service.d.ts +0 -4
  100. package/dist/wirings/trigger/trigger-runner.js +1 -0
  101. package/dist/wirings/virtual-user/run-virtual-user.js +11 -11
  102. package/dist/wirings/virtual-user/virtual-user-derive.js +4 -25
  103. package/dist/wirings/virtual-user/virtual-user-dispositions.js +1 -4
  104. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +29 -2
  105. package/dist/wirings/workflow/feature.js +7 -4
  106. package/dist/wirings/workflow/graph/graph-runner.d.ts +1 -2
  107. package/dist/wirings/workflow/graph/graph-runner.js +8 -7
  108. package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +0 -4
  109. package/dist/wirings/workflow/index.d.ts +7 -2
  110. package/dist/wirings/workflow/index.js +5 -1
  111. package/dist/wirings/workflow/pikku-scenario-service.d.ts +17 -3
  112. package/dist/wirings/workflow/pikku-scenario-service.js +38 -10
  113. package/dist/wirings/workflow/pikku-workflow-service.d.ts +44 -111
  114. package/dist/wirings/workflow/pikku-workflow-service.js +86 -404
  115. package/dist/wirings/workflow/workflow-approval.d.ts +39 -0
  116. package/dist/wirings/workflow/workflow-approval.js +114 -0
  117. package/dist/wirings/workflow/workflow-constants.d.ts +26 -0
  118. package/dist/wirings/workflow/workflow-constants.js +35 -0
  119. package/dist/wirings/workflow/workflow-errors.d.ts +58 -0
  120. package/dist/wirings/workflow/workflow-errors.js +112 -0
  121. package/dist/wirings/workflow/workflow-meta-resolver.d.ts +11 -0
  122. package/dist/wirings/workflow/workflow-meta-resolver.js +31 -0
  123. package/dist/wirings/workflow/workflow-queue-routing.d.ts +8 -0
  124. package/dist/wirings/workflow/workflow-queue-routing.js +38 -0
  125. package/dist/wirings/workflow/workflow-queue-wiring.d.ts +20 -0
  126. package/dist/wirings/workflow/workflow-queue-wiring.js +79 -0
  127. package/dist/wirings/workflow/workflow-recovery.d.ts +68 -0
  128. package/dist/wirings/workflow/workflow-recovery.js +101 -0
  129. package/dist/wirings/workflow/workflow-run-engine.types.d.ts +54 -0
  130. package/dist/wirings/workflow/workflow-run-engine.types.js +1 -0
  131. package/dist/wirings/workflow/workflow-run-ownership.d.ts +16 -0
  132. package/dist/wirings/workflow/workflow-run-ownership.js +29 -0
  133. package/dist/wirings/workflow/workflow-suspend.d.ts +12 -0
  134. package/dist/wirings/workflow/workflow-suspend.js +33 -0
  135. package/dist/wirings/workflow/workflow.types.d.ts +7 -0
  136. package/knowledge/decisions/internals/a-non-streaming-agent-run-registers-with-airunstate-too.md +22 -0
  137. package/knowledge/decisions/internals/a-resumed-agent-turn-is-as-interruptible-as-the-first.md +20 -0
  138. package/knowledge/decisions/internals/a-scenario-step-template-is-offered-unfilled.md +21 -0
  139. package/knowledge/decisions/internals/a-virtual-user-decides-whether-to-trust-memory-once-per-turn.md +21 -0
  140. package/knowledge/decisions/internals/a-wall-clock-threshold-is-a-load-test-in-disguise.md +46 -0
  141. package/knowledge/decisions/internals/a-workflow-wire-is-built-from-the-run-not-from-the-rpc-service.md +45 -0
  142. package/knowledge/decisions/internals/agent-context-waits-for-a-tool-result-still-being-written.md +21 -0
  143. package/knowledge/decisions/internals/agent-speech-travels-as-a-custom-agui-event.md +22 -0
  144. package/knowledge/decisions/internals/an-agent-interrupt-is-not-a-failure.md +23 -0
  145. package/knowledge/decisions/internals/an-agent-run-owned-by-another-instance-says-so.md +25 -0
  146. package/knowledge/decisions/internals/an-agent-stream-send-must-return-the-inner-sends-promise.md +22 -0
  147. package/knowledge/decisions/internals/an-empty-text-part-is-omitted-from-an-agent-message.md +20 -0
  148. package/knowledge/decisions/internals/an-empty-transcript-is-not-recorded.md +22 -0
  149. package/knowledge/decisions/internals/an-unref-d-timer-cannot-be-awaited-under-node-test.md +66 -0
  150. package/knowledge/decisions/internals/channel-state-accessors-are-unsound-generics-that-every-implementation-asserts.md +33 -0
  151. package/knowledge/decisions/internals/gateway-listener-middleware-runs-without-an-rpc-on-the-wire.md +43 -0
  152. package/knowledge/decisions/internals/hot-reload-writes-into-the-function-map-captured-at-startup.md +26 -0
  153. package/knowledge/decisions/internals/index.md +38 -26
  154. package/knowledge/decisions/internals/only-exposed-functions-enter-a-virtual-user-catalogue.md +21 -0
  155. package/knowledge/decisions/internals/scenario-given-and-when-are-sugar-but-then-is-not.md +24 -0
  156. package/knowledge/decisions/internals/side-effects-are-an-allowlist-not-a-boolean.md +34 -0
  157. package/knowledge/decisions/internals/speech-synthesis-picks-a-voice-per-sentence-and-warns-once.md +24 -0
  158. package/knowledge/decisions/internals/the-actor-prompt-says-json-because-of-json-object-mode.md +22 -0
  159. package/knowledge/decisions/internals/the-agent-done-event-goes-through-the-middleware-and-is-awaited.md +26 -0
  160. package/knowledge/decisions/internals/the-api-report-pins-members-not-just-names.md +43 -0
  161. package/knowledge/decisions/internals/the-ecosystem-entry-point-carries-the-adapter-surface.md +58 -0
  162. package/knowledge/decisions/internals/the-middleware-resolution-cache-is-deliberately-unbounded.md +40 -0
  163. package/knowledge/decisions/internals/the-per-invocation-rpc-view-is-a-class.md +40 -0
  164. package/knowledge/decisions/internals/the-persona-runtime-is-exported-from-the-persona-entry-point.md +28 -0
  165. package/knowledge/decisions/internals/the-transcript-event-is-sent-ahead-of-the-run.md +25 -0
  166. package/knowledge/decisions/internals/the-virtual-user-catalogue-is-the-only-gate-on-what-may-be-called.md +21 -0
  167. package/knowledge/decisions/internals/the-worker-disposition-is-the-one-that-is-not-testing.md +22 -0
  168. package/knowledge/decisions/internals/thread-history-records-the-transcript-not-the-audio.md +25 -0
  169. package/knowledge/decisions/internals/virtual-user-step-order-comes-from-insertion-order.md +21 -0
  170. package/knowledge/decisions/internals/voice-output-speaks-unless-voice-input-explicitly-says-otherwise.md +24 -0
  171. package/knowledge/decisions/internals/wiring-registries-erase-the-generics-their-wire-functions-capture.md +35 -0
  172. package/knowledge/decisions/security/a-dropped-audit-write-is-always-logged.md +4 -2
  173. package/knowledge/decisions/security/a-graph-run-starts-at-an-entry-node-the-graph-declared.md +33 -0
  174. package/knowledge/decisions/security/a-permission-gets-a-wire-it-cannot-reply-on.md +33 -0
  175. package/knowledge/decisions/security/a-step-runs-the-function-the-workflow-dispatched-it-with.md +37 -0
  176. package/knowledge/decisions/security/a-virtual-user-is-never-offered-a-step-that-would-forge-its-own-oracle.md +28 -0
  177. package/knowledge/decisions/security/a-workflow-run-is-read-and-approved-by-its-owner.md +34 -0
  178. package/knowledge/decisions/security/an-agent-approval-is-claimed-before-the-tool-runs.md +33 -0
  179. package/knowledge/decisions/security/an-upload-is-counted-as-it-arrives-not-buffered-then-measured.md +24 -0
  180. package/knowledge/decisions/security/gateway-handlers-run-through-the-function-runner-gate.md +13 -3
  181. package/knowledge/decisions/security/index.md +7 -0
  182. package/knowledge/questions/channel-middleware-accepts-bare-factories-that-nothing-resolves.md +35 -0
  183. package/knowledge/questions/index.md +2 -1
  184. package/knowledge/questions/unauthorized-channel-replies-escape-the-declared-out-type.md +44 -0
  185. package/package.json +14 -3
  186. package/scripts/generate-api-report.d.mts +1 -0
  187. package/scripts/generate-api-report.mjs +89 -0
  188. package/scripts/generate-api-report.mts +218 -0
  189. package/src/api-report.test.ts +69 -0
  190. package/src/column-form.ts +1 -4
  191. package/src/crypto-utils.test.ts +15 -2
  192. package/src/dev/hot-reload.ts +2 -7
  193. package/src/ecosystem.ts +40 -0
  194. package/src/errors/error-handler.ts +5 -3
  195. package/src/errors/error.test.ts +4 -1
  196. package/src/function/function-runner.test.ts +1 -1
  197. package/src/function/function-runner.ts +28 -39
  198. package/src/function/functions.types.ts +15 -9
  199. package/src/handle-error.ts +1 -1
  200. package/src/index.ts +3 -22
  201. package/src/middleware/auth-cookie.test.ts +50 -0
  202. package/src/middleware/auth-cookie.ts +38 -2
  203. package/src/middleware/cors.ts +2 -1
  204. package/src/middleware/index.ts +1 -1
  205. package/src/middleware/remote-auth.test.ts +43 -0
  206. package/src/middleware/remote-auth.ts +17 -3
  207. package/src/middleware-runner.ts +4 -2
  208. package/src/no-any-casts.test.ts +57 -0
  209. package/src/permissions.test.ts +3 -1
  210. package/src/permissions.ts +22 -24
  211. package/src/pikku-state.ts +17 -6
  212. package/src/public-surface.json +578 -0
  213. package/src/public-surface.json.README +25 -0
  214. package/src/public-surface.test.ts +105 -0
  215. package/src/removed-legacy-exports.test.ts +62 -0
  216. package/src/schema.test.ts +78 -0
  217. package/src/schema.ts +36 -1
  218. package/src/services/ai-run-state-service.ts +7 -1
  219. package/src/services/audit-service.ts +2 -2
  220. package/src/services/in-memory-ai-run-state-service.ts +3 -2
  221. package/src/services/in-memory-workflow-service.ts +25 -0
  222. package/src/services/index.ts +1 -4
  223. package/src/services/local-content-request-handler.test.ts +43 -5
  224. package/src/services/local-content-request-handler.ts +103 -74
  225. package/src/services/local-content.ts +15 -1
  226. package/src/services/local-email-service.ts +5 -1
  227. package/src/services/system-role-guard.test.ts +4 -1
  228. package/src/services/workflow-service.ts +9 -2
  229. package/src/side-effects-are-declared.test.ts +84 -0
  230. package/src/source-files-stay-composable.test.ts +41 -0
  231. package/src/testing/service-tests/agent-run-service-tests.ts +98 -0
  232. package/src/testing/service-tests/ai-storage-service-tests.ts +286 -0
  233. package/src/testing/service-tests/channel-store-tests.ts +98 -0
  234. package/src/testing/service-tests/credential-service-tests.ts +143 -0
  235. package/src/testing/service-tests/deployment-service-tests.ts +33 -0
  236. package/src/testing/service-tests/event-hub-store-tests.ts +48 -0
  237. package/src/testing/service-tests/secret-service-tests.ts +105 -0
  238. package/src/testing/service-tests/session-store-tests.ts +62 -0
  239. package/src/testing/service-tests/workflow-run-service-tests.ts +59 -0
  240. package/src/testing/service-tests/workflow-service-tests.ts +308 -0
  241. package/src/testing/service-tests.ts +31 -1111
  242. package/src/types/core.types.ts +15 -1
  243. package/src/types/state.types.ts +1 -1
  244. package/src/utils/node-host-resolver.ts +20 -0
  245. package/src/utils/safe-fetch.test.ts +143 -1
  246. package/src/utils/safe-fetch.ts +200 -25
  247. package/src/wirings/actor-flow/run-conversation.ts +1 -6
  248. package/src/wirings/ai-agent/agent-rpc.ts +120 -0
  249. package/src/wirings/ai-agent/ai-agent-agui.ts +1 -5
  250. package/src/wirings/ai-agent/ai-agent-interrupt.test.ts +2 -1
  251. package/src/wirings/ai-agent/ai-agent-memory.ts +8 -1
  252. package/src/wirings/ai-agent/ai-agent-prepare.ts +10 -12
  253. package/src/wirings/ai-agent/ai-agent-resume-authorization.test.ts +1 -0
  254. package/src/wirings/ai-agent/ai-agent-runner.test.ts +82 -2
  255. package/src/wirings/ai-agent/ai-agent-runner.ts +49 -120
  256. package/src/wirings/ai-agent/ai-agent-stream.test.ts +2 -0
  257. package/src/wirings/ai-agent/ai-agent-stream.ts +36 -63
  258. package/src/wirings/ai-agent/ai-agent-thread-ownership.test.ts +1 -1
  259. package/src/wirings/ai-agent/ai-agent-turn.ts +121 -0
  260. package/src/wirings/ai-agent/ai-agent.types.ts +1 -1
  261. package/src/wirings/ai-agent/voice-input.ts +1 -6
  262. package/src/wirings/ai-agent/voice-output.ts +2 -12
  263. package/src/wirings/channel/channel-common.ts +5 -2
  264. package/src/wirings/channel/channel-handler-shapes.test.ts +72 -0
  265. package/src/wirings/channel/channel-handler.ts +7 -7
  266. package/src/wirings/channel/channel-rpc-service.ts +0 -14
  267. package/src/wirings/channel/channel-rpc.test.ts +25 -4
  268. package/src/wirings/channel/channel-rpc.types.ts +14 -0
  269. package/src/wirings/channel/channel-runner.ts +33 -20
  270. package/src/wirings/channel/channel.types.ts +2 -0
  271. package/src/wirings/channel/local/local-channel-runner.ts +1 -1
  272. package/src/wirings/channel/pikku-abstract-channel-handler.ts +2 -1
  273. package/src/wirings/channel/serverless/serverless-channel-runner.ts +6 -3
  274. package/src/wirings/cli/channel/cli-channel-runner.ts +3 -1
  275. package/src/wirings/cli/channel/cli-raw-client-runner.ts +4 -1
  276. package/src/wirings/cli/cli-runner.ts +7 -4
  277. package/src/wirings/cli/cli.types.ts +0 -39
  278. package/src/wirings/cli/command-parser.test.ts +19 -0
  279. package/src/wirings/cli/command-parser.ts +17 -1
  280. package/src/wirings/gateway/gateway-authorization.test.ts +131 -0
  281. package/src/wirings/gateway/gateway-channel-meta.test.ts +44 -0
  282. package/src/wirings/gateway/gateway-runner.ts +62 -22
  283. package/src/wirings/http/http-routes.ts +4 -1
  284. package/src/wirings/http/http-runner.ts +11 -26
  285. package/src/wirings/http/http.types.ts +0 -15
  286. package/src/wirings/http/index.ts +1 -7
  287. package/src/wirings/http/pikku-fetch-http-request.ts +2 -2
  288. package/src/wirings/http/web-request.ts +1 -1
  289. package/src/wirings/mcp/mcp-runner.ts +2 -16
  290. package/src/wirings/persona/persona-environments.test.ts +14 -3
  291. package/src/wirings/persona/persona.test.ts +13 -3
  292. package/src/wirings/persona/validate-personas.ts +5 -1
  293. package/src/wirings/queue/queue-runner.ts +1 -1
  294. package/src/wirings/rpc/addon-auth-tags.test.ts +1 -5
  295. package/src/wirings/rpc/rpc-runner.ts +58 -136
  296. package/src/wirings/rpc/rpc-types.ts +7 -0
  297. package/src/wirings/rpc/wire-addon.ts +3 -1
  298. package/src/wirings/secret/validate-secret-definitions.test.ts +69 -0
  299. package/src/wirings/secret/validate-secret-definitions.ts +2 -0
  300. package/src/wirings/trigger/pikku-trigger-service.ts +0 -5
  301. package/src/wirings/trigger/trigger-runner.ts +7 -5
  302. package/src/wirings/virtual-user/run-virtual-user.test.ts +18 -9
  303. package/src/wirings/virtual-user/run-virtual-user.ts +28 -15
  304. package/src/wirings/virtual-user/virtual-user-agents.test.ts +4 -1
  305. package/src/wirings/virtual-user/virtual-user-derive.ts +4 -25
  306. package/src/wirings/virtual-user/virtual-user-dispositions.test.ts +7 -2
  307. package/src/wirings/virtual-user/virtual-user-dispositions.ts +1 -4
  308. package/src/wirings/virtual-user/virtual-user-intents.test.ts +13 -3
  309. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +35 -2
  310. package/src/wirings/workflow/feature.ts +7 -4
  311. package/src/wirings/workflow/graph/graph-node.ts +1 -1
  312. package/src/wirings/workflow/graph/graph-runner.test.ts +4 -2
  313. package/src/wirings/workflow/graph/graph-runner.ts +13 -16
  314. package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -5
  315. package/src/wirings/workflow/index.ts +12 -4
  316. package/src/wirings/workflow/pikku-scenario-service.ts +54 -25
  317. package/src/wirings/workflow/pikku-workflow-service.test.ts +2 -2
  318. package/src/wirings/workflow/pikku-workflow-service.ts +208 -630
  319. package/src/wirings/workflow/scenario-hooks.test.ts +51 -0
  320. package/src/wirings/workflow/workflow-approval.ts +185 -0
  321. package/src/wirings/workflow/workflow-child-run-session.test.ts +89 -0
  322. package/src/wirings/workflow/workflow-constants.ts +47 -0
  323. package/src/wirings/workflow/workflow-dispatch-durability.test.ts +1 -1
  324. package/src/wirings/workflow/workflow-dispatch-relay.test.ts +128 -0
  325. package/src/wirings/workflow/workflow-errors.ts +128 -0
  326. package/src/wirings/workflow/workflow-inline-authority.test.ts +12 -6
  327. package/src/wirings/workflow/workflow-meta-resolver.ts +45 -0
  328. package/src/wirings/workflow/workflow-missing-meta.test.ts +92 -0
  329. package/src/wirings/workflow/workflow-queue-routing.ts +85 -0
  330. package/src/wirings/workflow/workflow-queue-wiring.ts +149 -0
  331. package/src/wirings/workflow/workflow-recovery.ts +162 -0
  332. package/src/wirings/workflow/workflow-retry-policy.test.ts +1 -1
  333. package/src/wirings/workflow/workflow-run-authority.test.ts +215 -0
  334. package/src/wirings/workflow/workflow-run-engine.types.ts +91 -0
  335. package/src/wirings/workflow/workflow-run-ownership.ts +36 -0
  336. package/src/wirings/workflow/workflow-suspend.ts +61 -0
  337. package/src/wirings/workflow/workflow.types.ts +7 -0
  338. package/src/wirings-stay-decoupled.test.ts +123 -0
  339. package/tsconfig.json +1 -1
  340. package/tsconfig.tsbuildinfo +1 -1
  341. package/src/internal.ts +0 -10
@@ -197,18 +197,6 @@ export type ValidateParameters<Params extends string, Input> =
197
197
  ? Params
198
198
  : never
199
199
 
200
- /**
201
- * Extract output type from a Pikku function config type
202
- */
203
- export type ExtractFunctionOutput<Func> =
204
- Func extends CorePikkuFunctionConfig<infer FuncType, any, any>
205
- ? FuncType extends
206
- | CorePikkuFunction<any, infer Output, any, any, any>
207
- | CorePikkuFunctionSessionless<any, infer Output, any, any, any>
208
- ? Output
209
- : never
210
- : never
211
-
212
200
  /**
213
201
  * CLI command configuration that infers options from function input type.
214
202
  * This is a helper type for creating type-safe CLI commands.
@@ -290,33 +278,6 @@ export type CLICommandShorthand<
290
278
  >,
291
279
  > = PikkuFunctionConfig
292
280
 
293
- /**
294
- * Command definition (either full or shorthand)
295
- */
296
- export type CLICommandDefinition<
297
- In,
298
- Out,
299
- PikkuFunctionConfig extends CorePikkuFunctionConfig<
300
- | CorePikkuFunction<In, Out, any, any, any>
301
- | CorePikkuFunctionSessionless<In, Out, any, any, any>
302
- >,
303
- PikkuPermission extends CorePikkuPermission<any, any, any>,
304
- PikkuMiddleware extends CorePikkuMiddleware,
305
- Options = any,
306
- Subcommands extends Record<string, CoreCLICommandConfig<any, any, any>> =
307
- Record<string, CoreCLICommandConfig<any, any, any>>,
308
- > =
309
- | CoreCLICommand<
310
- In,
311
- Out,
312
- PikkuFunctionConfig,
313
- PikkuPermission,
314
- PikkuMiddleware,
315
- Options,
316
- Subcommands
317
- >
318
- | CLICommandShorthand<In, Out, PikkuFunctionConfig>
319
-
320
281
  /**
321
282
  * CLI wiring configuration
322
283
  */
@@ -710,5 +710,24 @@ describe('Command Parser', () => {
710
710
  assert.ok(result.errors.some((e) => e.includes('Unknown option: -x')))
711
711
  assert.deepStrictEqual(result.warnings, [])
712
712
  })
713
+ describe('short-flag cluster is bounded (DoS)', () => {
714
+ test('a huge short-flag cluster yields a single error, not one per char', () => {
715
+ const huge = '-' + 'a'.repeat(200_000)
716
+ const result = parseCLIArguments(
717
+ ['greet', 'Alice', huge],
718
+ 'test-cli',
719
+ testMeta
720
+ )
721
+ const clusterErrors = result.errors.filter((e) =>
722
+ e.includes('Unknown option')
723
+ )
724
+ // Without the cap this would be ~200k errors (one per character).
725
+ assert.ok(
726
+ clusterErrors.length <= 2,
727
+ `expected the oversized cluster to collapse to a single error, got ${clusterErrors.length}`
728
+ )
729
+ assert.ok(result.errors.some((e) => e.includes('too long')))
730
+ })
731
+ })
713
732
  })
714
733
  })
@@ -86,6 +86,15 @@ export interface ParsedCommand {
86
86
  warnings: string[]
87
87
  }
88
88
 
89
+ /**
90
+ * A real short-flag cluster is a handful of characters (`-abc`). Anything past
91
+ * this is treated as a single malformed token rather than scanned per
92
+ * character — the parser runs over untrusted CLI-channel frames, and a
93
+ * multi-megabyte `-aaaa…` would otherwise be O(length) work that also pushed
94
+ * one error per character.
95
+ */
96
+ const MAX_SHORT_FLAG_CLUSTER = 64
97
+
89
98
  export function parseCLIArguments(
90
99
  args: string[],
91
100
  programName: string,
@@ -238,6 +247,13 @@ export function parseCLIArguments(
238
247
  }
239
248
  }
240
249
  } else if (arg.startsWith('-') && arg.length > 1) {
250
+ if (arg.length > MAX_SHORT_FLAG_CLUSTER) {
251
+ result.errors.push(
252
+ `Unknown option: ${arg.slice(0, MAX_SHORT_FLAG_CLUSTER)}… (too long)`
253
+ )
254
+ currentIndex++
255
+ continue
256
+ }
241
257
  for (let i = 1; i < arg.length; i++) {
242
258
  const shortFlag = arg[i]
243
259
 
@@ -354,7 +370,7 @@ function parseOptionValue(value: string, optionDef?: CLIOption): any {
354
370
  return parseFloat(value)
355
371
  }
356
372
 
357
- if (optionDef.choices && !optionDef.choices.includes(value as any)) {
373
+ if (optionDef.choices && !optionDef.choices.includes(value as never)) {
358
374
  // Deliberately not an error here — applyOptionDefaults reports bad choices.
359
375
  return value
360
376
  }
@@ -8,6 +8,7 @@ import {
8
8
  addGlobalPermission,
9
9
  clearPermissionsCache,
10
10
  } from '../../permissions.js'
11
+ import { addTagMiddleware } from '../../middleware-runner.js'
11
12
  import type {
12
13
  GatewayAdapter,
13
14
  GatewayInboundMessage,
@@ -84,6 +85,31 @@ const seedCompiledMeta = () => {
84
85
  }
85
86
  }
86
87
 
88
+ /**
89
+ * What the inspector records for a gateway and the function it was wired with.
90
+ * These tests wire gateways by hand, so nothing populates it otherwise — and it
91
+ * has to be in place before `wireGateway`, exactly as the generated bootstrap
92
+ * loads every meta file before any wiring file.
93
+ */
94
+ const seedDeclaredHandler = (
95
+ gatewayName: string,
96
+ funcId: string,
97
+ funcMeta: Record<string, any>,
98
+ gatewayMeta: Record<string, any> = {}
99
+ ) => {
100
+ ;(pikkuState(null, 'function', 'meta') as any)[funcId] = {
101
+ pikkuFuncId: funcId,
102
+ inputSchemaName: null,
103
+ outputSchemaName: null,
104
+ ...funcMeta,
105
+ }
106
+ ;(pikkuState(null, 'gateway', 'meta') as any)[gatewayName] = {
107
+ pikkuFuncId: funcId,
108
+ name: gatewayName,
109
+ ...gatewayMeta,
110
+ }
111
+ }
112
+
87
113
  const postMessage = async (route: string) => {
88
114
  const request = new Request(`http://localhost${route}`, {
89
115
  method: 'POST',
@@ -229,6 +255,68 @@ describe('gateway handler authorization', () => {
229
255
  assert.deepEqual(calls, ['ran'])
230
256
  })
231
257
 
258
+ test('a handler declared with pikkuFunc keeps its session requirement', async () => {
259
+ const calls: string[] = []
260
+
261
+ seedDeclaredHandler('declared-session', 'myHandler', {
262
+ sessionless: false,
263
+ })
264
+
265
+ wireGateway({
266
+ name: 'declared-session',
267
+ type: 'webhook',
268
+ route: '/webhooks/declared-session',
269
+ adapter: createMockAdapter(),
270
+ func: {
271
+ func: async () => {
272
+ calls.push('ran')
273
+ return { text: 'reply' }
274
+ },
275
+ } as any,
276
+ })
277
+
278
+ seedCompiledMeta()
279
+ httpRouter.initialize()
280
+
281
+ const response = await postMessage('/webhooks/declared-session')
282
+
283
+ assert.equal(response.status, 403)
284
+ assert.deepEqual(
285
+ calls,
286
+ [],
287
+ 'a session-required pikkuFunc must not be silently made sessionless'
288
+ )
289
+ })
290
+
291
+ test('a handler declared sessionless keeps running without a session', async () => {
292
+ const calls: string[] = []
293
+
294
+ seedDeclaredHandler('declared-sessionless', 'mySessionlessHandler', {
295
+ sessionless: true,
296
+ })
297
+
298
+ wireGateway({
299
+ name: 'declared-sessionless',
300
+ type: 'webhook',
301
+ route: '/webhooks/declared-sessionless',
302
+ adapter: createMockAdapter(),
303
+ func: {
304
+ func: async () => {
305
+ calls.push('ran')
306
+ return { text: 'reply' }
307
+ },
308
+ } as any,
309
+ })
310
+
311
+ seedCompiledMeta()
312
+ httpRouter.initialize()
313
+
314
+ const response = await postMessage('/webhooks/declared-sessionless')
315
+
316
+ assert.equal(response.status, 200)
317
+ assert.deepEqual(calls, ['ran'])
318
+ })
319
+
232
320
  test('gateway-level auth: true requires a session', async () => {
233
321
  const calls: string[] = []
234
322
 
@@ -281,6 +369,49 @@ describe('gateway handler authorization', () => {
281
369
  assert.deepEqual(calls, [], 'auth: true must require a session')
282
370
  })
283
371
 
372
+ test('tag middleware declared for the gateway actually runs', async () => {
373
+ const order: string[] = []
374
+
375
+ addTagMiddleware('audited', [
376
+ async (_s: any, _wire: any, next: any) => {
377
+ order.push('middleware')
378
+ await next()
379
+ },
380
+ ] as any)
381
+
382
+ seedDeclaredHandler(
383
+ 'tagged',
384
+ 'myTaggedHandler',
385
+ { sessionless: true },
386
+ { tags: ['audited'], middleware: [{ type: 'tag', tag: 'audited' }] }
387
+ )
388
+
389
+ wireGateway({
390
+ name: 'tagged',
391
+ type: 'webhook',
392
+ route: '/webhooks/tagged',
393
+ adapter: createMockAdapter(),
394
+ func: {
395
+ func: async () => {
396
+ order.push('handler')
397
+ return { text: 'reply' }
398
+ },
399
+ } as any,
400
+ })
401
+
402
+ seedCompiledMeta()
403
+ httpRouter.initialize()
404
+
405
+ const response = await postMessage('/webhooks/tagged')
406
+
407
+ assert.equal(response.status, 200)
408
+ assert.deepEqual(
409
+ order,
410
+ ['middleware', 'handler'],
411
+ 'addTagMiddleware must gate a gateway carrying the tag'
412
+ )
413
+ })
414
+
284
415
  test('the adapter still auto-sends the handler reply', async () => {
285
416
  const adapter = createMockAdapter()
286
417
 
@@ -0,0 +1,44 @@
1
+ import { describe, test } from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+
4
+ import { pikkuState, resetPikkuState } from '../../pikku-state.js'
5
+ import { wireGateway } from './gateway-runner.js'
6
+
7
+ const wireWebsocketGateway = (name: string) => {
8
+ resetPikkuState()
9
+ wireGateway({
10
+ name,
11
+ type: 'websocket',
12
+ route: `/${name}`,
13
+ adapter: { name: 'test', parse: () => null, send: async () => {} },
14
+ func: { func: async () => undefined },
15
+ } as any)
16
+ return pikkuState(null, 'channel', 'meta')[name]!
17
+ }
18
+
19
+ describe('a gateway-wired websocket channel writes complete channel meta', () => {
20
+ test('the fields every channel reader indexes are present', () => {
21
+ const meta = wireWebsocketGateway('chatGateway')
22
+
23
+ // channel-handler.ts indexes messageWirings without a guard, and the
24
+ // serverless and local runners read disconnect directly.
25
+ assert.deepEqual(
26
+ meta.messageWirings,
27
+ {},
28
+ 'messageWirings must be an object — channel-handler indexes it unguarded'
29
+ )
30
+ assert.equal(meta.disconnect, null)
31
+ assert.equal(meta.input, null)
32
+ })
33
+
34
+ test('it is marked as gateway-wired', () => {
35
+ assert.equal(wireWebsocketGateway('flagged').gateway, true)
36
+ })
37
+
38
+ test('connect and message point at the generated handlers', () => {
39
+ const meta = wireWebsocketGateway('handlers')
40
+
41
+ assert.equal(meta.connect?.pikkuFuncId, 'gateway__handlers__connect')
42
+ assert.equal(meta.message?.pikkuFuncId, 'gateway__handlers__message')
43
+ })
44
+ })
@@ -3,6 +3,7 @@ import { NotFoundError, UnauthorizedError } from '../../errors/errors.js'
3
3
  import { addFunction, runPikkuFunc } from '../../function/function-runner.js'
4
4
  import { runMiddleware } from '../../middleware-runner.js'
5
5
  import { httpRouter } from '../http/routers/http-router.js'
6
+ import type { CoreHTTPFunctionWiring } from '../http/http.types.js'
6
7
  import type {
7
8
  CoreGateway,
8
9
  GatewayAdapter,
@@ -23,20 +24,46 @@ const bridgeMiddlewareSession = async (wire: PikkuRawWire): Promise<void> => {
23
24
  }
24
25
  }
25
26
 
27
+ /**
28
+ * Metadata the inspector recorded for the function the gateway was wired with.
29
+ * The bootstrap loads every meta file before any wiring file, so this is
30
+ * already populated by the time a gateway wires itself. A gateway wired by
31
+ * hand rather than through codegen has no entry, and falls back to the
32
+ * sessionless default below.
33
+ */
34
+ const declaredHandlerMeta = (config: CoreGateway) => {
35
+ const declaredFuncId = pikkuState(null, 'gateway', 'meta')[config.name]
36
+ ?.pikkuFuncId
37
+ return declaredFuncId
38
+ ? pikkuState(null, 'function', 'meta')[declaredFuncId]
39
+ : undefined
40
+ }
41
+
26
42
  // knowledge: decisions/security/gateway-handlers-run-through-the-function-runner-gate.md
27
43
  const registerGatewayHandler = (config: CoreGateway): string => {
28
44
  const funcId = gatewayHandlerFuncId(config.name)
29
45
  const funcMeta = pikkuState(null, 'function', 'meta')
46
+ const declared = declaredHandlerMeta(config)
30
47
  funcMeta[funcId] = {
48
+ ...declared,
31
49
  pikkuFuncId: funcId,
32
- inputSchemaName: null,
33
- outputSchemaName: null,
34
- sessionless: true,
50
+ inputSchemaName: declared?.inputSchemaName ?? null,
51
+ outputSchemaName: declared?.outputSchemaName ?? null,
52
+ sessionless: declared?.sessionless ?? true,
35
53
  }
36
- addFunction(funcId, config.func as any)
54
+ addFunction(funcId, config.func)
37
55
  return funcId
38
56
  }
39
57
 
58
+ /**
59
+ * Tag middleware the inspector resolved for this gateway. It is keyed by
60
+ * gateway name rather than reachable from `config`, because `tags` is a
61
+ * compile-time input everywhere — nothing at runtime maps a tag to its
62
+ * middleware group.
63
+ */
64
+ const gatewayInheritedMiddleware = (config: CoreGateway) =>
65
+ pikkuState(null, 'gateway', 'meta')[config.name]?.middleware
66
+
40
67
  export const resolveGatewayAdapter = (
41
68
  config: CoreGateway,
42
69
  services: CoreSingletonServices
@@ -73,7 +100,7 @@ export const wireGateway = (config: CoreGateway): void => {
73
100
  break
74
101
  default:
75
102
  throw new Error(
76
- `Unknown gateway type '${(config as any).type}' for gateway '${config.name}'`
103
+ `Unknown gateway type '${config.type}' for gateway '${config.name}'`
77
104
  )
78
105
  }
79
106
  }
@@ -92,7 +119,7 @@ const wireWebhookGateway = (config: CoreGateway): void => {
92
119
  func: createWebhookPostHandler(config),
93
120
  }
94
121
 
95
- addFunction(postFuncId, postHandler as any)
122
+ addFunction(postFuncId, postHandler)
96
123
 
97
124
  if (!routes.has('post')) {
98
125
  routes.set('post', new Map())
@@ -102,7 +129,10 @@ const wireWebhookGateway = (config: CoreGateway): void => {
102
129
  route,
103
130
  func: postHandler,
104
131
  auth: false,
105
- } as any)
132
+ // A gateway handler takes (services, data, wire) rather than a pikku
133
+ // function's shape, so it never matches CorePikkuFunctionConfig. It is only
134
+ // ever invoked through runPikkuFunc, which is what makes that safe.
135
+ } as unknown as CoreHTTPFunctionWiring<unknown, unknown, string>)
106
136
 
107
137
  // knowledge: decisions/internals/gateway-adapters-resolve-lazily-and-are-promise-cached.md
108
138
  if (typeof adapter === 'function' || adapter.verifyWebhook) {
@@ -113,7 +143,7 @@ const wireWebhookGateway = (config: CoreGateway): void => {
113
143
  func: createWebhookVerifyHandler(config),
114
144
  }
115
145
 
116
- addFunction(verifyFuncId, verifyHandler as any)
146
+ addFunction(verifyFuncId, verifyHandler)
117
147
 
118
148
  if (!routes.has('get')) {
119
149
  routes.set('get', new Map())
@@ -125,7 +155,7 @@ const wireWebhookGateway = (config: CoreGateway): void => {
125
155
  auth: false,
126
156
  // knowledge: decisions/internals/gateway-webhook-challenges-echo-bytes-not-json.md
127
157
  returnsJSON: false,
128
- } as any)
158
+ } as unknown as CoreHTTPFunctionWiring<unknown, unknown, string>)
129
159
  }
130
160
 
131
161
  httpRouter.reset()
@@ -134,6 +164,7 @@ const wireWebhookGateway = (config: CoreGateway): void => {
134
164
  const createWebhookPostHandler = (config: CoreGateway) => {
135
165
  const { name, middleware: userMiddleware } = config
136
166
  const handlerFuncId = registerGatewayHandler(config)
167
+ const inheritedMiddleware = gatewayInheritedMiddleware(config)
137
168
 
138
169
  return async (
139
170
  services: CoreSingletonServices,
@@ -160,16 +191,17 @@ const createWebhookPostHandler = (config: CoreGateway) => {
160
191
  platform: adapter.name,
161
192
  send: (msg: GatewayOutboundMessage) => adapter.send(parsed.senderId, msg),
162
193
  }
163
- ;(wire as any).gateway = gateway
194
+ wire.gateway = gateway
164
195
 
165
196
  // Gateway middleware runs outside the gate so it can establish the session the gate checks.
166
197
  const invoke = async () => {
167
- await bridgeMiddlewareSession(wire as any)
198
+ await bridgeMiddlewareSession(wire)
168
199
  return await runPikkuFunc('gateway', name, handlerFuncId, {
169
200
  singletonServices: services,
170
201
  data: () => parsed,
171
202
  auth: config.auth,
172
- wire: wire as any,
203
+ inheritedMiddleware,
204
+ wire,
173
205
  })
174
206
  }
175
207
 
@@ -247,18 +279,22 @@ const wireWebsocketGateway = (config: CoreGateway): void => {
247
279
  name,
248
280
  route,
249
281
  gateway: true,
282
+ input: null,
250
283
  connect: { pikkuFuncId: connectFuncId },
284
+ disconnect: null,
251
285
  message: { pikkuFuncId: messageFuncId },
252
- } as any
286
+ messageWirings: {},
287
+ }
253
288
 
254
289
  const userMiddleware = config.middleware as CorePikkuMiddleware[] | undefined
255
290
  const handlerFuncId = registerGatewayHandler(config)
291
+ const inheritedMiddleware = gatewayInheritedMiddleware(config)
256
292
 
257
293
  addFunction(connectFuncId, {
258
294
  auth: false,
259
295
  func: async (services: any, _data: unknown, wire: PikkuWire) => {
260
296
  const adapter = await resolveGatewayAdapter(config, services)
261
- ;(wire as any).gateway = {
297
+ wire.gateway = {
262
298
  gatewayName: name,
263
299
  senderId: '',
264
300
  platform: adapter.name,
@@ -267,7 +303,7 @@ const wireWebsocketGateway = (config: CoreGateway): void => {
267
303
  },
268
304
  } satisfies PikkuGateway
269
305
  },
270
- } as any)
306
+ })
271
307
 
272
308
  addFunction(messageFuncId, {
273
309
  auth: false,
@@ -284,15 +320,16 @@ const wireWebsocketGateway = (config: CoreGateway): void => {
284
320
  wire.channel?.send(msg)
285
321
  },
286
322
  }
287
- ;(wire as any).gateway = gateway
323
+ wire.gateway = gateway
288
324
 
289
325
  const invoke = async () => {
290
- await bridgeMiddlewareSession(wire as any)
326
+ await bridgeMiddlewareSession(wire)
291
327
  return await runPikkuFunc('gateway', name, handlerFuncId, {
292
328
  singletonServices: services,
293
329
  data: () => parsed,
294
330
  auth: config.auth,
295
- wire: wire as any,
331
+ inheritedMiddleware,
332
+ wire,
296
333
  })
297
334
  }
298
335
 
@@ -307,7 +344,7 @@ const wireWebsocketGateway = (config: CoreGateway): void => {
307
344
  wire.channel?.send(result)
308
345
  }
309
346
  },
310
- } as any)
347
+ })
311
348
 
312
349
  // knowledge: decisions/internals/gateway-wiring-is-a-meta-wiring-over-http-and-channels.md
313
350
  channels.set(name, {
@@ -316,7 +353,7 @@ const wireWebsocketGateway = (config: CoreGateway): void => {
316
353
  auth: false,
317
354
  onConnect: { func: async () => {} },
318
355
  onMessage: { func: async () => {} },
319
- } as any)
356
+ })
320
357
 
321
358
  httpRouter.reset()
322
359
  }
@@ -333,6 +370,7 @@ export const createListenerMessageHandler = (
333
370
  ): ((rawData: unknown) => Promise<void>) => {
334
371
  const userMiddleware = config.middleware as CorePikkuMiddleware[] | undefined
335
372
  const handlerFuncId = registerGatewayHandler(config)
373
+ const inheritedMiddleware = gatewayInheritedMiddleware(config)
336
374
 
337
375
  return async (rawData: unknown): Promise<void> => {
338
376
  const adapter = await resolveGatewayAdapter(config, singletonServices)
@@ -346,7 +384,7 @@ export const createListenerMessageHandler = (
346
384
  platform: adapter.name,
347
385
  send: (msg: GatewayOutboundMessage) => adapter.send(parsed.senderId, msg),
348
386
  }
349
- ;(wire as any).gateway = gateway
387
+ wire.gateway = gateway
350
388
 
351
389
  const invoke = async () => {
352
390
  await bridgeMiddlewareSession(wire)
@@ -354,14 +392,16 @@ export const createListenerMessageHandler = (
354
392
  singletonServices,
355
393
  data: () => parsed,
356
394
  auth: config.auth,
395
+ inheritedMiddleware,
357
396
  wire,
358
397
  })
359
398
  }
360
399
 
400
+ // knowledge: decisions/internals/gateway-listener-middleware-runs-without-an-rpc-on-the-wire.md
361
401
  const result: any = userMiddleware?.length
362
402
  ? await runMiddleware(
363
403
  singletonServices,
364
- wire as any,
404
+ wire as PikkuWire,
365
405
  userMiddleware,
366
406
  invoke
367
407
  )
@@ -1,4 +1,5 @@
1
1
  import type {
2
+ CoreHTTPFunctionWiring,
2
3
  HTTPRouteConfig,
3
4
  HTTPRouteMap,
4
5
  HTTPRouteContract,
@@ -84,7 +85,9 @@ function registerRoute(
84
85
  timeout: route.timeout,
85
86
  headers: route.headers,
86
87
  sse: route.sse,
87
- } as any)
88
+ // `CoreHTTPFunctionWiring` is discriminated by `method`, and a group builds
89
+ // its routes from a method chosen at runtime — no arm can be narrowed to.
90
+ } as CoreHTTPFunctionWiring<unknown, unknown, string>)
88
91
  }
89
92
 
90
93
  function isRouteConfig(value: unknown): value is HTTPRouteConfig {
@@ -33,8 +33,10 @@ import { isProduction } from '../../env.js'
33
33
  import { pikkuState } from '../../pikku-state.js'
34
34
  import { PikkuFetchHTTPResponse } from './pikku-fetch-http-response.js'
35
35
  import { PikkuFetchHTTPRequest } from './pikku-fetch-http-request.js'
36
- import type { PikkuChannel } from '../channel/channel.types.js'
37
- import { unsupportedChannelRemote } from '../channel/channel-rpc.js'
36
+ import type { BinaryData, PikkuChannel } from '../channel/channel.types.js'
37
+ // The leaf module, not the channel-rpc barrel: http needs one refusal
38
+ // function, and the barrel drags in 4,932 lines of channel RPC runtime.
39
+ import { unsupportedChannelRemote } from '../channel/channel-rpc.types.js'
38
40
  import { addFunction, runPikkuFunc } from '../../function/function-runner.js'
39
41
  import { applyWebResponse } from './web-request.js'
40
42
  import { httpRouter } from './routers/http-router.js'
@@ -68,26 +70,6 @@ export const addHTTPMiddleware = <PikkuMiddleware extends CorePikkuMiddleware>(
68
70
  return middleware
69
71
  }
70
72
 
71
- /**
72
- * @deprecated HTTP-route-level permissions were removed in #972 — permissions
73
- * are now function-scoped only (declare them on the function via
74
- * `pikkuFunc({ permissions })`). This throwing stub exists solely so the pinned
75
- * bootstrap CLI (which still generates an `addHTTPPermission` wrapper) can
76
- * resolve the import at build time; it is never called. Delete once
77
- * `PIKKU_CLI_VERSION` in the CLI build is bumped past the release that removes
78
- * HTTP-route permissions.
79
- */
80
- export const addHTTPPermission = (
81
- _pattern: string,
82
- _permissions:
83
- | Record<string, CorePikkuPermission | CorePikkuPermission[]>
84
- | CorePikkuPermission[]
85
- ): never => {
86
- throw new Error(
87
- 'addHTTPPermission was removed in #972 — HTTP-route-level permissions no longer exist. Declare permissions on the function definition instead: pikkuFunc({ permissions }).'
88
- )
89
- }
90
-
91
73
  export const wireHTTP = <
92
74
  In,
93
75
  Out,
@@ -126,7 +108,8 @@ export const wireHTTP = <
126
108
  }
127
109
  pikkuState(null, 'http', 'routes')
128
110
  .get(httpWiring.method)
129
- ?.set(httpWiring.route, httpWiring as any)
111
+ // knowledge: decisions/internals/wiring-registries-erase-the-generics-their-wire-functions-capture.md
112
+ ?.set(httpWiring.route, httpWiring as CoreHTTPFunctionWiring<any, any, any>)
130
113
  }
131
114
 
132
115
  const getMatchingRoute = (requestType: string, requestPath: string) => {
@@ -261,7 +244,8 @@ const executeRoute = async (
261
244
  setState: (s) => {
262
245
  sseState = s
263
246
  },
264
- getState: () => sseState as any,
247
+ // knowledge: decisions/internals/channel-state-accessors-are-unsound-generics-that-every-implementation-asserts.md
248
+ getState: () => sseState as never,
265
249
  clearState: () => {
266
250
  sseState = undefined
267
251
  },
@@ -275,7 +259,7 @@ const executeRoute = async (
275
259
  const channelHandler = {
276
260
  getChannel: () => channelRef,
277
261
  send: (data: unknown, isBinary?: boolean) => {
278
- if (isBinary) channelRef.sendBinary(data as any)
262
+ if (isBinary) channelRef.sendBinary(data as BinaryData)
279
263
  else channelRef.send(data)
280
264
  },
281
265
  sendBinary: (data: any) => channelRef.sendBinary(data),
@@ -424,7 +408,8 @@ export const fetchData = async <In, Out>(
424
408
  globalMiddleware as CorePikkuMiddleware[]
425
409
  )
426
410
  }
427
- response.status(204).json(undefined as any)
411
+ // 204 carries no body, and `json` has no no-content overload.
412
+ response.status(204).json(undefined as never)
428
413
  return
429
414
  }
430
415
  scopedLogger.info({
@@ -73,10 +73,6 @@ export interface PikkuHTTP<In = unknown> {
73
73
  response?: PikkuHTTPResponse
74
74
  }
75
75
 
76
- export type RequestHeaders =
77
- | Record<string, string | string[] | undefined>
78
- | ((headerName: string) => string | string[] | undefined)
79
-
80
76
  export type PikkuQuery<T = Record<string, string | undefined>> = Record<
81
77
  string,
82
78
  string | T | null | Array<T | null>
@@ -207,17 +203,6 @@ export type HTTPWiringMeta = CommonWireMeta & {
207
203
  }
208
204
  export type HTTPWiringsMeta = Record<HTTPMethod, Record<string, HTTPWiringMeta>>
209
205
 
210
- export type HTTPFunctionsMeta = Array<{
211
- name: string
212
- inputs: string[] | null
213
- outputs: string[] | null
214
- }>
215
-
216
- export type HTTPWiringMiddleware = {
217
- route: string
218
- middleware: CorePikkuMiddleware[]
219
- }
220
-
221
206
  export interface PikkuHTTPRequest<In = unknown> {
222
207
  method(): HTTPMethod
223
208
  path(): string