@pikku/core 0.12.71 → 0.12.74
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 +848 -0
- package/dist/crypto-utils.d.ts +30 -5
- package/dist/crypto-utils.js +146 -41
- package/dist/dev/hot-reload.js +11 -30
- package/dist/dev/module-runner.d.ts +3 -7
- package/dist/dev/module-runner.js +4 -10
- package/dist/dev/reload-meta.d.ts +8 -20
- package/dist/dev/reload-meta.js +9 -29
- package/dist/errors/error-handler.d.ts +5 -30
- package/dist/errors/error-handler.js +16 -32
- package/dist/errors/errors.d.ts +32 -151
- package/dist/errors/errors.js +55 -157
- package/dist/function/abort-scope.d.ts +47 -0
- package/dist/function/abort-scope.js +63 -0
- package/dist/function/function-runner.js +40 -30
- package/dist/function/functions.types.d.ts +44 -136
- package/dist/function/functions.types.js +0 -58
- package/dist/function/list.types.d.ts +12 -62
- package/dist/function/list.types.js +4 -25
- package/dist/handle-error.d.ts +0 -11
- package/dist/handle-error.js +6 -18
- package/dist/index.d.ts +5 -2
- package/dist/index.js +4 -1
- package/dist/middleware/auth-apikey.d.ts +3 -18
- package/dist/middleware/auth-apikey.js +0 -17
- package/dist/middleware/auth-bearer.d.ts +6 -41
- package/dist/middleware/auth-bearer.js +3 -40
- package/dist/middleware/auth-cookie.d.ts +5 -27
- package/dist/middleware/auth-cookie.js +2 -26
- package/dist/middleware/cors.d.ts +7 -34
- package/dist/middleware/cors.js +7 -34
- package/dist/middleware/remote-auth.d.ts +3 -1
- package/dist/middleware/remote-auth.js +3 -2
- package/dist/middleware/telemetry.d.ts +8 -33
- package/dist/middleware/telemetry.js +2 -31
- package/dist/middleware-runner.d.ts +4 -55
- package/dist/middleware-runner.js +5 -74
- package/dist/permissions.d.ts +3 -44
- package/dist/permissions.js +19 -71
- package/dist/pikku-request.d.ts +0 -6
- package/dist/pikku-request.js +0 -6
- package/dist/pikku-state.d.ts +0 -26
- package/dist/pikku-state.js +2 -30
- package/dist/remote.d.ts +3 -5
- package/dist/remote.js +8 -7
- package/dist/schema.d.ts +7 -17
- package/dist/schema.js +30 -18
- package/dist/scopes.d.ts +4 -23
- package/dist/scopes.js +7 -48
- package/dist/services/ai-agent-runner-service.d.ts +20 -0
- package/dist/services/ai-embedding-service.d.ts +2 -25
- package/dist/services/audit-service.js +1 -2
- package/dist/services/content-service.d.ts +1 -46
- package/dist/services/credential-service.d.ts +3 -40
- package/dist/services/deployment-service.d.ts +3 -9
- package/dist/services/gateway-service.d.ts +0 -15
- package/dist/services/http-personas.d.ts +80 -0
- package/dist/services/http-personas.js +233 -0
- package/dist/services/in-memory-queue-service.d.ts +0 -14
- package/dist/services/in-memory-queue-service.js +1 -15
- package/dist/services/in-memory-trigger-service.d.ts +0 -18
- package/dist/services/in-memory-trigger-service.js +1 -18
- package/dist/services/in-memory-workflow-service.d.ts +0 -16
- package/dist/services/in-memory-workflow-service.js +4 -33
- package/dist/services/index.d.ts +5 -6
- package/dist/services/index.js +2 -5
- package/dist/services/istanbul-coverage-service.d.ts +1 -5
- package/dist/services/istanbul-coverage-service.js +2 -8
- package/dist/services/jwt-service.d.ts +1 -16
- package/dist/services/local-content.d.ts +13 -2
- package/dist/services/local-content.js +40 -13
- package/dist/services/local-gateway-service.d.ts +0 -16
- package/dist/services/local-gateway-service.js +2 -17
- package/dist/services/local-secrets.d.ts +0 -4
- package/dist/services/local-secrets.js +0 -4
- package/dist/services/logger-console.d.ts +3 -7
- package/dist/services/logger-console.js +3 -7
- package/dist/services/logger.d.ts +2 -37
- package/dist/services/meta-service.d.ts +23 -26
- package/dist/services/meta-service.js +22 -36
- package/dist/services/personas-service.d.ts +134 -0
- package/dist/services/personas-service.js +40 -0
- package/dist/services/pikku-user-id.js +0 -4
- package/dist/services/queue-webhook-service.d.ts +2 -36
- package/dist/services/queue-webhook-service.js +9 -41
- package/dist/services/scheduler-service.d.ts +1 -50
- package/dist/services/scheduler-service.js +0 -10
- package/dist/services/schema-service.d.ts +1 -24
- package/dist/services/scope-service.d.ts +49 -34
- package/dist/services/scoped-secret-service.d.ts +0 -4
- package/dist/services/scoped-secret-service.js +0 -4
- package/dist/services/secret-host-binding.d.ts +8 -0
- package/dist/services/secret-host-binding.js +36 -0
- package/dist/services/secret-service.d.ts +5 -33
- package/dist/services/secretless.d.ts +6 -0
- package/dist/services/secretless.js +21 -0
- package/dist/services/stub-tracker.d.ts +7 -18
- package/dist/services/stub-tracker.js +8 -18
- package/dist/services/system-role-guard.d.ts +33 -0
- package/dist/services/system-role-guard.js +38 -0
- package/dist/services/trigger-service.d.ts +0 -12
- package/dist/services/typed-secret-service.d.ts +0 -7
- package/dist/services/typed-secret-service.js +1 -7
- package/dist/services/v8-coverage-service.d.ts +2 -3
- package/dist/services/v8-coverage-service.js +1 -2
- package/dist/services/variables-service.d.ts +1 -8
- package/dist/services/webhook-service.d.ts +19 -63
- package/dist/services/webhook-service.js +6 -20
- package/dist/services/workflow-service.d.ts +3 -15
- package/dist/testing/service-tests.js +0 -17
- package/dist/time-utils.d.ts +0 -16
- package/dist/time-utils.js +1 -19
- package/dist/types/core.types.d.ts +99 -219
- package/dist/types/core.types.js +0 -42
- package/dist/types/state.types.d.ts +4 -9
- package/dist/utils/hmac.d.ts +4 -10
- package/dist/utils/hmac.js +4 -10
- package/dist/utils/safe-fetch.d.ts +7 -35
- package/dist/utils/safe-fetch.js +13 -53
- package/dist/utils.d.ts +1 -6
- package/dist/utils.js +6 -15
- package/dist/wirings/actor-flow/actor-flow.types.d.ts +1 -34
- package/dist/wirings/actor-flow/index.d.ts +0 -9
- package/dist/wirings/actor-flow/run-conversation.d.ts +5 -5
- package/dist/wirings/actor-flow/run-conversation.js +14 -7
- package/dist/wirings/ai-agent/ai-agent-agui.d.ts +0 -5
- package/dist/wirings/ai-agent/ai-agent-agui.js +34 -12
- package/dist/wirings/ai-agent/ai-agent-helpers.d.ts +7 -0
- package/dist/wirings/ai-agent/ai-agent-helpers.js +7 -0
- package/dist/wirings/ai-agent/ai-agent-interrupt.d.ts +153 -0
- package/dist/wirings/ai-agent/ai-agent-interrupt.js +256 -0
- package/dist/wirings/ai-agent/ai-agent-memory.js +0 -2
- package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +0 -9
- package/dist/wirings/ai-agent/ai-agent-model-config.js +1 -9
- package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +10 -99
- package/dist/wirings/ai-agent/ai-agent-prepare.js +58 -131
- package/dist/wirings/ai-agent/ai-agent-registry.d.ts +2 -1
- package/dist/wirings/ai-agent/ai-agent-registry.js +5 -1
- package/dist/wirings/ai-agent/ai-agent-runner.js +49 -20
- package/dist/wirings/ai-agent/ai-agent-stream.d.ts +25 -2
- package/dist/wirings/ai-agent/ai-agent-stream.js +153 -63
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +84 -4
- package/dist/wirings/ai-agent/index.d.ts +6 -4
- package/dist/wirings/ai-agent/index.js +5 -4
- package/dist/wirings/ai-agent/voice-input.d.ts +39 -1
- package/dist/wirings/ai-agent/voice-input.js +46 -3
- package/dist/wirings/ai-agent/voice-output.d.ts +54 -1
- package/dist/wirings/ai-agent/voice-output.js +153 -50
- package/dist/wirings/channel/channel-common.d.ts +7 -20
- package/dist/wirings/channel/channel-common.js +7 -21
- package/dist/wirings/channel/channel-handler.js +25 -6
- package/dist/wirings/channel/channel-host-rpc.d.ts +25 -0
- package/dist/wirings/channel/channel-host-rpc.js +38 -0
- package/dist/wirings/channel/channel-middleware-runner.d.ts +0 -12
- package/dist/wirings/channel/channel-middleware-runner.js +0 -12
- package/dist/wirings/channel/channel-rpc-registry.d.ts +31 -0
- package/dist/wirings/channel/channel-rpc-registry.js +89 -0
- package/dist/wirings/channel/channel-rpc-responder.d.ts +15 -0
- package/dist/wirings/channel/channel-rpc-responder.js +71 -0
- package/dist/wirings/channel/channel-rpc-service.d.ts +40 -0
- package/dist/wirings/channel/channel-rpc-service.js +106 -0
- package/dist/wirings/channel/channel-rpc-validators.d.ts +14 -0
- package/dist/wirings/channel/channel-rpc-validators.js +30 -0
- package/dist/wirings/channel/channel-rpc.d.ts +5 -0
- package/dist/wirings/channel/channel-rpc.js +5 -0
- package/dist/wirings/channel/channel-rpc.types.d.ts +90 -0
- package/dist/wirings/channel/channel-rpc.types.js +50 -0
- package/dist/wirings/channel/channel-runner.d.ts +0 -4
- package/dist/wirings/channel/channel-runner.js +0 -14
- package/dist/wirings/channel/channel-store.d.ts +0 -10
- package/dist/wirings/channel/channel.types.d.ts +12 -1
- package/dist/wirings/channel/define-channel-routes.d.ts +0 -20
- package/dist/wirings/channel/define-channel-routes.js +0 -20
- package/dist/wirings/channel/eventhub-service.d.ts +0 -18
- package/dist/wirings/channel/index.d.ts +4 -1
- package/dist/wirings/channel/index.js +2 -0
- package/dist/wirings/channel/local/local-channel-runner.js +3 -1
- package/dist/wirings/channel/local/local-eventhub-service.d.ts +0 -33
- package/dist/wirings/channel/local/local-eventhub-service.js +2 -36
- package/dist/wirings/channel/log-channels.d.ts +0 -4
- package/dist/wirings/channel/log-channels.js +0 -4
- package/dist/wirings/channel/pikku-abstract-channel-handler.js +6 -0
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +2 -5
- package/dist/wirings/cli/channel/cli-approval.d.ts +41 -0
- package/dist/wirings/cli/channel/cli-approval.js +81 -0
- package/dist/wirings/cli/channel/cli-channel-runner.d.ts +0 -4
- package/dist/wirings/cli/channel/cli-channel-runner.js +3 -25
- package/dist/wirings/cli/channel/cli-raw-channel-runner.d.ts +47 -9
- package/dist/wirings/cli/channel/cli-raw-channel-runner.js +24 -16
- package/dist/wirings/cli/channel/cli-raw-client-runner.d.ts +20 -0
- package/dist/wirings/cli/channel/cli-raw-client-runner.js +121 -0
- package/dist/wirings/cli/channel/index.d.ts +4 -0
- package/dist/wirings/cli/channel/index.js +2 -0
- package/dist/wirings/cli/cli-runner.d.ts +20 -20
- package/dist/wirings/cli/cli-runner.js +28 -89
- package/dist/wirings/cli/cli.types.d.ts +14 -3
- package/dist/wirings/cli/command-parser.d.ts +1 -10
- package/dist/wirings/cli/command-parser.js +10 -87
- package/dist/wirings/cli/define-cli-commands.d.ts +1 -17
- package/dist/wirings/cli/define-cli-commands.js +1 -17
- package/dist/wirings/credential/credential.types.d.ts +0 -12
- package/dist/wirings/credential/define-credential.d.ts +48 -0
- package/dist/wirings/credential/define-credential.js +47 -0
- package/dist/wirings/credential/index.d.ts +1 -1
- package/dist/wirings/credential/index.js +1 -1
- package/dist/wirings/credential/validate-credential-definitions.d.ts +2 -4
- package/dist/wirings/gateway/gateway-runner.d.ts +1 -20
- package/dist/wirings/gateway/gateway-runner.js +8 -105
- package/dist/wirings/gateway/gateway.types.d.ts +7 -80
- package/dist/wirings/http/http-routes.d.ts +0 -63
- package/dist/wirings/http/http-routes.js +0 -63
- package/dist/wirings/http/http-runner.d.ts +1 -100
- package/dist/wirings/http/http-runner.js +12 -166
- package/dist/wirings/http/http.types.d.ts +16 -55
- package/dist/wirings/http/index.d.ts +2 -1
- package/dist/wirings/http/index.js +1 -1
- package/dist/wirings/http/log-http-routes.d.ts +0 -4
- package/dist/wirings/http/log-http-routes.js +0 -4
- package/dist/wirings/http/pikku-fetch-http-request.d.ts +6 -36
- package/dist/wirings/http/pikku-fetch-http-request.js +56 -50
- package/dist/wirings/http/pikku-fetch-http-response.js +0 -3
- package/dist/wirings/http/routers/path-to-regex.js +2 -13
- package/dist/wirings/http/web-request.d.ts +0 -8
- package/dist/wirings/http/web-request.js +25 -17
- package/dist/wirings/mcp/mcp-runner.d.ts +2 -0
- package/dist/wirings/mcp/mcp-runner.js +6 -16
- package/dist/wirings/mcp/mcp.types.d.ts +2 -35
- package/dist/wirings/oauth2/oauth2.types.d.ts +0 -28
- package/dist/wirings/oauth2/oauth2.types.js +0 -3
- package/dist/wirings/persona/define-personas.d.ts +28 -0
- package/dist/wirings/persona/define-personas.js +27 -0
- package/dist/wirings/persona/index.d.ts +21 -0
- package/dist/wirings/persona/index.js +17 -0
- package/dist/wirings/persona/persona-email.d.ts +37 -0
- package/dist/wirings/persona/persona-email.js +69 -0
- package/dist/wirings/persona/persona-environments.d.ts +45 -0
- package/dist/wirings/persona/persona-environments.js +81 -0
- package/dist/wirings/persona/persona-mailbox.d.ts +101 -0
- package/dist/wirings/persona/persona-mailbox.js +53 -0
- package/dist/wirings/persona/persona.types.d.ts +125 -0
- package/dist/wirings/persona/persona.types.js +1 -0
- package/dist/wirings/persona/validate-personas.d.ts +53 -0
- package/dist/wirings/persona/validate-personas.js +94 -0
- package/dist/wirings/queue/index.d.ts +3 -0
- package/dist/wirings/queue/index.js +2 -3
- package/dist/wirings/queue/queue-identity.d.ts +28 -0
- package/dist/wirings/queue/queue-identity.js +102 -0
- package/dist/wirings/queue/queue-runner.d.ts +0 -19
- package/dist/wirings/queue/queue-runner.js +9 -30
- package/dist/wirings/queue/queue.types.d.ts +18 -89
- package/dist/wirings/queue/register-queue-helper.d.ts +0 -12
- package/dist/wirings/queue/register-queue-helper.js +0 -11
- package/dist/wirings/queue/signed-queue-service.d.ts +16 -0
- package/dist/wirings/queue/signed-queue-service.js +42 -0
- package/dist/wirings/queue/validate-worker-config.d.ts +2 -23
- package/dist/wirings/queue/validate-worker-config.js +0 -14
- package/dist/wirings/role/define-system-role.d.ts +32 -0
- package/dist/wirings/role/define-system-role.js +31 -0
- package/dist/wirings/role/index.d.ts +3 -0
- package/dist/wirings/role/index.js +2 -0
- package/dist/wirings/role/role.types.d.ts +43 -0
- package/dist/wirings/role/role.types.js +1 -0
- package/dist/wirings/role/validate-role-definitions.d.ts +21 -0
- package/dist/wirings/role/validate-role-definitions.js +71 -0
- package/dist/wirings/rpc/addon-runner.d.ts +0 -19
- package/dist/wirings/rpc/addon-runner.js +0 -51
- package/dist/wirings/rpc/remote-addon-auth.d.ts +1 -12
- package/dist/wirings/rpc/remote-addon-auth.js +1 -9
- package/dist/wirings/rpc/rpc-runner.d.ts +11 -18
- package/dist/wirings/rpc/rpc-runner.js +88 -105
- package/dist/wirings/rpc/rpc-types.d.ts +7 -6
- package/dist/wirings/rpc/wire-addon.d.ts +25 -0
- package/dist/wirings/rpc/wire-addon.js +62 -0
- package/dist/wirings/rpc/wire-remote-addon.d.ts +3 -28
- package/dist/wirings/rpc/wire-remote-addon.js +0 -8
- package/dist/wirings/scheduler/log-schedulers.d.ts +0 -4
- package/dist/wirings/scheduler/log-schedulers.js +0 -4
- package/dist/wirings/scheduler/scheduler-runner.d.ts +0 -1
- package/dist/wirings/scheduler/scheduler-runner.js +0 -1
- package/dist/wirings/scheduler/scheduler.types.d.ts +1 -14
- package/dist/wirings/scope/define-scope.d.ts +32 -0
- package/dist/wirings/scope/define-scope.js +31 -0
- package/dist/wirings/scope/index.d.ts +1 -1
- package/dist/wirings/scope/index.js +1 -1
- package/dist/wirings/scope/scope.types.d.ts +7 -9
- package/dist/wirings/scope/validate-scope-definitions.d.ts +2 -21
- package/dist/wirings/scope/validate-scope-definitions.js +3 -21
- package/dist/wirings/secret/index.d.ts +1 -1
- package/dist/wirings/secret/index.js +1 -1
- package/dist/wirings/secret/secret.types.d.ts +19 -15
- package/dist/wirings/secret/secret.types.js +1 -1
- package/dist/wirings/secret/validate-secret-definitions.d.ts +2 -4
- package/dist/wirings/trigger/trigger-runner.d.ts +0 -27
- package/dist/wirings/trigger/trigger-runner.js +1 -24
- package/dist/wirings/trigger/trigger.types.d.ts +1 -82
- package/dist/wirings/trigger/trigger.types.js +0 -34
- package/dist/wirings/variable/index.d.ts +1 -1
- package/dist/wirings/variable/index.js +1 -1
- package/dist/wirings/variable/validate-variable-definitions.d.ts +2 -4
- package/dist/wirings/variable/variable.types.d.ts +1 -13
- package/dist/wirings/variable/variable.types.js +1 -1
- package/dist/wirings/virtual-user/index.d.ts +27 -0
- package/dist/wirings/virtual-user/index.js +8 -0
- package/dist/wirings/virtual-user/run-virtual-user.d.ts +92 -0
- package/dist/wirings/virtual-user/run-virtual-user.js +478 -0
- package/dist/wirings/virtual-user/virtual-user-agents.d.ts +38 -0
- package/dist/wirings/virtual-user/virtual-user-agents.js +24 -0
- package/dist/wirings/virtual-user/virtual-user-catalogue.d.ts +92 -0
- package/dist/wirings/virtual-user/virtual-user-catalogue.js +134 -0
- package/dist/wirings/virtual-user/virtual-user-derive.d.ts +26 -0
- package/dist/wirings/virtual-user/virtual-user-derive.js +137 -0
- package/dist/wirings/virtual-user/virtual-user-dispositions.d.ts +79 -0
- package/dist/wirings/virtual-user/virtual-user-dispositions.js +128 -0
- package/dist/wirings/virtual-user/virtual-user-intents.d.ts +78 -0
- package/dist/wirings/virtual-user/virtual-user-intents.js +142 -0
- package/dist/wirings/virtual-user/virtual-user-rng.d.ts +24 -0
- package/dist/wirings/virtual-user/virtual-user-rng.js +44 -0
- package/dist/wirings/virtual-user/virtual-user-target.d.ts +21 -0
- package/dist/wirings/virtual-user/virtual-user-target.js +34 -0
- package/dist/wirings/virtual-user/virtual-user.types.d.ts +199 -0
- package/dist/wirings/virtual-user/virtual-user.types.js +8 -0
- package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +5 -5
- package/dist/wirings/workflow/dsl/workflow-runner.d.ts +0 -4
- package/dist/wirings/workflow/dsl/workflow-runner.js +0 -4
- package/dist/wirings/workflow/feature.d.ts +0 -19
- package/dist/wirings/workflow/feature.js +0 -19
- package/dist/wirings/workflow/graph/graph-node.d.ts +0 -98
- package/dist/wirings/workflow/graph/graph-node.js +0 -34
- package/dist/wirings/workflow/graph/graph-runner.js +6 -41
- package/dist/wirings/workflow/graph/wire-workflow-graph.d.ts +0 -4
- package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +0 -58
- package/dist/wirings/workflow/graph/workflow-graph.types.js +0 -6
- package/dist/wirings/workflow/index.d.ts +5 -7
- package/dist/wirings/workflow/index.js +3 -17
- package/dist/wirings/workflow/pikku-scenario-service.d.ts +87 -5
- package/dist/wirings/workflow/pikku-scenario-service.js +204 -42
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +7 -459
- package/dist/wirings/workflow/pikku-workflow-service.js +58 -551
- package/dist/wirings/workflow/run-timeline.d.ts +0 -47
- package/dist/wirings/workflow/run-timeline.js +0 -22
- package/dist/wirings/workflow/scenario-cookie-jar.d.ts +0 -23
- package/dist/wirings/workflow/scenario-cookie-jar.js +0 -16
- package/dist/wirings/workflow/scenario-poll.d.ts +0 -15
- package/dist/wirings/workflow/scenario-poll.js +0 -12
- package/dist/wirings/workflow/scenario-prose.d.ts +0 -28
- package/dist/wirings/workflow/scenario-prose.js +0 -18
- package/dist/wirings/workflow/scenario-step-guards.d.ts +0 -13
- package/dist/wirings/workflow/scenario-step-guards.js +1 -14
- package/dist/wirings/workflow/scenario-step.types.d.ts +72 -6
- package/dist/wirings/workflow/scenario-step.types.js +5 -1
- package/dist/wirings/workflow/scenario-surface.d.ts +16 -0
- package/dist/wirings/workflow/scenario-surface.js +56 -0
- package/dist/wirings/workflow/workflow-invocation-id.d.ts +0 -18
- package/dist/wirings/workflow/workflow-invocation-id.js +2 -22
- package/dist/wirings/workflow/workflow-queue-workers.d.ts +0 -20
- package/dist/wirings/workflow/workflow-queue-workers.js +0 -19
- package/dist/wirings/workflow/workflow.types.d.ts +0 -197
- package/knowledge/decisions/index.md +19 -0
- package/knowledge/decisions/internals/a-secret-that-fails-to-decrypt-fails-the-whole-read.md +49 -0
- package/knowledge/decisions/internals/actor-flow-conversations-seed-a-hidden-kickoff-message.md +23 -0
- package/knowledge/decisions/internals/actor-flow-drives-the-target-through-a-transport-seam.md +24 -0
- package/knowledge/decisions/internals/actor-flow-verdicts-are-llm-self-evaluations.md +25 -0
- package/knowledge/decisions/internals/addon-package-roots-resolve-by-walking-node-module-search-paths.md +26 -0
- package/knowledge/decisions/internals/addon-singleton-services-are-cached-per-namespace-not-per-package.md +33 -0
- package/knowledge/decisions/internals/addon-workflow-names-are-prefixed-with-the-consumer-namespace.md +28 -0
- package/knowledge/decisions/internals/ai-agent-agui-bridge-obeys-the-client-ordering-contract.md +29 -0
- package/knowledge/decisions/internals/ai-agent-audio-chunks-carry-the-format-the-provider-returned.md +20 -0
- package/knowledge/decisions/internals/ai-agent-credential-suspensions-hide-the-tool-result.md +26 -0
- package/knowledge/decisions/internals/ai-agent-delegate-and-supervise-hide-different-text.md +26 -0
- package/knowledge/decisions/internals/ai-agent-llm-tool-arguments-have-nulls-stripped.md +23 -0
- package/knowledge/decisions/internals/ai-agent-model-config-stays-a-single-resolution-seam.md +25 -0
- package/knowledge/decisions/internals/ai-agent-onerror-hooks-cannot-change-the-failure.md +22 -0
- package/knowledge/decisions/internals/ai-agent-runner-methods-must-keep-their-receiver.md +22 -0
- package/knowledge/decisions/internals/ai-agent-stream-persistence-is-best-effort.md +27 -0
- package/knowledge/decisions/internals/ai-agent-sub-agents-inherit-the-parent-context-block.md +26 -0
- package/knowledge/decisions/internals/ai-agent-tool-execute-failures-are-logged-unconditionally.md +25 -0
- package/knowledge/decisions/internals/ai-agent-voice-input-transcribes-audio-parts-in-place.md +22 -0
- package/knowledge/decisions/internals/ai-agent-working-memory-is-persisted-only-when-valid.md +25 -0
- package/knowledge/decisions/internals/channel-message-handlers-accept-three-config-shapes.md +30 -0
- package/knowledge/decisions/internals/channel-middleware-caches-only-statically-resolved-middleware.md +31 -0
- package/knowledge/decisions/internals/channel-state-is-per-socket-session-state-is-per-user.md +29 -0
- package/knowledge/decisions/internals/channel-user-id-is-persisted-after-onconnect-middleware-runs.md +28 -0
- package/knowledge/decisions/internals/cli-option-names-are-camelcase-in-state-and-kebab-on-the-command-line.md +27 -0
- package/knowledge/decisions/internals/cli-parse-errors-are-routed-by-message-prefix.md +28 -0
- package/knowledge/decisions/internals/cli-stdout-is-reserved-for-machine-readable-output.md +34 -0
- package/knowledge/decisions/internals/cli-unknown-long-options-warn-instead-of-failing.md +29 -0
- package/knowledge/decisions/internals/core-data-classification-brand-is-an-optional-property.md +34 -0
- package/knowledge/decisions/internals/core-function-runner-restores-the-wire-fields-it-overwrites.md +44 -0
- package/knowledge/decisions/internals/core-hot-reload-merges-generated-meta-never-replaces-it.md +39 -0
- package/knowledge/decisions/internals/core-hot-reload-owns-its-module-registry.md +42 -0
- package/knowledge/decisions/internals/core-middleware-order-is-scope-then-priority.md +39 -0
- package/knowledge/decisions/internals/core-schema-defaults-apply-on-every-transport.md +43 -0
- package/knowledge/decisions/internals/core-scopes-are-an-and-gate-separate-from-permissions.md +38 -0
- package/knowledge/decisions/internals/core-state-is-a-global-map-written-only-at-registration-time.md +44 -0
- package/knowledge/decisions/internals/email-meta-is-read-uncached-because-codegen-rewrites-it-mid-session.md +27 -0
- package/knowledge/decisions/internals/gateway-adapters-resolve-lazily-and-are-promise-cached.md +32 -0
- package/knowledge/decisions/internals/gateway-webhook-challenges-echo-bytes-not-json.md +28 -0
- package/knowledge/decisions/internals/gateway-wiring-is-a-meta-wiring-over-http-and-channels.md +31 -0
- package/knowledge/decisions/internals/generated-src-paths-in-pikku-meta-are-absolute.md +26 -0
- package/knowledge/decisions/internals/http-request-bodies-are-read-once-and-shared.md +32 -0
- package/knowledge/decisions/internals/http-route-groups-cascade-config-in-a-fixed-order.md +28 -0
- package/knowledge/decisions/internals/http-router-matches-normalized-paths-but-returns-registered-ones.md +30 -0
- package/knowledge/decisions/internals/http-runner-logs-through-a-trace-scoped-logger-functions-do-not.md +26 -0
- package/knowledge/decisions/internals/http-set-cookie-headers-are-appended-never-joined.md +28 -0
- package/knowledge/decisions/internals/http-sse-streams-flush-headers-only-after-middleware.md +32 -0
- package/knowledge/decisions/internals/http-wiring-without-metadata-is-skipped-not-fatal.md +26 -0
- package/knowledge/decisions/internals/in-a-scenario-a-4xx-is-data-not-an-exception.md +25 -0
- package/knowledge/decisions/internals/in-memory-workflow-history-aliases-the-live-step-object.md +26 -0
- package/knowledge/decisions/internals/index.md +113 -0
- package/knowledge/decisions/internals/istanbul-statement-counts-attach-to-the-start-line-only.md +25 -0
- package/knowledge/decisions/internals/local-trigger-and-gateway-services-assume-a-single-process.md +26 -0
- package/knowledge/decisions/internals/node-only-builtins-are-imported-dynamically.md +24 -0
- package/knowledge/decisions/internals/queue-group-concurrency-keeps-one-shared-queue-fair.md +28 -0
- package/knowledge/decisions/internals/queue-jobs-always-carry-an-explicit-attempts-count.md +27 -0
- package/knowledge/decisions/internals/remote-addons-dispatch-over-http-instead-of-local-meta.md +31 -0
- package/knowledge/decisions/internals/rpc-names-resolve-through-package-scope-before-root.md +32 -0
- package/knowledge/decisions/internals/scenario-agent-calls-sign-in-on-401-only.md +27 -0
- package/knowledge/decisions/internals/scenario-meta-lives-apart-from-app-meta-but-merges-when-read-off-disk.md +26 -0
- package/knowledge/decisions/internals/scenario-steps-return-drained-response-records.md +27 -0
- package/knowledge/decisions/internals/scope-roots-may-be-co-declared-by-an-addon-and-its-host-app.md +30 -0
- package/knowledge/decisions/internals/serverless-channel-disconnect-must-tolerate-a-missing-channel.md +28 -0
- package/knowledge/decisions/internals/the-dev-queue-copies-prod-timing-and-serialization-semantics.md +30 -0
- package/knowledge/decisions/internals/the-embedding-model-is-pinned-per-service-and-doc-query-embedding-is-split.md +29 -0
- package/knowledge/decisions/internals/the-in-memory-workflow-service-is-inline-only-and-single-process.md +27 -0
- package/knowledge/decisions/internals/the-kek-salt-is-scoped-to-the-key-version.md +40 -0
- package/knowledge/decisions/internals/the-schema-service-is-never-stubbed.md +26 -0
- package/knowledge/decisions/internals/trigger-declaration-is-split-from-trigger-source.md +33 -0
- package/knowledge/decisions/internals/typed-secret-service-caches-for-the-process-lifetime.md +26 -0
- package/knowledge/decisions/internals/webhook-delivery-history-records-every-attempt-best-effort.md +26 -0
- package/knowledge/decisions/internals/webhook-service-collaborators-are-constructor-args-not-locator-lookups.md +25 -0
- package/knowledge/decisions/internals/whether-a-run-is-inline-is-read-from-the-run-record.md +58 -0
- package/knowledge/decisions/internals/workflow-approval-expiry-is-decided-from-a-recorded-deadline.md +34 -0
- package/knowledge/decisions/internals/workflow-core-never-imports-a-browser-driver.md +42 -0
- package/knowledge/decisions/internals/workflow-dsl-meta-separates-runtime-expressions-from-literals.md +38 -0
- package/knowledge/decisions/internals/workflow-features-resolve-scenarios-by-object-identity.md +29 -0
- package/knowledge/decisions/internals/workflow-graph-inline-and-queued-runs-share-one-planner.md +42 -0
- package/knowledge/decisions/internals/workflow-graph-node-notes-are-excluded-from-the-graph-hash.md +25 -0
- package/knowledge/decisions/internals/workflow-inline-runs-report-their-run-id-before-they-can-fail.md +29 -0
- package/knowledge/decisions/internals/workflow-invocation-id-is-the-dedupe-key-not-step-id.md +43 -0
- package/knowledge/decisions/internals/workflow-queued-step-dispatch-requires-an-explicit-opt-in.md +29 -0
- package/knowledge/decisions/internals/workflow-queues-are-per-workflow-by-default.md +42 -0
- package/knowledge/decisions/internals/workflow-repeated-step-names-get-an-ordinal-suffix.md +33 -0
- package/knowledge/decisions/internals/workflow-replay-reads-its-steps-once-and-caches-only-the-immutable-half.md +32 -0
- package/knowledge/decisions/internals/workflow-retries-are-owned-by-the-workflow-not-the-queue.md +31 -0
- package/knowledge/decisions/internals/workflow-run-capabilities-are-extensions-not-subclasses.md +39 -0
- package/knowledge/decisions/internals/workflow-run-mirror-is-never-a-source-of-truth.md +29 -0
- package/knowledge/decisions/internals/workflow-run-polling-backs-off-to-the-callers-ceiling.md +33 -0
- package/knowledge/decisions/internals/workflow-run-timeline-is-a-pure-fold-over-durable-history.md +37 -0
- package/knowledge/decisions/internals/workflow-scenario-assertions-never-retry-and-record-one-step.md +50 -0
- package/knowledge/decisions/internals/workflow-scenario-hooks-are-a-scenario-only-affordance.md +43 -0
- package/knowledge/decisions/internals/workflow-scenario-prose-is-rendered-from-typed-calls-not-parsed-from-english.md +32 -0
- package/knowledge/decisions/internals/workflow-scenario-quarantine-reason-lives-in-code.md +18 -0
- package/knowledge/decisions/internals/workflow-scenario-step-targets-are-string-literals-for-the-inspector.md +34 -0
- package/knowledge/decisions/internals/workflow-step-compensation-runs-as-its-own-durable-step.md +26 -0
- package/knowledge/decisions/internals/workflow-step-dispatch-failure-is-transient-not-a-run-failure.md +33 -0
- package/knowledge/decisions/internals/workflow-step-lock-is-held-only-to-claim-the-step.md +27 -0
- package/knowledge/decisions/internals/workflow-step-rpc-name-is-provenance-only.md +34 -0
- package/knowledge/decisions/internals/workflow-suspend-and-approval-reasons-are-durable-step-identities.md +38 -0
- package/knowledge/decisions/internals/workflow-suspended-runs-keep-their-in-process-context.md +30 -0
- package/knowledge/decisions/security/a-dropped-audit-write-is-always-logged.md +26 -0
- package/knowledge/decisions/security/actor-flow-missing-approval-decisions-default-to-denied.md +22 -0
- package/knowledge/decisions/security/actor-sign-in-is-proven-by-set-cookie-not-a-non-empty-jar.md +27 -0
- package/knowledge/decisions/security/actor-sign-in-only-works-for-actor-flagged-users.md +27 -0
- package/knowledge/decisions/security/addon-auth-and-tags-only-tighten.md +43 -0
- package/knowledge/decisions/security/addon-config-gates-apply-only-at-the-namespaced-rpc-boundary.md +52 -0
- package/knowledge/decisions/security/addon-scopes-are-resolved-where-the-function-runs.md +46 -0
- package/knowledge/decisions/security/ai-agent-approval-forwarding-requires-a-symbol-brand.md +27 -0
- package/knowledge/decisions/security/ai-agent-credential-requests-are-symbol-branded.md +37 -0
- package/knowledge/decisions/security/ai-agent-gate-requires-a-session-only-when-auth-is-true.md +31 -0
- package/knowledge/decisions/security/ai-agent-ownership-failures-never-echo-the-resource.md +23 -0
- package/knowledge/decisions/security/ai-agent-resume-re-runs-the-authorization-gate.md +22 -0
- package/knowledge/decisions/security/ai-agent-sessionless-deployments-have-no-thread-ownership.md +39 -0
- package/knowledge/decisions/security/ai-agent-thread-ownership-composes-the-session-principal.md +30 -0
- package/knowledge/decisions/security/ai-agent-tool-filtering-reads-the-live-function-config.md +24 -0
- package/knowledge/decisions/security/an-empty-owners-constraint-matches-nothing.md +30 -0
- package/knowledge/decisions/security/an-exposed-ungated-function-is-a-codegen-warning.md +49 -0
- package/knowledge/decisions/security/console-addon-privileged-functions-gate-themselves.md +76 -0
- package/knowledge/decisions/security/core-safe-fetch-blocks-ssrf-by-host-literal-not-dns.md +39 -0
- package/knowledge/decisions/security/core-secrets-use-a-per-secret-dek-wrapped-by-a-kek.md +37 -0
- package/knowledge/decisions/security/gateway-handlers-run-through-the-function-runner-gate.md +31 -0
- package/knowledge/decisions/security/gateway-middleware-sessions-must-be-bridged-onto-the-wire.md +30 -0
- package/knowledge/decisions/security/global-permissions-and-function-permissions-are-independent-gates.md +40 -0
- package/knowledge/decisions/security/http-error-detail-is-withheld-from-clients-in-production.md +33 -0
- package/knowledge/decisions/security/http-request-bodies-are-bounded-before-they-are-buffered.md +46 -0
- package/knowledge/decisions/security/index.md +55 -0
- package/knowledge/decisions/security/mcp-internal-error-details-are-double-gated-on-production.md +27 -0
- package/knowledge/decisions/security/passphrases-are-stretched-key-material-is-expanded.md +40 -0
- package/knowledge/decisions/security/permission-auth-filtering-requires-live-permission-functions.md +31 -0
- package/knowledge/decisions/security/pikku-carries-actor-scopes-as-data-and-the-app-grants-them.md +26 -0
- package/knowledge/decisions/security/queue-job-identities-are-signed-at-enqueue.md +69 -0
- package/knowledge/decisions/security/queue-jobs-carry-the-producers-pikku-user-id.md +39 -0
- package/knowledge/decisions/security/remote-addon-tokens-are-client-credentials-not-mesh-trust.md +34 -0
- package/knowledge/decisions/security/scaffold-features-are-authenticated-unless-opted-out.md +49 -0
- package/knowledge/decisions/security/scenario-step-functions-are-never-externally-invocable.md +30 -0
- package/knowledge/decisions/security/scope-resolution-happens-at-the-session-boundary-and-sync-never-deletes.md +28 -0
- package/knowledge/decisions/security/self-authentication-is-declared-not-detected.md +34 -0
- package/knowledge/decisions/security/signed-content-urls-bind-the-request-path.md +37 -0
- package/knowledge/decisions/security/webhook-bodies-are-signed-before-they-are-enqueued.md +25 -0
- package/knowledge/decisions/security/workflow-actor-steps-always-use-the-real-transport.md +34 -0
- package/knowledge/decisions/security/workflow-approval-payloads-are-validated-on-replay-inside-the-workflow.md +40 -0
- package/knowledge/decisions/security/workflow-queued-steps-rehydrate-their-session-from-the-run-wire.md +32 -0
- package/knowledge/decisions/security/workflow-scenario-sessions-are-isolated-per-actor-and-per-scenario.md +32 -0
- package/knowledge/decisions/security/workflow-scenario-steps-are-never-network-invocable.md +31 -0
- package/knowledge/index.md +24 -0
- package/knowledge/questions/index.md +15 -0
- package/package.json +4 -2
- package/run-tests.sh +0 -0
- package/src/crypto-utils.test.ts +460 -19
- package/src/crypto-utils.ts +283 -55
- package/src/data-classification.ts +1 -7
- package/src/dev/hot-reload.test.ts +0 -4
- package/src/dev/hot-reload.ts +11 -30
- package/src/dev/module-runner.ts +7 -32
- package/src/dev/reload-meta.ts +9 -29
- package/src/errors/error-handler.ts +20 -35
- package/src/errors/error.test.ts +30 -1
- package/src/errors/errors.ts +73 -157
- package/src/function/abort-scope.test.ts +97 -0
- package/src/function/abort-scope.ts +80 -0
- package/src/function/function-runner.test.ts +75 -7
- package/src/function/function-runner.ts +73 -30
- package/src/function/functions.types.ts +56 -136
- package/src/function/list.types.test.ts +3 -25
- package/src/function/list.types.ts +12 -62
- package/src/gopass-secrets-removed.test.ts +51 -0
- package/src/handle-error.test.ts +108 -1
- package/src/handle-error.ts +8 -18
- package/src/index.ts +60 -1
- package/src/middleware/auth-apikey.test.ts +0 -1
- package/src/middleware/auth-apikey.ts +0 -17
- package/src/middleware/auth-bearer.test.ts +0 -3
- package/src/middleware/auth-bearer.ts +3 -40
- package/src/middleware/auth-cookie.test.ts +0 -6
- package/src/middleware/auth-cookie.ts +2 -26
- package/src/middleware/cors.test.ts +34 -0
- package/src/middleware/cors.ts +12 -33
- package/src/middleware/remote-auth.test.ts +24 -9
- package/src/middleware/remote-auth.ts +10 -2
- package/src/middleware/telemetry.ts +2 -31
- package/src/middleware-runner.test.ts +0 -2
- package/src/middleware-runner.ts +5 -74
- package/src/permissions.test.ts +30 -0
- package/src/permissions.ts +24 -74
- package/src/pikku-request.ts +0 -6
- package/src/pikku-state.ts +2 -30
- package/src/production-barrels-stay-lean.test.ts +110 -0
- package/src/remote.test.ts +172 -0
- package/src/remote.ts +17 -7
- package/src/schema.test.ts +103 -0
- package/src/schema.ts +35 -18
- package/src/scopes.ts +7 -48
- package/src/services/ai-agent-runner-service.ts +20 -0
- package/src/services/ai-embedding-service.ts +3 -25
- package/src/services/audit-service.ts +1 -2
- package/src/services/content-service.ts +1 -46
- package/src/services/credential-service.ts +3 -40
- package/src/services/credential-wire-service.test.ts +0 -2
- package/src/services/deployment-service.ts +3 -9
- package/src/services/gateway-service.ts +0 -15
- package/src/services/{http-scenario-actors-converse.test.ts → http-personas-converse.test.ts} +38 -9
- package/src/services/{http-scenario-actors.test.ts → http-personas.test.ts} +39 -22
- package/src/services/{http-scenario-actors.ts → http-personas.ts} +85 -45
- package/src/services/in-memory-queue-service.ts +1 -15
- package/src/services/in-memory-trigger-service.ts +1 -18
- package/src/services/in-memory-workflow-service.test.ts +0 -13
- package/src/services/in-memory-workflow-service.ts +4 -38
- package/src/services/index.ts +20 -15
- package/src/services/istanbul-coverage-service.ts +2 -8
- package/src/services/jwt-service.ts +1 -16
- package/src/services/local-content.test.ts +159 -27
- package/src/services/local-content.ts +55 -23
- package/src/services/local-gateway-service.ts +2 -17
- package/src/services/local-secrets.ts +0 -4
- package/src/services/logger-console.test.ts +0 -1
- package/src/services/logger-console.ts +3 -7
- package/src/services/logger.ts +2 -37
- package/src/services/meta-service.test.ts +1 -5
- package/src/services/meta-service.ts +41 -61
- package/src/services/{scenario-actors-service.ts → personas-service.ts} +48 -43
- package/src/services/pikku-user-id.ts +0 -4
- package/src/services/queue-webhook-service.ts +9 -41
- package/src/services/scheduler-service.ts +1 -50
- package/src/services/schema-service.ts +1 -24
- package/src/services/scope-service.ts +50 -34
- package/src/services/scoped-secret-service.ts +0 -4
- package/src/services/secret-host-binding.test.ts +138 -0
- package/src/services/secret-host-binding.ts +51 -0
- package/src/services/secret-service.ts +5 -33
- package/src/services/secretless.test.ts +54 -0
- package/src/services/secretless.ts +29 -0
- package/src/services/stub-tracker.ts +8 -18
- package/src/services/system-role-guard.test.ts +93 -0
- package/src/services/system-role-guard.ts +71 -0
- package/src/services/trigger-service.ts +0 -12
- package/src/services/typed-secret-service.ts +1 -7
- package/src/services/v8-coverage-service.ts +3 -6
- package/src/services/variables-service.ts +1 -8
- package/src/services/webhook-service.ts +19 -63
- package/src/services/workflow-service.ts +3 -20
- package/src/testing/service-tests.ts +0 -26
- package/src/time-utils.ts +1 -19
- package/src/types/core.types.ts +116 -229
- package/src/types/state.types.ts +7 -9
- package/src/utils/hmac.ts +4 -10
- package/src/utils/safe-fetch.ts +13 -54
- package/src/utils.test.ts +11 -2
- package/src/utils.ts +6 -15
- package/src/wirings/actor-flow/actor-flow.types.ts +1 -34
- package/src/wirings/actor-flow/index.ts +0 -9
- package/src/wirings/actor-flow/run-conversation.test.ts +11 -6
- package/src/wirings/actor-flow/run-conversation.ts +19 -12
- package/src/wirings/ai-agent/ai-agent-agui.test.ts +75 -10
- package/src/wirings/ai-agent/ai-agent-agui.ts +36 -17
- package/src/wirings/ai-agent/ai-agent-helpers.ts +20 -0
- package/src/wirings/ai-agent/ai-agent-interrupt.test.ts +842 -0
- package/src/wirings/ai-agent/ai-agent-interrupt.ts +399 -0
- package/src/wirings/ai-agent/ai-agent-memory.ts +0 -2
- package/src/wirings/ai-agent/ai-agent-model-config.ts +1 -9
- package/src/wirings/ai-agent/ai-agent-prepare.test.ts +202 -31
- package/src/wirings/ai-agent/ai-agent-prepare.ts +82 -138
- package/src/wirings/ai-agent/ai-agent-registry.test.ts +191 -6
- package/src/wirings/ai-agent/ai-agent-registry.ts +18 -1
- package/src/wirings/ai-agent/ai-agent-resume-authorization.test.ts +0 -2
- package/src/wirings/ai-agent/ai-agent-runner.test.ts +11 -9
- package/src/wirings/ai-agent/ai-agent-runner.ts +67 -33
- package/src/wirings/ai-agent/ai-agent-stream.test.ts +205 -103
- package/src/wirings/ai-agent/ai-agent-stream.ts +192 -75
- package/src/wirings/ai-agent/ai-agent-thread-ownership.test.ts +301 -0
- package/src/wirings/ai-agent/ai-agent.types.ts +85 -4
- package/src/wirings/ai-agent/index.ts +35 -3
- package/src/wirings/ai-agent/voice-input.test.ts +72 -7
- package/src/wirings/ai-agent/voice-input.ts +48 -3
- package/src/wirings/ai-agent/voice-output.test.ts +422 -0
- package/src/wirings/ai-agent/voice-output.ts +216 -56
- package/src/wirings/channel/channel-common.ts +15 -20
- package/src/wirings/channel/channel-handler.test.ts +50 -0
- package/src/wirings/channel/channel-handler.ts +32 -11
- package/src/wirings/channel/channel-host-rpc.test.ts +150 -0
- package/src/wirings/channel/channel-host-rpc.ts +69 -0
- package/src/wirings/channel/channel-middleware-runner.test.ts +0 -1
- package/src/wirings/channel/channel-middleware-runner.ts +0 -12
- package/src/wirings/channel/channel-rpc-registry.ts +116 -0
- package/src/wirings/channel/channel-rpc-responder.ts +117 -0
- package/src/wirings/channel/channel-rpc-service.ts +146 -0
- package/src/wirings/channel/channel-rpc-validators.ts +65 -0
- package/src/wirings/channel/channel-rpc.test.ts +820 -0
- package/src/wirings/channel/channel-rpc.ts +5 -0
- package/src/wirings/channel/channel-rpc.types.ts +150 -0
- package/src/wirings/channel/channel-runner.ts +0 -14
- package/src/wirings/channel/channel-store.ts +0 -10
- package/src/wirings/channel/channel.types.ts +19 -8
- package/src/wirings/channel/define-channel-routes.ts +0 -20
- package/src/wirings/channel/eventhub-service.ts +0 -18
- package/src/wirings/channel/index.ts +35 -0
- package/src/wirings/channel/local/local-channel-handler.ts +3 -1
- package/src/wirings/channel/local/local-channel-runner.test.ts +0 -10
- package/src/wirings/channel/local/local-channel-runner.ts +3 -1
- package/src/wirings/channel/local/local-eventhub-service.test.ts +0 -13
- package/src/wirings/channel/local/local-eventhub-service.ts +2 -37
- package/src/wirings/channel/log-channels.ts +0 -4
- package/src/wirings/channel/pikku-abstract-channel-handler.test.ts +83 -2
- package/src/wirings/channel/pikku-abstract-channel-handler.ts +7 -0
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +2 -5
- package/src/wirings/cli/channel/cli-approval.test.ts +177 -0
- package/src/wirings/cli/channel/cli-approval.ts +135 -0
- package/src/wirings/cli/channel/cli-channel-runner.ts +4 -26
- package/src/wirings/cli/channel/cli-raw-channel-runner.test.ts +169 -0
- package/src/wirings/cli/channel/cli-raw-channel-runner.ts +59 -16
- package/src/wirings/cli/channel/cli-raw-client-runner.test.ts +480 -0
- package/src/wirings/cli/channel/cli-raw-client-runner.ts +155 -0
- package/src/wirings/cli/channel/index.ts +9 -0
- package/src/wirings/cli/cli-runner.test.ts +0 -1
- package/src/wirings/cli/cli-runner.ts +46 -88
- package/src/wirings/cli/cli.types.ts +14 -3
- package/src/wirings/cli/command-parser.test.ts +0 -4
- package/src/wirings/cli/command-parser.ts +11 -91
- package/src/wirings/cli/define-cli-commands.ts +1 -17
- package/src/wirings/credential/credential.types.ts +0 -12
- package/src/wirings/credential/{wire-credential.ts → define-credential.ts} +7 -7
- package/src/wirings/credential/index.ts +1 -1
- package/src/wirings/credential/validate-credential-definitions.ts +2 -4
- package/src/wirings/gateway/gateway-runner.test.ts +1 -21
- package/src/wirings/gateway/gateway-runner.ts +8 -110
- package/src/wirings/gateway/gateway.types.ts +7 -80
- package/src/wirings/http/http-routes.test.ts +0 -3
- package/src/wirings/http/http-routes.ts +0 -86
- package/src/wirings/http/http-runner.test.ts +0 -1
- package/src/wirings/http/http-runner.ts +12 -168
- package/src/wirings/http/http.types.ts +17 -62
- package/src/wirings/http/index.ts +5 -1
- package/src/wirings/http/log-http-routes.ts +0 -4
- package/src/wirings/http/pikku-fetch-http-request.test.ts +88 -7
- package/src/wirings/http/pikku-fetch-http-request.ts +74 -50
- package/src/wirings/http/pikku-fetch-http-response.test.ts +1 -1
- package/src/wirings/http/pikku-fetch-http-response.ts +0 -3
- package/src/wirings/http/routers/path-to-regex.test.ts +4 -17
- package/src/wirings/http/routers/path-to-regex.ts +2 -13
- package/src/wirings/http/web-request.test.ts +33 -2
- package/src/wirings/http/web-request.ts +30 -17
- package/src/wirings/mcp/mcp-endpoint-registry.test.ts +0 -1
- package/src/wirings/mcp/mcp-runner.test.ts +40 -0
- package/src/wirings/mcp/mcp-runner.ts +9 -15
- package/src/wirings/mcp/mcp.types.ts +7 -42
- package/src/wirings/oauth2/oauth2.types.ts +0 -30
- package/src/wirings/persona/define-personas.ts +29 -0
- package/src/wirings/persona/index.ts +62 -0
- package/src/wirings/persona/persona-email.ts +87 -0
- package/src/wirings/persona/persona-environments.test.ts +183 -0
- package/src/wirings/persona/persona-environments.ts +138 -0
- package/src/wirings/persona/persona-mailbox.ts +156 -0
- package/src/wirings/persona/persona.test.ts +220 -0
- package/src/wirings/persona/persona.types.ts +131 -0
- package/src/wirings/persona/validate-personas.ts +133 -0
- package/src/wirings/queue/index.ts +13 -3
- package/src/wirings/queue/queue-identity.test.ts +453 -0
- package/src/wirings/queue/queue-identity.ts +173 -0
- package/src/wirings/queue/queue-runner.ts +12 -31
- package/src/wirings/queue/queue.types.ts +19 -89
- package/src/wirings/queue/register-queue-helper.ts +0 -14
- package/src/wirings/queue/signed-queue-service.ts +59 -0
- package/src/wirings/queue/validate-worker-config.ts +2 -28
- package/src/wirings/role/define-system-role.ts +33 -0
- package/src/wirings/role/index.ts +13 -0
- package/src/wirings/role/role.test.ts +104 -0
- package/src/wirings/role/role.types.ts +47 -0
- package/src/wirings/role/validate-role-definitions.ts +93 -0
- package/src/wirings/rpc/addon-auth-tags.test.ts +223 -0
- package/src/wirings/rpc/addon-runner.ts +0 -56
- package/src/wirings/rpc/addon-scopes.test.ts +225 -0
- package/src/wirings/rpc/remote-addon-auth.ts +1 -13
- package/src/wirings/rpc/rpc-runner.test.ts +186 -2
- package/src/wirings/rpc/rpc-runner.ts +145 -127
- package/src/wirings/rpc/rpc-types.ts +11 -6
- package/src/wirings/rpc/wire-addon.test.ts +43 -1
- package/src/wirings/rpc/wire-addon.ts +99 -0
- package/src/wirings/rpc/wire-remote-addon.ts +9 -29
- package/src/wirings/scheduler/log-schedulers.ts +0 -4
- package/src/wirings/scheduler/scheduler-runner.test.ts +1 -8
- package/src/wirings/scheduler/scheduler-runner.ts +0 -2
- package/src/wirings/scheduler/scheduler.types.ts +1 -14
- package/src/wirings/scope/{wire-scope.ts → define-scope.ts} +5 -6
- package/src/wirings/scope/index.ts +1 -1
- package/src/wirings/scope/scope.test.ts +1 -2
- package/src/wirings/scope/scope.types.ts +7 -9
- package/src/wirings/scope/validate-scope-definitions.ts +3 -21
- package/src/wirings/secret/index.ts +1 -1
- package/src/wirings/secret/secret.types.ts +19 -15
- package/src/wirings/secret/validate-secret-definitions.ts +2 -4
- package/src/wirings/trigger/trigger-runner.ts +1 -27
- package/src/wirings/trigger/trigger.types.ts +1 -82
- package/src/wirings/variable/index.ts +1 -1
- package/src/wirings/variable/validate-variable-definitions.ts +2 -4
- package/src/wirings/variable/variable.types.ts +1 -13
- package/src/wirings/virtual-user/index.ts +76 -0
- package/src/wirings/virtual-user/run-virtual-user.test.ts +765 -0
- package/src/wirings/virtual-user/run-virtual-user.ts +671 -0
- package/src/wirings/virtual-user/virtual-user-agents.test.ts +65 -0
- package/src/wirings/virtual-user/virtual-user-agents.ts +57 -0
- package/src/wirings/virtual-user/virtual-user-catalogue.test.ts +215 -0
- package/src/wirings/virtual-user/virtual-user-catalogue.ts +184 -0
- package/src/wirings/virtual-user/virtual-user-derive.test.ts +398 -0
- package/src/wirings/virtual-user/virtual-user-derive.ts +173 -0
- package/src/wirings/virtual-user/virtual-user-dispositions.test.ts +63 -0
- package/src/wirings/virtual-user/virtual-user-dispositions.ts +213 -0
- package/src/wirings/virtual-user/virtual-user-intents.test.ts +208 -0
- package/src/wirings/virtual-user/virtual-user-intents.ts +185 -0
- package/src/wirings/virtual-user/virtual-user-rng.test.ts +72 -0
- package/src/wirings/virtual-user/virtual-user-rng.ts +50 -0
- package/src/wirings/virtual-user/virtual-user-target.ts +47 -0
- package/src/wirings/virtual-user/virtual-user.types.ts +219 -0
- package/src/wirings/workflow/dsl/workflow-dsl.types.ts +5 -4
- package/src/wirings/workflow/dsl/workflow-runner.ts +0 -4
- package/src/wirings/workflow/feature.ts +0 -19
- package/src/wirings/workflow/graph/graph-node.ts +0 -136
- package/src/wirings/workflow/graph/graph-runner.test.ts +20 -19
- package/src/wirings/workflow/graph/graph-runner.ts +6 -41
- package/src/wirings/workflow/graph/wire-workflow-graph.ts +0 -4
- package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -58
- package/src/wirings/workflow/index.ts +10 -44
- package/src/wirings/workflow/pikku-scenario-service.ts +235 -52
- package/src/wirings/workflow/pikku-workflow-service.test.ts +0 -39
- package/src/wirings/workflow/pikku-workflow-service.ts +77 -674
- package/src/wirings/workflow/run-timeline.test.ts +7 -19
- package/src/wirings/workflow/run-timeline.ts +0 -56
- package/src/wirings/workflow/scenario-cookie-jar.test.ts +0 -1
- package/src/wirings/workflow/scenario-cookie-jar.ts +0 -25
- package/src/wirings/workflow/scenario-expectations.test.ts +2 -7
- package/src/wirings/workflow/scenario-hooks.test.ts +2 -7
- package/src/wirings/workflow/scenario-poll.test.ts +0 -2
- package/src/wirings/workflow/scenario-poll.ts +0 -15
- package/src/wirings/workflow/scenario-prose.ts +0 -28
- package/src/wirings/workflow/scenario-service.test.ts +2 -9
- package/src/wirings/workflow/scenario-step-guards.ts +1 -14
- package/src/wirings/workflow/scenario-step.test.ts +159 -14
- package/src/wirings/workflow/scenario-step.types.ts +82 -6
- package/src/wirings/workflow/scenario-surface.test.ts +145 -0
- package/src/wirings/workflow/scenario-surface.ts +71 -0
- package/src/wirings/workflow/workflow-dispatch-durability.test.ts +14 -15
- package/src/wirings/workflow/workflow-dispatch-payload.test.ts +0 -4
- package/src/wirings/workflow/workflow-inline-authority.test.ts +169 -0
- package/src/wirings/workflow/workflow-invocation-id.test.ts +0 -2
- package/src/wirings/workflow/workflow-invocation-id.ts +2 -22
- package/src/wirings/workflow/workflow-mirror.test.ts +0 -7
- package/src/wirings/workflow/workflow-on-error.test.ts +0 -9
- package/src/wirings/workflow/workflow-queue-workers.ts +0 -21
- package/src/wirings/workflow/workflow-replay-snapshot.test.ts +8 -7
- package/src/wirings/workflow/workflow-retry-policy.test.ts +0 -5
- package/src/wirings/workflow/workflow-run-context.test.ts +5 -10
- package/src/wirings/workflow/workflow-run-polling.test.ts +0 -5
- package/src/wirings/workflow/workflow-step-ordinal.test.ts +19 -4
- package/src/wirings/workflow/workflow-step-session.test.ts +0 -7
- package/src/wirings/workflow/workflow.types.ts +0 -203
- package/tsconfig.tsbuildinfo +1 -1
- package/src/middleware/timeout.ts +0 -22
- package/src/pikku-response.ts +0 -5
- package/src/services/gopass-secrets.ts +0 -78
- package/src/wirings/mcp/mcp-endpoint-registry.test.d.ts +0 -1
- package/src/wirings/workflow/dsl/index.ts +0 -36
- package/src/wirings/workflow/graph/index.ts +0 -15
|
@@ -1,33 +1,10 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Interface for a schema service that handles schema compilation, validation, and management.
|
|
3
|
-
*/
|
|
4
1
|
export interface SchemaService {
|
|
5
|
-
/**
|
|
6
|
-
* Compiles a schema with the provided name and value, making it available for use.
|
|
7
|
-
* @param {string} name - The unique name for the schema.
|
|
8
|
-
* @param {any} value - The schema definition or configuration to be compiled.
|
|
9
|
-
* @returns {Promise<void> | void} A promise if asynchronous, or void if synchronous.
|
|
10
|
-
*/
|
|
11
2
|
compileSchema: (name: string, value: any) => Promise<void> | void
|
|
12
3
|
|
|
13
|
-
/**
|
|
14
|
-
* Validates data against a specified schema.
|
|
15
|
-
* @param {string} schema - The name of the schema to validate against.
|
|
16
|
-
* @param {any} data - The data to validate against the schema.
|
|
17
|
-
* @returns {Promise<void> | void} A promise if asynchronous, or void if synchronous.
|
|
18
|
-
*/
|
|
19
4
|
validateSchema: (schema: string, data: any) => Promise<void> | void
|
|
20
5
|
|
|
21
|
-
/**
|
|
22
|
-
* Retrieves a set of all registered schema names.
|
|
23
|
-
* @returns {Set<string>} A set containing the names of all available schemas.
|
|
24
|
-
*/
|
|
25
6
|
getSchemaNames: () => Set<string>
|
|
26
7
|
|
|
27
|
-
/**
|
|
28
|
-
* Retrieves the property keys from a compiled JSON schema.
|
|
29
|
-
* @param {string} schemaName - The name of the schema.
|
|
30
|
-
* @returns {string[]} An array of property keys, or empty array if schema not found.
|
|
31
|
-
*/
|
|
8
|
+
/** Empty when the schema is not registered. */
|
|
32
9
|
getSchemaKeys: (schemaName: string) => string[]
|
|
33
10
|
}
|
|
@@ -1,49 +1,62 @@
|
|
|
1
1
|
import type { FlatScope } from '../wirings/scope/scope.types.js'
|
|
2
|
+
import type { SystemRole } from '../wirings/role/role.types.js'
|
|
2
3
|
|
|
3
|
-
/** A role: a named, admin-composed bag of scopes. */
|
|
4
4
|
export interface Role {
|
|
5
5
|
name: string
|
|
6
6
|
description?: string
|
|
7
7
|
scopes: string[]
|
|
8
|
+
/**
|
|
9
|
+
* True when the role was declared in code with `defineSystemRole` rather
|
|
10
|
+
* than composed by an admin. System roles may be granted, but not renamed,
|
|
11
|
+
* re-scoped or deleted — see {@link ScopeService.syncSystemRoles}.
|
|
12
|
+
*/
|
|
13
|
+
system?: boolean
|
|
14
|
+
/**
|
|
15
|
+
* False when a system role's declaration has been removed from code but its
|
|
16
|
+
* row survives: still held by whoever holds it, no longer offered for new
|
|
17
|
+
* grants, awaiting `pikku roles prune`.
|
|
18
|
+
*/
|
|
19
|
+
declared?: boolean
|
|
8
20
|
}
|
|
9
21
|
|
|
10
|
-
|
|
11
|
-
* Resolves and administers the scopes granted to a user.
|
|
12
|
-
*
|
|
13
|
-
* Implementations are called at the **session boundary** — e.g. better-auth's
|
|
14
|
-
* `mapSession` — never by the function runner. The runner reads
|
|
15
|
-
* `session.scopes` and never performs I/O, which keeps it viable on Workers
|
|
16
|
-
* and Lambda. Because the session is rebuilt per request, a scope change takes
|
|
17
|
-
* effect on the next call with nothing cached and nothing to invalidate.
|
|
18
|
-
*
|
|
19
|
-
* `syncScopes` is deliberately additive: scopes are declared in code, so a
|
|
20
|
-
* removed declaration leaves an inert row rather than silently revoking a
|
|
21
|
-
* grant mid-deploy. Removal is an explicit operation (`pikku scopes prune`).
|
|
22
|
-
*/
|
|
22
|
+
// knowledge: decisions/security/scope-resolution-happens-at-the-session-boundary-and-sync-never-deletes.md
|
|
23
23
|
export interface ScopeService {
|
|
24
|
-
/**
|
|
25
|
-
* Registers the declared scope set. Additive — never deletes.
|
|
26
|
-
* Called once during startup with the generated scope list.
|
|
27
|
-
*/
|
|
28
24
|
syncScopes(scopes: FlatScope[]): Promise<void>
|
|
29
25
|
|
|
26
|
+
/** The union of role-derived scopes and scopes granted directly. */
|
|
27
|
+
resolveScopes(userId: string): Promise<string[]>
|
|
28
|
+
|
|
30
29
|
/**
|
|
31
|
-
*
|
|
32
|
-
*
|
|
30
|
+
* The whole vocabulary a role can be composed from. `declared: false` marks a
|
|
31
|
+
* scope still in the store but no longer declared in code: inert, since no
|
|
32
|
+
* function can require it, and awaiting `pikku scopes prune`.
|
|
33
33
|
*/
|
|
34
|
-
|
|
34
|
+
listScopes(): Promise<Array<FlatScope & { declared: boolean }>>
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
|
-
*
|
|
37
|
+
* Registers the roles declared with `defineSystemRole`. Additive on the same
|
|
38
|
+
* terms as {@link syncScopes}: a removed declaration leaves the row in place,
|
|
39
|
+
* marked `declared: false`, rather than revoking everyone's grant on deploy.
|
|
40
|
+
*
|
|
41
|
+
* A role's scope set *is* re-synced, because that is the declaration's whole
|
|
42
|
+
* content — editing `defineSystemRole` is how you change what a system role
|
|
43
|
+
* means, and the deploy is when it takes effect.
|
|
38
44
|
*
|
|
39
|
-
*
|
|
40
|
-
* declared in code — inert (no function can require it) and awaiting
|
|
41
|
-
* `pikku scopes prune`.
|
|
45
|
+
* Called once during startup with the generated role list.
|
|
42
46
|
*/
|
|
43
|
-
|
|
47
|
+
syncSystemRoles(roles: SystemRole[]): Promise<void>
|
|
44
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Creates an admin-composed role.
|
|
51
|
+
*
|
|
52
|
+
* Must throw {@link SystemRoleShadowedError} when `role.name` matches a
|
|
53
|
+
* declared system role. Two rows answering to one name make "does this user
|
|
54
|
+
* hold `buyer`?" depend on which the store returns first.
|
|
55
|
+
*/
|
|
45
56
|
createRole(role: Role): Promise<void>
|
|
57
|
+
/** Must throw {@link SystemRoleImmutableError} for a system role. */
|
|
46
58
|
deleteRole(name: string): Promise<void>
|
|
59
|
+
/** Must throw {@link SystemRoleImmutableError} for a system role. */
|
|
47
60
|
setRoleScopes(name: string, scopes: string[]): Promise<void>
|
|
48
61
|
listRoles(): Promise<Role[]>
|
|
49
62
|
|
|
@@ -51,10 +64,7 @@ export interface ScopeService {
|
|
|
51
64
|
removeUserFromRole(userId: string, role: string): Promise<void>
|
|
52
65
|
listUserRoles(userId: string): Promise<string[]>
|
|
53
66
|
|
|
54
|
-
/**
|
|
55
|
-
* Grants a scope directly to a user, outside of any role. Additive: the
|
|
56
|
-
* resolved set is the union of role-derived and directly-granted scopes.
|
|
57
|
-
*/
|
|
67
|
+
/** Grants outside of any role; additive with the user's role-derived scopes. */
|
|
58
68
|
addScopeToUser(
|
|
59
69
|
userId: string,
|
|
60
70
|
scope: string,
|
|
@@ -64,12 +74,18 @@ export interface ScopeService {
|
|
|
64
74
|
/** Only the scopes granted directly, not those inherited from roles. */
|
|
65
75
|
listUserScopes(userId: string): Promise<string[]>
|
|
66
76
|
|
|
67
|
-
/**
|
|
68
|
-
* Scopes present in the store that are no longer declared in code, with the
|
|
69
|
-
* roles that would lose them. Powers `pikku scopes audit`.
|
|
70
|
-
*/
|
|
77
|
+
/** Undeclared scopes with the roles that would lose them; powers `pikku scopes audit`. */
|
|
71
78
|
findStaleScopes(): Promise<Array<{ scope: string; roles: string[] }>>
|
|
72
79
|
|
|
73
80
|
/** Removes undeclared scopes, cascading them out of roles. */
|
|
74
81
|
pruneScopes(): Promise<string[]>
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* System roles in the store whose declaration has gone, with the number of
|
|
85
|
+
* users still holding each. Powers `pikku roles audit`.
|
|
86
|
+
*/
|
|
87
|
+
findStaleSystemRoles(): Promise<Array<{ role: string; users: number }>>
|
|
88
|
+
|
|
89
|
+
/** Removes undeclared system roles, cascading them out of user grants. */
|
|
90
|
+
pruneSystemRoles(): Promise<string[]>
|
|
75
91
|
}
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import type { SecretService } from './secret-service.js'
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* A read-only wrapper around SecretService that restricts access
|
|
5
|
-
* to only a defined set of allowed secret keys.
|
|
6
|
-
*/
|
|
7
3
|
export class ScopedSecretService implements SecretService {
|
|
8
4
|
constructor(
|
|
9
5
|
private secrets: SecretService,
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { describe, test } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import {
|
|
4
|
+
SecretHostNotAllowedError,
|
|
5
|
+
assertSecretAllowedForHost,
|
|
6
|
+
} from './secret-host-binding.js'
|
|
7
|
+
import type { SecretDefinitionsMeta } from '../wirings/secret/secret.types.js'
|
|
8
|
+
|
|
9
|
+
const definitions: SecretDefinitionsMeta = {
|
|
10
|
+
notion: {
|
|
11
|
+
name: 'notion',
|
|
12
|
+
displayName: 'Notion',
|
|
13
|
+
secretId: 'NOTION_KEY',
|
|
14
|
+
allowedHosts: ['api.notion.com'],
|
|
15
|
+
},
|
|
16
|
+
stripe: {
|
|
17
|
+
name: 'stripe',
|
|
18
|
+
displayName: 'Stripe',
|
|
19
|
+
secretId: 'STRIPE_KEY',
|
|
20
|
+
allowedHosts: ['*.stripe.com'],
|
|
21
|
+
},
|
|
22
|
+
legacy: {
|
|
23
|
+
name: 'legacy',
|
|
24
|
+
displayName: 'Legacy',
|
|
25
|
+
secretId: 'LEGACY_KEY',
|
|
26
|
+
},
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
describe('assertSecretAllowedForHost', () => {
|
|
30
|
+
test('allows a declared host', () => {
|
|
31
|
+
assertSecretAllowedForHost(
|
|
32
|
+
'NOTION_KEY',
|
|
33
|
+
'https://api.notion.com/v1/pages',
|
|
34
|
+
definitions
|
|
35
|
+
)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
test('refuses a host the secret was not declared for', () => {
|
|
39
|
+
assert.throws(
|
|
40
|
+
() =>
|
|
41
|
+
assertSecretAllowedForHost(
|
|
42
|
+
'NOTION_KEY',
|
|
43
|
+
'https://attacker.test/collect',
|
|
44
|
+
definitions
|
|
45
|
+
),
|
|
46
|
+
SecretHostNotAllowedError
|
|
47
|
+
)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
test('never puts the secret value in the message', () => {
|
|
51
|
+
assert.throws(
|
|
52
|
+
() =>
|
|
53
|
+
assertSecretAllowedForHost(
|
|
54
|
+
'NOTION_KEY',
|
|
55
|
+
'https://attacker.test/',
|
|
56
|
+
definitions
|
|
57
|
+
),
|
|
58
|
+
(error: Error) =>
|
|
59
|
+
error.message.includes('NOTION_KEY') &&
|
|
60
|
+
error.message.includes('attacker.test')
|
|
61
|
+
)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
test('matches a subdomain wildcard', () => {
|
|
65
|
+
assertSecretAllowedForHost(
|
|
66
|
+
'STRIPE_KEY',
|
|
67
|
+
'https://api.stripe.com/v1/charges',
|
|
68
|
+
definitions
|
|
69
|
+
)
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
test('anchors the wildcard on a dot, so a suffix lookalike is refused', () => {
|
|
73
|
+
assert.throws(
|
|
74
|
+
() =>
|
|
75
|
+
assertSecretAllowedForHost(
|
|
76
|
+
'STRIPE_KEY',
|
|
77
|
+
'https://stripe.com.attacker.test/',
|
|
78
|
+
definitions
|
|
79
|
+
),
|
|
80
|
+
SecretHostNotAllowedError
|
|
81
|
+
)
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
test('a bare domain does not match its own subdomain wildcard', () => {
|
|
85
|
+
assert.throws(
|
|
86
|
+
() =>
|
|
87
|
+
assertSecretAllowedForHost(
|
|
88
|
+
'STRIPE_KEY',
|
|
89
|
+
'https://stripe.com/',
|
|
90
|
+
definitions
|
|
91
|
+
),
|
|
92
|
+
SecretHostNotAllowedError
|
|
93
|
+
)
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
test('is case insensitive on the host', () => {
|
|
97
|
+
assertSecretAllowedForHost(
|
|
98
|
+
'NOTION_KEY',
|
|
99
|
+
'https://API.NOTION.COM/v1',
|
|
100
|
+
definitions
|
|
101
|
+
)
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
test('an undeclared secret is unrestricted by default', () => {
|
|
105
|
+
assertSecretAllowedForHost(
|
|
106
|
+
'LEGACY_KEY',
|
|
107
|
+
'https://anywhere.test/',
|
|
108
|
+
definitions
|
|
109
|
+
)
|
|
110
|
+
assertSecretAllowedForHost(
|
|
111
|
+
'UNKNOWN_KEY',
|
|
112
|
+
'https://anywhere.test/',
|
|
113
|
+
definitions
|
|
114
|
+
)
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
test('requireAllowedHosts refuses a secret that declares none', () => {
|
|
118
|
+
assert.throws(
|
|
119
|
+
() =>
|
|
120
|
+
assertSecretAllowedForHost(
|
|
121
|
+
'LEGACY_KEY',
|
|
122
|
+
'https://anywhere.test/',
|
|
123
|
+
definitions,
|
|
124
|
+
true
|
|
125
|
+
),
|
|
126
|
+
SecretHostNotAllowedError
|
|
127
|
+
)
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
test('requireAllowedHosts still allows a declared pairing', () => {
|
|
131
|
+
assertSecretAllowedForHost(
|
|
132
|
+
'NOTION_KEY',
|
|
133
|
+
'https://api.notion.com/v1',
|
|
134
|
+
definitions,
|
|
135
|
+
true
|
|
136
|
+
)
|
|
137
|
+
})
|
|
138
|
+
})
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { SecretDefinitionsMeta } from '../wirings/secret/secret.types.js'
|
|
2
|
+
|
|
3
|
+
export class SecretHostNotAllowedError extends Error {
|
|
4
|
+
constructor(
|
|
5
|
+
public readonly secretId: string,
|
|
6
|
+
public readonly host: string,
|
|
7
|
+
allowedHosts: string[] | undefined
|
|
8
|
+
) {
|
|
9
|
+
super(
|
|
10
|
+
allowedHosts?.length
|
|
11
|
+
? `Secret '${secretId}' may not be sent to '${host}' — it is declared for ${allowedHosts.map((h) => `'${h}'`).join(', ')}. Add the host to allowedHosts on its defineSecret if this is intended.`
|
|
12
|
+
: `Secret '${secretId}' has no allowedHosts and this project requires one. Declare the hosts it may be sent to on its defineSecret.`
|
|
13
|
+
)
|
|
14
|
+
this.name = 'SecretHostNotAllowedError'
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Exact match, or a single leading `*.` wildcard anchored on a dot. */
|
|
19
|
+
const hostMatches = (host: string, pattern: string): boolean => {
|
|
20
|
+
const h = host.toLowerCase()
|
|
21
|
+
const p = pattern.toLowerCase()
|
|
22
|
+
if (p.startsWith('*.')) {
|
|
23
|
+
return h.endsWith(p.slice(1)) && h.length > p.length - 1
|
|
24
|
+
}
|
|
25
|
+
return h === p
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Refuses a secret/host pairing the declarations do not permit. */
|
|
29
|
+
export const assertSecretAllowedForHost = (
|
|
30
|
+
secretId: string,
|
|
31
|
+
url: string | URL,
|
|
32
|
+
secretDefinitions: SecretDefinitionsMeta | undefined,
|
|
33
|
+
requireAllowedHosts = false
|
|
34
|
+
): void => {
|
|
35
|
+
const host = (typeof url === 'string' ? new URL(url) : url).hostname
|
|
36
|
+
const definition = Object.values(secretDefinitions ?? {}).find(
|
|
37
|
+
(d) => d.secretId === secretId
|
|
38
|
+
)
|
|
39
|
+
const allowedHosts = definition?.allowedHosts
|
|
40
|
+
|
|
41
|
+
if (!allowedHosts?.length) {
|
|
42
|
+
if (requireAllowedHosts) {
|
|
43
|
+
throw new SecretHostNotAllowedError(secretId, host, allowedHosts)
|
|
44
|
+
}
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!allowedHosts.some((pattern) => hostMatches(host, pattern))) {
|
|
49
|
+
throw new SecretHostNotAllowedError(secretId, host, allowedHosts)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -1,42 +1,14 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Interface for retrieving and managing secrets.
|
|
3
|
-
*/
|
|
4
1
|
export interface SecretService {
|
|
5
|
-
/**
|
|
6
|
-
* Retrieves a secret by key, typed as T (defaults to string).
|
|
7
|
-
* @param key - The key of the secret to retrieve.
|
|
8
|
-
* @returns A promise that resolves to the secret value.
|
|
9
|
-
* @throws If the secret is not found.
|
|
10
|
-
*/
|
|
2
|
+
/** Throws if the secret is not found. */
|
|
11
3
|
getSecret<T = string>(key: string): Promise<T>
|
|
12
|
-
/**
|
|
13
|
-
* Checks if a secret exists without throwing.
|
|
14
|
-
* @param key - The key of the secret to check.
|
|
15
|
-
* @returns A promise that resolves to true if the secret exists, false otherwise.
|
|
16
|
-
*/
|
|
4
|
+
/** Answers for any key, including a disallowed one — it must not throw. */
|
|
17
5
|
hasSecret(key: string): Promise<boolean>
|
|
18
|
-
/**
|
|
19
|
-
* Stores a secret value.
|
|
20
|
-
* @param key - The key to store the secret under.
|
|
21
|
-
* @param value - The value to store.
|
|
22
|
-
* @returns A promise that resolves when the secret is stored.
|
|
23
|
-
*/
|
|
24
6
|
setSecret(key: string, value: unknown): Promise<void>
|
|
25
|
-
/**
|
|
26
|
-
* Deletes a secret by key.
|
|
27
|
-
* @param key - The key of the secret to delete.
|
|
28
|
-
* @returns A promise that resolves when the secret is deleted.
|
|
29
|
-
*/
|
|
30
7
|
deleteSecret(key: string): Promise<void>
|
|
31
8
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* `Partial<T>` and callers must handle keys that may be absent at runtime.
|
|
36
|
-
*
|
|
37
|
-
* Pass a shape as `T` to get a typed result without casting, e.g.
|
|
38
|
-
* `await secrets.getSecrets<{ FOO: string; BAR: { id: string } }>(['FOO', 'BAR'])`.
|
|
39
|
-
* @param keys - The keys of the secrets to retrieve.
|
|
9
|
+
* Missing keys are omitted rather than throwing, hence `Partial<T>`: callers
|
|
10
|
+
* must handle keys absent at runtime. Pass a shape as `T` to avoid casting,
|
|
11
|
+
* e.g. `getSecrets<{ FOO: string; BAR: { id: string } }>(['FOO', 'BAR'])`.
|
|
40
12
|
*/
|
|
41
13
|
getSecrets<T extends Record<string, unknown> = Record<string, unknown>>(
|
|
42
14
|
keys: (keyof T & string)[]
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { describe, test } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import { SecretAccessDeniedError, withoutSecrets } from './secretless.js'
|
|
4
|
+
|
|
5
|
+
const services = () => ({
|
|
6
|
+
logger: { info: () => {} },
|
|
7
|
+
secrets: { getSecret: async () => 'super-secret' },
|
|
8
|
+
db: { query: async () => [] },
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
describe('withoutSecrets', () => {
|
|
12
|
+
test('throws when secrets is read', () => {
|
|
13
|
+
const stripped = withoutSecrets(services(), 'a pikku function') as any
|
|
14
|
+
assert.throws(() => stripped.secrets, SecretAccessDeniedError)
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
test('throws when secrets is destructured, at the point of the mistake', () => {
|
|
18
|
+
const stripped = withoutSecrets(services(), 'a pikku function') as any
|
|
19
|
+
assert.throws(() => {
|
|
20
|
+
const { secrets } = stripped
|
|
21
|
+
return secrets
|
|
22
|
+
}, SecretAccessDeniedError)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
test('names the context so the message points somewhere', () => {
|
|
26
|
+
const stripped = withoutSecrets(services(), 'a permission') as any
|
|
27
|
+
assert.throws(
|
|
28
|
+
() => stripped.secrets,
|
|
29
|
+
(error: Error) => error.message.includes('a permission')
|
|
30
|
+
)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
test('leaves every other service reachable', () => {
|
|
34
|
+
const stripped = withoutSecrets(services(), 'a pikku function')
|
|
35
|
+
assert.ok(stripped.logger)
|
|
36
|
+
assert.ok(stripped.db)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
test('does not mutate the original services object', async () => {
|
|
40
|
+
const original = services()
|
|
41
|
+
withoutSecrets(original, 'a pikku function')
|
|
42
|
+
assert.equal(await original.secrets.getSecret(), 'super-secret')
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
test('is a no-op when there is no secrets service', () => {
|
|
46
|
+
const bare = { logger: {} }
|
|
47
|
+
assert.equal(withoutSecrets(bare, 'a pikku function'), bare)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
test('does not leak the value through spreading', () => {
|
|
51
|
+
const stripped = withoutSecrets(services(), 'a pikku function')
|
|
52
|
+
assert.equal('secrets' in { ...stripped }, false)
|
|
53
|
+
})
|
|
54
|
+
})
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { SecretlessServices } from '../types/core.types.js'
|
|
2
|
+
|
|
3
|
+
export class SecretAccessDeniedError extends Error {
|
|
4
|
+
constructor(context: string) {
|
|
5
|
+
super(
|
|
6
|
+
`'secrets' is not available inside ${context}. SecretService is confined to pikkuServices, pikkuWireServices, addon service factories and middleware — give a service the secret when you construct it and ask that service here.`
|
|
7
|
+
)
|
|
8
|
+
this.name = 'SecretAccessDeniedError'
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Returns `services` with `secrets` replaced by a throwing accessor. */
|
|
13
|
+
export const withoutSecrets = <T extends object>(
|
|
14
|
+
services: T,
|
|
15
|
+
context: string
|
|
16
|
+
): SecretlessServices<T> => {
|
|
17
|
+
if (!('secrets' in services)) {
|
|
18
|
+
return services as SecretlessServices<T>
|
|
19
|
+
}
|
|
20
|
+
const stripped = { ...services } as Record<string, unknown>
|
|
21
|
+
Object.defineProperty(stripped, 'secrets', {
|
|
22
|
+
get() {
|
|
23
|
+
throw new SecretAccessDeniedError(context)
|
|
24
|
+
},
|
|
25
|
+
configurable: true,
|
|
26
|
+
enumerable: false,
|
|
27
|
+
})
|
|
28
|
+
return stripped as SecretlessServices<T>
|
|
29
|
+
}
|
|
@@ -3,10 +3,9 @@ export type StubCall = { service: string; method: string; args: unknown[] }
|
|
|
3
3
|
type Call = { method: string; args: unknown[]; verified: boolean }
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* Services never touched by an assertion stay lenient.
|
|
6
|
+
* Strict per service: once a scenario asserts any call on a service, every
|
|
7
|
+
* recorded call on it must be verified by the end of the scenario or the After
|
|
8
|
+
* hook fails. A service no assertion ever touched stays lenient.
|
|
10
9
|
*/
|
|
11
10
|
export class StubTracker {
|
|
12
11
|
private readonly calls = new Map<string, Call[]>()
|
|
@@ -123,16 +122,11 @@ export class StubTracker {
|
|
|
123
122
|
}
|
|
124
123
|
}
|
|
125
124
|
|
|
126
|
-
/**
|
|
127
|
-
* Creates a Proxy suitable for passing as `existingServices` to
|
|
128
|
-
* `createSingletonServices`. Every property returns `tracker.stub(prop)`
|
|
129
|
-
* EXCEPT `schema`, which returns `undefined` so the service factory creates
|
|
130
|
-
* a real schema service. Stubbing the schema makes validation a no-op —
|
|
131
|
-
* required fields pass silently and tests validate nothing.
|
|
132
|
-
*/
|
|
125
|
+
/** Pass as `existingServices` to `createSingletonServices`. */
|
|
133
126
|
export function createStubProxy(tracker: StubTracker): Record<string, unknown> {
|
|
134
127
|
return new Proxy({} as Record<string, unknown>, {
|
|
135
128
|
get(_, prop: string) {
|
|
129
|
+
// knowledge: decisions/internals/the-schema-service-is-never-stubbed.md
|
|
136
130
|
if (prop === 'schema') return undefined
|
|
137
131
|
return tracker.stub(prop)
|
|
138
132
|
},
|
|
@@ -141,19 +135,15 @@ export function createStubProxy(tracker: StubTracker): Record<string, unknown> {
|
|
|
141
135
|
|
|
142
136
|
const defaultStubTracker = new StubTracker()
|
|
143
137
|
|
|
144
|
-
/** The process-wide tracker
|
|
138
|
+
/** The process-wide tracker `stub()`/`spy()` record into; read by the console's getStubCalls/resetStubs RPCs. */
|
|
145
139
|
export const getStubTracker = (): StubTracker => defaultStubTracker
|
|
146
140
|
|
|
147
|
-
/** True when the server was started by `pikku dev --test
|
|
141
|
+
/** True when the server was started by `pikku dev --test`, which sets PIKKU_TEST_RUN. */
|
|
148
142
|
export const isTestRun = (): boolean =>
|
|
149
143
|
(globalThis as { process?: { env?: Record<string, string | undefined> } })
|
|
150
144
|
.process?.env?.PIKKU_TEST_RUN === 'true'
|
|
151
145
|
|
|
152
|
-
/**
|
|
153
|
-
* Creates a recording fake for a service. Methods present on `impl` run and
|
|
154
|
-
* their result is returned; missing methods resolve `undefined`. Every call
|
|
155
|
-
* is recorded so scenarios can assert via workflow.expectService().
|
|
156
|
-
*/
|
|
146
|
+
/** Methods on `impl` run and return; every other method resolves `undefined`. */
|
|
157
147
|
export function stub<T = any>(service: string, impl?: Partial<T>): T {
|
|
158
148
|
return new Proxy((impl ?? {}) as object, {
|
|
159
149
|
get(target: any, method: string | symbol) {
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { describe, test } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
assertRoleIsMutable,
|
|
6
|
+
assertRoleNameAvailable,
|
|
7
|
+
roleLockReason,
|
|
8
|
+
} from './system-role-guard.js'
|
|
9
|
+
import {
|
|
10
|
+
SystemRoleImmutableError,
|
|
11
|
+
SystemRoleShadowedError,
|
|
12
|
+
} from '../errors/errors.js'
|
|
13
|
+
|
|
14
|
+
const system = (...names: string[]) => (name: string) => names.includes(name)
|
|
15
|
+
|
|
16
|
+
describe('mutating a role', () => {
|
|
17
|
+
test('a declared role refuses to be deleted or re-scoped', async () => {
|
|
18
|
+
await assert.rejects(
|
|
19
|
+
() => assertRoleIsMutable('buyer', system('buyer'), 'delete role'),
|
|
20
|
+
SystemRoleImmutableError
|
|
21
|
+
)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
test('the refusal says which role and what was attempted', async () => {
|
|
25
|
+
await assert.rejects(
|
|
26
|
+
() => assertRoleIsMutable('buyer', system('buyer'), 'set scopes on'),
|
|
27
|
+
/Cannot set scopes on 'buyer'[\s\S]*defineSystemRole/
|
|
28
|
+
)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test('a custom role is left alone', async () => {
|
|
32
|
+
await assert.doesNotReject(() =>
|
|
33
|
+
assertRoleIsMutable('invoicing-clerk', system('buyer'), 'delete role')
|
|
34
|
+
)
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
test('an async lookup is awaited, not truthy-tested', async () => {
|
|
38
|
+
await assert.rejects(
|
|
39
|
+
() => assertRoleIsMutable('buyer', async () => true, 'delete role'),
|
|
40
|
+
SystemRoleImmutableError
|
|
41
|
+
)
|
|
42
|
+
// A promise resolving to false is itself truthy — the guard must await it
|
|
43
|
+
// rather than treat the promise as the answer.
|
|
44
|
+
await assert.doesNotReject(() =>
|
|
45
|
+
assertRoleIsMutable('buyer', async () => false, 'delete role')
|
|
46
|
+
)
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
describe('creating a role', () => {
|
|
51
|
+
test('shadowing a declared name is refused', async () => {
|
|
52
|
+
await assert.rejects(
|
|
53
|
+
() => assertRoleNameAvailable('buyer', system('buyer')),
|
|
54
|
+
SystemRoleShadowedError
|
|
55
|
+
)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
test('an unused name is allowed', async () => {
|
|
59
|
+
await assert.doesNotReject(() =>
|
|
60
|
+
assertRoleNameAvailable('invoicing-clerk', system('buyer'))
|
|
61
|
+
)
|
|
62
|
+
})
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
describe('what the console renders', () => {
|
|
66
|
+
test('a custom role has no lock', () => {
|
|
67
|
+
assert.equal(roleLockReason({ name: 'clerk', scopes: [] }), null)
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
test('a declared role locks with the reason and the fix', () => {
|
|
71
|
+
const reason = roleLockReason({
|
|
72
|
+
name: 'buyer',
|
|
73
|
+
scopes: [],
|
|
74
|
+
system: true,
|
|
75
|
+
declared: true,
|
|
76
|
+
})
|
|
77
|
+
assert.match(reason!, /declared in code with defineSystemRole/)
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
// An undeclared system role is still locked, but for a different reason and
|
|
81
|
+
// with a different fix — saying "edit the declaration" would send someone
|
|
82
|
+
// looking for a declaration that no longer exists.
|
|
83
|
+
test('an undeclared system role explains that it is inert', () => {
|
|
84
|
+
const reason = roleLockReason({
|
|
85
|
+
name: 'buyer',
|
|
86
|
+
scopes: [],
|
|
87
|
+
system: true,
|
|
88
|
+
declared: false,
|
|
89
|
+
})
|
|
90
|
+
assert.match(reason!, /inert/)
|
|
91
|
+
assert.match(reason!, /pikku roles prune/)
|
|
92
|
+
})
|
|
93
|
+
})
|