@pikku/core 0.12.79 → 0.12.82

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 (479) hide show
  1. package/CHANGELOG.md +473 -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/errors/index.d.ts +1 -1
  7. package/dist/errors/index.js +1 -1
  8. package/dist/function/function-runner.js +22 -47
  9. package/dist/function/functions.types.d.ts +9 -5
  10. package/dist/function/index.d.ts +1 -1
  11. package/dist/index.d.ts +14 -19
  12. package/dist/index.js +6 -11
  13. package/dist/middleware/auth-cookie.d.ts +0 -4
  14. package/dist/middleware/auth-cookie.js +38 -2
  15. package/dist/middleware/cors.js +1 -0
  16. package/dist/middleware/index.d.ts +1 -1
  17. package/dist/middleware/index.js +1 -1
  18. package/dist/middleware/remote-auth.js +14 -3
  19. package/dist/permissions.d.ts +8 -10
  20. package/dist/permissions.js +0 -11
  21. package/dist/pikku-state.js +16 -5
  22. package/dist/schema.js +35 -1
  23. package/dist/services/ai-agent-runner-service.d.ts +7 -0
  24. package/dist/services/ai-run-state-service.d.ts +17 -1
  25. package/dist/services/in-memory-ai-run-state-service.d.ts +6 -2
  26. package/dist/services/in-memory-ai-run-state-service.js +11 -1
  27. package/dist/services/in-memory-workflow-service.js +2 -0
  28. package/dist/services/index.d.ts +15 -15
  29. package/dist/services/index.js +5 -5
  30. package/dist/services/local-content-request-handler.d.ts +21 -0
  31. package/dist/services/local-content-request-handler.js +72 -53
  32. package/dist/services/local-content.d.ts +6 -0
  33. package/dist/services/local-content.js +14 -1
  34. package/dist/services/scoped-credential-service.d.ts +21 -0
  35. package/dist/services/scoped-credential-service.js +53 -0
  36. package/dist/services/workflow-service.d.ts +4 -2
  37. package/dist/testing/service-tests/agent-run-service-tests.d.ts +10 -0
  38. package/dist/testing/service-tests/agent-run-service-tests.js +72 -0
  39. package/dist/testing/service-tests/ai-storage-service-tests.d.ts +3 -0
  40. package/dist/testing/service-tests/ai-storage-service-tests.js +302 -0
  41. package/dist/testing/service-tests/channel-store-tests.d.ts +3 -0
  42. package/dist/testing/service-tests/channel-store-tests.js +72 -0
  43. package/dist/testing/service-tests/credential-service-tests.d.ts +3 -0
  44. package/dist/testing/service-tests/credential-service-tests.js +109 -0
  45. package/dist/testing/service-tests/deployment-service-tests.d.ts +3 -0
  46. package/dist/testing/service-tests/deployment-service-tests.js +21 -0
  47. package/dist/testing/service-tests/event-hub-store-tests.d.ts +3 -0
  48. package/dist/testing/service-tests/event-hub-store-tests.js +34 -0
  49. package/dist/testing/service-tests/secret-service-tests.d.ts +3 -0
  50. package/dist/testing/service-tests/secret-service-tests.js +80 -0
  51. package/dist/testing/service-tests/session-store-tests.d.ts +3 -0
  52. package/dist/testing/service-tests/session-store-tests.js +43 -0
  53. package/dist/testing/service-tests/workflow-run-service-tests.d.ts +3 -0
  54. package/dist/testing/service-tests/workflow-run-service-tests.js +42 -0
  55. package/dist/testing/service-tests/workflow-service-tests.d.ts +3 -0
  56. package/dist/testing/service-tests/workflow-service-tests.js +150 -0
  57. package/dist/testing/service-tests.d.ts +6 -0
  58. package/dist/testing/service-tests.js +26 -791
  59. package/dist/types/core.types.d.ts +11 -3
  60. package/dist/types/state.types.d.ts +14 -1
  61. package/dist/wirings/actor-flow/index.d.ts +1 -1
  62. package/dist/wirings/actor-flow/run-conversation.js +1 -6
  63. package/dist/wirings/ai-agent/agent-rpc.d.ts +15 -0
  64. package/dist/wirings/ai-agent/agent-rpc.js +53 -0
  65. package/dist/wirings/ai-agent/ai-agent-agui.js +1 -5
  66. package/dist/wirings/ai-agent/ai-agent-finalize.d.ts +58 -0
  67. package/dist/wirings/ai-agent/ai-agent-finalize.js +138 -0
  68. package/dist/wirings/ai-agent/ai-agent-interrupt.js +1 -0
  69. package/dist/wirings/ai-agent/ai-agent-memory.d.ts +2 -8
  70. package/dist/wirings/ai-agent/ai-agent-memory.js +37 -18
  71. package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +7 -0
  72. package/dist/wirings/ai-agent/ai-agent-model-config.js +44 -1
  73. package/dist/wirings/ai-agent/ai-agent-prepare.js +5 -9
  74. package/dist/wirings/ai-agent/ai-agent-runner.js +89 -147
  75. package/dist/wirings/ai-agent/ai-agent-stream.js +109 -97
  76. package/dist/wirings/ai-agent/ai-agent-turn.d.ts +57 -0
  77. package/dist/wirings/ai-agent/ai-agent-turn.js +82 -0
  78. package/dist/wirings/ai-agent/ai-agent.types.d.ts +47 -2
  79. package/dist/wirings/ai-agent/index.d.ts +8 -7
  80. package/dist/wirings/ai-agent/index.js +5 -4
  81. package/dist/wirings/ai-agent/voice-input.js +1 -6
  82. package/dist/wirings/ai-agent/voice-output.js +2 -12
  83. package/dist/wirings/ai-scorer/ai-scorer-grade.d.ts +26 -0
  84. package/dist/wirings/ai-scorer/ai-scorer-grade.js +33 -0
  85. package/dist/wirings/ai-scorer/ai-scorer-judge.d.ts +17 -0
  86. package/dist/wirings/ai-scorer/ai-scorer-judge.js +92 -0
  87. package/dist/wirings/ai-scorer/ai-scorer-live.d.ts +15 -0
  88. package/dist/wirings/ai-scorer/ai-scorer-live.js +38 -0
  89. package/dist/wirings/ai-scorer/ai-scorer-registry.d.ts +18 -0
  90. package/dist/wirings/ai-scorer/ai-scorer-registry.js +46 -0
  91. package/dist/wirings/ai-scorer/ai-scorer-sampling.d.ts +8 -0
  92. package/dist/wirings/ai-scorer/ai-scorer-sampling.js +31 -0
  93. package/dist/wirings/ai-scorer/ai-scorer-snapshots.d.ts +10 -0
  94. package/dist/wirings/ai-scorer/ai-scorer-snapshots.js +40 -0
  95. package/dist/wirings/ai-scorer/ai-scorer-worker.d.ts +15 -0
  96. package/dist/wirings/ai-scorer/ai-scorer-worker.js +58 -0
  97. package/dist/wirings/ai-scorer/ai-scorer.d.ts +39 -0
  98. package/dist/wirings/ai-scorer/ai-scorer.js +40 -0
  99. package/dist/wirings/ai-scorer/ai-scorer.types.d.ts +90 -0
  100. package/dist/wirings/ai-scorer/ai-scorer.types.js +4 -0
  101. package/dist/wirings/ai-scorer/index.d.ts +6 -0
  102. package/dist/wirings/ai-scorer/index.js +5 -0
  103. package/dist/wirings/channel/channel-common.js +1 -0
  104. package/dist/wirings/channel/channel-handler.js +3 -5
  105. package/dist/wirings/channel/channel-rpc-service.d.ts +0 -6
  106. package/dist/wirings/channel/channel-rpc-service.js +0 -8
  107. package/dist/wirings/channel/channel-rpc.types.d.ts +6 -0
  108. package/dist/wirings/channel/channel-rpc.types.js +8 -0
  109. package/dist/wirings/channel/channel-runner.d.ts +1 -3
  110. package/dist/wirings/channel/channel-runner.js +16 -8
  111. package/dist/wirings/channel/channel.types.d.ts +2 -0
  112. package/dist/wirings/channel/index.d.ts +5 -6
  113. package/dist/wirings/channel/index.js +3 -4
  114. package/dist/wirings/channel/local/local-channel-runner.js +8 -1
  115. package/dist/wirings/channel/pikku-abstract-channel-handler.js +1 -0
  116. package/dist/wirings/channel/serverless/serverless-channel-runner.js +3 -0
  117. package/dist/wirings/cli/channel/cli-channel-runner.js +2 -0
  118. package/dist/wirings/cli/channel/cli-raw-channel-runner.js +9 -1
  119. package/dist/wirings/cli/channel/index.d.ts +1 -2
  120. package/dist/wirings/cli/channel/index.js +0 -1
  121. package/dist/wirings/cli/cli-runner.js +17 -3
  122. package/dist/wirings/cli/cli.types.d.ts +0 -8
  123. package/dist/wirings/cli/command-parser.js +13 -0
  124. package/dist/wirings/credential/index.d.ts +1 -1
  125. package/dist/wirings/gateway/gateway-runner.js +9 -2
  126. package/dist/wirings/gateway/index.d.ts +1 -1
  127. package/dist/wirings/http/http-routes.js +2 -0
  128. package/dist/wirings/http/http-runner.d.ts +0 -10
  129. package/dist/wirings/http/http-runner.js +14 -15
  130. package/dist/wirings/http/http.types.d.ts +0 -10
  131. package/dist/wirings/http/index.d.ts +2 -3
  132. package/dist/wirings/http/index.js +1 -1
  133. package/dist/wirings/mcp/index.d.ts +1 -1
  134. package/dist/wirings/mcp/mcp-runner.d.ts +15 -7
  135. package/dist/wirings/mcp/mcp-runner.js +18 -11
  136. package/dist/wirings/persona/index.d.ts +3 -4
  137. package/dist/wirings/persona/index.js +2 -3
  138. package/dist/wirings/queue/index.d.ts +1 -3
  139. package/dist/wirings/queue/index.js +1 -3
  140. package/dist/wirings/rpc/addon-runner.d.ts +4 -0
  141. package/dist/wirings/rpc/addon-runner.js +19 -3
  142. package/dist/wirings/rpc/rpc-runner.d.ts +8 -51
  143. package/dist/wirings/rpc/rpc-runner.js +55 -86
  144. package/dist/wirings/rpc/rpc-types.d.ts +7 -0
  145. package/dist/wirings/rpc/wire-addon.d.ts +13 -0
  146. package/dist/wirings/rpc/wire-addon.js +4 -0
  147. package/dist/wirings/scheduler/index.d.ts +1 -1
  148. package/dist/wirings/secret/validate-secret-definitions.js +2 -2
  149. package/dist/wirings/trigger/index.d.ts +1 -1
  150. package/dist/wirings/trigger/pikku-trigger-service.d.ts +0 -4
  151. package/dist/wirings/trigger/trigger-runner.js +1 -0
  152. package/dist/wirings/virtual-user/index.d.ts +5 -6
  153. package/dist/wirings/virtual-user/index.js +2 -4
  154. package/dist/wirings/virtual-user/run-virtual-user.js +11 -11
  155. package/dist/wirings/virtual-user/virtual-user-derive.js +4 -25
  156. package/dist/wirings/virtual-user/virtual-user-dispositions.js +1 -4
  157. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +100 -3
  158. package/dist/wirings/workflow/feature.js +7 -4
  159. package/dist/wirings/workflow/graph/graph-runner.d.ts +1 -2
  160. package/dist/wirings/workflow/graph/graph-runner.js +8 -7
  161. package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +0 -4
  162. package/dist/wirings/workflow/index.d.ts +12 -7
  163. package/dist/wirings/workflow/index.js +7 -3
  164. package/dist/wirings/workflow/pikku-scenario-service.d.ts +17 -3
  165. package/dist/wirings/workflow/pikku-scenario-service.js +64 -10
  166. package/dist/wirings/workflow/pikku-workflow-service.d.ts +28 -147
  167. package/dist/wirings/workflow/pikku-workflow-service.js +85 -493
  168. package/dist/wirings/workflow/scenario-step.types.d.ts +8 -0
  169. package/dist/wirings/workflow/workflow-approval-audit.d.ts +16 -0
  170. package/dist/wirings/workflow/workflow-approval-audit.js +40 -0
  171. package/dist/wirings/workflow/workflow-approval-policy.d.ts +20 -0
  172. package/dist/wirings/workflow/workflow-approval-policy.js +48 -0
  173. package/dist/wirings/workflow/workflow-approval.d.ts +67 -0
  174. package/dist/wirings/workflow/workflow-approval.js +177 -0
  175. package/dist/wirings/workflow/workflow-constants.d.ts +26 -0
  176. package/dist/wirings/workflow/workflow-constants.js +35 -0
  177. package/dist/wirings/workflow/workflow-errors.d.ts +58 -0
  178. package/dist/wirings/workflow/workflow-errors.js +112 -0
  179. package/dist/wirings/workflow/workflow-meta-resolver.d.ts +11 -0
  180. package/dist/wirings/workflow/workflow-meta-resolver.js +31 -0
  181. package/dist/wirings/workflow/workflow-queue-routing.d.ts +8 -0
  182. package/dist/wirings/workflow/workflow-queue-routing.js +38 -0
  183. package/dist/wirings/workflow/workflow-queue-wiring.d.ts +20 -0
  184. package/dist/wirings/workflow/workflow-queue-wiring.js +79 -0
  185. package/dist/wirings/workflow/workflow-recovery.d.ts +68 -0
  186. package/dist/wirings/workflow/workflow-recovery.js +101 -0
  187. package/dist/wirings/workflow/workflow-run-engine.types.d.ts +54 -0
  188. package/dist/wirings/workflow/workflow-run-ownership.d.ts +17 -0
  189. package/dist/wirings/workflow/workflow-run-ownership.js +30 -0
  190. package/dist/wirings/workflow/workflow-suspend.d.ts +12 -0
  191. package/dist/wirings/workflow/workflow-suspend.js +33 -0
  192. package/dist/wirings/workflow/workflow.types.d.ts +8 -1
  193. package/knowledge/decisions/internals/a-non-streaming-agent-run-registers-with-airunstate-too.md +22 -0
  194. package/knowledge/decisions/internals/a-resumed-agent-turn-is-as-interruptible-as-the-first.md +20 -0
  195. package/knowledge/decisions/internals/a-scenario-step-template-is-offered-unfilled.md +21 -0
  196. package/knowledge/decisions/internals/a-virtual-user-decides-whether-to-trust-memory-once-per-turn.md +21 -0
  197. package/knowledge/decisions/internals/a-wall-clock-threshold-is-a-load-test-in-disguise.md +46 -0
  198. package/knowledge/decisions/internals/a-workflow-wire-is-built-from-the-run-not-from-the-rpc-service.md +45 -0
  199. package/knowledge/decisions/internals/addon-pikku-meta-ships-at-the-package-root-or-under-dist.md +32 -0
  200. package/knowledge/decisions/internals/agent-context-waits-for-a-tool-result-still-being-written.md +21 -0
  201. package/knowledge/decisions/internals/agent-speech-travels-as-a-custom-agui-event.md +22 -0
  202. package/knowledge/decisions/internals/an-addon-scope-root-loses-to-a-root-the-host-already-declares.md +39 -0
  203. package/knowledge/decisions/internals/an-agent-interrupt-is-not-a-failure.md +23 -0
  204. package/knowledge/decisions/internals/an-agent-run-owned-by-another-instance-says-so.md +25 -0
  205. package/knowledge/decisions/internals/an-agent-stream-send-must-return-the-inner-sends-promise.md +22 -0
  206. package/knowledge/decisions/internals/an-empty-text-part-is-omitted-from-an-agent-message.md +20 -0
  207. package/knowledge/decisions/internals/an-empty-transcript-is-not-recorded.md +22 -0
  208. package/knowledge/decisions/internals/an-unref-d-timer-cannot-be-awaited-under-node-test.md +66 -0
  209. package/knowledge/decisions/internals/channel-state-accessors-are-unsound-generics-that-every-implementation-asserts.md +33 -0
  210. package/knowledge/decisions/internals/gateway-listener-middleware-runs-without-an-rpc-on-the-wire.md +43 -0
  211. package/knowledge/decisions/internals/hot-reload-writes-into-the-function-map-captured-at-startup.md +26 -0
  212. package/knowledge/decisions/internals/index.md +42 -3
  213. package/knowledge/decisions/internals/only-exposed-functions-enter-a-virtual-user-catalogue.md +21 -0
  214. package/knowledge/decisions/internals/scenario-given-and-when-are-sugar-but-then-is-not.md +24 -0
  215. package/knowledge/decisions/internals/side-effects-are-an-allowlist-not-a-boolean.md +34 -0
  216. package/knowledge/decisions/internals/speech-synthesis-picks-a-voice-per-sentence-and-warns-once.md +24 -0
  217. package/knowledge/decisions/internals/the-actor-prompt-says-json-because-of-json-object-mode.md +22 -0
  218. package/knowledge/decisions/internals/the-agent-done-event-goes-through-the-middleware-and-is-awaited.md +26 -0
  219. package/knowledge/decisions/internals/the-api-report-pins-members-not-just-names.md +43 -0
  220. package/knowledge/decisions/internals/the-ecosystem-entry-point-carries-the-adapter-surface.md +58 -0
  221. package/knowledge/decisions/internals/the-middleware-resolution-cache-is-deliberately-unbounded.md +40 -0
  222. package/knowledge/decisions/internals/the-per-invocation-rpc-view-is-a-class.md +40 -0
  223. package/knowledge/decisions/internals/the-persona-runtime-is-exported-from-the-persona-entry-point.md +28 -0
  224. package/knowledge/decisions/internals/the-transcript-event-is-sent-ahead-of-the-run.md +25 -0
  225. package/knowledge/decisions/internals/the-virtual-user-catalogue-is-the-only-gate-on-what-may-be-called.md +21 -0
  226. package/knowledge/decisions/internals/the-worker-disposition-is-the-one-that-is-not-testing.md +22 -0
  227. package/knowledge/decisions/internals/thread-history-records-the-transcript-not-the-audio.md +25 -0
  228. package/knowledge/decisions/internals/validate-runs-checks-by-precondition.md +115 -0
  229. package/knowledge/decisions/internals/virtual-user-step-order-comes-from-insertion-order.md +21 -0
  230. package/knowledge/decisions/internals/voice-output-speaks-unless-voice-input-explicitly-says-otherwise.md +24 -0
  231. package/knowledge/decisions/internals/wiring-registries-erase-the-generics-their-wire-functions-capture.md +35 -0
  232. package/knowledge/decisions/security/a-dropped-audit-write-is-always-logged.md +4 -2
  233. package/knowledge/decisions/security/a-function-never-receives-the-secret-service.md +37 -0
  234. package/knowledge/decisions/security/a-graph-run-starts-at-an-entry-node-the-graph-declared.md +33 -0
  235. package/knowledge/decisions/security/a-permission-gets-a-wire-it-cannot-reply-on.md +33 -0
  236. package/knowledge/decisions/security/a-step-runs-the-function-the-workflow-dispatched-it-with.md +37 -0
  237. package/knowledge/decisions/security/a-virtual-user-is-never-offered-a-step-that-would-forge-its-own-oracle.md +28 -0
  238. package/knowledge/decisions/security/a-workflow-run-is-read-and-approved-by-its-owner.md +50 -0
  239. package/knowledge/decisions/security/an-agent-approval-is-claimed-before-the-tool-runs.md +33 -0
  240. package/knowledge/decisions/security/an-approval-answer-outlives-the-run-it-answered.md +59 -0
  241. package/knowledge/decisions/security/an-upload-is-counted-as-it-arrives-not-buffered-then-measured.md +24 -0
  242. package/knowledge/decisions/security/index.md +9 -0
  243. package/knowledge/questions/channel-middleware-accepts-bare-factories-that-nothing-resolves.md +35 -0
  244. package/knowledge/questions/index.md +2 -1
  245. package/knowledge/questions/unauthorized-channel-replies-escape-the-declared-out-type.md +44 -0
  246. package/package.json +15 -3
  247. package/scripts/generate-api-report.d.mts +1 -0
  248. package/scripts/generate-api-report.mjs +89 -0
  249. package/scripts/generate-api-report.mts +343 -0
  250. package/src/api-report.test.ts +69 -0
  251. package/src/column-form.ts +1 -4
  252. package/src/crypto-utils.test.ts +15 -2
  253. package/src/dev/hot-reload.ts +2 -7
  254. package/src/ecosystem.ts +40 -0
  255. package/src/errors/error-handler.ts +5 -3
  256. package/src/errors/error.test.ts +4 -1
  257. package/src/errors/index.ts +1 -1
  258. package/src/function/function-runner.test.ts +53 -1
  259. package/src/function/function-runner.ts +33 -48
  260. package/src/function/functions.types.ts +15 -9
  261. package/src/function/index.ts +0 -2
  262. package/src/handle-error.ts +1 -1
  263. package/src/index.ts +3 -57
  264. package/src/middleware/auth-cookie.test.ts +50 -0
  265. package/src/middleware/auth-cookie.ts +38 -2
  266. package/src/middleware/cors.ts +2 -1
  267. package/src/middleware/index.ts +1 -1
  268. package/src/middleware/remote-auth.test.ts +43 -0
  269. package/src/middleware/remote-auth.ts +17 -3
  270. package/src/middleware-runner.ts +4 -2
  271. package/src/no-any-casts.test.ts +57 -0
  272. package/src/permissions.test.ts +3 -1
  273. package/src/permissions.ts +22 -24
  274. package/src/pikku-state.ts +22 -6
  275. package/src/public-surface.json +554 -0
  276. package/src/public-surface.json.README +25 -0
  277. package/src/public-surface.test.ts +105 -0
  278. package/src/removed-legacy-exports.test.ts +62 -0
  279. package/src/schema.test.ts +78 -0
  280. package/src/schema.ts +36 -1
  281. package/src/services/ai-agent-runner-service.ts +12 -1
  282. package/src/services/ai-run-state-service.ts +18 -1
  283. package/src/services/audit-service.ts +2 -2
  284. package/src/services/in-memory-ai-run-state-service.ts +16 -2
  285. package/src/services/in-memory-workflow-service.ts +2 -0
  286. package/src/services/index.ts +4 -47
  287. package/src/services/local-content-request-handler.test.ts +43 -5
  288. package/src/services/local-content-request-handler.ts +103 -74
  289. package/src/services/local-content.ts +15 -1
  290. package/src/services/local-email-service.ts +5 -1
  291. package/src/services/scoped-credential-service.test.ts +86 -0
  292. package/src/services/scoped-credential-service.ts +63 -0
  293. package/src/services/system-role-guard.test.ts +4 -1
  294. package/src/services/workflow-service.ts +9 -2
  295. package/src/side-effects-are-declared.test.ts +84 -0
  296. package/src/source-files-stay-composable.test.ts +41 -0
  297. package/src/testing/service-tests/agent-run-service-tests.ts +98 -0
  298. package/src/testing/service-tests/ai-storage-service-tests.ts +379 -0
  299. package/src/testing/service-tests/channel-store-tests.ts +98 -0
  300. package/src/testing/service-tests/credential-service-tests.ts +143 -0
  301. package/src/testing/service-tests/deployment-service-tests.ts +33 -0
  302. package/src/testing/service-tests/event-hub-store-tests.ts +48 -0
  303. package/src/testing/service-tests/secret-service-tests.ts +105 -0
  304. package/src/testing/service-tests/session-store-tests.ts +62 -0
  305. package/src/testing/service-tests/workflow-run-service-tests.ts +59 -0
  306. package/src/testing/service-tests/workflow-service-tests.ts +308 -0
  307. package/src/testing/service-tests.ts +31 -1111
  308. package/src/types/core.types.ts +14 -3
  309. package/src/types/state.types.ts +17 -1
  310. package/src/wirings/actor-flow/index.ts +0 -3
  311. package/src/wirings/actor-flow/run-conversation.ts +1 -6
  312. package/src/wirings/ai-agent/agent-rpc.ts +120 -0
  313. package/src/wirings/ai-agent/ai-agent-agui.ts +1 -5
  314. package/src/wirings/ai-agent/ai-agent-finalize.test.ts +186 -0
  315. package/src/wirings/ai-agent/ai-agent-finalize.ts +197 -0
  316. package/src/wirings/ai-agent/ai-agent-interrupt.test.ts +2 -1
  317. package/src/wirings/ai-agent/ai-agent-interrupt.ts +1 -0
  318. package/src/wirings/ai-agent/ai-agent-memory.ts +62 -39
  319. package/src/wirings/ai-agent/ai-agent-model-config.test.ts +72 -3
  320. package/src/wirings/ai-agent/ai-agent-model-config.ts +49 -1
  321. package/src/wirings/ai-agent/ai-agent-prepare.ts +12 -12
  322. package/src/wirings/ai-agent/ai-agent-resume-authorization.test.ts +1 -0
  323. package/src/wirings/ai-agent/ai-agent-runner.test.ts +82 -2
  324. package/src/wirings/ai-agent/ai-agent-runner.ts +120 -160
  325. package/src/wirings/ai-agent/ai-agent-stream-output-hooks.test.ts +353 -0
  326. package/src/wirings/ai-agent/ai-agent-stream.test.ts +2 -0
  327. package/src/wirings/ai-agent/ai-agent-stream.ts +152 -117
  328. package/src/wirings/ai-agent/ai-agent-thread-ownership.test.ts +1 -1
  329. package/src/wirings/ai-agent/ai-agent-turn.test.ts +67 -0
  330. package/src/wirings/ai-agent/ai-agent-turn.ts +122 -0
  331. package/src/wirings/ai-agent/ai-agent.types.ts +65 -5
  332. package/src/wirings/ai-agent/index.ts +2 -16
  333. package/src/wirings/ai-agent/voice-input.ts +1 -6
  334. package/src/wirings/ai-agent/voice-output.ts +2 -12
  335. package/src/wirings/ai-scorer/ai-scorer-grade.test.ts +106 -0
  336. package/src/wirings/ai-scorer/ai-scorer-grade.ts +55 -0
  337. package/src/wirings/ai-scorer/ai-scorer-judge.test.ts +143 -0
  338. package/src/wirings/ai-scorer/ai-scorer-judge.ts +120 -0
  339. package/src/wirings/ai-scorer/ai-scorer-live.test.ts +174 -0
  340. package/src/wirings/ai-scorer/ai-scorer-live.ts +56 -0
  341. package/src/wirings/ai-scorer/ai-scorer-registry.ts +63 -0
  342. package/src/wirings/ai-scorer/ai-scorer-sampling.test.ts +34 -0
  343. package/src/wirings/ai-scorer/ai-scorer-sampling.ts +36 -0
  344. package/src/wirings/ai-scorer/ai-scorer-snapshots.test.ts +49 -0
  345. package/src/wirings/ai-scorer/ai-scorer-snapshots.ts +46 -0
  346. package/src/wirings/ai-scorer/ai-scorer-worker.test.ts +122 -0
  347. package/src/wirings/ai-scorer/ai-scorer-worker.ts +69 -0
  348. package/src/wirings/ai-scorer/ai-scorer.ts +76 -0
  349. package/src/wirings/ai-scorer/ai-scorer.types.ts +107 -0
  350. package/src/wirings/ai-scorer/index.ts +24 -0
  351. package/src/wirings/channel/channel-common.ts +5 -2
  352. package/src/wirings/channel/channel-handler-shapes.test.ts +72 -0
  353. package/src/wirings/channel/channel-handler.ts +7 -7
  354. package/src/wirings/channel/channel-rpc-service.ts +0 -14
  355. package/src/wirings/channel/channel-rpc.test.ts +25 -4
  356. package/src/wirings/channel/channel-rpc.types.ts +14 -0
  357. package/src/wirings/channel/channel-runner.ts +33 -20
  358. package/src/wirings/channel/channel.types.ts +2 -0
  359. package/src/wirings/channel/index.ts +1 -20
  360. package/src/wirings/channel/local/local-channel-runner.test.ts +68 -0
  361. package/src/wirings/channel/local/local-channel-runner.ts +9 -2
  362. package/src/wirings/channel/pikku-abstract-channel-handler.ts +2 -1
  363. package/src/wirings/channel/serverless/serverless-channel-runner.ts +6 -3
  364. package/src/wirings/cli/channel/cli-channel-runner.ts +3 -1
  365. package/src/wirings/cli/channel/cli-raw-channel-runner.test.ts +23 -0
  366. package/src/wirings/cli/channel/cli-raw-channel-runner.ts +12 -1
  367. package/src/wirings/cli/channel/cli-raw-client-runner.ts +4 -1
  368. package/src/wirings/cli/channel/index.ts +0 -7
  369. package/src/wirings/cli/cli-runner.test.ts +68 -0
  370. package/src/wirings/cli/cli-runner.ts +25 -5
  371. package/src/wirings/cli/cli.types.ts +0 -39
  372. package/src/wirings/cli/command-parser.test.ts +19 -0
  373. package/src/wirings/cli/command-parser.ts +17 -1
  374. package/src/wirings/credential/index.ts +0 -1
  375. package/src/wirings/gateway/gateway-channel-meta.test.ts +44 -0
  376. package/src/wirings/gateway/gateway-runner.ts +27 -19
  377. package/src/wirings/gateway/index.ts +0 -3
  378. package/src/wirings/http/http-routes.ts +4 -1
  379. package/src/wirings/http/http-runner.test.ts +66 -0
  380. package/src/wirings/http/http-runner.ts +21 -28
  381. package/src/wirings/http/http.types.ts +0 -15
  382. package/src/wirings/http/index.ts +2 -8
  383. package/src/wirings/http/pikku-fetch-http-request.ts +2 -2
  384. package/src/wirings/http/web-request.ts +1 -1
  385. package/src/wirings/mcp/index.ts +0 -1
  386. package/src/wirings/mcp/mcp-runner.test.ts +181 -0
  387. package/src/wirings/mcp/mcp-runner.ts +37 -21
  388. package/src/wirings/persona/index.ts +0 -8
  389. package/src/wirings/persona/persona-environments.test.ts +14 -3
  390. package/src/wirings/persona/persona.test.ts +13 -3
  391. package/src/wirings/persona/validate-personas.ts +5 -1
  392. package/src/wirings/queue/index.ts +0 -14
  393. package/src/wirings/queue/queue-runner.ts +1 -1
  394. package/src/wirings/rpc/addon-auth-tags.test.ts +1 -5
  395. package/src/wirings/rpc/addon-runner.ts +34 -3
  396. package/src/wirings/rpc/addon-secrets.test.ts +261 -0
  397. package/src/wirings/rpc/rpc-runner.test.ts +2 -0
  398. package/src/wirings/rpc/rpc-runner.ts +60 -136
  399. package/src/wirings/rpc/rpc-types.ts +11 -0
  400. package/src/wirings/rpc/wire-addon.ts +20 -1
  401. package/src/wirings/scheduler/index.ts +0 -1
  402. package/src/wirings/secret/validate-secret-definitions.test.ts +22 -0
  403. package/src/wirings/secret/validate-secret-definitions.ts +2 -2
  404. package/src/wirings/trigger/index.ts +0 -1
  405. package/src/wirings/trigger/pikku-trigger-service.ts +0 -5
  406. package/src/wirings/trigger/trigger-runner.ts +7 -5
  407. package/src/wirings/virtual-user/index.ts +0 -16
  408. package/src/wirings/virtual-user/run-virtual-user.test.ts +18 -9
  409. package/src/wirings/virtual-user/run-virtual-user.ts +28 -15
  410. package/src/wirings/virtual-user/virtual-user-agents.test.ts +4 -1
  411. package/src/wirings/virtual-user/virtual-user-derive.ts +4 -25
  412. package/src/wirings/virtual-user/virtual-user-dispositions.test.ts +7 -2
  413. package/src/wirings/virtual-user/virtual-user-dispositions.ts +1 -4
  414. package/src/wirings/virtual-user/virtual-user-intents.test.ts +13 -3
  415. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +117 -4
  416. package/src/wirings/workflow/feature.ts +7 -4
  417. package/src/wirings/workflow/graph/graph-node.ts +1 -1
  418. package/src/wirings/workflow/graph/graph-runner.test.ts +76 -2
  419. package/src/wirings/workflow/graph/graph-runner.ts +13 -16
  420. package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -5
  421. package/src/wirings/workflow/index.ts +14 -24
  422. package/src/wirings/workflow/pikku-scenario-service.ts +101 -27
  423. package/src/wirings/workflow/pikku-workflow-service.test.ts +15 -14
  424. package/src/wirings/workflow/pikku-workflow-service.ts +214 -743
  425. package/src/wirings/workflow/scenario-expectations.test.ts +75 -0
  426. package/src/wirings/workflow/scenario-hooks.test.ts +52 -0
  427. package/src/wirings/workflow/scenario-step.types.ts +8 -0
  428. package/src/wirings/workflow/workflow-approval-audit.ts +47 -0
  429. package/src/wirings/workflow/workflow-approval-policy.test.ts +524 -0
  430. package/src/wirings/workflow/workflow-approval-policy.ts +68 -0
  431. package/src/wirings/workflow/workflow-approval.ts +289 -0
  432. package/src/wirings/workflow/workflow-child-run-session.test.ts +89 -0
  433. package/src/wirings/workflow/workflow-constants.ts +47 -0
  434. package/src/wirings/workflow/workflow-dispatch-durability.test.ts +1 -1
  435. package/src/wirings/workflow/workflow-errors.ts +128 -0
  436. package/src/wirings/workflow/workflow-inline-authority.test.ts +12 -6
  437. package/src/wirings/workflow/workflow-meta-resolver.ts +45 -0
  438. package/src/wirings/workflow/workflow-missing-meta.test.ts +92 -0
  439. package/src/wirings/workflow/workflow-queue-routing.ts +85 -0
  440. package/src/wirings/workflow/workflow-queue-wiring.ts +149 -0
  441. package/src/wirings/workflow/workflow-recovery.ts +162 -0
  442. package/src/wirings/workflow/workflow-retry-policy.test.ts +1 -1
  443. package/src/wirings/workflow/workflow-run-authority.test.ts +212 -0
  444. package/src/wirings/workflow/workflow-run-engine.types.ts +91 -0
  445. package/src/wirings/workflow/workflow-run-ownership.ts +37 -0
  446. package/src/wirings/workflow/workflow-suspend.ts +61 -0
  447. package/src/wirings/workflow/workflow.types.ts +7 -9
  448. package/src/wirings-stay-decoupled.test.ts +127 -0
  449. package/tsconfig.json +1 -1
  450. package/tsconfig.tsbuildinfo +1 -1
  451. package/dist/internal.d.ts +0 -3
  452. package/dist/internal.js +0 -2
  453. package/dist/middleware/timeout.d.ts +0 -9
  454. package/dist/middleware/timeout.js +0 -15
  455. package/dist/pikku-response.d.ts +0 -6
  456. package/dist/pikku-response.js +0 -6
  457. package/dist/services/gopass-secrets.d.ts +0 -15
  458. package/dist/services/gopass-secrets.js +0 -76
  459. package/dist/services/http-scenario-actors.d.ts +0 -75
  460. package/dist/services/http-scenario-actors.js +0 -195
  461. package/dist/services/http-user-flow-actors.d.ts +0 -67
  462. package/dist/services/http-user-flow-actors.js +0 -193
  463. package/dist/services/scenario-actors-service.d.ts +0 -127
  464. package/dist/services/scenario-actors-service.js +0 -40
  465. package/dist/services/user-flow-actors-service.d.ts +0 -39
  466. package/dist/wirings/credential/wire-credential.d.ts +0 -48
  467. package/dist/wirings/credential/wire-credential.js +0 -47
  468. package/dist/wirings/oauth2/oauth2-client.d.ts +0 -47
  469. package/dist/wirings/oauth2/oauth2-client.js +0 -263
  470. package/dist/wirings/oauth2/oauth2-routes.d.ts +0 -35
  471. package/dist/wirings/oauth2/oauth2-routes.js +0 -146
  472. package/dist/wirings/scope/wire-scope.d.ts +0 -33
  473. package/dist/wirings/scope/wire-scope.js +0 -32
  474. package/dist/wirings/workflow/dsl/index.d.ts +0 -5
  475. package/dist/wirings/workflow/dsl/index.js +0 -4
  476. package/dist/wirings/workflow/graph/index.d.ts +0 -5
  477. package/dist/wirings/workflow/graph/index.js +0 -4
  478. package/src/internal.ts +0 -10
  479. /package/dist/{services/user-flow-actors-service.js → wirings/workflow/workflow-run-engine.types.js} +0 -0
