@pikku/core 0.12.106 → 0.12.111

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 (589) hide show
  1. package/CHANGELOG.md +358 -0
  2. package/dist/analytics/analytics.d.ts +6 -0
  3. package/dist/analytics/analytics.js +58 -0
  4. package/dist/analytics/analytics.types.d.ts +156 -0
  5. package/dist/analytics/analytics.types.js +1 -0
  6. package/dist/analytics/anonymous-analytics-identity.d.ts +23 -0
  7. package/dist/analytics/anonymous-analytics-identity.js +27 -0
  8. package/dist/analytics/compose-analytics-identity.d.ts +14 -0
  9. package/dist/analytics/compose-analytics-identity.js +33 -0
  10. package/dist/analytics/cookie-analytics-identity.d.ts +24 -0
  11. package/dist/analytics/cookie-analytics-identity.js +37 -0
  12. package/dist/analytics/define-analytics-events.d.ts +22 -0
  13. package/dist/analytics/define-analytics-events.js +9 -0
  14. package/dist/analytics/fan-out-analytics.d.ts +15 -0
  15. package/dist/analytics/fan-out-analytics.js +36 -0
  16. package/dist/analytics/index.d.ts +13 -0
  17. package/dist/analytics/index.js +8 -0
  18. package/dist/analytics/logger-analytics-service.d.ts +14 -0
  19. package/dist/analytics/logger-analytics-service.js +23 -0
  20. package/dist/analytics/mint-cookie.d.ts +44 -0
  21. package/dist/analytics/mint-cookie.js +55 -0
  22. package/dist/errors/errors.d.ts +7 -0
  23. package/dist/errors/errors.js +17 -0
  24. package/dist/function/function-meta.types.d.ts +2 -0
  25. package/dist/function/function-runner.js +29 -0
  26. package/dist/function/functions.types.d.ts +22 -3
  27. package/dist/middleware/auth-apikey.d.ts +1 -1
  28. package/dist/pikku-state.d.ts +1 -1
  29. package/dist/scopes.d.ts +11 -0
  30. package/dist/scopes.js +17 -0
  31. package/dist/services/credential-wire-service.d.ts +1 -1
  32. package/dist/services/feature-flag-service.d.ts +100 -0
  33. package/dist/services/feature-flag-service.js +1 -0
  34. package/dist/services/index.d.ts +1 -0
  35. package/dist/services/meta-service.d.ts +16 -0
  36. package/dist/services/meta-service.js +19 -0
  37. package/dist/services/webhook-service.d.ts +7 -2
  38. package/dist/services/webhook-service.js +11 -6
  39. package/dist/testing/service-tests/agent-run-service-tests.d.ts +2 -2
  40. package/dist/testing/service-tests/agent-storage-service-tests.d.ts +1 -1
  41. package/dist/testing/service-tests/channel-store-tests.d.ts +1 -1
  42. package/dist/testing/service-tests/credential-service-tests.d.ts +1 -1
  43. package/dist/testing/service-tests/deployment-service-tests.d.ts +1 -1
  44. package/dist/testing/service-tests/event-hub-store-tests.d.ts +1 -1
  45. package/dist/testing/service-tests/secret-service-tests.d.ts +1 -1
  46. package/dist/testing/service-tests/session-store-tests.d.ts +1 -1
  47. package/dist/testing/service-tests/workflow-run-service-tests.d.ts +1 -1
  48. package/dist/testing/service-tests/workflow-service-tests.d.ts +1 -1
  49. package/dist/types/core.types.d.ts +23 -0
  50. package/dist/wirings/agent/agent-rpc.d.ts +1 -1
  51. package/dist/wirings/agent/agent-turn.d.ts +1 -1
  52. package/dist/wirings/agent-scorer/agent-scorer-live.d.ts +1 -1
  53. package/dist/wirings/channel/channel-common.d.ts +1 -1
  54. package/dist/wirings/channel/channel-rpc-validators.d.ts +2 -2
  55. package/dist/wirings/channel/channel-runner.d.ts +1 -1
  56. package/dist/wirings/channel/local/local-channel-runner.d.ts +1 -1
  57. package/dist/wirings/channel/serverless/serverless-channel-runner.d.ts +1 -1
  58. package/dist/wirings/cli/channel/cli-approval.d.ts +2 -2
  59. package/dist/wirings/flag/assert-feature-available.d.ts +15 -0
  60. package/dist/wirings/flag/assert-feature-available.js +23 -0
  61. package/dist/wirings/flag/cached-flag-source.d.ts +73 -0
  62. package/dist/wirings/flag/cached-flag-source.js +96 -0
  63. package/dist/wirings/flag/define-feature-flags.d.ts +33 -0
  64. package/dist/wirings/flag/define-feature-flags.js +32 -0
  65. package/dist/wirings/flag/flag.types.d.ts +97 -0
  66. package/dist/wirings/flag/flag.types.js +1 -0
  67. package/dist/wirings/flag/index.d.ts +7 -0
  68. package/dist/wirings/flag/index.js +5 -0
  69. package/dist/wirings/flag/resolve-flag.d.ts +52 -0
  70. package/dist/wirings/flag/resolve-flag.js +90 -0
  71. package/dist/wirings/flag/validate-flag-definitions.d.ts +26 -0
  72. package/dist/wirings/flag/validate-flag-definitions.js +103 -0
  73. package/dist/wirings/rpc/rpc-runner.js +3 -0
  74. package/dist/wirings/virtual-user/virtual-user-scaffold.d.ts +8 -8
  75. package/dist/wirings/virtual-user/virtual-user-schedule.d.ts +1 -1
  76. package/dist/wirings/workflow/workflow-queue-routing.d.ts +1 -1
  77. package/package.json +11 -5
  78. package/run-tests.sh +17 -9
  79. package/src/public-surface.json +26 -0
  80. package/src/agent-naming.test.ts +0 -68
  81. package/src/api-report.test.ts +0 -138
  82. package/src/app-alias-surface.test.ts +0 -179
  83. package/src/app-leaf-surface.test.ts +0 -222
  84. package/src/bootstrap-compat/root.ts +0 -20
  85. package/src/classification/column-form.test.ts +0 -97
  86. package/src/classification/column-form.ts +0 -55
  87. package/src/classification/data-classification.ts +0 -73
  88. package/src/classification/index.ts +0 -40
  89. package/src/classification/key-ids.ts +0 -2
  90. package/src/classification/secret-value.test.ts +0 -204
  91. package/src/classification/secret-value.ts +0 -106
  92. package/src/crypto-utils.test.ts +0 -668
  93. package/src/crypto-utils.ts +0 -460
  94. package/src/dev/hot-reload.test.ts +0 -587
  95. package/src/dev/hot-reload.ts +0 -225
  96. package/src/dev/module-runner.test.ts +0 -235
  97. package/src/dev/module-runner.ts +0 -138
  98. package/src/dev/reload-meta.test.ts +0 -183
  99. package/src/dev/reload-meta.ts +0 -144
  100. package/src/ecosystem-tier-removed.test.ts +0 -72
  101. package/src/env.ts +0 -1
  102. package/src/errors/error-handler.ts +0 -77
  103. package/src/errors/error.test.ts +0 -229
  104. package/src/errors/errors.ts +0 -393
  105. package/src/errors/index.ts +0 -11
  106. package/src/errors/serialized-error.ts +0 -12
  107. package/src/factory-functions.test.ts +0 -111
  108. package/src/function/abort-scope.test.ts +0 -97
  109. package/src/function/abort-scope.ts +0 -80
  110. package/src/function/function-meta.types.ts +0 -151
  111. package/src/function/function-runner.test.ts +0 -1619
  112. package/src/function/function-runner.ts +0 -499
  113. package/src/function/functions.types.ts +0 -319
  114. package/src/function/index.ts +0 -40
  115. package/src/function/list.types.test.ts +0 -100
  116. package/src/function/list.types.ts +0 -69
  117. package/src/function/pikku-request.test.ts +0 -35
  118. package/src/function/pikku-request.ts +0 -17
  119. package/src/gopass-secrets-removed.test.ts +0 -51
  120. package/src/handle-error.test.ts +0 -532
  121. package/src/handle-error.ts +0 -64
  122. package/src/middleware/auth-apikey.test.ts +0 -362
  123. package/src/middleware/auth-apikey.ts +0 -39
  124. package/src/middleware/auth-bearer.test.ts +0 -566
  125. package/src/middleware/auth-bearer.ts +0 -83
  126. package/src/middleware/auth-cookie.test.ts +0 -572
  127. package/src/middleware/auth-cookie.ts +0 -107
  128. package/src/middleware/cors.test.ts +0 -579
  129. package/src/middleware/cors.ts +0 -103
  130. package/src/middleware/index.ts +0 -30
  131. package/src/middleware/middleware-factories.ts +0 -76
  132. package/src/middleware/middleware.types.ts +0 -61
  133. package/src/middleware/remote-auth.test.ts +0 -547
  134. package/src/middleware/remote-auth.ts +0 -95
  135. package/src/middleware/remote-jobs-secret.ts +0 -35
  136. package/src/middleware/require-origin.test.ts +0 -115
  137. package/src/middleware/require-origin.ts +0 -79
  138. package/src/middleware/telemetry.ts +0 -83
  139. package/src/middleware-runner.test.ts +0 -578
  140. package/src/middleware-runner.ts +0 -232
  141. package/src/no-any-casts.test.ts +0 -57
  142. package/src/no-root-barrel.test.ts +0 -122
  143. package/src/permissions.test.ts +0 -256
  144. package/src/permissions.ts +0 -217
  145. package/src/pikku-state.test.ts +0 -198
  146. package/src/pikku-state.ts +0 -206
  147. package/src/production-barrels-stay-lean.test.ts +0 -110
  148. package/src/public-surface.test.ts +0 -133
  149. package/src/remote.test.ts +0 -173
  150. package/src/remote.ts +0 -56
  151. package/src/removed-legacy-exports.test.ts +0 -66
  152. package/src/run-tests-script.test.ts +0 -67
  153. package/src/schema.test.ts +0 -430
  154. package/src/schema.ts +0 -204
  155. package/src/scopes.test.ts +0 -203
  156. package/src/scopes.ts +0 -67
  157. package/src/services/agent-run-state-service.ts +0 -37
  158. package/src/services/agent-runner-service.ts +0 -238
  159. package/src/services/agent-storage-service.ts +0 -39
  160. package/src/services/ai-embedding-service.ts +0 -9
  161. package/src/services/audit-service.test.ts +0 -44
  162. package/src/services/audit-service.ts +0 -280
  163. package/src/services/content-service.ts +0 -65
  164. package/src/services/credential-service.ts +0 -20
  165. package/src/services/credential-wire-service.test.ts +0 -235
  166. package/src/services/credential-wire-service.ts +0 -120
  167. package/src/services/deployment-service.ts +0 -32
  168. package/src/services/email-service.test.ts +0 -100
  169. package/src/services/email-service.ts +0 -60
  170. package/src/services/email-template.test.ts +0 -311
  171. package/src/services/email-template.ts +0 -254
  172. package/src/services/file-scenario-run-store.test.ts +0 -349
  173. package/src/services/file-scenario-run-store.ts +0 -282
  174. package/src/services/gateway-service.ts +0 -5
  175. package/src/services/http-personas-converse.test.ts +0 -274
  176. package/src/services/http-personas.test.ts +0 -379
  177. package/src/services/http-personas.ts +0 -508
  178. package/src/services/in-memory-agent-run-state-service.ts +0 -87
  179. package/src/services/in-memory-queue-service.test.ts +0 -162
  180. package/src/services/in-memory-queue-service.ts +0 -78
  181. package/src/services/in-memory-session-store.test.ts +0 -58
  182. package/src/services/in-memory-session-store.ts +0 -20
  183. package/src/services/in-memory-trigger-service.ts +0 -47
  184. package/src/services/in-memory-workflow-service.test.ts +0 -430
  185. package/src/services/in-memory-workflow-service.ts +0 -595
  186. package/src/services/index.ts +0 -192
  187. package/src/services/istanbul-coverage-service.test.ts +0 -66
  188. package/src/services/istanbul-coverage-service.ts +0 -59
  189. package/src/services/jwt-service.ts +0 -15
  190. package/src/services/local-content-request-handler.test.ts +0 -240
  191. package/src/services/local-content-request-handler.ts +0 -295
  192. package/src/services/local-content.test.ts +0 -186
  193. package/src/services/local-content.ts +0 -242
  194. package/src/services/local-credential-service.ts +0 -63
  195. package/src/services/local-email-service.test.ts +0 -182
  196. package/src/services/local-email-service.ts +0 -43
  197. package/src/services/local-gateway-service.ts +0 -51
  198. package/src/services/local-secrets.test.ts +0 -95
  199. package/src/services/local-secrets.ts +0 -71
  200. package/src/services/local-variables.test.ts +0 -61
  201. package/src/services/local-variables.ts +0 -45
  202. package/src/services/logger-console.test.ts +0 -117
  203. package/src/services/logger-console.ts +0 -174
  204. package/src/services/logger.ts +0 -48
  205. package/src/services/meta-service.test.ts +0 -75
  206. package/src/services/meta-service.ts +0 -767
  207. package/src/services/persona-actor-secret.test.ts +0 -68
  208. package/src/services/persona-actor-secret.ts +0 -70
  209. package/src/services/persona-sign-in.test.ts +0 -219
  210. package/src/services/persona-sign-in.ts +0 -238
  211. package/src/services/personas-service.ts +0 -191
  212. package/src/services/pikku-user-id.test.ts +0 -62
  213. package/src/services/pikku-user-id.ts +0 -13
  214. package/src/services/queue-webhook-service.test.ts +0 -409
  215. package/src/services/queue-webhook-service.ts +0 -150
  216. package/src/services/remote-jobs.test.ts +0 -106
  217. package/src/services/remote-jobs.ts +0 -92
  218. package/src/services/scheduler-service.ts +0 -37
  219. package/src/services/schema-service.ts +0 -10
  220. package/src/services/scope-service.ts +0 -91
  221. package/src/services/scoped-credential-service.test.ts +0 -86
  222. package/src/services/scoped-credential-service.ts +0 -63
  223. package/src/services/scoped-secret-service.test.ts +0 -93
  224. package/src/services/scoped-secret-service.ts +0 -40
  225. package/src/services/secret-host-binding.test.ts +0 -138
  226. package/src/services/secret-host-binding.ts +0 -51
  227. package/src/services/secret-service.ts +0 -25
  228. package/src/services/secretless.test.ts +0 -54
  229. package/src/services/secretless.ts +0 -29
  230. package/src/services/session-store.ts +0 -9
  231. package/src/services/stub-tracker.test.ts +0 -104
  232. package/src/services/stub-tracker.ts +0 -175
  233. package/src/services/system-role-guard.test.ts +0 -96
  234. package/src/services/system-role-guard.ts +0 -71
  235. package/src/services/temporary-file-service.ts +0 -76
  236. package/src/services/trigger-service.ts +0 -5
  237. package/src/services/typed-credential-service.ts +0 -83
  238. package/src/services/typed-secret-service.test.ts +0 -204
  239. package/src/services/typed-secret-service.ts +0 -132
  240. package/src/services/typed-variables-service.test.ts +0 -166
  241. package/src/services/typed-variables-service.ts +0 -166
  242. package/src/services/user-session-service.test.ts +0 -147
  243. package/src/services/user-session-service.ts +0 -85
  244. package/src/services/v8-coverage-service.test.ts +0 -69
  245. package/src/services/v8-coverage-service.ts +0 -163
  246. package/src/services/variables-service.ts +0 -13
  247. package/src/services/webhook-service.ts +0 -147
  248. package/src/services/workflow-service.ts +0 -120
  249. package/src/side-effects-are-declared.test.ts +0 -84
  250. package/src/source-files-stay-composable.test.ts +0 -41
  251. package/src/template-alias-surface.test.ts +0 -240
  252. package/src/test-utils.ts +0 -38
  253. package/src/testing/index.ts +0 -3
  254. package/src/testing/service-tests/agent-run-service-tests.ts +0 -98
  255. package/src/testing/service-tests/agent-storage-service-tests.ts +0 -379
  256. package/src/testing/service-tests/channel-store-tests.ts +0 -98
  257. package/src/testing/service-tests/credential-service-tests.ts +0 -143
  258. package/src/testing/service-tests/deployment-service-tests.ts +0 -33
  259. package/src/testing/service-tests/event-hub-store-tests.ts +0 -48
  260. package/src/testing/service-tests/secret-service-tests.ts +0 -105
  261. package/src/testing/service-tests/session-store-tests.ts +0 -62
  262. package/src/testing/service-tests/workflow-run-service-tests.ts +0 -59
  263. package/src/testing/service-tests/workflow-service-tests.ts +0 -308
  264. package/src/testing/service-tests.ts +0 -95
  265. package/src/time-utils.test.ts +0 -56
  266. package/src/time-utils.ts +0 -89
  267. package/src/types/core.types.ts +0 -446
  268. package/src/types/index.ts +0 -25
  269. package/src/types/state.types.ts +0 -226
  270. package/src/types/typed-credentials.test.ts +0 -72
  271. package/src/utils/hash.test.ts +0 -68
  272. package/src/utils/hash.ts +0 -26
  273. package/src/utils/hmac.ts +0 -21
  274. package/src/utils/node-host-resolver.ts +0 -20
  275. package/src/utils/safe-fetch.test.ts +0 -515
  276. package/src/utils/safe-fetch.ts +0 -347
  277. package/src/utils.test.ts +0 -359
  278. package/src/utils.ts +0 -165
  279. package/src/version.test.ts +0 -80
  280. package/src/version.ts +0 -25
  281. package/src/wirings/actor-flow/actor-flow.types.ts +0 -40
  282. package/src/wirings/actor-flow/index.ts +0 -10
  283. package/src/wirings/actor-flow/run-conversation.test.ts +0 -187
  284. package/src/wirings/actor-flow/run-conversation.ts +0 -280
  285. package/src/wirings/addon/addon-auth-tags.test.ts +0 -219
  286. package/src/wirings/addon/addon-runner.ts +0 -236
  287. package/src/wirings/addon/addon-scopes.test.ts +0 -225
  288. package/src/wirings/addon/addon-secrets.test.ts +0 -391
  289. package/src/wirings/addon/index.ts +0 -12
  290. package/src/wirings/addon/remote-addon-auth.ts +0 -65
  291. package/src/wirings/addon/wire-addon.test.ts +0 -102
  292. package/src/wirings/addon/wire-addon.ts +0 -202
  293. package/src/wirings/addon/wire-remote-addon.ts +0 -41
  294. package/src/wirings/agent/agent-agui.test.ts +0 -1213
  295. package/src/wirings/agent/agent-agui.ts +0 -405
  296. package/src/wirings/agent/agent-authorization.test.ts +0 -208
  297. package/src/wirings/agent/agent-finalize.test.ts +0 -187
  298. package/src/wirings/agent/agent-finalize.ts +0 -197
  299. package/src/wirings/agent/agent-helpers.test.ts +0 -215
  300. package/src/wirings/agent/agent-helpers.ts +0 -96
  301. package/src/wirings/agent/agent-interrupt.test.ts +0 -833
  302. package/src/wirings/agent/agent-interrupt.ts +0 -400
  303. package/src/wirings/agent/agent-memory.test.ts +0 -397
  304. package/src/wirings/agent/agent-memory.ts +0 -496
  305. package/src/wirings/agent/agent-middleware.types.test.ts +0 -41
  306. package/src/wirings/agent/agent-model-config.test.ts +0 -103
  307. package/src/wirings/agent/agent-model-config.ts +0 -59
  308. package/src/wirings/agent/agent-prepare.test.ts +0 -977
  309. package/src/wirings/agent/agent-prepare.ts +0 -1083
  310. package/src/wirings/agent/agent-registry.test.ts +0 -455
  311. package/src/wirings/agent/agent-registry.ts +0 -99
  312. package/src/wirings/agent/agent-resume-authorization.test.ts +0 -206
  313. package/src/wirings/agent/agent-rpc.ts +0 -116
  314. package/src/wirings/agent/agent-runner.test.ts +0 -1229
  315. package/src/wirings/agent/agent-runner.ts +0 -858
  316. package/src/wirings/agent/agent-stream-delegate.test.ts +0 -381
  317. package/src/wirings/agent/agent-stream-output-hooks.test.ts +0 -353
  318. package/src/wirings/agent/agent-stream.test.ts +0 -1800
  319. package/src/wirings/agent/agent-stream.ts +0 -1639
  320. package/src/wirings/agent/agent-thread-ownership.test.ts +0 -297
  321. package/src/wirings/agent/agent-turn.test.ts +0 -65
  322. package/src/wirings/agent/agent-turn.ts +0 -122
  323. package/src/wirings/agent/agent-utils.ts +0 -20
  324. package/src/wirings/agent/agent.types.ts +0 -676
  325. package/src/wirings/agent/index.ts +0 -58
  326. package/src/wirings/agent/voice-input.test.ts +0 -220
  327. package/src/wirings/agent/voice-input.ts +0 -180
  328. package/src/wirings/agent/voice-output.test.ts +0 -510
  329. package/src/wirings/agent/voice-output.ts +0 -311
  330. package/src/wirings/agent-scorer/agent-scorer-grade.test.ts +0 -106
  331. package/src/wirings/agent-scorer/agent-scorer-grade.ts +0 -55
  332. package/src/wirings/agent-scorer/agent-scorer-judge.test.ts +0 -285
  333. package/src/wirings/agent-scorer/agent-scorer-judge.ts +0 -180
  334. package/src/wirings/agent-scorer/agent-scorer-live.test.ts +0 -174
  335. package/src/wirings/agent-scorer/agent-scorer-live.ts +0 -56
  336. package/src/wirings/agent-scorer/agent-scorer-registry.ts +0 -66
  337. package/src/wirings/agent-scorer/agent-scorer-sampling.test.ts +0 -34
  338. package/src/wirings/agent-scorer/agent-scorer-sampling.ts +0 -36
  339. package/src/wirings/agent-scorer/agent-scorer-snapshots.test.ts +0 -49
  340. package/src/wirings/agent-scorer/agent-scorer-snapshots.ts +0 -46
  341. package/src/wirings/agent-scorer/agent-scorer-worker.test.ts +0 -122
  342. package/src/wirings/agent-scorer/agent-scorer-worker.ts +0 -71
  343. package/src/wirings/agent-scorer/agent-scorer.ts +0 -102
  344. package/src/wirings/agent-scorer/agent-scorer.types.ts +0 -128
  345. package/src/wirings/agent-scorer/index.ts +0 -23
  346. package/src/wirings/channel/channel-common.ts +0 -102
  347. package/src/wirings/channel/channel-handler-shapes.test.ts +0 -72
  348. package/src/wirings/channel/channel-handler.test.ts +0 -322
  349. package/src/wirings/channel/channel-handler.ts +0 -259
  350. package/src/wirings/channel/channel-host-rpc.test.ts +0 -150
  351. package/src/wirings/channel/channel-host-rpc.ts +0 -69
  352. package/src/wirings/channel/channel-middleware-runner.test.ts +0 -188
  353. package/src/wirings/channel/channel-middleware-runner.ts +0 -126
  354. package/src/wirings/channel/channel-rpc-registry.ts +0 -116
  355. package/src/wirings/channel/channel-rpc-responder.ts +0 -117
  356. package/src/wirings/channel/channel-rpc-service.ts +0 -132
  357. package/src/wirings/channel/channel-rpc-validators.ts +0 -65
  358. package/src/wirings/channel/channel-rpc.test.ts +0 -841
  359. package/src/wirings/channel/channel-rpc.ts +0 -5
  360. package/src/wirings/channel/channel-rpc.types.ts +0 -160
  361. package/src/wirings/channel/channel-runner.ts +0 -164
  362. package/src/wirings/channel/channel-store.ts +0 -35
  363. package/src/wirings/channel/channel.types.ts +0 -193
  364. package/src/wirings/channel/define-channel-routes.ts +0 -5
  365. package/src/wirings/channel/eventhub-service.ts +0 -16
  366. package/src/wirings/channel/eventhub-store.ts +0 -13
  367. package/src/wirings/channel/index.ts +0 -40
  368. package/src/wirings/channel/local/index.ts +0 -3
  369. package/src/wirings/channel/local/local-channel-handler.ts +0 -98
  370. package/src/wirings/channel/local/local-channel-runner.test.ts +0 -339
  371. package/src/wirings/channel/local/local-channel-runner.ts +0 -271
  372. package/src/wirings/channel/local/local-eventhub-service.test.ts +0 -77
  373. package/src/wirings/channel/local/local-eventhub-service.ts +0 -69
  374. package/src/wirings/channel/log-channels.ts +0 -16
  375. package/src/wirings/channel/pikku-abstract-channel-handler.test.ts +0 -135
  376. package/src/wirings/channel/pikku-abstract-channel-handler.ts +0 -60
  377. package/src/wirings/channel/serverless/index.ts +0 -6
  378. package/src/wirings/channel/serverless/serverless-channel-runner.ts +0 -328
  379. package/src/wirings/cli/channel/cli-approval.test.ts +0 -177
  380. package/src/wirings/cli/channel/cli-approval.ts +0 -135
  381. package/src/wirings/cli/channel/cli-channel-runner.ts +0 -118
  382. package/src/wirings/cli/channel/cli-raw-channel-runner.test.ts +0 -192
  383. package/src/wirings/cli/channel/cli-raw-channel-runner.ts +0 -148
  384. package/src/wirings/cli/channel/cli-raw-client-runner.test.ts +0 -480
  385. package/src/wirings/cli/channel/cli-raw-client-runner.ts +0 -188
  386. package/src/wirings/cli/channel/index.ts +0 -6
  387. package/src/wirings/cli/cli-runner.test.ts +0 -969
  388. package/src/wirings/cli/cli-runner.ts +0 -538
  389. package/src/wirings/cli/cli.types.ts +0 -388
  390. package/src/wirings/cli/command-parser.test.ts +0 -1120
  391. package/src/wirings/cli/command-parser.ts +0 -713
  392. package/src/wirings/cli/define-cli-commands.ts +0 -13
  393. package/src/wirings/cli/format-cli-error.test.ts +0 -91
  394. package/src/wirings/cli/format-cli-error.ts +0 -96
  395. package/src/wirings/cli/index.ts +0 -19
  396. package/src/wirings/credential/credential.types.ts +0 -37
  397. package/src/wirings/credential/define-credential.ts +0 -49
  398. package/src/wirings/credential/index.ts +0 -7
  399. package/src/wirings/credential/validate-credential-definitions.ts +0 -63
  400. package/src/wirings/gateway/gateway-authorization.test.ts +0 -575
  401. package/src/wirings/gateway/gateway-channel-meta.test.ts +0 -44
  402. package/src/wirings/gateway/gateway-runner.test.ts +0 -581
  403. package/src/wirings/gateway/gateway-runner.ts +0 -411
  404. package/src/wirings/gateway/gateway.types.ts +0 -137
  405. package/src/wirings/gateway/index.ts +0 -15
  406. package/src/wirings/http/http-routes.test.ts +0 -318
  407. package/src/wirings/http/http-routes.ts +0 -111
  408. package/src/wirings/http/http-runner-addon-ref.test.ts +0 -238
  409. package/src/wirings/http/http-runner.test.ts +0 -503
  410. package/src/wirings/http/http-runner.ts +0 -462
  411. package/src/wirings/http/http.types.ts +0 -307
  412. package/src/wirings/http/index.ts +0 -27
  413. package/src/wirings/http/log-http-routes.ts +0 -18
  414. package/src/wirings/http/pikku-fetch-http-request.test.ts +0 -318
  415. package/src/wirings/http/pikku-fetch-http-request.ts +0 -260
  416. package/src/wirings/http/pikku-fetch-http-response.test.ts +0 -123
  417. package/src/wirings/http/pikku-fetch-http-response.ts +0 -149
  418. package/src/wirings/http/routers/http-router.ts +0 -13
  419. package/src/wirings/http/routers/path-to-regex.test.ts +0 -306
  420. package/src/wirings/http/routers/path-to-regex.ts +0 -115
  421. package/src/wirings/http/web-request.test.ts +0 -382
  422. package/src/wirings/http/web-request.ts +0 -162
  423. package/src/wirings/mcp/index.ts +0 -26
  424. package/src/wirings/mcp/mcp-endpoint-registry.test.ts +0 -388
  425. package/src/wirings/mcp/mcp-endpoint-registry.ts +0 -159
  426. package/src/wirings/mcp/mcp-runner.test.ts +0 -588
  427. package/src/wirings/mcp/mcp-runner.ts +0 -330
  428. package/src/wirings/mcp/mcp.types.ts +0 -199
  429. package/src/wirings/node/index.ts +0 -2
  430. package/src/wirings/node/node.types.ts +0 -23
  431. package/src/wirings/oauth2/index.ts +0 -1
  432. package/src/wirings/oauth2/oauth2.types.ts +0 -12
  433. package/src/wirings/persona/define-personas.ts +0 -33
  434. package/src/wirings/persona/index.ts +0 -75
  435. package/src/wirings/persona/persona-app-scopes.test.ts +0 -47
  436. package/src/wirings/persona/persona-app-scopes.ts +0 -74
  437. package/src/wirings/persona/persona-email.ts +0 -87
  438. package/src/wirings/persona/persona-environments.test.ts +0 -194
  439. package/src/wirings/persona/persona-environments.ts +0 -138
  440. package/src/wirings/persona/persona-mailbox.ts +0 -156
  441. package/src/wirings/persona/persona.test.ts +0 -230
  442. package/src/wirings/persona/persona.types.ts +0 -156
  443. package/src/wirings/persona/validate-personas.ts +0 -137
  444. package/src/wirings/queue/index.ts +0 -29
  445. package/src/wirings/queue/queue-identity.test.ts +0 -454
  446. package/src/wirings/queue/queue-identity.ts +0 -176
  447. package/src/wirings/queue/queue-runner.test.ts +0 -705
  448. package/src/wirings/queue/queue-runner.ts +0 -181
  449. package/src/wirings/queue/queue.types.ts +0 -161
  450. package/src/wirings/queue/register-queue-helper.ts +0 -46
  451. package/src/wirings/queue/signed-queue-service.ts +0 -60
  452. package/src/wirings/queue/validate-worker-config.test.ts +0 -108
  453. package/src/wirings/queue/validate-worker-config.ts +0 -90
  454. package/src/wirings/role/define-system-role.ts +0 -33
  455. package/src/wirings/role/index.ts +0 -13
  456. package/src/wirings/role/role.test.ts +0 -104
  457. package/src/wirings/role/role.types.ts +0 -47
  458. package/src/wirings/role/validate-role-definitions.ts +0 -93
  459. package/src/wirings/rpc/index.ts +0 -8
  460. package/src/wirings/rpc/rpc-runner.test.ts +0 -1130
  461. package/src/wirings/rpc/rpc-runner.ts +0 -566
  462. package/src/wirings/rpc/rpc-types.ts +0 -87
  463. package/src/wirings/scheduler/index.ts +0 -11
  464. package/src/wirings/scheduler/log-schedulers.ts +0 -16
  465. package/src/wirings/scheduler/scheduler-runner.test.ts +0 -835
  466. package/src/wirings/scheduler/scheduler-runner.ts +0 -138
  467. package/src/wirings/scheduler/scheduler.types.ts +0 -42
  468. package/src/wirings/scope/define-scope.ts +0 -33
  469. package/src/wirings/scope/index.ts +0 -15
  470. package/src/wirings/scope/scope.test.ts +0 -159
  471. package/src/wirings/scope/scope.types.ts +0 -42
  472. package/src/wirings/scope/validate-scope-definitions.ts +0 -107
  473. package/src/wirings/secret/index.ts +0 -9
  474. package/src/wirings/secret/secret.types.ts +0 -70
  475. package/src/wirings/secret/validate-secret-definitions.test.ts +0 -232
  476. package/src/wirings/secret/validate-secret-definitions.ts +0 -88
  477. package/src/wirings/trigger/index.ts +0 -9
  478. package/src/wirings/trigger/pikku-trigger-service.ts +0 -107
  479. package/src/wirings/trigger/trigger-runner.test.ts +0 -78
  480. package/src/wirings/trigger/trigger-runner.ts +0 -113
  481. package/src/wirings/trigger/trigger.types.ts +0 -100
  482. package/src/wirings/variable/index.ts +0 -8
  483. package/src/wirings/variable/validate-variable-definitions.test.ts +0 -115
  484. package/src/wirings/variable/validate-variable-definitions.ts +0 -71
  485. package/src/wirings/variable/variable.types.ts +0 -40
  486. package/src/wirings/virtual-user/index.ts +0 -107
  487. package/src/wirings/virtual-user/prepare-virtual-user-run.test.ts +0 -115
  488. package/src/wirings/virtual-user/prepare-virtual-user-run.ts +0 -95
  489. package/src/wirings/virtual-user/run-virtual-user.test.ts +0 -774
  490. package/src/wirings/virtual-user/run-virtual-user.ts +0 -684
  491. package/src/wirings/virtual-user/virtual-user-agents.test.ts +0 -72
  492. package/src/wirings/virtual-user/virtual-user-agents.ts +0 -62
  493. package/src/wirings/virtual-user/virtual-user-catalogue.test.ts +0 -215
  494. package/src/wirings/virtual-user/virtual-user-catalogue.ts +0 -184
  495. package/src/wirings/virtual-user/virtual-user-derive.test.ts +0 -426
  496. package/src/wirings/virtual-user/virtual-user-derive.ts +0 -161
  497. package/src/wirings/virtual-user/virtual-user-dispositions.test.ts +0 -68
  498. package/src/wirings/virtual-user/virtual-user-dispositions.ts +0 -210
  499. package/src/wirings/virtual-user/virtual-user-intents.test.ts +0 -218
  500. package/src/wirings/virtual-user/virtual-user-intents.ts +0 -185
  501. package/src/wirings/virtual-user/virtual-user-rng.test.ts +0 -72
  502. package/src/wirings/virtual-user/virtual-user-rng.ts +0 -50
  503. package/src/wirings/virtual-user/virtual-user-run-store.ts +0 -131
  504. package/src/wirings/virtual-user/virtual-user-scaffold.test.ts +0 -854
  505. package/src/wirings/virtual-user/virtual-user-scaffold.ts +0 -664
  506. package/src/wirings/virtual-user/virtual-user-schedule-store.ts +0 -93
  507. package/src/wirings/virtual-user/virtual-user-schedule.test.ts +0 -280
  508. package/src/wirings/virtual-user/virtual-user-schedule.ts +0 -156
  509. package/src/wirings/virtual-user/virtual-user-target.ts +0 -47
  510. package/src/wirings/virtual-user/virtual-user.types.ts +0 -215
  511. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +0 -709
  512. package/src/wirings/workflow/dsl/workflow-runner.ts +0 -25
  513. package/src/wirings/workflow/feature.test.ts +0 -131
  514. package/src/wirings/workflow/feature.ts +0 -59
  515. package/src/wirings/workflow/graph/graph-foreach-queued.test.ts +0 -569
  516. package/src/wirings/workflow/graph/graph-foreach.test.ts +0 -626
  517. package/src/wirings/workflow/graph/graph-node.ts +0 -115
  518. package/src/wirings/workflow/graph/graph-runner.test.ts +0 -1049
  519. package/src/wirings/workflow/graph/graph-runner.ts +0 -1376
  520. package/src/wirings/workflow/graph/graph-validation.test.ts +0 -27
  521. package/src/wirings/workflow/graph/graph-validation.ts +0 -41
  522. package/src/wirings/workflow/graph/template.test.ts +0 -49
  523. package/src/wirings/workflow/graph/template.ts +0 -42
  524. package/src/wirings/workflow/graph/wire-workflow-graph.ts +0 -39
  525. package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -75
  526. package/src/wirings/workflow/index.ts +0 -107
  527. package/src/wirings/workflow/pikku-scenario-service.ts +0 -1013
  528. package/src/wirings/workflow/pikku-workflow-service.test.ts +0 -963
  529. package/src/wirings/workflow/pikku-workflow-service.ts +0 -1993
  530. package/src/wirings/workflow/run-timeline.test.ts +0 -199
  531. package/src/wirings/workflow/run-timeline.ts +0 -185
  532. package/src/wirings/workflow/scenario-cookie-jar.test.ts +0 -107
  533. package/src/wirings/workflow/scenario-cookie-jar.ts +0 -57
  534. package/src/wirings/workflow/scenario-expectations.test.ts +0 -238
  535. package/src/wirings/workflow/scenario-hooks.test.ts +0 -259
  536. package/src/wirings/workflow/scenario-poll.test.ts +0 -64
  537. package/src/wirings/workflow/scenario-poll.ts +0 -27
  538. package/src/wirings/workflow/scenario-prose.test.ts +0 -275
  539. package/src/wirings/workflow/scenario-prose.ts +0 -86
  540. package/src/wirings/workflow/scenario-run.types.ts +0 -193
  541. package/src/wirings/workflow/scenario-service.test.ts +0 -147
  542. package/src/wirings/workflow/scenario-step-guards.ts +0 -23
  543. package/src/wirings/workflow/scenario-step.test.ts +0 -800
  544. package/src/wirings/workflow/scenario-step.types.ts +0 -262
  545. package/src/wirings/workflow/scenario-surface.test.ts +0 -146
  546. package/src/wirings/workflow/scenario-surface.ts +0 -71
  547. package/src/wirings/workflow/scenario.types.ts +0 -63
  548. package/src/wirings/workflow/workflow-approval-audit.ts +0 -47
  549. package/src/wirings/workflow/workflow-approval-policy.test.ts +0 -594
  550. package/src/wirings/workflow/workflow-approval-policy.ts +0 -68
  551. package/src/wirings/workflow/workflow-approval.ts +0 -290
  552. package/src/wirings/workflow/workflow-child-run-session.test.ts +0 -168
  553. package/src/wirings/workflow/workflow-constants.ts +0 -66
  554. package/src/wirings/workflow/workflow-dispatch-durability.test.ts +0 -116
  555. package/src/wirings/workflow/workflow-dispatch-payload.test.ts +0 -55
  556. package/src/wirings/workflow/workflow-dispatch-relay.test.ts +0 -128
  557. package/src/wirings/workflow/workflow-errors.ts +0 -132
  558. package/src/wirings/workflow/workflow-inline-authority.test.ts +0 -175
  559. package/src/wirings/workflow/workflow-invocation-id.test.ts +0 -51
  560. package/src/wirings/workflow/workflow-invocation-id.ts +0 -28
  561. package/src/wirings/workflow/workflow-meta-resolver.ts +0 -45
  562. package/src/wirings/workflow/workflow-mirror.test.ts +0 -171
  563. package/src/wirings/workflow/workflow-missing-meta.test.ts +0 -92
  564. package/src/wirings/workflow/workflow-on-error.test.ts +0 -145
  565. package/src/wirings/workflow/workflow-queue-routing.ts +0 -129
  566. package/src/wirings/workflow/workflow-queue-wiring.ts +0 -149
  567. package/src/wirings/workflow/workflow-queue-workers.test.ts +0 -131
  568. package/src/wirings/workflow/workflow-queue-workers.ts +0 -66
  569. package/src/wirings/workflow/workflow-recovery.ts +0 -192
  570. package/src/wirings/workflow/workflow-replay-snapshot.test.ts +0 -140
  571. package/src/wirings/workflow/workflow-retry-policy.test.ts +0 -113
  572. package/src/wirings/workflow/workflow-run-authority.test.ts +0 -212
  573. package/src/wirings/workflow/workflow-run-context.test.ts +0 -172
  574. package/src/wirings/workflow/workflow-run-engine.types.ts +0 -92
  575. package/src/wirings/workflow/workflow-run-ownership.ts +0 -37
  576. package/src/wirings/workflow/workflow-run-polling.test.ts +0 -127
  577. package/src/wirings/workflow/workflow-stalled-recovery.test.ts +0 -152
  578. package/src/wirings/workflow/workflow-status-stream.test.ts +0 -354
  579. package/src/wirings/workflow/workflow-status-stream.ts +0 -144
  580. package/src/wirings/workflow/workflow-step-claim.ts +0 -46
  581. package/src/wirings/workflow/workflow-step-ordinal.test.ts +0 -94
  582. package/src/wirings/workflow/workflow-step-session.test.ts +0 -87
  583. package/src/wirings/workflow/workflow-suspend.ts +0 -61
  584. package/src/wirings/workflow/workflow-terminal-run-guard.test.ts +0 -105
  585. package/src/wirings/workflow/workflow.types.ts +0 -268
  586. package/src/wirings-stay-decoupled.test.ts +0 -130
  587. package/tsconfig.json +0 -14
  588. package/tsconfig.tsbuildinfo +0 -1
  589. package/tsconfig.type-tests.json +0 -15
