@pikku/core 0.12.107 → 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 (588) hide show
  1. package/CHANGELOG.md +344 -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/virtual-user/virtual-user-scaffold.d.ts +8 -8
  74. package/dist/wirings/virtual-user/virtual-user-schedule.d.ts +1 -1
  75. package/dist/wirings/workflow/workflow-queue-routing.d.ts +1 -1
  76. package/package.json +11 -5
  77. package/run-tests.sh +17 -9
  78. package/src/public-surface.json +26 -0
  79. package/src/agent-naming.test.ts +0 -68
  80. package/src/api-report.test.ts +0 -138
  81. package/src/app-alias-surface.test.ts +0 -179
  82. package/src/app-leaf-surface.test.ts +0 -222
  83. package/src/bootstrap-compat/root.ts +0 -20
  84. package/src/classification/column-form.test.ts +0 -97
  85. package/src/classification/column-form.ts +0 -55
  86. package/src/classification/data-classification.ts +0 -73
  87. package/src/classification/index.ts +0 -40
  88. package/src/classification/key-ids.ts +0 -2
  89. package/src/classification/secret-value.test.ts +0 -204
  90. package/src/classification/secret-value.ts +0 -106
  91. package/src/crypto-utils.test.ts +0 -668
  92. package/src/crypto-utils.ts +0 -460
  93. package/src/dev/hot-reload.test.ts +0 -587
  94. package/src/dev/hot-reload.ts +0 -225
  95. package/src/dev/module-runner.test.ts +0 -235
  96. package/src/dev/module-runner.ts +0 -138
  97. package/src/dev/reload-meta.test.ts +0 -183
  98. package/src/dev/reload-meta.ts +0 -144
  99. package/src/ecosystem-tier-removed.test.ts +0 -72
  100. package/src/env.ts +0 -1
  101. package/src/errors/error-handler.ts +0 -77
  102. package/src/errors/error.test.ts +0 -229
  103. package/src/errors/errors.ts +0 -393
  104. package/src/errors/index.ts +0 -11
  105. package/src/errors/serialized-error.ts +0 -12
  106. package/src/factory-functions.test.ts +0 -111
  107. package/src/function/abort-scope.test.ts +0 -97
  108. package/src/function/abort-scope.ts +0 -80
  109. package/src/function/function-meta.types.ts +0 -151
  110. package/src/function/function-runner.test.ts +0 -1619
  111. package/src/function/function-runner.ts +0 -499
  112. package/src/function/functions.types.ts +0 -319
  113. package/src/function/index.ts +0 -40
  114. package/src/function/list.types.test.ts +0 -100
  115. package/src/function/list.types.ts +0 -69
  116. package/src/function/pikku-request.test.ts +0 -35
  117. package/src/function/pikku-request.ts +0 -17
  118. package/src/gopass-secrets-removed.test.ts +0 -51
  119. package/src/handle-error.test.ts +0 -532
  120. package/src/handle-error.ts +0 -64
  121. package/src/middleware/auth-apikey.test.ts +0 -362
  122. package/src/middleware/auth-apikey.ts +0 -39
  123. package/src/middleware/auth-bearer.test.ts +0 -566
  124. package/src/middleware/auth-bearer.ts +0 -83
  125. package/src/middleware/auth-cookie.test.ts +0 -572
  126. package/src/middleware/auth-cookie.ts +0 -107
  127. package/src/middleware/cors.test.ts +0 -579
  128. package/src/middleware/cors.ts +0 -103
  129. package/src/middleware/index.ts +0 -30
  130. package/src/middleware/middleware-factories.ts +0 -76
  131. package/src/middleware/middleware.types.ts +0 -61
  132. package/src/middleware/remote-auth.test.ts +0 -547
  133. package/src/middleware/remote-auth.ts +0 -95
  134. package/src/middleware/remote-jobs-secret.ts +0 -35
  135. package/src/middleware/require-origin.test.ts +0 -115
  136. package/src/middleware/require-origin.ts +0 -79
  137. package/src/middleware/telemetry.ts +0 -83
  138. package/src/middleware-runner.test.ts +0 -578
  139. package/src/middleware-runner.ts +0 -232
  140. package/src/no-any-casts.test.ts +0 -57
  141. package/src/no-root-barrel.test.ts +0 -122
  142. package/src/permissions.test.ts +0 -256
  143. package/src/permissions.ts +0 -217
  144. package/src/pikku-state.test.ts +0 -198
  145. package/src/pikku-state.ts +0 -206
  146. package/src/production-barrels-stay-lean.test.ts +0 -110
  147. package/src/public-surface.test.ts +0 -133
  148. package/src/remote.test.ts +0 -173
  149. package/src/remote.ts +0 -56
  150. package/src/removed-legacy-exports.test.ts +0 -66
  151. package/src/run-tests-script.test.ts +0 -67
  152. package/src/schema.test.ts +0 -430
  153. package/src/schema.ts +0 -204
  154. package/src/scopes.test.ts +0 -203
  155. package/src/scopes.ts +0 -67
  156. package/src/services/agent-run-state-service.ts +0 -37
  157. package/src/services/agent-runner-service.ts +0 -238
  158. package/src/services/agent-storage-service.ts +0 -39
  159. package/src/services/ai-embedding-service.ts +0 -9
  160. package/src/services/audit-service.test.ts +0 -44
  161. package/src/services/audit-service.ts +0 -280
  162. package/src/services/content-service.ts +0 -65
  163. package/src/services/credential-service.ts +0 -20
  164. package/src/services/credential-wire-service.test.ts +0 -235
  165. package/src/services/credential-wire-service.ts +0 -120
  166. package/src/services/deployment-service.ts +0 -32
  167. package/src/services/email-service.test.ts +0 -100
  168. package/src/services/email-service.ts +0 -60
  169. package/src/services/email-template.test.ts +0 -311
  170. package/src/services/email-template.ts +0 -254
  171. package/src/services/file-scenario-run-store.test.ts +0 -349
  172. package/src/services/file-scenario-run-store.ts +0 -282
  173. package/src/services/gateway-service.ts +0 -5
  174. package/src/services/http-personas-converse.test.ts +0 -274
  175. package/src/services/http-personas.test.ts +0 -379
  176. package/src/services/http-personas.ts +0 -508
  177. package/src/services/in-memory-agent-run-state-service.ts +0 -87
  178. package/src/services/in-memory-queue-service.test.ts +0 -162
  179. package/src/services/in-memory-queue-service.ts +0 -78
  180. package/src/services/in-memory-session-store.test.ts +0 -58
  181. package/src/services/in-memory-session-store.ts +0 -20
  182. package/src/services/in-memory-trigger-service.ts +0 -47
  183. package/src/services/in-memory-workflow-service.test.ts +0 -430
  184. package/src/services/in-memory-workflow-service.ts +0 -595
  185. package/src/services/index.ts +0 -192
  186. package/src/services/istanbul-coverage-service.test.ts +0 -66
  187. package/src/services/istanbul-coverage-service.ts +0 -59
  188. package/src/services/jwt-service.ts +0 -15
  189. package/src/services/local-content-request-handler.test.ts +0 -240
  190. package/src/services/local-content-request-handler.ts +0 -295
  191. package/src/services/local-content.test.ts +0 -186
  192. package/src/services/local-content.ts +0 -242
  193. package/src/services/local-credential-service.ts +0 -63
  194. package/src/services/local-email-service.test.ts +0 -182
  195. package/src/services/local-email-service.ts +0 -43
  196. package/src/services/local-gateway-service.ts +0 -51
  197. package/src/services/local-secrets.test.ts +0 -95
  198. package/src/services/local-secrets.ts +0 -71
  199. package/src/services/local-variables.test.ts +0 -61
  200. package/src/services/local-variables.ts +0 -45
  201. package/src/services/logger-console.test.ts +0 -117
  202. package/src/services/logger-console.ts +0 -174
  203. package/src/services/logger.ts +0 -48
  204. package/src/services/meta-service.test.ts +0 -75
  205. package/src/services/meta-service.ts +0 -767
  206. package/src/services/persona-actor-secret.test.ts +0 -68
  207. package/src/services/persona-actor-secret.ts +0 -70
  208. package/src/services/persona-sign-in.test.ts +0 -219
  209. package/src/services/persona-sign-in.ts +0 -238
  210. package/src/services/personas-service.ts +0 -191
  211. package/src/services/pikku-user-id.test.ts +0 -62
  212. package/src/services/pikku-user-id.ts +0 -13
  213. package/src/services/queue-webhook-service.test.ts +0 -409
  214. package/src/services/queue-webhook-service.ts +0 -150
  215. package/src/services/remote-jobs.test.ts +0 -106
  216. package/src/services/remote-jobs.ts +0 -92
  217. package/src/services/scheduler-service.ts +0 -37
  218. package/src/services/schema-service.ts +0 -10
  219. package/src/services/scope-service.ts +0 -91
  220. package/src/services/scoped-credential-service.test.ts +0 -86
  221. package/src/services/scoped-credential-service.ts +0 -63
  222. package/src/services/scoped-secret-service.test.ts +0 -93
  223. package/src/services/scoped-secret-service.ts +0 -40
  224. package/src/services/secret-host-binding.test.ts +0 -138
  225. package/src/services/secret-host-binding.ts +0 -51
  226. package/src/services/secret-service.ts +0 -25
  227. package/src/services/secretless.test.ts +0 -54
  228. package/src/services/secretless.ts +0 -29
  229. package/src/services/session-store.ts +0 -9
  230. package/src/services/stub-tracker.test.ts +0 -104
  231. package/src/services/stub-tracker.ts +0 -175
  232. package/src/services/system-role-guard.test.ts +0 -96
  233. package/src/services/system-role-guard.ts +0 -71
  234. package/src/services/temporary-file-service.ts +0 -76
  235. package/src/services/trigger-service.ts +0 -5
  236. package/src/services/typed-credential-service.ts +0 -83
  237. package/src/services/typed-secret-service.test.ts +0 -204
  238. package/src/services/typed-secret-service.ts +0 -132
  239. package/src/services/typed-variables-service.test.ts +0 -166
  240. package/src/services/typed-variables-service.ts +0 -166
  241. package/src/services/user-session-service.test.ts +0 -147
  242. package/src/services/user-session-service.ts +0 -85
  243. package/src/services/v8-coverage-service.test.ts +0 -69
  244. package/src/services/v8-coverage-service.ts +0 -163
  245. package/src/services/variables-service.ts +0 -13
  246. package/src/services/webhook-service.ts +0 -147
  247. package/src/services/workflow-service.ts +0 -120
  248. package/src/side-effects-are-declared.test.ts +0 -84
  249. package/src/source-files-stay-composable.test.ts +0 -41
  250. package/src/template-alias-surface.test.ts +0 -240
  251. package/src/test-utils.ts +0 -38
  252. package/src/testing/index.ts +0 -3
  253. package/src/testing/service-tests/agent-run-service-tests.ts +0 -98
  254. package/src/testing/service-tests/agent-storage-service-tests.ts +0 -379
  255. package/src/testing/service-tests/channel-store-tests.ts +0 -98
  256. package/src/testing/service-tests/credential-service-tests.ts +0 -143
  257. package/src/testing/service-tests/deployment-service-tests.ts +0 -33
  258. package/src/testing/service-tests/event-hub-store-tests.ts +0 -48
  259. package/src/testing/service-tests/secret-service-tests.ts +0 -105
  260. package/src/testing/service-tests/session-store-tests.ts +0 -62
  261. package/src/testing/service-tests/workflow-run-service-tests.ts +0 -59
  262. package/src/testing/service-tests/workflow-service-tests.ts +0 -308
  263. package/src/testing/service-tests.ts +0 -95
  264. package/src/time-utils.test.ts +0 -56
  265. package/src/time-utils.ts +0 -89
  266. package/src/types/core.types.ts +0 -446
  267. package/src/types/index.ts +0 -25
  268. package/src/types/state.types.ts +0 -226
  269. package/src/types/typed-credentials.test.ts +0 -72
  270. package/src/utils/hash.test.ts +0 -68
  271. package/src/utils/hash.ts +0 -26
  272. package/src/utils/hmac.ts +0 -21
  273. package/src/utils/node-host-resolver.ts +0 -20
  274. package/src/utils/safe-fetch.test.ts +0 -515
  275. package/src/utils/safe-fetch.ts +0 -347
  276. package/src/utils.test.ts +0 -359
  277. package/src/utils.ts +0 -165
  278. package/src/version.test.ts +0 -80
  279. package/src/version.ts +0 -25
  280. package/src/wirings/actor-flow/actor-flow.types.ts +0 -40
  281. package/src/wirings/actor-flow/index.ts +0 -10
  282. package/src/wirings/actor-flow/run-conversation.test.ts +0 -187
  283. package/src/wirings/actor-flow/run-conversation.ts +0 -280
  284. package/src/wirings/addon/addon-auth-tags.test.ts +0 -219
  285. package/src/wirings/addon/addon-runner.ts +0 -236
  286. package/src/wirings/addon/addon-scopes.test.ts +0 -225
  287. package/src/wirings/addon/addon-secrets.test.ts +0 -391
  288. package/src/wirings/addon/index.ts +0 -12
  289. package/src/wirings/addon/remote-addon-auth.ts +0 -65
  290. package/src/wirings/addon/wire-addon.test.ts +0 -102
  291. package/src/wirings/addon/wire-addon.ts +0 -202
  292. package/src/wirings/addon/wire-remote-addon.ts +0 -41
  293. package/src/wirings/agent/agent-agui.test.ts +0 -1213
  294. package/src/wirings/agent/agent-agui.ts +0 -405
  295. package/src/wirings/agent/agent-authorization.test.ts +0 -208
  296. package/src/wirings/agent/agent-finalize.test.ts +0 -187
  297. package/src/wirings/agent/agent-finalize.ts +0 -197
  298. package/src/wirings/agent/agent-helpers.test.ts +0 -215
  299. package/src/wirings/agent/agent-helpers.ts +0 -96
  300. package/src/wirings/agent/agent-interrupt.test.ts +0 -833
  301. package/src/wirings/agent/agent-interrupt.ts +0 -400
  302. package/src/wirings/agent/agent-memory.test.ts +0 -397
  303. package/src/wirings/agent/agent-memory.ts +0 -496
  304. package/src/wirings/agent/agent-middleware.types.test.ts +0 -41
  305. package/src/wirings/agent/agent-model-config.test.ts +0 -103
  306. package/src/wirings/agent/agent-model-config.ts +0 -59
  307. package/src/wirings/agent/agent-prepare.test.ts +0 -977
  308. package/src/wirings/agent/agent-prepare.ts +0 -1083
  309. package/src/wirings/agent/agent-registry.test.ts +0 -455
  310. package/src/wirings/agent/agent-registry.ts +0 -99
  311. package/src/wirings/agent/agent-resume-authorization.test.ts +0 -206
  312. package/src/wirings/agent/agent-rpc.ts +0 -116
  313. package/src/wirings/agent/agent-runner.test.ts +0 -1229
  314. package/src/wirings/agent/agent-runner.ts +0 -858
  315. package/src/wirings/agent/agent-stream-delegate.test.ts +0 -381
  316. package/src/wirings/agent/agent-stream-output-hooks.test.ts +0 -353
  317. package/src/wirings/agent/agent-stream.test.ts +0 -1800
  318. package/src/wirings/agent/agent-stream.ts +0 -1639
  319. package/src/wirings/agent/agent-thread-ownership.test.ts +0 -297
  320. package/src/wirings/agent/agent-turn.test.ts +0 -65
  321. package/src/wirings/agent/agent-turn.ts +0 -122
  322. package/src/wirings/agent/agent-utils.ts +0 -20
  323. package/src/wirings/agent/agent.types.ts +0 -676
  324. package/src/wirings/agent/index.ts +0 -58
  325. package/src/wirings/agent/voice-input.test.ts +0 -220
  326. package/src/wirings/agent/voice-input.ts +0 -180
  327. package/src/wirings/agent/voice-output.test.ts +0 -510
  328. package/src/wirings/agent/voice-output.ts +0 -311
  329. package/src/wirings/agent-scorer/agent-scorer-grade.test.ts +0 -106
  330. package/src/wirings/agent-scorer/agent-scorer-grade.ts +0 -55
  331. package/src/wirings/agent-scorer/agent-scorer-judge.test.ts +0 -285
  332. package/src/wirings/agent-scorer/agent-scorer-judge.ts +0 -180
  333. package/src/wirings/agent-scorer/agent-scorer-live.test.ts +0 -174
  334. package/src/wirings/agent-scorer/agent-scorer-live.ts +0 -56
  335. package/src/wirings/agent-scorer/agent-scorer-registry.ts +0 -66
  336. package/src/wirings/agent-scorer/agent-scorer-sampling.test.ts +0 -34
  337. package/src/wirings/agent-scorer/agent-scorer-sampling.ts +0 -36
  338. package/src/wirings/agent-scorer/agent-scorer-snapshots.test.ts +0 -49
  339. package/src/wirings/agent-scorer/agent-scorer-snapshots.ts +0 -46
  340. package/src/wirings/agent-scorer/agent-scorer-worker.test.ts +0 -122
  341. package/src/wirings/agent-scorer/agent-scorer-worker.ts +0 -71
  342. package/src/wirings/agent-scorer/agent-scorer.ts +0 -102
  343. package/src/wirings/agent-scorer/agent-scorer.types.ts +0 -128
  344. package/src/wirings/agent-scorer/index.ts +0 -23
  345. package/src/wirings/channel/channel-common.ts +0 -102
  346. package/src/wirings/channel/channel-handler-shapes.test.ts +0 -72
  347. package/src/wirings/channel/channel-handler.test.ts +0 -322
  348. package/src/wirings/channel/channel-handler.ts +0 -259
  349. package/src/wirings/channel/channel-host-rpc.test.ts +0 -150
  350. package/src/wirings/channel/channel-host-rpc.ts +0 -69
  351. package/src/wirings/channel/channel-middleware-runner.test.ts +0 -188
  352. package/src/wirings/channel/channel-middleware-runner.ts +0 -126
  353. package/src/wirings/channel/channel-rpc-registry.ts +0 -116
  354. package/src/wirings/channel/channel-rpc-responder.ts +0 -117
  355. package/src/wirings/channel/channel-rpc-service.ts +0 -132
  356. package/src/wirings/channel/channel-rpc-validators.ts +0 -65
  357. package/src/wirings/channel/channel-rpc.test.ts +0 -841
  358. package/src/wirings/channel/channel-rpc.ts +0 -5
  359. package/src/wirings/channel/channel-rpc.types.ts +0 -160
  360. package/src/wirings/channel/channel-runner.ts +0 -164
  361. package/src/wirings/channel/channel-store.ts +0 -35
  362. package/src/wirings/channel/channel.types.ts +0 -193
  363. package/src/wirings/channel/define-channel-routes.ts +0 -5
  364. package/src/wirings/channel/eventhub-service.ts +0 -16
  365. package/src/wirings/channel/eventhub-store.ts +0 -13
  366. package/src/wirings/channel/index.ts +0 -40
  367. package/src/wirings/channel/local/index.ts +0 -3
  368. package/src/wirings/channel/local/local-channel-handler.ts +0 -98
  369. package/src/wirings/channel/local/local-channel-runner.test.ts +0 -339
  370. package/src/wirings/channel/local/local-channel-runner.ts +0 -271
  371. package/src/wirings/channel/local/local-eventhub-service.test.ts +0 -77
  372. package/src/wirings/channel/local/local-eventhub-service.ts +0 -69
  373. package/src/wirings/channel/log-channels.ts +0 -16
  374. package/src/wirings/channel/pikku-abstract-channel-handler.test.ts +0 -135
  375. package/src/wirings/channel/pikku-abstract-channel-handler.ts +0 -60
  376. package/src/wirings/channel/serverless/index.ts +0 -6
  377. package/src/wirings/channel/serverless/serverless-channel-runner.ts +0 -328
  378. package/src/wirings/cli/channel/cli-approval.test.ts +0 -177
  379. package/src/wirings/cli/channel/cli-approval.ts +0 -135
  380. package/src/wirings/cli/channel/cli-channel-runner.ts +0 -118
  381. package/src/wirings/cli/channel/cli-raw-channel-runner.test.ts +0 -192
  382. package/src/wirings/cli/channel/cli-raw-channel-runner.ts +0 -148
  383. package/src/wirings/cli/channel/cli-raw-client-runner.test.ts +0 -480
  384. package/src/wirings/cli/channel/cli-raw-client-runner.ts +0 -188
  385. package/src/wirings/cli/channel/index.ts +0 -6
  386. package/src/wirings/cli/cli-runner.test.ts +0 -969
  387. package/src/wirings/cli/cli-runner.ts +0 -538
  388. package/src/wirings/cli/cli.types.ts +0 -388
  389. package/src/wirings/cli/command-parser.test.ts +0 -1120
  390. package/src/wirings/cli/command-parser.ts +0 -713
  391. package/src/wirings/cli/define-cli-commands.ts +0 -13
  392. package/src/wirings/cli/format-cli-error.test.ts +0 -91
  393. package/src/wirings/cli/format-cli-error.ts +0 -96
  394. package/src/wirings/cli/index.ts +0 -19
  395. package/src/wirings/credential/credential.types.ts +0 -37
  396. package/src/wirings/credential/define-credential.ts +0 -49
  397. package/src/wirings/credential/index.ts +0 -7
  398. package/src/wirings/credential/validate-credential-definitions.ts +0 -63
  399. package/src/wirings/gateway/gateway-authorization.test.ts +0 -575
  400. package/src/wirings/gateway/gateway-channel-meta.test.ts +0 -44
  401. package/src/wirings/gateway/gateway-runner.test.ts +0 -581
  402. package/src/wirings/gateway/gateway-runner.ts +0 -411
  403. package/src/wirings/gateway/gateway.types.ts +0 -137
  404. package/src/wirings/gateway/index.ts +0 -15
  405. package/src/wirings/http/http-routes.test.ts +0 -318
  406. package/src/wirings/http/http-routes.ts +0 -111
  407. package/src/wirings/http/http-runner-addon-ref.test.ts +0 -238
  408. package/src/wirings/http/http-runner.test.ts +0 -503
  409. package/src/wirings/http/http-runner.ts +0 -462
  410. package/src/wirings/http/http.types.ts +0 -307
  411. package/src/wirings/http/index.ts +0 -27
  412. package/src/wirings/http/log-http-routes.ts +0 -18
  413. package/src/wirings/http/pikku-fetch-http-request.test.ts +0 -318
  414. package/src/wirings/http/pikku-fetch-http-request.ts +0 -260
  415. package/src/wirings/http/pikku-fetch-http-response.test.ts +0 -123
  416. package/src/wirings/http/pikku-fetch-http-response.ts +0 -149
  417. package/src/wirings/http/routers/http-router.ts +0 -13
  418. package/src/wirings/http/routers/path-to-regex.test.ts +0 -306
  419. package/src/wirings/http/routers/path-to-regex.ts +0 -115
  420. package/src/wirings/http/web-request.test.ts +0 -382
  421. package/src/wirings/http/web-request.ts +0 -162
  422. package/src/wirings/mcp/index.ts +0 -26
  423. package/src/wirings/mcp/mcp-endpoint-registry.test.ts +0 -388
  424. package/src/wirings/mcp/mcp-endpoint-registry.ts +0 -159
  425. package/src/wirings/mcp/mcp-runner.test.ts +0 -588
  426. package/src/wirings/mcp/mcp-runner.ts +0 -330
  427. package/src/wirings/mcp/mcp.types.ts +0 -199
  428. package/src/wirings/node/index.ts +0 -2
  429. package/src/wirings/node/node.types.ts +0 -23
  430. package/src/wirings/oauth2/index.ts +0 -1
  431. package/src/wirings/oauth2/oauth2.types.ts +0 -12
  432. package/src/wirings/persona/define-personas.ts +0 -33
  433. package/src/wirings/persona/index.ts +0 -75
  434. package/src/wirings/persona/persona-app-scopes.test.ts +0 -47
  435. package/src/wirings/persona/persona-app-scopes.ts +0 -74
  436. package/src/wirings/persona/persona-email.ts +0 -87
  437. package/src/wirings/persona/persona-environments.test.ts +0 -194
  438. package/src/wirings/persona/persona-environments.ts +0 -138
  439. package/src/wirings/persona/persona-mailbox.ts +0 -156
  440. package/src/wirings/persona/persona.test.ts +0 -230
  441. package/src/wirings/persona/persona.types.ts +0 -156
  442. package/src/wirings/persona/validate-personas.ts +0 -137
  443. package/src/wirings/queue/index.ts +0 -29
  444. package/src/wirings/queue/queue-identity.test.ts +0 -454
  445. package/src/wirings/queue/queue-identity.ts +0 -176
  446. package/src/wirings/queue/queue-runner.test.ts +0 -705
  447. package/src/wirings/queue/queue-runner.ts +0 -181
  448. package/src/wirings/queue/queue.types.ts +0 -161
  449. package/src/wirings/queue/register-queue-helper.ts +0 -46
  450. package/src/wirings/queue/signed-queue-service.ts +0 -60
  451. package/src/wirings/queue/validate-worker-config.test.ts +0 -108
  452. package/src/wirings/queue/validate-worker-config.ts +0 -90
  453. package/src/wirings/role/define-system-role.ts +0 -33
  454. package/src/wirings/role/index.ts +0 -13
  455. package/src/wirings/role/role.test.ts +0 -104
  456. package/src/wirings/role/role.types.ts +0 -47
  457. package/src/wirings/role/validate-role-definitions.ts +0 -93
  458. package/src/wirings/rpc/index.ts +0 -8
  459. package/src/wirings/rpc/rpc-runner.test.ts +0 -1130
  460. package/src/wirings/rpc/rpc-runner.ts +0 -569
  461. package/src/wirings/rpc/rpc-types.ts +0 -87
  462. package/src/wirings/scheduler/index.ts +0 -11
  463. package/src/wirings/scheduler/log-schedulers.ts +0 -16
  464. package/src/wirings/scheduler/scheduler-runner.test.ts +0 -835
  465. package/src/wirings/scheduler/scheduler-runner.ts +0 -138
  466. package/src/wirings/scheduler/scheduler.types.ts +0 -42
  467. package/src/wirings/scope/define-scope.ts +0 -33
  468. package/src/wirings/scope/index.ts +0 -15
  469. package/src/wirings/scope/scope.test.ts +0 -159
  470. package/src/wirings/scope/scope.types.ts +0 -42
  471. package/src/wirings/scope/validate-scope-definitions.ts +0 -107
  472. package/src/wirings/secret/index.ts +0 -9
  473. package/src/wirings/secret/secret.types.ts +0 -70
  474. package/src/wirings/secret/validate-secret-definitions.test.ts +0 -232
  475. package/src/wirings/secret/validate-secret-definitions.ts +0 -88
  476. package/src/wirings/trigger/index.ts +0 -9
  477. package/src/wirings/trigger/pikku-trigger-service.ts +0 -107
  478. package/src/wirings/trigger/trigger-runner.test.ts +0 -78
  479. package/src/wirings/trigger/trigger-runner.ts +0 -113
  480. package/src/wirings/trigger/trigger.types.ts +0 -100
  481. package/src/wirings/variable/index.ts +0 -8
  482. package/src/wirings/variable/validate-variable-definitions.test.ts +0 -115
  483. package/src/wirings/variable/validate-variable-definitions.ts +0 -71
  484. package/src/wirings/variable/variable.types.ts +0 -40
  485. package/src/wirings/virtual-user/index.ts +0 -107
  486. package/src/wirings/virtual-user/prepare-virtual-user-run.test.ts +0 -115
  487. package/src/wirings/virtual-user/prepare-virtual-user-run.ts +0 -95
  488. package/src/wirings/virtual-user/run-virtual-user.test.ts +0 -774
  489. package/src/wirings/virtual-user/run-virtual-user.ts +0 -684
  490. package/src/wirings/virtual-user/virtual-user-agents.test.ts +0 -72
  491. package/src/wirings/virtual-user/virtual-user-agents.ts +0 -62
  492. package/src/wirings/virtual-user/virtual-user-catalogue.test.ts +0 -215
  493. package/src/wirings/virtual-user/virtual-user-catalogue.ts +0 -184
  494. package/src/wirings/virtual-user/virtual-user-derive.test.ts +0 -426
  495. package/src/wirings/virtual-user/virtual-user-derive.ts +0 -161
  496. package/src/wirings/virtual-user/virtual-user-dispositions.test.ts +0 -68
  497. package/src/wirings/virtual-user/virtual-user-dispositions.ts +0 -210
  498. package/src/wirings/virtual-user/virtual-user-intents.test.ts +0 -218
  499. package/src/wirings/virtual-user/virtual-user-intents.ts +0 -185
  500. package/src/wirings/virtual-user/virtual-user-rng.test.ts +0 -72
  501. package/src/wirings/virtual-user/virtual-user-rng.ts +0 -50
  502. package/src/wirings/virtual-user/virtual-user-run-store.ts +0 -131
  503. package/src/wirings/virtual-user/virtual-user-scaffold.test.ts +0 -854
  504. package/src/wirings/virtual-user/virtual-user-scaffold.ts +0 -664
  505. package/src/wirings/virtual-user/virtual-user-schedule-store.ts +0 -93
  506. package/src/wirings/virtual-user/virtual-user-schedule.test.ts +0 -280
  507. package/src/wirings/virtual-user/virtual-user-schedule.ts +0 -156
  508. package/src/wirings/virtual-user/virtual-user-target.ts +0 -47
  509. package/src/wirings/virtual-user/virtual-user.types.ts +0 -215
  510. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +0 -709
  511. package/src/wirings/workflow/dsl/workflow-runner.ts +0 -25
  512. package/src/wirings/workflow/feature.test.ts +0 -131
  513. package/src/wirings/workflow/feature.ts +0 -59
  514. package/src/wirings/workflow/graph/graph-foreach-queued.test.ts +0 -569
  515. package/src/wirings/workflow/graph/graph-foreach.test.ts +0 -626
  516. package/src/wirings/workflow/graph/graph-node.ts +0 -115
  517. package/src/wirings/workflow/graph/graph-runner.test.ts +0 -1049
  518. package/src/wirings/workflow/graph/graph-runner.ts +0 -1376
  519. package/src/wirings/workflow/graph/graph-validation.test.ts +0 -27
  520. package/src/wirings/workflow/graph/graph-validation.ts +0 -41
  521. package/src/wirings/workflow/graph/template.test.ts +0 -49
  522. package/src/wirings/workflow/graph/template.ts +0 -42
  523. package/src/wirings/workflow/graph/wire-workflow-graph.ts +0 -39
  524. package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -75
  525. package/src/wirings/workflow/index.ts +0 -107
  526. package/src/wirings/workflow/pikku-scenario-service.ts +0 -1013
  527. package/src/wirings/workflow/pikku-workflow-service.test.ts +0 -963
  528. package/src/wirings/workflow/pikku-workflow-service.ts +0 -1993
  529. package/src/wirings/workflow/run-timeline.test.ts +0 -199
  530. package/src/wirings/workflow/run-timeline.ts +0 -185
  531. package/src/wirings/workflow/scenario-cookie-jar.test.ts +0 -107
  532. package/src/wirings/workflow/scenario-cookie-jar.ts +0 -57
  533. package/src/wirings/workflow/scenario-expectations.test.ts +0 -238
  534. package/src/wirings/workflow/scenario-hooks.test.ts +0 -259
  535. package/src/wirings/workflow/scenario-poll.test.ts +0 -64
  536. package/src/wirings/workflow/scenario-poll.ts +0 -27
  537. package/src/wirings/workflow/scenario-prose.test.ts +0 -275
  538. package/src/wirings/workflow/scenario-prose.ts +0 -86
  539. package/src/wirings/workflow/scenario-run.types.ts +0 -193
  540. package/src/wirings/workflow/scenario-service.test.ts +0 -147
  541. package/src/wirings/workflow/scenario-step-guards.ts +0 -23
  542. package/src/wirings/workflow/scenario-step.test.ts +0 -800
  543. package/src/wirings/workflow/scenario-step.types.ts +0 -262
  544. package/src/wirings/workflow/scenario-surface.test.ts +0 -146
  545. package/src/wirings/workflow/scenario-surface.ts +0 -71
  546. package/src/wirings/workflow/scenario.types.ts +0 -63
  547. package/src/wirings/workflow/workflow-approval-audit.ts +0 -47
  548. package/src/wirings/workflow/workflow-approval-policy.test.ts +0 -594
  549. package/src/wirings/workflow/workflow-approval-policy.ts +0 -68
  550. package/src/wirings/workflow/workflow-approval.ts +0 -290
  551. package/src/wirings/workflow/workflow-child-run-session.test.ts +0 -168
  552. package/src/wirings/workflow/workflow-constants.ts +0 -66
  553. package/src/wirings/workflow/workflow-dispatch-durability.test.ts +0 -116
  554. package/src/wirings/workflow/workflow-dispatch-payload.test.ts +0 -55
  555. package/src/wirings/workflow/workflow-dispatch-relay.test.ts +0 -128
  556. package/src/wirings/workflow/workflow-errors.ts +0 -132
  557. package/src/wirings/workflow/workflow-inline-authority.test.ts +0 -175
  558. package/src/wirings/workflow/workflow-invocation-id.test.ts +0 -51
  559. package/src/wirings/workflow/workflow-invocation-id.ts +0 -28
  560. package/src/wirings/workflow/workflow-meta-resolver.ts +0 -45
  561. package/src/wirings/workflow/workflow-mirror.test.ts +0 -171
  562. package/src/wirings/workflow/workflow-missing-meta.test.ts +0 -92
  563. package/src/wirings/workflow/workflow-on-error.test.ts +0 -145
  564. package/src/wirings/workflow/workflow-queue-routing.ts +0 -129
  565. package/src/wirings/workflow/workflow-queue-wiring.ts +0 -149
  566. package/src/wirings/workflow/workflow-queue-workers.test.ts +0 -131
  567. package/src/wirings/workflow/workflow-queue-workers.ts +0 -66
  568. package/src/wirings/workflow/workflow-recovery.ts +0 -192
  569. package/src/wirings/workflow/workflow-replay-snapshot.test.ts +0 -140
  570. package/src/wirings/workflow/workflow-retry-policy.test.ts +0 -113
  571. package/src/wirings/workflow/workflow-run-authority.test.ts +0 -212
  572. package/src/wirings/workflow/workflow-run-context.test.ts +0 -172
  573. package/src/wirings/workflow/workflow-run-engine.types.ts +0 -92
  574. package/src/wirings/workflow/workflow-run-ownership.ts +0 -37
  575. package/src/wirings/workflow/workflow-run-polling.test.ts +0 -127
  576. package/src/wirings/workflow/workflow-stalled-recovery.test.ts +0 -152
  577. package/src/wirings/workflow/workflow-status-stream.test.ts +0 -354
  578. package/src/wirings/workflow/workflow-status-stream.ts +0 -144
  579. package/src/wirings/workflow/workflow-step-claim.ts +0 -46
  580. package/src/wirings/workflow/workflow-step-ordinal.test.ts +0 -94
  581. package/src/wirings/workflow/workflow-step-session.test.ts +0 -87
  582. package/src/wirings/workflow/workflow-suspend.ts +0 -61
  583. package/src/wirings/workflow/workflow-terminal-run-guard.test.ts +0 -105
  584. package/src/wirings/workflow/workflow.types.ts +0 -268
  585. package/src/wirings-stay-decoupled.test.ts +0 -130
  586. package/tsconfig.json +0 -14
  587. package/tsconfig.tsbuildinfo +0 -1
  588. 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
- })