@@ -4,7 +4,7 @@ import {
4
4
  combineChannelMiddleware,
5
5
  wrapChannelWithMiddleware,
6
6
  } from '../wirings/channel/channel-middleware-runner.js'
7
- import { runPermissions } from '../permissions.js'
7
+ import { runPermissions, type PermissionWire } from '../permissions.js'
8
8
  import { withoutSecrets } from '../services/secretless.js'
9
9
  import { pikkuState } from '../pikku-state.js'
10
10
  import {
@@ -177,8 +177,6 @@ export const runPikkuFunc = async <In = any, Out = any>(
177
177
 
178
178
  const resolvedFunctionId = funcMeta.pikkuFuncId ?? funcName
179
179
 
180
- const keepsSecrets = funcMeta.secretBroker === true
181
-
182
180
  const resolvedSingletonServices = packageName
183
181
  ? await getOrCreatePackageSingletonServices(
184
182
  packageName,
@@ -248,6 +246,28 @@ export const runPikkuFunc = async <In = any, Out = any>(
248
246
  invocationWire,
249
247
  'rpc'
250
248
  )
249
+
250
+ // knowledge: decisions/internals/core-function-runner-restores-the-wire-fields-it-overwrites.md
251
+ const restoreInvocationWire = () => {
252
+ if (previousRpcDescriptor) {
253
+ Object.defineProperty(invocationWire, 'rpc', previousRpcDescriptor)
254
+ }
255
+ restoreField('functionId', previousFunctionId)
256
+ restoreField('audit', previousAudit)
257
+ restoreField('addonNamespace', previousAddonNamespace)
258
+ }
259
+
260
+ function restoreField<K extends 'functionId' | 'audit' | 'addonNamespace'>(
261
+ key: K,
262
+ previous: PikkuWire[K]
263
+ ) {
264
+ if (previous === undefined) {
265
+ delete invocationWire[key]
266
+ } else {
267
+ invocationWire[key] = previous
268
+ }
269
+ }
270
+
251
271
  invocationWire.functionId = resolvedFunctionId
252
272
  invocationWire.audit = resolvedAuditConfig
253
273
  // Track which addon instance is executing so intra-addon sibling calls
@@ -294,7 +314,7 @@ export const runPikkuFunc = async <In = any, Out = any>(
294
314
  }
295
315
  }
296
316
 
297
- if ((session as any)?.readonly && !funcMeta.readonly) {
317
+ if (session?.readonly && !funcMeta.readonly) {
298
318
  throw new ReadonlySessionError()
299
319
  }
300
320
 
@@ -341,13 +361,12 @@ export const runPikkuFunc = async <In = any, Out = any>(
341
361
 
342
362
  await runPermissions({
343
363
  funcPermissions: funcConfig.permissions,
344
- services: keepsSecrets
345
- ? resolvedSingletonServices
346
- : (withoutSecrets(
347
- resolvedSingletonServices,
348
- 'a permission'
349
- ) as CoreSingletonServices),
350
- wire: invocationWire as any,
364
+ services: withoutSecrets(
365
+ resolvedSingletonServices,
366
+ 'a permission'
367
+ ) as CoreSingletonServices,
368
+ // knowledge: decisions/security/a-permission-gets-a-wire-it-cannot-reply-on.md
369
+ wire: invocationWire as PermissionWire,
351
370
  data: actualData,
352
371
  packageName,
353
372
  })
@@ -397,7 +416,7 @@ export const runPikkuFunc = async <In = any, Out = any>(
397
416
  enumerable: true,
398
417
  })
399
418
  return await funcConfig.func(
400
- keepsSecrets ? services : withoutSecrets(services, 'a pikku function'),
419
+ withoutSecrets(services, 'a pikku function'),
401
420
  actualData,
402
421
  invocationWire
403
422
  )
@@ -435,47 +454,13 @@ export const runPikkuFunc = async <In = any, Out = any>(
435
454
  executeFunction
436
455
  )) as Out
437
456
  } finally {
438
- if (previousRpcDescriptor) {
439
- Object.defineProperty(invocationWire, 'rpc', previousRpcDescriptor)
440
- }
441
- if (previousFunctionId === undefined) {
442
- delete (invocationWire as any).functionId
443
- } else {
444
- invocationWire.functionId = previousFunctionId
445
- }
446
- if (previousAudit === undefined) {
447
- delete (invocationWire as any).audit
448
- } else {
449
- invocationWire.audit = previousAudit
450
- }
451
- if (previousAddonNamespace === undefined) {
452
- delete (invocationWire as any).addonNamespace
453
- } else {
454
- invocationWire.addonNamespace = previousAddonNamespace
455
- }
457
+ restoreInvocationWire()
456
458
  }
457
459
  }
