@pikku/core 0.12.141 → 0.12.142

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 (237) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/dist/errors/errors.d.ts +1 -1
  3. package/dist/errors/errors.js +1 -1
  4. package/dist/function/function-meta.types.d.ts +6 -6
  5. package/dist/function/functions.types.d.ts +2 -2
  6. package/dist/services/audit-service.d.ts +4 -4
  7. package/dist/services/feature-flag-service.d.ts +3 -3
  8. package/dist/services/{http-personas.d.ts → http-virtual-users.d.ts} +25 -47
  9. package/dist/services/{http-personas.js → http-virtual-users.js} +29 -53
  10. package/dist/services/index.d.ts +2 -2
  11. package/dist/services/index.js +1 -1
  12. package/dist/services/meta-service.d.ts +6 -6
  13. package/dist/services/meta-service.js +8 -8
  14. package/dist/{wirings/workflow → services}/scenario-cookie-jar.d.ts +2 -0
  15. package/dist/{wirings/workflow → services}/scenario-cookie-jar.js +18 -14
  16. package/dist/services/system-role-guard.d.ts +1 -1
  17. package/dist/services/virtual-user-sign-in.d.ts +52 -0
  18. package/dist/services/virtual-user-sign-in.js +80 -0
  19. package/dist/services/virtual-user-statement.d.ts +31 -0
  20. package/dist/services/virtual-user-statement.js +24 -0
  21. package/dist/services/{personas-service.d.ts → virtual-users-service.d.ts} +25 -23
  22. package/dist/services/{personas-service.js → virtual-users-service.js} +3 -3
  23. package/dist/types/core.types.d.ts +11 -11
  24. package/dist/wirings/role/define-system-role.d.ts +1 -1
  25. package/dist/wirings/role/define-system-role.js +1 -1
  26. package/dist/wirings/{actor-flow/actor-flow.types.d.ts → virtual-user/conversation/conversation.types.d.ts} +5 -5
  27. package/dist/wirings/virtual-user/conversation/index.d.ts +2 -0
  28. package/dist/wirings/virtual-user/conversation/run-conversation.d.ts +36 -0
  29. package/dist/wirings/{actor-flow → virtual-user/conversation}/run-conversation.js +30 -30
  30. package/dist/wirings/virtual-user/define-virtual-users.d.ts +32 -0
  31. package/dist/wirings/{persona/define-personas.js → virtual-user/define-virtual-users.js} +9 -9
  32. package/dist/wirings/virtual-user/index.d.ts +30 -7
  33. package/dist/wirings/virtual-user/index.js +23 -4
  34. package/dist/wirings/virtual-user/prepare-virtual-user-run.d.ts +8 -8
  35. package/dist/wirings/virtual-user/prepare-virtual-user-run.js +9 -9
  36. package/dist/wirings/virtual-user/run-virtual-user.d.ts +6 -6
  37. package/dist/wirings/virtual-user/run-virtual-user.js +10 -10
  38. package/dist/wirings/{persona/validate-personas.d.ts → virtual-user/validate-virtual-users.d.ts} +11 -11
  39. package/dist/wirings/{persona/validate-personas.js → virtual-user/validate-virtual-users.js} +24 -24
  40. package/dist/wirings/virtual-user/virtual-user-agents.d.ts +7 -7
  41. package/dist/wirings/virtual-user/virtual-user-agents.js +2 -2
  42. package/dist/wirings/{persona/persona-app-scopes.d.ts → virtual-user/virtual-user-app-scopes.d.ts} +10 -10
  43. package/dist/wirings/{persona/persona-app-scopes.js → virtual-user/virtual-user-app-scopes.js} +12 -12
  44. package/dist/wirings/virtual-user/virtual-user-catalogue.d.ts +3 -3
  45. package/dist/wirings/virtual-user/virtual-user-catalogue.js +2 -2
  46. package/dist/wirings/{persona/persona.types.d.ts → virtual-user/virtual-user-declaration.types.d.ts} +24 -24
  47. package/dist/wirings/virtual-user/virtual-user-derive.js +13 -7
  48. package/dist/wirings/virtual-user/virtual-user-dispositions.d.ts +1 -1
  49. package/dist/wirings/{persona/persona-email.d.ts → virtual-user/virtual-user-email.d.ts} +11 -11
  50. package/dist/wirings/{persona/persona-email.js → virtual-user/virtual-user-email.js} +19 -19
  51. package/dist/wirings/{persona/persona-environments.d.ts → virtual-user/virtual-user-environments.d.ts} +10 -10
  52. package/dist/wirings/{persona/persona-environments.js → virtual-user/virtual-user-environments.js} +21 -21
  53. package/dist/wirings/virtual-user/virtual-user-intents.d.ts +3 -3
  54. package/dist/wirings/virtual-user/virtual-user-intents.js +3 -3
  55. package/dist/wirings/{persona/persona-mailbox.d.ts → virtual-user/virtual-user-mailbox.d.ts} +4 -4
  56. package/dist/wirings/virtual-user/virtual-user-run-store.d.ts +4 -4
  57. package/dist/wirings/virtual-user/virtual-user-scaffold.d.ts +42 -61
  58. package/dist/wirings/virtual-user/virtual-user-scaffold.js +69 -117
  59. package/dist/wirings/virtual-user/virtual-user-schedule-store.d.ts +15 -15
  60. package/dist/wirings/virtual-user/virtual-user-schedule.d.ts +6 -6
  61. package/dist/wirings/virtual-user/virtual-user-schedule.js +11 -11
  62. package/dist/wirings/virtual-user/virtual-user-target.d.ts +6 -6
  63. package/dist/wirings/virtual-user/virtual-user-target.js +5 -5
  64. package/dist/wirings/virtual-user/virtual-user.types.d.ts +11 -11
  65. package/dist/wirings/virtual-user/virtual-user.types.js +1 -1
  66. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +9 -9
  67. package/dist/wirings/workflow/pikku-scenario-service.d.ts +28 -28
  68. package/dist/wirings/workflow/pikku-scenario-service.js +77 -77
  69. package/dist/wirings/workflow/pikku-workflow-service.d.ts +2 -2
  70. package/dist/wirings/workflow/pikku-workflow-service.js +4 -4
  71. package/dist/wirings/workflow/scenario-prose.d.ts +8 -8
  72. package/dist/wirings/workflow/scenario-prose.js +12 -8
  73. package/dist/wirings/workflow/scenario-run.types.d.ts +13 -13
  74. package/dist/wirings/workflow/scenario-step.types.d.ts +23 -23
  75. package/dist/wirings/workflow/workflow.types.d.ts +2 -2
  76. package/knowledge/decisions/index.md +0 -2
  77. package/knowledge/decisions/internals/a-credential-name-declared-twice-must-agree-on-schema-and-type.md +29 -0
  78. package/knowledge/decisions/internals/a-grant-can-name-a-scope-declared-without-its-addon.md +29 -0
  79. package/knowledge/decisions/internals/a-scheduled-task-writes-its-caller-session-before-it-runs.md +22 -0
  80. package/knowledge/decisions/internals/a-secret-set-in-memory-shadows-the-variable-of-the-same-name.md +28 -0
  81. package/knowledge/decisions/internals/a-virtual-user-acts-through-invokeraw-so-a-refusal-is-data.md +32 -0
  82. package/knowledge/decisions/internals/a-virtual-user-cadence-is-a-row-not-a-timer.md +12 -12
  83. package/knowledge/decisions/internals/a-virtual-user-converse-signs-in-before-its-first-turn.md +24 -0
  84. package/knowledge/decisions/internals/a-virtual-user-email-is-computed-with-the-run-id-as-a-sub-address.md +34 -0
  85. package/knowledge/decisions/internals/a-virtual-user-run-is-not-a-workflow-but-it-needs-a-trigger.md +2 -2
  86. package/knowledge/decisions/internals/an-agent-is-offered-under-its-registry-key-and-only-within-the-virtual-users-scopes.md +27 -0
  87. package/knowledge/decisions/internals/an-oauth2-credential-implies-an-optional-app-secret.md +26 -0
  88. package/knowledge/decisions/internals/analytics-identity-resolvers-run-in-declared-order.md +22 -0
  89. package/knowledge/decisions/internals/feature-flag-declarations-refuse-an-empty-anyof-and-conflicting-scopes.md +22 -0
  90. package/knowledge/decisions/internals/feature-flags-fail-open-and-never-enforce-access.md +28 -0
  91. package/knowledge/decisions/internals/flag-sync-rewrites-only-the-declared-text.md +24 -0
  92. package/knowledge/decisions/internals/in-a-scenario-a-4xx-is-data-not-an-exception.md +3 -3
  93. package/knowledge/decisions/internals/index.md +46 -31
  94. package/knowledge/decisions/internals/one-project-shape-check-two-validators.md +10 -10
  95. package/knowledge/decisions/internals/role-names-cannot-contain-the-scope-separator.md +30 -0
  96. package/knowledge/decisions/internals/scenario-agent-calls-sign-in-on-401-only.md +23 -19
  97. package/knowledge/decisions/internals/scenario-steps-return-drained-response-records.md +2 -2
  98. package/knowledge/decisions/internals/scenarios-live-in-files-named-for-them.md +12 -12
  99. package/knowledge/decisions/internals/the-core-scope-validator-refuses-separator-wildcard-and-empty-segments.md +22 -0
  100. package/knowledge/decisions/internals/the-pikku-user-id-resolves-in-a-fixed-order.md +24 -0
  101. package/knowledge/decisions/internals/{the-actor-prompt-says-json-because-of-json-object-mode.md → the-virtual-user-prompt-says-json-because-of-json-object-mode.md} +4 -4
  102. package/knowledge/decisions/internals/{the-persona-runtime-is-exported-from-the-persona-entry-point.md → the-virtual-user-runtime-is-exported-from-the-virtual-user-entry-point.md} +8 -8
  103. package/knowledge/decisions/internals/validate-checks-virtual-users-through-a-shared-module.md +43 -0
  104. package/knowledge/decisions/internals/{actor-flow-drives-the-target-through-a-transport-seam.md → virtual-user-conversation-drives-the-target-through-a-transport-seam.md} +6 -6
  105. package/knowledge/decisions/internals/virtual-user-conversation-verdicts-are-llm-self-evaluations.md +25 -0
  106. package/knowledge/decisions/internals/virtual-user-conversations-seed-a-hidden-kickoff-message.md +23 -0
  107. package/knowledge/decisions/internals/virtual-users-are-declared-in-one-definevirtualusers-call-per-codebase.md +30 -0
  108. package/knowledge/decisions/internals/workflow-core-never-imports-a-browser-driver.md +5 -5
  109. package/knowledge/decisions/internals/workflow-run-capabilities-are-extensions-not-subclasses.md +2 -2
  110. package/knowledge/decisions/internals/workflow-scenario-assertions-never-retry-and-record-one-step.md +4 -4
  111. package/knowledge/decisions/internals/workflow-scenario-hooks-are-a-scenario-only-affordance.md +1 -1
  112. package/knowledge/decisions/internals/workflow-scenario-prose-is-rendered-from-typed-calls-not-parsed-from-english.md +2 -2
  113. package/knowledge/decisions/internals/workflow-scenario-step-targets-are-string-literals-for-the-inspector.md +1 -1
  114. package/knowledge/decisions/internals/workflow-suspended-runs-keep-their-in-process-context.md +1 -1
  115. package/knowledge/decisions/security/a-bearer-token-checked-against-a-secret-reads-it-per-request.md +26 -0
  116. package/knowledge/decisions/security/a-call-without-a-session-raises-missing-session-not-forbidden.md +20 -0
  117. package/knowledge/decisions/security/a-caller-cookie-wins-over-the-jar-for-the-same-name.md +23 -0
  118. package/knowledge/decisions/security/a-channel-lifecycle-acts-as-the-socket-upgrade-session.md +16 -0
  119. package/knowledge/decisions/security/a-channel-requires-a-session-unless-it-says-auth-false.md +26 -0
  120. package/knowledge/decisions/security/a-credential-read-path-follows-its-declared-type-not-absence.md +32 -0
  121. package/knowledge/decisions/security/a-credential-type-is-a-literal-the-inspector-checks-at-declaration.md +27 -0
  122. package/knowledge/decisions/security/a-first-party-cookie-is-written-only-after-its-purposes-consent.md +33 -0
  123. package/knowledge/decisions/security/a-readonly-session-reaches-only-readonly-functions.md +25 -0
  124. package/knowledge/decisions/security/a-scaffold-flag-says-a-surface-exists-not-who-may-call-it.md +10 -5
  125. package/knowledge/decisions/security/a-scheduled-virtual-user-run-needs-no-admin-at-run-time.md +27 -0
  126. package/knowledge/decisions/security/a-scoped-credential-view-is-limited-to-declared-names.md +26 -0
  127. package/knowledge/decisions/security/a-scoped-secret-view-reads-only-declared-keys-and-never-writes.md +25 -0
  128. package/knowledge/decisions/security/a-secret-is-sent-only-to-the-hosts-it-declares.md +29 -0
  129. package/knowledge/decisions/security/a-step-can-name-an-identity-no-virtual-user-holds-through-per-call-headers.md +25 -0
  130. package/knowledge/decisions/security/a-stopped-run-by-id-skips-the-ownership-check.md +24 -0
  131. package/knowledge/decisions/security/a-vault-secret-redacts-on-serialization-and-throws-on-coercion.md +29 -0
  132. package/knowledge/decisions/security/a-virtual-user-catalogue-entry-is-filtered-by-scope-and-approval-is-denied-by-default.md +30 -0
  133. package/knowledge/decisions/security/a-virtual-user-environment-fails-closed.md +38 -0
  134. package/knowledge/decisions/security/a-virtual-user-never-runs-against-production.md +23 -0
  135. package/knowledge/decisions/security/a-virtual-user-reads-its-roles-from-the-apps-own-rpc-before-better-auth.md +27 -0
  136. package/knowledge/decisions/security/a-virtual-user-run-treats-an-unresolved-environment-as-production.md +41 -0
  137. package/knowledge/decisions/security/a-virtual-user-scopes-are-expanded-from-its-roles-once-at-run-preparation.md +25 -0
  138. package/knowledge/decisions/security/a-virtual-user-whose-roles-drift-from-the-declaration-refuses-to-run.md +32 -0
  139. package/knowledge/decisions/security/addon-screen-scopes-hide-and-do-not-enforce.md +20 -0
  140. package/knowledge/decisions/security/an-addon-header-can-only-narrow-the-session.md +26 -0
  141. package/knowledge/decisions/security/an-addon-instance-reads-only-the-secrets-and-credentials-it-is-named.md +33 -0
  142. package/knowledge/decisions/security/an-addon-may-reach-only-itself-and-the-addons-it-uses.md +16 -0
  143. package/knowledge/decisions/security/an-api-key-is-jwt-decoded-into-the-session.md +26 -0
  144. package/knowledge/decisions/security/an-external-virtual-user-caller-presents-one-signed-statement.md +38 -0
  145. package/knowledge/decisions/security/an-inbound-webhook-source-dispatches-only-verified-requests.md +31 -0
  146. package/knowledge/decisions/security/an-mcp-call-with-no-http-request-stays-anonymous.md +18 -0
  147. package/knowledge/decisions/security/an-omitted-user-id-addresses-the-platform-credential.md +32 -0
  148. package/knowledge/decisions/security/analytics-identity-is-stamped-from-the-session-not-the-event.md +24 -0
  149. package/knowledge/decisions/security/app-access-is-a-scope-tree-synthesised-from-virtual-users.md +26 -0
  150. package/knowledge/decisions/security/approval-policy-decides-who-answers-a-tool-call.md +27 -0
  151. package/knowledge/decisions/security/auth-false-on-a-session-function-warns-and-still-requires-one.md +25 -0
  152. package/knowledge/decisions/security/bearer-token-hashes-are-unpeppered-sha256.md +18 -0
  153. package/knowledge/decisions/security/consent-is-read-from-a-cookie-and-a-recognised-denial-counts-as-refusal.md +29 -0
  154. package/knowledge/decisions/security/cors-defaults-to-any-origin-and-refuses-the-wildcard-with-credentials.md +22 -0
  155. package/knowledge/decisions/security/credential-backends-share-one-conformance-suite-for-per-user-isolation.md +29 -0
  156. package/knowledge/decisions/security/each-stage-has-one-virtual-user-key-pair.md +27 -0
  157. package/knowledge/decisions/security/hmac-verification-fails-closed-on-empty-inputs.md +25 -0
  158. package/knowledge/decisions/security/index.md +88 -24
  159. package/knowledge/decisions/security/local-content-refuses-private-buckets-under-the-public-segment.md +21 -0
  160. package/knowledge/decisions/security/mail-is-allowlisted-before-a-virtual-user-run-sees-it.md +38 -0
  161. package/knowledge/decisions/security/mcp-resources-tools-and-prompts-take-sessionless-functions.md +18 -0
  162. package/knowledge/decisions/security/origin-locked-routes-match-the-origin-exactly.md +22 -0
  163. package/knowledge/decisions/security/oss-auth-works-without-pikku-studio-cloud.md +26 -0
  164. package/knowledge/decisions/security/outbound-webhooks-use-an-allowlist-when-configured.md +24 -0
  165. package/knowledge/decisions/security/pikku-carries-virtual-user-scopes-as-data-and-the-app-grants-them.md +35 -0
  166. package/knowledge/decisions/security/scoped-content-access-is-a-root-folder-with-longest-prefix-grants.md +31 -0
  167. package/knowledge/decisions/security/services-without-secrets-get-a-throwing-secrets-accessor.md +22 -0
  168. package/knowledge/decisions/security/shared-guards-refuse-to-mutate-or-shadow-a-system-role.md +34 -0
  169. package/knowledge/decisions/security/signed-uploads-are-verified-by-the-same-check-as-signed-reads.md +26 -0
  170. package/knowledge/decisions/security/system-role-scopes-must-be-declared-with-define-scope.md +24 -0
  171. package/knowledge/decisions/security/system-roles-are-additive-and-immutable.md +16 -0
  172. package/knowledge/decisions/security/the-channel-rpc-does-not-send-the-callers-session.md +21 -0
  173. package/knowledge/decisions/security/the-remote-jobs-inbox-fails-closed-without-a-secret.md +24 -0
  174. package/knowledge/decisions/security/the-remote-rpc-gate-fails-closed-and-binds-the-token-to-its-function.md +34 -0
  175. package/knowledge/decisions/security/the-workflow-status-stream-rechecks-ownership-on-every-poll.md +16 -0
  176. package/knowledge/decisions/security/two-credentials-on-one-key-must-share-a-read-mode.md +29 -0
  177. package/knowledge/decisions/security/verified-bearer-claims-are-pass-through-data-that-core-never-fills.md +23 -0
  178. package/knowledge/decisions/security/virtual-user-catalogue-excludes-the-machinery-that-runs-virtual-users.md +25 -0
  179. package/knowledge/decisions/security/{actor-flow-missing-approval-decisions-default-to-denied.md → virtual-user-conversation-missing-approval-decisions-default-to-denied.md} +7 -7
  180. package/knowledge/decisions/security/virtual-user-run-records-are-gated-behind-a-read-scope.md +18 -0
  181. package/knowledge/decisions/security/virtual-user-sign-in-does-not-exist-in-production.md +25 -0
  182. package/knowledge/decisions/security/virtual-user-sign-in-has-one-door.md +42 -0
  183. package/knowledge/decisions/security/{actor-sign-in-is-proven-by-set-cookie-not-a-non-empty-jar.md → virtual-user-sign-in-is-proven-by-set-cookie-not-a-non-empty-jar.md} +10 -8
  184. package/knowledge/decisions/security/virtual-user-sign-in-only-works-for-virtual-user-flagged-users.md +29 -0
  185. package/knowledge/decisions/security/workflow-helper-functions-are-sessionless-by-declaration.md +18 -0
  186. package/knowledge/decisions/security/{workflow-scenario-sessions-are-isolated-per-actor-and-per-scenario.md → workflow-scenario-sessions-are-isolated-per-virtual-user-and-per-scenario.md} +6 -6
  187. package/knowledge/decisions/security/workflow-scenario-steps-are-never-network-invocable.md +5 -5
  188. package/knowledge/decisions/security/{workflow-actor-steps-always-use-the-real-transport.md → workflow-virtual-user-steps-always-use-the-real-transport.md} +11 -11
  189. package/knowledge/decisions/security/writing-a-virtual-user-schedule-is-gated-by-its-own-scope.md +18 -0
  190. package/knowledge/index.md +0 -2
  191. package/knowledge/questions/a-bearer-jwt-with-no-identity-becomes-a-session.md +24 -0
  192. package/knowledge/questions/dev-quick-login-as-impersonation.md +25 -0
  193. package/knowledge/questions/does-a-delayed-rpc-run-as-the-session-it-was-scheduled-with.md +26 -0
  194. package/knowledge/questions/does-a-user-id-with-a-colon-read-another-users-credentials.md +27 -0
  195. package/knowledge/questions/does-a-wirecli-command-need-a-session-by-default.md +26 -0
  196. package/knowledge/questions/does-an-adversarial-in-scope-success-count-as-a-finding.md +26 -0
  197. package/knowledge/questions/does-approve-step-need-the-run-owners-session-or-the-gates-approvers.md +34 -0
  198. package/knowledge/questions/does-cors-origin-true-reflect-any-origin-with-credentials.md +20 -0
  199. package/knowledge/questions/does-skip-user-session-do-anything-on-a-channel.md +24 -0
  200. package/knowledge/questions/does-the-store-session-match-the-other-two.md +19 -0
  201. package/knowledge/questions/index.md +25 -2
  202. package/knowledge/questions/is-the-agent-score-worker-reachable-without-a-session.md +21 -0
  203. package/knowledge/questions/live-scheduled-tests-may-write.md +19 -0
  204. package/knowledge/questions/provision-virtual-users-has-no-caller-in-this-repo.md +23 -0
  205. package/knowledge/questions/remote-secret-refuses-requests-without-a-remote-token-on-every-path.md +32 -0
  206. package/knowledge/questions/should-a-middleware-set-session-persist-to-the-store.md +25 -0
  207. package/knowledge/questions/should-a-scoped-secret-view-throw-from-has-secret-for-a-disallowed-key.md +23 -0
  208. package/knowledge/questions/should-a-wrong-bearer-token-be-anonymous-or-refused.md +35 -0
  209. package/knowledge/questions/should-an-empty-webhook-signing-secret-send-unsigned.md +23 -0
  210. package/knowledge/questions/should-http-virtual-user-sessions-reset-between-scenarios-in-one-run.md +27 -0
  211. package/knowledge/questions/should-the-cookie-jar-scope-cookies-to-the-api-origin.md +26 -0
  212. package/knowledge/questions/should-voice-input-fetch-audio-urls-without-a-host-allowlist.md +20 -0
  213. package/knowledge/questions/staging-impersonation-rules.md +27 -0
  214. package/knowledge/questions/virtual-user-keys-on-cloud-stages-are-pikku-studios-to-build.md +34 -0
  215. package/knowledge/questions/virtual-user-statement-replay-is-per-process.md +20 -0
  216. package/knowledge/questions/what-an-impersonated-session-carries.md +22 -0
  217. package/package.json +2 -3
  218. package/src/public-surface.json +38 -47
  219. package/dist/services/persona-actor-secret.d.ts +0 -38
  220. package/dist/services/persona-actor-secret.js +0 -39
  221. package/dist/services/persona-sign-in.d.ts +0 -117
  222. package/dist/services/persona-sign-in.js +0 -154
  223. package/dist/wirings/actor-flow/index.d.ts +0 -2
  224. package/dist/wirings/actor-flow/run-conversation.d.ts +0 -36
  225. package/dist/wirings/persona/define-personas.d.ts +0 -32
  226. package/dist/wirings/persona/index.d.ts +0 -23
  227. package/dist/wirings/persona/index.js +0 -19
  228. package/knowledge/decisions/internals/actor-flow-conversations-seed-a-hidden-kickoff-message.md +0 -23
  229. package/knowledge/decisions/internals/actor-flow-verdicts-are-llm-self-evaluations.md +0 -25
  230. package/knowledge/decisions/internals/validate-checks-personas-through-a-shared-module.md +0 -43
  231. package/knowledge/decisions/security/actor-sign-in-only-works-for-actor-flagged-users.md +0 -31
  232. package/knowledge/decisions/security/an-actor-credential-is-derived-per-persona.md +0 -42
  233. package/knowledge/decisions/security/pikku-carries-actor-scopes-as-data-and-the-app-grants-them.md +0 -26
  234. /package/dist/wirings/{actor-flow/actor-flow.types.js → virtual-user/conversation/conversation.types.js} +0 -0
  235. /package/dist/wirings/{actor-flow → virtual-user/conversation}/index.js +0 -0
  236. /package/dist/wirings/{persona/persona.types.js → virtual-user/virtual-user-declaration.types.js} +0 -0
  237. /package/dist/wirings/{persona/persona-mailbox.js → virtual-user/virtual-user-mailbox.js} +0 -0
