@pikku/core 0.12.72 → 0.12.77
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 +1171 -0
- package/dist/column-form.d.ts +32 -0
- package/dist/column-form.js +42 -0
- package/dist/crypto-utils.d.ts +43 -7
- package/dist/crypto-utils.js +163 -42
- package/dist/data-classification.d.ts +44 -0
- 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 +37 -32
- package/dist/function/functions.types.d.ts +57 -136
- package/dist/function/functions.types.js +0 -58
- package/dist/function/index.d.ts +1 -1
- package/dist/function/list.types.d.ts +12 -62
- package/dist/function/list.types.js +4 -25
- package/dist/handle-error.d.ts +0 -13
- package/dist/handle-error.js +0 -18
- package/dist/index.d.ts +11 -5
- package/dist/index.js +7 -2
- 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 +5 -41
- 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 +4 -3
- 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 +9 -8
- package/dist/schema.d.ts +5 -39
- package/dist/schema.js +5 -39
- package/dist/scopes.d.ts +4 -23
- package/dist/scopes.js +7 -48
- package/dist/secret-value.d.ts +56 -0
- package/dist/secret-value.js +46 -0
- 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.d.ts +74 -4
- package/dist/services/audit-service.js +8 -7
- package/dist/services/content-service.d.ts +1 -46
- package/dist/services/credential-service.d.ts +3 -40
- package/dist/services/credential-wire-service.d.ts +5 -0
- package/dist/services/credential-wire-service.js +9 -1
- package/dist/services/deployment-service.d.ts +3 -9
- package/dist/services/email-service.d.ts +2 -1
- 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 +8 -9
- package/dist/services/index.js +3 -6
- 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-request-handler.d.ts +29 -0
- package/dist/services/local-content-request-handler.js +176 -0
- 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 +4 -7
- package/dist/services/local-secrets.js +7 -7
- package/dist/services/logger-console.d.ts +3 -7
- package/dist/services/logger-console.js +3 -7
- package/dist/services/logger.d.ts +22 -40
- 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 +10 -42
- 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 +4 -7
- 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 +12 -35
- 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 +5 -11
- 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 +21 -64
- package/dist/services/webhook-service.js +6 -20
- package/dist/services/workflow-service.d.ts +3 -15
- package/dist/testing/service-tests.js +6 -23
- package/dist/time-utils.d.ts +0 -16
- package/dist/time-utils.js +1 -19
- package/dist/types/core.types.d.ts +120 -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 +46 -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 +65 -132
- 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 +63 -22
- package/dist/wirings/ai-agent/ai-agent-stream.d.ts +25 -2
- package/dist/wirings/ai-agent/ai-agent-stream.js +180 -64
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +124 -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 +59 -1
- package/dist/wirings/ai-agent/voice-input.js +90 -12
- package/dist/wirings/ai-agent/voice-output.d.ts +69 -1
- package/dist/wirings/ai-agent/voice-output.js +162 -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 +38 -0
- package/dist/wirings/cli/channel/cli-raw-client-runner.js +129 -0
- package/dist/wirings/cli/channel/index.d.ts +5 -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 +0 -99
- package/dist/wirings/http/http-runner.js +9 -165
- package/dist/wirings/http/http.types.d.ts +14 -55
- 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 +0 -40
- package/dist/wirings/http/pikku-fetch-http-request.js +0 -58
- 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 +1 -4
- package/dist/wirings/mcp/mcp-runner.js +1 -14
- 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 +32 -0
- package/dist/wirings/persona/define-personas.js +31 -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 +136 -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 +103 -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 +20 -90
- 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 +17 -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 +3 -13
- package/dist/wirings/rpc/remote-addon-auth.js +7 -11
- 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 +30 -0
- package/dist/wirings/virtual-user/index.js +10 -0
- package/dist/wirings/virtual-user/prepare-virtual-user-run.d.ts +54 -0
- package/dist/wirings/virtual-user/prepare-virtual-user-run.js +49 -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-run-store.d.ts +90 -0
- package/dist/wirings/virtual-user/virtual-user-run-store.js +1 -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 +19 -15
- 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 -43
- 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 +1 -19
- 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 +84 -12
- 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 +5 -195
- 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/a-virtual-user-run-is-not-a-workflow-and-not-a-queued-job.md +48 -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-column-form-is-an-axis-of-its-own.md +84 -0
- package/knowledge/decisions/internals/core-data-classification-brand-is-an-optional-property.md +41 -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 +117 -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/one-project-shape-check-two-validators.md +53 -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/scenarios-live-in-files-named-for-them.md +48 -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/validate-checks-personas-through-a-shared-module.md +43 -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 +6 -2
- package/run-tests.sh +0 -0
- package/src/column-form.test.ts +97 -0
- package/src/column-form.ts +58 -0
- package/src/crypto-utils.test.ts +460 -19
- package/src/crypto-utils.ts +306 -59
- package/src/data-classification.ts +45 -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 +0 -7
- package/src/function/function-runner.ts +62 -32
- package/src/function/functions.types.ts +95 -138
- package/src/function/index.ts +1 -0
- package/src/function/list.types.test.ts +3 -25
- package/src/function/list.types.ts +12 -62
- package/src/handle-error.ts +0 -18
- package/src/index.ts +84 -3
- package/src/middleware/auth-apikey.test.ts +0 -1
- package/src/middleware/auth-apikey.ts +0 -17
- package/src/middleware/auth-bearer.test.ts +3 -5
- package/src/middleware/auth-bearer.ts +5 -41
- 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 +26 -10
- package/src/middleware/remote-auth.ts +11 -3
- 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 +173 -0
- package/src/remote.ts +18 -8
- package/src/schema.ts +5 -39
- package/src/scopes.ts +7 -48
- package/src/secret-value.test.ts +204 -0
- package/src/secret-value.ts +111 -0
- 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 +88 -11
- 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/credential-wire-service.ts +9 -1
- package/src/services/deployment-service.ts +3 -9
- package/src/services/email-service.ts +3 -1
- 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 +23 -18
- package/src/services/istanbul-coverage-service.ts +2 -8
- package/src/services/jwt-service.ts +1 -16
- package/src/services/local-content-request-handler.test.ts +202 -0
- package/src/services/local-content-request-handler.ts +267 -0
- 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.test.ts +20 -5
- package/src/services/local-secrets.ts +15 -11
- package/src/services/logger-console.test.ts +0 -1
- package/src/services/logger-console.ts +3 -7
- package/src/services/logger.ts +31 -46
- 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.test.ts +2 -1
- package/src/services/queue-webhook-service.ts +10 -42
- 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 +4 -7
- 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 +12 -35
- 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 +12 -14
- package/src/services/v8-coverage-service.ts +3 -6
- package/src/services/variables-service.ts +1 -8
- package/src/services/webhook-service.ts +23 -64
- package/src/services/workflow-service.ts +3 -20
- package/src/testing/service-tests.ts +6 -32
- package/src/time-utils.ts +1 -19
- package/src/types/core.types.ts +137 -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 +91 -10
- package/src/wirings/ai-agent/ai-agent-agui.ts +49 -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 +89 -139
- 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 +85 -35
- package/src/wirings/ai-agent/ai-agent-stream.test.ts +205 -103
- package/src/wirings/ai-agent/ai-agent-stream.ts +224 -76
- package/src/wirings/ai-agent/ai-agent-thread-ownership.test.ts +301 -0
- package/src/wirings/ai-agent/ai-agent.types.ts +130 -5
- package/src/wirings/ai-agent/index.ts +37 -3
- package/src/wirings/ai-agent/voice-input.test.ts +137 -7
- package/src/wirings/ai-agent/voice-input.ts +96 -12
- package/src/wirings/ai-agent/voice-output.test.ts +512 -0
- package/src/wirings/ai-agent/voice-output.ts +243 -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 +185 -0
- package/src/wirings/cli/channel/index.ts +13 -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 +8 -167
- package/src/wirings/http/http.types.ts +15 -62
- package/src/wirings/http/log-http-routes.ts +0 -4
- package/src/wirings/http/pikku-fetch-http-request.test.ts +2 -10
- package/src/wirings/http/pikku-fetch-http-request.ts +0 -58
- 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.ts +2 -17
- 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 +33 -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 +142 -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 +454 -0
- package/src/wirings/queue/queue-identity.ts +176 -0
- package/src/wirings/queue/queue-runner.ts +12 -31
- package/src/wirings/queue/queue.types.ts +25 -90
- package/src/wirings/queue/register-queue-helper.ts +0 -14
- package/src/wirings/queue/signed-queue-service.ts +60 -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 +9 -16
- package/src/wirings/rpc/rpc-runner.test.ts +192 -6
- 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 +88 -0
- package/src/wirings/virtual-user/prepare-virtual-user-run.test.ts +115 -0
- package/src/wirings/virtual-user/prepare-virtual-user-run.ts +95 -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-run-store.ts +98 -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 +19 -20
- 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 -61
- 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.test.ts +5 -7
- package/src/wirings/workflow/scenario-prose.ts +1 -29
- package/src/wirings/workflow/scenario-service.test.ts +2 -10
- package/src/wirings/workflow/scenario-step-guards.ts +1 -14
- package/src/wirings/workflow/scenario-step.test.ts +163 -19
- package/src/wirings/workflow/scenario-step.types.ts +94 -12
- package/src/wirings/workflow/scenario-surface.test.ts +146 -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 +5 -201
- package/tsconfig.tsbuildinfo +1 -1
- package/tsconfig.type-tests.json +12 -0
- package/src/middleware/timeout.ts +0 -22
- package/src/pikku-response.ts +0 -5
- 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
package/src/crypto-utils.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import type { WrappedValue } from './data-classification.js'
|
|
2
|
+
import { WeakKeyMaterialError } from './errors/errors.js'
|
|
3
|
+
|
|
1
4
|
const encoder = new TextEncoder()
|
|
2
5
|
const decoder = new TextDecoder()
|
|
3
6
|
|
|
@@ -45,13 +48,35 @@ const fromBase64Url = (input: string): Uint8Array => {
|
|
|
45
48
|
return base64Decode(base64)
|
|
46
49
|
}
|
|
47
50
|
|
|
48
|
-
const
|
|
51
|
+
const SALT_BYTES = 16
|
|
52
|
+
const IV_BYTES = 12
|
|
53
|
+
const TAG_BYTES = 16
|
|
54
|
+
const PBKDF2_ITERATIONS = 600_000
|
|
55
|
+
|
|
56
|
+
const deriveKey = async (
|
|
57
|
+
secret: string,
|
|
58
|
+
salt: Uint8Array
|
|
59
|
+
): Promise<CryptoKey> => {
|
|
49
60
|
const subtle = getSubtle()
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
'
|
|
54
|
-
|
|
61
|
+
const material = await subtle.importKey(
|
|
62
|
+
'raw',
|
|
63
|
+
encoder.encode(secret),
|
|
64
|
+
{ name: 'PBKDF2' },
|
|
65
|
+
false,
|
|
66
|
+
['deriveKey']
|
|
67
|
+
)
|
|
68
|
+
return subtle.deriveKey(
|
|
69
|
+
{
|
|
70
|
+
name: 'PBKDF2',
|
|
71
|
+
salt: salt as BufferSource,
|
|
72
|
+
iterations: PBKDF2_ITERATIONS,
|
|
73
|
+
hash: 'SHA-256',
|
|
74
|
+
},
|
|
75
|
+
material,
|
|
76
|
+
{ name: 'AES-GCM', length: 256 },
|
|
77
|
+
false,
|
|
78
|
+
['encrypt', 'decrypt']
|
|
79
|
+
)
|
|
55
80
|
}
|
|
56
81
|
|
|
57
82
|
export const encryptJSON = async (
|
|
@@ -63,8 +88,9 @@ export const encryptJSON = async (
|
|
|
63
88
|
throw new Error('WebCrypto not available')
|
|
64
89
|
}
|
|
65
90
|
const subtle = getSubtle()
|
|
66
|
-
const
|
|
67
|
-
const
|
|
91
|
+
const salt = crypto.getRandomValues(new Uint8Array(SALT_BYTES))
|
|
92
|
+
const iv = crypto.getRandomValues(new Uint8Array(IV_BYTES))
|
|
93
|
+
const key = await deriveKey(secret, salt)
|
|
68
94
|
const plaintext = encoder.encode(JSON.stringify(value))
|
|
69
95
|
const encrypted = await subtle.encrypt(
|
|
70
96
|
{ name: 'AES-GCM', iv },
|
|
@@ -72,9 +98,10 @@ export const encryptJSON = async (
|
|
|
72
98
|
plaintext
|
|
73
99
|
)
|
|
74
100
|
const cipherBytes = new Uint8Array(encrypted)
|
|
75
|
-
const out = new Uint8Array(iv.length + cipherBytes.length)
|
|
76
|
-
out.set(
|
|
77
|
-
out.set(
|
|
101
|
+
const out = new Uint8Array(salt.length + iv.length + cipherBytes.length)
|
|
102
|
+
out.set(salt, 0)
|
|
103
|
+
out.set(iv, salt.length)
|
|
104
|
+
out.set(cipherBytes, salt.length + iv.length)
|
|
78
105
|
return toBase64Url(out)
|
|
79
106
|
}
|
|
80
107
|
|
|
@@ -84,12 +111,13 @@ export const decryptJSON = async <T>(
|
|
|
84
111
|
): Promise<T> => {
|
|
85
112
|
const subtle = getSubtle()
|
|
86
113
|
const data = fromBase64Url(token)
|
|
87
|
-
if (data.length
|
|
114
|
+
if (data.length <= SALT_BYTES + IV_BYTES + TAG_BYTES) {
|
|
88
115
|
throw new Error('Invalid encrypted payload')
|
|
89
116
|
}
|
|
90
|
-
const
|
|
91
|
-
const
|
|
92
|
-
const
|
|
117
|
+
const salt = data.slice(0, SALT_BYTES)
|
|
118
|
+
const iv = data.slice(SALT_BYTES, SALT_BYTES + IV_BYTES)
|
|
119
|
+
const ciphertext = data.slice(SALT_BYTES + IV_BYTES)
|
|
120
|
+
const key = await deriveKey(secret, salt)
|
|
93
121
|
const decrypted = await subtle.decrypt(
|
|
94
122
|
{ name: 'AES-GCM', iv },
|
|
95
123
|
key,
|
|
@@ -99,58 +127,202 @@ export const decryptJSON = async <T>(
|
|
|
99
127
|
}
|
|
100
128
|
|
|
101
129
|
/**
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
* Each secret gets its own random DEK (data encryption key).
|
|
105
|
-
* The DEK is wrapped (encrypted) by a KEK (key encryption key) — typically an env var.
|
|
106
|
-
* The actual secret is encrypted with the DEK.
|
|
107
|
-
*
|
|
108
|
-
* KEK rotation only re-wraps the DEK, never touches the ciphertext.
|
|
130
|
+
* Namespaces the remote-RPC session key so the same deployment secret used for
|
|
131
|
+
* another purpose derives a different key. See knowledge/crypto.md.
|
|
109
132
|
*/
|
|
133
|
+
export const REMOTE_SESSION_INFO = 'pikku:remote-session'
|
|
110
134
|
|
|
111
|
-
const
|
|
135
|
+
export const MIN_KEY_MATERIAL_LENGTH = 32
|
|
136
|
+
|
|
137
|
+
export const assertStrongKeyMaterial = (
|
|
138
|
+
name: string,
|
|
139
|
+
keyMaterial: string
|
|
140
|
+
): void => {
|
|
141
|
+
if (keyMaterial.length < MIN_KEY_MATERIAL_LENGTH) {
|
|
142
|
+
throw new WeakKeyMaterialError(
|
|
143
|
+
name,
|
|
144
|
+
MIN_KEY_MATERIAL_LENGTH,
|
|
145
|
+
keyMaterial.length
|
|
146
|
+
)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const expandKeyMaterial = async (
|
|
151
|
+
keyMaterial: string,
|
|
152
|
+
info: string,
|
|
153
|
+
salt: Uint8Array
|
|
154
|
+
): Promise<CryptoKey> => {
|
|
112
155
|
const subtle = getSubtle()
|
|
113
|
-
|
|
156
|
+
const material = await subtle.importKey(
|
|
114
157
|
'raw',
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
158
|
+
encoder.encode(keyMaterial),
|
|
159
|
+
'HKDF',
|
|
160
|
+
false,
|
|
161
|
+
['deriveKey']
|
|
162
|
+
)
|
|
163
|
+
return subtle.deriveKey(
|
|
164
|
+
{
|
|
165
|
+
name: 'HKDF',
|
|
166
|
+
hash: 'SHA-256',
|
|
167
|
+
salt: salt as BufferSource,
|
|
168
|
+
info: encoder.encode(info) as BufferSource,
|
|
169
|
+
},
|
|
170
|
+
material,
|
|
171
|
+
{ name: 'AES-GCM', length: 256 },
|
|
172
|
+
false,
|
|
118
173
|
['encrypt', 'decrypt']
|
|
119
174
|
)
|
|
120
175
|
}
|
|
121
176
|
|
|
122
|
-
export const
|
|
123
|
-
|
|
124
|
-
|
|
177
|
+
export const encryptWithKeyMaterial = async (
|
|
178
|
+
name: string,
|
|
179
|
+
keyMaterial: string,
|
|
180
|
+
info: string,
|
|
181
|
+
value: unknown
|
|
182
|
+
): Promise<string> => {
|
|
183
|
+
assertStrongKeyMaterial(name, keyMaterial)
|
|
184
|
+
const crypto = globalThis.crypto
|
|
185
|
+
if (!crypto?.getRandomValues) {
|
|
186
|
+
throw new Error('WebCrypto not available')
|
|
187
|
+
}
|
|
188
|
+
const subtle = getSubtle()
|
|
189
|
+
const salt = crypto.getRandomValues(new Uint8Array(SALT_BYTES))
|
|
190
|
+
const iv = crypto.getRandomValues(new Uint8Array(IV_BYTES))
|
|
191
|
+
const key = await expandKeyMaterial(keyMaterial, info, salt)
|
|
192
|
+
const encrypted = await subtle.encrypt(
|
|
193
|
+
{ name: 'AES-GCM', iv },
|
|
194
|
+
key,
|
|
195
|
+
encoder.encode(JSON.stringify(value))
|
|
196
|
+
)
|
|
197
|
+
const cipherBytes = new Uint8Array(encrypted)
|
|
198
|
+
const out = new Uint8Array(salt.length + iv.length + cipherBytes.length)
|
|
199
|
+
out.set(salt, 0)
|
|
200
|
+
out.set(iv, salt.length)
|
|
201
|
+
out.set(cipherBytes, salt.length + iv.length)
|
|
202
|
+
return toBase64Url(out)
|
|
125
203
|
}
|
|
126
204
|
|
|
127
|
-
export const
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
205
|
+
export const decryptWithKeyMaterial = async <T>(
|
|
206
|
+
name: string,
|
|
207
|
+
keyMaterial: string,
|
|
208
|
+
info: string,
|
|
209
|
+
token: string
|
|
210
|
+
): Promise<T> => {
|
|
211
|
+
assertStrongKeyMaterial(name, keyMaterial)
|
|
212
|
+
const subtle = getSubtle()
|
|
213
|
+
const data = fromBase64Url(token)
|
|
214
|
+
if (data.length <= SALT_BYTES + IV_BYTES + TAG_BYTES) {
|
|
215
|
+
throw new Error('Invalid encrypted payload')
|
|
216
|
+
}
|
|
217
|
+
const salt = data.slice(0, SALT_BYTES)
|
|
218
|
+
const iv = data.slice(SALT_BYTES, SALT_BYTES + IV_BYTES)
|
|
219
|
+
const ciphertext = data.slice(SALT_BYTES + IV_BYTES)
|
|
220
|
+
const key = await expandKeyMaterial(keyMaterial, info, salt)
|
|
221
|
+
const decrypted = await subtle.decrypt(
|
|
222
|
+
{ name: 'AES-GCM', iv },
|
|
223
|
+
key,
|
|
224
|
+
ciphertext
|
|
225
|
+
)
|
|
226
|
+
return JSON.parse(decoder.decode(new Uint8Array(decrypted))) as T
|
|
132
227
|
}
|
|
133
228
|
|
|
134
|
-
export const
|
|
135
|
-
|
|
136
|
-
|
|
229
|
+
export const encodeBase64UrlText = (value: string): string =>
|
|
230
|
+
toBase64Url(encoder.encode(value))
|
|
231
|
+
|
|
232
|
+
export const decodeBase64UrlText = (value: string): string =>
|
|
233
|
+
decoder.decode(fromBase64Url(value))
|
|
234
|
+
|
|
235
|
+
const expandSigningKeyMaterial = async (
|
|
236
|
+
keyMaterial: string,
|
|
237
|
+
info: string
|
|
238
|
+
): Promise<CryptoKey> => {
|
|
239
|
+
const subtle = getSubtle()
|
|
240
|
+
const material = await subtle.importKey(
|
|
241
|
+
'raw',
|
|
242
|
+
encoder.encode(keyMaterial),
|
|
243
|
+
'HKDF',
|
|
244
|
+
false,
|
|
245
|
+
['deriveKey']
|
|
246
|
+
)
|
|
247
|
+
return subtle.deriveKey(
|
|
248
|
+
{
|
|
249
|
+
name: 'HKDF',
|
|
250
|
+
hash: 'SHA-256',
|
|
251
|
+
salt: new Uint8Array(0) as BufferSource,
|
|
252
|
+
info: encoder.encode(info) as BufferSource,
|
|
253
|
+
},
|
|
254
|
+
material,
|
|
255
|
+
{ name: 'HMAC', hash: 'SHA-256' },
|
|
256
|
+
false,
|
|
257
|
+
['sign', 'verify']
|
|
258
|
+
)
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* HMAC-SHA256 over `payload` under a key expanded from high-entropy key
|
|
263
|
+
* material, base64url-encoded. The salt is empty by design so the verifier can
|
|
264
|
+
* re-derive the key from `keyMaterial` and `info` alone.
|
|
265
|
+
*/
|
|
266
|
+
export const signWithKeyMaterial = async (
|
|
267
|
+
name: string,
|
|
268
|
+
keyMaterial: string,
|
|
269
|
+
info: string,
|
|
270
|
+
payload: string
|
|
137
271
|
): Promise<string> => {
|
|
138
|
-
|
|
272
|
+
assertStrongKeyMaterial(name, keyMaterial)
|
|
273
|
+
const key = await expandSigningKeyMaterial(keyMaterial, info)
|
|
274
|
+
const signature = await getSubtle().sign(
|
|
275
|
+
'HMAC',
|
|
276
|
+
key,
|
|
277
|
+
encoder.encode(payload) as BufferSource
|
|
278
|
+
)
|
|
279
|
+
return toBase64Url(new Uint8Array(signature))
|
|
139
280
|
}
|
|
140
281
|
|
|
141
|
-
|
|
142
|
-
|
|
282
|
+
/** False — never throws — for a malformed, truncated or mismatched signature. */
|
|
283
|
+
export const verifyWithKeyMaterial = async (
|
|
284
|
+
name: string,
|
|
285
|
+
keyMaterial: string,
|
|
286
|
+
info: string,
|
|
287
|
+
payload: string,
|
|
288
|
+
signature: string
|
|
289
|
+
): Promise<boolean> => {
|
|
290
|
+
assertStrongKeyMaterial(name, keyMaterial)
|
|
291
|
+
const key = await expandSigningKeyMaterial(keyMaterial, info)
|
|
292
|
+
try {
|
|
293
|
+
return await getSubtle().verify(
|
|
294
|
+
'HMAC',
|
|
295
|
+
key,
|
|
296
|
+
fromBase64Url(signature) as BufferSource,
|
|
297
|
+
encoder.encode(payload) as BufferSource
|
|
298
|
+
)
|
|
299
|
+
} catch {
|
|
300
|
+
return false
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const importRawKey = async (rawBytes: Uint8Array): Promise<CryptoKey> => {
|
|
305
|
+
const subtle = getSubtle()
|
|
306
|
+
return subtle.importKey(
|
|
307
|
+
'raw',
|
|
308
|
+
rawBytes.buffer as ArrayBuffer,
|
|
309
|
+
{ name: 'AES-GCM' },
|
|
310
|
+
true,
|
|
311
|
+
['encrypt', 'decrypt']
|
|
312
|
+
)
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const encryptWithCryptoKey = async (
|
|
316
|
+
key: CryptoKey,
|
|
143
317
|
value: unknown
|
|
144
318
|
): Promise<string> => {
|
|
145
319
|
const crypto = globalThis.crypto
|
|
146
320
|
const subtle = getSubtle()
|
|
147
|
-
const iv = crypto.getRandomValues(new Uint8Array(
|
|
148
|
-
const key = await importRawKey(fromBase64Url(dekBase64))
|
|
149
|
-
const plaintext = encoder.encode(JSON.stringify(value))
|
|
321
|
+
const iv = crypto.getRandomValues(new Uint8Array(IV_BYTES))
|
|
150
322
|
const encrypted = await subtle.encrypt(
|
|
151
323
|
{ name: 'AES-GCM', iv },
|
|
152
324
|
key,
|
|
153
|
-
|
|
325
|
+
encoder.encode(JSON.stringify(value))
|
|
154
326
|
)
|
|
155
327
|
const cipherBytes = new Uint8Array(encrypted)
|
|
156
328
|
const out = new Uint8Array(iv.length + cipherBytes.length)
|
|
@@ -159,18 +331,17 @@ const encryptWithDEK = async (
|
|
|
159
331
|
return toBase64Url(out)
|
|
160
332
|
}
|
|
161
333
|
|
|
162
|
-
const
|
|
163
|
-
|
|
334
|
+
const decryptWithCryptoKey = async <T>(
|
|
335
|
+
key: CryptoKey,
|
|
164
336
|
token: string
|
|
165
337
|
): Promise<T> => {
|
|
166
338
|
const subtle = getSubtle()
|
|
167
339
|
const data = fromBase64Url(token)
|
|
168
|
-
if (data.length <
|
|
340
|
+
if (data.length < IV_BYTES + TAG_BYTES) {
|
|
169
341
|
throw new Error('Invalid encrypted payload')
|
|
170
342
|
}
|
|
171
|
-
const iv = data.slice(0,
|
|
172
|
-
const ciphertext = data.slice(
|
|
173
|
-
const key = await importRawKey(fromBase64Url(dekBase64))
|
|
343
|
+
const iv = data.slice(0, IV_BYTES)
|
|
344
|
+
const ciphertext = data.slice(IV_BYTES)
|
|
174
345
|
const decrypted = await subtle.decrypt(
|
|
175
346
|
{ name: 'AES-GCM', iv },
|
|
176
347
|
key,
|
|
@@ -179,23 +350,99 @@ const decryptWithDEK = async <T>(
|
|
|
179
350
|
return JSON.parse(decoder.decode(new Uint8Array(decrypted))) as T
|
|
180
351
|
}
|
|
181
352
|
|
|
182
|
-
export
|
|
183
|
-
|
|
353
|
+
export const generateDEK = async (): Promise<string> => {
|
|
354
|
+
const raw = globalThis.crypto.getRandomValues(new Uint8Array(32))
|
|
355
|
+
return toBase64Url(raw)
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* One salt per (deployment, key version), stored beside the wrapped DEKs.
|
|
360
|
+
* See knowledge/crypto.md.
|
|
361
|
+
*/
|
|
362
|
+
export const generateKEKSalt = (): string => {
|
|
363
|
+
const crypto = globalThis.crypto
|
|
364
|
+
if (!crypto?.getRandomValues) {
|
|
365
|
+
throw new Error('WebCrypto not available')
|
|
366
|
+
}
|
|
367
|
+
return toBase64Url(crypto.getRandomValues(new Uint8Array(SALT_BYTES)))
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export const deriveKEK = async (
|
|
371
|
+
passphrase: string,
|
|
372
|
+
salt: string
|
|
373
|
+
): Promise<CryptoKey> => {
|
|
374
|
+
return deriveKey(passphrase, fromBase64Url(salt))
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* The one place a `WrappedValue` is minted. Every branded return below routes
|
|
379
|
+
* through here, so the assertion "these bytes really are ciphertext" is made
|
|
380
|
+
* once and audited once instead of at each call site.
|
|
381
|
+
*/
|
|
382
|
+
const asWrapped = (ciphertext: string): WrappedValue =>
|
|
383
|
+
ciphertext as WrappedValue
|
|
384
|
+
|
|
385
|
+
export const wrapDEK = async (
|
|
386
|
+
kek: CryptoKey,
|
|
387
|
+
plaintextDEK: string
|
|
388
|
+
): Promise<WrappedValue> => {
|
|
389
|
+
return asWrapped(await encryptWithCryptoKey(kek, plaintextDEK))
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
export const unwrapDEK = async (
|
|
393
|
+
kek: CryptoKey,
|
|
184
394
|
wrappedDEK: string
|
|
395
|
+
): Promise<string> => {
|
|
396
|
+
return decryptWithCryptoKey<string>(kek, wrappedDEK)
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
const encryptWithDEK = async (
|
|
400
|
+
dekBase64: string,
|
|
401
|
+
value: unknown
|
|
402
|
+
): Promise<string> => {
|
|
403
|
+
return encryptWithCryptoKey(
|
|
404
|
+
await importRawKey(fromBase64Url(dekBase64)),
|
|
405
|
+
value
|
|
406
|
+
)
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
const decryptWithDEK = async <T>(
|
|
410
|
+
dekBase64: string,
|
|
411
|
+
token: string
|
|
412
|
+
): Promise<T> => {
|
|
413
|
+
return decryptWithCryptoKey<T>(
|
|
414
|
+
await importRawKey(fromBase64Url(dekBase64)),
|
|
415
|
+
token
|
|
416
|
+
)
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
export interface EnvelopeEncryptResult {
|
|
420
|
+
ciphertext: WrappedValue
|
|
421
|
+
wrappedDEK: WrappedValue
|
|
185
422
|
}
|
|
186
423
|
|
|
187
424
|
export const envelopeEncrypt = async (
|
|
188
|
-
kek:
|
|
425
|
+
kek: CryptoKey,
|
|
189
426
|
value: unknown
|
|
190
427
|
): Promise<EnvelopeEncryptResult> => {
|
|
191
428
|
const dek = await generateDEK()
|
|
192
|
-
const ciphertext = await encryptWithDEK(dek, value)
|
|
429
|
+
const ciphertext = asWrapped(await encryptWithDEK(dek, value))
|
|
193
430
|
const wrappedDEK = await wrapDEK(kek, dek)
|
|
194
431
|
return { ciphertext, wrappedDEK }
|
|
195
432
|
}
|
|
196
433
|
|
|
434
|
+
/**
|
|
435
|
+
* Note the inputs are plain `string`, not `WrappedValue`.
|
|
436
|
+
*
|
|
437
|
+
* The brand exists to stop plaintext being *written* to a wrapped column, and
|
|
438
|
+
* a `WrappedValue` is assignable to `string`, so a branded caller still passes
|
|
439
|
+
* without a cast. Demanding the brand here would buy nothing — feeding the
|
|
440
|
+
* wrong string in already fails at the AEAD tag — while forcing a cast into
|
|
441
|
+
* every path that reads ciphertext back out of a row, a parsed envelope, or the
|
|
442
|
+
* wire, which is exactly where casts are least reviewable.
|
|
443
|
+
*/
|
|
197
444
|
export const envelopeDecrypt = async <T>(
|
|
198
|
-
kek:
|
|
445
|
+
kek: CryptoKey,
|
|
199
446
|
ciphertext: string,
|
|
200
447
|
wrappedDEK: string
|
|
201
448
|
): Promise<T> => {
|
|
@@ -204,10 +451,10 @@ export const envelopeDecrypt = async <T>(
|
|
|
204
451
|
}
|
|
205
452
|
|
|
206
453
|
export const envelopeRewrap = async (
|
|
207
|
-
oldKEK:
|
|
208
|
-
newKEK:
|
|
454
|
+
oldKEK: CryptoKey,
|
|
455
|
+
newKEK: CryptoKey,
|
|
209
456
|
wrappedDEK: string
|
|
210
|
-
): Promise<
|
|
457
|
+
): Promise<WrappedValue> => {
|
|
211
458
|
const dek = await unwrapDEK(oldKEK, wrappedDEK)
|
|
212
459
|
return wrapDEK(newKEK, dek)
|
|
213
460
|
}
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
// would make a plain value (e.g. `string`) unassignable to a branded column
|
|
3
|
-
// (`Private<string>`), which breaks ordinary Kysely query operands —
|
|
4
|
-
// `where('email', '=', someString)`, inserts, and `.set(...)`. Making it
|
|
5
|
-
// optional keeps the brand structurally present (so the inspector's PKU910
|
|
6
|
-
// output check still detects it) while allowing plain values to flow IN.
|
|
7
|
-
// See `findPiiPaths` in @pikku/inspector, which reads the level union-aware.
|
|
1
|
+
// knowledge: decisions/internals/core-data-classification-brand-is-an-optional-property.md
|
|
8
2
|
export type Private<T> = T & { readonly __classification__?: 'private' }
|
|
9
3
|
export type Pii<T> = T & { readonly __classification__?: 'pii' }
|
|
10
4
|
export type Secret<T> = T & { readonly __classification__?: 'secret' }
|
|
@@ -17,9 +11,53 @@ export type AnonymizeStrategy =
|
|
|
17
11
|
| 'keep'
|
|
18
12
|
| null
|
|
19
13
|
|
|
14
|
+
// knowledge: decisions/internals/core-column-form-is-an-axis-of-its-own.md
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* How a column's bytes are represented at rest, as distinct from how sensitive
|
|
18
|
+
* the value is (`Classification`). The two are independent: a token hash is
|
|
19
|
+
* `secret` + `hashed` and must never be encrypted, because the hash *is* the
|
|
20
|
+
* lookup key; a live bearer token is `secret` + `plain` today and should not be.
|
|
21
|
+
*
|
|
22
|
+
* `wrapped` and `sealed` are siblings rather than one being "encrypted": both
|
|
23
|
+
* are ciphertext, and what separates them is who can read it back. Wrapped is
|
|
24
|
+
* symmetric and the application holds the key. Sealed is asymmetric and the
|
|
25
|
+
* application holds only the public half, so it can write the value and never
|
|
26
|
+
* read it. Storing one where the other is expected is silent, permanent data
|
|
27
|
+
* loss, which is why they are not collapsed into a single `encrypted`.
|
|
28
|
+
*/
|
|
29
|
+
export type ColumnForm = 'plain' | 'hashed' | 'wrapped' | 'sealed'
|
|
30
|
+
|
|
31
|
+
declare const wrappedBrand: unique symbol
|
|
32
|
+
declare const sealedBrand: unique symbol
|
|
33
|
+
declare const hashedBrand: unique symbol
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Ciphertext under a symmetric key the application holds — the output of
|
|
37
|
+
* `envelopeEncrypt`, `wrapDEK` or `envelopeRewrap`.
|
|
38
|
+
*
|
|
39
|
+
* Unlike `Secret<T>` the brand is REQUIRED, so a plain `string` is not
|
|
40
|
+
* assignable and a column declared `form: 'wrapped'` cannot be written with
|
|
41
|
+
* anything but genuine ciphertext. It stays assignable *to* `string`, so it
|
|
42
|
+
* still works as a query operand and serializes normally — the constraint is on
|
|
43
|
+
* construction, not on use.
|
|
44
|
+
*/
|
|
45
|
+
export type WrappedValue = string & { readonly [wrappedBrand]: true }
|
|
46
|
+
|
|
47
|
+
/** Ciphertext under a public key whose private half the application does not
|
|
48
|
+
* hold. Deliberately not assignable to `WrappedValue`: writing one where the
|
|
49
|
+
* other belongs produces a row nobody can ever open. */
|
|
50
|
+
export type SealedValue = string & { readonly [sealedBrand]: true }
|
|
51
|
+
|
|
52
|
+
/** A one-way digest of a secret input. The brand's job is narrow — stop a *raw*
|
|
53
|
+
* credential being written into the column that should hold its hash. */
|
|
54
|
+
export type HashedValue = string & { readonly [hashedBrand]: true }
|
|
55
|
+
|
|
20
56
|
export interface ColumnClassification {
|
|
21
57
|
classification: Classification
|
|
22
58
|
anonymize_strategy: AnonymizeStrategy
|
|
59
|
+
/** At-rest representation. Absent means `plain`. */
|
|
60
|
+
form?: ColumnForm
|
|
23
61
|
description?: string
|
|
24
62
|
}
|
|
25
63
|
|
|
@@ -354,14 +354,12 @@ describe('pikkuDevReloader', { concurrency: false }, () => {
|
|
|
354
354
|
pikkuDir: tmpDir,
|
|
355
355
|
})
|
|
356
356
|
|
|
357
|
-
// Write updated function via file system and let the watcher pick it up
|
|
358
357
|
const jsV2 = `export const hotTask = { func: async () => { return { reloaded: true }; }, auth: false };\n`
|
|
359
358
|
await writeFile(join(tmpDir, 'hotTask.js'), jsV2)
|
|
360
359
|
await writeFile(join(tmpDir, 'hotTask.ts'), `// trigger ${Date.now()}`)
|
|
361
360
|
|
|
362
361
|
await wait(300)
|
|
363
362
|
|
|
364
|
-
// Verify the function was reloaded via the watcher
|
|
365
363
|
const reloadLog = mockLogger
|
|
366
364
|
.getLogs()
|
|
367
365
|
.find(
|
|
@@ -370,8 +368,6 @@ describe('pikkuDevReloader', { concurrency: false }, () => {
|
|
|
370
368
|
)
|
|
371
369
|
assert.ok(reloadLog, 'Should log hot-reload for hotTask')
|
|
372
370
|
|
|
373
|
-
// runScheduledTask uses runPikkuFunc which reads from the functions Map,
|
|
374
|
-
// so it will pick up the hot-reloaded function (no longer sets taskResult.ref)
|
|
375
371
|
await runScheduledTask({ name: 'hotTask' })
|
|
376
372
|
|
|
377
373
|
// The reloaded function no longer sets taskResult.ref, so it should
|
package/src/dev/hot-reload.ts
CHANGED
|
@@ -52,12 +52,6 @@ const findCompiledFile = async (
|
|
|
52
52
|
return null
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
// Changed user files are re-run through an evictable module runner keyed by a
|
|
56
|
-
// stable path (createModuleRunner), NOT re-imported under a fresh URL. A
|
|
57
|
-
// fresh-URL import (a `data:` URL on Node, a uniquely-named temp sibling on
|
|
58
|
-
// Bun) permanently leaks a record in the native ESM loader map on every
|
|
59
|
-
// reload, OOMing long editing sessions; the runner overwrites a single slot so
|
|
60
|
-
// the previous module is collected. See ./module-runner.ts.
|
|
61
55
|
const isWatchedTsFile = (filename: string): boolean => {
|
|
62
56
|
return (
|
|
63
57
|
filename.endsWith('.ts') &&
|
|
@@ -110,17 +104,12 @@ export async function pikkuDevReloader(
|
|
|
110
104
|
return
|
|
111
105
|
}
|
|
112
106
|
|
|
113
|
-
// Register every function-config export
|
|
114
|
-
// adding new ones
|
|
115
|
-
//
|
|
116
|
-
//
|
|
117
|
-
//
|
|
118
|
-
//
|
|
119
|
-
// that map is silently discarded when it restores the original.
|
|
120
|
-
// Schemas are NOT touched here: `input`/`output` hold raw zod schemas,
|
|
121
|
-
// while the schema map carries codegen-generated JSON schemas — mixing the
|
|
122
|
-
// two crashed every reload. Fresh JSON schemas arrive via
|
|
123
|
-
// reloadGeneratedMeta once codegen has re-emitted them.
|
|
107
|
+
// Register every function-config export, replacing known functions and
|
|
108
|
+
// adding new ones. Write into the map captured at startup, NOT pikkuState's
|
|
109
|
+
// current one: a dev-server watcher may have temporarily swapped in a
|
|
110
|
+
// codegen-scoped map, whose writes are discarded when it restores.
|
|
111
|
+
// Schemas are NOT touched here: `input`/`output` hold raw zod schemas while
|
|
112
|
+
// the schema map carries codegen JSON schemas; mixing them crashed reloads.
|
|
124
113
|
for (const [exportName, exportValue] of Object.entries(mod)) {
|
|
125
114
|
if (!isFunctionConfig(exportValue)) continue
|
|
126
115
|
const isNew = !functionsMap.has(exportName)
|
|
@@ -129,10 +118,9 @@ export async function pikkuDevReloader(
|
|
|
129
118
|
else reloadedNames.push(exportName)
|
|
130
119
|
}
|
|
131
120
|
|
|
132
|
-
// Re-importing
|
|
133
|
-
//
|
|
134
|
-
//
|
|
135
|
-
// wiring-only file edit rebuilds the route matchers too.
|
|
121
|
+
// Re-importing re-ran the module’s wire* side effects, so reset the router
|
|
122
|
+
// and caches even when no function export changed — a wiring-only edit has
|
|
123
|
+
// to rebuild the route matchers too.
|
|
136
124
|
clearMiddlewareCache()
|
|
137
125
|
clearPermissionsCache()
|
|
138
126
|
clearChannelMiddlewareCache()
|
|
@@ -149,9 +137,8 @@ export async function pikkuDevReloader(
|
|
|
149
137
|
|
|
150
138
|
let debounceTimer: ReturnType<typeof setTimeout> | undefined
|
|
151
139
|
const pendingChanges = new Set<string>()
|
|
152
|
-
// Files re-imported since the last reimportPending() drain
|
|
153
|
-
//
|
|
154
|
-
// were skipped for missing meta (a NEW route) run again with fresh meta.
|
|
140
|
+
// Files re-imported since the last reimportPending() drain, re-run after the
|
|
141
|
+
// dev server's codegen pass so registrations skipped for missing meta retry.
|
|
155
142
|
const postCodegenQueue = new Set<string>()
|
|
156
143
|
|
|
157
144
|
const safeHandleFileChange = async (file: string) => {
|
|
@@ -206,12 +193,6 @@ export async function pikkuDevReloader(
|
|
|
206
193
|
}
|
|
207
194
|
moduleRunner.clear()
|
|
208
195
|
},
|
|
209
|
-
// Drain the queue of recently re-imported files and import them again.
|
|
210
|
-
// A dev-server watcher calls this AFTER its codegen pass has refreshed
|
|
211
|
-
// the generated meta (reloadGeneratedMeta): wire* registrations skip
|
|
212
|
-
// routes whose meta doesn't exist yet, so a wiring file changed
|
|
213
|
-
// alongside a NEW function only registers its new route when
|
|
214
|
-
// re-imported after the fresh meta has landed.
|
|
215
196
|
reimportPending: async () => {
|
|
216
197
|
const files = [...postCodegenQueue]
|
|
217
198
|
postCodegenQueue.clear()
|