458
460
 
459
461
  try {
460
462
  return (await executeFunction()) as Out
461
463
  } finally {
462
- if (previousRpcDescriptor) {
463
- Object.defineProperty(invocationWire, 'rpc', previousRpcDescriptor)
464
- }
465
- if (previousFunctionId === undefined) {
466
- delete (invocationWire as any).functionId
467
- } else {
468
- invocationWire.functionId = previousFunctionId
469
- }
470
- if (previousAudit === undefined) {
471
- delete (invocationWire as any).audit
472
- } else {
473
- invocationWire.audit = previousAudit
474
- }
475
- if (previousAddonNamespace === undefined) {
476
- delete (invocationWire as any).addonNamespace
477
- } else {
478
- invocationWire.addonNamespace = previousAddonNamespace
479
- }
464
+ restoreInvocationWire()
480
465
  }
481
466
  }
@@ -14,12 +14,6 @@ import type { CoreNodeConfig } from '../wirings/node/node.types.js'
14
14
  import type { ScenarioSurface } from '../wirings/workflow/scenario-step.types.js'
15
15
  import type { Safe } from '../secret-value.js'
16
16
 
17
- /**
18
- * @deprecated Use StandardSchemaV1 from @standard-schema/spec instead.
19
- * This alias exists only for backward compatibility with generated code.
20
- */
21
- export type ZodLike<T = any> = StandardSchemaV1<T, T>
22
-
23
17
  export type CorePikkuFunction<
