@pikku/core 0.12.139 → 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.
- package/CHANGELOG.md +47 -0
- package/dist/errors/errors.d.ts +1 -1
- package/dist/errors/errors.js +1 -1
- package/dist/function/function-meta.types.d.ts +6 -6
- package/dist/function/functions.types.d.ts +2 -2
- package/dist/lifecycle.d.ts +6 -0
- package/dist/lifecycle.js +58 -0
- package/dist/services/audit-service.d.ts +4 -4
- package/dist/services/feature-flag-service.d.ts +3 -3
- package/dist/services/{http-personas.d.ts → http-virtual-users.d.ts} +25 -47
- package/dist/services/{http-personas.js → http-virtual-users.js} +29 -53
- package/dist/services/index.d.ts +2 -2
- package/dist/services/index.js +1 -1
- package/dist/services/meta-service.d.ts +6 -6
- package/dist/services/meta-service.js +8 -8
- package/dist/{wirings/workflow → services}/scenario-cookie-jar.d.ts +2 -0
- package/dist/{wirings/workflow → services}/scenario-cookie-jar.js +18 -14
- package/dist/services/scoped-secret-service.d.ts +1 -0
- package/dist/services/scoped-secret-service.js +3 -0
- package/dist/services/secret-service.d.ts +6 -0
- package/dist/services/system-role-guard.d.ts +1 -1
- package/dist/services/typed-secret-service.d.ts +1 -0
- package/dist/services/typed-secret-service.js +7 -0
- package/dist/services/virtual-user-sign-in.d.ts +52 -0
- package/dist/services/virtual-user-sign-in.js +80 -0
- package/dist/services/virtual-user-statement.d.ts +31 -0
- package/dist/services/virtual-user-statement.js +24 -0
- package/dist/services/{personas-service.d.ts → virtual-users-service.d.ts} +25 -23
- package/dist/services/{personas-service.js → virtual-users-service.js} +3 -3
- package/dist/testing/service-tests/secret-service-tests.js +9 -0
- package/dist/types/core.types.d.ts +11 -11
- package/dist/utils.d.ts +2 -5
- package/dist/utils.js +1 -38
- package/dist/wirings/cli/cli-runner.js +24 -9
- package/dist/wirings/http/http-runner.js +4 -0
- package/dist/wirings/http/http.types.d.ts +1 -0
- package/dist/wirings/http/pikku-fetch-http-response.d.ts +1 -0
- package/dist/wirings/http/pikku-fetch-http-response.js +12 -0
- package/dist/wirings/http/web-request.js +7 -0
- package/dist/wirings/role/define-system-role.d.ts +1 -1
- package/dist/wirings/role/define-system-role.js +1 -1
- package/dist/wirings/{actor-flow/actor-flow.types.d.ts → virtual-user/conversation/conversation.types.d.ts} +5 -5
- package/dist/wirings/virtual-user/conversation/index.d.ts +2 -0
- package/dist/wirings/virtual-user/conversation/run-conversation.d.ts +36 -0
- package/dist/wirings/{actor-flow → virtual-user/conversation}/run-conversation.js +30 -30
- package/dist/wirings/virtual-user/define-virtual-users.d.ts +32 -0
- package/dist/wirings/{persona/define-personas.js → virtual-user/define-virtual-users.js} +9 -9
- package/dist/wirings/virtual-user/index.d.ts +30 -7
- package/dist/wirings/virtual-user/index.js +23 -4
- package/dist/wirings/virtual-user/prepare-virtual-user-run.d.ts +8 -8
- package/dist/wirings/virtual-user/prepare-virtual-user-run.js +9 -9
- package/dist/wirings/virtual-user/run-virtual-user.d.ts +6 -6
- package/dist/wirings/virtual-user/run-virtual-user.js +10 -10
- package/dist/wirings/{persona/validate-personas.d.ts → virtual-user/validate-virtual-users.d.ts} +11 -11
- package/dist/wirings/{persona/validate-personas.js → virtual-user/validate-virtual-users.js} +24 -24
- package/dist/wirings/virtual-user/virtual-user-agents.d.ts +7 -7
- package/dist/wirings/virtual-user/virtual-user-agents.js +2 -2
- package/dist/wirings/{persona/persona-app-scopes.d.ts → virtual-user/virtual-user-app-scopes.d.ts} +10 -10
- package/dist/wirings/{persona/persona-app-scopes.js → virtual-user/virtual-user-app-scopes.js} +12 -12
- package/dist/wirings/virtual-user/virtual-user-catalogue.d.ts +3 -3
- package/dist/wirings/virtual-user/virtual-user-catalogue.js +2 -2
- package/dist/wirings/{persona/persona.types.d.ts → virtual-user/virtual-user-declaration.types.d.ts} +24 -24
- package/dist/wirings/virtual-user/virtual-user-derive.js +13 -7
- package/dist/wirings/virtual-user/virtual-user-dispositions.d.ts +1 -1
- package/dist/wirings/{persona/persona-email.d.ts → virtual-user/virtual-user-email.d.ts} +11 -11
- package/dist/wirings/{persona/persona-email.js → virtual-user/virtual-user-email.js} +19 -19
- package/dist/wirings/{persona/persona-environments.d.ts → virtual-user/virtual-user-environments.d.ts} +10 -10
- package/dist/wirings/{persona/persona-environments.js → virtual-user/virtual-user-environments.js} +21 -21
- package/dist/wirings/virtual-user/virtual-user-intents.d.ts +3 -3
- package/dist/wirings/virtual-user/virtual-user-intents.js +3 -3
- package/dist/wirings/{persona/persona-mailbox.d.ts → virtual-user/virtual-user-mailbox.d.ts} +4 -4
- package/dist/wirings/virtual-user/virtual-user-run-store.d.ts +4 -4
- package/dist/wirings/virtual-user/virtual-user-scaffold.d.ts +42 -61
- package/dist/wirings/virtual-user/virtual-user-scaffold.js +69 -117
- package/dist/wirings/virtual-user/virtual-user-schedule-store.d.ts +15 -15
- package/dist/wirings/virtual-user/virtual-user-schedule.d.ts +6 -6
- package/dist/wirings/virtual-user/virtual-user-schedule.js +11 -11
- package/dist/wirings/virtual-user/virtual-user-target.d.ts +6 -6
- package/dist/wirings/virtual-user/virtual-user-target.js +5 -5
- package/dist/wirings/virtual-user/virtual-user.types.d.ts +11 -11
- package/dist/wirings/virtual-user/virtual-user.types.js +1 -1
- package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +9 -9
- package/dist/wirings/workflow/pikku-scenario-service.d.ts +28 -28
- package/dist/wirings/workflow/pikku-scenario-service.js +77 -77
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +2 -2
- package/dist/wirings/workflow/pikku-workflow-service.js +4 -4
- package/dist/wirings/workflow/scenario-prose.d.ts +8 -8
- package/dist/wirings/workflow/scenario-prose.js +12 -8
- package/dist/wirings/workflow/scenario-run.types.d.ts +13 -13
- package/dist/wirings/workflow/scenario-step.types.d.ts +23 -23
- package/dist/wirings/workflow/workflow.types.d.ts +2 -2
- package/knowledge/decisions/index.md +0 -2
- package/knowledge/decisions/internals/a-credential-name-declared-twice-must-agree-on-schema-and-type.md +29 -0
- package/knowledge/decisions/internals/a-grant-can-name-a-scope-declared-without-its-addon.md +29 -0
- package/knowledge/decisions/internals/a-scheduled-task-writes-its-caller-session-before-it-runs.md +22 -0
- package/knowledge/decisions/internals/a-secret-set-in-memory-shadows-the-variable-of-the-same-name.md +28 -0
- package/knowledge/decisions/internals/a-virtual-user-acts-through-invokeraw-so-a-refusal-is-data.md +32 -0
- package/knowledge/decisions/internals/a-virtual-user-cadence-is-a-row-not-a-timer.md +12 -12
- package/knowledge/decisions/internals/a-virtual-user-converse-signs-in-before-its-first-turn.md +24 -0
- package/knowledge/decisions/internals/a-virtual-user-email-is-computed-with-the-run-id-as-a-sub-address.md +34 -0
- package/knowledge/decisions/internals/a-virtual-user-run-is-not-a-workflow-but-it-needs-a-trigger.md +2 -2
- package/knowledge/decisions/internals/an-agent-is-offered-under-its-registry-key-and-only-within-the-virtual-users-scopes.md +27 -0
- package/knowledge/decisions/internals/an-oauth2-credential-implies-an-optional-app-secret.md +26 -0
- package/knowledge/decisions/internals/analytics-identity-resolvers-run-in-declared-order.md +22 -0
- package/knowledge/decisions/internals/feature-flag-declarations-refuse-an-empty-anyof-and-conflicting-scopes.md +22 -0
- package/knowledge/decisions/internals/feature-flags-fail-open-and-never-enforce-access.md +28 -0
- package/knowledge/decisions/internals/flag-sync-rewrites-only-the-declared-text.md +24 -0
- package/knowledge/decisions/internals/in-a-scenario-a-4xx-is-data-not-an-exception.md +3 -3
- package/knowledge/decisions/internals/index.md +46 -31
- package/knowledge/decisions/internals/one-project-shape-check-two-validators.md +10 -10
- package/knowledge/decisions/internals/role-names-cannot-contain-the-scope-separator.md +30 -0
- package/knowledge/decisions/internals/scenario-agent-calls-sign-in-on-401-only.md +23 -19
- package/knowledge/decisions/internals/scenario-steps-return-drained-response-records.md +2 -2
- package/knowledge/decisions/internals/scenarios-live-in-files-named-for-them.md +12 -12
- package/knowledge/decisions/internals/the-core-scope-validator-refuses-separator-wildcard-and-empty-segments.md +22 -0
- package/knowledge/decisions/internals/the-pikku-user-id-resolves-in-a-fixed-order.md +24 -0
- 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
- 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
- package/knowledge/decisions/internals/validate-checks-virtual-users-through-a-shared-module.md +43 -0
- 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
- package/knowledge/decisions/internals/virtual-user-conversation-verdicts-are-llm-self-evaluations.md +25 -0
- package/knowledge/decisions/internals/virtual-user-conversations-seed-a-hidden-kickoff-message.md +23 -0
- package/knowledge/decisions/internals/virtual-users-are-declared-in-one-definevirtualusers-call-per-codebase.md +30 -0
- package/knowledge/decisions/internals/workflow-core-never-imports-a-browser-driver.md +5 -5
- package/knowledge/decisions/internals/workflow-run-capabilities-are-extensions-not-subclasses.md +2 -2
- package/knowledge/decisions/internals/workflow-scenario-assertions-never-retry-and-record-one-step.md +4 -4
- package/knowledge/decisions/internals/workflow-scenario-hooks-are-a-scenario-only-affordance.md +1 -1
- package/knowledge/decisions/internals/workflow-scenario-prose-is-rendered-from-typed-calls-not-parsed-from-english.md +2 -2
- package/knowledge/decisions/internals/workflow-scenario-step-targets-are-string-literals-for-the-inspector.md +1 -1
- package/knowledge/decisions/internals/workflow-suspended-runs-keep-their-in-process-context.md +1 -1
- package/knowledge/decisions/security/a-bearer-token-checked-against-a-secret-reads-it-per-request.md +26 -0
- package/knowledge/decisions/security/a-call-without-a-session-raises-missing-session-not-forbidden.md +20 -0
- package/knowledge/decisions/security/a-caller-cookie-wins-over-the-jar-for-the-same-name.md +23 -0
- package/knowledge/decisions/security/a-channel-lifecycle-acts-as-the-socket-upgrade-session.md +16 -0
- package/knowledge/decisions/security/a-channel-requires-a-session-unless-it-says-auth-false.md +26 -0
- package/knowledge/decisions/security/a-credential-read-path-follows-its-declared-type-not-absence.md +32 -0
- package/knowledge/decisions/security/a-credential-type-is-a-literal-the-inspector-checks-at-declaration.md +27 -0
- package/knowledge/decisions/security/a-first-party-cookie-is-written-only-after-its-purposes-consent.md +33 -0
- package/knowledge/decisions/security/a-readonly-session-reaches-only-readonly-functions.md +25 -0
- package/knowledge/decisions/security/a-scaffold-flag-says-a-surface-exists-not-who-may-call-it.md +10 -5
- package/knowledge/decisions/security/a-scheduled-virtual-user-run-needs-no-admin-at-run-time.md +27 -0
- package/knowledge/decisions/security/a-scoped-credential-view-is-limited-to-declared-names.md +26 -0
- package/knowledge/decisions/security/a-scoped-secret-view-reads-only-declared-keys-and-never-writes.md +25 -0
- package/knowledge/decisions/security/a-secret-is-sent-only-to-the-hosts-it-declares.md +29 -0
- package/knowledge/decisions/security/a-step-can-name-an-identity-no-virtual-user-holds-through-per-call-headers.md +25 -0
- package/knowledge/decisions/security/a-stopped-run-by-id-skips-the-ownership-check.md +24 -0
- package/knowledge/decisions/security/a-vault-secret-redacts-on-serialization-and-throws-on-coercion.md +29 -0
- package/knowledge/decisions/security/a-virtual-user-catalogue-entry-is-filtered-by-scope-and-approval-is-denied-by-default.md +30 -0
- package/knowledge/decisions/security/a-virtual-user-environment-fails-closed.md +38 -0
- package/knowledge/decisions/security/a-virtual-user-never-runs-against-production.md +23 -0
- package/knowledge/decisions/security/a-virtual-user-reads-its-roles-from-the-apps-own-rpc-before-better-auth.md +27 -0
- package/knowledge/decisions/security/a-virtual-user-run-treats-an-unresolved-environment-as-production.md +41 -0
- package/knowledge/decisions/security/a-virtual-user-scopes-are-expanded-from-its-roles-once-at-run-preparation.md +25 -0
- package/knowledge/decisions/security/a-virtual-user-whose-roles-drift-from-the-declaration-refuses-to-run.md +32 -0
- package/knowledge/decisions/security/addon-screen-scopes-hide-and-do-not-enforce.md +20 -0
- package/knowledge/decisions/security/an-addon-header-can-only-narrow-the-session.md +26 -0
- package/knowledge/decisions/security/an-addon-instance-reads-only-the-secrets-and-credentials-it-is-named.md +33 -0
- package/knowledge/decisions/security/an-addon-may-reach-only-itself-and-the-addons-it-uses.md +16 -0
- package/knowledge/decisions/security/an-api-key-is-jwt-decoded-into-the-session.md +26 -0
- package/knowledge/decisions/security/an-external-virtual-user-caller-presents-one-signed-statement.md +38 -0
- package/knowledge/decisions/security/an-inbound-webhook-source-dispatches-only-verified-requests.md +31 -0
- package/knowledge/decisions/security/an-mcp-call-with-no-http-request-stays-anonymous.md +18 -0
- package/knowledge/decisions/security/an-omitted-user-id-addresses-the-platform-credential.md +32 -0
- package/knowledge/decisions/security/analytics-identity-is-stamped-from-the-session-not-the-event.md +24 -0
- package/knowledge/decisions/security/app-access-is-a-scope-tree-synthesised-from-virtual-users.md +26 -0
- package/knowledge/decisions/security/approval-policy-decides-who-answers-a-tool-call.md +27 -0
- package/knowledge/decisions/security/auth-false-on-a-session-function-warns-and-still-requires-one.md +25 -0
- package/knowledge/decisions/security/bearer-token-hashes-are-unpeppered-sha256.md +18 -0
- package/knowledge/decisions/security/consent-is-read-from-a-cookie-and-a-recognised-denial-counts-as-refusal.md +29 -0
- package/knowledge/decisions/security/cors-defaults-to-any-origin-and-refuses-the-wildcard-with-credentials.md +22 -0
- package/knowledge/decisions/security/credential-backends-share-one-conformance-suite-for-per-user-isolation.md +29 -0
- package/knowledge/decisions/security/each-stage-has-one-virtual-user-key-pair.md +27 -0
- package/knowledge/decisions/security/hmac-verification-fails-closed-on-empty-inputs.md +25 -0
- package/knowledge/decisions/security/index.md +88 -24
- package/knowledge/decisions/security/local-content-refuses-private-buckets-under-the-public-segment.md +21 -0
- package/knowledge/decisions/security/mail-is-allowlisted-before-a-virtual-user-run-sees-it.md +38 -0
- package/knowledge/decisions/security/mcp-resources-tools-and-prompts-take-sessionless-functions.md +18 -0
- package/knowledge/decisions/security/origin-locked-routes-match-the-origin-exactly.md +22 -0
- package/knowledge/decisions/security/oss-auth-works-without-pikku-studio-cloud.md +26 -0
- package/knowledge/decisions/security/outbound-webhooks-use-an-allowlist-when-configured.md +24 -0
- package/knowledge/decisions/security/pikku-carries-virtual-user-scopes-as-data-and-the-app-grants-them.md +35 -0
- package/knowledge/decisions/security/scoped-content-access-is-a-root-folder-with-longest-prefix-grants.md +31 -0
- package/knowledge/decisions/security/services-without-secrets-get-a-throwing-secrets-accessor.md +22 -0
- package/knowledge/decisions/security/shared-guards-refuse-to-mutate-or-shadow-a-system-role.md +34 -0
- package/knowledge/decisions/security/signed-uploads-are-verified-by-the-same-check-as-signed-reads.md +26 -0
- package/knowledge/decisions/security/system-role-scopes-must-be-declared-with-define-scope.md +24 -0
- package/knowledge/decisions/security/system-roles-are-additive-and-immutable.md +16 -0
- package/knowledge/decisions/security/the-channel-rpc-does-not-send-the-callers-session.md +21 -0
- package/knowledge/decisions/security/the-remote-jobs-inbox-fails-closed-without-a-secret.md +24 -0
- package/knowledge/decisions/security/the-remote-rpc-gate-fails-closed-and-binds-the-token-to-its-function.md +34 -0
- package/knowledge/decisions/security/the-workflow-status-stream-rechecks-ownership-on-every-poll.md +16 -0
- package/knowledge/decisions/security/two-credentials-on-one-key-must-share-a-read-mode.md +29 -0
- package/knowledge/decisions/security/verified-bearer-claims-are-pass-through-data-that-core-never-fills.md +23 -0
- package/knowledge/decisions/security/virtual-user-catalogue-excludes-the-machinery-that-runs-virtual-users.md +25 -0
- 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
- package/knowledge/decisions/security/virtual-user-run-records-are-gated-behind-a-read-scope.md +18 -0
- package/knowledge/decisions/security/virtual-user-sign-in-does-not-exist-in-production.md +25 -0
- package/knowledge/decisions/security/virtual-user-sign-in-has-one-door.md +42 -0
- 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
- package/knowledge/decisions/security/virtual-user-sign-in-only-works-for-virtual-user-flagged-users.md +29 -0
- package/knowledge/decisions/security/workflow-helper-functions-are-sessionless-by-declaration.md +18 -0
- 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
- package/knowledge/decisions/security/workflow-scenario-steps-are-never-network-invocable.md +5 -5
- 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
- package/knowledge/decisions/security/writing-a-virtual-user-schedule-is-gated-by-its-own-scope.md +18 -0
- package/knowledge/index.md +0 -2
- package/knowledge/questions/a-bearer-jwt-with-no-identity-becomes-a-session.md +24 -0
- package/knowledge/questions/dev-quick-login-as-impersonation.md +25 -0
- package/knowledge/questions/does-a-delayed-rpc-run-as-the-session-it-was-scheduled-with.md +26 -0
- package/knowledge/questions/does-a-user-id-with-a-colon-read-another-users-credentials.md +27 -0
- package/knowledge/questions/does-a-wirecli-command-need-a-session-by-default.md +26 -0
- package/knowledge/questions/does-an-adversarial-in-scope-success-count-as-a-finding.md +26 -0
- package/knowledge/questions/does-approve-step-need-the-run-owners-session-or-the-gates-approvers.md +34 -0
- package/knowledge/questions/does-cors-origin-true-reflect-any-origin-with-credentials.md +20 -0
- package/knowledge/questions/does-skip-user-session-do-anything-on-a-channel.md +24 -0
- package/knowledge/questions/does-the-store-session-match-the-other-two.md +19 -0
- package/knowledge/questions/index.md +25 -2
- package/knowledge/questions/is-the-agent-score-worker-reachable-without-a-session.md +21 -0
- package/knowledge/questions/live-scheduled-tests-may-write.md +19 -0
- package/knowledge/questions/provision-virtual-users-has-no-caller-in-this-repo.md +23 -0
- package/knowledge/questions/remote-secret-refuses-requests-without-a-remote-token-on-every-path.md +32 -0
- package/knowledge/questions/should-a-middleware-set-session-persist-to-the-store.md +25 -0
- package/knowledge/questions/should-a-scoped-secret-view-throw-from-has-secret-for-a-disallowed-key.md +23 -0
- package/knowledge/questions/should-a-wrong-bearer-token-be-anonymous-or-refused.md +35 -0
- package/knowledge/questions/should-an-empty-webhook-signing-secret-send-unsigned.md +23 -0
- package/knowledge/questions/should-http-virtual-user-sessions-reset-between-scenarios-in-one-run.md +27 -0
- package/knowledge/questions/should-the-cookie-jar-scope-cookies-to-the-api-origin.md +26 -0
- package/knowledge/questions/should-voice-input-fetch-audio-urls-without-a-host-allowlist.md +20 -0
- package/knowledge/questions/staging-impersonation-rules.md +27 -0
- package/knowledge/questions/virtual-user-keys-on-cloud-stages-are-pikku-studios-to-build.md +34 -0
- package/knowledge/questions/virtual-user-statement-replay-is-per-process.md +20 -0
- package/knowledge/questions/what-an-impersonated-session-carries.md +22 -0
- package/package.json +3 -3
- package/src/public-surface.json +43 -47
- package/dist/services/persona-actor-secret.d.ts +0 -38
- package/dist/services/persona-actor-secret.js +0 -39
- package/dist/services/persona-sign-in.d.ts +0 -117
- package/dist/services/persona-sign-in.js +0 -154
- package/dist/wirings/actor-flow/index.d.ts +0 -2
- package/dist/wirings/actor-flow/run-conversation.d.ts +0 -36
- package/dist/wirings/persona/define-personas.d.ts +0 -32
- package/dist/wirings/persona/index.d.ts +0 -23
- package/dist/wirings/persona/index.js +0 -19
- package/knowledge/decisions/internals/actor-flow-conversations-seed-a-hidden-kickoff-message.md +0 -23
- package/knowledge/decisions/internals/actor-flow-verdicts-are-llm-self-evaluations.md +0 -25
- package/knowledge/decisions/internals/validate-checks-personas-through-a-shared-module.md +0 -43
- package/knowledge/decisions/security/actor-sign-in-only-works-for-actor-flagged-users.md +0 -31
- package/knowledge/decisions/security/an-actor-credential-is-derived-per-persona.md +0 -42
- package/knowledge/decisions/security/pikku-carries-actor-scopes-as-data-and-the-app-grants-them.md +0 -26
- /package/dist/wirings/{actor-flow/actor-flow.types.js → virtual-user/conversation/conversation.types.js} +0 -0
- /package/dist/wirings/{actor-flow → virtual-user/conversation}/index.js +0 -0
- /package/dist/wirings/{persona/persona.types.js → virtual-user/virtual-user-declaration.types.js} +0 -0
- /package/dist/wirings/{persona/persona-mailbox.js → virtual-user/virtual-user-mailbox.js} +0 -0
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* A
|
|
2
|
+
* A virtual user's email address is computed, never declared.
|
|
3
3
|
*
|
|
4
|
-
* A
|
|
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
|
|
10
|
+
* Lower-cases and strips a virtual user id down to something an address can carry.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
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
|
|
16
|
+
export declare const virtualUserEmailLabel: (virtualUserId: string) => string;
|
|
17
17
|
/**
|
|
18
|
-
* The address a
|
|
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
|
|
28
|
+
export declare const virtualUserEmail: (virtualUserId: string, domain: string, runId?: string) => string;
|
|
29
29
|
/**
|
|
30
|
-
* Every address in a run, keyed by
|
|
30
|
+
* Every address in a run, keyed by virtual user.
|
|
31
31
|
*
|
|
32
|
-
* All of a
|
|
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
|
|
35
|
+
* under test refuse to link the very thing the virtual user declared as linked.
|
|
36
36
|
*/
|
|
37
|
-
export declare const
|
|
37
|
+
export declare const virtualUserEmails: (virtualUserIds: readonly string[], domain: string, runId?: string) => Record<string, string>;
|
|
@@ -1,31 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* A
|
|
2
|
+
* A virtual user's email address is computed, never declared.
|
|
3
3
|
*
|
|
4
|
-
* A
|
|
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
|
|
11
|
+
* Lower-cases and strips a virtual user id down to something an address can carry.
|
|
12
12
|
*
|
|
13
|
-
*
|
|
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
|
|
18
|
-
const label =
|
|
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(`
|
|
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
|
|
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
|
|
39
|
-
const label =
|
|
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(`
|
|
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 ? `+${
|
|
44
|
+
const suffix = runId ? `+${virtualUserEmailLabel(runId)}` : '';
|
|
45
45
|
return `${label}${suffix}@${cleanDomain}`;
|
|
46
46
|
};
|
|
47
47
|
/**
|
|
48
|
-
* Every address in a run, keyed by
|
|
48
|
+
* Every address in a run, keyed by virtual user.
|
|
49
49
|
*
|
|
50
|
-
* All of a
|
|
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
|
|
53
|
+
* under test refuse to link the very thing the virtual user declared as linked.
|
|
54
54
|
*/
|
|
55
|
-
export const
|
|
55
|
+
export const virtualUserEmails = (virtualUserIds, domain, runId) => {
|
|
56
56
|
const emails = {};
|
|
57
57
|
const seen = new Map();
|
|
58
|
-
for (const id of
|
|
59
|
-
const address =
|
|
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(`
|
|
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
|
|
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
|
|
11
|
+
export interface VirtualUserEnvironment {
|
|
12
12
|
production?: boolean;
|
|
13
13
|
}
|
|
14
|
-
/** What a
|
|
15
|
-
export interface
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
45
|
+
export declare const virtualUserEnvironmentRefusal: (id: string, virtualUser: VirtualUserEnvironmentSubject, environmentName: string | undefined, environments: Readonly<Record<string, VirtualUserEnvironment>>) => string | null;
|
package/dist/wirings/{persona/persona-environments.js → virtual-user/virtual-user-environments.js}
RENAMED
|
@@ -1,45 +1,45 @@
|
|
|
1
1
|
import { PRODUCTION_DISPOSITION, } from '../virtual-user/virtual-user.types.js';
|
|
2
2
|
/**
|
|
3
|
-
* The environments a
|
|
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
|
|
10
|
-
if (
|
|
11
|
-
return [...
|
|
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
|
|
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
|
|
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
|
|
26
|
-
if (!
|
|
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
|
|
31
|
+
for (const name of virtualUser.environments) {
|
|
32
32
|
const env = environments[name];
|
|
33
33
|
if (!env) {
|
|
34
|
-
errors.push(`
|
|
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 &&
|
|
41
|
-
errors.push(`
|
|
42
|
-
`'${
|
|
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
|
|
60
|
+
export const virtualUserEnvironmentRefusal = (id, virtualUser, environmentName, environments) => {
|
|
61
61
|
if (!environmentName) {
|
|
62
|
-
return (`Refusing to sign in
|
|
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
|
|
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 &&
|
|
71
|
-
return (`Refusing to sign in
|
|
72
|
-
`its disposition is '${
|
|
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 =
|
|
75
|
+
const allowed = resolveVirtualUserEnvironments(virtualUser, environments);
|
|
76
76
|
if (!allowed.includes(environmentName)) {
|
|
77
|
-
return (`Refusing to sign in
|
|
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
|
|
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
|
|
75
|
+
* records which virtual users each scenario runs as.
|
|
76
76
|
*/
|
|
77
|
-
export declare const
|
|
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
|
|
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
|
|
140
|
+
* records which virtual users each scenario runs as.
|
|
141
141
|
*/
|
|
142
|
-
export const
|
|
142
|
+
export const intentsForVirtualUser = (sources, virtualUserId) => sources.filter((source) => !source.virtualUsers?.length || source.virtualUsers.includes(virtualUserId));
|
package/dist/wirings/{persona/persona-mailbox.d.ts → virtual-user/virtual-user-mailbox.d.ts}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** One email a
|
|
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
|
|
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
|
|
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
|
|
44
|
+
export interface VirtualUserMailbox {
|
|
45
45
|
/**
|
|
46
46
|
* Wait for a matching email, or reject on timeout.
|
|
47
47
|
*
|
|
@@ -16,7 +16,7 @@ import type { IntentRecord, StepRecord, VirtualUserDisposition, VirtualUserFindi
|
|
|
16
16
|
*/
|
|
17
17
|
export interface VirtualUserRunRecord {
|
|
18
18
|
runId: string;
|
|
19
|
-
|
|
19
|
+
virtualUserId: string;
|
|
20
20
|
disposition: VirtualUserDisposition;
|
|
21
21
|
/** What makes a run replayable at all — a finding without it is an anecdote. */
|
|
22
22
|
seed: number;
|
|
@@ -59,7 +59,7 @@ export interface VirtualUserRunRecord {
|
|
|
59
59
|
}
|
|
60
60
|
/** What a run is created with — everything else is filled in by the outcome. */
|
|
61
61
|
export interface VirtualUserRunStart {
|
|
62
|
-
|
|
62
|
+
virtualUserId: string;
|
|
63
63
|
disposition: VirtualUserDisposition;
|
|
64
64
|
seed: number;
|
|
65
65
|
goals?: readonly string[];
|
|
@@ -101,9 +101,9 @@ export interface VirtualUserRunStore {
|
|
|
101
101
|
/** Marks a run `failed`. The run itself broke; it has no findings. */
|
|
102
102
|
fail(runId: string, error: string): Promise<void>;
|
|
103
103
|
get(runId: string): Promise<VirtualUserRunRecord | null>;
|
|
104
|
-
/** Newest first. `
|
|
104
|
+
/** Newest first. `virtualUserId` narrows to one virtual user's history. */
|
|
105
105
|
list(options?: {
|
|
106
|
-
|
|
106
|
+
virtualUserId?: string;
|
|
107
107
|
limit?: number;
|
|
108
108
|
offset?: number;
|
|
109
109
|
}): Promise<VirtualUserRunRecord[]>;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { type InProcessAuth } from '../../services/virtual-user-sign-in.js';
|
|
1
2
|
import type { Logger } from '../../services/logger.js';
|
|
2
3
|
import type { MetaService } from '../../services/meta-service.js';
|
|
3
4
|
import type { VariablesService } from '../../services/variables-service.js';
|
|
4
5
|
import type { AgentRunnerService } from '../../services/agent-runner-service.js';
|
|
5
|
-
import type {
|
|
6
|
-
import type {
|
|
7
|
-
import type {
|
|
6
|
+
import type { HttpVirtualUsersConfig } from '../../services/http-virtual-users.js';
|
|
7
|
+
import type { ResolvedVirtualUser, ScenarioVirtualUsers } from '../../services/virtual-users-service.js';
|
|
8
|
+
import type { VirtualUserEnvironment } from '../virtual-user/virtual-user-environments.js';
|
|
8
9
|
import type { StepRecord, VirtualUserDisposition } from './virtual-user.types.js';
|
|
9
10
|
import type { VirtualUserRunRecord, VirtualUserRunStore } from './virtual-user-run-store.js';
|
|
10
11
|
import type { VirtualUserScheduleRecord, VirtualUserScheduleStore } from './virtual-user-schedule-store.js';
|
|
@@ -20,11 +21,11 @@ import type { VirtualUserTickResult } from './virtual-user-schedule.js';
|
|
|
20
21
|
* once rather than in every generated copy of it.
|
|
21
22
|
*
|
|
22
23
|
* What an application does supply arrives as a parameter — its declared
|
|
23
|
-
*
|
|
24
|
+
* virtual users, its `createVirtualUsers`, its config — because those are the only
|
|
24
25
|
* things codegen knows that this cannot.
|
|
25
26
|
*/
|
|
26
|
-
/**
|
|
27
|
-
export type
|
|
27
|
+
/** Virtual user id → the declaration, which is what `virtualUserConfigs` is. */
|
|
28
|
+
export type ScaffoldVirtualUsers = Record<string, ResolvedVirtualUser>;
|
|
28
29
|
/**
|
|
29
30
|
* The variables a scaffolded run reads.
|
|
30
31
|
*
|
|
@@ -39,48 +40,27 @@ export declare const VIRTUAL_USER_VARIABLES: {
|
|
|
39
40
|
* somewhere it only assumed was itself.
|
|
40
41
|
*/
|
|
41
42
|
readonly apiUrl: 'VIRTUAL_USER_API_URL';
|
|
42
|
-
readonly secret: 'SCENARIO_ACTOR_SECRET';
|
|
43
43
|
readonly model: 'VIRTUAL_USER_MODEL';
|
|
44
44
|
/**
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* auth somewhere other than the root — `/api/auth` is the common one — has no
|
|
48
|
-
* other way to say so, and without them the run signs in against a 404 and
|
|
49
|
-
* spends its whole budget thinking about why nothing works.
|
|
45
|
+
* Where the app serves its exposed RPCs, as a scenario run reads it. An app
|
|
46
|
+
* that mounts them somewhere other than `/rpc` has no other way to say so.
|
|
50
47
|
*/
|
|
51
|
-
readonly signInPath: 'SCENARIO_SIGN_IN_PATH';
|
|
52
48
|
readonly rpcPath: 'SCENARIO_RPC_PATH';
|
|
53
|
-
/**
|
|
54
|
-
* The deployed way in. A Fabric operator token is asymmetric — a stage can
|
|
55
|
-
* verify one and can never mint one — so unlike the actor secret it is safe
|
|
56
|
-
* for a run against a real environment. Read from the environment only as the
|
|
57
|
-
* fallback for a run nobody handed a token to, which is what a schedule is.
|
|
58
|
-
*/
|
|
59
|
-
readonly operatorToken: 'FABRIC_OPERATOR_TOKEN';
|
|
60
49
|
};
|
|
61
50
|
/**
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
* Both are better-auth plugins mounted side by side, so `SCENARIO_SIGN_IN_PATH`
|
|
65
|
-
* names the mount and the last segment is ours to pick — an app that moved auth
|
|
66
|
-
* to `/api/auth` says so once and both paths follow. A path that names neither
|
|
67
|
-
* plugin is left alone, since it was configured deliberately.
|
|
68
|
-
*/
|
|
69
|
-
export declare const signInPathFor: (configured: string | undefined, plugin: 'actor' | 'fabric') => string | undefined;
|
|
70
|
-
/**
|
|
71
|
-
* The declared persona behind an id, refused unless it is one a run may be.
|
|
51
|
+
* The declared virtual user behind an id, refused unless it is one a run may be.
|
|
72
52
|
*
|
|
73
|
-
* An acted-upon
|
|
53
|
+
* An acted-upon virtual user has no session of its own, and running one would race
|
|
74
54
|
* whatever scenario acts on it.
|
|
75
55
|
*/
|
|
76
|
-
export declare const
|
|
56
|
+
export declare const runnableVirtualUser: (virtualUsers: ScaffoldVirtualUsers, virtualUserId: string) => ResolvedVirtualUser;
|
|
77
57
|
/** The store, or the error naming the one to wire. */
|
|
78
58
|
export declare const requireVirtualUserRunStore: (store: VirtualUserRunStore | undefined, reading?: boolean) => VirtualUserRunStore;
|
|
79
59
|
export declare const requireVirtualUserScheduleStore: (store: VirtualUserScheduleStore | undefined) => VirtualUserScheduleStore;
|
|
80
60
|
/** What a caller asked for, before the declaration fills in what it left out. */
|
|
81
61
|
export interface StartVirtualUserRunParams {
|
|
82
62
|
store: VirtualUserRunStore | undefined;
|
|
83
|
-
|
|
63
|
+
virtualUsers: ScaffoldVirtualUsers;
|
|
84
64
|
/**
|
|
85
65
|
* The app's config, read only for `nodeEnv` — structural because an
|
|
86
66
|
* application's Config is its own interface and need not declare it at all.
|
|
@@ -89,11 +69,11 @@ export interface StartVirtualUserRunParams {
|
|
|
89
69
|
config: {
|
|
90
70
|
nodeEnv?: string;
|
|
91
71
|
} | undefined;
|
|
92
|
-
/** `environments` from pikku.config.json, as generated beside the
|
|
93
|
-
environments?: Readonly<Record<string,
|
|
72
|
+
/** `environments` from pikku.config.json, as generated beside the virtual users. */
|
|
73
|
+
environments?: Readonly<Record<string, VirtualUserEnvironment>>;
|
|
94
74
|
/** Which of them this process is. Defaults to `PIKKU_ENV`. */
|
|
95
75
|
environment?: string;
|
|
96
|
-
|
|
76
|
+
virtualUserId: string;
|
|
97
77
|
disposition?: string;
|
|
98
78
|
seed?: number;
|
|
99
79
|
goals?: string[];
|
|
@@ -104,7 +84,7 @@ export interface StartVirtualUserRunParams {
|
|
|
104
84
|
/** The recorded run, and the values the dispatch has to carry unchanged. */
|
|
105
85
|
export interface StartedVirtualUserRun {
|
|
106
86
|
runId: string;
|
|
107
|
-
|
|
87
|
+
virtualUserId: string;
|
|
108
88
|
disposition: VirtualUserDisposition;
|
|
109
89
|
seed: number;
|
|
110
90
|
goals: string[];
|
|
@@ -117,7 +97,7 @@ export interface StartedVirtualUserRun {
|
|
|
117
97
|
* scheduled tick have in common. The dispatch that follows is typed off the
|
|
118
98
|
* app's RPC map, so it stays in the generated wiring.
|
|
119
99
|
*/
|
|
120
|
-
export declare const startVirtualUserRun: ({ store,
|
|
100
|
+
export declare const startVirtualUserRun: ({ store, virtualUsers, config, environments, environment, virtualUserId, disposition: requested, seed: requestedSeed, goals, memory, startedBy, }: StartVirtualUserRunParams) => Promise<StartedVirtualUserRun>;
|
|
121
101
|
/**
|
|
122
102
|
* One run on the wire.
|
|
123
103
|
*
|
|
@@ -127,7 +107,7 @@ export declare const startVirtualUserRun: ({ store, personas, config, environmen
|
|
|
127
107
|
*/
|
|
128
108
|
export declare const serializeVirtualUserRun: (run: VirtualUserRunRecord) => {
|
|
129
109
|
runId: string;
|
|
130
|
-
|
|
110
|
+
virtualUserId: string;
|
|
131
111
|
disposition: VirtualUserDisposition;
|
|
132
112
|
seed: number;
|
|
133
113
|
status: "completed" | "failed" | "running";
|
|
@@ -175,8 +155,8 @@ export declare const serializeVirtualUserSteps: (steps: readonly StepRecord[]) =
|
|
|
175
155
|
* takes; the engine's own duration also accepts `'30m'`, which nothing on this
|
|
176
156
|
* side ever writes.
|
|
177
157
|
*/
|
|
178
|
-
export declare const serializeVirtualUserSchedule: (schedule: VirtualUserScheduleRecord,
|
|
179
|
-
|
|
158
|
+
export declare const serializeVirtualUserSchedule: (schedule: VirtualUserScheduleRecord, virtualUsers: ScaffoldVirtualUsers) => {
|
|
159
|
+
virtualUserId: string;
|
|
180
160
|
enabled: boolean;
|
|
181
161
|
disposition: VirtualUserDisposition;
|
|
182
162
|
goals: string[];
|
|
@@ -197,8 +177,8 @@ export declare const serializeVirtualUserSchedule: (schedule: VirtualUserSchedul
|
|
|
197
177
|
};
|
|
198
178
|
export interface WriteVirtualUserScheduleParams {
|
|
199
179
|
store: VirtualUserScheduleStore | undefined;
|
|
200
|
-
|
|
201
|
-
|
|
180
|
+
virtualUsers: ScaffoldVirtualUsers;
|
|
181
|
+
virtualUserId: string;
|
|
202
182
|
enabled?: boolean;
|
|
203
183
|
disposition?: string;
|
|
204
184
|
goals?: string[];
|
|
@@ -214,25 +194,25 @@ export interface WriteVirtualUserScheduleParams {
|
|
|
214
194
|
config?: {
|
|
215
195
|
nodeEnv?: string;
|
|
216
196
|
};
|
|
217
|
-
environments?: Readonly<Record<string,
|
|
197
|
+
environments?: Readonly<Record<string, VirtualUserEnvironment>>;
|
|
218
198
|
environment?: string;
|
|
219
199
|
}
|
|
220
200
|
/**
|
|
221
|
-
* Writes a
|
|
201
|
+
* Writes a virtual user's cadence.
|
|
222
202
|
*
|
|
223
203
|
* Applies the same rules `startVirtualUserRun` enforces, at the point the row is
|
|
224
|
-
* written rather than every hour afterwards: an acted-upon
|
|
225
|
-
* session, and
|
|
226
|
-
*
|
|
204
|
+
* written rather than every hour afterwards: an acted-upon virtual user has no
|
|
205
|
+
* session, and production refuses every run, so either is a tick that can only
|
|
206
|
+
* ever fail to start, with nobody watching.
|
|
227
207
|
*
|
|
228
|
-
*
|
|
229
|
-
* keeps what it had: enabling a row saved earlier as
|
|
230
|
-
*
|
|
208
|
+
* Whether the row is enabled is the one thing checked, since a field left out
|
|
209
|
+
* keeps what it had: enabling a row saved earlier is refused just as saving a
|
|
210
|
+
* new one would be.
|
|
231
211
|
*/
|
|
232
|
-
export declare const writeVirtualUserSchedule: ({ store,
|
|
212
|
+
export declare const writeVirtualUserSchedule: ({ store, virtualUsers, virtualUserId, enabled, disposition, goals, budget, minIntervalMs, maxIntervalMs, nextRunAt, config, environments, environment, }: WriteVirtualUserScheduleParams) => Promise<VirtualUserScheduleRecord>;
|
|
233
213
|
/** What a due schedule asks `runVirtualUser` for. */
|
|
234
214
|
export declare const virtualUserScheduleRunInput: (schedule: VirtualUserScheduleRecord) => {
|
|
235
|
-
|
|
215
|
+
virtualUserId: string;
|
|
236
216
|
disposition: VirtualUserDisposition;
|
|
237
217
|
goals: string[];
|
|
238
218
|
budget: {
|
|
@@ -245,7 +225,7 @@ export declare const virtualUserScheduleRunInput: (schedule: VirtualUserSchedule
|
|
|
245
225
|
* What a tick did.
|
|
246
226
|
*
|
|
247
227
|
* Logged rather than returned: the caller is a cron, and a run this started is
|
|
248
|
-
* otherwise the only trace that a
|
|
228
|
+
* otherwise the only trace that a virtual user is still out there working.
|
|
249
229
|
*/
|
|
250
230
|
export declare const logVirtualUserTick: (logger: Logger, result: VirtualUserTickResult) => void;
|
|
251
231
|
export interface ExecuteVirtualUserRunParams {
|
|
@@ -254,11 +234,11 @@ export interface ExecuteVirtualUserRunParams {
|
|
|
254
234
|
agentRunner: AgentRunnerService | undefined;
|
|
255
235
|
variables: VariablesService;
|
|
256
236
|
logger: Logger;
|
|
257
|
-
|
|
258
|
-
/** The app's generated `
|
|
259
|
-
|
|
237
|
+
virtualUsers: ScaffoldVirtualUsers;
|
|
238
|
+
/** The app's generated `createVirtualUsers`, which knows its own virtual user ids. */
|
|
239
|
+
createVirtualUsers: (options: Omit<HttpVirtualUsersConfig, 'virtualUsers'>) => ScenarioVirtualUsers;
|
|
260
240
|
runId: string;
|
|
261
|
-
|
|
241
|
+
virtualUserId: string;
|
|
262
242
|
disposition: string;
|
|
263
243
|
goals: string[];
|
|
264
244
|
memory: Record<string, string>;
|
|
@@ -268,16 +248,17 @@ export interface ExecuteVirtualUserRunParams {
|
|
|
268
248
|
mutations?: number;
|
|
269
249
|
durationMs?: number;
|
|
270
250
|
};
|
|
271
|
-
|
|
251
|
+
/** The app's auth instance, which a run signs in through without a credential. */
|
|
252
|
+
auth: InProcessAuth | undefined;
|
|
272
253
|
}
|
|
273
254
|
/**
|
|
274
255
|
* The run itself.
|
|
275
256
|
*
|
|
276
257
|
* Everything it needs is derived through `metaService` and the generated
|
|
277
|
-
*
|
|
258
|
+
* virtual users — the same public surface any consumer has. Nothing reaches into
|
|
278
259
|
* pikku's internals, because an app could not, and a feature built on what only
|
|
279
260
|
* the framework can see would not be this feature.
|
|
280
261
|
*/
|
|
281
|
-
export declare const executeVirtualUserRun: ({ runStore, metaService, agentRunner, variables, logger,
|
|
262
|
+
export declare const executeVirtualUserRun: ({ runStore, metaService, agentRunner, variables, logger, virtualUsers, createVirtualUsers, runId, virtualUserId, disposition, goals, memory, seed, budget, auth, }: ExecuteVirtualUserRunParams) => Promise<{
|
|
282
263
|
findings: number;
|
|
283
264
|
}>;
|