@pikku/core 0.12.84 → 0.12.86
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 +424 -0
- package/dist/bootstrap-compat/root.d.ts +20 -0
- package/dist/classification/column-form.d.ts +32 -0
- package/dist/classification/column-form.js +42 -0
- package/dist/classification/data-classification.d.ts +64 -0
- package/dist/classification/index.d.ts +13 -0
- package/dist/classification/index.js +2 -0
- package/dist/classification/secret-value.d.ts +56 -0
- package/dist/classification/secret-value.js +46 -0
- package/dist/crypto-utils.d.ts +1 -1
- package/dist/ecosystem/agent-scorer.d.ts +1 -1
- package/dist/ecosystem/agent.d.ts +4 -1
- package/dist/ecosystem/channel/local.d.ts +2 -0
- package/dist/ecosystem/channel/local.js +2 -0
- package/dist/ecosystem/channel/serverless.d.ts +9 -0
- package/dist/ecosystem/channel/serverless.js +1 -0
- package/dist/ecosystem/channel.d.ts +3 -0
- package/dist/ecosystem/channel.js +1 -0
- package/dist/ecosystem/cli.d.ts +1 -1
- package/dist/ecosystem/cli.js +1 -1
- package/dist/ecosystem/credential.d.ts +1 -0
- package/dist/ecosystem/crypto-utils.d.ts +8 -0
- package/dist/ecosystem/crypto-utils.js +1 -0
- package/dist/ecosystem/dev.d.ts +1 -0
- package/dist/ecosystem/dev.js +1 -0
- package/{src/ecosystem/testing.ts → dist/ecosystem/errors.d.ts} +3 -3
- package/dist/ecosystem/errors.js +2 -0
- package/dist/ecosystem/function.d.ts +1 -1
- package/dist/ecosystem/function.js +1 -1
- package/dist/ecosystem/http.d.ts +3 -1
- package/dist/ecosystem/http.js +3 -1
- package/dist/ecosystem/mcp.d.ts +1 -1
- package/dist/ecosystem/mcp.js +1 -1
- package/dist/ecosystem/middleware.d.ts +2 -1
- package/dist/ecosystem/middleware.js +2 -1
- package/dist/ecosystem/persona.d.ts +4 -2
- package/dist/ecosystem/persona.js +2 -1
- package/dist/ecosystem/queue.d.ts +4 -2
- package/dist/ecosystem/queue.js +3 -1
- package/dist/ecosystem/role.d.ts +1 -0
- package/dist/ecosystem/rpc.d.ts +2 -0
- package/dist/ecosystem/rpc.js +1 -0
- package/dist/ecosystem/scenario.d.ts +8 -2
- package/dist/ecosystem/scenario.js +5 -1
- package/dist/ecosystem/scheduler.d.ts +2 -1
- package/dist/ecosystem/scheduler.js +2 -1
- package/dist/ecosystem/schema.d.ts +2 -1
- package/dist/ecosystem/schema.js +1 -1
- package/dist/ecosystem/scope.d.ts +2 -0
- package/dist/ecosystem/scope.js +1 -0
- package/dist/ecosystem/secret.d.ts +2 -0
- package/dist/ecosystem/secret.js +1 -0
- package/dist/ecosystem/services/local-content.d.ts +2 -1
- package/dist/ecosystem/services/local-content.js +1 -1
- package/dist/ecosystem/services/local-meta.d.ts +1 -0
- package/dist/ecosystem/services/local-meta.js +1 -0
- package/dist/ecosystem/services.d.ts +11 -3
- package/dist/ecosystem/services.js +7 -1
- package/dist/ecosystem/trigger.d.ts +1 -0
- package/dist/ecosystem/trigger.js +1 -1
- package/dist/ecosystem/types.d.ts +6 -3
- package/dist/ecosystem/types.js +3 -2
- package/dist/ecosystem/variable.d.ts +1 -0
- package/dist/ecosystem/virtual-user.d.ts +3 -0
- package/dist/ecosystem/virtual-user.js +3 -0
- package/dist/ecosystem/workflow.d.ts +2 -0
- package/dist/ecosystem/workflow.js +2 -0
- package/dist/errors/index.d.ts +8 -0
- package/dist/errors/index.js +1 -0
- package/dist/errors/serialized-error.d.ts +7 -0
- package/dist/function/function-meta.types.d.ts +139 -0
- package/dist/function/function-runner.d.ts +3 -2
- package/dist/function/function-runner.js +31 -11
- package/dist/function/functions.types.d.ts +10 -2
- package/dist/function/index.d.ts +8 -2
- package/dist/function/index.js +4 -1
- package/dist/function/pikku-request.d.ts +8 -0
- package/dist/function/pikku-request.js +15 -0
- package/dist/middleware/auth-apikey.d.ts +2 -10
- package/dist/middleware/auth-apikey.js +1 -1
- package/dist/middleware/auth-bearer.d.ts +2 -10
- package/dist/middleware/auth-bearer.js +1 -1
- package/dist/middleware/auth-cookie.d.ts +2 -10
- package/dist/middleware/auth-cookie.js +1 -1
- package/dist/middleware/cors.d.ts +5 -11
- package/dist/middleware/cors.js +13 -6
- package/dist/middleware/index.d.ts +3 -0
- package/dist/middleware/index.js +1 -0
- package/dist/middleware/middleware-factories.d.ts +9 -0
- package/dist/middleware/middleware-factories.js +19 -0
- package/dist/middleware/middleware.types.d.ts +27 -0
- package/dist/middleware/middleware.types.js +1 -0
- package/dist/middleware/remote-auth.d.ts +2 -2
- package/dist/middleware/remote-auth.js +1 -1
- package/dist/middleware/telemetry.d.ts +4 -20
- package/dist/middleware/telemetry.js +1 -1
- package/dist/middleware-runner.d.ts +2 -1
- package/dist/pikku-state.d.ts +2 -1
- package/dist/services/audit-service.d.ts +1 -1
- package/dist/services/credential-wire-service.js +1 -1
- package/dist/services/email-service.d.ts +1 -1
- package/dist/services/file-scenario-run-store.d.ts +58 -0
- package/dist/services/file-scenario-run-store.js +214 -0
- package/dist/services/in-memory-workflow-service.d.ts +1 -1
- package/dist/services/index.d.ts +5 -1
- package/dist/services/index.js +3 -0
- package/dist/services/local-secrets.d.ts +1 -1
- package/dist/services/local-secrets.js +1 -1
- package/dist/services/logger.d.ts +7 -7
- package/dist/services/meta-service.d.ts +2 -1
- package/dist/services/scoped-secret-service.d.ts +1 -1
- package/dist/services/secret-service.d.ts +1 -1
- package/dist/services/typed-secret-service.d.ts +16 -2
- package/dist/services/typed-secret-service.js +5 -0
- package/dist/services/webhook-service.d.ts +1 -1
- package/dist/services/workflow-service.d.ts +2 -1
- package/dist/testing/index.d.ts +1 -0
- package/dist/testing/index.js +1 -0
- package/dist/types/core.types.d.ts +30 -180
- package/dist/types/core.types.js +1 -19
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +1 -0
- package/dist/types/state.types.d.ts +3 -1
- package/dist/utils.d.ts +13 -0
- package/dist/utils.js +2 -0
- package/dist/wirings/addon/addon-runner.d.ts +17 -0
- package/dist/wirings/addon/addon-runner.js +150 -0
- package/dist/wirings/addon/index.d.ts +6 -0
- package/dist/wirings/addon/index.js +3 -0
- package/dist/wirings/addon/remote-addon-auth.d.ts +16 -0
- package/dist/wirings/addon/remote-addon-auth.js +39 -0
- package/dist/wirings/addon/wire-addon.d.ts +80 -0
- package/dist/wirings/addon/wire-addon.js +120 -0
- package/dist/wirings/addon/wire-remote-addon.d.ts +22 -0
- package/dist/wirings/addon/wire-remote-addon.js +11 -0
- package/dist/wirings/agent/agent-prepare.d.ts +3 -3
- package/dist/wirings/agent/agent-prepare.js +1 -1
- package/dist/wirings/agent/agent-runner.js +2 -3
- package/dist/wirings/agent/agent-stream.js +2 -2
- package/dist/wirings/agent/agent-utils.d.ts +13 -0
- package/dist/wirings/agent/agent-utils.js +16 -0
- package/dist/wirings/agent/agent.types.d.ts +3 -2
- package/dist/wirings/agent/index.d.ts +1 -1
- package/dist/wirings/agent/voice-input.js +1 -1
- package/dist/wirings/agent/voice-output.js +1 -1
- package/dist/wirings/agent-scorer/agent-scorer-judge.d.ts +13 -0
- package/dist/wirings/agent-scorer/agent-scorer-judge.js +52 -0
- package/dist/wirings/agent-scorer/agent-scorer.d.ts +7 -1
- package/dist/wirings/agent-scorer/agent-scorer.js +1 -0
- package/dist/wirings/agent-scorer/agent-scorer.types.d.ts +20 -0
- package/dist/wirings/agent-scorer/index.d.ts +1 -1
- package/dist/wirings/channel/channel-common.d.ts +2 -1
- package/dist/wirings/channel/channel-middleware-runner.d.ts +2 -1
- package/dist/wirings/channel/channel.types.d.ts +1 -1
- package/dist/wirings/channel/serverless/index.d.ts +1 -0
- package/dist/wirings/cli/channel/index.d.ts +1 -1
- package/dist/wirings/cli/cli-runner.d.ts +2 -1
- package/dist/wirings/cli/cli-runner.js +4 -1
- package/dist/wirings/cli/cli.types.d.ts +21 -2
- package/dist/wirings/cli/command-parser.js +157 -23
- package/dist/wirings/gateway/gateway.types.d.ts +2 -1
- package/dist/wirings/http/http-runner.d.ts +1 -1
- package/dist/wirings/http/http-runner.js +1 -1
- package/dist/wirings/http/http.types.d.ts +2 -2
- package/dist/wirings/http/index.d.ts +1 -0
- package/dist/wirings/http/index.js +1 -0
- package/dist/wirings/http/pikku-fetch-http-request.js +1 -1
- package/dist/wirings/http/pikku-fetch-http-response.js +2 -2
- package/dist/wirings/mcp/mcp.types.d.ts +1 -1
- package/dist/wirings/persona/index.d.ts +1 -1
- package/dist/wirings/persona/index.js +1 -1
- package/dist/wirings/persona/persona.types.d.ts +14 -0
- package/dist/wirings/queue/queue.types.d.ts +1 -1
- package/dist/wirings/queue/signed-queue-service.d.ts +1 -1
- package/dist/wirings/rpc/index.d.ts +0 -6
- package/dist/wirings/rpc/index.js +0 -3
- package/dist/wirings/rpc/remote-addon-auth.d.ts +1 -1
- package/dist/wirings/rpc/remote-addon-auth.js +1 -1
- package/dist/wirings/rpc/rpc-runner.js +2 -2
- package/dist/wirings/rpc/wire-addon.d.ts +1 -1
- package/dist/wirings/scheduler/scheduler.types.d.ts +2 -1
- package/dist/wirings/scope/index.d.ts +1 -0
- package/dist/wirings/scope/index.js +1 -0
- package/dist/wirings/secret/secret.types.d.ts +10 -0
- package/dist/wirings/secret/validate-secret-definitions.js +2 -0
- package/dist/wirings/variable/validate-variable-definitions.js +2 -0
- package/dist/wirings/variable/variable.types.d.ts +9 -0
- package/dist/wirings/virtual-user/index.d.ts +1 -1
- package/dist/wirings/virtual-user/index.js +1 -1
- package/dist/wirings/virtual-user/prepare-virtual-user-run.d.ts +1 -1
- package/dist/wirings/virtual-user/virtual-user-derive.d.ts +1 -1
- package/dist/wirings/workflow/graph/graph-node.d.ts +9 -2
- package/dist/wirings/workflow/graph/graph-node.js +2 -0
- package/dist/wirings/workflow/graph/graph-runner.d.ts +1 -0
- package/dist/wirings/workflow/graph/graph-runner.js +283 -31
- package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +16 -1
- package/dist/wirings/workflow/index.d.ts +2 -0
- package/dist/wirings/workflow/index.js +1 -0
- package/dist/wirings/workflow/pikku-scenario-service.d.ts +14 -4
- package/dist/wirings/workflow/pikku-scenario-service.js +44 -16
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +2 -1
- package/dist/wirings/workflow/pikku-workflow-service.js +3 -4
- package/dist/wirings/workflow/run-timeline.d.ts +1 -1
- package/dist/wirings/workflow/scenario-run.types.d.ts +171 -0
- package/dist/wirings/workflow/scenario-run.types.js +1 -0
- package/dist/wirings/workflow/scenario-step-guards.d.ts +1 -2
- package/dist/wirings/workflow/scenario-step-guards.js +0 -8
- package/dist/wirings/workflow/scenario-step.types.d.ts +27 -12
- package/dist/wirings/workflow/workflow-approval.js +2 -1
- package/dist/wirings/workflow/workflow-run-engine.types.d.ts +2 -1
- package/dist/wirings/workflow/workflow.types.d.ts +2 -1
- package/knowledge/decisions/index.md +2 -0
- package/knowledge/decisions/internals/a-scenario-step-template-is-offered-unfilled.md +1 -1
- package/knowledge/decisions/internals/a-secret-that-fails-to-decrypt-fails-the-whole-read.md +1 -1
- package/knowledge/decisions/internals/a-virtual-user-run-is-not-a-workflow-and-not-a-queued-job.md +2 -2
- package/knowledge/decisions/internals/a-wall-clock-threshold-is-a-load-test-in-disguise.md +6 -6
- package/knowledge/decisions/internals/a-workflow-wire-is-built-from-the-run-not-from-the-rpc-service.md +1 -1
- package/knowledge/decisions/internals/addon-singleton-services-are-cached-per-namespace-not-per-package.md +1 -1
- package/knowledge/decisions/internals/addon-workflow-names-are-prefixed-with-the-consumer-namespace.md +1 -1
- package/knowledge/decisions/internals/an-addon-scope-root-loses-to-a-root-the-host-already-declares.md +1 -1
- package/knowledge/decisions/internals/channel-message-handlers-accept-three-config-shapes.md +1 -1
- package/knowledge/decisions/internals/channel-middleware-caches-only-statically-resolved-middleware.md +1 -1
- package/knowledge/decisions/internals/channel-user-id-is-persisted-after-onconnect-middleware-runs.md +1 -1
- package/knowledge/decisions/internals/cli-option-names-are-camelcase-in-state-and-kebab-on-the-command-line.md +1 -1
- package/knowledge/decisions/internals/cli-parse-errors-are-routed-by-message-prefix.md +1 -1
- package/knowledge/decisions/internals/cli-unknown-long-options-warn-instead-of-failing.md +1 -1
- package/knowledge/decisions/internals/core-column-form-is-an-axis-of-its-own.md +4 -4
- package/knowledge/decisions/internals/core-data-classification-brand-is-an-optional-property.md +1 -1
- package/knowledge/decisions/internals/core-function-runner-restores-the-wire-fields-it-overwrites.md +3 -3
- package/knowledge/decisions/internals/core-hot-reload-merges-generated-meta-never-replaces-it.md +2 -2
- package/knowledge/decisions/internals/core-hot-reload-owns-its-module-registry.md +2 -2
- package/knowledge/decisions/internals/core-middleware-order-is-scope-then-priority.md +1 -1
- package/knowledge/decisions/internals/core-schema-defaults-apply-on-every-transport.md +1 -1
- package/knowledge/decisions/internals/core-scopes-are-an-and-gate-separate-from-permissions.md +3 -3
- package/knowledge/decisions/internals/gateway-adapters-resolve-lazily-and-are-promise-cached.md +1 -1
- package/knowledge/decisions/internals/gateway-listener-middleware-runs-without-an-rpc-on-the-wire.md +4 -4
- package/knowledge/decisions/internals/gateway-wiring-is-a-meta-wiring-over-http-and-channels.md +1 -1
- package/knowledge/decisions/internals/http-router-matches-normalized-paths-but-returns-registered-ones.md +1 -1
- package/knowledge/decisions/internals/in-a-scenario-a-4xx-is-data-not-an-exception.md +1 -1
- package/knowledge/decisions/internals/in-memory-workflow-history-aliases-the-live-step-object.md +1 -1
- package/knowledge/decisions/internals/index.md +4 -2
- package/knowledge/decisions/internals/istanbul-statement-counts-attach-to-the-start-line-only.md +1 -1
- package/knowledge/decisions/internals/one-project-shape-check-two-validators.md +1 -1
- package/knowledge/decisions/internals/queue-jobs-always-carry-an-explicit-attempts-count.md +1 -1
- package/knowledge/decisions/internals/remote-addons-dispatch-over-http-instead-of-local-meta.md +1 -1
- package/knowledge/decisions/internals/rpc-names-resolve-through-package-scope-before-root.md +1 -1
- package/knowledge/decisions/internals/scenario-given-and-when-are-sugar-but-then-is-not.md +2 -2
- package/knowledge/decisions/internals/scenarios-live-in-files-named-for-them.md +5 -5
- package/knowledge/decisions/internals/the-actor-prompt-says-json-because-of-json-object-mode.md +1 -1
- package/knowledge/decisions/internals/the-api-report-pins-members-not-just-names.md +1 -1
- package/knowledge/decisions/internals/the-ecosystem-entry-point-carries-the-adapter-surface.md +43 -19
- package/knowledge/decisions/internals/the-persona-runtime-is-exported-from-the-persona-entry-point.md +1 -1
- package/knowledge/decisions/internals/the-worker-disposition-is-the-one-that-is-not-testing.md +1 -1
- package/knowledge/decisions/internals/validate-runs-checks-by-precondition.md +3 -3
- package/knowledge/decisions/internals/virtual-user-step-order-comes-from-insertion-order.md +1 -1
- package/knowledge/decisions/internals/webhook-delivery-history-records-every-attempt-best-effort.md +1 -1
- package/knowledge/decisions/internals/wiring-registries-erase-the-generics-their-wire-functions-capture.md +1 -1
- package/knowledge/decisions/internals/workflow-approval-expiry-is-decided-from-a-recorded-deadline.md +1 -1
- package/knowledge/decisions/internals/workflow-core-never-imports-a-browser-driver.md +1 -1
- package/knowledge/decisions/internals/workflow-inline-runs-report-their-run-id-before-they-can-fail.md +1 -1
- package/knowledge/decisions/internals/workflow-invocation-id-is-the-dedupe-key-not-step-id.md +1 -1
- package/knowledge/decisions/internals/workflow-run-capabilities-are-extensions-not-subclasses.md +1 -1
- package/knowledge/decisions/internals/workflow-run-timeline-is-a-pure-fold-over-durable-history.md +1 -1
- package/knowledge/decisions/internals/workflow-scenario-assertions-never-retry-and-record-one-step.md +9 -5
- package/knowledge/decisions/internals/workflow-scenario-hooks-are-a-scenario-only-affordance.md +1 -1
- package/knowledge/decisions/internals/workflow-step-rpc-name-is-provenance-only.md +2 -2
- package/knowledge/decisions/internals/workflow-suspend-and-approval-reasons-are-durable-step-identities.md +1 -1
- package/knowledge/decisions/security/a-function-never-receives-the-secret-service.md +1 -1
- package/knowledge/decisions/security/a-step-runs-the-function-the-workflow-dispatched-it-with.md +1 -1
- package/knowledge/decisions/security/a-virtual-user-is-never-offered-a-step-that-would-forge-its-own-oracle.md +2 -3
- package/knowledge/decisions/security/actor-sign-in-is-proven-by-set-cookie-not-a-non-empty-jar.md +1 -1
- package/knowledge/decisions/security/addon-auth-and-tags-only-tighten.md +1 -1
- package/knowledge/decisions/security/agent-gate-requires-a-session-only-when-auth-is-true.md +1 -1
- package/knowledge/decisions/security/an-approval-answer-outlives-the-run-it-answered.md +3 -3
- package/knowledge/decisions/security/console-addon-privileged-functions-gate-themselves.md +4 -3
- package/knowledge/decisions/security/core-safe-fetch-blocks-ssrf-by-host-literal-not-dns.md +1 -1
- package/knowledge/decisions/security/gateway-middleware-sessions-must-be-bridged-onto-the-wire.md +2 -2
- package/knowledge/decisions/security/global-permissions-and-function-permissions-are-independent-gates.md +1 -1
- package/knowledge/decisions/security/http-request-bodies-are-bounded-before-they-are-buffered.md +2 -2
- package/knowledge/decisions/security/index.md +2 -0
- package/knowledge/decisions/security/mcp-internal-error-details-are-double-gated-on-production.md +1 -1
- package/knowledge/decisions/security/queue-jobs-carry-the-producers-pikku-user-id.md +3 -3
- package/knowledge/decisions/security/remote-addon-tokens-are-client-credentials-not-mesh-trust.md +1 -1
- package/knowledge/decisions/security/scaffold-features-are-authenticated-unless-opted-out.md +2 -2
- package/knowledge/decisions/security/self-authentication-is-declared-not-detected.md +1 -1
- package/knowledge/decisions/security/signed-content-urls-bind-the-request-path.md +2 -2
- package/knowledge/index.md +3 -1
- package/knowledge/questions/channel-middleware-accepts-bare-factories-that-nothing-resolves.md +1 -1
- package/knowledge/questions/index.md +2 -0
- package/package.json +14 -13
- package/run-tests.sh +0 -0
- package/scripts/generate-api-report.d.mts +1 -1
- package/scripts/generate-api-report.mjs +67 -60
- package/scripts/generate-api-report.mts +11 -45
- package/src/api-report.test.ts +70 -1
- package/src/app-alias-surface.test.ts +179 -0
- package/src/app-leaf-surface.test.ts +217 -0
- package/src/bootstrap-compat/root.ts +20 -0
- package/src/{column-form.test.ts → classification/column-form.test.ts} +2 -2
- package/src/{data-classification.ts → classification/data-classification.ts} +1 -5
- package/src/classification/index.ts +38 -0
- package/src/{secret-value.test.ts → classification/secret-value.test.ts} +2 -2
- package/src/{secret-value.ts → classification/secret-value.ts} +1 -6
- package/src/crypto-utils.ts +1 -1
- package/src/dev/reload-meta.test.ts +1 -1
- package/src/errors/index.ts +9 -0
- package/src/errors/serialized-error.ts +9 -0
- package/src/factory-functions.test.ts +4 -2
- package/src/function/function-meta.types.ts +151 -0
- package/src/function/function-runner.test.ts +4 -2
- package/src/function/function-runner.ts +47 -14
- package/src/function/functions.types.ts +11 -7
- package/src/function/index.ts +24 -5
- package/src/function/list.types.ts +1 -3
- package/src/middleware/auth-apikey.ts +4 -2
- package/src/middleware/auth-bearer.test.ts +1 -1
- package/src/middleware/auth-bearer.ts +4 -2
- package/src/middleware/auth-cookie.ts +4 -1
- package/src/middleware/cors.test.ts +126 -5
- package/src/middleware/cors.ts +19 -8
- package/src/middleware/index.ts +16 -0
- package/src/middleware/middleware-factories.ts +62 -0
- package/src/middleware/middleware.types.ts +61 -0
- package/src/middleware/remote-auth.test.ts +1 -1
- package/src/middleware/remote-auth.ts +1 -1
- package/src/middleware/telemetry.ts +4 -2
- package/src/middleware-runner.test.ts +2 -3
- package/src/middleware-runner.ts +2 -2
- package/src/no-root-barrel.test.ts +114 -0
- package/src/permissions.ts +2 -4
- package/src/pikku-state.ts +3 -1
- package/src/public-surface.json +56 -241
- package/src/public-surface.json.README +3 -3
- package/src/public-surface.test.ts +5 -5
- package/src/remote.test.ts +1 -1
- package/src/removed-legacy-exports.test.ts +5 -1
- package/src/services/audit-service.ts +1 -1
- package/src/services/credential-wire-service.ts +1 -1
- package/src/services/email-service.ts +2 -4
- package/src/services/file-scenario-run-store.test.ts +349 -0
- package/src/services/file-scenario-run-store.ts +282 -0
- package/src/services/in-memory-workflow-service.ts +1 -1
- package/src/services/index.ts +13 -1
- package/src/services/local-content-request-handler.ts +1 -2
- package/src/services/local-secrets.ts +1 -1
- package/src/services/logger.ts +7 -7
- package/src/services/meta-service.ts +2 -2
- package/src/services/queue-webhook-service.test.ts +1 -1
- package/src/services/scoped-secret-service.ts +1 -1
- package/src/services/secret-service.ts +1 -1
- package/src/services/typed-secret-service.test.ts +52 -0
- package/src/services/typed-secret-service.ts +26 -2
- package/src/services/webhook-service.ts +1 -1
- package/src/services/workflow-service.ts +2 -1
- package/src/template-alias-surface.test.ts +240 -0
- package/src/testing/index.ts +1 -0
- package/src/types/core.types.ts +33 -285
- package/src/types/index.ts +2 -0
- package/src/types/state.types.ts +6 -5
- package/src/types/typed-credentials.test.ts +72 -0
- package/src/utils.ts +34 -0
- package/src/wirings/{rpc → addon}/addon-scopes.test.ts +1 -1
- package/src/wirings/addon/index.ts +12 -0
- package/src/wirings/{rpc → addon}/remote-addon-auth.ts +4 -1
- package/src/wirings/{rpc → addon}/wire-addon.ts +37 -2
- package/src/wirings/agent/agent-prepare.ts +8 -5
- package/src/wirings/agent/agent-runner.ts +2 -3
- package/src/wirings/agent/agent-stream.ts +2 -3
- package/src/wirings/agent/agent-utils.ts +19 -0
- package/src/wirings/agent/agent.types.ts +3 -3
- package/src/wirings/agent/index.ts +1 -0
- package/src/wirings/agent/voice-input.ts +1 -1
- package/src/wirings/agent/voice-output.test.ts +2 -4
- package/src/wirings/agent/voice-output.ts +1 -1
- package/src/wirings/agent-scorer/agent-scorer-judge.test.ts +145 -0
- package/src/wirings/agent-scorer/agent-scorer-judge.ts +60 -0
- package/src/wirings/agent-scorer/agent-scorer.ts +8 -0
- package/src/wirings/agent-scorer/agent-scorer.types.ts +21 -0
- package/src/wirings/agent-scorer/index.ts +1 -0
- package/src/wirings/channel/channel-common.ts +4 -2
- package/src/wirings/channel/channel-handler.ts +2 -5
- package/src/wirings/channel/channel-middleware-runner.ts +1 -1
- package/src/wirings/channel/channel-rpc.types.ts +1 -5
- package/src/wirings/channel/channel.types.ts +1 -2
- package/src/wirings/channel/local/local-channel-runner.test.ts +1 -2
- package/src/wirings/channel/serverless/index.ts +1 -0
- package/src/wirings/cli/channel/cli-raw-channel-runner.ts +2 -2
- package/src/wirings/cli/channel/index.ts +1 -3
- package/src/wirings/cli/cli-runner.test.ts +1 -1
- package/src/wirings/cli/cli-runner.ts +11 -7
- package/src/wirings/cli/cli.types.ts +24 -3
- package/src/wirings/cli/command-parser.test.ts +388 -1
- package/src/wirings/cli/command-parser.ts +189 -29
- package/src/wirings/gateway/gateway-runner.test.ts +1 -2
- package/src/wirings/gateway/gateway-runner.ts +3 -6
- package/src/wirings/gateway/gateway.types.ts +5 -4
- package/src/wirings/http/http-routes.test.ts +1 -2
- package/src/wirings/http/http-runner-addon-ref.test.ts +238 -0
- package/src/wirings/http/http-runner.test.ts +3 -8
- package/src/wirings/http/http-runner.ts +9 -3
- package/src/wirings/http/http.types.ts +3 -12
- package/src/wirings/http/index.ts +1 -0
- package/src/wirings/http/pikku-fetch-http-request.ts +1 -1
- package/src/wirings/http/pikku-fetch-http-response.ts +3 -2
- package/src/wirings/mcp/mcp-runner.test.ts +1 -1
- package/src/wirings/mcp/mcp.types.ts +1 -2
- package/src/wirings/persona/index.ts +1 -4
- package/src/wirings/persona/persona.types.ts +14 -0
- package/src/wirings/queue/queue-identity.test.ts +1 -1
- package/src/wirings/queue/queue.types.ts +2 -6
- package/src/wirings/queue/signed-queue-service.ts +1 -1
- package/src/wirings/rpc/index.ts +0 -12
- package/src/wirings/rpc/rpc-runner.test.ts +4 -4
- package/src/wirings/rpc/rpc-runner.ts +3 -3
- package/src/wirings/scheduler/scheduler.types.ts +2 -5
- package/src/wirings/scope/index.ts +1 -0
- package/src/wirings/secret/secret.types.ts +10 -0
- package/src/wirings/secret/validate-secret-definitions.test.ts +23 -0
- package/src/wirings/secret/validate-secret-definitions.ts +2 -0
- package/src/wirings/variable/validate-variable-definitions.test.ts +23 -0
- package/src/wirings/variable/validate-variable-definitions.ts +2 -0
- package/src/wirings/variable/variable.types.ts +9 -0
- package/src/wirings/virtual-user/index.ts +1 -4
- package/src/wirings/virtual-user/prepare-virtual-user-run.ts +1 -1
- package/src/wirings/virtual-user/virtual-user-derive.test.ts +1 -1
- package/src/wirings/virtual-user/virtual-user-derive.ts +1 -1
- package/src/wirings/virtual-user/virtual-user.types.ts +1 -5
- package/src/wirings/workflow/graph/graph-foreach-queued.test.ts +569 -0
- package/src/wirings/workflow/graph/graph-foreach.test.ts +626 -0
- package/src/wirings/workflow/graph/graph-node.ts +16 -1
- package/src/wirings/workflow/graph/graph-runner.ts +387 -61
- package/src/wirings/workflow/graph/workflow-graph.types.ts +28 -3
- package/src/wirings/workflow/index.ts +8 -0
- package/src/wirings/workflow/pikku-scenario-service.ts +59 -19
- package/src/wirings/workflow/pikku-workflow-service.ts +6 -8
- package/src/wirings/workflow/run-timeline.ts +1 -1
- package/src/wirings/workflow/scenario-expectations.test.ts +28 -13
- package/src/wirings/workflow/scenario-run.types.ts +186 -0
- package/src/wirings/workflow/scenario-step-guards.ts +1 -14
- package/src/wirings/workflow/scenario-step.test.ts +32 -7
- package/src/wirings/workflow/scenario-step.types.ts +27 -12
- package/src/wirings/workflow/workflow-approval-policy.test.ts +117 -47
- package/src/wirings/workflow/workflow-approval.ts +2 -1
- package/src/wirings/workflow/workflow-run-engine.types.ts +2 -1
- package/src/wirings/workflow/workflow.types.ts +4 -12
- package/src/wirings-stay-decoupled.test.ts +6 -3
- package/tsconfig.tsbuildinfo +1 -1
- package/tsconfig.type-tests.json +3 -2
- package/dist/ecosystem/ai-agent.d.ts +0 -18
- package/dist/ecosystem/ai-agent.js +0 -6
- package/dist/ecosystem/ai-scorer.d.ts +0 -12
- package/dist/ecosystem/ai-scorer.js +0 -5
- package/dist/services/ai-agent-runner-service.d.ts +0 -220
- package/dist/services/ai-run-state-service.d.ts +0 -29
- package/dist/services/ai-storage-service.d.ts +0 -18
- package/dist/services/in-memory-ai-run-state-service.d.ts +0 -19
- package/dist/services/in-memory-ai-run-state-service.js +0 -54
- package/dist/testing/service-tests/ai-storage-service-tests.d.ts +0 -3
- package/dist/testing/service-tests/ai-storage-service-tests.js +0 -302
- package/dist/wirings/ai-agent/agent-rpc.d.ts +0 -15
- package/dist/wirings/ai-agent/agent-rpc.js +0 -53
- package/dist/wirings/ai-agent/ai-agent-agui.d.ts +0 -79
- package/dist/wirings/ai-agent/ai-agent-agui.js +0 -327
- package/dist/wirings/ai-agent/ai-agent-finalize.d.ts +0 -58
- package/dist/wirings/ai-agent/ai-agent-finalize.js +0 -138
- package/dist/wirings/ai-agent/ai-agent-helpers.d.ts +0 -35
- package/dist/wirings/ai-agent/ai-agent-helpers.js +0 -47
- package/dist/wirings/ai-agent/ai-agent-interrupt.d.ts +0 -153
- package/dist/wirings/ai-agent/ai-agent-interrupt.js +0 -257
- package/dist/wirings/ai-agent/ai-agent-memory.d.ts +0 -42
- package/dist/wirings/ai-agent/ai-agent-memory.js +0 -333
- package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +0 -16
- package/dist/wirings/ai-agent/ai-agent-model-config.js +0 -51
- package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +0 -117
- package/dist/wirings/ai-agent/ai-agent-prepare.js +0 -728
- package/dist/wirings/ai-agent/ai-agent-registry.d.ts +0 -16
- package/dist/wirings/ai-agent/ai-agent-registry.js +0 -51
- package/dist/wirings/ai-agent/ai-agent-runner.d.ts +0 -7
- package/dist/wirings/ai-agent/ai-agent-runner.js +0 -580
- package/dist/wirings/ai-agent/ai-agent-stream.d.ts +0 -41
- package/dist/wirings/ai-agent/ai-agent-stream.js +0 -1029
- package/dist/wirings/ai-agent/ai-agent-turn.d.ts +0 -57
- package/dist/wirings/ai-agent/ai-agent-turn.js +0 -82
- package/dist/wirings/ai-agent/ai-agent-utils.d.ts +0 -1
- package/dist/wirings/ai-agent/ai-agent-utils.js +0 -1
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +0 -625
- package/dist/wirings/ai-agent/index.d.ts +0 -12
- package/dist/wirings/ai-agent/index.js +0 -10
- package/dist/wirings/ai-agent/voice-input.d.ts +0 -69
- package/dist/wirings/ai-agent/voice-input.js +0 -150
- package/dist/wirings/ai-agent/voice-output.d.ts +0 -85
- package/dist/wirings/ai-agent/voice-output.js +0 -196
- package/dist/wirings/ai-scorer/ai-scorer-grade.d.ts +0 -26
- package/dist/wirings/ai-scorer/ai-scorer-grade.js +0 -33
- package/dist/wirings/ai-scorer/ai-scorer-judge.d.ts +0 -17
- package/dist/wirings/ai-scorer/ai-scorer-judge.js +0 -92
- package/dist/wirings/ai-scorer/ai-scorer-live.d.ts +0 -15
- package/dist/wirings/ai-scorer/ai-scorer-live.js +0 -38
- package/dist/wirings/ai-scorer/ai-scorer-registry.d.ts +0 -18
- package/dist/wirings/ai-scorer/ai-scorer-registry.js +0 -46
- package/dist/wirings/ai-scorer/ai-scorer-sampling.d.ts +0 -8
- package/dist/wirings/ai-scorer/ai-scorer-sampling.js +0 -31
- package/dist/wirings/ai-scorer/ai-scorer-snapshots.d.ts +0 -10
- package/dist/wirings/ai-scorer/ai-scorer-snapshots.js +0 -40
- package/dist/wirings/ai-scorer/ai-scorer-worker.d.ts +0 -15
- package/dist/wirings/ai-scorer/ai-scorer-worker.js +0 -58
- package/dist/wirings/ai-scorer/ai-scorer.d.ts +0 -39
- package/dist/wirings/ai-scorer/ai-scorer.js +0 -40
- package/dist/wirings/ai-scorer/ai-scorer.types.d.ts +0 -90
- package/dist/wirings/ai-scorer/ai-scorer.types.js +0 -4
- package/dist/wirings/ai-scorer/index.d.ts +0 -6
- package/dist/wirings/ai-scorer/index.js +0 -5
- package/src/ecosystem/agent-scorer.ts +0 -24
- package/src/ecosystem/agent.ts +0 -42
- package/src/ecosystem/channel/local.ts +0 -1
- package/src/ecosystem/channel.ts +0 -22
- package/src/ecosystem/cli/channel.ts +0 -25
- package/src/ecosystem/cli.ts +0 -21
- package/src/ecosystem/credential.ts +0 -10
- package/src/ecosystem/dev.ts +0 -12
- package/src/ecosystem/function.ts +0 -28
- package/src/ecosystem/gateway.ts +0 -4
- package/src/ecosystem/hmac.ts +0 -1
- package/src/ecosystem/http.ts +0 -22
- package/src/ecosystem/mcp.ts +0 -17
- package/src/ecosystem/middleware.ts +0 -27
- package/src/ecosystem/node-host-resolver.ts +0 -1
- package/src/ecosystem/node.ts +0 -5
- package/src/ecosystem/oauth2.ts +0 -4
- package/src/ecosystem/persona.ts +0 -30
- package/src/ecosystem/queue.ts +0 -23
- package/src/ecosystem/remote.ts +0 -9
- package/src/ecosystem/role.ts +0 -13
- package/src/ecosystem/rpc.ts +0 -7
- package/src/ecosystem/safe-fetch.ts +0 -8
- package/src/ecosystem/scenario.ts +0 -32
- package/src/ecosystem/scheduler.ts +0 -5
- package/src/ecosystem/schema.ts +0 -1
- package/src/ecosystem/scope.ts +0 -14
- package/src/ecosystem/secret.ts +0 -15
- package/src/ecosystem/services/istanbul-coverage.ts +0 -1
- package/src/ecosystem/services/local-content-request-handler.ts +0 -16
- package/src/ecosystem/services/local-content.ts +0 -1
- package/src/ecosystem/services/v8-coverage.ts +0 -1
- package/src/ecosystem/services.ts +0 -82
- package/src/ecosystem/trigger.ts +0 -7
- package/src/ecosystem/types.ts +0 -34
- package/src/ecosystem/variable.ts +0 -14
- package/src/ecosystem/virtual-user.ts +0 -48
- package/src/ecosystem/workflow.ts +0 -68
- package/src/ecosystem.ts +0 -40
- package/src/index.ts +0 -244
- /package/dist/{services/ai-agent-runner-service.js → bootstrap-compat/root.js} +0 -0
- /package/dist/{services/ai-run-state-service.js → classification/data-classification.js} +0 -0
- /package/dist/{services/ai-storage-service.js → errors/serialized-error.js} +0 -0
- /package/dist/{wirings/ai-agent/ai-agent.types.js → function/function-meta.types.js} +0 -0
- /package/src/{column-form.ts → classification/column-form.ts} +0 -0
- /package/src/{pikku-request.test.ts → function/pikku-request.test.ts} +0 -0
- /package/src/{pikku-request.ts → function/pikku-request.ts} +0 -0
- /package/src/wirings/{rpc → addon}/addon-auth-tags.test.ts +0 -0
- /package/src/wirings/{rpc → addon}/addon-runner.ts +0 -0
- /package/src/wirings/{rpc → addon}/addon-secrets.test.ts +0 -0
- /package/src/wirings/{rpc → addon}/wire-addon.test.ts +0 -0
- /package/src/wirings/{rpc → addon}/wire-remote-addon.ts +0 -0
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
import { describe, test, beforeEach, afterEach } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import {
|
|
4
|
+
mkdtempSync,
|
|
5
|
+
mkdirSync,
|
|
6
|
+
rmSync,
|
|
7
|
+
writeFileSync,
|
|
8
|
+
existsSync,
|
|
9
|
+
} from 'node:fs'
|
|
10
|
+
import { tmpdir } from 'node:os'
|
|
11
|
+
import { join } from 'node:path'
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
FileScenarioRunStore,
|
|
15
|
+
scenarioRunSummary,
|
|
16
|
+
} from './file-scenario-run-store.js'
|
|
17
|
+
import type {
|
|
18
|
+
ScenarioResult,
|
|
19
|
+
ScenarioRunRecord,
|
|
20
|
+
} from '../wirings/workflow/scenario-run.types.js'
|
|
21
|
+
|
|
22
|
+
let dir: string
|
|
23
|
+
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
dir = mkdtempSync(join(tmpdir(), 'pikku-scenario-runs-'))
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
afterEach(() => {
|
|
29
|
+
rmSync(dir, { recursive: true, force: true })
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
const record = (
|
|
33
|
+
overrides: Partial<ScenarioRunRecord> = {}
|
|
34
|
+
): ScenarioRunRecord => ({
|
|
35
|
+
runId: 'run-1',
|
|
36
|
+
environment: 'local',
|
|
37
|
+
surface: 'browser',
|
|
38
|
+
status: 'running',
|
|
39
|
+
startedAt: '2026-08-15T10:00:00.000Z',
|
|
40
|
+
results: [],
|
|
41
|
+
skipped: [],
|
|
42
|
+
hookFailures: [],
|
|
43
|
+
...overrides,
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
const result = (overrides: Partial<ScenarioResult> = {}): ScenarioResult => ({
|
|
47
|
+
name: 'todos › a member adds one',
|
|
48
|
+
status: 'passed',
|
|
49
|
+
durationMs: 120,
|
|
50
|
+
...overrides,
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
describe('FileScenarioRunStore', () => {
|
|
54
|
+
test('a run is readable from the moment it opens, before any scenario finishes', async () => {
|
|
55
|
+
const store = new FileScenarioRunStore({ dir })
|
|
56
|
+
|
|
57
|
+
await store.start(record())
|
|
58
|
+
|
|
59
|
+
const open = await store.get('run-1')
|
|
60
|
+
assert.equal(open?.status, 'running')
|
|
61
|
+
assert.deepEqual(open?.results, [])
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
test('scenarios accumulate as they finish, so a suite killed halfway keeps what ran', async () => {
|
|
65
|
+
const store = new FileScenarioRunStore({ dir })
|
|
66
|
+
await store.start(record())
|
|
67
|
+
|
|
68
|
+
await store.recordScenario('run-1', result({ name: 'one' }))
|
|
69
|
+
await store.recordScenario(
|
|
70
|
+
'run-1',
|
|
71
|
+
result({ name: 'two', status: 'failed' })
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
const partial = await store.get('run-1')
|
|
75
|
+
assert.deepEqual(
|
|
76
|
+
partial?.results.map((r) => r.name),
|
|
77
|
+
['one', 'two']
|
|
78
|
+
)
|
|
79
|
+
assert.equal(
|
|
80
|
+
partial?.status,
|
|
81
|
+
'running',
|
|
82
|
+
'a run nobody finished is still running, not passed'
|
|
83
|
+
)
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
test('finishing settles the outcome and everything only known at the end', async () => {
|
|
87
|
+
const store = new FileScenarioRunStore({ dir })
|
|
88
|
+
await store.start(record())
|
|
89
|
+
await store.recordScenario('run-1', result())
|
|
90
|
+
|
|
91
|
+
await store.finish('run-1', {
|
|
92
|
+
status: 'failed',
|
|
93
|
+
finishedAt: '2026-08-15T10:00:30.000Z',
|
|
94
|
+
skipped: [{ name: 'quarantined', reason: 'flaky' }],
|
|
95
|
+
hookFailures: ['feature after hook failed: boom'],
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
const done = await store.get('run-1')
|
|
99
|
+
assert.equal(done?.status, 'failed')
|
|
100
|
+
assert.equal(done?.finishedAt, '2026-08-15T10:00:30.000Z')
|
|
101
|
+
assert.deepEqual(done?.skipped, [{ name: 'quarantined', reason: 'flaky' }])
|
|
102
|
+
assert.equal(done?.results.length, 1, 'finishing does not lose the results')
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
test('concurrent scenario writes never lose one to a read-modify-write race', async () => {
|
|
106
|
+
const store = new FileScenarioRunStore({ dir })
|
|
107
|
+
await store.start(record())
|
|
108
|
+
|
|
109
|
+
await Promise.all(
|
|
110
|
+
Array.from({ length: 20 }, (_, i) =>
|
|
111
|
+
store.recordScenario('run-1', result({ name: `scenario-${i}` }))
|
|
112
|
+
)
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
const all = await store.get('run-1')
|
|
116
|
+
assert.equal(all?.results.length, 20)
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
test('runs list newest first, summarised without loading their stacks', async () => {
|
|
120
|
+
const store = new FileScenarioRunStore({ dir })
|
|
121
|
+
await store.start(
|
|
122
|
+
record({ runId: 'older', startedAt: '2026-08-14T10:00:00.000Z' })
|
|
123
|
+
)
|
|
124
|
+
await store.start(
|
|
125
|
+
record({ runId: 'newer', startedAt: '2026-08-15T10:00:00.000Z' })
|
|
126
|
+
)
|
|
127
|
+
await store.recordScenario(
|
|
128
|
+
'newer',
|
|
129
|
+
result({
|
|
130
|
+
artifacts: [{ scenario: 'x', kind: 'video', path: 'x/admin.mp4' }],
|
|
131
|
+
})
|
|
132
|
+
)
|
|
133
|
+
await store.recordScenario('newer', result({ status: 'failed' }))
|
|
134
|
+
await store.finish('newer', {
|
|
135
|
+
status: 'failed',
|
|
136
|
+
finishedAt: '2026-08-15T10:00:05.000Z',
|
|
137
|
+
skipped: [{ name: 'held', reason: 'no browser' }],
|
|
138
|
+
hookFailures: [],
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
const runs = await store.list()
|
|
142
|
+
|
|
143
|
+
assert.deepEqual(
|
|
144
|
+
runs.map((r) => r.runId),
|
|
145
|
+
['newer', 'older']
|
|
146
|
+
)
|
|
147
|
+
assert.deepEqual(
|
|
148
|
+
{ ...runs[0] },
|
|
149
|
+
{
|
|
150
|
+
runId: 'newer',
|
|
151
|
+
environment: 'local',
|
|
152
|
+
surface: 'browser',
|
|
153
|
+
status: 'failed',
|
|
154
|
+
startedAt: '2026-08-15T10:00:00.000Z',
|
|
155
|
+
finishedAt: '2026-08-15T10:00:05.000Z',
|
|
156
|
+
durationMs: 5000,
|
|
157
|
+
passed: 1,
|
|
158
|
+
failed: 1,
|
|
159
|
+
skipped: 1,
|
|
160
|
+
artifacts: 1,
|
|
161
|
+
}
|
|
162
|
+
)
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
test('a limit takes the newest runs, not whichever the filesystem returned first', async () => {
|
|
166
|
+
const store = new FileScenarioRunStore({ dir })
|
|
167
|
+
for (const day of ['11', '12', '13']) {
|
|
168
|
+
await store.start(
|
|
169
|
+
record({
|
|
170
|
+
runId: `run-${day}`,
|
|
171
|
+
startedAt: `2026-08-${day}T10:00:00.000Z`,
|
|
172
|
+
})
|
|
173
|
+
)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const runs = await store.list({ limit: 2 })
|
|
177
|
+
|
|
178
|
+
assert.deepEqual(
|
|
179
|
+
runs.map((r) => r.runId),
|
|
180
|
+
['run-13', 'run-12']
|
|
181
|
+
)
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
test('opening a run drops the oldest past the limit, with everything they filed', async () => {
|
|
185
|
+
const store = new FileScenarioRunStore({ dir, keep: 2 })
|
|
186
|
+
for (const day of ['11', '12', '13']) {
|
|
187
|
+
await store.start(
|
|
188
|
+
record({
|
|
189
|
+
runId: `run-${day}`,
|
|
190
|
+
startedAt: `2026-08-${day}T10:00:00.000Z`,
|
|
191
|
+
})
|
|
192
|
+
)
|
|
193
|
+
writeFileSync(join(dir, `run-${day}`, 'video.mp4'), 'x')
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
assert.deepEqual(
|
|
197
|
+
(await store.list()).map((r) => r.runId),
|
|
198
|
+
['run-13', 'run-12']
|
|
199
|
+
)
|
|
200
|
+
assert.equal(
|
|
201
|
+
existsSync(join(dir, 'run-11')),
|
|
202
|
+
false,
|
|
203
|
+
'the pruned run takes its artifacts with it'
|
|
204
|
+
)
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
test('a keep of one still leaves the run being opened', async () => {
|
|
208
|
+
const store = new FileScenarioRunStore({ dir, keep: 1 })
|
|
209
|
+
await store.start(record({ runId: 'first' }))
|
|
210
|
+
await store.start(record({ runId: 'second' }))
|
|
211
|
+
|
|
212
|
+
assert.deepEqual(
|
|
213
|
+
(await store.list()).map((r) => r.runId),
|
|
214
|
+
['second']
|
|
215
|
+
)
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
test('artifacts are filed against the scenario the run knows them by', async () => {
|
|
219
|
+
const store = new FileScenarioRunStore({ dir })
|
|
220
|
+
await store.start(record())
|
|
221
|
+
await store.recordScenario('run-1', result({ name: 'checkout › breaks' }))
|
|
222
|
+
await store.recordScenario('run-1', result({ name: 'checkout › works' }))
|
|
223
|
+
|
|
224
|
+
await store.attachArtifacts('run-1', [
|
|
225
|
+
{ scenario: 'checkout › breaks', kind: 'video', path: 'a/admin.mp4' },
|
|
226
|
+
{
|
|
227
|
+
scenario: 'checkout › breaks',
|
|
228
|
+
kind: 'failure',
|
|
229
|
+
path: 'a/failure-admin.png',
|
|
230
|
+
},
|
|
231
|
+
{ scenario: 'a scenario that never ran', kind: 'video', path: 'b/x.mp4' },
|
|
232
|
+
])
|
|
233
|
+
|
|
234
|
+
const [broke, worked] = (await store.get('run-1'))!.results
|
|
235
|
+
assert.deepEqual(
|
|
236
|
+
broke?.artifacts?.map((a) => a.path),
|
|
237
|
+
['a/admin.mp4', 'a/failure-admin.png']
|
|
238
|
+
)
|
|
239
|
+
assert.equal(
|
|
240
|
+
worked?.artifacts,
|
|
241
|
+
undefined,
|
|
242
|
+
'a scenario that produced nothing gets no empty list to render'
|
|
243
|
+
)
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
test('a run id from outside cannot read its way out of the store', async () => {
|
|
247
|
+
const store = new FileScenarioRunStore({ dir })
|
|
248
|
+
writeFileSync(join(dir, 'run.json'), JSON.stringify(record()))
|
|
249
|
+
|
|
250
|
+
assert.equal(await store.get('..'), undefined)
|
|
251
|
+
assert.equal(await store.get('../..'), undefined)
|
|
252
|
+
assert.equal(existsSync(join(dir, 'run.json')), true)
|
|
253
|
+
|
|
254
|
+
await store.remove('../..')
|
|
255
|
+
assert.equal(
|
|
256
|
+
existsSync(dir),
|
|
257
|
+
true,
|
|
258
|
+
'a traversing id must not delete the store itself'
|
|
259
|
+
)
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
test('an artifact is served with the type its extension implies', async () => {
|
|
263
|
+
const store = new FileScenarioRunStore({ dir })
|
|
264
|
+
await store.start(record())
|
|
265
|
+
mkdirSync(join(dir, 'run-1', 'checkout'))
|
|
266
|
+
writeFileSync(join(dir, 'run-1', 'checkout', 'admin.mp4'), 'footage')
|
|
267
|
+
writeFileSync(join(dir, 'run-1', 'checkout', '01-shot.png'), 'image')
|
|
268
|
+
|
|
269
|
+
const video = await store.readArtifact('run-1', 'checkout/admin.mp4')
|
|
270
|
+
const shot = await store.readArtifact('run-1', 'checkout/01-shot.png')
|
|
271
|
+
|
|
272
|
+
assert.equal(video?.contentType, 'video/mp4')
|
|
273
|
+
assert.equal(Buffer.from(video!.body).toString(), 'footage')
|
|
274
|
+
assert.equal(shot?.contentType, 'image/png')
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
test('an artifact path cannot climb out of its run', async () => {
|
|
278
|
+
const store = new FileScenarioRunStore({ dir })
|
|
279
|
+
await store.start(record())
|
|
280
|
+
writeFileSync(join(dir, 'secret.txt'), 'not yours')
|
|
281
|
+
|
|
282
|
+
assert.equal(await store.readArtifact('run-1', '../secret.txt'), undefined)
|
|
283
|
+
assert.equal(
|
|
284
|
+
await store.readArtifact('run-1', 'checkout/../../secret.txt'),
|
|
285
|
+
undefined
|
|
286
|
+
)
|
|
287
|
+
assert.equal(await store.readArtifact('run-1', '/etc/hosts'), undefined)
|
|
288
|
+
assert.equal(
|
|
289
|
+
await store.readArtifact('run-1', 'checkout/never-taken.png'),
|
|
290
|
+
undefined,
|
|
291
|
+
'and an artifact that was never filed is simply absent'
|
|
292
|
+
)
|
|
293
|
+
})
|
|
294
|
+
|
|
295
|
+
test('an artifact of a run that never existed is absent, not an error', async () => {
|
|
296
|
+
const store = new FileScenarioRunStore({ dir })
|
|
297
|
+
|
|
298
|
+
assert.equal(await store.readArtifact('run-1', 'a/b.png'), undefined)
|
|
299
|
+
})
|
|
300
|
+
|
|
301
|
+
test('a half-written run is skipped rather than failing the whole listing', async () => {
|
|
302
|
+
const store = new FileScenarioRunStore({ dir })
|
|
303
|
+
await store.start(record())
|
|
304
|
+
mkdirSync(join(dir, 'killed-mid-write'))
|
|
305
|
+
writeFileSync(join(dir, 'killed-mid-write', 'run.json'), '{"runId":')
|
|
306
|
+
|
|
307
|
+
const runs = await store.list()
|
|
308
|
+
|
|
309
|
+
assert.deepEqual(
|
|
310
|
+
runs.map((r) => r.runId),
|
|
311
|
+
['run-1']
|
|
312
|
+
)
|
|
313
|
+
})
|
|
314
|
+
|
|
315
|
+
test('a store with nothing in it lists nothing rather than throwing', async () => {
|
|
316
|
+
const store = new FileScenarioRunStore({ dir: join(dir, 'never-created') })
|
|
317
|
+
|
|
318
|
+
assert.deepEqual(await store.list(), [])
|
|
319
|
+
assert.equal(await store.get('run-1'), undefined)
|
|
320
|
+
})
|
|
321
|
+
|
|
322
|
+
test('recording against a run that does not exist is ignored, not invented', async () => {
|
|
323
|
+
const store = new FileScenarioRunStore({ dir })
|
|
324
|
+
|
|
325
|
+
await store.recordScenario('never-started', result())
|
|
326
|
+
|
|
327
|
+
assert.deepEqual(await store.list(), [])
|
|
328
|
+
})
|
|
329
|
+
|
|
330
|
+
test('removing a run takes its whole folder', async () => {
|
|
331
|
+
const store = new FileScenarioRunStore({ dir })
|
|
332
|
+
await store.start(record())
|
|
333
|
+
writeFileSync(join(dir, 'run-1', 'video.mp4'), 'x')
|
|
334
|
+
|
|
335
|
+
await store.remove('run-1')
|
|
336
|
+
|
|
337
|
+
assert.equal(existsSync(join(dir, 'run-1')), false)
|
|
338
|
+
})
|
|
339
|
+
})
|
|
340
|
+
|
|
341
|
+
describe('scenarioRunSummary', () => {
|
|
342
|
+
test('a run still going has no duration to report', () => {
|
|
343
|
+
const summary = scenarioRunSummary(record({ results: [result()] }))
|
|
344
|
+
|
|
345
|
+
assert.equal(summary.durationMs, undefined)
|
|
346
|
+
assert.equal(summary.status, 'running')
|
|
347
|
+
assert.equal(summary.passed, 1)
|
|
348
|
+
})
|
|
349
|
+
})
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
import type {
|
|
4
|
+
ScenarioArtifact,
|
|
5
|
+
ScenarioResult,
|
|
6
|
+
ScenarioRunRecord,
|
|
7
|
+
ScenarioRunStore,
|
|
8
|
+
ScenarioRunSummary,
|
|
9
|
+
} from '../wirings/workflow/scenario-run.types.js'
|
|
10
|
+
|
|
11
|
+
/** The record, beside the images and footage the same run produced. */
|
|
12
|
+
const RECORD_FILE = 'run.json'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* A run id is a path segment, and `get('../../etc')` is a file read.
|
|
16
|
+
*
|
|
17
|
+
* Ids are generated here, so anything failing this arrived from outside and is
|
|
18
|
+
* refused rather than sanitised — a request for a run that cannot exist is a
|
|
19
|
+
* request for a run that does not exist.
|
|
20
|
+
*/
|
|
21
|
+
const SAFE_RUN_ID = /^[A-Za-z0-9][A-Za-z0-9_-]*$/
|
|
22
|
+
|
|
23
|
+
/** Counts and duration, derived rather than stored so they cannot disagree. */
|
|
24
|
+
export const scenarioRunSummary = (
|
|
25
|
+
record: ScenarioRunRecord
|
|
26
|
+
): ScenarioRunSummary => ({
|
|
27
|
+
runId: record.runId,
|
|
28
|
+
environment: record.environment,
|
|
29
|
+
surface: record.surface,
|
|
30
|
+
status: record.status,
|
|
31
|
+
startedAt: record.startedAt,
|
|
32
|
+
finishedAt: record.finishedAt,
|
|
33
|
+
durationMs: record.finishedAt
|
|
34
|
+
? new Date(record.finishedAt).getTime() -
|
|
35
|
+
new Date(record.startedAt).getTime()
|
|
36
|
+
: undefined,
|
|
37
|
+
passed: record.results.filter((r) => r.status === 'passed').length,
|
|
38
|
+
failed: record.results.filter((r) => r.status === 'failed').length,
|
|
39
|
+
skipped: record.skipped.length,
|
|
40
|
+
artifacts: record.results.reduce(
|
|
41
|
+
(total, result) => total + (result.artifacts?.length ?? 0),
|
|
42
|
+
0
|
|
43
|
+
),
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* What a scenario artifact is served as.
|
|
48
|
+
*
|
|
49
|
+
* A short, closed list rather than a MIME database: a run produces images and
|
|
50
|
+
* recordings and nothing else, and anything unrecognised is served as bytes the
|
|
51
|
+
* browser is told not to interpret.
|
|
52
|
+
*/
|
|
53
|
+
const CONTENT_TYPES: Record<string, string> = {
|
|
54
|
+
png: 'image/png',
|
|
55
|
+
jpg: 'image/jpeg',
|
|
56
|
+
jpeg: 'image/jpeg',
|
|
57
|
+
webp: 'image/webp',
|
|
58
|
+
mp4: 'video/mp4',
|
|
59
|
+
webm: 'video/webm',
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export const scenarioArtifactContentType = (path: string): string =>
|
|
63
|
+
CONTENT_TYPES[path.split('.').pop()?.toLowerCase() ?? ''] ??
|
|
64
|
+
'application/octet-stream'
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* An artifact path is a content key from the record, but it arrives from a
|
|
68
|
+
* client and is joined onto a directory. Anything that could climb out of the
|
|
69
|
+
* run, or name something other than a file inside it, is refused.
|
|
70
|
+
*/
|
|
71
|
+
const SAFE_ARTIFACT_PATH =
|
|
72
|
+
/^[A-Za-z0-9][A-Za-z0-9._-]*(\/[A-Za-z0-9][A-Za-z0-9._-]*)*$/
|
|
73
|
+
|
|
74
|
+
export interface FileScenarioRunStoreOptions {
|
|
75
|
+
/** The directory runs live under — one folder per run, named by its id. */
|
|
76
|
+
dir: string
|
|
77
|
+
/**
|
|
78
|
+
* How many runs to keep. Older ones are deleted, with their artifacts, as a
|
|
79
|
+
* new run opens.
|
|
80
|
+
*
|
|
81
|
+
* Bounded on purpose: a run with video is megabytes, and an unbounded history
|
|
82
|
+
* beside a project is a directory nobody notices until it is enormous.
|
|
83
|
+
*/
|
|
84
|
+
keep?: number
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const DEFAULT_KEEP = 20
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Scenario run history as files on disk — the OSS store.
|
|
91
|
+
*
|
|
92
|
+
* One folder per run holding its record and everything it filed, which makes a
|
|
93
|
+
* run a thing you can open, copy, attach to an issue or delete with `rm -rf`.
|
|
94
|
+
* A hosted project swaps this for a table and an object store; the console
|
|
95
|
+
* reads the same shapes from either.
|
|
96
|
+
*
|
|
97
|
+
* Writes are serialised through one chain. Scenarios finish one at a time, but
|
|
98
|
+
* `recordScenario` is read-modify-write on a single file, and a store that
|
|
99
|
+
* corrupts its own history the first time two things overlap is worse than no
|
|
100
|
+
* history.
|
|
101
|
+
*/
|
|
102
|
+
export class FileScenarioRunStore implements ScenarioRunStore {
|
|
103
|
+
private writes: Promise<unknown> = Promise.resolve()
|
|
104
|
+
|
|
105
|
+
constructor(private readonly options: FileScenarioRunStoreOptions) {}
|
|
106
|
+
|
|
107
|
+
async start(record: ScenarioRunRecord): Promise<void> {
|
|
108
|
+
await this.serialise(async () => {
|
|
109
|
+
await this.write(record)
|
|
110
|
+
await this.prune(record.runId)
|
|
111
|
+
})
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async recordScenario(runId: string, result: ScenarioResult): Promise<void> {
|
|
115
|
+
await this.serialise(async () => {
|
|
116
|
+
const record = await this.read(runId)
|
|
117
|
+
if (!record) {
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
record.results.push(result)
|
|
121
|
+
await this.write(record)
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async attachArtifacts(
|
|
126
|
+
runId: string,
|
|
127
|
+
artifacts: ScenarioArtifact[]
|
|
128
|
+
): Promise<void> {
|
|
129
|
+
if (artifacts.length === 0) {
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
await this.serialise(async () => {
|
|
133
|
+
const record = await this.read(runId)
|
|
134
|
+
if (!record) {
|
|
135
|
+
return
|
|
136
|
+
}
|
|
137
|
+
for (const artifact of artifacts) {
|
|
138
|
+
const result = record.results.find(
|
|
139
|
+
(candidate) => candidate.name === artifact.scenario
|
|
140
|
+
)
|
|
141
|
+
// An artifact whose scenario is not in the results belongs to a
|
|
142
|
+
// scenario that never produced one — it is dropped rather than filed
|
|
143
|
+
// under a run-level bucket nothing renders.
|
|
144
|
+
if (result) {
|
|
145
|
+
result.artifacts = [...(result.artifacts ?? []), artifact]
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
await this.write(record)
|
|
149
|
+
})
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async finish(
|
|
153
|
+
runId: string,
|
|
154
|
+
outcome: Pick<
|
|
155
|
+
ScenarioRunRecord,
|
|
156
|
+
'status' | 'finishedAt' | 'skipped' | 'hookFailures'
|
|
157
|
+
>
|
|
158
|
+
): Promise<void> {
|
|
159
|
+
await this.serialise(async () => {
|
|
160
|
+
const record = await this.read(runId)
|
|
161
|
+
if (!record) {
|
|
162
|
+
return
|
|
163
|
+
}
|
|
164
|
+
await this.write({ ...record, ...outcome })
|
|
165
|
+
})
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async readArtifact(
|
|
169
|
+
runId: string,
|
|
170
|
+
path: string
|
|
171
|
+
): Promise<
|
|
172
|
+
{ body: Uint8Array<ArrayBuffer>; contentType: string } | undefined
|
|
173
|
+
> {
|
|
174
|
+
if (!SAFE_RUN_ID.test(runId) || !SAFE_ARTIFACT_PATH.test(path)) {
|
|
175
|
+
return undefined
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
178
|
+
const file = await readFile(
|
|
179
|
+
join(this.options.dir, runId, ...path.split('/'))
|
|
180
|
+
)
|
|
181
|
+
return {
|
|
182
|
+
body: new Uint8Array(file),
|
|
183
|
+
contentType: scenarioArtifactContentType(path),
|
|
184
|
+
}
|
|
185
|
+
} catch {
|
|
186
|
+
return undefined
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async list(options: { limit?: number } = {}): Promise<ScenarioRunSummary[]> {
|
|
191
|
+
const summaries: ScenarioRunSummary[] = []
|
|
192
|
+
for (const runId of await this.runIds()) {
|
|
193
|
+
const record = await this.read(runId)
|
|
194
|
+
if (record) {
|
|
195
|
+
summaries.push(scenarioRunSummary(record))
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
summaries.sort((a, b) => b.startedAt.localeCompare(a.startedAt))
|
|
199
|
+
return options.limit ? summaries.slice(0, options.limit) : summaries
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async get(runId: string): Promise<ScenarioRunRecord | undefined> {
|
|
203
|
+
return this.read(runId)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
async remove(runId: string): Promise<void> {
|
|
207
|
+
if (!SAFE_RUN_ID.test(runId)) {
|
|
208
|
+
return
|
|
209
|
+
}
|
|
210
|
+
await rm(join(this.options.dir, runId), { recursive: true, force: true })
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/** Where this run's artifacts live, for a driver writing into it. */
|
|
214
|
+
runDir(runId: string): string {
|
|
215
|
+
return join(this.options.dir, runId)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
private serialise<T>(work: () => Promise<T>): Promise<T> {
|
|
219
|
+
const next = this.writes.then(work, work)
|
|
220
|
+
// Swallowed on the CHAIN only, so one failed write does not reject every
|
|
221
|
+
// later one; the caller still sees its own rejection through `next`.
|
|
222
|
+
this.writes = next.catch(() => {})
|
|
223
|
+
return next
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
private async read(runId: string): Promise<ScenarioRunRecord | undefined> {
|
|
227
|
+
if (!SAFE_RUN_ID.test(runId)) {
|
|
228
|
+
return undefined
|
|
229
|
+
}
|
|
230
|
+
try {
|
|
231
|
+
const raw = await readFile(
|
|
232
|
+
join(this.options.dir, runId, RECORD_FILE),
|
|
233
|
+
'utf-8'
|
|
234
|
+
)
|
|
235
|
+
return JSON.parse(raw) as ScenarioRunRecord
|
|
236
|
+
} catch {
|
|
237
|
+
// A folder with artifacts but no readable record is a run that was killed
|
|
238
|
+
// mid-write. It is not listable, and it is not an error either.
|
|
239
|
+
return undefined
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
private async write(record: ScenarioRunRecord): Promise<void> {
|
|
244
|
+
const dir = join(this.options.dir, record.runId)
|
|
245
|
+
await mkdir(dir, { recursive: true })
|
|
246
|
+
await writeFile(
|
|
247
|
+
join(dir, RECORD_FILE),
|
|
248
|
+
JSON.stringify(record, null, 2) + '\n'
|
|
249
|
+
)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
private async runIds(): Promise<string[]> {
|
|
253
|
+
try {
|
|
254
|
+
const entries = await readdir(this.options.dir, { withFileTypes: true })
|
|
255
|
+
return entries
|
|
256
|
+
.filter((entry) => entry.isDirectory() && SAFE_RUN_ID.test(entry.name))
|
|
257
|
+
.map((entry) => entry.name)
|
|
258
|
+
} catch {
|
|
259
|
+
return []
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Drop the oldest runs past the limit, never the one just opened — a `keep`
|
|
265
|
+
* of zero or one must still leave the run being started.
|
|
266
|
+
*/
|
|
267
|
+
private async prune(keeping: string): Promise<void> {
|
|
268
|
+
const keep = this.options.keep ?? DEFAULT_KEEP
|
|
269
|
+
const dated: Array<{ runId: string; startedAt: string }> = []
|
|
270
|
+
for (const runId of await this.runIds()) {
|
|
271
|
+
if (runId === keeping) {
|
|
272
|
+
continue
|
|
273
|
+
}
|
|
274
|
+
const record = await this.read(runId)
|
|
275
|
+
dated.push({ runId, startedAt: record?.startedAt ?? '' })
|
|
276
|
+
}
|
|
277
|
+
dated.sort((a, b) => b.startedAt.localeCompare(a.startedAt))
|
|
278
|
+
for (const { runId } of dated.slice(Math.max(keep - 1, 0))) {
|
|
279
|
+
await rm(join(this.options.dir, runId), { recursive: true, force: true })
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from 'crypto'
|
|
2
2
|
import { PikkuWorkflowService } from '../wirings/workflow/pikku-workflow-service.js'
|
|
3
3
|
import { isExpectedError } from '../errors/error-handler.js'
|
|
4
|
-
import type { SerializedError } from '../
|
|
4
|
+
import type { SerializedError } from '../errors/serialized-error.js'
|
|
5
5
|
import type {
|
|
6
6
|
WorkflowPlannedStep,
|
|
7
7
|
WorkflowQueueOptions,
|
package/src/services/index.ts
CHANGED
|
@@ -22,6 +22,12 @@ export { InMemoryQueueService } from './in-memory-queue-service.js'
|
|
|
22
22
|
export { InMemoryTriggerService } from './in-memory-trigger-service.js'
|
|
23
23
|
export { InMemoryAgentRunStateService } from './in-memory-agent-run-state-service.js'
|
|
24
24
|
export { LocalGatewayService } from './local-gateway-service.js'
|
|
25
|
+
export {
|
|
26
|
+
FileScenarioRunStore,
|
|
27
|
+
scenarioArtifactContentType,
|
|
28
|
+
scenarioRunSummary,
|
|
29
|
+
type FileScenarioRunStoreOptions,
|
|
30
|
+
} from './file-scenario-run-store.js'
|
|
25
31
|
export type {
|
|
26
32
|
ContentService,
|
|
27
33
|
SignContentKeyArgs,
|
|
@@ -67,8 +73,8 @@ export type { SessionService } from './user-session-service.js'
|
|
|
67
73
|
export type {
|
|
68
74
|
ScheduledTaskSummary,
|
|
69
75
|
ScheduledTaskInfo,
|
|
70
|
-
SchedulerService,
|
|
71
76
|
} from './scheduler-service.js'
|
|
77
|
+
export { SchedulerService } from './scheduler-service.js'
|
|
72
78
|
export type { TriggerService } from './trigger-service.js'
|
|
73
79
|
export type { GatewayService } from './gateway-service.js'
|
|
74
80
|
export type {
|
|
@@ -151,3 +157,9 @@ export {
|
|
|
151
157
|
SecretHostNotAllowedError,
|
|
152
158
|
assertSecretAllowedForHost,
|
|
153
159
|
} from './secret-host-binding.js'
|
|
160
|
+
export type {
|
|
161
|
+
AuditFacets,
|
|
162
|
+
AuditQuery,
|
|
163
|
+
AuditQueryResult,
|
|
164
|
+
} from './audit-service.js'
|
|
165
|
+
export { SecretAccessDeniedError, withoutSecrets } from './secretless.js'
|
|
@@ -78,8 +78,7 @@ const text = (status: number, body: string) =>
|
|
|
78
78
|
})
|
|
79
79
|
|
|
80
80
|
export type SignedContentVerification =
|
|
81
|
-
| { ok:
|
|
82
|
-
| { ok: false; status: number; body: string }
|
|
81
|
+
{ ok: true } | { ok: false; status: number; body: string }
|
|
83
82
|
|
|
84
83
|
/**
|
|
85
84
|
* Verifies a signed content URL — the one function that decides whether a
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
createSecretValue,
|
|
3
3
|
isSecretValue,
|
|
4
4
|
type SecretValue,
|
|
5
|
-
} from '../secret-value.js'
|
|
5
|
+
} from '../classification/secret-value.js'
|
|
6
6
|
import { LocalVariablesService } from './local-variables.js'
|
|
7
7
|
import type { SecretService, SecretValues } from './secret-service.js'
|
|
8
8
|
import type { VariablesService } from './variables-service.js'
|