24
18
  In,
25
19
  Out,
@@ -141,6 +135,14 @@ export type CorePikkuAuthConfig<
141
135
  description?: string
142
136
  }
143
137
 
138
+ /**
139
+ * Marks a permission produced by `pikkuAuth`, so agent tool filtering can tell a
140
+ * session check apart from an ordinary permission.
141
+ *
142
+ * knowledge: decisions/security/permission-auth-filtering-requires-live-permission-functions.md
143
+ */
144
+ export type AuthBranded = { __pikkuAuth?: true }
145
+
144
146
  export const pikkuAuth = <
145
147
  Services extends CoreSecretlessSingletonServices =
146
148
  SecretlessServices<CoreServices>,
@@ -151,13 +153,17 @@ export const pikkuAuth = <
151
153
  | CorePikkuAuthConfig<Services, Session>
152
154
  ): CorePikkuPermission<any, Services, any> => {
153
155
  const fn = typeof auth === 'function' ? auth : auth.func
154
- const wrapper = async (services: Services, _data: any, wire: any) => {
156
+ const wrapper: CorePikkuPermission<any, Services, any> & AuthBranded = async (
157
+ services: Services,
158
+ _data: any,
159
+ wire: any
160
+ ) => {
155
161
  const session = wire.session
156
162
  if (!session) return false
157
163
  return fn(services, session as Session)
158
164
  }
159
- ;(wrapper as any).__pikkuAuth = true
160
- return wrapper as any
165
+ wrapper.__pikkuAuth = true
166
+ return wrapper
161
167
  }
162
168
 
163
169
  export type CorePermissionGroup<PikkuPermission = CorePikkuPermission<any>> =
@@ -18,6 +18,4 @@ export type {
18
18
  ListInput,
19
19
  ListOutput,
20
20
  Filter,
21
- LeafFilter,
22
- LeafValue,
23
21
  } from './list.types.js'
@@ -33,7 +33,7 @@ export const handleHTTPError = (
33
33
  e.message !== 'An error occurred'
34
34
  ? e.message
35
35
  : errorResponse.message,
36
- payload: clientFacing ? (e as any).payload : undefined,
36
+ payload: clientFacing ? (e as { payload?: unknown }).payload : undefined,
37
37
  errorId: traceId,
38
38
  })
