@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,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Bare RPC names resolve through the caller's package scope before root
|
|
4
|
+
description: 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
|
|
5
|
+
tags: rpc
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Bare RPC names resolve through the caller's package scope before root
|
|
9
|
+
|
|
10
|
+
`resolvePikkuFunction` in `packages/core/src/wirings/rpc/rpc-runner.ts` tries the
|
|
11
|
+
caller's package function meta first when a `packageName` is supplied, then root
|
|
12
|
+
RPC meta, then a versioned base name, then root function meta, and only then
|
|
13
|
+
throws `RPCNotFoundError`. It returns the resolving package alongside the
|
|
14
|
+
`pikkuFuncId` so `ContextAwareRPCService` can pass the right scope into
|
|
15
|
+
`runPikkuFunc` without a second lookup.
|
|
16
|
+
|
|
17
|
+
The package-first order exists because RPC meta only ever lives in root: addon
|
|
18
|
+
packages register their handlers under their own package name as *function* meta,
|
|
19
|
+
never as RPC meta. Without the package probe, a bare `rpc('doThing')` made from
|
|
20
|
+
inside an addon would skip that addon's own `doThing` and either resolve to an
|
|
21
|
+
unrelated root function of the same name or fail outright. The versioned retry
|
|
22
|
+
exists so `name@2` falls back to the meta registered under `name`.
|
|
23
|
+
|
|
24
|
+
When even root resolution fails, `rpc` and `rpcWithWire` catch the
|
|
25
|
+
`RPCNotFoundError` and hand the call to `services.deploymentService` if one is
|
|
26
|
+
configured — a Cloudflare service binding or a Lambda invoke — so a name that is
|
|
27
|
+
not in this deploy unit can still be served by another.
|
|
28
|
+
|
|
29
|
+
**What this rules out:** flattening the lookup to a single root meta read,
|
|
30
|
+
resolving the package scope separately from the function id (the two must agree),
|
|
31
|
+
and treating an `RPCNotFoundError` as terminal before the deployment-service
|
|
32
|
+
fallback has had a chance.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Scenario agent calls sign in on 401 only
|
|
4
|
+
description: 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
|
|
5
|
+
tags: services
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Scenario agent calls sign in on 401 only
|
|
9
|
+
|
|
10
|
+
`HttpScenarioActor.postAgent`
|
|
11
|
+
(`packages/core/src/services/http-scenario-actors.ts`) sends its first request
|
|
12
|
+
with whatever cookie the jar happens to hold — none, for an actor that has never
|
|
13
|
+
signed in — and only a 401 triggers `login()` and a single retry. Its sibling
|
|
14
|
+
`invokeRaw` does the opposite: it signs in eagerly before the first RPC.
|
|
15
|
+
|
|
16
|
+
The asymmetry is deliberate. Agent HTTP routes may be public; RPC routes are
|
|
17
|
+
assumed not to be. Making agent calls eager would mean an actor could not talk to
|
|
18
|
+
a no-auth agent at all without a sign-in endpoint, an actor secret and a user
|
|
19
|
+
table — a large amount of wiring to exercise an agent that requires none of it.
|
|
20
|
+
Deferring to the 401 keeps the authenticated case working (the retry succeeds
|
|
21
|
+
with the session attached) at the cost of one extra round trip the first time.
|
|
22
|
+
|
|
23
|
+
**What this rules out:** unifying the two paths so `postAgent` signs in up front
|
|
24
|
+
"like `invokeRaw` does", and removing the 401 retry on the grounds that
|
|
25
|
+
`invokeRaw` already guarantees a session. Note the ordering consequence: an actor
|
|
26
|
+
whose first action is `converse` against a no-auth agent never signs in at all, so
|
|
27
|
+
nothing else may assume `signedIn` is true after a conversation.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Scenario meta lives apart from app meta but merges when read off disk
|
|
4
|
+
description: Scenarios generate into .pikku/scenarios so no app module imports them, yet MetaService folds them back into the workflow and function meta
|
|
5
|
+
tags: services
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Scenario meta lives apart from app meta but merges when read off disk
|
|
9
|
+
|
|
10
|
+
Scenario workflows and scenario steps are generated into `.pikku/scenarios/`
|
|
11
|
+
rather than alongside the app's own `workflow/` and `function/` meta. The split
|
|
12
|
+
exists at the import level: nothing app-facing should pull a scenario into a
|
|
13
|
+
production bundle.
|
|
14
|
+
|
|
15
|
+
The split does not exist at the meta level. `LocalMetaService.getWorkflowMeta`
|
|
16
|
+
reads both `workflow/meta` and `scenarios/meta`, and `getFunctionsMeta` reads
|
|
17
|
+
both `pikku-functions-meta` and `pikku-scenario-functions-meta`
|
|
18
|
+
(`packages/core/src/services/meta-service.ts`). Anything reading meta off disk —
|
|
19
|
+
the console's scenario list first among them — is entitled to see scenarios,
|
|
20
|
+
because to a meta reader they simply are workflows and functions.
|
|
21
|
+
`packages/core/src/services/meta-service.test.ts` guards this.
|
|
22
|
+
|
|
23
|
+
**What this rules out:** dropping the second read on the grounds that the app
|
|
24
|
+
never registers scenario workflows, and "tidying" the two meta directories into
|
|
25
|
+
one. The two reads are the seam: separate on disk and in the import graph,
|
|
26
|
+
merged in `MetaService`.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Scenario steps return drained response records
|
|
4
|
+
description: 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
|
|
5
|
+
tags: services
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Scenario steps return drained response records
|
|
9
|
+
|
|
10
|
+
`ScenarioHttpResponse` and `readScenarioHttpResponse`
|
|
11
|
+
(`packages/core/src/services/scenario-actors-service.ts`) exist because a `fetch`
|
|
12
|
+
`Response` cannot be a scenario step's return value. A step's result is
|
|
13
|
+
serialised into the workflow run record, and a `Response` body is a stream that
|
|
14
|
+
reads exactly once — by the time anything downstream looks at it, it is either
|
|
15
|
+
consumed or unreadable.
|
|
16
|
+
|
|
17
|
+
So the response is drained at the boundary: status, `ok`, the parsed body, and
|
|
18
|
+
the raw text it was parsed from. `serialized` is kept alongside `body` so an
|
|
19
|
+
assertion can search the payload without knowing its shape, and so an error page
|
|
20
|
+
that is HTML rather than JSON still says what went wrong instead of collapsing to
|
|
21
|
+
a parse failure. `body` is `undefined` for an empty response and the raw text when
|
|
22
|
+
the payload was not JSON; its type parameter is a claim the caller makes, not one
|
|
23
|
+
the transport checked.
|
|
24
|
+
|
|
25
|
+
**What this rules out:** returning `Response` (or anything holding a stream) from
|
|
26
|
+
a scenario step or an actor method, and dropping `serialized` as redundant with
|
|
27
|
+
`body` — a non-JSON error body has no other route to the assertion.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Scenarios, steps and personas live in files named for them, and validate errors when they do not
|
|
4
|
+
description: pikkuScenario/pikkuFeature/pikkuScenarioStep must be in *.scenario.ts, *.scenarios.ts or *.steps.ts, and definePersonas/runVirtualUser in *.virtual-user.ts or *.vu.ts — an error, because the mixing is only cheap to undo while it is one file
|
|
5
|
+
tags: cli, validate, scenarios, personas
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Scenarios, steps and personas live in files named for them, and validate errors when they do not
|
|
9
|
+
|
|
10
|
+
A `pikkuScenario` declared beside the functions it exercises reads as more of
|
|
11
|
+
the same file. The wiring, the function, and the test of the function arrive in
|
|
12
|
+
one scroll, and the scenario is the part that gets lost — you cannot tell from
|
|
13
|
+
a directory listing which files ship and which files test.
|
|
14
|
+
|
|
15
|
+
So `validate` requires the declaration to be in a file named for what it is:
|
|
16
|
+
|
|
17
|
+
| declaration | file |
|
|
18
|
+
| --- | --- |
|
|
19
|
+
| `pikkuScenario`, `pikkuFeature` | `*.scenario.ts`, `*.scenarios.ts` |
|
|
20
|
+
| `pikkuScenarioStep` and its platform/addon variants | `*.steps.ts` (or the above) |
|
|
21
|
+
| `definePersonas`, `runVirtualUser` | `*.virtual-user.ts`, `*.vu.ts` |
|
|
22
|
+
|
|
23
|
+
Three suffixes for scenarios rather than one, because the split that matters is
|
|
24
|
+
scenarios apart from application code, not a particular spelling — `.steps.ts`
|
|
25
|
+
holds the steps, `.scenarios.ts` holds the scenarios that call them, and a
|
|
26
|
+
project that already made that split does not have to rename anything.
|
|
27
|
+
|
|
28
|
+
**Error, not warning.** The mixing is cheap to undo while it is one file and
|
|
29
|
+
expensive once it is thirty, and a warning is exactly the signal a project
|
|
30
|
+
learns to scroll past. This is the one place where the scenario checks are
|
|
31
|
+
strict: everything else `validate` says about scenarios (no personas declared,
|
|
32
|
+
no actor sign-in, no environments) is a warning, because those describe an
|
|
33
|
+
under-tested project rather than an unreadable one.
|
|
34
|
+
|
|
35
|
+
**Personas are the virtual-user file** because there is no `defineVirtualUsers`
|
|
36
|
+
to look for. That name was retired in favour of `definePersonas`: a virtual user
|
|
37
|
+
is derived rather than authored — the function meta becomes its catalogue, the
|
|
38
|
+
scenario meta becomes its intents, the declared personas become its identities.
|
|
39
|
+
The persona list is the only part a project writes, so it is the part that has
|
|
40
|
+
to be findable by filename.
|
|
41
|
+
|
|
42
|
+
Matching is on the call (`\bpikkuScenario\s*\(`), not the import, so an aliased
|
|
43
|
+
import cannot slip past and a mention in a comment or a string does not trip it.
|
|
44
|
+
Generated files are exempt — codegen puts things where it likes.
|
|
45
|
+
|
|
46
|
+
**What this rules out:** a scenario in a function file; a step in a wiring file;
|
|
47
|
+
personas in a general-purpose `personas.ts`; and reporting any of these as a
|
|
48
|
+
warning that a project can carry indefinitely.
|
package/knowledge/decisions/internals/scope-roots-may-be-co-declared-by-an-addon-and-its-host-app.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Scope roots may be co-declared by an addon and its host app
|
|
4
|
+
description: flattenScopeDefinitions dedupes ids because the same root can legitimately be declared twice, and every consumer requires one entry per scope
|
|
5
|
+
tags: services
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Scope roots may be co-declared by an addon and its host app
|
|
9
|
+
|
|
10
|
+
`flattenScopeDefinitions`
|
|
11
|
+
(`packages/core/src/wirings/scope/validate-scope-definitions.ts`) walks the
|
|
12
|
+
declared trees depth-first, emits every node including intermediate ones, and
|
|
13
|
+
then filters the result through a `seen` set. The dedupe is not defensive
|
|
14
|
+
programming.
|
|
15
|
+
|
|
16
|
+
An addon and the app hosting it may both contribute the same root — both
|
|
17
|
+
declaring an `admin` tree, say — and that is a supported arrangement, not a
|
|
18
|
+
misconfiguration. `validateAndBuildScopeDefinitionsMeta` has already established
|
|
19
|
+
that definitions sharing a name are identical, and errors naming both source
|
|
20
|
+
files if they are not, so by the time flattening runs a repeat is redundant rather
|
|
21
|
+
than conflicting. Collapsing it here is what keeps the consumers honest: codegen
|
|
22
|
+
writes these ids into an object literal keyed by id, where a duplicate key is a
|
|
23
|
+
TypeScript error, and a `ScopeService` syncs one row per scope instead of
|
|
24
|
+
re-writing the same one. `packages/core/src/wirings/scope/scope.test.ts` covers
|
|
25
|
+
the co-declaration case.
|
|
26
|
+
|
|
27
|
+
**What this rules out:** dropping the `seen` filter on the grounds that ids are
|
|
28
|
+
already unique per declaration, and turning a repeated root into a validation
|
|
29
|
+
error. The uniqueness guarantee lives here, and both codegen and scope sync
|
|
30
|
+
depend on it.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Serverless channel disconnect must tolerate a missing channel
|
|
4
|
+
description: A failed channel lookup on disconnect returns quietly, because serverless runtimes deliver disconnect more than once
|
|
5
|
+
tags: channel
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Serverless channel disconnect must tolerate a missing channel
|
|
9
|
+
|
|
10
|
+
`runChannelDisconnect` in
|
|
11
|
+
`packages/core/src/wirings/channel/serverless/serverless-channel-runner.ts`
|
|
12
|
+
wraps `channelStore.getChannel(channelId)` in a `try`/`catch` and returns after
|
|
13
|
+
an info log when the lookup fails, before any lifecycle function runs.
|
|
14
|
+
|
|
15
|
+
Serverless runtimes do not guarantee a single disconnect delivery.
|
|
16
|
+
`serverless-offline`, worker-thread runners and retried invocations all call the
|
|
17
|
+
disconnect path more than once for the same connection, and the second call
|
|
18
|
+
arrives after `channelStore.removeChannels` has already run. There is nothing
|
|
19
|
+
left to disconnect at that point, so an error would be noise on a normal
|
|
20
|
+
shutdown — and, where the platform retries on failure, a loop. The local runner
|
|
21
|
+
does not need this because the channel object lives in-process for the whole
|
|
22
|
+
connection.
|
|
23
|
+
|
|
24
|
+
**What this rules out:** treating a missing channel as an error worth throwing or
|
|
25
|
+
logging at error level, and hoisting the `getChannel` call out of its `try` while
|
|
26
|
+
"tidying up" the early returns. It also means `onDisconnect` is best-effort, not
|
|
27
|
+
exactly-once — anything that must happen once per connection needs its own
|
|
28
|
+
idempotency, not this handler.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: The dev queue copies prod timing and serialization semantics
|
|
4
|
+
description: InMemoryQueueService dispatches via setTimeout, retries with backoff, and JSON round-trips every payload so dev behaviour matches a real backend
|
|
5
|
+
tags: services
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# The dev queue copies prod timing and serialization semantics
|
|
9
|
+
|
|
10
|
+
`InMemoryQueueService` (`packages/core/src/services/in-memory-queue-service.ts`)
|
|
11
|
+
is the local/dev queue, and it is deliberately less direct than it could be. It
|
|
12
|
+
schedules jobs on the macrotask queue via `setTimeout` rather than calling the
|
|
13
|
+
worker inline, it redelivers a failed job up to `options.attempts` times with
|
|
14
|
+
backoff, and it JSON round-trips every payload on the way in.
|
|
15
|
+
|
|
16
|
+
Each is there so dev does not teach a false lesson. Inline dispatch would make
|
|
17
|
+
enqueue synchronous, and code written against that ordering breaks the first time
|
|
18
|
+
it meets a real queue. Dropping a job on its first error would hide that a
|
|
19
|
+
transiently-failing workflow step recovers fine on pg-boss or BullMQ. And every
|
|
20
|
+
real backend puts the job on a wire — an SQS body, a Redis value, a `jsonb`
|
|
21
|
+
column — so the worker never receives the caller's live object; round-tripping
|
|
22
|
+
here means a payload carrying a `Date`, a class instance or a shared mutable
|
|
23
|
+
reference fails in dev rather than in production. Callers cannot know which
|
|
24
|
+
backend they are talking to, so they must not have to serialise defensively.
|
|
25
|
+
|
|
26
|
+
**What this rules out:** "optimising" the dev queue by invoking the handler
|
|
27
|
+
directly, skipping the JSON copy for speed, or short-circuiting retries. Its job
|
|
28
|
+
is fidelity, not throughput. (Separately, the detached `setTimeout` makes this
|
|
29
|
+
service unusable on Lambda or Workers, where the container freezes at response
|
|
30
|
+
time — it is a dev service by construction, not just by name.)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: The embedding model is pinned per service and doc/query embedding is split
|
|
4
|
+
description: AIEmbeddingService fixes its model at construction so index and query share a vector space, and separates embedDocuments from embedQuery for asymmetric models
|
|
5
|
+
tags: services
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# The embedding model is pinned per service and doc/query embedding is split
|
|
9
|
+
|
|
10
|
+
`AIEmbeddingService` (`packages/core/src/services/ai-embedding-service.ts`) is a
|
|
11
|
+
deliberately narrow interface with two properties that look like restrictions.
|
|
12
|
+
The model is `readonly` and fixed at construction rather than passed per call,
|
|
13
|
+
and documents and queries go through separate methods.
|
|
14
|
+
|
|
15
|
+
Both are about comparability. Vector stores (Qdrant, Pinecone, pgvector) embed at
|
|
16
|
+
index time and again at query time; if those two moments can name different
|
|
17
|
+
models they end up in different vector spaces, and similarity search does not
|
|
18
|
+
error — it silently returns nonsense. Pinning the model to the service makes the
|
|
19
|
+
drift unrepresentable. The split methods exist because several embedding models
|
|
20
|
+
are asymmetric and must know which side they are embedding to produce comparable
|
|
21
|
+
vectors: Cohere's `input_type`, E5's `query:` / `passage:` prefixes, BGE's query
|
|
22
|
+
instruction. Symmetric providers such as OpenAI simply point both methods at the
|
|
23
|
+
same call.
|
|
24
|
+
|
|
25
|
+
**What this rules out:** adding a per-call `model` parameter, collapsing
|
|
26
|
+
`embedDocuments` and `embedQuery` into one `embed`, and pointing a vector store
|
|
27
|
+
at `AIAgentRunnerService.embed` / `embedMany` instead — those take a per-call
|
|
28
|
+
model on purpose and drag in the whole agent-runner tool loop, and they give back
|
|
29
|
+
neither guarantee.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: The in-memory workflow service is inline-only and single-process
|
|
4
|
+
description: InMemoryWorkflowService wires no queues and implements withRunLock/withStepLock as pass-throughs, because inline execution has no second holder to exclude
|
|
5
|
+
tags: services
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# The in-memory workflow service is inline-only and single-process
|
|
9
|
+
|
|
10
|
+
`InMemoryWorkflowService` (`packages/core/src/services/in-memory-workflow-service.ts`)
|
|
11
|
+
calls `super({ ...options, wireQueues: false })` and implements `withRunLock` and
|
|
12
|
+
`withStepLock` as bare `return fn()`. Both look like unfinished work and neither
|
|
13
|
+
is.
|
|
14
|
+
|
|
15
|
+
Every step runs inline in the process that started the run: there are no queue
|
|
16
|
+
workers, so no other worker can be mid-step on the same run, and all state lives
|
|
17
|
+
in this instance's `Map`s, so no other process can see it to contend for it. A
|
|
18
|
+
lock would be excluding a competitor that cannot exist. It is offered for CLI
|
|
19
|
+
tools that want step orchestration, for tests, and for single-process apps that
|
|
20
|
+
do not need persistence — and the run state is unbounded and lost on restart,
|
|
21
|
+
which is the price of that.
|
|
22
|
+
|
|
23
|
+
**What this rules out:** treating the no-op locks as a bug and adding real
|
|
24
|
+
locking here, and running this service anywhere a second process or a queue
|
|
25
|
+
worker could touch the same run. A deployment that needs either wants a
|
|
26
|
+
persistent `WorkflowService` implementation instead; there is nothing to fix in
|
|
27
|
+
this one.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: The KEK salt is scoped to the key version, not the secret
|
|
4
|
+
description: One stored salt per key version means N secrets cost one derivation, which is the point of envelope encryption
|
|
5
|
+
tags: crypto, storage
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# The KEK salt is scoped to the key version, not the secret
|
|
9
|
+
|
|
10
|
+
Each secret and credential service stores one random salt per `keyVersion`,
|
|
11
|
+
generated on first use and read once — a `secretKekSalts` / `credentialKekSalts`
|
|
12
|
+
table for kysely, a hash field for redis, a document for mongodb. `deriveKEK`
|
|
13
|
+
runs against that salt to produce a `CryptoKey`, which is what
|
|
14
|
+
`wrapDEK`/`unwrapDEK`/`envelope*` accept. The wrapped-DEK blob therefore carries
|
|
15
|
+
no salt of its own: `[iv:12][ct+tag]`.
|
|
16
|
+
|
|
17
|
+
Envelope encryption exists so the expensive derivation happens once and many
|
|
18
|
+
cheap DEK unwraps follow. A per-secret salt destroys that: every
|
|
19
|
+
`envelopeDecrypt` re-derives, so `getSecrets` over 50 rows cost 50 × PBKDF2-600k
|
|
20
|
+
(~2.3s) and rotation cost twice that. Scoping the salt to the key version
|
|
21
|
+
restored the intended shape — one derivation for a bulk read, two for a
|
|
22
|
+
rotation.
|
|
23
|
+
|
|
24
|
+
Keying by version rather than storing a single salt is what lets `getKEK` keep
|
|
25
|
+
serving `previousKey` for older rows during rotation.
|
|
26
|
+
|
|
27
|
+
A salt's job is to defeat precomputation across deployments and passphrases; one
|
|
28
|
+
random salt per deployment per key version achieves that fully. Per-ciphertext
|
|
29
|
+
salt only buys something when each ciphertext might use a different passphrase,
|
|
30
|
+
which is never the case here. Storing the salt rather than taking it as
|
|
31
|
+
configuration keeps it off the operator's plate — it needs to be
|
|
32
|
+
deployment-random, not secret.
|
|
33
|
+
|
|
34
|
+
**What this rules out:** deriving the KEK inside a per-row loop; a salt shared
|
|
35
|
+
across key versions, which would break rotation; a deterministic salt derived
|
|
36
|
+
from the version number, which is the same salt in every deployment and so
|
|
37
|
+
restores the rainbow table; and caching derived keys anywhere but a read-through
|
|
38
|
+
instance map whose source of truth is the store.
|
|
39
|
+
|
|
40
|
+
See [[passphrases-are-stretched-key-material-is-expanded]].
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: The schema service is never stubbed, or tests validate nothing
|
|
4
|
+
description: createStubProxy returns undefined for the schema property so the real schema service is built — a stubbed one turns validation into a silent no-op
|
|
5
|
+
tags: services
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# The schema service is never stubbed, or tests validate nothing
|
|
9
|
+
|
|
10
|
+
`createStubProxy` (`packages/core/src/services/stub-tracker.ts`) is passed as
|
|
11
|
+
`existingServices` to `createSingletonServices`, and its proxy answers every
|
|
12
|
+
property with `tracker.stub(prop)` — every property except `schema`, which
|
|
13
|
+
returns `undefined` so the service factory goes on to construct a real schema
|
|
14
|
+
service.
|
|
15
|
+
|
|
16
|
+
A stub's methods resolve `undefined` and record the call. Applied to
|
|
17
|
+
`validateSchema`, that means validation always "passes": a request missing a
|
|
18
|
+
required field, or carrying a wrong type, sails through. Every scenario that
|
|
19
|
+
believed it was exercising input validation would be asserting on nothing, and
|
|
20
|
+
would keep passing after validation broke. The one-line exception in the proxy is
|
|
21
|
+
what keeps the test suite honest.
|
|
22
|
+
|
|
23
|
+
**What this rules out:** simplifying the `get` trap to `return tracker.stub(prop)`
|
|
24
|
+
for all properties, and adding `schema` to any list of services a scenario is
|
|
25
|
+
allowed to fake. If a scenario needs schema behaviour changed, change the schema,
|
|
26
|
+
not the service.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Trigger declaration is split from trigger source
|
|
4
|
+
description: Triggers are declared everywhere but subscribed only in the trigger worker, so app processes never open the underlying subscription
|
|
5
|
+
tags: trigger
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Trigger declaration is split from trigger source
|
|
9
|
+
|
|
10
|
+
`wireTrigger` and `wireTriggerSource` in
|
|
11
|
+
`packages/core/src/wirings/trigger/trigger-runner.ts` are deliberately two
|
|
12
|
+
separate registrations for the same trigger name. `wireTrigger` declares the
|
|
13
|
+
trigger name and the target pikku function; it is meant to be loaded by every
|
|
14
|
+
process, because the inspector extracts it at build time and every runtime needs
|
|
15
|
+
the name-to-function mapping in `pikkuState(null, 'trigger', 'meta')`.
|
|
16
|
+
`wireTriggerSource` carries the actual subscription implementation
|
|
17
|
+
(`CorePikkuTriggerFunction`, which opens the connection and returns a teardown)
|
|
18
|
+
and is only imported by the trigger worker process.
|
|
19
|
+
|
|
20
|
+
The split exists because the subscription has side effects at import-and-setup
|
|
21
|
+
time — a Redis `subscribe`, a socket, a poller. If every API instance loaded the
|
|
22
|
+
source, every instance would open its own subscription and the trigger would fire
|
|
23
|
+
once per instance instead of once per event. Keeping the source out of the
|
|
24
|
+
general bundle also keeps the trigger's transport dependency out of runtimes that
|
|
25
|
+
never need it. `CoreTriggerSource.name` must therefore match a `wireTrigger`
|
|
26
|
+
name exactly; nothing in the type system enforces that, and a mismatch shows up
|
|
27
|
+
only at `setupTrigger` time as `Trigger source not found`.
|
|
28
|
+
|
|
29
|
+
**What this rules out:** merging `wireTrigger` and `wireTriggerSource` into one
|
|
30
|
+
registration call, re-exporting trigger sources from a package barrel that
|
|
31
|
+
application code imports, or "simplifying" by having `wireTrigger` accept the
|
|
32
|
+
subscription function directly. Any of these pulls the subscription into every
|
|
33
|
+
process and silently multiplies trigger firings by the instance count.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: TypedSecretService caches for the process lifetime
|
|
4
|
+
description: 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
|
|
5
|
+
tags: services
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# TypedSecretService caches for the process lifetime
|
|
9
|
+
|
|
10
|
+
`TypedSecretService` (`packages/core/src/services/typed-secret-service.ts`) keeps
|
|
11
|
+
an in-process `Map` of resolved secrets so callers can read naively without
|
|
12
|
+
hitting the underlying secret service on every call. Only successful reads are
|
|
13
|
+
cached — a miss throws and is not stored, so the cache never memoises a negative
|
|
14
|
+
— and `setSecret` / `deleteSecret` invalidate the key they touch.
|
|
15
|
+
|
|
16
|
+
There is no TTL and no background refresh. One instance is created per
|
|
17
|
+
`createSingletonServices`, which in practice means once per process, so a secret
|
|
18
|
+
rotated out of band is not observed until the process restarts. That is a known
|
|
19
|
+
gap, tracked as pikkujs/pikku#964, not an oversight to rediscover.
|
|
20
|
+
|
|
21
|
+
**What this rules out:** assuming a rotation flow that writes to the secret
|
|
22
|
+
backend takes effect in a running instance — it does not; the deployment has to
|
|
23
|
+
cycle. It also means this cache is not a read-through cache in the usual sense,
|
|
24
|
+
so do not "fix" it by caching misses. Related: the cached values are plaintext
|
|
25
|
+
secrets held on the long-lived singleton services object, which is why a batch
|
|
26
|
+
`getSecrets([...everything])` should be avoided.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Both validators check personas through one shared module, and a persona counts from either the meta or the source
|
|
4
|
+
description: workspace validate and fabric validate are separate implementations, so the persona/actor/knowledge checks live in persona-checks.ts and are called by both — and a persona is counted from the generated meta or a definePersonas() source scan, whichever answers first
|
|
5
|
+
tags: cli, validate, scenarios, personas
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Both validators check personas through one shared module, and a persona counts from either the meta or the source
|
|
9
|
+
|
|
10
|
+
`pikku workspace validate` and `pikku fabric validate` read like one command
|
|
11
|
+
with a flag. They are not. They are two implementations that walk the same
|
|
12
|
+
project and duplicate about eighteen findings between them verbatim —
|
|
13
|
+
`functions-dir-missing` exists twice, character for character, in two files.
|
|
14
|
+
Fabric adds the deploy-shaped checks (themes, frontends, the Cloudflare
|
|
15
|
+
adapter, the `.gitignore` contract); workspace adds the local-development ones
|
|
16
|
+
(`dev.db`, the auth migrations).
|
|
17
|
+
|
|
18
|
+
So a check written into either one is a check half the projects never run. An
|
|
19
|
+
app that never deploys through fabric only ever sees workspace validate; an app
|
|
20
|
+
that does sees fabric validate in CI. The persona checks are the kind that only
|
|
21
|
+
pay off when nobody remembers to ask for them, which means they had to be in
|
|
22
|
+
both. Rather than duplicate them a nineteenth time, they live in
|
|
23
|
+
`persona-checks.ts` and both validators call `runPersonaChecks`. Merging the
|
|
24
|
+
two validators outright is the better fix and a much larger one; this does not
|
|
25
|
+
block it.
|
|
26
|
+
|
|
27
|
+
**A persona counts from either source, and either alone is wrong at a
|
|
28
|
+
predictable moment.** The generated `pikku-personas-meta.gen.json` is empty on
|
|
29
|
+
a fresh clone where codegen has not run, so trusting only it means a warning
|
|
30
|
+
that fires on every new checkout — and a validator that cries wolf gets muted,
|
|
31
|
+
after which it never says anything worth hearing. A source scan for
|
|
32
|
+
`definePersonas(` cannot see personas an addon contributed. Declared by either
|
|
33
|
+
counts as declared.
|
|
34
|
+
|
|
35
|
+
**Everything here is `warn`, never `error`.** A project with no personas is
|
|
36
|
+
under-tested, not broken, and `validate` gating a deploy on it would make the
|
|
37
|
+
first thing anyone does with the check be to remove it. `knowledge-empty` stays
|
|
38
|
+
at the `info` the shared `@pikku/knowledge` package already assigned it rather
|
|
39
|
+
than being raised to match — the severity belongs to that package.
|
|
40
|
+
|
|
41
|
+
**What this rules out:** duplicating the checks into both validators;
|
|
42
|
+
adding them to only one; deriving the persona count from the generated meta
|
|
43
|
+
alone; failing a build over a missing persona.
|
package/knowledge/decisions/internals/webhook-delivery-history-records-every-attempt-best-effort.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Webhook delivery history records every attempt, best effort
|
|
4
|
+
description: The webhook worker persists each attempt before it throws, and a failure to persist is logged rather than allowed to mask the delivery result
|
|
5
|
+
tags: services
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Webhook delivery history records every attempt, best effort
|
|
9
|
+
|
|
10
|
+
`pikkuWebhookWorkerFunc` (`packages/core/src/services/queue-webhook-service.ts`)
|
|
11
|
+
POSTs the delivery, then — when the job carries a `deliveryId` — calls
|
|
12
|
+
`webhookService.recordAttempt` with the outcome *before* throwing on a non-2xx.
|
|
13
|
+
The throw is what makes the queue retry, so recording first is the only way the
|
|
14
|
+
console's delivery history shows every try rather than just the final one.
|
|
15
|
+
|
|
16
|
+
A `deliveryId` is only present when a store-backed implementation (e.g.
|
|
17
|
+
`KyselyWebhookService`) enqueued the job, which is why the queue-only default's
|
|
18
|
+
base `recordAttempt` — which throws `NotImplementedError` — is never reached.
|
|
19
|
+
The `recordAttempt` call is wrapped in `.catch(log)`: history is bookkeeping, and
|
|
20
|
+
a store outage must not turn a delivered webhook into a failed one, nor a failed
|
|
21
|
+
one into an unexplained crash.
|
|
22
|
+
|
|
23
|
+
**What this rules out:** awaiting `recordAttempt` without the catch, moving it
|
|
24
|
+
after the throw, or making the worker's success depend on the store being
|
|
25
|
+
reachable. Equally, do not delete the `.catch` as a swallowed error — the log
|
|
26
|
+
line is the intended handling.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Webhook service collaborators are constructor args, not locator lookups
|
|
4
|
+
description: QueueWebhookService takes its queue as a constructor parameter so a project wiring webhooks without a queue fails to compile instead of at first send
|
|
5
|
+
tags: services
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Webhook service collaborators are constructor args, not locator lookups
|
|
9
|
+
|
|
10
|
+
`QueueWebhookService` (`packages/core/src/services/queue-webhook-service.ts`)
|
|
11
|
+
takes `queueService` as a constructor parameter, even though it reaches for
|
|
12
|
+
`config` and `secrets` through `getSingletonServices()` inside its methods. The
|
|
13
|
+
queue is different on purpose: it is the collaborator without which the class
|
|
14
|
+
cannot do anything at all.
|
|
15
|
+
|
|
16
|
+
A `getSingletonServices()` lookup turns a wiring mistake into a runtime failure
|
|
17
|
+
on the first `send()` — typically in production, typically on the first webhook a
|
|
18
|
+
customer was waiting for. A constructor parameter turns the same mistake into a
|
|
19
|
+
type error at the point where the service is wired.
|
|
20
|
+
|
|
21
|
+
**What this rules out:** "simplifying" the constructor away so the class looks
|
|
22
|
+
like its neighbours and pulls the queue from the service locator like everything
|
|
23
|
+
else. The inconsistency inside this class is the decision, not an oversight; if
|
|
24
|
+
anything the pressure should run the other way, toward making `config` and
|
|
25
|
+
`secrets` constructor args too.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Whether a run is inline is read from the run record
|
|
4
|
+
description: 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
|
|
5
|
+
tags: workflow, state
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Whether a run is inline is read from the run record
|
|
9
|
+
|
|
10
|
+
`PikkuWorkflowService.isInline` resolves `WorkflowRun.inline` from the store and
|
|
11
|
+
caches it on the process-local `runContexts` entry for the duration of the
|
|
12
|
+
execution that is running the step. `registerInlineRun` / `unregisterInlineRun`
|
|
13
|
+
prime and evict that cache; they no longer decide anything. Both callers pass
|
|
14
|
+
the same `shouldInline` to `createRun` that they pass to `registerInlineRun`, so
|
|
15
|
+
the prime is only ever a saved read.
|
|
16
|
+
|
|
17
|
+
`inline` decides two forks: whether a failed step retries in-process or is
|
|
18
|
+
handed to the queue, and whether a sleep blocks here or goes to the
|
|
19
|
+
`schedulerService`. Answering them from a `Map` that only the instance that
|
|
20
|
+
called `startWorkflow` ever populated makes both forks instance-dependent. On
|
|
21
|
+
Lambda, Workers, or any multi-instance container deployment, instance B reads an
|
|
22
|
+
empty map, concludes the run is queued, and dispatches an orchestrator job for a
|
|
23
|
+
run instance A is already driving in-process — two executors on one run. The
|
|
24
|
+
durable field is the only thing every instance can agree on.
|
|
25
|
+
|
|
26
|
+
`isInline` is therefore `async`. Its four call sites — `inlineStep` and
|
|
27
|
+
`scheduleSleep` in core, `dispatchStep` and `scheduleSleep` in the Cloudflare
|
|
28
|
+
Durable Object service — were already `async`, so nothing had to become
|
|
29
|
+
asynchronous to accommodate it. Resolving it through `getRunIdentity` means a
|
|
30
|
+
run job that already read its run pays no second read, and caching the answer on
|
|
31
|
+
the context bounds a step worker to one read. `WorkflowRun.inline` is written
|
|
32
|
+
once at `createRun` and never mutated, so a cached value cannot go stale.
|
|
33
|
+
|
|
34
|
+
The same entry carries per-replay ordinals, the last step name, and the step
|
|
35
|
+
snapshot. Those are genuinely process-local — they exist to give
|
|
36
|
+
`name`, `name#1`, `name#2` to repeated reaches of one logical step within a
|
|
37
|
+
single walk of a workflow, and to let a replay read its rows once. Their
|
|
38
|
+
lifetime is now an explicit `activeExecutions` count incremented by
|
|
39
|
+
`runWorkflowJob` and by `executeWorkflowStep` and decremented in their `finally`
|
|
40
|
+
blocks; the entry is deleted when the count reaches zero, and a terminal
|
|
41
|
+
`updateRunStatus` that arrives mid-execution defers to that. Previously
|
|
42
|
+
`nextStepKey` lazily created a `replay` object on every step invocation while
|
|
43
|
+
`releaseContext` refused to free any entry that had one, so any step reached
|
|
44
|
+
outside a `beginReplay` bracket — a graph node's RPC using its workflow wire
|
|
45
|
+
from the step-worker queue — stranded an ordinals map and a step-state snapshot
|
|
46
|
+
for the life of the process.
|
|
47
|
+
|
|
48
|
+
Resetting ordinals per execution rather than letting them accumulate across
|
|
49
|
+
separate step-worker invocations also makes step naming independent of how the
|
|
50
|
+
work happened to be distributed. Two step workers in one process used to see
|
|
51
|
+
different ordinals than the same two workers on different instances.
|
|
52
|
+
|
|
53
|
+
**What this rules out:** answering `isInline` from the map alone and defaulting
|
|
54
|
+
to `false` on a miss, which is the split-brain; a synchronous `isInline` backed
|
|
55
|
+
by a cache nothing guarantees is populated; keeping a run's entry alive because
|
|
56
|
+
a value is cached in it, since a cache that is never evicted is a leak; and
|
|
57
|
+
mutating `WorkflowRun.inline` after creation, which the cache is only safe
|
|
58
|
+
because nothing does.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Workflow approval expiry is decided from a recorded deadline, not from a timer firing
|
|
4
|
+
description: The wake-up job is best-effort liveness; losing, duplicating or delaying it cannot change the gate's answer
|
|
5
|
+
tags: workflow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Workflow approval expiry is decided from a recorded deadline, not from a timer firing
|
|
9
|
+
|
|
10
|
+
On its first reach, `approvalStep` in `pikku-workflow-service.ts` stamps
|
|
11
|
+
`expiresAt` into the gate's run-state record and calls `scheduleRunWake`. Every
|
|
12
|
+
later replay decides expiry by comparing `Date.now()` against that recorded
|
|
13
|
+
deadline. A duplicate, late, or entirely dropped timer therefore all produce the
|
|
14
|
+
same answer, and losing the wake costs liveness — the run sits until something
|
|
15
|
+
else resumes it — never correctness.
|
|
16
|
+
|
|
17
|
+
`scheduleRunWake` deliberately enqueues a delayed *orchestrator* pass rather
|
|
18
|
+
than reusing `scheduleSleep`. `scheduleSleep` resolves the step it is given,
|
|
19
|
+
which for an approval would resolve the gate itself; the wake only nudges the
|
|
20
|
+
run to replay and re-evaluate, leaving the gate the sole judge of its own
|
|
21
|
+
outcome. It is wrapped in a try/catch that logs and continues, because a
|
|
22
|
+
scheduling failure must not fail the run.
|
|
23
|
+
|
|
24
|
+
An approval returns an `ApprovalOutcome` union (`decided` | `expired`) rather
|
|
25
|
+
than throwing on the deadline, so callers are forced to handle expiry and "skip
|
|
26
|
+
it and carry on" stays trivial. `decided` means a human answered — whether the
|
|
27
|
+
answer was yes or no rides in `data` and is the application's business.
|
|
28
|
+
|
|
29
|
+
**What this rules out:** treating the timer's delivery as the expiry signal,
|
|
30
|
+
routing the wake through `scheduleSleep` or any path that writes the gate's step
|
|
31
|
+
result, letting a `scheduleRunWake` failure propagate, or turning expiry into a
|
|
32
|
+
thrown error. Expiry also fires unconditionally once enqueued — a durable timer
|
|
33
|
+
cannot be retracted — so the replay must no-op it when a decision has already
|
|
34
|
+
landed.
|