@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
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: HTTP route groups cascade config in a fixed, per-field order
|
|
4
|
+
description: basePath concatenates, tags and middleware merge outward-in, auth is overridden by the innermost group
|
|
5
|
+
tags: http
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# HTTP route groups cascade config in a fixed, per-field order
|
|
9
|
+
|
|
10
|
+
`wireHTTPRoutes` in `packages/core/src/wirings/http/http-routes.ts` walks a
|
|
11
|
+
nested route map and merges group config at each level through
|
|
12
|
+
`mergeGroupConfig`. Each field cascades differently, and the differences are the
|
|
13
|
+
contract callers write against:
|
|
14
|
+
|
|
15
|
+
- `basePath` concatenates, outer prefix first, so nesting composes URLs.
|
|
16
|
+
- `tags` merge, parent then child; nothing is replaced.
|
|
17
|
+
- `middleware` merges with the parent's entries first, so outer middleware always
|
|
18
|
+
runs before inner middleware.
|
|
19
|
+
- `auth` is a single value and the innermost declaration wins, which is what lets
|
|
20
|
+
one public route sit inside an authenticated group.
|
|
21
|
+
|
|
22
|
+
`registerRoute` then applies the same rules once more between the group config
|
|
23
|
+
and the individual route before calling `wireHTTP`.
|
|
24
|
+
|
|
25
|
+
**What this rules out:** collapsing `mergeGroupConfig` into an object spread or a
|
|
26
|
+
generic deep-merge. A spread would make the child replace the parent's `tags` and
|
|
27
|
+
`middleware` instead of extending them, and a deep-merge would concatenate `auth`
|
|
28
|
+
or reorder middleware — silently changing which middleware sees a request first.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: The HTTP router matches normalized paths but returns the registered path
|
|
4
|
+
description: Matching normalizes the leading slash while the match result carries the original key, because pikkuState is keyed by the registered string
|
|
5
|
+
tags: http
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# The HTTP router matches normalized paths but returns the registered path
|
|
9
|
+
|
|
10
|
+
`PathToRegexRouter` in `packages/core/src/wirings/http/routers/path-to-regex.ts`
|
|
11
|
+
normalizes every route and every incoming path to a leading `/` before matching,
|
|
12
|
+
so a route registered as `'todos'` still answers a request for `/todos`. The
|
|
13
|
+
`route` field it stores alongside each matcher and static entry is the
|
|
14
|
+
*un-normalized* original, and that is what `MatchResult.route` returns.
|
|
15
|
+
|
|
16
|
+
That asymmetry is load-bearing. `getMatchingRoute` in `http-runner.ts` takes the
|
|
17
|
+
returned route and uses it as a key into `pikkuState(null, 'http', 'routes')` and
|
|
18
|
+
into the HTTP meta record — both of which are keyed by exactly the string the
|
|
19
|
+
author passed to `wireHTTP`. Returning the normalized path instead would miss
|
|
20
|
+
those lookups for any route registered without a leading slash.
|
|
21
|
+
|
|
22
|
+
The same router also compiles channel routes, registered under the `get` method,
|
|
23
|
+
because a WebSocket connection arrives as an HTTP GET upgrade;
|
|
24
|
+
`getMatchingChannelConfig` in `channel-runner.ts` matches through
|
|
25
|
+
`httpRouter.match('get', path)`. Channels and HTTP GET routes therefore share one
|
|
26
|
+
path namespace and can collide with each other.
|
|
27
|
+
|
|
28
|
+
**What this rules out:** simplifying the compile step to store
|
|
29
|
+
`normalizedRoutePath` in both places, and treating the channel routes compiled
|
|
30
|
+
into the GET table as stray entries to be removed from the HTTP router.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: The HTTP runner logs through a trace-scoped logger, functions do not
|
|
4
|
+
description: Only runner-internal logging is scoped to the request id; functions keep the singleton logger for compatibility
|
|
5
|
+
tags: http
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# The HTTP runner logs through a trace-scoped logger, functions do not
|
|
9
|
+
|
|
10
|
+
`fetchData` in `packages/core/src/wirings/http/http-runner.ts` derives
|
|
11
|
+
`scopedLogger` from `singletonServices.logger.scope?.(requestId)` and uses it for
|
|
12
|
+
route-matching and error-handling output only. Functions and middleware continue
|
|
13
|
+
to receive `singletonServices.logger` unscoped, via the services object.
|
|
14
|
+
|
|
15
|
+
The split is deliberate, not an oversight. `scope` is optional on the `Logger`
|
|
16
|
+
interface, so a runtime supplying a plain logger still works — the runner falls
|
|
17
|
+
back to the singleton. Threading the scoped logger into the services object
|
|
18
|
+
instead would change the logger identity that every existing function and
|
|
19
|
+
middleware sees, which breaks implementations that compare or wrap
|
|
20
|
+
`services.logger`, and would make user code depend on an optional method.
|
|
21
|
+
|
|
22
|
+
**What this rules out:** "unifying" the two by overwriting `services.logger` with
|
|
23
|
+
`scopedLogger` before the handler runs, and equally the reverse cleanup of
|
|
24
|
+
dropping `scopedLogger` and logging runner internals through the singleton —
|
|
25
|
+
that loses the request-id correlation on 404s and unhandled errors, which is the
|
|
26
|
+
only place the trace id is attached automatically.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Set-Cookie headers are appended individually, never joined
|
|
4
|
+
description: Every cookie gets its own header line, because Set-Cookie is the one header comma-joining corrupts
|
|
5
|
+
tags: http
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Set-Cookie headers are appended individually, never joined
|
|
9
|
+
|
|
10
|
+
`PikkuFetchHTTPResponse.toResponse` in
|
|
11
|
+
`packages/core/src/wirings/http/pikku-fetch-http-response.ts` serializes each
|
|
12
|
+
cookie separately and calls `headers.append('Set-Cookie', cookie)` per value
|
|
13
|
+
rather than setting one joined string. `collectSetCookieHeaders` in
|
|
14
|
+
`web-request.ts` mirrors this when copying a web `Response` back onto a
|
|
15
|
+
`PikkuHTTPResponse`: it prefers `Headers.getSetCookie()` where the runtime
|
|
16
|
+
provides it, falls back to scanning for the header by name, de-duplicates, and
|
|
17
|
+
passes the values through as an array.
|
|
18
|
+
|
|
19
|
+
RFC 6265 makes `Set-Cookie` the exception to the "fold repeated headers with
|
|
20
|
+
commas" rule — cookie attributes such as `Expires` contain commas themselves, so
|
|
21
|
+
a joined header is parsed as a single malformed cookie and every cookie after the
|
|
22
|
+
first is lost. `Headers.set()` with a joined value, or a generic header-copy loop
|
|
23
|
+
that treats `set-cookie` like any other header, produces exactly that.
|
|
24
|
+
|
|
25
|
+
**What this rules out:** replacing the append loop with a single
|
|
26
|
+
`set('Set-Cookie', cookies.join(', '))`, and dropping the special-cased
|
|
27
|
+
`set-cookie` branch in `applyWebResponse` in favour of the generic
|
|
28
|
+
`headers.forEach` copy.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: HTTP SSE streams flush headers only after middleware has run
|
|
4
|
+
description: SSE responses defer the header flush and register with the eventHub, at the cost of a stricter ordering the runner must preserve
|
|
5
|
+
tags: http
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# HTTP SSE streams flush headers only after middleware has run
|
|
9
|
+
|
|
10
|
+
`executeRoute` in `packages/core/src/wirings/http/http-runner.ts` puts the
|
|
11
|
+
response into `'stream'` mode and sets the SSE content-type up front, but calls
|
|
12
|
+
`http.response.flushHeaders()` only after `runPikkuFunc` returns. Middleware runs
|
|
13
|
+
inside `runPikkuFunc`, and middleware is where CORS, auth and cookie headers are
|
|
14
|
+
set — flushing earlier would send the response head before those headers exist,
|
|
15
|
+
and they can never be added afterwards. `PikkuFetchHTTPResponse.createStream` in
|
|
16
|
+
`pikku-fetch-http-response.ts` enqueues a bare `:\n\n` comment frame on start for
|
|
17
|
+
the same reason on the client side: proxies and browsers do not surface the
|
|
18
|
+
stream until some body bytes arrive.
|
|
19
|
+
|
|
20
|
+
The SSE channel is also registered with `singletonServices.eventHub` when the
|
|
21
|
+
service exposes `onChannelOpened`, wrapped in a minimal object that satisfies
|
|
22
|
+
`PikkuChannelHandler`. That is what makes `eventHub.publish()` reach SSE
|
|
23
|
+
subscribers and not just WebSocket ones, and `channel.close` is rewrapped so the
|
|
24
|
+
eventHub is told about the close. On the delivery side,
|
|
25
|
+
`LocalEventHubService.publish` treats a throwing `channel.send` as a disconnect
|
|
26
|
+
and calls `onChannelClosed` — an SSE `ReadableStream` controller that the browser
|
|
27
|
+
has already abandoned throws rather than reporting closure.
|
|
28
|
+
|
|
29
|
+
**What this rules out:** hoisting `flushHeaders()` next to the other SSE header
|
|
30
|
+
calls; dropping the `:\n\n` priming frame as dead output; treating the eventHub
|
|
31
|
+
registration as WebSocket-only bookkeeping; and letting `publish` propagate a
|
|
32
|
+
send error instead of unregistering the channel.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: HTTP wiring without generated metadata is skipped, not fatal
|
|
4
|
+
description: wireHTTP warns and returns when a route has no metadata, so partial deploy units still boot
|
|
5
|
+
tags: http
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# HTTP wiring without generated metadata is skipped, not fatal
|
|
9
|
+
|
|
10
|
+
`wireHTTP` in `packages/core/src/wirings/http/http-runner.ts` looks the route up in
|
|
11
|
+
`pikkuState(null, 'http', 'meta')` and, when nothing is found, logs a warning and
|
|
12
|
+
returns instead of throwing. `wireChannel` in
|
|
13
|
+
`packages/core/src/wirings/channel/channel-runner.ts` does the same for channels.
|
|
14
|
+
|
|
15
|
+
A deploy unit is built from filtered metadata: only the functions belonging to
|
|
16
|
+
that unit get meta entries. A wiring file, however, is imported whole. When two
|
|
17
|
+
wirings share one file, importing it for the sake of the first wiring also
|
|
18
|
+
executes the second — whose function is not in this unit and therefore has no
|
|
19
|
+
metadata. Throwing there would make an otherwise valid deploy unit fail to boot.
|
|
20
|
+
The warning names the route and tells the author to split the wirings into
|
|
21
|
+
separate files, which both fixes the warning and improves tree-shaking.
|
|
22
|
+
|
|
23
|
+
**What this rules out:** turning the missing-metadata branch into a thrown error
|
|
24
|
+
or an assertion "because a route should always have metadata". It should not, in
|
|
25
|
+
filtered builds. It also rules out silently dropping the warning — the warning is
|
|
26
|
+
the only signal an author gets that a route they wired is not actually served.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: In a scenario a 4xx is data, not an exception
|
|
4
|
+
description: postScenarioJson and invokeRaw report the status instead of throwing, because a refusal is the expected outcome of a permissions scenario
|
|
5
|
+
tags: services
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# In a scenario a 4xx is data, not an exception
|
|
9
|
+
|
|
10
|
+
`postScenarioJson` (`packages/core/src/services/scenario-actors-service.ts`) and
|
|
11
|
+
`ScenarioActor.invokeRaw` return a `ScenarioHttpResponse` for every status. Only
|
|
12
|
+
`invoke` throws, and it throws with a truncated body — which is why a scenario
|
|
13
|
+
asserting on a refusal must use `invokeRaw`.
|
|
14
|
+
|
|
15
|
+
A permissions or scopes scenario *expects* the 403. The status is the assertion,
|
|
16
|
+
and the body usually names the scope that was missing, so both have to survive as
|
|
17
|
+
data rather than being reduced to a thrown `Error`. These helpers also exist
|
|
18
|
+
because every scenario reaching past an actor was hand-writing the same
|
|
19
|
+
`content-type`, `JSON.stringify` and drain — and the copies had drifted: several
|
|
20
|
+
returned `res.json()`, which discards the status entirely and throws outright on
|
|
21
|
+
an empty body or an HTML error page.
|
|
22
|
+
|
|
23
|
+
**What this rules out:** adding a `throwOnError` default to these helpers,
|
|
24
|
+
routing scenario assertions through `invoke`, and reintroducing per-scenario
|
|
25
|
+
fetch wrappers that return a parsed body without the status.
|
package/knowledge/decisions/internals/in-memory-workflow-history-aliases-the-live-step-object.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: In-memory workflow history aliases the live step object
|
|
4
|
+
description: stepHistory pushes the same StepState reference that steps holds, so later mutations to a step are visible in its history entry
|
|
5
|
+
tags: services
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# In-memory workflow history aliases the live step object
|
|
9
|
+
|
|
10
|
+
`InMemoryWorkflowService` (`packages/core/src/services/in-memory-workflow-service.ts`)
|
|
11
|
+
stores each step twice: in `steps`, keyed `${runId}:${stepName}`, and appended to
|
|
12
|
+
`stepHistory` for the run. Both hold the *same object*. `createStepImpl` and
|
|
13
|
+
`createRetryAttemptImpl` push the reference they just put into `steps`, not a
|
|
14
|
+
copy.
|
|
15
|
+
|
|
16
|
+
That aliasing is the mechanism, not an accident. The service mutates a step in
|
|
17
|
+
place as it progresses — status, `runningAt`, `completedAt`, output, error — and
|
|
18
|
+
every one of those updates has to appear in the run's history without the history
|
|
19
|
+
being rewritten. Break the aliasing and history freezes at the moment each step
|
|
20
|
+
was created: every entry reads `pending`, and `getRunHistory` reports a run in
|
|
21
|
+
which nothing ever finished.
|
|
22
|
+
|
|
23
|
+
**What this rules out:** pushing `{ ...step }` into `stepHistory`, or introducing
|
|
24
|
+
any clone/freeze/structuredClone on the way in — the obvious "don't share mutable
|
|
25
|
+
state" cleanup. If history ever needs to be immutable, the step updates have to
|
|
26
|
+
start writing to both structures explicitly, in the same change.
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: overview
|
|
3
|
+
title: Internals
|
|
4
|
+
description: How core behaves — runtime constraints, execution semantics, and the shapes the API commits to
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Internals
|
|
8
|
+
|
|
9
|
+
A rule about how core behaves: what runs where, in what order, and what a
|
|
10
|
+
caller is entitled to assume.
|
|
11
|
+
|
|
12
|
+
<!-- pikku:knowledge-index -->
|
|
13
|
+
- [A secret that fails to decrypt fails the whole read](a-secret-that-fails-to-decrypt-fails-the-whole-read.md) — getSecrets throws naming the key and its key_version rather than omitting the row, because a silent omission surfaces as an unrelated failure much later
|
|
14
|
+
- [An actor conversation starts from a seeded kickoff message](actor-flow-conversations-seed-a-hidden-kickoff-message.md) — The actor's first turn needs a non-empty message list because providers reject an empty prompt; the seed is an instruction and stays out of the transcript
|
|
15
|
+
- [The actor-flow conversation engine only sees a transport-agnostic target driver](actor-flow-drives-the-target-through-a-transport-seam.md) — The engine never imports the agent runner; the target is injected as run/approve, so scenarios exercise the real wire path
|
|
16
|
+
- [An actor-flow verdict is the persona's self-evaluation, not an assertion](actor-flow-verdicts-are-llm-self-evaluations.md) — The engine returns what the actor judged plus the transcript; deterministic checks stay with the caller
|
|
17
|
+
- [Addon package roots resolve by walking node module search paths](addon-package-roots-resolve-by-walking-node-module-search-paths.md) — LocalMetaService finds an addon's directory by scanning resolve.paths, not by require.resolve, because addon packages expose no main entry
|
|
18
|
+
- [Addon singleton services are cached per namespace, not per package](addon-singleton-services-are-cached-per-namespace-not-per-package.md) — Each wireAddon instance gets its own services built from its own overrides, at the cost of one service graph per wired instance
|
|
19
|
+
- [Bare workflow names from inside an addon are prefixed with the consumer's namespace](addon-workflow-names-are-prefixed-with-the-consumer-namespace.md) — The addon's workflowService is proxied so an addon never has to hardcode the name its consumer chose
|
|
20
|
+
- [The AG-UI bridge obeys the client's event-ordering contract exactly](ai-agent-agui-bridge-obeys-the-client-ordering-contract.md) — RUN_STARTED opens lazily, RUN_FINISHED fires once on done, and step names are globally sequential — a violation makes the client drop the whole stream
|
|
21
|
+
- [Audio chunks are labelled with the format the provider actually returned](ai-agent-audio-chunks-carry-the-format-the-provider-returned.md) — The configured format is only a request, so the response's own format wins with the request and pcm16 as fallbacks
|
|
22
|
+
- [A credential-required tool result never reaches the client or the transcript](ai-agent-credential-suspensions-hide-the-tool-result.md) — The run suspends with credential-request events instead, leaving the tool call unresulted so it can be resumed after connecting
|
|
23
|
+
- [Delegate mode hides the parent's later text, supervise mode hides the sub-agent's](ai-agent-delegate-and-supervise-hide-different-text.md) — Exactly one voice reaches the client per agent-mode; approvals and tool events always flow through either way
|
|
24
|
+
- [Nulls are stripped from approved tool arguments before execution](ai-agent-llm-tool-arguments-have-nulls-stripped.md) — LLMs emit null for optional fields where the schema layer expects undefined, so a resumed tool call is cleaned recursively first
|
|
25
|
+
- [Model resolution stays a single seam even though it is currently a passthrough](ai-agent-model-config-stays-a-single-resolution-seam.md) — resolveModelConfig looks removable but is the one merge point for per-request model overrides
|
|
26
|
+
- [An aiMiddleware onError hook cannot change how a run fails](ai-agent-onerror-hooks-cannot-change-the-failure.md) — Hook throws are swallowed so observability code can never convert, mask, or replace the original error
|
|
27
|
+
- [AI runner methods must be called on the runner, never as detached references](ai-agent-runner-methods-must-keep-their-receiver.md) — Implementations use this internally, so grabbing transcribe or generateSpeech as a bare function loses the receiver and throws at runtime
|
|
28
|
+
- [Persisting an agent stream from send is best-effort and must never reject](ai-agent-stream-persistence-is-best-effort.md) — The persisting channel flushes fire-and-forget because send is synchronous; a storage failure degrades the transcript instead of killing the process
|
|
29
|
+
- [A delegated sub-agent inherits the parent run's context block](ai-agent-sub-agents-inherit-the-parent-context-block.md) — The sub-agent tool schema carries only message and session, so the parent's identifier block is forwarded rather than re-typed by the model
|
|
30
|
+
- [A tool's execute() failure is logged before the AI SDK swallows it](ai-agent-tool-execute-failures-are-logged-unconditionally.md) — Every agent tool is wrapped in a logging try/catch, because a thrown tool error otherwise becomes a conversational reply and is invisible server-side
|
|
31
|
+
- [Voice input transcribes audio parts sequentially and in place](ai-agent-voice-input-transcribes-audio-parts-in-place.md) — Each audio part is replaced by its text where it sat, one at a time, bounding concurrent downloads and preserving content order
|
|
32
|
+
- [Working memory is persisted only when the merged value validates](ai-agent-working-memory-is-persisted-only-when-valid.md) — A failed schema check logs and drops the update rather than saving it, because invalid state poisons every later read
|
|
33
|
+
- [Channel message handlers accept three config shapes](channel-message-handlers-accept-three-config-shapes.md) — onMessage may be a function config, a wrapper with middleware, or a wrapper around a function config — the runtime discriminates structurally
|
|
34
|
+
- [Channel middleware caching covers only statically resolved middleware](channel-middleware-caches-only-statically-resolved-middleware.md) — Inherited tag/named middleware is cached per uid; per-run closures are appended fresh every call, at the cost of re-allocating the array
|
|
35
|
+
- [Channel state is per-socket, session state is per-user](channel-state-is-per-socket-session-state-is-per-user.md) — ChannelStore holds connection-scoped scratch data keyed by channelId, deliberately separate from the pikkuUserId-keyed SessionStore
|
|
36
|
+
- [A channel's user id is persisted only after onConnect middleware has run](channel-user-id-is-persisted-after-onconnect-middleware-runs.md) — The channelId to pikkuUserId mapping is written post-onConnect, because auth middleware is what establishes the session
|
|
37
|
+
- [CLI option names are camelCase in state and kebab-case on the command line](cli-option-names-are-camelcase-in-state-and-kebab-on-the-command-line.md) — Option keys match the function's input field names so they can be plucked by schema, and are converted to kebab only for display and parsing
|
|
38
|
+
- [CLI parse errors are routed by message prefix](cli-parse-errors-are-routed-by-message-prefix.md) — The CLI runners decide between printing help and printing errors by string-matching the prefixes the parser writes, so those message strings are an interface
|
|
39
|
+
- [CLI stdout is reserved for machine-readable output](cli-stdout-is-reserved-for-machine-readable-output.md) — The default renderer emits single-line NDJSON, diagnostics go to stderr, and --json only hijacks rendering for commands that declared a renderer
|
|
40
|
+
- [CLI unknown long options warn instead of failing](cli-unknown-long-options-warn-instead-of-failing.md) — Unrecognised --long options are accepted, warned about and dropped so older binaries tolerate newer invocations, while unknown short flags stay hard errors
|
|
41
|
+
- [A column's at-rest form is an axis of its own](core-column-form-is-an-axis-of-its-own.md) — How a value is stored is independent of how sensitive it is, so form carries a required nominal brand on writes while classification stays optional on reads
|
|
42
|
+
- [The data-classification brand is an optional property](core-data-classification-brand-is-an-optional-property.md) — Making __classification__ required would break ordinary Kysely operands, so the brand only constrains values flowing out
|
|
43
|
+
- [The function runner restores the wire fields it overwrites](core-function-runner-restores-the-wire-fields-it-overwrites.md) — One wire object is reused across nested calls, so functionId, audit, addonNamespace and rpc are saved and put back in a finally
|
|
44
|
+
- [Hot reload merges generated meta and never replaces it](core-hot-reload-merges-generated-meta-never-replaces-it.md) — Reloading codegen output must preserve runtime-registered meta, which no generated JSON contains
|
|
45
|
+
- [Hot reload owns its module registry instead of re-importing](core-hot-reload-owns-its-module-registry.md) — Dev reload transpiles to CJS and runs modules through vm.compileFunction, because the native ESM loader map cannot be evicted
|
|
46
|
+
- [Middleware order is resolution scope first, then priority](core-middleware-order-is-scope-then-priority.md) — Middleware is collected global to function, then stably sorted by priority, deduped, frozen and cached per wire
|
|
47
|
+
- [Schema defaults are applied on every transport, not just HTTP](core-schema-defaults-apply-on-every-transport.md) — Defaults belong to the schema rather than the call's encoding, so they run unconditionally and are cloned per request
|
|
48
|
+
- [Scopes are an AND gate, separate from permissions](core-scopes-are-an-and-gate-separate-from-permissions.md) — Every declared scope must be held, so adding one can only narrow access — permissions OR, and can only widen it
|
|
49
|
+
- [Pikku state is a global map written only at registration time](core-state-is-a-global-map-written-only-at-registration-time.md) — A symbol-keyed globalThis map holds the wiring registry; nothing per-request may ever be written to it
|
|
50
|
+
- [Email meta is read uncached because codegen rewrites it mid-session](email-meta-is-read-uncached-because-codegen-rewrites-it-mid-session.md) — getEmailMeta re-reads its file on every call, unlike every other meta accessor, because the file appears and changes during a long-lived session
|
|
51
|
+
- [Gateway adapters resolve lazily and are promise-cached](gateway-adapters-resolve-lazily-and-are-promise-cached.md) — wireGateway accepts an adapter factory because real adapters need boot-time secrets, which forces the webhook GET route to be registered unconditionally
|
|
52
|
+
- [Gateway webhook challenges echo bytes not JSON](gateway-webhook-challenges-echo-bytes-not-json.md) — String verification challenges are returned raw with returnsJSON false, because platforms byte-compare the echo and JSON quoting fails the handshake
|
|
53
|
+
- [Gateway wiring is a meta-wiring over HTTP and channels](gateway-wiring-is-a-meta-wiring-over-http-and-channels.md) — wireGateway writes handler implementations into the HTTP and channel state directly while the inspector compiles the corresponding meta, so runtime registration deliberately writes no meta
|
|
54
|
+
- [Generated src paths in pikku meta are absolute](generated-src-paths-in-pikku-meta-are-absolute.md) — emailsMeta.src is resolved by the CLI at generation time, so reading through the project-relative helpers produces a wrong compound path
|
|
55
|
+
- [HTTP request bodies are read once and shared between consumers](http-request-bodies-are-read-once-and-shared.md) — The fetch request wrapper memoises the single-use body and builds web Requests lazily, at the cost of holding the whole body in memory
|
|
56
|
+
- [HTTP route groups cascade config in a fixed, per-field order](http-route-groups-cascade-config-in-a-fixed-order.md) — basePath concatenates, tags and middleware merge outward-in, auth is overridden by the innermost group
|
|
57
|
+
- [The HTTP router matches normalized paths but returns the registered path](http-router-matches-normalized-paths-but-returns-registered-ones.md) — Matching normalizes the leading slash while the match result carries the original key, because pikkuState is keyed by the registered string
|
|
58
|
+
- [The HTTP runner logs through a trace-scoped logger, functions do not](http-runner-logs-through-a-trace-scoped-logger-functions-do-not.md) — Only runner-internal logging is scoped to the request id; functions keep the singleton logger for compatibility
|
|
59
|
+
- [Set-Cookie headers are appended individually, never joined](http-set-cookie-headers-are-appended-never-joined.md) — Every cookie gets its own header line, because Set-Cookie is the one header comma-joining corrupts
|
|
60
|
+
- [HTTP SSE streams flush headers only after middleware has run](http-sse-streams-flush-headers-only-after-middleware.md) — SSE responses defer the header flush and register with the eventHub, at the cost of a stricter ordering the runner must preserve
|
|
61
|
+
- [HTTP wiring without generated metadata is skipped, not fatal](http-wiring-without-metadata-is-skipped-not-fatal.md) — wireHTTP warns and returns when a route has no metadata, so partial deploy units still boot
|
|
62
|
+
- [In a scenario a 4xx is data, not an exception](in-a-scenario-a-4xx-is-data-not-an-exception.md) — postScenarioJson and invokeRaw report the status instead of throwing, because a refusal is the expected outcome of a permissions scenario
|
|
63
|
+
- [In-memory workflow history aliases the live step object](in-memory-workflow-history-aliases-the-live-step-object.md) — stepHistory pushes the same StepState reference that steps holds, so later mutations to a step are visible in its history entry
|
|
64
|
+
- [Istanbul statement counts attach to the start line only](istanbul-statement-counts-attach-to-the-start-line-only.md) — The istanbul coverage reader credits a statement's hits to its first line, so an enclosing multi-line statement cannot mask an unexecuted inner one
|
|
65
|
+
- [Local trigger and gateway services assume a single process](local-trigger-and-gateway-services-assume-a-single-process.md) — InMemoryTriggerService and LocalGatewayService start every listener unconditionally with no distributed claiming, so a second instance duplicates every event
|
|
66
|
+
- [Node-only builtins are imported dynamically](node-only-builtins-are-imported-dynamically.md) — V8CoverageService imports node:inspector inside start() so the module stays loadable on runtimes that have no such builtin
|
|
67
|
+
- [Queue group concurrency keeps one shared queue fair](queue-group-concurrency-keeps-one-shared-queue-fair.md) — Per-group slot caps let many producers share a single queue instead of one queue each, at the cost of a cap that must stay under batchSize
|
|
68
|
+
- [Queue jobs always carry an explicit attempts count](queue-jobs-always-carry-an-explicit-attempts-count.md) — resolveJobOptions always passes attempts so a queue backend can never apply its own retry default, and an explicit retries of 0 is honoured
|
|
69
|
+
- [Remote addons dispatch over HTTP instead of through local function meta](remote-addons-dispatch-over-http-instead-of-local-meta.md) — wireRemoteAddon ships the addon as a devDependency and posts to the host, so there is deliberately no local handler to resolve
|
|
70
|
+
- [Bare RPC names resolve through the caller's package scope before root](rpc-names-resolve-through-package-scope-before-root.md) — An addon's own functions win over root RPC meta for bare names, and the resolving scope is returned so it can be threaded into runPikkuFunc
|
|
71
|
+
- [Scenario agent calls sign in on 401 only](scenario-agent-calls-sign-in-on-401-only.md) — postAgent sends the first request with whatever session it holds and logs in only if refused, so an actor can converse with a no-auth agent with no sign-in wiring
|
|
72
|
+
- [Scenario meta lives apart from app meta but merges when read off disk](scenario-meta-lives-apart-from-app-meta-but-merges-when-read-off-disk.md) — Scenarios generate into .pikku/scenarios so no app module imports them, yet MetaService folds them back into the workflow and function meta
|
|
73
|
+
- [Scenario steps return drained response records](scenario-steps-return-drained-response-records.md) — A scenario step hands back ScenarioHttpResponse rather than a Response, because the body stream reads once and the return value crosses into the run record
|
|
74
|
+
- [Scope roots may be co-declared by an addon and its host app](scope-roots-may-be-co-declared-by-an-addon-and-its-host-app.md) — flattenScopeDefinitions dedupes ids because the same root can legitimately be declared twice, and every consumer requires one entry per scope
|
|
75
|
+
- [Serverless channel disconnect must tolerate a missing channel](serverless-channel-disconnect-must-tolerate-a-missing-channel.md) — A failed channel lookup on disconnect returns quietly, because serverless runtimes deliver disconnect more than once
|
|
76
|
+
- [The dev queue copies prod timing and serialization semantics](the-dev-queue-copies-prod-timing-and-serialization-semantics.md) — InMemoryQueueService dispatches via setTimeout, retries with backoff, and JSON round-trips every payload so dev behaviour matches a real backend
|
|
77
|
+
- [The embedding model is pinned per service and doc/query embedding is split](the-embedding-model-is-pinned-per-service-and-doc-query-embedding-is-split.md) — AIEmbeddingService fixes its model at construction so index and query share a vector space, and separates embedDocuments from embedQuery for asymmetric models
|
|
78
|
+
- [The in-memory workflow service is inline-only and single-process](the-in-memory-workflow-service-is-inline-only-and-single-process.md) — InMemoryWorkflowService wires no queues and implements withRunLock/withStepLock as pass-throughs, because inline execution has no second holder to exclude
|
|
79
|
+
- [The KEK salt is scoped to the key version, not the secret](the-kek-salt-is-scoped-to-the-key-version.md) — One stored salt per key version means N secrets cost one derivation, which is the point of envelope encryption
|
|
80
|
+
- [The schema service is never stubbed, or tests validate nothing](the-schema-service-is-never-stubbed.md) — createStubProxy returns undefined for the schema property so the real schema service is built — a stubbed one turns validation into a silent no-op
|
|
81
|
+
- [One project-shape check, called by both validators](one-project-shape-check-two-validators.md) — workspace validate and fabric validate were separate walks over the same project that duplicated sixteen findings verbatim; the shared half now lives in shared-checks.ts
|
|
82
|
+
- [Scenarios, steps and personas live in files named for them](scenarios-live-in-files-named-for-them.md) — pikkuScenario/pikkuScenarioStep must be in *.scenario.ts/*.steps.ts and definePersonas in *.virtual-user.ts, an error because the mixing is only cheap to undo while it is one file
|
|
83
|
+
- [Trigger declaration is split from trigger source](trigger-declaration-is-split-from-trigger-source.md) — Triggers are declared everywhere but subscribed only in the trigger worker, so app processes never open the underlying subscription
|
|
84
|
+
- [TypedSecretService caches for the process lifetime](typed-secret-service-caches-for-the-process-lifetime.md) — Resolved secrets are cached with no TTL, so a secret rotated out of band is not picked up until restart — tracked as pikkujs/pikku#964
|
|
85
|
+
- [Both validators check personas through one shared module, and a persona counts from either the meta or the source](validate-checks-personas-through-a-shared-module.md) — workspace validate and fabric validate are separate implementations, so the persona/actor/knowledge checks live in persona-checks.ts and are called by both
|
|
86
|
+
- [Webhook delivery history records every attempt, best effort](webhook-delivery-history-records-every-attempt-best-effort.md) — The webhook worker persists each attempt before it throws, and a failure to persist is logged rather than allowed to mask the delivery result
|
|
87
|
+
- [Webhook service collaborators are constructor args, not locator lookups](webhook-service-collaborators-are-constructor-args-not-locator-lookups.md) — QueueWebhookService takes its queue as a constructor parameter so a project wiring webhooks without a queue fails to compile instead of at first send
|
|
88
|
+
- [Whether a run is inline is read from the run record](whether-a-run-is-inline-is-read-from-the-run-record.md) — The runContexts map is a read-through cache over WorkflowRun.inline and a lifetime for replay ordinals, never the answer to what a run is
|
|
89
|
+
- [Workflow approval expiry is decided from a recorded deadline, not from a timer firing](workflow-approval-expiry-is-decided-from-a-recorded-deadline.md) — The wake-up job is best-effort liveness; losing, duplicating or delaying it cannot change the gate's answer
|
|
90
|
+
- [Core declares the scenario browser surface structurally and never imports a driver](workflow-core-never-imports-a-browser-driver.md) — `@pikku/core` must stay dependency-free for edge runtimes, so playwright augments the interface instead of being imported by it
|
|
91
|
+
- [Workflow DSL meta keeps runtime expressions in their own field, apart from literal values](workflow-dsl-meta-separates-runtime-expressions-from-literals.md) — A string `value` regenerates as a string literal; an `expression` regenerates as code, so the two can never share a field
|
|
92
|
+
- [A feature resolves its scenarios by object identity, never by name or shape](workflow-features-resolve-scenarios-by-object-identity.md) — An unregistered scenario comes back explicitly unresolved rather than silently running as something else
|
|
93
|
+
- [Inline and queued workflow graph runs share one transition planner](workflow-graph-inline-and-queued-runs-share-one-planner.md) — A second, weaker inline traversal would lose joins, cycle revisits and step provenance that the queued path has
|
|
94
|
+
- [Workflow graph node notes are non-semantic and excluded from the graph hash](workflow-graph-node-notes-are-excluded-from-the-graph-hash.md) — Documentation on a node must not count as a topology change, or editing a comment redeploys the workflow
|
|
95
|
+
- [An inline workflow run reports its run id the moment it exists, because a failure throws instead of returning](workflow-inline-runs-report-their-run-id-before-they-can-fail.md) — `onRunCreated` is the only moment guaranteed to happen whether the run passes, fails or suspends
|
|
96
|
+
- [`invocationId` is a workflow step's dedupe key; `stepId` is store-specific and must never be used as one](workflow-invocation-id-is-the-dedupe-key-not-step-id.md) — The invocation id is a frozen UUIDv5 of runId + stepName, identical across retries on every backend
|
|
97
|
+
- [A workflow step goes through the queue only if its function opts in, and there is no inline fallback](workflow-queued-step-dispatch-requires-an-explicit-opt-in.md) — `workflowQueued: true` is the whole decision; a missing queue service is a hard error, not a silent downgrade
|
|
98
|
+
- [Workflows get their own queues by default, and queue names are resolved from queue meta](workflow-queues-are-per-workflow-by-default.md) — Per-workflow queues stop one slow step head-of-line-blocking every other workflow; `shared-groups` trades that for one set of pollers
|
|
99
|
+
- [A workflow step name repeated in one run gets an ordinal suffix, and the first reach stays bare](workflow-repeated-step-names-get-an-ordinal-suffix.md) — `name`, `name#1`, `name#2` keys each reach separately without changing the durable key of any existing run
|
|
100
|
+
- [A workflow replay reads its steps once and caches only the run's immutable half](workflow-replay-reads-its-steps-once-and-caches-only-the-immutable-half.md) — The per-replay snapshot collapses O(N^2) step reads to one, but caching mutable run fields would make the replay read a lie
|
|
101
|
+
- [Workflow step retries are owned by the workflow, never by the queue](workflow-retries-are-owned-by-the-workflow-not-the-queue.md) — A step's retry count is resolved once and always passed to the queue as `attempts`, so the queue can never apply its own default
|
|
102
|
+
- [Workflow run capabilities are extensions, not subclasses](workflow-run-capabilities-are-extensions-not-subclasses.md) — Scenario support lives in a separate module behind `setRunExtension` because a bundler drops an unused module but never an unused class member
|
|
103
|
+
- [The workflow run mirror is an observability sink, never a second source of truth](workflow-run-mirror-is-never-a-source-of-truth.md) — Every mirrored write happens after the authoritative write lands, and a mirror failure can never fail the workflow
|
|
104
|
+
- [Workflow run polling starts short and backs off to the caller's ceiling](workflow-run-polling-backs-off-to-the-callers-ceiling.md) — `pollIntervalMs` is a ceiling, not a cadence, and the wait lives in its own method so the schedule can be asserted without the clock
|
|
105
|
+
- [The workflow run timeline is a pure fold over durable history, with the row's status as the authority](workflow-run-timeline-is-a-pure-fold-over-durable-history.md) — No IO in the fold keeps time-travel transport-independent; the terminal event comes from `status`, not from a timestamp every backend populates
|
|
106
|
+
- [Scenario steps default to no retries, and a whole poll is one durable step](workflow-scenario-assertions-never-retry-and-record-one-step.md) — Retrying a failed assertion is wrong for a test primitive; recording the poll as one step means replay returns the outcome, not the loop
|
|
107
|
+
- [Scenario lifecycle hooks are a scenario-only affordance and never mask the failure they follow](workflow-scenario-hooks-are-a-scenario-only-affordance.md) — A durable workflow replays, so a callback that reruns each replay has no honest meaning there
|
|
108
|
+
- [Scenario prose is rendered out of typed calls, not parsed into them](workflow-scenario-prose-is-rendered-from-typed-calls-not-parsed-from-english.md) — The inversion of cucumber — a readable report with no regex step registry to maintain
|
|
109
|
+
- [A quarantined scenario states its reason in code, not in a CI invocation](workflow-scenario-quarantine-reason-lives-in-code.md) — `skip` carries the why next to the scenario it applies to, and naming the scenario explicitly still runs it
|
|
110
|
+
- [Scenario step targets are string literals so the inspector can read them statically](workflow-scenario-step-targets-are-string-literals-for-the-inspector.md) — `step/given/when/then` mirror `do`'s RPC shape because the extractor reads a literal, not an imported symbol
|
|
111
|
+
- [A step's compensation handler runs as a durable step of its own, and never compensates itself](workflow-step-compensation-runs-as-its-own-durable-step.md) — A refund or rollback must not fire twice on replay, so `onError` is recorded as `<step>:onError` with retries disabled
|
|
112
|
+
- [A failed workflow step dispatch is transient infrastructure, not a run failure](workflow-step-dispatch-failure-is-transient-not-a-run-failure.md) — Queue-unreachable errors leave the run running and the step pending so the orchestrator replays; marking the run failed loses it
|
|
113
|
+
- [A workflow step lock is held only to claim the step, never across its execution](workflow-step-lock-is-held-only-to-claim-the-step.md) — Holding the advisory lock — and its pooled connection — across step work exhausted the connection pool and self-deadlocked
|
|
114
|
+
- [A workflow step's recorded `rpcName` is provenance only — nothing dispatches off it](workflow-step-rpc-name-is-provenance-only.md) — It exists so a reader can join a runtime step row back to the declaration that produced it, especially when the durable name was built in a loop
|
|
115
|
+
- [A suspend or approval `reason` is the step's durable identity, not just a message](workflow-suspend-and-approval-reasons-are-durable-step-identities.md) — The reason is namespaced and used raw as the step key, so it must be derived deterministically across replays
|
|
116
|
+
- [A suspended workflow run keeps its in-process context; only terminal runs release it](workflow-suspended-runs-keep-their-in-process-context.md) — `suspended` is absent from the terminal set on purpose, and a context is dropped only when nothing is holding it open
|
|
117
|
+
<!-- /pikku:knowledge-index -->
|
package/knowledge/decisions/internals/istanbul-statement-counts-attach-to-the-start-line-only.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Istanbul statement counts attach to the start line only
|
|
4
|
+
description: The istanbul coverage reader credits a statement's hits to its first line, so an enclosing multi-line statement cannot mask an unexecuted inner one
|
|
5
|
+
tags: services
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Istanbul statement counts attach to the start line only
|
|
9
|
+
|
|
10
|
+
`IstanbulCoverageService` (`packages/core/src/services/istanbul-coverage-service.ts`)
|
|
11
|
+
reads instrumented counters off the `__coverage__` global and, when turning
|
|
12
|
+
statement maps into line hits, credits each statement's count to its *start* line
|
|
13
|
+
and no other line it spans.
|
|
14
|
+
|
|
15
|
+
This is istanbul's own semantics, and the reason matters: statements nest. An
|
|
16
|
+
`if` block spanning ten lines has a non-zero count as soon as the `if` is
|
|
17
|
+
reached, and a `throw` on line six inside it that never ran has a count of zero.
|
|
18
|
+
Spreading the enclosing statement's count across its whole range would paint that
|
|
19
|
+
`throw` as covered — the uncovered branch disappears into the covered one, which
|
|
20
|
+
is precisely the case coverage exists to surface.
|
|
21
|
+
|
|
22
|
+
**What this rules out:** filling in `start.line`..`end.line` from a single
|
|
23
|
+
statement's count, or merging a nested statement's zero into its parent's total.
|
|
24
|
+
Any change here has to keep the innermost statement's own count as the authority
|
|
25
|
+
for its line.
|
package/knowledge/decisions/internals/local-trigger-and-gateway-services-assume-a-single-process.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Local trigger and gateway services assume a single process
|
|
4
|
+
description: InMemoryTriggerService and LocalGatewayService start every listener unconditionally with no distributed claiming, so a second instance duplicates every event
|
|
5
|
+
tags: services
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Local trigger and gateway services assume a single process
|
|
9
|
+
|
|
10
|
+
`InMemoryTriggerService` (`packages/core/src/services/in-memory-trigger-service.ts`)
|
|
11
|
+
and `LocalGatewayService` (`packages/core/src/services/local-gateway-service.ts`)
|
|
12
|
+
start every registered trigger source and every listener gateway
|
|
13
|
+
unconditionally. There is no claiming, no lease, no leader election: whoever
|
|
14
|
+
boots, listens.
|
|
15
|
+
|
|
16
|
+
That is correct for exactly one owner. Run two instances and both subscribe to
|
|
17
|
+
the same source, so every external event fires its RPC target twice — and because
|
|
18
|
+
triggers and listener gateways are typically wired to side-effecting functions,
|
|
19
|
+
the duplicate is not idempotent. A distributed deployment needs a different
|
|
20
|
+
`TriggerService` / `GatewayService` implementation that coordinates first; the
|
|
21
|
+
interfaces exist so that implementation can be dropped in.
|
|
22
|
+
|
|
23
|
+
**What this rules out:** scaling a `pikku serve` or container running these
|
|
24
|
+
services beyond one replica, and adding coordination inside these two classes.
|
|
25
|
+
They are the single-process implementations by definition — coordination belongs
|
|
26
|
+
in a sibling implementation, not behind a flag here.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Node-only builtins are imported dynamically
|
|
4
|
+
description: V8CoverageService imports node:inspector inside start() so the module stays loadable on runtimes that have no such builtin
|
|
5
|
+
tags: services
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Node-only builtins are imported dynamically
|
|
9
|
+
|
|
10
|
+
`V8CoverageService` (`packages/core/src/services/v8-coverage-service.ts`) reaches
|
|
11
|
+
`node:inspector` through `await import('node:inspector')` inside `doStart()`,
|
|
12
|
+
not through a top-level import.
|
|
13
|
+
|
|
14
|
+
`@pikku/core` is loaded whole on runtimes that have no Node builtins —
|
|
15
|
+
Cloudflare Workers most notably. A static `import 'node:inspector'` is resolved
|
|
16
|
+
when the module graph loads, so it would fail the entire bundle at startup on
|
|
17
|
+
those runtimes, for a service that would never have been started there anyway.
|
|
18
|
+
Deferring the import moves the failure to the point of use, where it is both
|
|
19
|
+
correct and avoidable.
|
|
20
|
+
|
|
21
|
+
**What this rules out:** hoisting the import to the top of the file because the
|
|
22
|
+
dynamic form "looks unnecessary", and the same move in any other core module that
|
|
23
|
+
touches a Node-only builtin. The rule is general: if core can be loaded on
|
|
24
|
+
Workers, a Node builtin is imported at the call site.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: One project-shape check, called by both validators
|
|
4
|
+
description: workspace validate and fabric validate were separate walks over the same project that duplicated sixteen findings verbatim; the shared half now lives in shared-checks.ts and fabric validate is that plus the deploy-shaped checks
|
|
5
|
+
tags: cli, validate, fabric
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# One project-shape check, called by both validators
|
|
9
|
+
|
|
10
|
+
`pikku workspace validate` and `pikku fabric validate` read like one command
|
|
11
|
+
with a flag. They were two implementations — 495 lines and 2026 — that walked
|
|
12
|
+
the same project and emitted sixteen identical findings. `functions-dir-missing`
|
|
13
|
+
existed character for character in both files. All sixteen already agreed on
|
|
14
|
+
severity, which is the only reason the duplication was invisible.
|
|
15
|
+
|
|
16
|
+
What the duplication cost was not the lines. It was that each validator carried
|
|
17
|
+
checks the other lacked for no reason anyone could name, and nobody noticed
|
|
18
|
+
because nobody read them side by side:
|
|
19
|
+
|
|
20
|
+
- fabric validate never checked that `packages/functions` declares zod v4, or
|
|
21
|
+
that it has a `package.json` at all — while it did check that six other
|
|
22
|
+
dependencies are present.
|
|
23
|
+
- workspace validate never checked the four scaffold flags beyond `console`,
|
|
24
|
+
though the console it requires is useless without `rpc`.
|
|
25
|
+
- fabric validate swallowed a JSON parse error and reported
|
|
26
|
+
`pikku-config-missing` for a file sitting right there.
|
|
27
|
+
|
|
28
|
+
Two of workspace validate's own checks were not merely absent from fabric — they
|
|
29
|
+
had never run anywhere:
|
|
30
|
+
|
|
31
|
+
- the auth checks were gated on a middleware instance with `definitionId ===
|
|
32
|
+
'betterAuthSession'`, but the CLI wires `betterAuthStatelessSession` whenever
|
|
33
|
+
`session.cookieCache` is on, which is the configuration Fabric asks for. So
|
|
34
|
+
they skipped precisely the apps most likely to have auth.
|
|
35
|
+
- they looked for migrations in `packages/functions/db/`, and for tables named
|
|
36
|
+
`app_user` and `auth_verification_token`. `pikku db migrate` reads migrations
|
|
37
|
+
from `<root>/db/<engine>/`, and those two table names appear nowhere else in
|
|
38
|
+
pikku or in any template. Had the gate ever opened, the check would have been
|
|
39
|
+
wrong for every project it fired on.
|
|
40
|
+
|
|
41
|
+
`shared-checks.ts` is now the half that is true of any pikku project regardless
|
|
42
|
+
of where it deploys. Workspace validate is exactly that module; fabric validate
|
|
43
|
+
is that module plus the deploy-shaped checks — themes, frontends, the
|
|
44
|
+
Cloudflare adapter, the `.gitignore` contract, the frontend type-check.
|
|
45
|
+
|
|
46
|
+
Fabric's fix hints won where the two differed: they are multi-line and show the
|
|
47
|
+
config block to paste, and there was no reason workspace users were getting the
|
|
48
|
+
one-line version.
|
|
49
|
+
|
|
50
|
+
**What this rules out:** adding a check to one validator and not the other;
|
|
51
|
+
`pikku fabric validate` reporting a corrupt config as a missing one; asserting
|
|
52
|
+
auth table names no scaffold generates; and reading migrations from anywhere
|
|
53
|
+
other than where `pikku db migrate` reads them.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Queue group concurrency keeps one shared queue fair
|
|
4
|
+
description: Per-group slot caps let many producers share a single queue instead of one queue each, at the cost of a cap that must stay under batchSize
|
|
5
|
+
tags: queue
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Queue group concurrency keeps one shared queue fair
|
|
9
|
+
|
|
10
|
+
`PikkuWorkerConfig.groupConcurrency` in
|
|
11
|
+
`packages/core/src/wirings/queue/queue.types.ts` caps how many jobs of any one
|
|
12
|
+
group (`JobOptions.group`, a `JobGroup` with an `id` and optional `tier`) may run
|
|
13
|
+
at once. Jobs sharing a group `id` count against the same limit;
|
|
14
|
+
`GroupConcurrencyConfig.tiers` varies the limit per tier so a slow group can be
|
|
15
|
+
allowed more or fewer slots than the default.
|
|
16
|
+
|
|
17
|
+
The alternative considered was one queue per producer, which gives isolation for
|
|
18
|
+
free. It was rejected because pull-based backends poll per queue, so splitting
|
|
19
|
+
multiplies polling cost linearly with the number of producers. A single shared
|
|
20
|
+
queue plus a per-group cap gets the same "no one producer starves the others"
|
|
21
|
+
property at constant polling cost. The cap must not exceed
|
|
22
|
+
`PikkuWorkerConfig.batchSize`, which is the worker's total concurrency — a group
|
|
23
|
+
limit above it can never bind and silently reverts the queue to unfair.
|
|
24
|
+
|
|
25
|
+
**What this rules out:** dropping `group`/`groupConcurrency` in favour of
|
|
26
|
+
per-producer queues, and raising a group limit to or above `batchSize` as a way
|
|
27
|
+
to "disable" fairness — that reintroduces head-of-line blocking by a single
|
|
28
|
+
producer rather than turning the feature off.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Queue jobs always carry an explicit attempts count
|
|
4
|
+
description: resolveJobOptions always passes attempts so a queue backend can never apply its own retry default, and an explicit retries of 0 is honoured
|
|
5
|
+
tags: services
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Queue jobs always carry an explicit attempts count
|
|
9
|
+
|
|
10
|
+
`QueueWebhookService.resolveJobOptions`
|
|
11
|
+
(`packages/core/src/services/queue-webhook-service.ts`) resolves retries as
|
|
12
|
+
per-call `retries` → `config.webhook.retries` → `DEFAULT_WEBHOOK_RETRIES`, then
|
|
13
|
+
*always* puts `attempts: retries + 1` on the job options. It mirrors the workflow
|
|
14
|
+
service's policy resolution. Backoff is exponential unless a concrete
|
|
15
|
+
`retryDelay` selects a fixed one.
|
|
16
|
+
|
|
17
|
+
Two rules are load-bearing. `attempts` is passed unconditionally so the queue
|
|
18
|
+
backend never gets to apply its own default — pg-boss, BullMQ and SQS disagree
|
|
19
|
+
about what that default is, and a webhook silently retried a different number of
|
|
20
|
+
times per backend is not a behaviour anyone can reason about. And an explicitly
|
|
21
|
+
set `retries: 0` is honoured rather than treated as unset, because "deliver this
|
|
22
|
+
exactly once, do not retry" is a real caller intent that `??` chains lose.
|
|
23
|
+
|
|
24
|
+
**What this rules out:** omitting `attempts` when it equals the default, folding
|
|
25
|
+
`retries` into a truthiness check (`retries || configRetries`, which turns 0 back
|
|
26
|
+
into the default), and relying on a queue adapter's retry configuration in place
|
|
27
|
+
of passing the value.
|
package/knowledge/decisions/internals/remote-addons-dispatch-over-http-instead-of-local-meta.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Remote addons dispatch over HTTP instead of through local function meta
|
|
4
|
+
description: wireRemoteAddon ships the addon as a devDependency and posts to the host, so there is deliberately no local handler to resolve
|
|
5
|
+
tags: rpc
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Remote addons dispatch over HTTP instead of through local function meta
|
|
9
|
+
|
|
10
|
+
`wireAddon` bundles an addon's functions in-process: the package is a production
|
|
11
|
+
dependency and its handlers run inside the consumer. `wireRemoteAddon`
|
|
12
|
+
(`packages/core/src/wirings/rpc/wire-remote-addon.ts`) does the opposite — the
|
|
13
|
+
package is installed as a **devDependency**, contributing types only, and the
|
|
14
|
+
handlers run on the host at `serverUrl`. `pikku verify` enforces the
|
|
15
|
+
devDependency placement.
|
|
16
|
+
|
|
17
|
+
`ContextAwareRPCService.invokeAddonFunction` in `rpc-runner.ts` therefore checks
|
|
18
|
+
`resolved.addonConfig?.remote` *before* it looks for local function meta, and
|
|
19
|
+
routes to `invokeRemoteAddonFunction`. That method POSTs the addon's own function
|
|
20
|
+
name — the bare name, not the namespaced `ns:fn` form, optionally remapped by
|
|
21
|
+
`remoteName` — to `${serverUrl}/remote/rpc/:rpcName`, authenticating as a client
|
|
22
|
+
with the token bound in `wireRemoteAddon({ auth })`. There is no local meta entry
|
|
23
|
+
to fall back on, which is why a missing `serverUrl` raises
|
|
24
|
+
`RemoteAddonConfigError` rather than degrading to a local lookup, and a non-2xx
|
|
25
|
+
response raises `RemoteAddonRequestError` with a truncated body for context.
|
|
26
|
+
|
|
27
|
+
**What this rules out:** moving the `remote` check after the local meta lookup
|
|
28
|
+
(the lookup will always miss and mask the real error), sending the namespaced
|
|
29
|
+
name over the wire, and promoting the addon to a production dependency so its
|
|
30
|
+
handlers can be "used directly" — that defeats the point of the remote wiring and
|
|
31
|
+
puts the host's code in the consumer's bundle.
|