39
39
 
package/src/index.ts CHANGED
@@ -17,12 +17,10 @@ export type {
17
17
  CreateConfig,
18
18
  ServerLifecycle,
19
19
  FunctionMeta,
20
- FunctionRuntimeMeta,
21
20
  FunctionServicesMeta,
22
21
  FunctionWiresMeta,
23
22
  FunctionsMeta,
24
23
  FunctionsRuntimeMeta,
25
- JSONPrimitive,
26
24
  JSONValue,
27
25
  MakeRequired,
28
26
  MiddlewareMetadata,
@@ -43,7 +41,6 @@ export type {
43
41
  SecuritySeverity,
44
42
  SecurityUpdateLevel,
45
43
  SerializedError,
46
- WireServices,
47
44
  } from './types/core.types.js'
48
45
  export {
49
46
  pikkuAIMiddleware,
@@ -57,13 +54,11 @@ export type {
57
54
  CorePikkuAuthConfig,
58
55
  CorePikkuFunction,
59
56
  CorePikkuFunctionConfig,
60
- CorePikkuFunctionHook,
61
57
  CorePikkuPermission,
62
58
  CorePikkuPermissionConfig,
63
59
  CorePikkuPermissionFactory,
64
60
  CorePikkuApprovalDescription,
65
61
  CorePermissionGroup,
66
- ZodLike,
67
62
  } from './function/functions.types.js'
68
63
  export {
69
64
  pikkuAuth,
@@ -71,14 +66,13 @@ export {
71
66
  pikkuPermissionFactory,
72
67
  pikkuApprovalDescription,
73
68
  } from './function/functions.types.js'
74
- export { addFunction, getAllFunctionNames } from './function/index.js'
69
+ export { getAllFunctionNames } from './function/index.js'
75
70
  export type {
76
71
  ListInput,
77
72
  ListOutput,
78
73
  Filter,
79
- LeafFilter,
80
- LeafValue,
81
74
  } from './function/list.types.js'
75
+ export { pikkuCLIRender } from './wirings/cli/cli-runner.js'
82
76
  export { PikkuRequest } from './pikku-request.js'
83
77
  export {
84
78
  getRelativeTimeOffsetFromNow,
@@ -90,28 +84,16 @@ export {
90
84
  isVersionedId,
91
85
  parseVersionedId,
92
86
  } from './version.js'
93
- export { runPikkuFunc } from './function/function-runner.js'
94
87
  export {
95
88
  AbandonedError,
96
- beginChanges,
97
- getAbortScope,
98
- runInAbortScope,
99
89
  type AbortScope,
100
90
  } from './function/abort-scope.js'
101
- export { runCLICommand, pikkuCLIRender } from './wirings/cli/cli-runner.js'
102
91
  export { fetch } from './wirings/http/http-runner.js'
103
- export {
104
- runMCPTool,
105
- runMCPResource,
106
- runMCPPrompt,
107
- } from './wirings/mcp/mcp-runner.js'
108
92
  export type {
109
93
  MCPToolResponse,
110
94
  MCPResourceResponse,
111
95
  MCPPromptResponse,
112
96
  } from './wirings/mcp/mcp.types.js'
113
- export { runQueueJob } from './wirings/queue/queue-runner.js'
114
- export { runScheduledTask } from './wirings/scheduler/scheduler-runner.js'
115
97
  export {
116
98
  AIProviderAuthError,
117
99
  AIProviderNotConfiguredError,
@@ -161,7 +143,6 @@ export type { QueueService } from './wirings/queue/queue.types.js'
161
143
  export type { JWTService } from './services/jwt-service.js'
162
144
  export type {
163
145
  EmailService,
164
- EmailTemplateReference,
165
146
  SendEmailInput,
166
147
  SendEmailResult,
167
148
  SendHTMLEmailInput,
@@ -197,8 +178,6 @@ export type { SessionService } from './services/user-session-service.js'
197
178
  export {
198
179
  NoopAuditService,
199
180
  createInvocationAudit,
200
- resolveAuditConfig,
201
- resolveAuditUserIdentityFromWire,
202
181
  } from './services/audit-service.js'
203
182
  export type {
204
183
  AuditConfig,
@@ -207,31 +186,14 @@ export type {
207
186
  AuditEventBatch,
208
187
  AuditFacets,
209
188
  AuditLog,
210
- AuditLogWriteInput,
211
- AuditOutcome,
212
189
  AuditQuery,
213
190
  AuditQueryResult,
214
191
  AuditService,
215
- AuditSource,
216
192
  AuditUserIdentity,
217
193
  ResolvedAuditConfig,
218
194
  } from './services/audit-service.js'
219
195
  export type {
220
196
  AIAgentRunnerService,
221
- AIEmbedManyParams,
222
- AIEmbedManyResult,
223
- AIEmbedParams,
224
- AIEmbedResult,
225
- AIGenerateImageParams,
226
- AIGenerateImagePrompt,
227
- AIGenerateImageResult,
228
- AIGenerateSpeechParams,
229
- AIGenerateSpeechResult,
230
- AIProviderOptions,
231
- AIRerankParams,
232
- AIRerankResult,
233
- AITranscriptionParams,
234
- AITranscriptionResult,
235
197
  } from './services/ai-agent-runner-service.js'
236
198
  export type { AIEmbeddingService } from './services/ai-embedding-service.js'
237
199
  export type { AIRunStateService } from './services/ai-run-state-service.js'
@@ -239,8 +201,6 @@ export type { AIStorageService } from './services/ai-storage-service.js'
239
201
  export type {
240
202
  EmailsMeta,
241
203
  EmailTemplateMeta,
242
- EmailTemplateLocaleMeta,
243
- EmailTemplateAssets,
244
204
  MetaService,
245
205
  } from './services/meta-service.js'
246
206
  export type { HTTPMethod } from './wirings/http/http.types.js'
@@ -254,12 +214,7 @@ export type {
254
214
  RemoteAddonAuth,
255
215
  } from './wirings/rpc/wire-remote-addon.js'
256
216
  export type { PikkuPackageState } from './types/state.types.js'
257
- export {
258
- runMiddleware,
259
- addTagMiddleware,
260
- addTagMiddleware as addMiddleware,
261
- addGlobalMiddleware,
262
- } from './middleware-runner.js'
217
+ export { runMiddleware, addTagMiddleware } from './middleware-runner.js'
263
218
  export { addGlobalPermission, checkAuthPermissions } from './permissions.js'
264
219
  export { hasScopes, verifyScopes } from './scopes.js'
265
220
  export {
@@ -267,11 +222,6 @@ export {
267
222
  stopSingletonServices,
268
223
  pikkuServerLifecycle,
269
224
  } from './utils.js'
270
- export {
271
- getSingletonServices,
272
- getCreateWireServices,
273
- setSingletonServices,
274
- } from './pikku-state.js'
275
225
  export { clearPikkuRuntimeState } from './test-utils.js'
276
226
  export {
277
227
  type ScheduledTaskInfo,
@@ -285,7 +235,6 @@ export type {
285
235
  Secret,
286
236
  Classification,
287
237
  AnonymizeStrategy,
288
- ColumnClassification,
289
238
  ClassificationManifest,
290
239
  ColumnForm,
291
240
  WrappedValue,
@@ -295,9 +244,6 @@ export type {
295
244
 
296
245
  export {
297
246
  hashToken,
298
- unsafeAsWrapped,
299
- unsafeAsSealed,
300
- unsafeAsHashed,
301
247
  } from './column-form.js'
302
248
 
303
249
  export type { SecretValue, Safe } from './secret-value.js'
@@ -131,6 +131,56 @@ describe('authCookie middleware', () => {
131
131
  assert(setCookies[0].options.expires instanceof Date)
132
132
  })
133
133
 
134
+ test('clears the cookie on logout instead of re-minting a credential', async () => {
135
+ const SessionService = new PikkuSessionService<CoreUserSession>()
136
+ let encodeCalled = false
137
+ const jwtService = {
138
+ // A JWT of an absent session still decodes to a truthy {iat,exp} the
139
+ // runner accepts — so encode must never be called on logout.
140
+ encode: async () => {
141
+ encodeCalled = true
142
+ return 'reminted-jwt'
143
+ },
144
+ decode: async () => ({ userId: 'user123' }),
145
+ }
146
+
147
+ const middleware = authCookie({
148
+ name: 'session',
149
+ expiresIn: { value: 30, unit: 'day' },
150
+ options: { httpOnly: true },
151
+ })
152
+
153
+ const mockResponse = createMockHTTPResponse()
154
+
155
+ await middleware(
156
+ { jwt: jwtService, logger: createMockLogger() } as any,
157
+ {
158
+ ...createMiddlewareSessionWireProps(SessionService),
159
+ http: {
160
+ request: createMockHTTPRequest({ session: 'existing-jwt' }),
161
+ response: mockResponse,
162
+ },
163
+ } as any,
164
+ async () => {
165
+ // The logout handler clears the session.
166
+ SessionService.clear()
167
+ }
168
+ )
169
+
170
+ const setCookies = mockResponse.getCookies()
171
+ assert.equal(setCookies.length, 1, 'a clearing cookie must be written')
172
+ const cleared = setCookies[0]!
173
+ assert.equal(cleared.name, 'session')
174
+ assert.equal(cleared.value, '', 'the cookie value must be empty')
175
+ assert.equal(cleared.options.maxAge, 0)
176
+ assert.ok(
177
+ cleared.options.expires instanceof Date &&
178
+ cleared.options.expires.getTime() === 0,
179
+ 'the cookie must expire at the epoch'
180
+ )
181
+ assert.equal(encodeCalled, false, 'must not sign an absent session')
182
+ })
183
+
134
184
  test('should not set cookie when session does not change', async () => {
135
185
  const mockUserSession: CoreUserSession = { userId: 'user789' }
136
186
  const SessionService = new PikkuSessionService<CoreUserSession>()
@@ -7,6 +7,27 @@ import { getRelativeTimeOffsetFromNow } from '../time-utils.js'
7
7
  * Reads a JWT session from a cookie, and re-issues the cookie after the
8
8
  * request whenever the session changed (e.g. after login).
9
9
  */
10
+ /** Standard JWT registered claims — present on a token even with no session. */
11
+ const JWT_REGISTERED_CLAIMS = new Set([
12
+ 'iat',
13
+ 'exp',
14
+ 'nbf',
15
+ 'iss',
16
+ 'aud',
17
+ 'sub',
18
+ 'jti',
19
+ ])
20
+
21
+ /**
22
+ * Whether a decoded payload carries an actual session, as opposed to being
23
+ * absent or a bare JWT envelope of `{ iat, exp }`. True only for a non-null
24
+ * object with at least one key that is not a registered JWT claim.
25
+ */
26
+ const hasSessionIdentity = (session: unknown): boolean => {
27
+ if (!session || typeof session !== 'object') return false
28
+ return Object.keys(session).some((key) => !JWT_REGISTERED_CLAIMS.has(key))
29
+ }
30
+
10
31
  export const authCookie = pikkuMiddlewareFactory<{
11
32
  name: string
12
33
  options: SerializeOptions
@@ -32,7 +53,12 @@ export const authCookie = pikkuMiddlewareFactory<{
32
53
  const cookieValue = http.request.cookie(name)
33
54
  if (cookieValue && jwtService) {
34
55
  const userSession = await jwtService.decode(cookieValue)
35
- if (userSession) {
56
+ // Not just truthy: a JWT of an absent session still decodes to a
57
+ // `{ iat, exp }` object, which is truthy and which the function runner
58
+ // would accept as a session. Require at least one claim that is not a
59
+ // standard JWT timestamp, so an identity-less token is treated as no
60
+ // session rather than as an authenticated one.
61
+ if (userSession && hasSessionIdentity(userSession)) {
36
62
  setSession?.(userSession)
37
63
  }
38
64
  }
@@ -45,7 +71,17 @@ export const authCookie = pikkuMiddlewareFactory<{
45
71
 
46
72
  if (hasSessionChanged?.()) {
47
73
  const currentSession = await getSession?.()
48
- if (jwtService) {
74
+ // Logout path: `clearSession()` marks the session changed while leaving
75
+ // it absent. Re-signing that into a fresh, unexpired cookie would hand
76
+ // the browser a credential on the way out — so clear the cookie instead
77
+ // of minting one, and never call `encode` with an absent session.
78
+ if (!hasSessionIdentity(currentSession)) {
79
+ http.response.cookie(name, '', {
80
+ ...mergedOptions,
81
+ expires: new Date(0),
82
+ maxAge: 0,
83
+ })
84
+ } else if (jwtService) {
49
85
  http.response.cookie(
50
86
  name,
51
87
  await jwtService.encode(expiresIn, currentSession),
@@ -72,7 +72,8 @@ export const cors = pikkuMiddlewareFactory<{
72
72
 
73
73
  if (request.method() === 'options') {
74
74
  response.header('Access-Control-Max-Age', String(maxAge))
75
- response.status(204).json(undefined as any)
75
+ // 204 carries no body, and `json` has no no-content overload.
76
+ response.status(204).json(undefined as never)
76
77
  return
77
78
  }
78
79
 
@@ -10,4 +10,4 @@ export {
10
10
  addGlobalMiddleware,
11
11
  runMiddleware,
12
12
  } from '../middleware-runner.js'
13
- export { addGlobalPermission, addTagPermission } from '../permissions.js'
13
+ export { addGlobalPermission } from '../permissions.js'
@@ -263,6 +263,49 @@ describe('pikkuRemoteAuthMiddleware', () => {
263
263
  )
264
264
  })
265
265
 
266
+ test('enforces the fn binding even when the path prefix varies in case', async () => {
267
+ // The router matches /remote/rpc/ case-insensitively, so /Remote/RPC/
268
+ // reaches the same handler. The fn-binding check must run for it too, or
269
+ // a token scoped to one function invokes any other by varying the case.
270
+ await assert.rejects(
271
+ () =>
272
+ pikkuRemoteAuthMiddleware(
273
+ {
274
+ secrets: createMockSecrets(TEST_SECRET),
275
+ jwt: createMockJWT({ aud: 'pikku-remote', fn: 'allowedFunc' }),
276
+ } as any,
277
+ {
278
+ http: {
279
+ request: createMockRequest(
280
+ { authorization: 'Bearer valid-token' },
281
+ '/Remote/RPC/otherFunc'
282
+ ),
283
+ },
284
+ } as any,
285
+ async () => {}
286
+ ),
287
+ (err: any) => err instanceof UnauthorizedError
288
+ )
289
+ })
290
+
291
+ test('requires authorization for a case-varied remote path when no secret is set', async () => {
292
+ // The no-secret branch must also treat /REMOTE/RPC/ as remote, or a
293
+ // misconfigured mesh silently serves it unauthenticated.
294
+ await assert.rejects(
295
+ () =>
296
+ pikkuRemoteAuthMiddleware(
297
+ { secrets: createMockSecrets(undefined) } as any,
298
+ {
299
+ http: {
300
+ request: createMockRequest({}, '/REMOTE/RPC/anyFunc'),
301
+ },
302
+ } as any,
303
+ async () => {}
304
+ ),
305
+ (err: any) => err instanceof UnauthorizedError
306
+ )
307
+ })
308
+
266
309
  test('should allow when token fn matches requested function', async () => {
267
310
  let nextCalled = false
268
311
  await pikkuRemoteAuthMiddleware(
@@ -6,6 +6,18 @@ import {
6
6
  REMOTE_SESSION_INFO,
7
7
  } from '../crypto-utils.js'
8
8
 
9
+ const REMOTE_RPC_PREFIX = '/remote/rpc/'
10
+
11
+ /**
12
+ * Whether this request targets the remote-RPC surface. Compared case-insensitively
13
+ * because the router matches routes that way (path-to-regexp defaults to
14
+ * `sensitive: false`), so `/Remote/RPC/fn` reaches the same handler as
15
+ * `/remote/rpc/fn`. A case-sensitive check here let a case-varied path slip
16
+ * past the trust gate and the token's `fn` binding while still being dispatched.
17
+ */
18
+ const isRemoteRpcPath = (path: string): boolean =>
19
+ path.toLowerCase().startsWith(REMOTE_RPC_PREFIX)
20
+
9
21
  export const pikkuRemoteAuthMiddleware = pikkuMiddleware(
10
22
  async ({ secrets, jwt }, { http, setSession }, next) => {
11
23
  if (!http?.request || !secrets) {
@@ -16,7 +28,7 @@ export const pikkuRemoteAuthMiddleware = pikkuMiddleware(
16
28
  try {
17
29
  secret = (await secrets.getSecret('PIKKU_REMOTE_SECRET')).reveal()
18
30
  } catch {
19
- if (http.request.path().startsWith('/remote/rpc/')) {
31
+ if (isRemoteRpcPath(http.request.path())) {
20
32
  throw new UnauthorizedError()
21
33
  }
22
34
  return next()
@@ -51,9 +63,11 @@ export const pikkuRemoteAuthMiddleware = pikkuMiddleware(
51
63
  throw new UnauthorizedError()
52
64
  }
53
65
 
54
- if (payload?.fn && http.request.path().startsWith('/remote/rpc/')) {
66
+ if (payload?.fn && isRemoteRpcPath(http.request.path())) {
67
+ // The prefix length is the same in any case, so slicing the raw path
68
+ // keeps the requested function name in its original case for the compare.
55
69
  const fn = decodeURIComponent(
56
- http.request.path().slice('/remote/rpc/'.length)
70
+ http.request.path().slice(REMOTE_RPC_PREFIX.length)
57
71
  )
58
72
  if (fn && payload.fn !== fn) {
59
73
  throw new UnauthorizedError()
@@ -47,8 +47,10 @@ export const runMiddleware = async <
47
47
  let result: any
48
48
  const dispatch = async (index: number): Promise<any> => {
49
49
  if (sorted && index < sorted.length) {
50
- return await sorted[index]!(services as any, wire, () =>
51
- dispatch(index + 1)
50
+ return await sorted[index]!(
51
+ services as Parameters<Middleware>[0],
52
+ wire,
53
+ () => dispatch(index + 1)
52
54
  )
53
55
  } else if (main) {
54
56
  result = await main()
@@ -0,0 +1,57 @@
1
+ import { describe, test } from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+ import { readFileSync, readdirSync } from 'node:fs'
4
+ import { fileURLToPath } from 'node:url'
5
+ import { join, dirname, relative } from 'node:path'
6
+
7
+ const srcRoot = dirname(fileURLToPath(import.meta.url))
8
+ const thisFile = fileURLToPath(import.meta.url)
9
+
10
+ /**
11
+ * `as any` in a cast position. The word boundary and the following delimiter
12
+ * keep prose such as "as any URL a browser can load" out of the match.
13
+ */
14
+ const AS_ANY = /\bas any\b(?!\s+[A-Za-z])/
15
+
16
+ const collectSourceFiles = (directory: string): string[] =>
17
+ readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
18
+ const entryPath = join(directory, entry.name)
19
+ if (entry.isDirectory()) {
20
+ return entry.name === 'dist' ? [] : collectSourceFiles(entryPath)
21
+ }
22
+ return entry.name.endsWith('.ts') && !entry.name.endsWith('.test.ts')
23
+ ? [entryPath]
24
+ : []
25
+ })
26
+
27
+ describe('core asserts to named types, never to any', () => {
28
+ test('no non-test module casts through `as any`', () => {
29
+ const offenders = collectSourceFiles(srcRoot)
30
+ .filter((file) => file !== thisFile)
31
+ .flatMap((file) =>
32
+ readFileSync(file, 'utf-8')
33
+ .split('\n')
34
+ .flatMap((line, index) =>
35
+ AS_ANY.test(line)
36
+ ? [`${relative(srcRoot, file)}:${index + 1} ${line.trim()}`]
37
+ : []
38
+ )
39
+ )
40
+
41
+ assert.deepEqual(
42
+ offenders,
43
+ [],
44
+ '`as any` discards the target type, so a wrong value passes as readily as ' +
45
+ 'a right one. Assert to the type actually wanted — and if the narrowing ' +
46
+ 'cannot be expressed, say why in a knowledge note and point at it:\n' +
47
+ offenders.join('\n')
48
+ )
49
+ })
50
+
51
+ test('the matcher finds a cast and ignores the prose that reads like one', () => {
52
+ // Guards the test above: a regex that matched nothing would pass forever.
53
+ assert.equal(AS_ANY.test('const x = y as any'), true)
54
+ assert.equal(AS_ANY.test('foo(bar as any)'), true)
55
+ assert.equal(AS_ANY.test('a picture, as any URL a browser can load'), false)
56
+ })
57
+ })