@@ -1,1619 +0,0 @@
1
- import { describe, test, beforeEach } from 'node:test'
2
- import * as assert from 'node:assert'
3
- import {
4
- addFunction,
5
- getAllFunctionNames,
6
- getFunctionNames,
7
- runPikkuFunc,
8
- } from './function-runner.js'
9
- import { addGlobalPermission } from '../permissions.js'
10
- import { addTagMiddleware } from '../middleware-runner.js'
11
- import { addSchema } from '../schema.js'
12
- import { resetPikkuState, pikkuState } from '../pikku-state.js'
13
- import type { CoreServices } from '../types/core.types.js'
14
- import type { CorePikkuMiddleware } from '../middleware/middleware.types.js'
15
- import type { CorePermissionGroup } from './functions.types.js'
16
- import { PikkuSessionService } from '../services/user-session-service.js'
17
- import { MissingScopeError, ReadonlySessionError } from '../errors/errors.js'
18
- import { createInvocationAudit } from '../services/audit-service.js'
19
- import { SecretAccessDeniedError } from '../services/secretless.js'
20
-
21
- beforeEach(() => {
22
- resetPikkuState()
23
- })
24
-
25
- const addTestFunction = (funcName: string, funcConfig: any) => {
26
- addFunction(funcName, funcConfig)
27
- // Convert tags to middleware metadata (tags are organizational only; they no
28
- // longer carry permissions in the session+function authorization model).
29
- const middleware = funcConfig.tags
30
- ? funcConfig.tags.map((tag: string) => ({ type: 'tag' as const, tag }))
31
- : undefined
32
- pikkuState(null, 'function', 'meta')[funcName] = {
33
- pikkuFuncId: funcName,
34
- inputSchemaName: null,
35
- outputSchemaName: null,
36
- sessionless: true,
37
- middleware,
38
- }
39
- }
40
-
41
- const mockSingletonServices = {
42
- logger: {
43
- info: () => {},
44
- warn: () => {},
45
- error: () => {},
46
- debug: () => {},
47
- },
48
- } as any
49
-
50
- const mockServices: CoreServices = {
51
- ...mockSingletonServices,
52
- } as any
53
-
54
- describe('runPikkuFunc - Integration Tests', () => {
55
- test('should execute middleware in correct order: wiringTags → wiringMiddleware → funcTags → funcMiddleware', async () => {
56
- const executionOrder: string[] = []
57
- const createMiddleware = (name: string): CorePikkuMiddleware => {
58
- return async (services, wire, next) => {
59
- executionOrder.push(name)
60
- await next()
61
- }
62
- }
63
-
64
- addTagMiddleware('wiringTag', [createMiddleware('wiringTag')])
65
- addTagMiddleware('funcTag', [createMiddleware('funcTag')])
66
-
67
- addTestFunction('testFunc', {
68
- func: async () => {
69
- executionOrder.push('main')
70
- return 'success'
71
- },
72
- middleware: [createMiddleware('funcMiddleware')],
73
- tags: ['funcTag'],
74
- })
75
-
76
- const result = await runPikkuFunc(
77
- 'rpc',
78
- Math.random().toString(),
79
- 'testFunc',
80
- {
81
- singletonServices: mockSingletonServices,
82
- getAllServices: () => mockServices,
83
- data: () => ({}),
84
- wireMiddleware: [createMiddleware('wiringMiddleware')],
85
- inheritedMiddleware: [{ type: 'tag', tag: 'wiringTag' }],
86
- auth: false,
87
- wire: {},
88
- }
89
- )
90
-
91
- assert.equal(result, 'success')
92
- // Order: wireInheritedMiddleware (tags), wireMiddleware, funcInheritedMiddleware (tags), funcMiddleware
93
- assert.deepEqual(executionOrder, [
94
- 'wiringTag',
95
- 'wiringMiddleware',
96
- 'funcTag',
97
- 'funcMiddleware',
98
- 'main',
99
- ])
100
- })
101
-
102
- test('runs global (AND) then function (OR) permissions before the handler', async () => {
103
- const executionOrder: string[] = []
104
-
105
- addGlobalPermission([
106
- async () => {
107
- executionOrder.push('globalPermission')
108
- return true
109
- },
110
- ])
111
-
112
- const funcPermissions: CorePermissionGroup = {
113
- permissions: [
114
- async () => {
115
- executionOrder.push('funcPermission')
116
- return true
117
- },
118
- ],
119
- }
120
-
121
- addTestFunction('testFunc', {
122
- func: async () => {
123
- executionOrder.push('main')
124
- return 'success'
125
- },
126
- permissions: funcPermissions,
127
- })
128
-
129
- const result = await runPikkuFunc(
130
- 'rpc',
131
- Math.random().toString(),
132
- 'testFunc',
133
- {
134
- singletonServices: mockSingletonServices,
135
- getAllServices: () => mockServices,
136
- data: () => ({}),
137
- auth: false,
138
- wire: {},
139
- }
140
- )
141
-
142
- assert.equal(result, 'success')
143
- assert.deepEqual(executionOrder, [
144
- 'globalPermission',
145
- 'funcPermission',
146
- 'main',
147
- ])
148
- })
149
-
150
- test('a failing global permission denies before the function permission runs', async () => {
151
- let funcPermissionRan = false
152
- addGlobalPermission([async () => false])
153
-
154
- addTestFunction('testFunc', {
155
- func: async () => 'success',
156
- permissions: {
157
- allow: [
158
- async () => {
159
- funcPermissionRan = true
160
- return true
161
- },
162
- ],
163
- },
164
- })
165
-
166
- await assert.rejects(
167
- runPikkuFunc('rpc', Math.random().toString(), 'testFunc', {
168
- singletonServices: mockSingletonServices,
169
- getAllServices: () => mockServices,
170
- data: () => ({}),
171
- auth: false,
172
- wire: {},
173
- }),
174
- {
175
- message: 'Permission denied',
176
- }
177
- )
178
- assert.equal(funcPermissionRan, false)
179
- })
180
-
181
- test('a passing global permission does not satisfy a failing function permission', async () => {
182
- addGlobalPermission([async () => true])
183
-
184
- addTestFunction('testFunc', {
185
- func: async () => 'success',
186
- permissions: { admin: [async () => false] },
187
- })
188
-
189
- await assert.rejects(
190
- runPikkuFunc('rpc', Math.random().toString(), 'testFunc', {
191
- singletonServices: mockSingletonServices,
192
- getAllServices: () => mockServices,
193
- data: () => ({}),
194
- auth: false,
195
- wire: {},
196
- }),
197
- {
198
- message: 'Permission denied',
199
- }
200
- )
201
- })
202
-
203
- test('should throw specific error for function permission failures', async () => {
204
- const funcPermissions: CorePermissionGroup = {
205
- permissions: [async () => false],
206
- }
207
-
208
- addTestFunction('testFunc', {
209
- func: async () => 'success',
210
- permissions: funcPermissions,
211
- })
212
-
213
- await assert.rejects(
214
- runPikkuFunc('rpc', Math.random().toString(), 'testFunc', {
215
- singletonServices: mockSingletonServices,
216
- getAllServices: () => mockServices,
217
- data: () => ({}),
218
- auth: false,
219
- wire: {},
220
- }),
221
- {
222
- message: 'Permission denied',
223
- }
224
- )
225
- })
226
-
227
- test('should deduplicate middleware when same middleware appears in tags and direct', async () => {
228
- let executionCount = 0
229
-
230
- const duplicatedMiddleware: CorePikkuMiddleware = async (
231
- services,
232
- wire,
233
- next
234
- ) => {
235
- executionCount++
236
- await next()
237
- }
238
-
239
- addTagMiddleware('testTag', [duplicatedMiddleware])
240
-
241
- addTestFunction('testFunc', {
242
- func: async () => 'success',
243
- middleware: [duplicatedMiddleware], // Same middleware directly
244
- tags: ['testTag'], // Same middleware via tag
245
- })
246
-
247
- await runPikkuFunc('rpc', Math.random().toString(), 'testFunc', {
248
- singletonServices: mockSingletonServices,
249
- getAllServices: () => mockServices,
250
- data: () => ({}),
251
- auth: false,
252
- wire: {},
253
- })
254
-
255
- assert.equal(executionCount, 1)
256
- })
257
-
258
- test('should OR function permission groups and short-circuit on the first pass', async () => {
259
- const executionOrder: string[] = []
260
-
261
- // Two groups ORed together: the first (owner) fails, the second (admin) passes.
262
- const permissions: CorePermissionGroup = {
263
- owner: [
264
- async () => {
265
- executionOrder.push('owner')
266
- return false
267
- },
268
- ],
269
- admin: [
270
- async () => {
271
- executionOrder.push('admin')
272
- return true
273
- },
274
- ],
275
- }
276
-
277
- addTestFunction('testFunc', {
278
- func: async () => {
279
- executionOrder.push('main')
280
- return 'success'
281
- },
282
- permissions,
283
- })
284
-
285
- const result = await runPikkuFunc(
286
- 'rpc',
287
- Math.random().toString(),
288
- 'testFunc',
289
- {
290
- singletonServices: mockSingletonServices,
291
- getAllServices: () => mockServices,
292
- data: () => ({}),
293
- auth: false,
294
- wire: {},
295
- }
296
- )
297
-
298
- assert.equal(result, 'success')
299
- assert.deepEqual(executionOrder, ['owner', 'admin', 'main'])
300
- })
301
-
302
- test('should work without any middleware or permissions', async () => {
303
- addTestFunction('simpleFunc', {
304
- func: async () => 'simple success',
305
- })
306
-
307
- const result = await runPikkuFunc(
308
- 'rpc',
309
- Math.random().toString(),
310
- 'simpleFunc',
311
- {
312
- singletonServices: mockSingletonServices,
313
- getAllServices: () => mockServices,
314
- data: () => ({}),
315
- auth: false,
316
- wire: {},
317
- }
318
- )
319
-
320
- assert.equal(result, 'simple success')
321
- })
322
-
323
- test('should work with only wiring-level middleware', async () => {
324
- const executionOrder: string[] = []
325
-
326
- const wiringMiddleware: CorePikkuMiddleware = async (
327
- services,
328
- wire,
329
- next
330
- ) => {
331
- executionOrder.push('wiringMiddleware')
332
- await next()
333
- }
334
-
335
- addTestFunction('testFunc', {
336
- func: async () => {
337
- executionOrder.push('main')
338
- return 'success'
339
- },
340
- })
341
-
342
- const result = await runPikkuFunc(
343
- 'rpc',
344
- Math.random().toString(),
345
- 'testFunc',
346
- {
347
- singletonServices: mockSingletonServices,
348
- getAllServices: () => mockServices,
349
- data: () => ({}),
350
- wireMiddleware: [wiringMiddleware],
351
- auth: false,
352
- wire: {},
353
- }
354
- )
355
-
356
- assert.equal(result, 'success')
357
- assert.deepEqual(executionOrder, ['wiringMiddleware', 'main'])
358
- })
359
-
360
- test('should work with only function-level middleware and permissions', async () => {
361
- const executionOrder: string[] = []
362
-
363
- const funcMiddleware: CorePikkuMiddleware = async (
364
- services,
365
- wire,
366
- next
367
- ) => {
368
- executionOrder.push('funcMiddleware')
369
- await next()
370
- }
371
-
372
- const funcPermissions: CorePermissionGroup = {
373
- permissions: [
374
- async () => {
375
- executionOrder.push('funcPermission')
376
- return true
377
- },
378
- ],
379
- }
380
-
381
- addTestFunction('testFunc', {
382
- func: async () => {
383
- executionOrder.push('main')
384
- return 'success'
385
- },
386
- middleware: [funcMiddleware],
387
- permissions: funcPermissions,
388
- })
389
-
390
- const result = await runPikkuFunc(
391
- 'rpc',
392
- Math.random().toString(),
393
- 'testFunc',
394
- {
395
- singletonServices: mockSingletonServices,
396
- getAllServices: () => mockServices,
397
- data: () => ({}),
398
- auth: false,
399
- wire: {},
400
- }
401
- )
402
-
403
- assert.equal(result, 'success')
404
- assert.deepEqual(executionOrder, [
405
- 'funcMiddleware',
406
- 'funcPermission',
407
- 'main',
408
- ])
409
- })
410
-
411
- test('should pass correct parameters to function', async () => {
412
- let receivedServices: any
413
- let receivedData: any
414
- let receivedWire: any
415
-
416
- const testData = { test: 'data' }
417
-
418
- addTestFunction('testFunc', {
419
- func: async (services, data, wire) => {
420
- receivedServices = services
421
- receivedData = data
422
- receivedWire = wire
423
- return 'success'
424
- },
425
- })
426
-
427
- await runPikkuFunc('rpc', Math.random().toString(), 'testFunc', {
428
- singletonServices: mockServices,
429
- data: () => testData,
430
- auth: false,
431
- wire: { rpc: {} },
432
- })
433
-
434
- assert.deepEqual(receivedServices, mockServices)
435
- assert.equal(receivedData, testData)
436
- assert.ok(receivedWire.rpc)
437
- assert.equal(receivedWire.session, undefined)
438
- })
439
-
440
- test('should handle async createWireServices function', async () => {
441
- let servicesProvided: any
442
- const wireServices = { customService: 'value' }
443
-
444
- addTestFunction('testFunc', {
445
- func: async (services, data, wire) => {
446
- servicesProvided = services
447
- return 'success'
448
- },
449
- })
450
-
451
- const asyncCreateWireServices = async () => {
452
- await new Promise((resolve) => setTimeout(resolve, 1))
453
- return wireServices
454
- }
455
-
456
- const result = await runPikkuFunc(
457
- 'rpc',
458
- Math.random().toString(),
459
- 'testFunc',
460
- {
461
- singletonServices: mockSingletonServices,
462
- createWireServices: asyncCreateWireServices,
463
- data: () => ({}),
464
- auth: false,
465
- wire: {},
466
- }
467
- )
468
-
469
- assert.equal(result, 'success')
470
- assert.deepEqual(servicesProvided, {
471
- ...mockSingletonServices,
472
- ...wireServices,
473
- })
474
- })
475
-
476
- test('should resolve versioned function ids to the base function and warn once', async () => {
477
- const warnings: string[] = []
478
- const singletonServices = {
479
- ...mockSingletonServices,
480
- logger: {
481
- ...mockSingletonServices.logger,
482
- warn: (message: string) => {
483
- warnings.push(message)
484
- },
485
- },
486
- } as any
487
-
488
- addTestFunction('versionedBase', {
489
- func: async () => 'resolved',
490
- })
491
-
492
- const result = await runPikkuFunc(
493
- 'rpc',
494
- Math.random().toString(),
495
- 'versionedBase@v2',
496
- {
497
- singletonServices,
498
- data: () => ({}),
499
- auth: false,
500
- wire: {},
501
- }
502
- )
503
-
504
- assert.equal(result, 'resolved')
505
- assert.equal(warnings.length, 1)
506
- assert.match(
507
- warnings[0]!,
508
- /Version 'versionedBase@v2' not registered, resolved to 'versionedBase'/
509
- )
510
- })
511
-
512
- test('should throw when function metadata is missing', async () => {
513
- addFunction('metaMissing', {
514
- func: async () => 'ok',
515
- } as any)
516
-
517
- await assert.rejects(
518
- () =>
519
- runPikkuFunc('rpc', Math.random().toString(), 'metaMissing', {
520
- singletonServices: mockSingletonServices,
521
- data: () => ({}),
522
- auth: false,
523
- wire: {},
524
- }),
525
- {
526
- message: 'Function meta not found: metaMissing',
527
- }
528
- )
529
- })
530
-
531
- test('should throw when function config is missing', async () => {
532
- pikkuState(null, 'function', 'meta').missingConfig = {
533
- pikkuFuncId: 'missingConfig',
534
- sessionless: true,
535
- permissions: [],
536
- } as any
537
-
538
- await assert.rejects(
539
- () =>
540
- runPikkuFunc('rpc', Math.random().toString(), 'missingConfig', {
541
- singletonServices: mockSingletonServices,
542
- data: () => ({}),
543
- auth: false,
544
- wire: {},
545
- }),
546
- {
547
- message: 'Function not found: missingConfig',
548
- }
549
- )
550
- })
551
-
552
- test('should require a session when sessionless metadata is false', async () => {
553
- addTestFunction('sessionRequired', {
554
- func: async () => 'ok',
555
- })
556
- pikkuState(null, 'function', 'meta').sessionRequired.sessionless = false
557
-
558
- await assert.rejects(
559
- () =>
560
- runPikkuFunc('rpc', Math.random().toString(), 'sessionRequired', {
561
- singletonServices: mockSingletonServices,
562
- data: () => ({}),
563
- auth: true,
564
- wire: {},
565
- }),
566
- {
567
- message: 'Authentication required',
568
- }
569
- )
570
- })
571
-
572
- test('should warn when auth is disabled for a session-required function but still enforce session', async () => {
573
- const warnings: string[] = []
574
- const singletonServices = {
575
- ...mockSingletonServices,
576
- logger: {
577
- ...mockSingletonServices.logger,
578
- warn: (message: string) => {
579
- warnings.push(message)
580
- },
581
- },
582
- } as any
583
-
584
- addTestFunction('sessionRequired', {
585
- func: async () => 'ok',
586
- auth: false,
587
- })
588
- pikkuState(null, 'function', 'meta').sessionRequired.sessionless = false
589
-
590
- await assert.rejects(
591
- () =>
592
- runPikkuFunc('rpc', Math.random().toString(), 'sessionRequired', {
593
- singletonServices,
594
- data: () => ({}),
595
- auth: false,
596
- wire: {},
597
- }),
598
- {
599
- message: 'Authentication required',
600
- }
601
- )
602
-
603
- assert.equal(warnings.length, 1)
604
- assert.match(
605
- warnings[0]!,
606
- /requires a session but auth was explicitly disabled/
607
- )
608
- })
609
-
610
- test('should require auth when sessionless metadata is absent (undefined defaults to session-required)', async () => {
611
- addTestFunction('legacyAuth', {
612
- func: async () => 'ok',
613
- auth: true,
614
- })
615
- delete pikkuState(null, 'function', 'meta').legacyAuth.sessionless
616
-
617
- await assert.rejects(
618
- () =>
619
- runPikkuFunc('rpc', Math.random().toString(), 'legacyAuth', {
620
- singletonServices: mockSingletonServices,
621
- data: () => ({}),
622
- auth: false,
623
- wire: {},
624
- }),
625
- {
626
- message: 'Authentication required',
627
- }
628
- )
629
- })
630
-
631
- test('should reject readonly sessions for non-readonly functions', async () => {
632
- addTestFunction('readonlyBlocked', {
633
- func: async () => 'ok',
634
- })
635
- pikkuState(null, 'function', 'meta').readonlyBlocked.sessionless = true
636
-
637
- await assert.rejects(
638
- () =>
639
- runPikkuFunc('rpc', Math.random().toString(), 'readonlyBlocked', {
640
- singletonServices: mockSingletonServices,
641
- data: () => ({}),
642
- auth: false,
643
- wire: { session: { readonly: true } },
644
- }),
645
- ReadonlySessionError
646
- )
647
- })
648
-
649
- test('should set session helpers on the wire when a session service is provided', async () => {
650
- const sessionStore = {
651
- get: async () => undefined,
652
- }
653
- const sessionService = new PikkuSessionService(sessionStore as any)
654
- const wire: any = {}
655
- let receivedWire: any
656
-
657
- addTestFunction('sessionHelpers', {
658
- func: async (_services: any, _data: any, innerWire: any) => {
659
- receivedWire = innerWire
660
- innerWire.setSession({ userId: 'u1' })
661
- return innerWire.getSession()
662
- },
663
- })
664
-
665
- const result = await runPikkuFunc(
666
- 'rpc',
667
- Math.random().toString(),
668
- 'sessionHelpers',
669
- {
670
- singletonServices: {
671
- ...mockSingletonServices,
672
- sessionStore,
673
- } as any,
674
- data: () => ({}),
675
- auth: false,
676
- wire,
677
- sessionService,
678
- }
679
- )
680
-
681
- assert.deepEqual(result, { userId: 'u1' })
682
- assert.equal(typeof receivedWire.setSession, 'function')
683
- assert.equal(typeof receivedWire.clearSession, 'function')
684
- assert.equal(typeof receivedWire.getSession, 'function')
685
- assert.equal(typeof receivedWire.hasSessionChanged, 'function')
686
- })
687
-
688
- test('should load session from sessionStore using pikkuUserId from the wire', async () => {
689
- let sessionLookups = 0
690
- let receivedSession: any
691
-
692
- addTestFunction('loadStoredSession', {
693
- func: async (_services: any, _data: any, wire: any) => {
694
- receivedSession = wire.session
695
- return 'ok'
696
- },
697
- })
698
-
699
- await runPikkuFunc('rpc', Math.random().toString(), 'loadStoredSession', {
700
- singletonServices: {
701
- ...mockSingletonServices,
702
- sessionStore: {
703
- get: async (userId: string) => {
704
- sessionLookups++
705
- assert.equal(userId, 'user-1')
706
- return { userId, loaded: true }
707
- },
708
- },
709
- } as any,
710
- data: () => ({}),
711
- auth: false,
712
- wire: { pikkuUserId: 'user-1' },
713
- })
714
-
715
- assert.equal(sessionLookups, 1)
716
- assert.deepEqual(receivedSession, { userId: 'user-1', loaded: true })
717
- })
718
-
719
- test('should expose middleware-set session to createWireServices credential lookups', async () => {
720
- let credentialLookups = 0
721
- let receivedCredential: any
722
- const sessionService = new PikkuSessionService<any>()
723
-
724
- addTestFunction('credentialWire', {
725
- middleware: [
726
- async (_services: any, wire: any, next: any) => {
727
- wire.setSession({ userId: 'user-1' })
728
- await next()
729
- },
730
- ],
731
- func: async (_services: any, _data: any, wire: any) => {
732
- return wire.getSession()
733
- },
734
- })
735
-
736
- await runPikkuFunc('rpc', Math.random().toString(), 'credentialWire', {
737
- singletonServices: {
738
- ...mockSingletonServices,
739
- credentialService: {
740
- getAll: async (userId: string) => {
741
- credentialLookups++
742
- assert.equal(userId, 'user-1')
743
- return {
744
- 'user-oauth': { accessToken: 'token-1' },
745
- }
746
- },
747
- },
748
- } as any,
749
- createWireServices: async (_services: any, wire: any) => {
750
- receivedCredential = await wire.getCredential('user-oauth')
751
- return {}
752
- },
753
- data: () => ({}),
754
- auth: false,
755
- wire: {
756
- session: undefined,
757
- setSession: (session: any) => sessionService.setInitial(session),
758
- getSession: () => sessionService.get(),
759
- hasSessionChanged: () => sessionService.sessionChanged,
760
- } as any,
761
- sessionService,
762
- })
763
-
764
- assert.equal(credentialLookups, 1)
765
- assert.deepEqual(receivedCredential, { accessToken: 'token-1' })
766
- })
767
-
768
- test('should pass addon-scoped singleton services and wrap bare workflow names', async () => {
769
- pikkuState(null, 'addons', 'packages').set('stripe', {
770
- package: '@addon/stripe',
771
- } as any)
772
-
773
- const workflowCalls: unknown[][] = []
774
- let singletonFactoryCalls = 0
775
- let configFactoryCalls = 0
776
-
777
- pikkuState('@addon/stripe', 'package', 'factories', {
778
- createConfig: async () => {
779
- configFactoryCalls++
780
- return { name: 'addon-config' }
781
- },
782
- createSingletonServices: async () => {
783
- singletonFactoryCalls++
784
- return {
785
- logger: mockSingletonServices.logger,
786
- workflowService: {
787
- startWorkflow: async (...args: unknown[]) => {
788
- workflowCalls.push(args)
789
- return { runId: 'wf-1' }
790
- },
791
- },
792
- }
793
- },
794
- } as any)
795
-
796
- addFunction(
797
- 'addonFunc',
798
- {
799
- func: async (services: any, _data: any) => {
800
- await services.workflowService.startWorkflow('chargeCustomer', {
801
- amount: 10,
802
- })
803
- await services.workflowService.startWorkflow('stripe:alreadyScoped', {
804
- amount: 20,
805
- })
806
- return 'ok'
807
- },
808
- } as any,
809
- '@addon/stripe'
810
- )
811
- pikkuState('@addon/stripe', 'function', 'meta').addonFunc = {
812
- pikkuFuncId: 'addonFunc',
813
- sessionless: true,
814
- permissions: [],
815
- } as any
816
-
817
- await runPikkuFunc('rpc', Math.random().toString(), 'addonFunc', {
818
- singletonServices: {
819
- ...mockSingletonServices,
820
- config: { parent: true },
821
- variables: {},
822
- } as any,
823
- data: () => ({}),
824
- auth: false,
825
- wire: {},
826
- packageName: '@addon/stripe',
827
- })
828
-
829
- assert.equal(configFactoryCalls, 1)
830
- assert.equal(singletonFactoryCalls, 1)
831
- assert.deepEqual(workflowCalls, [
832
- ['stripe:chargeCustomer', { amount: 10 }],
833
- ['stripe:alreadyScoped', { amount: 20 }],
834
- ])
835
- })
836
-
837
- test('should reuse cached addon singleton services on subsequent calls', async () => {
838
- let singletonFactoryCalls = 0
839
- pikkuState('@addon/cache', 'package', 'factories', {
840
- createSingletonServices: async () => {
841
- singletonFactoryCalls++
842
- return {
843
- logger: mockSingletonServices.logger,
844
- }
845
- },
846
- } as any)
847
-
848
- addFunction(
849
- 'cachedFunc',
850
- {
851
- func: async () => 'ok',
852
- } as any,
853
- '@addon/cache'
854
- )
855
- pikkuState('@addon/cache', 'function', 'meta').cachedFunc = {
856
- pikkuFuncId: 'cachedFunc',
857
- sessionless: true,
858
- permissions: [],
859
- } as any
860
-
861
- await runPikkuFunc('rpc', '1', 'cachedFunc', {
862
- singletonServices: mockSingletonServices,
863
- data: () => ({}),
864
- auth: false,
865
- wire: {},
866
- packageName: '@addon/cache',
867
- })
868
- await runPikkuFunc('rpc', '2', 'cachedFunc', {
869
- singletonServices: mockSingletonServices,
870
- data: () => ({}),
871
- auth: false,
872
- wire: {},
873
- packageName: '@addon/cache',
874
- })
875
-
876
- assert.equal(singletonFactoryCalls, 1)
877
- })
878
-
879
- test('should use addon createWireServices instead of the caller createWireServices', async () => {
880
- let callerCreateWireServicesUsed = false
881
- let addonCreateWireServicesUsed = false
882
- let receivedServices: any
883
-
884
- pikkuState('@addon/wires', 'package', 'factories', {
885
- createSingletonServices: async () => ({
886
- logger: mockSingletonServices.logger,
887
- }),
888
- createWireServices: async () => {
889
- addonCreateWireServicesUsed = true
890
- return { addonWire: true }
891
- },
892
- } as any)
893
-
894
- addFunction(
895
- 'wireFunc',
896
- {
897
- func: async (services: any) => {
898
- receivedServices = services
899
- return 'ok'
900
- },
901
- } as any,
902
- '@addon/wires'
903
- )
904
- pikkuState('@addon/wires', 'function', 'meta').wireFunc = {
905
- pikkuFuncId: 'wireFunc',
906
- sessionless: true,
907
- permissions: [],
908
- } as any
909
-
910
- await runPikkuFunc('rpc', 'wire', 'wireFunc', {
911
- singletonServices: mockSingletonServices,
912
- createWireServices: async () => {
913
- callerCreateWireServicesUsed = true
914
- return { callerWire: true }
915
- },
916
- data: () => ({}),
917
- auth: false,
918
- wire: {},
919
- packageName: '@addon/wires',
920
- })
921
-
922
- assert.equal(callerCreateWireServicesUsed, false)
923
- assert.equal(addonCreateWireServicesUsed, true)
924
- assert.deepEqual(receivedServices, {
925
- logger: mockSingletonServices.logger,
926
- addonWire: true,
927
- })
928
- })
929
-
930
- test('should lazily memoize the rpc getter on the wire', async () => {
931
- let receivedWire: any
932
-
933
- addTestFunction('rpcGetter', {
934
- func: async (_services: any, _data: any, wire: any) => {
935
- receivedWire = wire
936
- const rpcA = wire.rpc
937
- const rpcB = wire.rpc
938
- return rpcA === rpcB
939
- },
940
- })
941
-
942
- const result = await runPikkuFunc('rpc', 'rpc-getter', 'rpcGetter', {
943
- singletonServices: mockSingletonServices,
944
- data: () => ({}),
945
- auth: false,
946
- wire: {},
947
- })
948
-
949
- assert.equal(result, true)
950
- assert.ok(receivedWire.rpc)
951
- })
952
-
953
- test('should expose resolved audit metadata on the wire for audited functions', async () => {
954
- let receivedAudit: any
955
-
956
- addTestFunction('auditedWire', {
957
- audit: { durability: 'transactional' },
958
- func: async (_services: any, _data: any, wire: any) => {
959
- receivedAudit = wire.audit
960
- return 'ok'
961
- },
962
- })
963
-
964
- const result = await runPikkuFunc('rpc', 'wire-audit-on', 'auditedWire', {
965
- singletonServices: mockSingletonServices,
966
- data: () => ({}),
967
- auth: false,
968
- wire: {},
969
- })
970
-
971
- assert.equal(result, 'ok')
972
- assert.deepEqual(receivedAudit, { durability: 'transactional' })
973
- })
974
-
975
- test('should leave wire audit metadata undefined when audit is disabled', async () => {
976
- let receivedWire: any
977
-
978
- addTestFunction('plainWire', {
979
- func: async (_services: any, _data: any, wire: any) => {
980
- receivedWire = wire
981
- return 'ok'
982
- },
983
- })
984
-
985
- const result = await runPikkuFunc('rpc', 'wire-audit-off', 'plainWire', {
986
- singletonServices: mockSingletonServices,
987
- data: () => ({}),
988
- auth: false,
989
- wire: {},
990
- })
991
-
992
- assert.equal(result, 'ok')
993
- assert.equal(receivedWire.audit, undefined)
994
- })
995
-
996
- test('should restore parent audit metadata after nested non-audited calls', async () => {
997
- let auditBeforeChild: any
998
- let auditAfterChild: any
999
-
1000
- addTestFunction('childPlain', {
1001
- func: async () => 'child-ok',
1002
- })
1003
-
1004
- addTestFunction('parentAudited', {
1005
- audit: true,
1006
- func: async (_services: any, _data: any, wire: any) => {
1007
- auditBeforeChild = wire.audit
1008
- await runPikkuFunc('rpc', 'nested-child-wire', 'childPlain', {
1009
- singletonServices: mockSingletonServices,
1010
- data: () => ({}),
1011
- auth: false,
1012
- wire,
1013
- })
1014
- auditAfterChild = wire.audit
1015
- return 'parent-ok'
1016
- },
1017
- })
1018
-
1019
- const result = await runPikkuFunc(
1020
- 'rpc',
1021
- 'nested-parent-wire',
1022
- 'parentAudited',
1023
- {
1024
- singletonServices: mockSingletonServices,
1025
- data: () => ({}),
1026
- auth: false,
1027
- wire: {},
1028
- }
1029
- )
1030
-
1031
- assert.equal(result, 'parent-ok')
1032
- assert.deepEqual(auditBeforeChild, { durability: 'best-effort' })
1033
- assert.deepEqual(auditAfterChild, { durability: 'best-effort' })
1034
- })
1035
-
1036
- test('should preserve parent audit metadata across rpc sub-calls to non-audited functions', async () => {
1037
- let parentAuditBeforeChild: any
1038
- let parentAuditAfterChild: any
1039
- let parentFunctionIdBeforeChild: any
1040
- let parentFunctionIdAfterChild: any
1041
- let childAudit: any
1042
- let childFunctionId: any
1043
-
1044
- addTestFunction('rpcChildPlain', {
1045
- func: async (_services: any, _data: any, wire: any) => {
1046
- childAudit = wire.audit
1047
- childFunctionId = wire.functionId
1048
- return 'child-ok'
1049
- },
1050
- })
1051
-
1052
- addTestFunction('rpcParentAudited', {
1053
- audit: true,
1054
- func: async (_services: any, _data: any, wire: any) => {
1055
- parentAuditBeforeChild = wire.audit
1056
- parentFunctionIdBeforeChild = wire.functionId
1057
- const childResult = await wire.rpc.invoke('rpcChildPlain', {})
1058
- parentAuditAfterChild = wire.audit
1059
- parentFunctionIdAfterChild = wire.functionId
1060
- return childResult
1061
- },
1062
- })
1063
-
1064
- const result = await runPikkuFunc(
1065
- 'rpc',
1066
- 'rpc-parent-wire',
1067
- 'rpcParentAudited',
1068
- {
1069
- singletonServices: mockSingletonServices,
1070
- data: () => ({}),
1071
- auth: false,
1072
- wire: {},
1073
- }
1074
- )
1075
-
1076
- assert.equal(result, 'child-ok')
1077
- assert.deepEqual(parentAuditBeforeChild, { durability: 'best-effort' })
1078
- assert.deepEqual(parentAuditAfterChild, { durability: 'best-effort' })
1079
- assert.equal(parentFunctionIdBeforeChild, 'rpcParentAudited')
1080
- assert.equal(parentFunctionIdAfterChild, 'rpcParentAudited')
1081
- assert.equal(childAudit, undefined)
1082
- assert.equal(childFunctionId, 'rpcChildPlain')
1083
- })
1084
-
1085
- test('should bind audited rpc sub-calls to the child invocation context', async () => {
1086
- let parentAuditBeforeChild: any
1087
- let parentAuditAfterChild: any
1088
- let parentFunctionIdAfterChild: any
1089
- let childAudit: any
1090
- let childFunctionId: any
1091
-
1092
- addTestFunction('rpcChildAudited', {
1093
- audit: { durability: 'transactional' },
1094
- func: async (_services: any, _data: any, wire: any) => {
1095
- childAudit = wire.audit
1096
- childFunctionId = wire.functionId
1097
- return 'child-audited-ok'
1098
- },
1099
- })
1100
-
1101
- addTestFunction('rpcParentAuditedChild', {
1102
- audit: true,
1103
- func: async (_services: any, _data: any, wire: any) => {
1104
- parentAuditBeforeChild = wire.audit
1105
- const childResult = await wire.rpc.invoke('rpcChildAudited', {})
1106
- parentAuditAfterChild = wire.audit
1107
- parentFunctionIdAfterChild = wire.functionId
1108
- return childResult
1109
- },
1110
- })
1111
-
1112
- const result = await runPikkuFunc(
1113
- 'rpc',
1114
- 'rpc-parent-child-audit-wire',
1115
- 'rpcParentAuditedChild',
1116
- {
1117
- singletonServices: mockSingletonServices,
1118
- data: () => ({}),
1119
- auth: false,
1120
- wire: {},
1121
- }
1122
- )
1123
-
1124
- assert.equal(result, 'child-audited-ok')
1125
- assert.deepEqual(parentAuditBeforeChild, { durability: 'best-effort' })
1126
- assert.deepEqual(parentAuditAfterChild, { durability: 'best-effort' })
1127
- assert.equal(parentFunctionIdAfterChild, 'rpcParentAuditedChild')
1128
- assert.deepEqual(childAudit, { durability: 'transactional' })
1129
- assert.equal(childFunctionId, 'rpcChildAudited')
1130
- })
1131
-
1132
- test('should audit writes from an audited function invoked via exposed rpc (stale outer auditLog)', async () => {
1133
- // Repro of the exposed-RPC HTTP path: the generated rpcCaller has no
1134
- // audit config, and createWireServices builds auditLog on ITS wire —
1135
- // the audited inner function must not inherit that disabled instance.
1136
- const events: any[] = []
1137
- const singletonServices = {
1138
- ...mockSingletonServices,
1139
- audit: { audit: async (event: any) => events.push(event) },
1140
- }
1141
-
1142
- addTestFunction('auditedInner', {
1143
- audit: true,
1144
- func: async (services: any) => {
1145
- await services.auditLog.write({
1146
- type: 'booking.update',
1147
- source: 'explicit',
1148
- })
1149
- return 'inner-ok'
1150
- },
1151
- })
1152
-
1153
- addTestFunction('rpcCallerLike', {
1154
- func: async (_services: any, _data: any, wire: any) => {
1155
- return wire.rpc.invoke('auditedInner', {})
1156
- },
1157
- })
1158
-
1159
- const result = await runPikkuFunc(
1160
- 'http',
1161
- 'exposed-rpc-route',
1162
- 'rpcCallerLike',
1163
- {
1164
- singletonServices,
1165
- data: () => ({}),
1166
- auth: false,
1167
- wire: {},
1168
- createWireServices: async (services: any, wire: any) => ({
1169
- auditLog: createInvocationAudit(services.audit, wire),
1170
- }),
1171
- }
1172
- )
1173
-
1174
- assert.equal(result, 'inner-ok')
1175
- assert.equal(events.length, 1)
1176
- assert.equal(events[0].type, 'booking.update')
1177
- assert.equal(events[0].functionId, 'auditedInner')
1178
- })
1179
-
1180
- test('should give an audited rpc sub-call its own audit buffer with child attribution', async () => {
1181
- const events: any[] = []
1182
- const singletonServices = {
1183
- ...mockSingletonServices,
1184
- audit: { audit: async (event: any) => events.push(event) },
1185
- }
1186
-
1187
- addTestFunction('auditedChildWriter', {
1188
- audit: true,
1189
- func: async (services: any) => {
1190
- await services.auditLog.write({
1191
- type: 'child.event',
1192
- source: 'explicit',
1193
- })
1194
- return 'child-ok'
1195
- },
1196
- })
1197
-
1198
- addTestFunction('auditedParentWriter', {
1199
- audit: true,
1200
- func: async (services: any, _data: any, wire: any) => {
1201
- await services.auditLog.write({
1202
- type: 'parent.event',
1203
- source: 'explicit',
1204
- })
1205
- return wire.rpc.invoke('auditedChildWriter', {})
1206
- },
1207
- })
1208
-
1209
- const result = await runPikkuFunc(
1210
- 'rpc',
1211
- 'audited-parent-child',
1212
- 'auditedParentWriter',
1213
- {
1214
- singletonServices,
1215
- data: () => ({}),
1216
- auth: false,
1217
- wire: {},
1218
- }
1219
- )
1220
-
1221
- assert.equal(result, 'child-ok')
1222
- const byType = Object.fromEntries(events.map((e) => [e.type, e.functionId]))
1223
- assert.equal(byType['parent.event'], 'auditedParentWriter')
1224
- assert.equal(byType['child.event'], 'auditedChildWriter')
1225
- })
1226
-
1227
- test('should warn via the singleton logger when audit writes are dropped', async () => {
1228
- const warnings: any[] = []
1229
- const singletonServices = {
1230
- ...mockSingletonServices,
1231
- logger: {
1232
- ...mockSingletonServices.logger,
1233
- warn: (msg: any) => warnings.push(msg),
1234
- },
1235
- audit: { audit: async () => {} },
1236
- }
1237
-
1238
- addTestFunction('unauditedWriter', {
1239
- func: async (services: any) => {
1240
- await services.auditLog.write({
1241
- type: 'dropped.event',
1242
- source: 'explicit',
1243
- })
1244
- return 'ok'
1245
- },
1246
- })
1247
-
1248
- const result = await runPikkuFunc(
1249
- 'rpc',
1250
- 'unaudited-writer',
1251
- 'unauditedWriter',
1252
- {
1253
- singletonServices,
1254
- data: () => ({}),
1255
- auth: false,
1256
- wire: {},
1257
- createWireServices: async (services: any, wire: any) => ({
1258
- auditLog: createInvocationAudit(
1259
- services.audit,
1260
- wire,
1261
- services.logger
1262
- ),
1263
- }),
1264
- }
1265
- )
1266
-
1267
- assert.equal(result, 'ok')
1268
- assert.equal(warnings.length, 1)
1269
- assert.match(String(warnings[0]), /dropped/)
1270
- assert.match(String(warnings[0]), /unauditedWriter/)
1271
- })
1272
-
1273
- test('should expose the resolved base function id after version fallback', async () => {
1274
- let receivedFunctionId: any
1275
-
1276
- addTestFunction('versionedBase', {
1277
- audit: true,
1278
- func: async (_services: any, _data: any, wire: any) => {
1279
- receivedFunctionId = wire.functionId
1280
- return 'ok'
1281
- },
1282
- })
1283
-
1284
- const result = await runPikkuFunc(
1285
- 'rpc',
1286
- 'wire-version-fallback',
1287
- 'versionedBase@v2',
1288
- {
1289
- singletonServices: mockSingletonServices,
1290
- data: () => ({}),
1291
- auth: false,
1292
- wire: {},
1293
- }
1294
- )
1295
-
1296
- assert.equal(result, 'ok')
1297
- assert.equal(receivedFunctionId, 'versionedBase')
1298
- })
1299
- })
1300
-
1301
- describe('function-runner helpers', () => {
1302
- test('getFunctionNames and getAllFunctionNames should include addon namespaces', () => {
1303
- addTestFunction('rootFunc', { func: async () => 'ok' })
1304
- pikkuState(null, 'addons', 'packages').set('stripe', {
1305
- package: '@addon/stripe',
1306
- } as any)
1307
- addFunction(
1308
- 'addonFunc',
1309
- {
1310
- func: async () => 'ok',
1311
- } as any,
1312
- '@addon/stripe'
1313
- )
1314
- pikkuState('@addon/stripe', 'function', 'meta').addonFunc = {
1315
- pikkuFuncId: 'addonFunc',
1316
- sessionless: true,
1317
- permissions: [],
1318
- } as any
1319
-
1320
- assert.deepEqual(getFunctionNames().sort(), ['rootFunc'])
1321
- assert.deepEqual(getFunctionNames('@addon/stripe').sort(), ['addonFunc'])
1322
- assert.deepEqual(getAllFunctionNames().sort(), [
1323
- 'rootFunc',
1324
- 'stripe:addonFunc',
1325
- ])
1326
- })
1327
- })
1328
-
1329
- describe('runPikkuFunc - scopes', () => {
1330
- const runWithScopes = (
1331
- funcName: string,
1332
- {
1333
- scopes,
1334
- sessionScopes,
1335
- data = () => ({}),
1336
- }: {
1337
- scopes?: string[]
1338
- sessionScopes?: string[]
1339
- data?: () => any
1340
- }
1341
- ) =>
1342
- runPikkuFunc('rpc', Math.random().toString(), funcName, {
1343
- singletonServices: mockSingletonServices,
1344
- data,
1345
- auth: false,
1346
- wire: { session: { userId: 'u1', scopes: sessionScopes } as any },
1347
- })
1348
-
1349
- test('runs the function when the session holds the required scope', async () => {
1350
- addTestFunction('scoped', {
1351
- func: async () => 'ok',
1352
- scopes: ['invoices:create'],
1353
- })
1354
-
1355
- const result = await runWithScopes('scoped', {
1356
- sessionScopes: ['invoices:create'],
1357
- })
1358
-
1359
- assert.equal(result, 'ok')
1360
- })
1361
-
1362
- test('throws MissingScopeError when the session lacks the scope', async () => {
1363
- addTestFunction('scoped', {
1364
- func: async () => 'ok',
1365
- scopes: ['invoices:create'],
1366
- })
1367
-
1368
- await assert.rejects(
1369
- () => runWithScopes('scoped', { sessionScopes: ['billing:read'] }),
1370
- MissingScopeError
1371
- )
1372
- })
1373
-
1374
- test('honours wildcards held by the session', async () => {
1375
- addTestFunction('scoped', {
1376
- func: async () => 'ok',
1377
- scopes: ['admin:invoices:create'],
1378
- })
1379
-
1380
- const result = await runWithScopes('scoped', { sessionScopes: ['admin:*'] })
1381
-
1382
- assert.equal(result, 'ok')
1383
- })
1384
-
1385
- test('does not gate a function that declares no scopes', async () => {
1386
- addTestFunction('unscoped', { func: async () => 'ok' })
1387
-
1388
- const result = await runWithScopes('unscoped', { sessionScopes: [] })
1389
-
1390
- assert.equal(result, 'ok')
1391
- })
1392
-
1393
- test('reads scopes from function meta when the config omits them', async () => {
1394
- addTestFunction('metaScoped', { func: async () => 'ok' })
1395
- pikkuState(null, 'function', 'meta').metaScoped.scopes = ['invoices:create']
1396
-
1397
- await assert.rejects(
1398
- () => runWithScopes('metaScoped', { sessionScopes: [] }),
1399
- MissingScopeError
1400
- )
1401
- })
1402
-
1403
- // The load-bearing test. Scopes are an AND gate separate from permissions, so
1404
- // a passing global (or function) permission must never satisfy a scope.
1405
- test('a passing global permission does not satisfy a scope', async () => {
1406
- addGlobalPermission([async () => true])
1407
- addTestFunction('scoped', { func: async () => 'ok', scopes: ['admin'] })
1408
-
1409
- await assert.rejects(
1410
- () => runWithScopes('scoped', { sessionScopes: [] }),
1411
- MissingScopeError
1412
- )
1413
- })
1414
-
1415
- test('a passing function permission does not satisfy a scope', async () => {
1416
- addTestFunction('scoped', {
1417
- func: async () => 'ok',
1418
- scopes: ['admin'],
1419
- permissions: { allow: [async () => true] },
1420
- })
1421
-
1422
- await assert.rejects(
1423
- () => runWithScopes('scoped', { sessionScopes: [] }),
1424
- MissingScopeError
1425
- )
1426
- })
1427
-
1428
- test('a held scope does not bypass a failing permission', async () => {
1429
- addTestFunction('scoped', {
1430
- func: async () => 'ok',
1431
- scopes: ['admin'],
1432
- permissions: { deny: [async () => false] },
1433
- })
1434
-
1435
- await assert.rejects(
1436
- () => runWithScopes('scoped', { sessionScopes: ['admin'] }),
1437
- { message: 'Permission denied' }
1438
- )
1439
- })
1440
-
1441
- test('a failing scope short-circuits before permissions run', async () => {
1442
- let permissionRan = false
1443
- addTestFunction('scoped', {
1444
- func: async () => 'ok',
1445
- scopes: ['admin'],
1446
- permissions: {
1447
- allow: [
1448
- async () => {
1449
- permissionRan = true
1450
- return true
1451
- },
1452
- ],
1453
- },
1454
- })
1455
-
1456
- await assert.rejects(
1457
- () => runWithScopes('scoped', { sessionScopes: [] }),
1458
- MissingScopeError
1459
- )
1460
- assert.equal(permissionRan, false)
1461
- })
1462
-
1463
- // Scopes depend only on the session, so a denied request must never pay to
1464
- // parse or validate its body.
1465
- test('a failing scope short-circuits before the data is evaluated', async () => {
1466
- addTestFunction('scoped', { func: async () => 'ok', scopes: ['admin'] })
1467
-
1468
- await assert.rejects(
1469
- () =>
1470
- runWithScopes('scoped', {
1471
- sessionScopes: [],
1472
- data: () => {
1473
- throw new Error('data should not have been evaluated')
1474
- },
1475
- }),
1476
- MissingScopeError
1477
- )
1478
- })
1479
-
1480
- test('fails closed when there is no session at all', async () => {
1481
- addTestFunction('scoped', { func: async () => 'ok', scopes: ['admin'] })
1482
-
1483
- await assert.rejects(
1484
- () =>
1485
- runPikkuFunc('rpc', Math.random().toString(), 'scoped', {
1486
- singletonServices: mockSingletonServices,
1487
- data: () => ({}),
1488
- auth: false,
1489
- wire: {},
1490
- }),
1491
- MissingScopeError
1492
- )
1493
- })
1494
-
1495
- describe('schema defaults', () => {
1496
- const addPagedFunction = (funcName: string, seen: { data?: any }) => {
1497
- addSchema('PagedInput', {
1498
- properties: {
1499
- page: { type: 'number', default: 1 },
1500
- limit: { type: 'number', default: 50 },
1501
- },
1502
- })
1503
- addTestFunction(funcName, {
1504
- func: async (_services: any, data: any) => {
1505
- seen.data = data
1506
- return 'ok'
1507
- },
1508
- })
1509
- pikkuState(null, 'function', 'meta')[funcName]!.inputSchemaName =
1510
- 'PagedInput'
1511
- }
1512
-
1513
- // The whole point of the fix: `{}` validates because a defaulted property
1514
- // is not `required`, so without this the body reads `undefined` for a value
1515
- // its generated type declares as a number.
1516
- test('a function called with {} receives its schema defaults', async () => {
1517
- const seen: { data?: any } = {}
1518
- addPagedFunction('paged', seen)
1519
-
1520
- await runPikkuFunc('rpc', Math.random().toString(), 'paged', {
1521
- singletonServices: mockSingletonServices,
1522
- getAllServices: () => mockServices,
1523
- data: () => ({}),
1524
- auth: false,
1525
- wire: {},
1526
- })
1527
-
1528
- assert.equal(seen.data.page, 1)
1529
- assert.equal(seen.data.limit, 50)
1530
- })
1531
-
1532
- // `coerceDataFromSchema` is not passed here, exactly as a direct RPC
1533
- // invocation leaves it. Defaults belong to the schema rather than to the
1534
- // transport, so they must not ride on that flag — and a call made with no
1535
- // arguments at all still has to get them.
1536
- test('defaults apply with coercion off and no data', async () => {
1537
- const seen: { data?: any } = {}
1538
- addPagedFunction('pagedNoCoerce', seen)
1539
-
1540
- await runPikkuFunc('rpc', Math.random().toString(), 'pagedNoCoerce', {
1541
- singletonServices: mockSingletonServices,
1542
- getAllServices: () => mockServices,
1543
- data: () => undefined,
1544
- auth: false,
1545
- wire: {},
1546
- })
1547
-
1548
- assert.equal(seen.data.page, 1)
1549
- assert.equal(seen.data.limit, 50)
1550
- })
1551
-
1552
- test('a supplied value survives', async () => {
1553
- const seen: { data?: any } = {}
1554
- addPagedFunction('pagedSupplied', seen)
1555
-
1556
- await runPikkuFunc('rpc', Math.random().toString(), 'pagedSupplied', {
1557
- singletonServices: mockSingletonServices,
1558
- getAllServices: () => mockServices,
1559
- data: () => ({ page: 3 }),
1560
- auth: false,
1561
- wire: {},
1562
- })
1563
-
1564
- assert.equal(seen.data.page, 3)
1565
- assert.equal(seen.data.limit, 50)
1566
- })
1567
- })
1568
- })
1569
-
1570
- describe('runPikkuFunc - secrets', () => {
1571
- const singletonServicesWithSecrets = {
1572
- ...mockSingletonServices,
1573
- secrets: { getSecret: async () => 'super-secret' },
1574
- } as any
1575
-
1576
- const addSecretReadingFunction = (
1577
- funcName: string,
1578
- seen: { error?: unknown }
1579
- ) => {
1580
- addTestFunction(funcName, {
1581
- func: async (services: any) => {
1582
- try {
1583
- return services.secrets
1584
- } catch (error) {
1585
- seen.error = error
1586
- return 'denied'
1587
- }
1588
- },
1589
- })
1590
- }
1591
-
1592
- const run = (funcName: string) =>
1593
- runPikkuFunc('rpc', Math.random().toString(), funcName, {
1594
- singletonServices: singletonServicesWithSecrets,
1595
- getAllServices: () => singletonServicesWithSecrets,
1596
- data: () => ({}),
1597
- auth: false,
1598
- wire: {},
1599
- })
1600
-
1601
- test('a function never receives the secrets service', async () => {
1602
- const seen: { error?: unknown } = {}
1603
- addSecretReadingFunction('readsSecrets', seen)
1604
-
1605
- assert.equal(await run('readsSecrets'), 'denied')
1606
- assert.ok(seen.error instanceof SecretAccessDeniedError)
1607
- })
1608
-
1609
- test('no metadata flag can restore the secrets service', async () => {
1610
- const seen: { error?: unknown } = {}
1611
- addSecretReadingFunction('claimsAnExemption', seen)
1612
- Object.assign(pikkuState(null, 'function', 'meta')['claimsAnExemption']!, {
1613
- secretBroker: true,
1614
- })
1615
-
1616
- assert.equal(await run('claimsAnExemption'), 'denied')
1617
- assert.ok(seen.error instanceof SecretAccessDeniedError)
1618
- })
1619
- })