@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,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: CLI unknown long options warn instead of failing
|
|
4
|
+
description: Unrecognised --long options are accepted, warned about and dropped so older binaries tolerate newer invocations, while unknown short flags stay hard errors
|
|
5
|
+
tags: cli
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# CLI unknown long options warn instead of failing
|
|
9
|
+
|
|
10
|
+
`warnUnknownOption` in `packages/core/src/wirings/cli/command-parser.ts` pushes
|
|
11
|
+
onto `ParsedCommand.warnings`, not `ParsedCommand.errors`, so an unrecognised
|
|
12
|
+
`--long` option does not abort the command. The value is still parsed into
|
|
13
|
+
`optionArgs`, but `pluckCLIData` in `cli-runner.ts` drops anything absent from
|
|
14
|
+
the function's input schema — so the option is silently ignored at execution
|
|
15
|
+
time. The warning exists precisely so that dropping is not silent.
|
|
16
|
+
|
|
17
|
+
The reason is forward compatibility: a script or wrapper written against a newer
|
|
18
|
+
command version may pass options an older installed binary does not know, and
|
|
19
|
+
failing hard there turns a harmless extra flag into a broken pipeline.
|
|
20
|
+
`RESERVED_OPTIONS` exempts flags the runner handles itself (`help`) from the
|
|
21
|
+
warning. Unknown *short* flags are treated differently — they go to
|
|
22
|
+
`result.errors` and do fail — because a bundled short-flag cluster like `-abc`
|
|
23
|
+
cannot be reliably attributed, and a typo'd short flag is far more likely than a
|
|
24
|
+
version skew.
|
|
25
|
+
|
|
26
|
+
**What this rules out:** promoting unknown long options to errors "for
|
|
27
|
+
strictness", and removing the warning on the grounds that the schema pluck
|
|
28
|
+
already handles it — that restores the silent drop this was added to end. It also
|
|
29
|
+
rules out making unknown short flags non-fatal for symmetry.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: A column's at-rest form is an axis of its own
|
|
4
|
+
description: How a value is stored is independent of how sensitive it is, so form carries a required nominal brand on writes while classification stays optional on reads
|
|
5
|
+
tags: core
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# A column's at-rest form is an axis of its own
|
|
9
|
+
|
|
10
|
+
`ColumnForm` in `packages/core/src/data-classification.ts` is a second,
|
|
11
|
+
independent annotation on a column: `plain | hashed | wrapped | sealed`. It
|
|
12
|
+
answers "how are these bytes held?", where `Classification` answers "may this
|
|
13
|
+
value leave the process?".
|
|
14
|
+
|
|
15
|
+
The two axes were one field before this, with `security: 'encrypted'` sitting
|
|
16
|
+
alongside `secret` as though they were alternatives. They are not, and the
|
|
17
|
+
conflation made the field unanswerable: a token hash and a live bearer token are
|
|
18
|
+
both `secret`, one must never be encrypted — the digest *is* the lookup key —
|
|
19
|
+
and the other must always be. Nothing in a single enum could tell them apart, so
|
|
20
|
+
nothing could check either.
|
|
21
|
+
|
|
22
|
+
## Why `wrapped` and `sealed` rather than `encrypted`
|
|
23
|
+
|
|
24
|
+
Sealed values *are* encrypted, so an `encrypted` member sitting beside `sealed`
|
|
25
|
+
would be a supertype posing as a sibling, and every new column would be an
|
|
26
|
+
even-odds guess. What actually separates them is who can read the value back:
|
|
27
|
+
`wrapped` is symmetric and the application holds the key; `sealed` is asymmetric
|
|
28
|
+
and the application holds only the public half. Writing one where the other
|
|
29
|
+
belongs produces a row nobody can ever open, which is why the type system is
|
|
30
|
+
made to know the difference.
|
|
31
|
+
|
|
32
|
+
## Why these brands are required when `Secret<T>` is optional
|
|
33
|
+
|
|
34
|
+
`WrappedValue`, `SealedValue` and `HashedValue` are `string & { readonly [sym]:
|
|
35
|
+
true }` with a `unique symbol` — nominal, and **required**, which
|
|
36
|
+
[the classification-brand decision](core-data-classification-brand-is-an-optional-property.md)
|
|
37
|
+
explicitly rules out for `Private`/`Pii`/`Secret`. That decision still stands and
|
|
38
|
+
this does not weaken it. It applies to a different side of a different set of
|
|
39
|
+
columns:
|
|
40
|
+
|
|
41
|
+
- `Secret<T>` brands **every** classified column's SELECT type. A required brand
|
|
42
|
+
there would break `where('email', '=', someString)` in every downstream
|
|
43
|
+
project.
|
|
44
|
+
- A form brands **only** the INSERT/UPDATE type, and only on the columns that
|
|
45
|
+
opt in by declaring a form. There is nothing to break, because a column
|
|
46
|
+
without a form generates exactly what it generated before.
|
|
47
|
+
|
|
48
|
+
The brands compose rather than compete: a wrapped secret column selects as
|
|
49
|
+
`Secret<WrappedValue>`, so the inspector's PKU910 check still finds
|
|
50
|
+
`__classification__`, while a row read back is already a `WrappedValue` and
|
|
51
|
+
flows into a rewrap or re-seal without a cast.
|
|
52
|
+
|
|
53
|
+
Each brand widens to `string`, so query operands, serialization and template
|
|
54
|
+
literals are unaffected. The constraint is on **construction**: the only way to
|
|
55
|
+
produce one is `envelopeEncrypt`/`envelopeRewrap`/`wrapDEK` (wrapped) or
|
|
56
|
+
`hashToken` (hashed), or the deliberately-named `unsafeAs*` assertions in
|
|
57
|
+
`column-form.ts` for the three cases a bare string legitimately arrives —
|
|
58
|
+
backfill migrations, test fixtures, and values sealed by another service.
|
|
59
|
+
|
|
60
|
+
## What is deliberately NOT enforced
|
|
61
|
+
|
|
62
|
+
`envelopeDecrypt` and `unwrapDEK` take plain `string`, not the brand. Requiring
|
|
63
|
+
it would buy nothing — feeding in the wrong string already fails at the AEAD tag
|
|
64
|
+
— while forcing a cast into every path that reads ciphertext out of a row or off
|
|
65
|
+
the wire, which is where casts are least reviewable.
|
|
66
|
+
|
|
67
|
+
The brand proves *provenance*, not correctness. It cannot know a value was
|
|
68
|
+
wrapped under the right key, and making it know would mean phantom-typing key
|
|
69
|
+
ids per scope, which the multi-recipient path would fight constantly.
|
|
70
|
+
|
|
71
|
+
## The plain-secret diagnostic
|
|
72
|
+
|
|
73
|
+
A `secret` column with no declared form raises **PKU483** as a warning, not an
|
|
74
|
+
error. Every project predating the axis has such columns, and failing their next
|
|
75
|
+
`db migrate` would be a breaking change for a diagnosis they have not had a
|
|
76
|
+
chance to act on. `pikku db --fail-on-warn` is how a project opts into the
|
|
77
|
+
ratchet. An explicit `form: 'plain'` silences it — that is the acknowledgement
|
|
78
|
+
that reading the row is *meant* to yield a usable credential.
|
|
79
|
+
|
|
80
|
+
**What this rules out:** collapsing `wrapped` and `sealed` back into one
|
|
81
|
+
`encrypted`; making the form brands optional (they would enforce nothing);
|
|
82
|
+
re-declaring them in generated schema files, since a local `unique symbol` is a
|
|
83
|
+
distinct nominal type and core's own ciphertext would not be assignable to the
|
|
84
|
+
column it belongs in — `db-codegen` imports them from `@pikku/core` instead.
|
package/knowledge/decisions/internals/core-data-classification-brand-is-an-optional-property.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: The data-classification brand is an optional property
|
|
4
|
+
description: Making __classification__ required would break ordinary Kysely operands, so the brand only constrains values flowing out
|
|
5
|
+
tags: core
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# The data-classification brand is an optional property
|
|
9
|
+
|
|
10
|
+
`Private<T>`, `Pii<T>` and `Secret<T>` in
|
|
11
|
+
`packages/core/src/data-classification.ts` brand a type with
|
|
12
|
+
`{ readonly __classification__?: 'private' | 'pii' | 'secret' }` — and the
|
|
13
|
+
marker is **optional on purpose**.
|
|
14
|
+
|
|
15
|
+
A required property would make a plain value unassignable to a branded column: a
|
|
16
|
+
`string` could no longer be passed where `Private<string>` is expected, which
|
|
17
|
+
breaks every ordinary Kysely query operand — `where('email', '=', someString)`,
|
|
18
|
+
inserts, and `.set(...)`. Making it optional keeps the brand structurally present
|
|
19
|
+
so static analysis still sees it, while letting plain values flow *in*. The
|
|
20
|
+
asymmetry is the point: the brand constrains what comes out of a query, not what
|
|
21
|
+
goes into one.
|
|
22
|
+
|
|
23
|
+
The consumer is `@pikku/inspector`, whose `findPiiPaths` reads the level union
|
|
24
|
+
directly and whose PKU910 output check detects the brand on a function's return
|
|
25
|
+
type. The brands are populated from the hand-authored `db/annotations.ts`
|
|
26
|
+
(`DbClassificationMap`) via `pikku db migrate`, which regenerates
|
|
27
|
+
`outDir/db/schema.d.ts` and `outDir/db/classification.gen.ts`.
|
|
28
|
+
|
|
29
|
+
A column's **at-rest form** is a separate axis making the opposite trade — see
|
|
30
|
+
[form is an axis of its own](core-column-form-is-an-axis-of-its-own.md). Its
|
|
31
|
+
brands are nominal and required, which is safe precisely because they land on
|
|
32
|
+
the INSERT/UPDATE side of the columns that opt in, rather than on the SELECT
|
|
33
|
+
side of every classified column. That is not an exception to the rule below; it
|
|
34
|
+
is a different rule about a different side.
|
|
35
|
+
|
|
36
|
+
**What this rules out:** making `__classification__` required to get stronger
|
|
37
|
+
guarantees, or replacing the optional property with a unique symbol / nominal
|
|
38
|
+
brand that behaves like a required one. Either change compiles here and then
|
|
39
|
+
breaks every generated Kysely call site in every downstream project. It also
|
|
40
|
+
rules out renaming the property or narrowing its literal union without updating
|
|
41
|
+
`findPiiPaths` in the inspector, which matches on both.
|
package/knowledge/decisions/internals/core-function-runner-restores-the-wire-fields-it-overwrites.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: The function runner restores the wire fields it overwrites
|
|
4
|
+
description: One wire object is reused across nested calls, so functionId, audit, addonNamespace and rpc are saved and put back in a finally
|
|
5
|
+
tags: core
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# The function runner restores the wire fields it overwrites
|
|
9
|
+
|
|
10
|
+
`runPikkuFunc` in `packages/core/src/function/function-runner.ts` does not build a
|
|
11
|
+
fresh wire per call. Nested invocations — an RPC from inside a function, an addon
|
|
12
|
+
sibling call, a workflow step — reuse the *same* wire object the outer transport
|
|
13
|
+
created. So before it runs, the runner captures `functionId`, `audit`,
|
|
14
|
+
`addonNamespace` and the property descriptor for `rpc`, overwrites them for the
|
|
15
|
+
duration of this function, and restores or `delete`s them in a `finally`. Both
|
|
16
|
+
the middleware path and the direct path carry that restore block. Without it, an
|
|
17
|
+
inner call would leave its identity on the wire and every subsequent outer step
|
|
18
|
+
would be attributed to the wrong function.
|
|
19
|
+
|
|
20
|
+
The same reuse is why the audit binding is re-gated inside `executeFunction`
|
|
21
|
+
rather than trusted from `createWireServices`. The audit *gate* is per-function
|
|
22
|
+
but the `auditLog` wire service is created per-transport-invocation. A nested or
|
|
23
|
+
exposed-RPC call would otherwise inherit an `auditLog` built while the outer
|
|
24
|
+
wire's audit config was unset (the generated `rpcCaller` declares none), and
|
|
25
|
+
every write from the audited inner function would be silently dropped. The runner
|
|
26
|
+
compares config identity (`services.auditLog?.config !== resolvedAuditConfig`)
|
|
27
|
+
and binds a fresh invocation audit when they differ, then closes it in the
|
|
28
|
+
`finally` before wire services are closed.
|
|
29
|
+
|
|
30
|
+
Authorization order in `executeFunction` is also deliberate: session resolution,
|
|
31
|
+
then the auth/readonly checks, then `verifyScopes` — all of which depend only on
|
|
32
|
+
the session — and only then `await data()`, schema defaults, coercion, validation
|
|
33
|
+
and `runPermissions`. A request denied by scope never pays to parse or validate
|
|
34
|
+
its body. `rpc` is installed as a lazily-evaluating accessor that replaces itself
|
|
35
|
+
with the resolved value on first read, capturing the *caller's* package name in
|
|
36
|
+
the closure so an addon's RPCs resolve in its own namespace.
|
|
37
|
+
|
|
38
|
+
**What this rules out:** dropping the save/restore blocks as duplicated
|
|
39
|
+
boilerplate, or "hoisting" them into a single wrapper that only runs on the
|
|
40
|
+
outermost call. It rules out moving `verifyScopes` down next to `runPermissions`
|
|
41
|
+
for tidiness — that reintroduces body parsing for denied requests. And it rules
|
|
42
|
+
out taking `services.auditLog` at face value when the function declares audit;
|
|
43
|
+
the identity check is the only thing distinguishing an inherited disabled
|
|
44
|
+
instance from one built for this invocation.
|
package/knowledge/decisions/internals/core-hot-reload-merges-generated-meta-never-replaces-it.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Hot reload merges generated meta and never replaces it
|
|
4
|
+
description: Reloading codegen output must preserve runtime-registered meta, which no generated JSON contains
|
|
5
|
+
tags: core
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Hot reload merges generated meta and never replaces it
|
|
9
|
+
|
|
10
|
+
`reloadGeneratedMeta` in `packages/core/src/dev/reload-meta.ts` re-reads the
|
|
11
|
+
codegen output (`.pikku/**/*.gen.json`) straight into `pikkuState` after each dev
|
|
12
|
+
codegen pass. It reads the JSON directly rather than re-importing the generated
|
|
13
|
+
`*-meta.gen.ts` wrappers because the ESM cache pins both the wrapper and its JSON
|
|
14
|
+
import, so a re-import returns the stale value.
|
|
15
|
+
|
|
16
|
+
For `function.meta` and `queue.meta` it merges over the existing map instead of
|
|
17
|
+
assigning. Framework internals are registered at service-init time and appear in
|
|
18
|
+
no generated file: `pikkuWorkflowOrchestrator` and the per-workflow
|
|
19
|
+
`wf-orchestrator-*` / `wf-step-*` queue workers are added by
|
|
20
|
+
`pikku-workflow-service.ts`. A wholesale replace drops them, and the next
|
|
21
|
+
workflow job fails with `Function meta not found: pikkuWorkflowOrchestrator`.
|
|
22
|
+
`dev/reload-meta.test.ts` pins this. Meta maps that only codegen ever writes
|
|
23
|
+
(`http`, `rpc`, `agent`) are assigned outright.
|
|
24
|
+
|
|
25
|
+
Two limits are inherent rather than incidental. Routes registered by a *new*
|
|
26
|
+
`wireHTTP` file are not picked up here — those modules were never imported — which
|
|
27
|
+
is why `hot-reload.ts` keeps a `postCodegenQueue` and exposes `reimportPending()`
|
|
28
|
+
for the dev server to drain after codegen, so registrations that were skipped for
|
|
29
|
+
missing meta run again against fresh meta. And `reconcileAddonRegistry` has to
|
|
30
|
+
prune `addons.packages` explicitly, because hot reload only ever re-imports files
|
|
31
|
+
that still exist, so a deleted `*.addon.ts` would otherwise leave its `wireAddon`
|
|
32
|
+
entry stranded until a restart.
|
|
33
|
+
|
|
34
|
+
**What this rules out:** replacing the two merges with plain
|
|
35
|
+
`pikkuState(null, 'function', 'meta', functionsMeta)` assignments on the grounds
|
|
36
|
+
that codegen output is authoritative — it is authoritative only for what codegen
|
|
37
|
+
emits. It also rules out folding `reimportPending()` back into the debounced
|
|
38
|
+
reload (the whole point is that it runs *after* codegen), and dropping
|
|
39
|
+
`reconcileAddonRegistry` as dead code.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Hot reload owns its module registry instead of re-importing
|
|
4
|
+
description: Dev reload transpiles to CJS and runs modules through vm.compileFunction, because the native ESM loader map cannot be evicted
|
|
5
|
+
tags: core
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Hot reload owns its module registry instead of re-importing
|
|
9
|
+
|
|
10
|
+
`packages/core/src/dev/module-runner.ts` re-runs a changed user file by
|
|
11
|
+
transpiling it to CJS with esbuild, executing it via `vm.compileFunction`, and
|
|
12
|
+
storing the resulting exports under a **stable absolute-path key**. A reload
|
|
13
|
+
overwrites that one registry slot, so the previous module becomes unreachable and
|
|
14
|
+
is collected. `packages/core/src/dev/hot-reload.ts` drives it from the file
|
|
15
|
+
watcher.
|
|
16
|
+
|
|
17
|
+
The obvious alternative — re-`import()`ing the file under a fresh URL (a `data:`
|
|
18
|
+
URL on Node, a uniquely-named temp sibling on Bun) — is unbounded. The native ESM
|
|
19
|
+
loader keeps a `Map<url, moduleRecord>` for the life of the realm with no
|
|
20
|
+
eviction API, so every reload permanently leaks a module record; measured at
|
|
21
|
+
roughly 0.3–1.3 MB per edit, which is ~84 MB on Node and ~222 MB on Bun over 200
|
|
22
|
+
edits, and eventually OOMs a long editing session. `dev/module-runner.test.ts`
|
|
23
|
+
asserts both the single-slot guarantee and bounded heap growth.
|
|
24
|
+
|
|
25
|
+
Two details keep the mechanism honest. `import`s inside the user file are
|
|
26
|
+
delegated to `createRequire`, whose resolution matches the native loader *and*
|
|
27
|
+
returns the same live singletons (Node and Bun share the require/import cache) —
|
|
28
|
+
that is what lets a reloaded file's top-level `wireHTTP` side effects mutate the
|
|
29
|
+
services the running server is already using. And esbuild is invoked with no
|
|
30
|
+
sourcemap: an inline sourcemap embeds a base64 copy of the source that the engine
|
|
31
|
+
retains per compile, reintroducing exactly the linear growth this runner exists
|
|
32
|
+
to remove. The known limitation is that a file using top-level `await` cannot be
|
|
33
|
+
emitted as CJS; `run` returns `null` and the caller keeps the previously loaded
|
|
34
|
+
code.
|
|
35
|
+
|
|
36
|
+
**What this rules out:** "simplifying" the reloader back to `await
|
|
37
|
+
import(url + '?t=' + Date.now())` or any fresh-URL variant, and turning
|
|
38
|
+
sourcemaps back on for nicer stack traces (`filename` already anchors traces to
|
|
39
|
+
the user file). It also rules out swapping `createRequire` for a fresh `import()`
|
|
40
|
+
inside the compiled module — resolution would produce a *distinct* copy of every
|
|
41
|
+
dependency, and the reloaded file would then wire itself into services nobody is
|
|
42
|
+
serving from.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Middleware order is resolution scope first, then priority
|
|
4
|
+
description: Middleware is collected global to function, then stably sorted by priority, deduped, frozen and cached per wire
|
|
5
|
+
tags: core
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Middleware order is resolution scope first, then priority
|
|
9
|
+
|
|
10
|
+
`combineMiddleware` in `packages/core/src/middleware-runner.ts` builds the chain
|
|
11
|
+
for a wire by appending, in this order: global middleware
|
|
12
|
+
(`addGlobalMiddleware`), then wire-inherited entries (the HTTP route group, then
|
|
13
|
+
tag groups resolved parent-first by `getTagGroups`, then named wire middleware),
|
|
14
|
+
then inline wire middleware, then function-inherited tag groups, then inline
|
|
15
|
+
function middleware. That collected array is then stably sorted by
|
|
16
|
+
`MiddlewarePriority` — `highest` (0) runs first and outermost, `lowest` (4) runs
|
|
17
|
+
last and innermost, closest to the function, with `medium` the default — and
|
|
18
|
+
finally passed through `freezeDedupe` and cached in `middlewareCache` keyed by
|
|
19
|
+
wire type and wire id.
|
|
20
|
+
|
|
21
|
+
Two properties fall out of that and both are load-bearing. Because the sort is
|
|
22
|
+
stable, priority is a coarse band and registration order breaks ties *within* a
|
|
23
|
+
band, so declaration order still means something. And because the result is
|
|
24
|
+
deduped by function identity, a middleware reachable through both a tag group and
|
|
25
|
+
a direct wire registration runs exactly once — a fact several tests assert
|
|
26
|
+
directly. `runMiddleware` re-sorts only when `isSortedByPriority` says the input
|
|
27
|
+
is not already ordered, which is why the cached array must never be handed back
|
|
28
|
+
unsorted.
|
|
29
|
+
|
|
30
|
+
The cache is why `clearMiddlewareCache()` exists and why dev hot-reload calls it
|
|
31
|
+
alongside `clearPermissionsCache()`, `clearChannelMiddlewareCache()` and
|
|
32
|
+
`httpRouter.reset()` on every reload.
|
|
33
|
+
|
|
34
|
+
**What this rules out:** switching `sortByPriority` to a comparator that is not
|
|
35
|
+
stable, or to a sort that runs before the scope-ordered collection — either one
|
|
36
|
+
silently reorders same-priority middleware and breaks the "declaration order
|
|
37
|
+
wins within a band" contract. It also rules out dropping `freezeDedupe` as
|
|
38
|
+
redundant (a tag-plus-wire registration would then run twice), and rules out
|
|
39
|
+
caching by wire id alone without clearing on reload.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Schema defaults are applied on every transport, not just HTTP
|
|
4
|
+
description: Defaults belong to the schema rather than the call's encoding, so they run unconditionally and are cloned per request
|
|
5
|
+
tags: core
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Schema defaults are applied on every transport, not just HTTP
|
|
9
|
+
|
|
10
|
+
`applyDefaultsFromSchema` in `packages/core/src/schema.ts` fills in absent
|
|
11
|
+
top-level properties from their JSON Schema `default`, and the function runner
|
|
12
|
+
calls it **unconditionally** — before coercion, before validation, on every wire
|
|
13
|
+
type.
|
|
14
|
+
|
|
15
|
+
It exists because a `default` reaches the generated JSON Schema and keeps the
|
|
16
|
+
property out of `required`, so omitting it validates. But JSON Schema validators
|
|
17
|
+
are pure by specification, and none of the ones Pikku ships with
|
|
18
|
+
(`@cfworker/json-schema`, and Ajv unless `useDefaults` is set) annotate the
|
|
19
|
+
instance. The function therefore received `undefined` for a property its
|
|
20
|
+
generated TypeScript type declares as present — the worst shape a mismatch can
|
|
21
|
+
take: validation permits the omission, the type promises the value, the body
|
|
22
|
+
reads `undefined`.
|
|
23
|
+
|
|
24
|
+
It is deliberately *not* gated on the `coerceDataFromSchema` flag that guards
|
|
25
|
+
`coerceTopLevelDataFromSchema`. That flag is about decoding transport-encoded
|
|
26
|
+
values — a query string's `"1,2"` into an array, an ISO string into a `Date` —
|
|
27
|
+
and is set only by transports that need it. Defaults are a property of the
|
|
28
|
+
schema, not of how the call arrived, so gating them on that flag would apply them
|
|
29
|
+
over HTTP and skip them on a direct RPC invocation. Two smaller rules follow: a
|
|
30
|
+
non-null primitive body is returned untouched for the validator to reject rather
|
|
31
|
+
than reshaped into something that would pass; and each value is
|
|
32
|
+
`structuredClone`d, so an object or array default (`[]`, `{}`) is never shared as
|
|
33
|
+
one mutable instance across every request. The result object is allocated only
|
|
34
|
+
once a default is actually found, which is what lets a call made with no
|
|
35
|
+
arguments at all still receive them.
|
|
36
|
+
|
|
37
|
+
**What this rules out:** moving the `applyDefaultsFromSchema` call inside the
|
|
38
|
+
`if (coerceDataFromSchema)` branch next to the coercion call, or reordering it
|
|
39
|
+
after validation. It also rules out dropping the `structuredClone` as an
|
|
40
|
+
allocation — the shared-mutable-default bug it prevents is cross-request and
|
|
41
|
+
`schema.test.ts` pins it — and rules out replacing the `'default' in property`
|
|
42
|
+
presence check with a truthiness check, since `false` and `0` are exactly the
|
|
43
|
+
defaults a truthiness check silently discards.
|
package/knowledge/decisions/internals/core-scopes-are-an-and-gate-separate-from-permissions.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Scopes are an AND gate, separate from permissions
|
|
4
|
+
description: Every declared scope must be held, so adding one can only narrow access — permissions OR, and can only widen it
|
|
5
|
+
tags: core
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Scopes are an AND gate, separate from permissions
|
|
9
|
+
|
|
10
|
+
`packages/core/src/scopes.ts` implements the scope check that
|
|
11
|
+
`runPikkuFunc` performs before permissions. Every entry in a function's `scopes`
|
|
12
|
+
must be satisfied by the session's grants — an AND gate — and the check fails
|
|
13
|
+
closed: a session without a `scopes` field, or no session at all, satisfies
|
|
14
|
+
nothing. An empty `required` is the only thing anything satisfies.
|
|
15
|
+
|
|
16
|
+
This is deliberately the opposite composition from `permissions`, whose groups OR
|
|
17
|
+
together. Because permissions OR, adding a permission group can only *widen*
|
|
18
|
+
access; because scopes AND, adding a scope can only *narrow* it. That is the
|
|
19
|
+
whole reason the two are separate mechanisms and separate code paths rather than
|
|
20
|
+
one merged authorization step, and it is why a passing global or function
|
|
21
|
+
permission must never be allowed to satisfy a scope.
|
|
22
|
+
|
|
23
|
+
Satisfaction itself is hierarchical, computed by `satisfyingGrants`: a grant
|
|
24
|
+
matches when it is the scope itself, a plain ancestor (`admin` covers
|
|
25
|
+
`admin:invoices:create`), a wildcard at or above it (`admin:*`, or the bare `*`),
|
|
26
|
+
or a wildcard directly beneath it. Narrower never satisfies broader —
|
|
27
|
+
`admin:invoices` does not grant `admin`. Core only ever *reads*
|
|
28
|
+
`session.scopes`; whoever builds the session populates it (better-auth's
|
|
29
|
+
`mapSession` resolving through a `ScopeService`, for instance), and the runner
|
|
30
|
+
never fetches. `hasScopes` is the non-throwing counterpart of `verifyScopes`, for
|
|
31
|
+
gates that fall back to another check rather than rejecting outright.
|
|
32
|
+
|
|
33
|
+
**What this rules out:** folding the scope check into `runPermissions` so there
|
|
34
|
+
is "one authorization step", or making an OR of scopes so a session holding any
|
|
35
|
+
one of them passes. Either turns a narrowing gate into a widening one, which is a
|
|
36
|
+
privilege escalation and not a refactor. It also rules out defaulting an absent
|
|
37
|
+
`session.scopes` to "all" for convenience, and rules out having core resolve
|
|
38
|
+
scopes itself at call time.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Pikku state is a global map written only at registration time
|
|
4
|
+
description: A symbol-keyed globalThis map holds the wiring registry; nothing per-request may ever be written to it
|
|
5
|
+
tags: core
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Pikku state is a global map written only at registration time
|
|
9
|
+
|
|
10
|
+
`packages/core/src/pikku-state.ts` keeps every registry Pikku has —
|
|
11
|
+
functions, HTTP routes, channels, schedulers, queues, workflows, triggers, MCP
|
|
12
|
+
tools, agents, gateways, CLI programs, middleware groups, permissions, schemas
|
|
13
|
+
and error definitions — in a single `Map<string, PikkuPackageState>` hung off
|
|
14
|
+
`globalThis` under `Symbol('@pikku/core/state')`. `pikkuState(packageName, type,
|
|
15
|
+
content, value?)` is the only accessor; `PikkuPackageState` in
|
|
16
|
+
`packages/core/src/types/state.types.ts` is its shape.
|
|
17
|
+
|
|
18
|
+
It is on `globalThis` rather than in a module-level `const` because a bundled
|
|
19
|
+
app can end up with more than one copy of `@pikku/core` in the module graph
|
|
20
|
+
(workspace links, addon packages that depend on their own core, a runtime
|
|
21
|
+
adapter pulling a second instance). Module-level state would give each copy its
|
|
22
|
+
own empty registry and functions would go missing at call time; a symbol on the
|
|
23
|
+
realm global is shared by every copy in that realm. The package-name dimension
|
|
24
|
+
is what keeps addon registries from colliding with the host project's.
|
|
25
|
+
|
|
26
|
+
Everything written here is written **once, at import time**, by `wireHTTP`,
|
|
27
|
+
`addFunction`, `addTagMiddleware`, `addError`, `addSchema` and friends — that is,
|
|
28
|
+
by the top-level side effects of the generated and user modules. It is
|
|
29
|
+
registration data, not request data. Pikku must stay stateless and
|
|
30
|
+
serverless-compatible: the same process serves concurrent invocations on Lambda,
|
|
31
|
+
Workers and multi-instance containers, and nothing in a request may outlive it.
|
|
32
|
+
The file reads like a violation of that rule until you know the writes are all
|
|
33
|
+
registration-time. The one exception is deliberate and narrow:
|
|
34
|
+
`resetPikkuState()` preserves the `misc.errors` map across a reset, because error
|
|
35
|
+
definitions are registered by module-import side effects that will not re-run.
|
|
36
|
+
|
|
37
|
+
**What this rules out:** using `pikkuState` as a convenient place to stash
|
|
38
|
+
anything derived from an invocation — a session, a request-scoped cache, a
|
|
39
|
+
pending workflow, a "current user". Any such write is shared across every
|
|
40
|
+
concurrent request in the process and lost entirely on the next cold start. It
|
|
41
|
+
also rules out replacing the `globalThis` symbol with a module-scoped `Map` "for
|
|
42
|
+
cleanliness", and rules out making the state per-request (an `AsyncLocalStorage`
|
|
43
|
+
context, say) — the registry is read on hot paths by the function runner and the
|
|
44
|
+
routers, and it must be identical for every caller.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Email meta is read uncached because codegen rewrites it mid-session
|
|
4
|
+
description: getEmailMeta re-reads its file on every call, unlike every other meta accessor, because the file appears and changes during a long-lived session
|
|
5
|
+
tags: services
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Email meta is read uncached because codegen rewrites it mid-session
|
|
9
|
+
|
|
10
|
+
`LocalMetaService.getEmailMeta` (`packages/core/src/services/meta-service.ts`)
|
|
11
|
+
reads `email/pikku-emails-meta.gen.json` fresh on every call. Every other
|
|
12
|
+
`getXMeta` on that class memoises into a private cache field; this one
|
|
13
|
+
deliberately does not.
|
|
14
|
+
|
|
15
|
+
The email meta file is written by `pikku all` / `pikku emails generate`, and in a
|
|
16
|
+
long-lived session it is regenerated underneath a running process — the sandbox
|
|
17
|
+
boots the orchestrator before the user project's codegen has produced it. When
|
|
18
|
+
this accessor was cached, the first call landed before the file existed, cached
|
|
19
|
+
the empty `{ templates: {} }` fallback, and the console's emails screen stayed
|
|
20
|
+
blank for the rest of the session even after the file appeared. A local JSON
|
|
21
|
+
read is essentially free, so re-reading is the cheaper mistake.
|
|
22
|
+
|
|
23
|
+
**What this rules out:** "consistency" refactors that give every meta accessor
|
|
24
|
+
the same caching treatment, including the one that collapses the ~25 hand-written
|
|
25
|
+
`getXMeta` methods and their cache fields into a single generic
|
|
26
|
+
`cached(key, loader)` helper. Email meta must stay outside whatever cache that
|
|
27
|
+
introduces.
|
package/knowledge/decisions/internals/gateway-adapters-resolve-lazily-and-are-promise-cached.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Gateway adapters resolve lazily and are promise-cached
|
|
4
|
+
description: wireGateway accepts an adapter factory because real adapters need boot-time secrets, which forces the webhook GET route to be registered unconditionally
|
|
5
|
+
tags: gateway
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Gateway adapters resolve lazily and are promise-cached
|
|
9
|
+
|
|
10
|
+
`wireGateway` runs at module load, before secrets and services exist. Real
|
|
11
|
+
platform adapters (WhatsApp Cloud API, Slack, …) need both, so
|
|
12
|
+
`CoreGateway.adapter` accepts a `GatewayAdapterFactory` as well as an instance.
|
|
13
|
+
`resolveGatewayAdapter` in
|
|
14
|
+
`packages/core/src/wirings/gateway/gateway-runner.ts` invokes the factory on the
|
|
15
|
+
first inbound request (webhook/websocket) or on gateway start (listener). The
|
|
16
|
+
`resolvedAdapters` WeakMap caches the *promise*, not the resolved adapter, so
|
|
17
|
+
concurrent first requests share one construction instead of racing to build two
|
|
18
|
+
adapters — which for a stateful adapter would mean two platform connections.
|
|
19
|
+
|
|
20
|
+
The lazy resolution has one visible consequence in `wireWebhookGateway`: a
|
|
21
|
+
factory cannot be probed for `verifyWebhook` at wiring time, because it has not
|
|
22
|
+
run yet. The GET verification route is therefore registered unconditionally
|
|
23
|
+
whenever the adapter is a function, and only conditionally
|
|
24
|
+
(`adapter.verifyWebhook`) when it is a concrete instance. The GET handler throws
|
|
25
|
+
`NotFoundError` at request time if the resolved adapter turns out not to support
|
|
26
|
+
verification.
|
|
27
|
+
|
|
28
|
+
**What this rules out:** calling the factory eagerly inside `wireGateway` to
|
|
29
|
+
"simplify" route registration, caching the resolved adapter instead of the
|
|
30
|
+
promise, and narrowing the GET route registration to `adapter.verifyWebhook` for
|
|
31
|
+
all adapters — the last silently drops webhook verification for every
|
|
32
|
+
factory-based gateway.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Gateway webhook challenges echo bytes not JSON
|
|
4
|
+
description: String verification challenges are returned raw with returnsJSON false, because platforms byte-compare the echo and JSON quoting fails the handshake
|
|
5
|
+
tags: gateway
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Gateway webhook challenges echo bytes not JSON
|
|
9
|
+
|
|
10
|
+
Webhook verification handshakes (WhatsApp's `hub.challenge`, similar GET
|
|
11
|
+
challenges elsewhere) are validated by the platform doing a byte-for-byte
|
|
12
|
+
comparison of the response body against the challenge it sent. JSON-encoding a
|
|
13
|
+
string challenge adds surrounding quotes and fails the handshake, and the gateway
|
|
14
|
+
is then never activated.
|
|
15
|
+
|
|
16
|
+
`wireWebhookGateway` in
|
|
17
|
+
`packages/core/src/wirings/gateway/gateway-runner.ts` therefore registers the GET
|
|
18
|
+
verification route with `returnsJSON: false`, and
|
|
19
|
+
`createWebhookVerifyHandler` returns `String(response)` when the adapter's
|
|
20
|
+
`WebhookVerificationResult.response` is a string or number. Object responses
|
|
21
|
+
(Slack's `url_verification` style) still go out as JSON, with the
|
|
22
|
+
`content-type: application/json` header set explicitly by the handler, since the
|
|
23
|
+
route no longer does it.
|
|
24
|
+
|
|
25
|
+
**What this rules out:** setting `returnsJSON: true` on the gateway GET route for
|
|
26
|
+
consistency with other routes, and routing the challenge response through the
|
|
27
|
+
normal JSON serializer. Any change that makes the string branch serialize as JSON
|
|
28
|
+
breaks webhook activation on every platform that byte-compares.
|
package/knowledge/decisions/internals/gateway-wiring-is-a-meta-wiring-over-http-and-channels.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Gateway wiring is a meta-wiring over HTTP and channels
|
|
4
|
+
description: wireGateway writes handler implementations into the HTTP and channel state directly while the inspector compiles the corresponding meta, so runtime registration deliberately writes no meta
|
|
5
|
+
tags: gateway
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Gateway wiring is a meta-wiring over HTTP and channels
|
|
9
|
+
|
|
10
|
+
`wireGateway` in `packages/core/src/wirings/gateway/gateway-runner.ts` is not a
|
|
11
|
+
transport of its own. It composes the existing primitives: a `webhook` gateway
|
|
12
|
+
pushes entries straight into `pikkuState(null, 'http', 'routes')`, a `websocket`
|
|
13
|
+
gateway pushes into `pikkuState(null, 'channel', 'meta')` and `'channels'`, and a
|
|
14
|
+
`listener` gateway registers no route at all and is driven by a
|
|
15
|
+
`GatewayService` calling `createListenerMessageHandler`. Each mutation is
|
|
16
|
+
followed by `httpRouter.reset()` because the router caches its match table.
|
|
17
|
+
|
|
18
|
+
The wrapper functions and routes created here look like they are missing their
|
|
19
|
+
metadata. They are not: the inspector projects a `wireGateway` call into the
|
|
20
|
+
generated HTTP and function meta at build time, so only the handler
|
|
21
|
+
*implementations* register at runtime — the same split every other wire uses.
|
|
22
|
+
This is why `wireWebhookGateway` writes route entries but no `CommonWireMeta`,
|
|
23
|
+
and why the websocket path sets `channels.set(name, …)` with empty
|
|
24
|
+
`onConnect`/`onMessage` stubs while the real handlers live under the
|
|
25
|
+
`gateway__<name>__connect` / `__message` function ids named in the channel meta.
|
|
26
|
+
|
|
27
|
+
**What this rules out:** adding runtime meta generation inside `wireGateway` to
|
|
28
|
+
"fix" the apparently missing metadata — it would duplicate or conflict with the
|
|
29
|
+
compiled meta. It also rules out replacing the empty channel `onConnect` /
|
|
30
|
+
`onMessage` stubs with the real handler functions; the channel runner dispatches
|
|
31
|
+
through the meta's `pikkuFuncId`, not through those fields.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Generated src paths in pikku meta are absolute
|
|
4
|
+
description: emailsMeta.src is resolved by the CLI at generation time, so reading through the project-relative helpers produces a wrong compound path
|
|
5
|
+
tags: services
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Generated src paths in pikku meta are absolute
|
|
9
|
+
|
|
10
|
+
`emailsMeta.src` is written by the CLI at generation time and is already an
|
|
11
|
+
absolute filesystem path. `LocalMetaService.getEmailTemplateAssets`
|
|
12
|
+
(`packages/core/src/services/meta-service.ts`) therefore calls `readFile` on
|
|
13
|
+
`join(baseDir, rel)` directly instead of going through its own
|
|
14
|
+
`readProjectFile`, which is the helper every other read in that class uses.
|
|
15
|
+
|
|
16
|
+
`readProjectFile` prepends the project root (`join(basePath, '..', relativePath)`).
|
|
17
|
+
Handing it an already-absolute `src` yields a compound path that points nowhere,
|
|
18
|
+
and the failure is silent — the helpers return `null` on a missing file, so the
|
|
19
|
+
symptom is a template that reports itself as having no assets rather than an
|
|
20
|
+
error naming the path.
|
|
21
|
+
|
|
22
|
+
**What this rules out:** routing the email asset reads through `readProjectFile`
|
|
23
|
+
or `readFile` "for consistency", and assuming that any `src` field appearing in a
|
|
24
|
+
`.gen.json` is relative to the project. If a remote `MetaService` ever needs to
|
|
25
|
+
serve these assets, it has to translate the absolute path rather than pass it
|
|
26
|
+
through.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: HTTP request bodies are read once and shared between consumers
|
|
4
|
+
description: The fetch request wrapper memoises the single-use body and builds web Requests lazily, at the cost of holding the whole body in memory
|
|
5
|
+
tags: http
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# HTTP request bodies are read once and shared between consumers
|
|
9
|
+
|
|
10
|
+
A fetch `Request` body is a single-use stream: the second reader gets "Body has
|
|
11
|
+
already been used". `PikkuFetchHTTPRequest` in
|
|
12
|
+
`packages/core/src/wirings/http/pikku-fetch-http-request.ts` therefore funnels
|
|
13
|
+
`json()`, `arrayBuffer()`, `data()` and everything reached through
|
|
14
|
+
`toWebRequest()` into `#readRawBuffer`, which memoises both the in-flight promise
|
|
15
|
+
and the resolved buffer. A second consumer arriving while the first read is still
|
|
16
|
+
running is served the same promise — and warned, because a duplicate consumer is
|
|
17
|
+
a bug to remove at the source rather than a case to lean on the cache for.
|
|
18
|
+
|
|
19
|
+
`toWebRequest` in `packages/core/src/wirings/http/web-request.ts` builds its body
|
|
20
|
+
stream with `pull` rather than `start`, so the underlying body is touched only
|
|
21
|
+
when the stream is actually consumed. A caller that constructs a web `Request`
|
|
22
|
+
purely to read headers — session middleware calling `getSession({ headers })` is
|
|
23
|
+
the common case — performs zero body I/O and cannot race the route handler's own
|
|
24
|
+
read. Its fallback path exists because some runtimes (Express with a body-parser
|
|
25
|
+
in front) hand pikku a request whose raw body is already drained; there
|
|
26
|
+
`arrayBuffer()` is empty and the body has to be reconstructed from the parsed
|
|
27
|
+
form or JSON.
|
|
28
|
+
|
|
29
|
+
**What this rules out:** calling `request.arrayBuffer()`/`request.json()` on the
|
|
30
|
+
underlying fetch `Request` directly anywhere in the runner; switching the
|
|
31
|
+
`toWebRequest` stream to `start` for eagerness; and deleting the empty-buffer
|
|
32
|
+
reconstruction branch as an impossible case.
|