@@ -8,20 +8,20 @@ export const APP_SCOPE_ROOT = 'app';
8
8
  /** `app:staff` for `staff`. */
9
9
  export const appScopeId = (app) => `${APP_SCOPE_ROOT}:${app}`;
10
10
  /**
11
- * The apps named across the declared personas, sorted and deduplicated.
11
+ * The apps named across the declared virtual users, sorted and deduplicated.
12
12
  *
13
- * The personas *are* the registry. There is no separate list of apps to keep in
13
+ * The virtual users *are* the registry. There is no separate list of apps to keep in
14
14
  * step, because a frontend nobody signs into is not a thing the auth layer has
15
15
  * an opinion about — and the moment somebody does sign into it, they are a
16
- * persona and they name it.
16
+ * virtual user and they name it.
17
17
  */
18
- export const declaredApps = (personas) => [
19
- ...new Set(personas
20
- .map((persona) => persona.app)
18
+ export const declaredApps = (virtualUsers) => [
19
+ ...new Set(virtualUsers
20
+ .map((virtualUser) => virtualUser.app)
21
21
  .filter((app) => typeof app === 'string' && app !== '')),
22
22
  ].sort();
23
23
  /**
24
- * The `app` scope tree, synthesised from the personas that name an app.
24
+ * The `app` scope tree, synthesised from the virtual users that name an app.
25
25
  *
26
26
  * Which frontend a person may sign into is a different question from what they
27
27
  * may do once inside it, but it is the same *kind* of question — a grant that
@@ -33,15 +33,15 @@ export const declaredApps = (personas) => [
33
33
  *
34
34
  * Synthesised rather than written by hand because the declaration already
35
35
  * exists. Asking an app to also spell out `defineScope({ app: { staff: {} } })`
36
- * beside its personas invites the two to drift, and the failure that produces —
37
- * a persona provisioned with a grant the vocabulary no longer declares — is one
36
+ * beside its virtual users invites the two to drift, and the failure that produces —
37
+ * a virtual user provisioned with a grant the vocabulary no longer declares — is one
38
38
  * `pikku scopes prune` away from silently revoking sign-in.
39
39
  *
40
- * Null when no persona names an app, which is the single-frontend case: nothing
40
+ * Null when no virtual user names an app, which is the single-frontend case: nothing
41
41
  * to declare, and no empty root cluttering the console's grant list.
42
42
  */
43
- export const buildAppScopeDefinition = (personas) => {
44
- const apps = declaredApps(personas);
43
+ export const buildAppScopeDefinition = (virtualUsers) => {
44
+ const apps = declaredApps(virtualUsers);
45
45
  if (apps.length === 0) {
46
46
  return null;
47
47
  }
@@ -28,7 +28,7 @@ export declare const renderCatalogue: (entries: readonly ApiCatalogueEntry[]) =>
28
28
  /**
29
29
  * The entries a given user may reach: approval-gated calls dropped unless the
30
30
  * run opted in, mutations dropped for a read-only disposition, and anything the
31
- * actor's tier cannot satisfy dropped when the caller supplied one.
31
+ * virtual user's tier cannot satisfy dropped when the caller supplied one.
32
32
  *
33
33
  * This narrows *what is offered*, never what is enforced — the server is the
34
34
  * only thing that decides who may call what, and a call this filter would have
@@ -38,7 +38,7 @@ export declare const reachableCatalogue: (entries: readonly ApiCatalogueEntry[],
38
38
  readOnly?: boolean;
39
39
  allowApprovalRequired?: boolean;
40
40
  /**
41
- * The scopes this persona holds, resolved from its roles. Omit to keep
41
+ * The scopes this virtual user holds, resolved from its roles. Omit to keep
42
42
  * every entry.
43
43
  *
44
44
  * Scopes rather than permission-function names: a function's `scopes` are
@@ -49,7 +49,7 @@ export declare const reachableCatalogue: (entries: readonly ApiCatalogueEntry[],
49
49
  scopes?: readonly string[];
50
50
  }) => ApiCatalogueEntry[];
51
51
  /**
52
- * Endpoints this persona is *not* entitled to reach.
52
+ * Endpoints this virtual user is *not* entitled to reach.
53
53
  *
54
54
  * The adversarial oracle. Withheld from the catalogue, so reaching one takes
55
55
  * initiative — and a 2xx from one is the finding, because the server is the
@@ -67,7 +67,7 @@ export const renderCatalogue = (entries) => entries.map(renderEntry).join('\n');
67
67
  /**
68
68
  * The entries a given user may reach: approval-gated calls dropped unless the
69
69
  * run opted in, mutations dropped for a read-only disposition, and anything the
70
- * actor's tier cannot satisfy dropped when the caller supplied one.
70
+ * virtual user's tier cannot satisfy dropped when the caller supplied one.
71
71
  *
72
72
  * This narrows *what is offered*, never what is enforced — the server is the
73
73
  * only thing that decides who may call what, and a call this filter would have
@@ -84,7 +84,7 @@ export const reachableCatalogue = (entries, { readOnly = false, allowApprovalReq
84
84
  return true;
85
85
  });
86
86
  /**
87
- * Endpoints this persona is *not* entitled to reach.
87
+ * Endpoints this virtual user is *not* entitled to reach.
88
88
  *
89
89
  * The adversarial oracle. Withheld from the catalogue, so reaching one takes
90
90
  * initiative — and a 2xx from one is the finding, because the server is the
@@ -1,23 +1,23 @@
1
1
  import type { VirtualUserDisposition } from '../virtual-user/virtual-user.types.js';
2
2
  import type { VirtualUserTuning } from '../virtual-user/virtual-user-dispositions.js';
3
3
  /**
4
- * One login belonging to a persona.
4
+ * One login belonging to a virtual user.
5
5
  *
6
6
  * Deliberately near-empty in the common case: the address is computed from the
7
- * persona's name and the run id, and the password derives from
8
- * `SCENARIO_ACTOR_SECRET`, so there is nothing left to write down. It fills up
7
+ * virtual user's name and the run id, and sign-in needs no password, so there is
8
+ * nothing left to write down. It fills up
9
9
  * only for a provider login.
10
10
  *
11
11
  * Shaped after better-auth's `account` table, which is what most pikku apps are
12
12
  * actually running: `providerId` plus the provider's own id, and no email
13
13
  * column — the address belongs to the person, not the login.
14
14
  */
15
- export type CorePersonaAccount = {
15
+ export type CoreVirtualUserAccount = {
16
16
  /**
17
17
  * The identity provider, e.g. `'google'`. Omit for email and password.
18
18
  *
19
19
  * A provider account is declarable but not runnable: driving its consent
20
- * screen needs a human, so `pikku persona run` refuses rather than failing
20
+ * screen needs a human, so `pikku virtual-user run` refuses rather than failing
21
21
  * somewhere inside a browser.
22
22
  */
23
23
  provider?: string;
@@ -26,12 +26,12 @@ export type CorePersonaAccount = {
26
26
  * A person who uses your product: a name, a job, a temperament, and what they
27
27
  * are trying to get done.
28
28
  *
29
- * This is Cooper's persona — "a fictional character created to represent a user
29
+ * This is Cooper's virtual user — "a fictional character created to represent a user
30
30
  * type" — with the two things a synthetic user additionally needs: the roles
31
- * that say what they may do, and the account they log in with. A persona while
31
+ * that say what they may do, and the account they log in with. A virtual user while
32
32
  * running is a virtual user; there is no second declaration for that.
33
33
  */
34
- export type CorePersona = {
34
+ export type CoreVirtualUser = {
35
35
  /** The person's name, as a person would give it. */
36
36
  name: string;
37
37
  jobTitle?: string;
@@ -41,14 +41,14 @@ export type CorePersona = {
41
41
  * serves, an asset on a CDN, a Gravatar link.
42
42
  *
43
43
  * Optional because it is decoration. Omitted, the console draws a colour and
44
- * an icon derived from the persona's id, which is stable, needs no network and
44
+ * an icon derived from the virtual user's id, which is stable, needs no network and
45
45
  * is more legible than the identicon a synthetic address would resolve to —
46
46
  * which is also why nothing is derived here.
47
47
  */
48
48
  avatarUrl?: string;
49
49
  /**
50
50
  * The roles this person holds. Only system roles may be named — a custom
51
- * role can be deleted from the console, so a persona pinned to one silently
51
+ * role can be deleted from the console, so a virtual user pinned to one silently
52
52
  * stops testing what it claims to.
53
53
  *
54
54
  * These are granted, not merely recorded: the generated seed applies them,
@@ -74,15 +74,15 @@ export type CorePersona = {
74
74
  /** Fixture paths this person may upload, relative to the project root. */
75
75
  fixtures?: string[];
76
76
  /** Their login. `{}` — email and password — is the normal case. */
77
- account?: CorePersonaAccount;
77
+ account?: CoreVirtualUserAccount;
78
78
  /**
79
79
  * Further logins belonging to the same human, keyed by name.
80
80
  *
81
- * Rare, and shaped that way on purpose. All of them share the persona's one
81
+ * Rare, and shaped that way on purpose. All of them share the virtual user's one
82
82
  * computed address: better-auth's `allowDifferentEmails` defaults to false,
83
83
  * so distinct addresses would be refused linking by the library under test.
84
84
  */
85
- linkedAccounts?: Record<string, CorePersonaAccount>;
85
+ linkedAccounts?: Record<string, CoreVirtualUserAccount>;
86
86
  /**
87
87
  * The environments this person may run against, by config key.
88
88
  *
@@ -100,7 +100,7 @@ export type CorePersona = {
100
100
  *
101
101
  * An assertion, not something inferred from the absence of a disposition:
102
102
  * `target` *must not* run, because a run signing in as her would race the
103
- * scenario banning her. "Nobody has given this persona a disposition yet" is
103
+ * scenario banning her. "Nobody has given this virtual user a disposition yet" is
104
104
  * a different state, and collapsing the two turns a deliberate constraint
105
105
  * into a flaky suite.
106
106
  */
@@ -110,20 +110,20 @@ export type CorePersona = {
110
110
  *
111
111
  * A person uses one of them — staff their app, customers theirs — and that is
112
112
  * what decides where a browser step navigates: `/dashboard` is a different
113
- * page in each, so the actor settles which one without the scenario saying.
113
+ * page in each, so the virtual user settles which one without the scenario saying.
114
114
  * The runner takes the base url per app (`--app-url <app>=<url>`, or
115
- * `appUrls` on the environment) and each actor browses against its own.
115
+ * `appUrls` on the environment) and each virtual user browses against its own.
116
116
  *
117
117
  * Omitted is the normal case: one app, one url, nothing to say.
118
118
  */
119
119
  app?: string;
120
120
  };
121
- /** Personas to declare, keyed by id. */
122
- export type CorePersonas = Record<string, CorePersona>;
123
- export type PersonaAccountMeta = {
121
+ /** Virtual users to declare, keyed by id. */
122
+ export type CoreVirtualUsers = Record<string, CoreVirtualUser>;
123
+ export type VirtualUserAccountMeta = {
124
124
  provider?: string;
125
125
  };
126
- export type PersonaMeta = {
126
+ export type VirtualUserMeta = {
127
127
  /** The key it was declared under. */
128
128
  id: string;
129
129
  name: string;
@@ -137,8 +137,8 @@ export type PersonaMeta = {
137
137
  disposition?: VirtualUserDisposition;
138
138
  tuning?: VirtualUserTuning;
139
139
  fixtures?: string[];
140
- account?: PersonaAccountMeta;
141
- linkedAccounts?: Record<string, PersonaAccountMeta>;
140
+ account?: VirtualUserAccountMeta;
141
+ linkedAccounts?: Record<string, VirtualUserAccountMeta>;
142
142
  /** Absent means "everywhere but production", which is resolved, not stored. */
143
143
  environments?: string[];
144
144
  runnable: boolean;
@@ -146,5 +146,5 @@ export type PersonaMeta = {
146
146
  app?: string;
147
147
  sourceFile?: string;
148
148
  };
149
- export type PersonaDefinitions = PersonaMeta[];
150
- export type PersonasMeta = Record<string, PersonaMeta>;
149
+ export type VirtualUserDefinitions = VirtualUserMeta[];
150
+ export type VirtualUsersMeta = Record<string, VirtualUserMeta>;
@@ -25,9 +25,9 @@ export const deriveCatalogue = (functions, schemas = {}) => {
25
25
  if (meta.expose !== true)
26
26
  continue;
27
27
  // A virtual user is not offered the machinery that runs virtual users. A
28
- // persona whose role carries `virtualUser:*` would otherwise be able to
28
+ // virtual user whose role carries `virtualUser:*` would otherwise be able to
29
29
  // start further runs, read every run's findings — an adversarial run's
30
- // transcript is working exploits against this same app — and put a persona
30
+ // transcript is working exploits against this same app — and put a virtual user
31
31
  // on a schedule that outlives it. Same reasoning as the scenario-step rule
32
32
  // above: the tool is about the run, not about the product being explored.
33
33
  if (meta.scopes?.some((scope) => scope.split(':')[0] === 'virtualUser')) {
@@ -68,15 +68,21 @@ export const deriveCatalogue = (functions, schemas = {}) => {
68
68
  const scenarioSteps = (meta) => {
69
69
  if (meta.steps?.length) {
70
70
  return meta.steps.flatMap((step) => step.type === 'scenarioStep'
71
- ? [{ stepFunc: step.stepFunc, phase: step.phase, actor: step.actor }]
71
+ ? [
72
+ {
73
+ stepFunc: step.stepFunc,
74
+ phase: step.phase,
75
+ virtualUser: step.virtualUser,
76
+ },
77
+ ]
72
78
  : []);
73
79
  }
74
80
  // knowledge: decisions/internals/virtual-user-step-order-comes-from-insertion-order.md
75
81
  return Object.values(meta.nodes ?? {}).flatMap((node) => {
76
- const { rpcName, scenarioStepPhase, actor } = (node ?? {});
82
+ const { rpcName, scenarioStepPhase, virtualUser } = (node ?? {});
77
83
  if (!rpcName || !scenarioStepPhase)
78
84
  return [];
79
- return [{ stepFunc: rpcName, phase: scenarioStepPhase, actor }];
85
+ return [{ stepFunc: rpcName, phase: scenarioStepPhase, virtualUser }];
80
86
  });
81
87
  };
82
88
  /**
@@ -109,7 +115,7 @@ export const deriveIntents = (workflows, functions = {}) => {
109
115
  phase: step.phase,
110
116
  // knowledge: decisions/internals/a-scenario-step-template-is-offered-unfilled.md
111
117
  description: template ?? description ?? '',
112
- actor: step.actor,
118
+ virtualUser: step.virtualUser,
113
119
  }));
114
120
  }
115
121
  intents.push({
@@ -118,7 +124,7 @@ export const deriveIntents = (workflows, functions = {}) => {
118
124
  description: meta.description,
119
125
  steps: steps.length ? steps : undefined,
120
126
  tags: meta.tags?.length ? meta.tags : undefined,
121
- personas: meta.actors?.length ? meta.actors : undefined,
127
+ virtualUsers: meta.virtualUsers?.length ? meta.virtualUsers : undefined,
122
128
  });
123
129
  }
124
130
  return intents;
@@ -5,7 +5,7 @@ import type { VirtualUserDisposition } from './virtual-user.types.js';
5
5
  * behaviour the dials cannot express on their own.
6
6
  */
7
7
  export interface DispositionProfile {
8
- /** Appended to the persona instructions. Behaviour, never identity. */
8
+ /** Appended to the virtual user instructions. Behaviour, never identity. */
9
9
  instructions: string;
10
10
  /**
11
11
  * Relative weights for the scheduler's four moves. `continue` dominating is
@@ -1,21 +1,21 @@
1
1
  /**
2
- * A persona's email address is computed, never declared.
2
+ * A virtual user's email address is computed, never declared.
3
3
  *
4
- * A persona that cannot read its own email cannot complete sign-up, magic
4
+ * A virtual user that cannot read its own email cannot complete sign-up, magic
5
5
  * links, invites or password resets — which are most of the flows worth
6
6
  * exercising. So addresses are real and deliverable against a domain the stage
7
7
  * actually receives mail on, rather than a synthetic `.local` dead end.
8
8
  */
9
9
  /**
10
- * Lower-cases and strips a persona id down to something an address can carry.
10
+ * Lower-cases and strips a virtual user id down to something an address can carry.
11
11
  *
12
- * Personas are declared as object keys, so they are already identifier-shaped;
12
+ * Virtual users are declared as object keys, so they are already identifier-shaped;
13
13
  * this exists for the ones that are not (`'susan.buyer'`, `'Susan_2'`) rather
14
14
  * than to permit arbitrary input.
15
15
  */
16
- export declare const personaEmailLabel: (personaId: string) => string;
16
+ export declare const virtualUserEmailLabel: (virtualUserId: string) => string;
17
17
  /**
18
- * The address a persona reads mail at during a run.
18
+ * The address a virtual user reads mail at during a run.
19
19
  *
20
20
  * The `runId` suffix is not decoration. Without it two concurrent runs share an
21
21
  * inbox *and* a user row, and run B reads run A's magic link. Sub-addressing
@@ -25,13 +25,13 @@ export declare const personaEmailLabel: (personaId: string) => string;
25
25
  * Omitting `runId` gives the bare form, which is what a seeded fixture that has
26
26
  * to stay stable across runs wants.
27
27
  */
28
- export declare const personaEmail: (personaId: string, domain: string, runId?: string) => string;
28
+ export declare const virtualUserEmail: (virtualUserId: string, domain: string, runId?: string) => string;
29
29
  /**
30
- * Every address in a run, keyed by persona.
30
+ * Every address in a run, keyed by virtual user.
31
31
  *
32
- * All of a persona's logins share one address. That is not a simplification:
32
+ * All of a virtual user's logins share one address. That is not a simplification:
33
33
  * better-auth keeps `email` on the `user` and defaults `allowDifferentEmails`
34
34
  * to false, so giving a linked account its own address would have the library
35
- * under test refuse to link the very thing the persona declared as linked.
35
+ * under test refuse to link the very thing the virtual user declared as linked.
36
36
  */
37
- export declare const personaEmails: (personaIds: readonly string[], domain: string, runId?: string) => Record<string, string>;
37
+ export declare const virtualUserEmails: (virtualUserIds: readonly string[], domain: string, runId?: string) => Record<string, string>;
@@ -1,31 +1,31 @@
1
1
  /**
2
- * A persona's email address is computed, never declared.
2
+ * A virtual user's email address is computed, never declared.
3
3
  *
4
- * A persona that cannot read its own email cannot complete sign-up, magic
4
+ * A virtual user that cannot read its own email cannot complete sign-up, magic
5
5
  * links, invites or password resets — which are most of the flows worth
6
6
  * exercising. So addresses are real and deliverable against a domain the stage
7
7
  * actually receives mail on, rather than a synthetic `.local` dead end.
8
8
  */
9
9
  const LABEL = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
10
10
  /**
11
- * Lower-cases and strips a persona id down to something an address can carry.
11
+ * Lower-cases and strips a virtual user id down to something an address can carry.
12
12
  *
13
- * Personas are declared as object keys, so they are already identifier-shaped;
13
+ * Virtual users are declared as object keys, so they are already identifier-shaped;
14
14
  * this exists for the ones that are not (`'susan.buyer'`, `'Susan_2'`) rather
15
15
  * than to permit arbitrary input.
16
16
  */
17
- export const personaEmailLabel = (personaId) => {
18
- const label = personaId
17
+ export const virtualUserEmailLabel = (virtualUserId) => {
18
+ const label = virtualUserId
19
19
  .toLowerCase()
20
20
  .replace(/[^a-z0-9]+/g, '-')
21
21
  .replace(/^-+|-+$/g, '');
22
22
  if (!LABEL.test(label)) {
23
- throw new Error(`Persona '${personaId}' has no usable email label. A persona id must contain at least one letter or digit.`);
23
+ throw new Error(`VirtualUser '${virtualUserId}' has no usable email label. A virtual user id must contain at least one letter or digit.`);
24
24
  }
25
25
  return label;
26
26
  };
27
27
  /**
28
- * The address a persona reads mail at during a run.
28
+ * The address a virtual user reads mail at during a run.
29
29
  *
30
30
  * The `runId` suffix is not decoration. Without it two concurrent runs share an
31
31
  * inbox *and* a user row, and run B reads run A's magic link. Sub-addressing
@@ -35,31 +35,31 @@ export const personaEmailLabel = (personaId) => {
35
35
  * Omitting `runId` gives the bare form, which is what a seeded fixture that has
36
36
  * to stay stable across runs wants.
37
37
  */
38
- export const personaEmail = (personaId, domain, runId) => {
39
- const label = personaEmailLabel(personaId);
38
+ export const virtualUserEmail = (virtualUserId, domain, runId) => {
39
+ const label = virtualUserEmailLabel(virtualUserId);
40
40
  const cleanDomain = domain.trim().toLowerCase().replace(/^@/, '');
41
41
  if (!cleanDomain || cleanDomain.includes('@') || !cleanDomain.includes('.')) {
42
- throw new Error(`Persona email domain '${domain}' is not a domain. Set it to a domain the stage actually receives mail on.`);
42
+ throw new Error(`VirtualUser email domain '${domain}' is not a domain. Set it to a domain the stage actually receives mail on.`);
43
43
  }
44
- const suffix = runId ? `+${personaEmailLabel(runId)}` : '';
44
+ const suffix = runId ? `+${virtualUserEmailLabel(runId)}` : '';
45
45
  return `${label}${suffix}@${cleanDomain}`;
46
46
  };
47
47
  /**
48
- * Every address in a run, keyed by persona.
48
+ * Every address in a run, keyed by virtual user.
49
49
  *
50
- * All of a persona's logins share one address. That is not a simplification:
50
+ * All of a virtual user's logins share one address. That is not a simplification:
51
51
  * better-auth keeps `email` on the `user` and defaults `allowDifferentEmails`
52
52
  * to false, so giving a linked account its own address would have the library
53
- * under test refuse to link the very thing the persona declared as linked.
53
+ * under test refuse to link the very thing the virtual user declared as linked.
54
54
  */
55
- export const personaEmails = (personaIds, domain, runId) => {
55
+ export const virtualUserEmails = (virtualUserIds, domain, runId) => {
56
56
  const emails = {};
57
57
  const seen = new Map();
58
- for (const id of personaIds) {
59
- const address = personaEmail(id, domain, runId);
58
+ for (const id of virtualUserIds) {
59
+ const address = virtualUserEmail(id, domain, runId);
60
60
  const collidesWith = seen.get(address);
61
61
  if (collidesWith !== undefined) {
62
- throw new Error(`Personas '${collidesWith}' and '${id}' both compute the address ${address}. ` +
62
+ throw new Error(`VirtualUsers '${collidesWith}' and '${id}' both compute the address ${address}. ` +
63
63
  `They would share a user row and read each other's email.`);
64
64
  }
65
65
  seen.set(address, id);
@@ -1,6 +1,6 @@
1
1
  import { type VirtualUserDisposition } from '../virtual-user/virtual-user.types.js';
2
2
  /**
3
- * Which environments a persona may run against, and the one rule on it.
3
+ * Which environments a virtual user may run against, and the one rule on it.
4
4
  *
5
5
  * Two callers, deliberately sharing this file. The inspector checks the
6
6
  * declaration at build time; sign-in re-checks against the environment actually
@@ -8,31 +8,31 @@ import { type VirtualUserDisposition } from '../virtual-user/virtual-user.types.
8
8
  * and the run check does not trust which artifact got deployed.
9
9
  */
10
10
  /** The part of an environment entry this rule cares about. */
11
- export interface PersonaEnvironment {
11
+ export interface VirtualUserEnvironment {
12
12
  production?: boolean;
13
13
  }
14
- /** What a persona needs to expose for the rule to be applied to it. */
15
- export interface PersonaEnvironmentSubject {
14
+ /** What a virtual user needs to expose for the rule to be applied to it. */
15
+ export interface VirtualUserEnvironmentSubject {
16
16
  disposition?: VirtualUserDisposition;
17
17
  environments?: string[];
18
18
  }
19
19
  /**
20
- * The environments a persona may target, resolved.
20
+ * The environments a virtual user may target, resolved.
21
21
  *
22
22
  * An omitted `environments` means every configured environment **except** the
23
23
  * production ones: production is opt-in for everybody, so nothing reaches it by
24
24
  * being forgotten.
25
25
  */
26
- export declare const resolvePersonaEnvironments: (persona: PersonaEnvironmentSubject, environments: Readonly<Record<string, PersonaEnvironment>>) => string[];
26
+ export declare const resolveVirtualUserEnvironments: (virtualUser: VirtualUserEnvironmentSubject, environments: Readonly<Record<string, VirtualUserEnvironment>>) => string[];
27
27
  /**
28
- * The declaration check, as a list of messages. Empty means the persona's
28
+ * The declaration check, as a list of messages. Empty means the virtual user's
29
29
  * `environments` are coherent with the config and its disposition.
30
30
  *
31
31
  * An unknown environment name is an error rather than a shrug: a typo silently
32
- * narrowing a persona to nothing is the same class of bug as the one this whole
32
+ * narrowing a virtual user to nothing is the same class of bug as the one this whole
33
33
  * rule exists to prevent, only quieter.
34
34
  */
35
- export declare const personaEnvironmentErrors: (id: string, persona: PersonaEnvironmentSubject, environments: Readonly<Record<string, PersonaEnvironment>>) => string[];
35
+ export declare const virtualUserEnvironmentErrors: (id: string, virtualUser: VirtualUserEnvironmentSubject, environments: Readonly<Record<string, VirtualUserEnvironment>>) => string[];
36
36
  /**
37
37
  * The sign-in check: the message to refuse with, or `null` to let the run
38
38
  * start.
@@ -42,4 +42,4 @@ export declare const personaEnvironmentErrors: (id: string, persona: PersonaEnvi
42
42
  * artifact than the one running, so treating "I don't know where I am" as
43
43
  * permission is exactly backwards.
44
44
  */
45
- export declare const personaEnvironmentRefusal: (id: string, persona: PersonaEnvironmentSubject, environmentName: string | undefined, environments: Readonly<Record<string, PersonaEnvironment>>) => string | null;
45
+ export declare const virtualUserEnvironmentRefusal: (id: string, virtualUser: VirtualUserEnvironmentSubject, environmentName: string | undefined, environments: Readonly<Record<string, VirtualUserEnvironment>>) => string | null;
@@ -1,45 +1,45 @@
1
1
  import { PRODUCTION_DISPOSITION, } from '../virtual-user/virtual-user.types.js';
2
2
  /**
3
- * The environments a persona may target, resolved.
3
+ * The environments a virtual user may target, resolved.
4
4
  *
5
5
  * An omitted `environments` means every configured environment **except** the
6
6
  * production ones: production is opt-in for everybody, so nothing reaches it by
7
7
  * being forgotten.
8
8
  */
9
- export const resolvePersonaEnvironments = (persona, environments) => {
10
- if (persona.environments) {
11
- return [...persona.environments];
9
+ export const resolveVirtualUserEnvironments = (virtualUser, environments) => {
10
+ if (virtualUser.environments) {
11
+ return [...virtualUser.environments];
12
12
  }
13
13
  return Object.entries(environments)
14
14
  .filter(([, env]) => !env.production)
15
15
  .map(([name]) => name);
16
16
  };
17
17
  /**
18
- * The declaration check, as a list of messages. Empty means the persona's
18
+ * The declaration check, as a list of messages. Empty means the virtual user's
19
19
  * `environments` are coherent with the config and its disposition.
20
20
  *
21
21
  * An unknown environment name is an error rather than a shrug: a typo silently
22
- * narrowing a persona to nothing is the same class of bug as the one this whole
22
+ * narrowing a virtual user to nothing is the same class of bug as the one this whole
23
23
  * rule exists to prevent, only quieter.
24
24
  */
25
- export const personaEnvironmentErrors = (id, persona, environments) => {
26
- if (!persona.environments) {
25
+ export const virtualUserEnvironmentErrors = (id, virtualUser, environments) => {
26
+ if (!virtualUser.environments) {
27
27
  return [];
28
28
  }
29
29
  const errors = [];
30
30
  const known = Object.keys(environments);
31
- for (const name of persona.environments) {
31
+ for (const name of virtualUser.environments) {
32
32
  const env = environments[name];
33
33
  if (!env) {
34
- errors.push(`Persona '${id}' names environment '${name}', which is not configured. ` +
34
+ errors.push(`VirtualUser '${id}' names environment '${name}', which is not configured. ` +
35
35
  (known.length
36
36
  ? `Configured environments: ${known.join(', ')}.`
37
37
  : `Declare it under 'environments' in pikku.config.json.`));
38
38
  continue;
39
39
  }
40
- if (env.production && persona.disposition !== PRODUCTION_DISPOSITION) {
41
- errors.push(`Persona '${id}' names production environment '${name}' with disposition ` +
42
- `'${persona.disposition ?? 'realistic'}'. ` +
40
+ if (env.production && virtualUser.disposition !== PRODUCTION_DISPOSITION) {
41
+ errors.push(`VirtualUser '${id}' names production environment '${name}' with disposition ` +
42
+ `'${virtualUser.disposition ?? 'realistic'}'. ` +
43
43
  `Only '${PRODUCTION_DISPOSITION}' may run against production — every other ` +
44
44
  `disposition exists to find out what the product does wrong, which is not a ` +
45
45
  `thing to do to real data. Either give '${id}' disposition '${PRODUCTION_DISPOSITION}', ` +
@@ -57,24 +57,24 @@ export const personaEnvironmentErrors = (id, persona, environments) => {
57
57
  * artifact than the one running, so treating "I don't know where I am" as
58
58
  * permission is exactly backwards.
59
59
  */
60
- export const personaEnvironmentRefusal = (id, persona, environmentName, environments) => {
60
+ export const virtualUserEnvironmentRefusal = (id, virtualUser, environmentName, environments) => {
61
61
  if (!environmentName) {
62
- return (`Refusing to sign in persona '${id}': no environment is resolved. ` +
62
+ return (`Refusing to sign in virtual user '${id}': no environment is resolved. ` +
63
63
  `Set PIKKU_ENV to one of the configured environments (${Object.keys(environments).join(', ') || 'none are configured'}).`);
64
64
  }
65
65
  const env = environments[environmentName];
66
66
  if (!env) {
67
- return (`Refusing to sign in persona '${id}': environment '${environmentName}' is not configured. ` +
67
+ return (`Refusing to sign in virtual user '${id}': environment '${environmentName}' is not configured. ` +
68
68
  `Configured environments: ${Object.keys(environments).join(', ') || 'none'}.`);
69
69
  }
70
- if (env.production && persona.disposition !== PRODUCTION_DISPOSITION) {
71
- return (`Refusing to sign in persona '${id}' against production environment '${environmentName}': ` +
72
- `its disposition is '${persona.disposition ?? 'realistic'}', and only ` +
70
+ if (env.production && virtualUser.disposition !== PRODUCTION_DISPOSITION) {
71
+ return (`Refusing to sign in virtual user '${id}' against production environment '${environmentName}': ` +
72
+ `its disposition is '${virtualUser.disposition ?? 'realistic'}', and only ` +
73
73
  `'${PRODUCTION_DISPOSITION}' may act on real data.`);
74
74
  }
75
- const allowed = resolvePersonaEnvironments(persona, environments);
75
+ const allowed = resolveVirtualUserEnvironments(virtualUser, environments);
76
76
  if (!allowed.includes(environmentName)) {
77
- return (`Refusing to sign in persona '${id}' against '${environmentName}': ` +
77
+ return (`Refusing to sign in virtual user '${id}' against '${environmentName}': ` +
78
78
  `it declares environments ${allowed.join(', ') || 'none'}.`);
79
79
  }
80
80
  return null;
@@ -68,11 +68,11 @@ export declare class IntentStack {
68
68
  private resumeSuspended;
69
69
  }
70
70
  /**
71
- * The intents a persona may be given: those whose source names them, plus every
71
+ * The intents a virtual user may be given: those whose source names them, plus every
72
72
  * source that names nobody.
73
73
  *
74
74
  * This is a free lookup rather than new authoring — scenario meta already
75
- * records which personas each scenario runs as.
75
+ * records which virtual users each scenario runs as.
76
76
  */
77
- export declare const intentsForPersona: (sources: readonly IntentSource[], personaId: string) => IntentSource[];
77
+ export declare const intentsForVirtualUser: (sources: readonly IntentSource[], virtualUserId: string) => IntentSource[];
78
78
  export {};
@@ -133,10 +133,10 @@ export class IntentStack {
133
133
  }
134
134
  }
135
135
  /**
136
- * The intents a persona may be given: those whose source names them, plus every
136
+ * The intents a virtual user may be given: those whose source names them, plus every
137
137
  * source that names nobody.
138
138
  *
139
139
  * This is a free lookup rather than new authoring — scenario meta already
140
- * records which personas each scenario runs as.
140
+ * records which virtual users each scenario runs as.
141
141
  */
142
- export const intentsForPersona = (sources, personaId) => sources.filter((source) => !source.personas?.length || source.personas.includes(personaId));
142
+ export const intentsForVirtualUser = (sources, virtualUserId) => sources.filter((source) => !source.virtualUsers?.length || source.virtualUsers.includes(virtualUserId));
@@ -1,4 +1,4 @@
1
- /** One email a persona received. */
1
+ /** One email a virtual user received. */
2
2
  export interface ReceivedEmail {
3
3
  to: string;
4
4
  from: string;
@@ -8,7 +8,7 @@ export interface ReceivedEmail {
8
8
  * Links found in the body, already extracted.
9
9
  *
10
10
  * Extracted rather than handed over as text on purpose — see
11
- * {@link PersonaMailbox}. A magic link is the only part of most emails a
11
+ * {@link VirtualUserMailbox}. A magic link is the only part of most emails a
12
12
  * virtual user needs, and it is checkable in a way prose is not.
13
13
  */
14
14
  links: string[];
@@ -30,7 +30,7 @@ export interface ReceivedEmail {
30
30
  body?: string;
31
31
  }
32
32
  /**
33
- * Where a persona reads its mail.
33
+ * Where a virtual user reads its mail.
34
34
  *
35
35
  * Capturing inbound mail is platform-specific — on Cloudflare an Email Worker
36
36
  * on the test domain, elsewhere whatever the stage can receive with — so pikku
@@ -41,7 +41,7 @@ export interface ReceivedEmail {
41
41
  * user's address is real and deliverable, so anyone who learns it can send it
42
42
  * instructions, and the run holds a live session against a real stage.
43
43
  */
44
- export interface PersonaMailbox {
44
+ export interface VirtualUserMailbox {
45
45
  /**
46
46
  * Wait for a matching email, or reject on timeout.
47
47
  *