@pikku/core 0.12.72 → 0.12.74
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +793 -0
- package/dist/crypto-utils.d.ts +30 -5
- package/dist/crypto-utils.js +146 -41
- package/dist/dev/hot-reload.js +11 -30
- package/dist/dev/module-runner.d.ts +3 -7
- package/dist/dev/module-runner.js +4 -10
- package/dist/dev/reload-meta.d.ts +8 -20
- package/dist/dev/reload-meta.js +9 -29
- package/dist/errors/error-handler.d.ts +5 -30
- package/dist/errors/error-handler.js +16 -32
- package/dist/errors/errors.d.ts +32 -151
- package/dist/errors/errors.js +55 -157
- package/dist/function/abort-scope.d.ts +47 -0
- package/dist/function/abort-scope.js +63 -0
- package/dist/function/function-runner.js +37 -32
- package/dist/function/functions.types.d.ts +44 -136
- package/dist/function/functions.types.js +0 -58
- package/dist/function/list.types.d.ts +12 -62
- package/dist/function/list.types.js +4 -25
- package/dist/handle-error.d.ts +0 -13
- package/dist/handle-error.js +0 -18
- package/dist/index.d.ts +5 -2
- package/dist/index.js +4 -1
- package/dist/middleware/auth-apikey.d.ts +3 -18
- package/dist/middleware/auth-apikey.js +0 -17
- package/dist/middleware/auth-bearer.d.ts +6 -41
- package/dist/middleware/auth-bearer.js +3 -40
- package/dist/middleware/auth-cookie.d.ts +5 -27
- package/dist/middleware/auth-cookie.js +2 -26
- package/dist/middleware/cors.d.ts +7 -34
- package/dist/middleware/cors.js +7 -34
- package/dist/middleware/remote-auth.d.ts +3 -1
- package/dist/middleware/remote-auth.js +3 -2
- package/dist/middleware/telemetry.d.ts +8 -33
- package/dist/middleware/telemetry.js +2 -31
- package/dist/middleware-runner.d.ts +4 -55
- package/dist/middleware-runner.js +5 -74
- package/dist/permissions.d.ts +3 -44
- package/dist/permissions.js +19 -71
- package/dist/pikku-request.d.ts +0 -6
- package/dist/pikku-request.js +0 -6
- package/dist/pikku-state.d.ts +0 -26
- package/dist/pikku-state.js +2 -30
- package/dist/remote.d.ts +3 -5
- package/dist/remote.js +8 -7
- package/dist/schema.d.ts +5 -39
- package/dist/schema.js +5 -39
- package/dist/scopes.d.ts +4 -23
- package/dist/scopes.js +7 -48
- package/dist/services/ai-agent-runner-service.d.ts +20 -0
- package/dist/services/ai-embedding-service.d.ts +2 -25
- package/dist/services/audit-service.js +1 -2
- package/dist/services/content-service.d.ts +1 -46
- package/dist/services/credential-service.d.ts +3 -40
- package/dist/services/deployment-service.d.ts +3 -9
- package/dist/services/gateway-service.d.ts +0 -15
- package/dist/services/http-personas.d.ts +80 -0
- package/dist/services/http-personas.js +233 -0
- package/dist/services/in-memory-queue-service.d.ts +0 -14
- package/dist/services/in-memory-queue-service.js +1 -15
- package/dist/services/in-memory-trigger-service.d.ts +0 -18
- package/dist/services/in-memory-trigger-service.js +1 -18
- package/dist/services/in-memory-workflow-service.d.ts +0 -16
- package/dist/services/in-memory-workflow-service.js +4 -33
- package/dist/services/index.d.ts +5 -6
- package/dist/services/index.js +2 -5
- package/dist/services/istanbul-coverage-service.d.ts +1 -5
- package/dist/services/istanbul-coverage-service.js +2 -8
- package/dist/services/jwt-service.d.ts +1 -16
- package/dist/services/local-content.d.ts +13 -2
- package/dist/services/local-content.js +40 -13
- package/dist/services/local-gateway-service.d.ts +0 -16
- package/dist/services/local-gateway-service.js +2 -17
- package/dist/services/local-secrets.d.ts +0 -4
- package/dist/services/local-secrets.js +0 -4
- package/dist/services/logger-console.d.ts +3 -7
- package/dist/services/logger-console.js +3 -7
- package/dist/services/logger.d.ts +2 -37
- package/dist/services/meta-service.d.ts +23 -26
- package/dist/services/meta-service.js +22 -36
- package/dist/services/personas-service.d.ts +134 -0
- package/dist/services/personas-service.js +40 -0
- package/dist/services/pikku-user-id.js +0 -4
- package/dist/services/queue-webhook-service.d.ts +2 -36
- package/dist/services/queue-webhook-service.js +9 -41
- package/dist/services/scheduler-service.d.ts +1 -50
- package/dist/services/scheduler-service.js +0 -10
- package/dist/services/schema-service.d.ts +1 -24
- package/dist/services/scope-service.d.ts +49 -34
- package/dist/services/scoped-secret-service.d.ts +0 -4
- package/dist/services/scoped-secret-service.js +0 -4
- package/dist/services/secret-host-binding.d.ts +8 -0
- package/dist/services/secret-host-binding.js +36 -0
- package/dist/services/secret-service.d.ts +5 -33
- package/dist/services/secretless.d.ts +6 -0
- package/dist/services/secretless.js +21 -0
- package/dist/services/stub-tracker.d.ts +7 -18
- package/dist/services/stub-tracker.js +8 -18
- package/dist/services/system-role-guard.d.ts +33 -0
- package/dist/services/system-role-guard.js +38 -0
- package/dist/services/trigger-service.d.ts +0 -12
- package/dist/services/typed-secret-service.d.ts +0 -7
- package/dist/services/typed-secret-service.js +1 -7
- package/dist/services/v8-coverage-service.d.ts +2 -3
- package/dist/services/v8-coverage-service.js +1 -2
- package/dist/services/variables-service.d.ts +1 -8
- package/dist/services/webhook-service.d.ts +19 -63
- package/dist/services/webhook-service.js +6 -20
- package/dist/services/workflow-service.d.ts +3 -15
- package/dist/testing/service-tests.js +0 -17
- package/dist/time-utils.d.ts +0 -16
- package/dist/time-utils.js +1 -19
- package/dist/types/core.types.d.ts +99 -219
- package/dist/types/core.types.js +0 -42
- package/dist/types/state.types.d.ts +4 -9
- package/dist/utils/hmac.d.ts +4 -10
- package/dist/utils/hmac.js +4 -10
- package/dist/utils/safe-fetch.d.ts +7 -35
- package/dist/utils/safe-fetch.js +13 -53
- package/dist/utils.d.ts +1 -6
- package/dist/utils.js +6 -15
- package/dist/wirings/actor-flow/actor-flow.types.d.ts +1 -34
- package/dist/wirings/actor-flow/index.d.ts +0 -9
- package/dist/wirings/actor-flow/run-conversation.d.ts +5 -5
- package/dist/wirings/actor-flow/run-conversation.js +14 -7
- package/dist/wirings/ai-agent/ai-agent-agui.d.ts +0 -5
- package/dist/wirings/ai-agent/ai-agent-agui.js +34 -12
- package/dist/wirings/ai-agent/ai-agent-helpers.d.ts +7 -0
- package/dist/wirings/ai-agent/ai-agent-helpers.js +7 -0
- package/dist/wirings/ai-agent/ai-agent-interrupt.d.ts +153 -0
- package/dist/wirings/ai-agent/ai-agent-interrupt.js +256 -0
- package/dist/wirings/ai-agent/ai-agent-memory.js +0 -2
- package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +0 -9
- package/dist/wirings/ai-agent/ai-agent-model-config.js +1 -9
- package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +10 -99
- package/dist/wirings/ai-agent/ai-agent-prepare.js +58 -131
- package/dist/wirings/ai-agent/ai-agent-registry.d.ts +2 -1
- package/dist/wirings/ai-agent/ai-agent-registry.js +5 -1
- package/dist/wirings/ai-agent/ai-agent-runner.js +49 -20
- package/dist/wirings/ai-agent/ai-agent-stream.d.ts +25 -2
- package/dist/wirings/ai-agent/ai-agent-stream.js +153 -63
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +84 -4
- package/dist/wirings/ai-agent/index.d.ts +6 -4
- package/dist/wirings/ai-agent/index.js +5 -4
- package/dist/wirings/ai-agent/voice-input.d.ts +39 -1
- package/dist/wirings/ai-agent/voice-input.js +46 -3
- package/dist/wirings/ai-agent/voice-output.d.ts +54 -1
- package/dist/wirings/ai-agent/voice-output.js +153 -50
- package/dist/wirings/channel/channel-common.d.ts +7 -20
- package/dist/wirings/channel/channel-common.js +7 -21
- package/dist/wirings/channel/channel-handler.js +25 -6
- package/dist/wirings/channel/channel-host-rpc.d.ts +25 -0
- package/dist/wirings/channel/channel-host-rpc.js +38 -0
- package/dist/wirings/channel/channel-middleware-runner.d.ts +0 -12
- package/dist/wirings/channel/channel-middleware-runner.js +0 -12
- package/dist/wirings/channel/channel-rpc-registry.d.ts +31 -0
- package/dist/wirings/channel/channel-rpc-registry.js +89 -0
- package/dist/wirings/channel/channel-rpc-responder.d.ts +15 -0
- package/dist/wirings/channel/channel-rpc-responder.js +71 -0
- package/dist/wirings/channel/channel-rpc-service.d.ts +40 -0
- package/dist/wirings/channel/channel-rpc-service.js +106 -0
- package/dist/wirings/channel/channel-rpc-validators.d.ts +14 -0
- package/dist/wirings/channel/channel-rpc-validators.js +30 -0
- package/dist/wirings/channel/channel-rpc.d.ts +5 -0
- package/dist/wirings/channel/channel-rpc.js +5 -0
- package/dist/wirings/channel/channel-rpc.types.d.ts +90 -0
- package/dist/wirings/channel/channel-rpc.types.js +50 -0
- package/dist/wirings/channel/channel-runner.d.ts +0 -4
- package/dist/wirings/channel/channel-runner.js +0 -14
- package/dist/wirings/channel/channel-store.d.ts +0 -10
- package/dist/wirings/channel/channel.types.d.ts +12 -1
- package/dist/wirings/channel/define-channel-routes.d.ts +0 -20
- package/dist/wirings/channel/define-channel-routes.js +0 -20
- package/dist/wirings/channel/eventhub-service.d.ts +0 -18
- package/dist/wirings/channel/index.d.ts +4 -1
- package/dist/wirings/channel/index.js +2 -0
- package/dist/wirings/channel/local/local-channel-runner.js +3 -1
- package/dist/wirings/channel/local/local-eventhub-service.d.ts +0 -33
- package/dist/wirings/channel/local/local-eventhub-service.js +2 -36
- package/dist/wirings/channel/log-channels.d.ts +0 -4
- package/dist/wirings/channel/log-channels.js +0 -4
- package/dist/wirings/channel/pikku-abstract-channel-handler.js +6 -0
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +2 -5
- package/dist/wirings/cli/channel/cli-approval.d.ts +41 -0
- package/dist/wirings/cli/channel/cli-approval.js +81 -0
- package/dist/wirings/cli/channel/cli-channel-runner.d.ts +0 -4
- package/dist/wirings/cli/channel/cli-channel-runner.js +3 -25
- package/dist/wirings/cli/channel/cli-raw-channel-runner.d.ts +47 -9
- package/dist/wirings/cli/channel/cli-raw-channel-runner.js +24 -16
- package/dist/wirings/cli/channel/cli-raw-client-runner.d.ts +20 -0
- package/dist/wirings/cli/channel/cli-raw-client-runner.js +121 -0
- package/dist/wirings/cli/channel/index.d.ts +4 -0
- package/dist/wirings/cli/channel/index.js +2 -0
- package/dist/wirings/cli/cli-runner.d.ts +20 -20
- package/dist/wirings/cli/cli-runner.js +28 -89
- package/dist/wirings/cli/cli.types.d.ts +14 -3
- package/dist/wirings/cli/command-parser.d.ts +1 -10
- package/dist/wirings/cli/command-parser.js +10 -87
- package/dist/wirings/cli/define-cli-commands.d.ts +1 -17
- package/dist/wirings/cli/define-cli-commands.js +1 -17
- package/dist/wirings/credential/credential.types.d.ts +0 -12
- package/dist/wirings/credential/define-credential.d.ts +48 -0
- package/dist/wirings/credential/define-credential.js +47 -0
- package/dist/wirings/credential/index.d.ts +1 -1
- package/dist/wirings/credential/index.js +1 -1
- package/dist/wirings/credential/validate-credential-definitions.d.ts +2 -4
- package/dist/wirings/gateway/gateway-runner.d.ts +1 -20
- package/dist/wirings/gateway/gateway-runner.js +8 -105
- package/dist/wirings/gateway/gateway.types.d.ts +7 -80
- package/dist/wirings/http/http-routes.d.ts +0 -63
- package/dist/wirings/http/http-routes.js +0 -63
- package/dist/wirings/http/http-runner.d.ts +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 +28 -0
- package/dist/wirings/persona/define-personas.js +27 -0
- package/dist/wirings/persona/index.d.ts +21 -0
- package/dist/wirings/persona/index.js +17 -0
- package/dist/wirings/persona/persona-email.d.ts +37 -0
- package/dist/wirings/persona/persona-email.js +69 -0
- package/dist/wirings/persona/persona-environments.d.ts +45 -0
- package/dist/wirings/persona/persona-environments.js +81 -0
- package/dist/wirings/persona/persona-mailbox.d.ts +101 -0
- package/dist/wirings/persona/persona-mailbox.js +53 -0
- package/dist/wirings/persona/persona.types.d.ts +125 -0
- package/dist/wirings/persona/persona.types.js +1 -0
- package/dist/wirings/persona/validate-personas.d.ts +53 -0
- package/dist/wirings/persona/validate-personas.js +94 -0
- package/dist/wirings/queue/index.d.ts +3 -0
- package/dist/wirings/queue/index.js +2 -3
- package/dist/wirings/queue/queue-identity.d.ts +28 -0
- package/dist/wirings/queue/queue-identity.js +102 -0
- package/dist/wirings/queue/queue-runner.d.ts +0 -19
- package/dist/wirings/queue/queue-runner.js +9 -30
- package/dist/wirings/queue/queue.types.d.ts +18 -89
- package/dist/wirings/queue/register-queue-helper.d.ts +0 -12
- package/dist/wirings/queue/register-queue-helper.js +0 -11
- package/dist/wirings/queue/signed-queue-service.d.ts +16 -0
- package/dist/wirings/queue/signed-queue-service.js +42 -0
- package/dist/wirings/queue/validate-worker-config.d.ts +2 -23
- package/dist/wirings/queue/validate-worker-config.js +0 -14
- package/dist/wirings/role/define-system-role.d.ts +32 -0
- package/dist/wirings/role/define-system-role.js +31 -0
- package/dist/wirings/role/index.d.ts +3 -0
- package/dist/wirings/role/index.js +2 -0
- package/dist/wirings/role/role.types.d.ts +43 -0
- package/dist/wirings/role/role.types.js +1 -0
- package/dist/wirings/role/validate-role-definitions.d.ts +21 -0
- package/dist/wirings/role/validate-role-definitions.js +71 -0
- package/dist/wirings/rpc/addon-runner.d.ts +0 -19
- package/dist/wirings/rpc/addon-runner.js +0 -51
- package/dist/wirings/rpc/remote-addon-auth.d.ts +1 -12
- package/dist/wirings/rpc/remote-addon-auth.js +1 -9
- package/dist/wirings/rpc/rpc-runner.d.ts +11 -18
- package/dist/wirings/rpc/rpc-runner.js +88 -105
- package/dist/wirings/rpc/rpc-types.d.ts +7 -6
- package/dist/wirings/rpc/wire-addon.d.ts +25 -0
- package/dist/wirings/rpc/wire-addon.js +62 -0
- package/dist/wirings/rpc/wire-remote-addon.d.ts +3 -28
- package/dist/wirings/rpc/wire-remote-addon.js +0 -8
- package/dist/wirings/scheduler/log-schedulers.d.ts +0 -4
- package/dist/wirings/scheduler/log-schedulers.js +0 -4
- package/dist/wirings/scheduler/scheduler-runner.d.ts +0 -1
- package/dist/wirings/scheduler/scheduler-runner.js +0 -1
- package/dist/wirings/scheduler/scheduler.types.d.ts +1 -14
- package/dist/wirings/scope/define-scope.d.ts +32 -0
- package/dist/wirings/scope/define-scope.js +31 -0
- package/dist/wirings/scope/index.d.ts +1 -1
- package/dist/wirings/scope/index.js +1 -1
- package/dist/wirings/scope/scope.types.d.ts +7 -9
- package/dist/wirings/scope/validate-scope-definitions.d.ts +2 -21
- package/dist/wirings/scope/validate-scope-definitions.js +3 -21
- package/dist/wirings/secret/index.d.ts +1 -1
- package/dist/wirings/secret/index.js +1 -1
- package/dist/wirings/secret/secret.types.d.ts +19 -15
- package/dist/wirings/secret/secret.types.js +1 -1
- package/dist/wirings/secret/validate-secret-definitions.d.ts +2 -4
- package/dist/wirings/trigger/trigger-runner.d.ts +0 -27
- package/dist/wirings/trigger/trigger-runner.js +1 -24
- package/dist/wirings/trigger/trigger.types.d.ts +1 -82
- package/dist/wirings/trigger/trigger.types.js +0 -34
- package/dist/wirings/variable/index.d.ts +1 -1
- package/dist/wirings/variable/index.js +1 -1
- package/dist/wirings/variable/validate-variable-definitions.d.ts +2 -4
- package/dist/wirings/variable/variable.types.d.ts +1 -13
- package/dist/wirings/variable/variable.types.js +1 -1
- package/dist/wirings/virtual-user/index.d.ts +27 -0
- package/dist/wirings/virtual-user/index.js +8 -0
- package/dist/wirings/virtual-user/run-virtual-user.d.ts +92 -0
- package/dist/wirings/virtual-user/run-virtual-user.js +478 -0
- package/dist/wirings/virtual-user/virtual-user-agents.d.ts +38 -0
- package/dist/wirings/virtual-user/virtual-user-agents.js +24 -0
- package/dist/wirings/virtual-user/virtual-user-catalogue.d.ts +92 -0
- package/dist/wirings/virtual-user/virtual-user-catalogue.js +134 -0
- package/dist/wirings/virtual-user/virtual-user-derive.d.ts +26 -0
- package/dist/wirings/virtual-user/virtual-user-derive.js +137 -0
- package/dist/wirings/virtual-user/virtual-user-dispositions.d.ts +79 -0
- package/dist/wirings/virtual-user/virtual-user-dispositions.js +128 -0
- package/dist/wirings/virtual-user/virtual-user-intents.d.ts +78 -0
- package/dist/wirings/virtual-user/virtual-user-intents.js +142 -0
- package/dist/wirings/virtual-user/virtual-user-rng.d.ts +24 -0
- package/dist/wirings/virtual-user/virtual-user-rng.js +44 -0
- package/dist/wirings/virtual-user/virtual-user-target.d.ts +21 -0
- package/dist/wirings/virtual-user/virtual-user-target.js +34 -0
- package/dist/wirings/virtual-user/virtual-user.types.d.ts +199 -0
- package/dist/wirings/virtual-user/virtual-user.types.js +8 -0
- package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +5 -5
- package/dist/wirings/workflow/dsl/workflow-runner.d.ts +0 -4
- package/dist/wirings/workflow/dsl/workflow-runner.js +0 -4
- package/dist/wirings/workflow/feature.d.ts +0 -19
- package/dist/wirings/workflow/feature.js +0 -19
- package/dist/wirings/workflow/graph/graph-node.d.ts +0 -98
- package/dist/wirings/workflow/graph/graph-node.js +0 -34
- package/dist/wirings/workflow/graph/graph-runner.js +6 -41
- package/dist/wirings/workflow/graph/wire-workflow-graph.d.ts +0 -4
- package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +0 -58
- package/dist/wirings/workflow/graph/workflow-graph.types.js +0 -6
- package/dist/wirings/workflow/index.d.ts +5 -7
- package/dist/wirings/workflow/index.js +3 -17
- package/dist/wirings/workflow/pikku-scenario-service.d.ts +87 -5
- package/dist/wirings/workflow/pikku-scenario-service.js +204 -42
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +7 -459
- package/dist/wirings/workflow/pikku-workflow-service.js +58 -551
- package/dist/wirings/workflow/run-timeline.d.ts +0 -47
- package/dist/wirings/workflow/run-timeline.js +0 -22
- package/dist/wirings/workflow/scenario-cookie-jar.d.ts +0 -23
- package/dist/wirings/workflow/scenario-cookie-jar.js +0 -16
- package/dist/wirings/workflow/scenario-poll.d.ts +0 -15
- package/dist/wirings/workflow/scenario-poll.js +0 -12
- package/dist/wirings/workflow/scenario-prose.d.ts +0 -28
- package/dist/wirings/workflow/scenario-prose.js +0 -18
- package/dist/wirings/workflow/scenario-step-guards.d.ts +0 -13
- package/dist/wirings/workflow/scenario-step-guards.js +1 -14
- package/dist/wirings/workflow/scenario-step.types.d.ts +72 -6
- package/dist/wirings/workflow/scenario-step.types.js +5 -1
- package/dist/wirings/workflow/scenario-surface.d.ts +16 -0
- package/dist/wirings/workflow/scenario-surface.js +56 -0
- package/dist/wirings/workflow/workflow-invocation-id.d.ts +0 -18
- package/dist/wirings/workflow/workflow-invocation-id.js +2 -22
- package/dist/wirings/workflow/workflow-queue-workers.d.ts +0 -20
- package/dist/wirings/workflow/workflow-queue-workers.js +0 -19
- package/dist/wirings/workflow/workflow.types.d.ts +0 -197
- package/knowledge/decisions/index.md +19 -0
- package/knowledge/decisions/internals/a-secret-that-fails-to-decrypt-fails-the-whole-read.md +49 -0
- package/knowledge/decisions/internals/actor-flow-conversations-seed-a-hidden-kickoff-message.md +23 -0
- package/knowledge/decisions/internals/actor-flow-drives-the-target-through-a-transport-seam.md +24 -0
- package/knowledge/decisions/internals/actor-flow-verdicts-are-llm-self-evaluations.md +25 -0
- package/knowledge/decisions/internals/addon-package-roots-resolve-by-walking-node-module-search-paths.md +26 -0
- package/knowledge/decisions/internals/addon-singleton-services-are-cached-per-namespace-not-per-package.md +33 -0
- package/knowledge/decisions/internals/addon-workflow-names-are-prefixed-with-the-consumer-namespace.md +28 -0
- package/knowledge/decisions/internals/ai-agent-agui-bridge-obeys-the-client-ordering-contract.md +29 -0
- package/knowledge/decisions/internals/ai-agent-audio-chunks-carry-the-format-the-provider-returned.md +20 -0
- package/knowledge/decisions/internals/ai-agent-credential-suspensions-hide-the-tool-result.md +26 -0
- package/knowledge/decisions/internals/ai-agent-delegate-and-supervise-hide-different-text.md +26 -0
- package/knowledge/decisions/internals/ai-agent-llm-tool-arguments-have-nulls-stripped.md +23 -0
- package/knowledge/decisions/internals/ai-agent-model-config-stays-a-single-resolution-seam.md +25 -0
- package/knowledge/decisions/internals/ai-agent-onerror-hooks-cannot-change-the-failure.md +22 -0
- package/knowledge/decisions/internals/ai-agent-runner-methods-must-keep-their-receiver.md +22 -0
- package/knowledge/decisions/internals/ai-agent-stream-persistence-is-best-effort.md +27 -0
- package/knowledge/decisions/internals/ai-agent-sub-agents-inherit-the-parent-context-block.md +26 -0
- package/knowledge/decisions/internals/ai-agent-tool-execute-failures-are-logged-unconditionally.md +25 -0
- package/knowledge/decisions/internals/ai-agent-voice-input-transcribes-audio-parts-in-place.md +22 -0
- package/knowledge/decisions/internals/ai-agent-working-memory-is-persisted-only-when-valid.md +25 -0
- package/knowledge/decisions/internals/channel-message-handlers-accept-three-config-shapes.md +30 -0
- package/knowledge/decisions/internals/channel-middleware-caches-only-statically-resolved-middleware.md +31 -0
- package/knowledge/decisions/internals/channel-state-is-per-socket-session-state-is-per-user.md +29 -0
- package/knowledge/decisions/internals/channel-user-id-is-persisted-after-onconnect-middleware-runs.md +28 -0
- package/knowledge/decisions/internals/cli-option-names-are-camelcase-in-state-and-kebab-on-the-command-line.md +27 -0
- package/knowledge/decisions/internals/cli-parse-errors-are-routed-by-message-prefix.md +28 -0
- package/knowledge/decisions/internals/cli-stdout-is-reserved-for-machine-readable-output.md +34 -0
- package/knowledge/decisions/internals/cli-unknown-long-options-warn-instead-of-failing.md +29 -0
- package/knowledge/decisions/internals/core-data-classification-brand-is-an-optional-property.md +34 -0
- package/knowledge/decisions/internals/core-function-runner-restores-the-wire-fields-it-overwrites.md +44 -0
- package/knowledge/decisions/internals/core-hot-reload-merges-generated-meta-never-replaces-it.md +39 -0
- package/knowledge/decisions/internals/core-hot-reload-owns-its-module-registry.md +42 -0
- package/knowledge/decisions/internals/core-middleware-order-is-scope-then-priority.md +39 -0
- package/knowledge/decisions/internals/core-schema-defaults-apply-on-every-transport.md +43 -0
- package/knowledge/decisions/internals/core-scopes-are-an-and-gate-separate-from-permissions.md +38 -0
- package/knowledge/decisions/internals/core-state-is-a-global-map-written-only-at-registration-time.md +44 -0
- package/knowledge/decisions/internals/email-meta-is-read-uncached-because-codegen-rewrites-it-mid-session.md +27 -0
- package/knowledge/decisions/internals/gateway-adapters-resolve-lazily-and-are-promise-cached.md +32 -0
- package/knowledge/decisions/internals/gateway-webhook-challenges-echo-bytes-not-json.md +28 -0
- package/knowledge/decisions/internals/gateway-wiring-is-a-meta-wiring-over-http-and-channels.md +31 -0
- package/knowledge/decisions/internals/generated-src-paths-in-pikku-meta-are-absolute.md +26 -0
- package/knowledge/decisions/internals/http-request-bodies-are-read-once-and-shared.md +32 -0
- package/knowledge/decisions/internals/http-route-groups-cascade-config-in-a-fixed-order.md +28 -0
- package/knowledge/decisions/internals/http-router-matches-normalized-paths-but-returns-registered-ones.md +30 -0
- package/knowledge/decisions/internals/http-runner-logs-through-a-trace-scoped-logger-functions-do-not.md +26 -0
- package/knowledge/decisions/internals/http-set-cookie-headers-are-appended-never-joined.md +28 -0
- package/knowledge/decisions/internals/http-sse-streams-flush-headers-only-after-middleware.md +32 -0
- package/knowledge/decisions/internals/http-wiring-without-metadata-is-skipped-not-fatal.md +26 -0
- package/knowledge/decisions/internals/in-a-scenario-a-4xx-is-data-not-an-exception.md +25 -0
- package/knowledge/decisions/internals/in-memory-workflow-history-aliases-the-live-step-object.md +26 -0
- package/knowledge/decisions/internals/index.md +113 -0
- package/knowledge/decisions/internals/istanbul-statement-counts-attach-to-the-start-line-only.md +25 -0
- package/knowledge/decisions/internals/local-trigger-and-gateway-services-assume-a-single-process.md +26 -0
- package/knowledge/decisions/internals/node-only-builtins-are-imported-dynamically.md +24 -0
- package/knowledge/decisions/internals/queue-group-concurrency-keeps-one-shared-queue-fair.md +28 -0
- package/knowledge/decisions/internals/queue-jobs-always-carry-an-explicit-attempts-count.md +27 -0
- package/knowledge/decisions/internals/remote-addons-dispatch-over-http-instead-of-local-meta.md +31 -0
- package/knowledge/decisions/internals/rpc-names-resolve-through-package-scope-before-root.md +32 -0
- package/knowledge/decisions/internals/scenario-agent-calls-sign-in-on-401-only.md +27 -0
- package/knowledge/decisions/internals/scenario-meta-lives-apart-from-app-meta-but-merges-when-read-off-disk.md +26 -0
- package/knowledge/decisions/internals/scenario-steps-return-drained-response-records.md +27 -0
- package/knowledge/decisions/internals/scope-roots-may-be-co-declared-by-an-addon-and-its-host-app.md +30 -0
- package/knowledge/decisions/internals/serverless-channel-disconnect-must-tolerate-a-missing-channel.md +28 -0
- package/knowledge/decisions/internals/the-dev-queue-copies-prod-timing-and-serialization-semantics.md +30 -0
- package/knowledge/decisions/internals/the-embedding-model-is-pinned-per-service-and-doc-query-embedding-is-split.md +29 -0
- package/knowledge/decisions/internals/the-in-memory-workflow-service-is-inline-only-and-single-process.md +27 -0
- package/knowledge/decisions/internals/the-kek-salt-is-scoped-to-the-key-version.md +40 -0
- package/knowledge/decisions/internals/the-schema-service-is-never-stubbed.md +26 -0
- package/knowledge/decisions/internals/trigger-declaration-is-split-from-trigger-source.md +33 -0
- package/knowledge/decisions/internals/typed-secret-service-caches-for-the-process-lifetime.md +26 -0
- package/knowledge/decisions/internals/webhook-delivery-history-records-every-attempt-best-effort.md +26 -0
- package/knowledge/decisions/internals/webhook-service-collaborators-are-constructor-args-not-locator-lookups.md +25 -0
- package/knowledge/decisions/internals/whether-a-run-is-inline-is-read-from-the-run-record.md +58 -0
- package/knowledge/decisions/internals/workflow-approval-expiry-is-decided-from-a-recorded-deadline.md +34 -0
- package/knowledge/decisions/internals/workflow-core-never-imports-a-browser-driver.md +42 -0
- package/knowledge/decisions/internals/workflow-dsl-meta-separates-runtime-expressions-from-literals.md +38 -0
- package/knowledge/decisions/internals/workflow-features-resolve-scenarios-by-object-identity.md +29 -0
- package/knowledge/decisions/internals/workflow-graph-inline-and-queued-runs-share-one-planner.md +42 -0
- package/knowledge/decisions/internals/workflow-graph-node-notes-are-excluded-from-the-graph-hash.md +25 -0
- package/knowledge/decisions/internals/workflow-inline-runs-report-their-run-id-before-they-can-fail.md +29 -0
- package/knowledge/decisions/internals/workflow-invocation-id-is-the-dedupe-key-not-step-id.md +43 -0
- package/knowledge/decisions/internals/workflow-queued-step-dispatch-requires-an-explicit-opt-in.md +29 -0
- package/knowledge/decisions/internals/workflow-queues-are-per-workflow-by-default.md +42 -0
- package/knowledge/decisions/internals/workflow-repeated-step-names-get-an-ordinal-suffix.md +33 -0
- package/knowledge/decisions/internals/workflow-replay-reads-its-steps-once-and-caches-only-the-immutable-half.md +32 -0
- package/knowledge/decisions/internals/workflow-retries-are-owned-by-the-workflow-not-the-queue.md +31 -0
- package/knowledge/decisions/internals/workflow-run-capabilities-are-extensions-not-subclasses.md +39 -0
- package/knowledge/decisions/internals/workflow-run-mirror-is-never-a-source-of-truth.md +29 -0
- package/knowledge/decisions/internals/workflow-run-polling-backs-off-to-the-callers-ceiling.md +33 -0
- package/knowledge/decisions/internals/workflow-run-timeline-is-a-pure-fold-over-durable-history.md +37 -0
- package/knowledge/decisions/internals/workflow-scenario-assertions-never-retry-and-record-one-step.md +50 -0
- package/knowledge/decisions/internals/workflow-scenario-hooks-are-a-scenario-only-affordance.md +43 -0
- package/knowledge/decisions/internals/workflow-scenario-prose-is-rendered-from-typed-calls-not-parsed-from-english.md +32 -0
- package/knowledge/decisions/internals/workflow-scenario-quarantine-reason-lives-in-code.md +18 -0
- package/knowledge/decisions/internals/workflow-scenario-step-targets-are-string-literals-for-the-inspector.md +34 -0
- package/knowledge/decisions/internals/workflow-step-compensation-runs-as-its-own-durable-step.md +26 -0
- package/knowledge/decisions/internals/workflow-step-dispatch-failure-is-transient-not-a-run-failure.md +33 -0
- package/knowledge/decisions/internals/workflow-step-lock-is-held-only-to-claim-the-step.md +27 -0
- package/knowledge/decisions/internals/workflow-step-rpc-name-is-provenance-only.md +34 -0
- package/knowledge/decisions/internals/workflow-suspend-and-approval-reasons-are-durable-step-identities.md +38 -0
- package/knowledge/decisions/internals/workflow-suspended-runs-keep-their-in-process-context.md +30 -0
- package/knowledge/decisions/security/a-dropped-audit-write-is-always-logged.md +26 -0
- package/knowledge/decisions/security/actor-flow-missing-approval-decisions-default-to-denied.md +22 -0
- package/knowledge/decisions/security/actor-sign-in-is-proven-by-set-cookie-not-a-non-empty-jar.md +27 -0
- package/knowledge/decisions/security/actor-sign-in-only-works-for-actor-flagged-users.md +27 -0
- package/knowledge/decisions/security/addon-auth-and-tags-only-tighten.md +43 -0
- package/knowledge/decisions/security/addon-config-gates-apply-only-at-the-namespaced-rpc-boundary.md +52 -0
- package/knowledge/decisions/security/addon-scopes-are-resolved-where-the-function-runs.md +46 -0
- package/knowledge/decisions/security/ai-agent-approval-forwarding-requires-a-symbol-brand.md +27 -0
- package/knowledge/decisions/security/ai-agent-credential-requests-are-symbol-branded.md +37 -0
- package/knowledge/decisions/security/ai-agent-gate-requires-a-session-only-when-auth-is-true.md +31 -0
- package/knowledge/decisions/security/ai-agent-ownership-failures-never-echo-the-resource.md +23 -0
- package/knowledge/decisions/security/ai-agent-resume-re-runs-the-authorization-gate.md +22 -0
- package/knowledge/decisions/security/ai-agent-sessionless-deployments-have-no-thread-ownership.md +39 -0
- package/knowledge/decisions/security/ai-agent-thread-ownership-composes-the-session-principal.md +30 -0
- package/knowledge/decisions/security/ai-agent-tool-filtering-reads-the-live-function-config.md +24 -0
- package/knowledge/decisions/security/an-empty-owners-constraint-matches-nothing.md +30 -0
- package/knowledge/decisions/security/an-exposed-ungated-function-is-a-codegen-warning.md +49 -0
- package/knowledge/decisions/security/console-addon-privileged-functions-gate-themselves.md +76 -0
- package/knowledge/decisions/security/core-safe-fetch-blocks-ssrf-by-host-literal-not-dns.md +39 -0
- package/knowledge/decisions/security/core-secrets-use-a-per-secret-dek-wrapped-by-a-kek.md +37 -0
- package/knowledge/decisions/security/gateway-handlers-run-through-the-function-runner-gate.md +31 -0
- package/knowledge/decisions/security/gateway-middleware-sessions-must-be-bridged-onto-the-wire.md +30 -0
- package/knowledge/decisions/security/global-permissions-and-function-permissions-are-independent-gates.md +40 -0
- package/knowledge/decisions/security/http-error-detail-is-withheld-from-clients-in-production.md +33 -0
- package/knowledge/decisions/security/http-request-bodies-are-bounded-before-they-are-buffered.md +46 -0
- package/knowledge/decisions/security/index.md +55 -0
- package/knowledge/decisions/security/mcp-internal-error-details-are-double-gated-on-production.md +27 -0
- package/knowledge/decisions/security/passphrases-are-stretched-key-material-is-expanded.md +40 -0
- package/knowledge/decisions/security/permission-auth-filtering-requires-live-permission-functions.md +31 -0
- package/knowledge/decisions/security/pikku-carries-actor-scopes-as-data-and-the-app-grants-them.md +26 -0
- package/knowledge/decisions/security/queue-job-identities-are-signed-at-enqueue.md +69 -0
- package/knowledge/decisions/security/queue-jobs-carry-the-producers-pikku-user-id.md +39 -0
- package/knowledge/decisions/security/remote-addon-tokens-are-client-credentials-not-mesh-trust.md +34 -0
- package/knowledge/decisions/security/scaffold-features-are-authenticated-unless-opted-out.md +49 -0
- package/knowledge/decisions/security/scenario-step-functions-are-never-externally-invocable.md +30 -0
- package/knowledge/decisions/security/scope-resolution-happens-at-the-session-boundary-and-sync-never-deletes.md +28 -0
- package/knowledge/decisions/security/self-authentication-is-declared-not-detected.md +34 -0
- package/knowledge/decisions/security/signed-content-urls-bind-the-request-path.md +37 -0
- package/knowledge/decisions/security/webhook-bodies-are-signed-before-they-are-enqueued.md +25 -0
- package/knowledge/decisions/security/workflow-actor-steps-always-use-the-real-transport.md +34 -0
- package/knowledge/decisions/security/workflow-approval-payloads-are-validated-on-replay-inside-the-workflow.md +40 -0
- package/knowledge/decisions/security/workflow-queued-steps-rehydrate-their-session-from-the-run-wire.md +32 -0
- package/knowledge/decisions/security/workflow-scenario-sessions-are-isolated-per-actor-and-per-scenario.md +32 -0
- package/knowledge/decisions/security/workflow-scenario-steps-are-never-network-invocable.md +31 -0
- package/knowledge/index.md +24 -0
- package/knowledge/questions/index.md +15 -0
- package/package.json +4 -1
- package/run-tests.sh +0 -0
- package/src/crypto-utils.test.ts +460 -19
- package/src/crypto-utils.ts +283 -55
- package/src/data-classification.ts +1 -7
- package/src/dev/hot-reload.test.ts +0 -4
- package/src/dev/hot-reload.ts +11 -30
- package/src/dev/module-runner.ts +7 -32
- package/src/dev/reload-meta.ts +9 -29
- package/src/errors/error-handler.ts +20 -35
- package/src/errors/error.test.ts +30 -1
- package/src/errors/errors.ts +73 -157
- package/src/function/abort-scope.test.ts +97 -0
- package/src/function/abort-scope.ts +80 -0
- package/src/function/function-runner.test.ts +0 -7
- package/src/function/function-runner.ts +62 -32
- package/src/function/functions.types.ts +56 -136
- package/src/function/list.types.test.ts +3 -25
- package/src/function/list.types.ts +12 -62
- package/src/handle-error.ts +0 -18
- package/src/index.ts +60 -1
- package/src/middleware/auth-apikey.test.ts +0 -1
- package/src/middleware/auth-apikey.ts +0 -17
- package/src/middleware/auth-bearer.test.ts +0 -3
- package/src/middleware/auth-bearer.ts +3 -40
- package/src/middleware/auth-cookie.test.ts +0 -6
- package/src/middleware/auth-cookie.ts +2 -26
- package/src/middleware/cors.test.ts +34 -0
- package/src/middleware/cors.ts +12 -33
- package/src/middleware/remote-auth.test.ts +24 -9
- package/src/middleware/remote-auth.ts +10 -2
- package/src/middleware/telemetry.ts +2 -31
- package/src/middleware-runner.test.ts +0 -2
- package/src/middleware-runner.ts +5 -74
- package/src/permissions.test.ts +30 -0
- package/src/permissions.ts +24 -74
- package/src/pikku-request.ts +0 -6
- package/src/pikku-state.ts +2 -30
- package/src/production-barrels-stay-lean.test.ts +110 -0
- package/src/remote.test.ts +172 -0
- package/src/remote.ts +17 -7
- package/src/schema.ts +5 -39
- package/src/scopes.ts +7 -48
- package/src/services/ai-agent-runner-service.ts +20 -0
- package/src/services/ai-embedding-service.ts +3 -25
- package/src/services/audit-service.ts +1 -2
- package/src/services/content-service.ts +1 -46
- package/src/services/credential-service.ts +3 -40
- package/src/services/credential-wire-service.test.ts +0 -2
- package/src/services/deployment-service.ts +3 -9
- package/src/services/gateway-service.ts +0 -15
- package/src/services/{http-scenario-actors-converse.test.ts → http-personas-converse.test.ts} +38 -9
- package/src/services/{http-scenario-actors.test.ts → http-personas.test.ts} +39 -22
- package/src/services/{http-scenario-actors.ts → http-personas.ts} +85 -45
- package/src/services/in-memory-queue-service.ts +1 -15
- package/src/services/in-memory-trigger-service.ts +1 -18
- package/src/services/in-memory-workflow-service.test.ts +0 -13
- package/src/services/in-memory-workflow-service.ts +4 -38
- package/src/services/index.ts +20 -15
- package/src/services/istanbul-coverage-service.ts +2 -8
- package/src/services/jwt-service.ts +1 -16
- package/src/services/local-content.test.ts +159 -27
- package/src/services/local-content.ts +55 -23
- package/src/services/local-gateway-service.ts +2 -17
- package/src/services/local-secrets.ts +0 -4
- package/src/services/logger-console.test.ts +0 -1
- package/src/services/logger-console.ts +3 -7
- package/src/services/logger.ts +2 -37
- package/src/services/meta-service.test.ts +1 -5
- package/src/services/meta-service.ts +41 -61
- package/src/services/{scenario-actors-service.ts → personas-service.ts} +48 -43
- package/src/services/pikku-user-id.ts +0 -4
- package/src/services/queue-webhook-service.ts +9 -41
- package/src/services/scheduler-service.ts +1 -50
- package/src/services/schema-service.ts +1 -24
- package/src/services/scope-service.ts +50 -34
- package/src/services/scoped-secret-service.ts +0 -4
- package/src/services/secret-host-binding.test.ts +138 -0
- package/src/services/secret-host-binding.ts +51 -0
- package/src/services/secret-service.ts +5 -33
- package/src/services/secretless.test.ts +54 -0
- package/src/services/secretless.ts +29 -0
- package/src/services/stub-tracker.ts +8 -18
- package/src/services/system-role-guard.test.ts +93 -0
- package/src/services/system-role-guard.ts +71 -0
- package/src/services/trigger-service.ts +0 -12
- package/src/services/typed-secret-service.ts +1 -7
- package/src/services/v8-coverage-service.ts +3 -6
- package/src/services/variables-service.ts +1 -8
- package/src/services/webhook-service.ts +19 -63
- package/src/services/workflow-service.ts +3 -20
- package/src/testing/service-tests.ts +0 -26
- package/src/time-utils.ts +1 -19
- package/src/types/core.types.ts +116 -229
- package/src/types/state.types.ts +7 -9
- package/src/utils/hmac.ts +4 -10
- package/src/utils/safe-fetch.ts +13 -54
- package/src/utils.test.ts +11 -2
- package/src/utils.ts +6 -15
- package/src/wirings/actor-flow/actor-flow.types.ts +1 -34
- package/src/wirings/actor-flow/index.ts +0 -9
- package/src/wirings/actor-flow/run-conversation.test.ts +11 -6
- package/src/wirings/actor-flow/run-conversation.ts +19 -12
- package/src/wirings/ai-agent/ai-agent-agui.test.ts +75 -10
- package/src/wirings/ai-agent/ai-agent-agui.ts +36 -17
- package/src/wirings/ai-agent/ai-agent-helpers.ts +20 -0
- package/src/wirings/ai-agent/ai-agent-interrupt.test.ts +842 -0
- package/src/wirings/ai-agent/ai-agent-interrupt.ts +399 -0
- package/src/wirings/ai-agent/ai-agent-memory.ts +0 -2
- package/src/wirings/ai-agent/ai-agent-model-config.ts +1 -9
- package/src/wirings/ai-agent/ai-agent-prepare.test.ts +202 -31
- package/src/wirings/ai-agent/ai-agent-prepare.ts +82 -138
- package/src/wirings/ai-agent/ai-agent-registry.test.ts +191 -6
- package/src/wirings/ai-agent/ai-agent-registry.ts +18 -1
- package/src/wirings/ai-agent/ai-agent-resume-authorization.test.ts +0 -2
- package/src/wirings/ai-agent/ai-agent-runner.test.ts +11 -9
- package/src/wirings/ai-agent/ai-agent-runner.ts +67 -33
- package/src/wirings/ai-agent/ai-agent-stream.test.ts +205 -103
- package/src/wirings/ai-agent/ai-agent-stream.ts +192 -75
- package/src/wirings/ai-agent/ai-agent-thread-ownership.test.ts +301 -0
- package/src/wirings/ai-agent/ai-agent.types.ts +85 -4
- package/src/wirings/ai-agent/index.ts +35 -3
- package/src/wirings/ai-agent/voice-input.test.ts +72 -7
- package/src/wirings/ai-agent/voice-input.ts +48 -3
- package/src/wirings/ai-agent/voice-output.test.ts +422 -0
- package/src/wirings/ai-agent/voice-output.ts +216 -56
- package/src/wirings/channel/channel-common.ts +15 -20
- package/src/wirings/channel/channel-handler.test.ts +50 -0
- package/src/wirings/channel/channel-handler.ts +32 -11
- package/src/wirings/channel/channel-host-rpc.test.ts +150 -0
- package/src/wirings/channel/channel-host-rpc.ts +69 -0
- package/src/wirings/channel/channel-middleware-runner.test.ts +0 -1
- package/src/wirings/channel/channel-middleware-runner.ts +0 -12
- package/src/wirings/channel/channel-rpc-registry.ts +116 -0
- package/src/wirings/channel/channel-rpc-responder.ts +117 -0
- package/src/wirings/channel/channel-rpc-service.ts +146 -0
- package/src/wirings/channel/channel-rpc-validators.ts +65 -0
- package/src/wirings/channel/channel-rpc.test.ts +820 -0
- package/src/wirings/channel/channel-rpc.ts +5 -0
- package/src/wirings/channel/channel-rpc.types.ts +150 -0
- package/src/wirings/channel/channel-runner.ts +0 -14
- package/src/wirings/channel/channel-store.ts +0 -10
- package/src/wirings/channel/channel.types.ts +19 -8
- package/src/wirings/channel/define-channel-routes.ts +0 -20
- package/src/wirings/channel/eventhub-service.ts +0 -18
- package/src/wirings/channel/index.ts +35 -0
- package/src/wirings/channel/local/local-channel-handler.ts +3 -1
- package/src/wirings/channel/local/local-channel-runner.test.ts +0 -10
- package/src/wirings/channel/local/local-channel-runner.ts +3 -1
- package/src/wirings/channel/local/local-eventhub-service.test.ts +0 -13
- package/src/wirings/channel/local/local-eventhub-service.ts +2 -37
- package/src/wirings/channel/log-channels.ts +0 -4
- package/src/wirings/channel/pikku-abstract-channel-handler.test.ts +83 -2
- package/src/wirings/channel/pikku-abstract-channel-handler.ts +7 -0
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +2 -5
- package/src/wirings/cli/channel/cli-approval.test.ts +177 -0
- package/src/wirings/cli/channel/cli-approval.ts +135 -0
- package/src/wirings/cli/channel/cli-channel-runner.ts +4 -26
- package/src/wirings/cli/channel/cli-raw-channel-runner.test.ts +169 -0
- package/src/wirings/cli/channel/cli-raw-channel-runner.ts +59 -16
- package/src/wirings/cli/channel/cli-raw-client-runner.test.ts +480 -0
- package/src/wirings/cli/channel/cli-raw-client-runner.ts +155 -0
- package/src/wirings/cli/channel/index.ts +9 -0
- package/src/wirings/cli/cli-runner.test.ts +0 -1
- package/src/wirings/cli/cli-runner.ts +46 -88
- package/src/wirings/cli/cli.types.ts +14 -3
- package/src/wirings/cli/command-parser.test.ts +0 -4
- package/src/wirings/cli/command-parser.ts +11 -91
- package/src/wirings/cli/define-cli-commands.ts +1 -17
- package/src/wirings/credential/credential.types.ts +0 -12
- package/src/wirings/credential/{wire-credential.ts → define-credential.ts} +7 -7
- package/src/wirings/credential/index.ts +1 -1
- package/src/wirings/credential/validate-credential-definitions.ts +2 -4
- package/src/wirings/gateway/gateway-runner.test.ts +1 -21
- package/src/wirings/gateway/gateway-runner.ts +8 -110
- package/src/wirings/gateway/gateway.types.ts +7 -80
- package/src/wirings/http/http-routes.test.ts +0 -3
- package/src/wirings/http/http-routes.ts +0 -86
- package/src/wirings/http/http-runner.test.ts +0 -1
- package/src/wirings/http/http-runner.ts +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 +29 -0
- package/src/wirings/persona/index.ts +62 -0
- package/src/wirings/persona/persona-email.ts +87 -0
- package/src/wirings/persona/persona-environments.test.ts +183 -0
- package/src/wirings/persona/persona-environments.ts +138 -0
- package/src/wirings/persona/persona-mailbox.ts +156 -0
- package/src/wirings/persona/persona.test.ts +220 -0
- package/src/wirings/persona/persona.types.ts +131 -0
- package/src/wirings/persona/validate-personas.ts +133 -0
- package/src/wirings/queue/index.ts +13 -3
- package/src/wirings/queue/queue-identity.test.ts +453 -0
- package/src/wirings/queue/queue-identity.ts +173 -0
- package/src/wirings/queue/queue-runner.ts +12 -31
- package/src/wirings/queue/queue.types.ts +19 -89
- package/src/wirings/queue/register-queue-helper.ts +0 -14
- package/src/wirings/queue/signed-queue-service.ts +59 -0
- package/src/wirings/queue/validate-worker-config.ts +2 -28
- package/src/wirings/role/define-system-role.ts +33 -0
- package/src/wirings/role/index.ts +13 -0
- package/src/wirings/role/role.test.ts +104 -0
- package/src/wirings/role/role.types.ts +47 -0
- package/src/wirings/role/validate-role-definitions.ts +93 -0
- package/src/wirings/rpc/addon-auth-tags.test.ts +223 -0
- package/src/wirings/rpc/addon-runner.ts +0 -56
- package/src/wirings/rpc/addon-scopes.test.ts +225 -0
- package/src/wirings/rpc/remote-addon-auth.ts +1 -13
- package/src/wirings/rpc/rpc-runner.test.ts +186 -2
- package/src/wirings/rpc/rpc-runner.ts +145 -127
- package/src/wirings/rpc/rpc-types.ts +11 -6
- package/src/wirings/rpc/wire-addon.test.ts +43 -1
- package/src/wirings/rpc/wire-addon.ts +99 -0
- package/src/wirings/rpc/wire-remote-addon.ts +9 -29
- package/src/wirings/scheduler/log-schedulers.ts +0 -4
- package/src/wirings/scheduler/scheduler-runner.test.ts +1 -8
- package/src/wirings/scheduler/scheduler-runner.ts +0 -2
- package/src/wirings/scheduler/scheduler.types.ts +1 -14
- package/src/wirings/scope/{wire-scope.ts → define-scope.ts} +5 -6
- package/src/wirings/scope/index.ts +1 -1
- package/src/wirings/scope/scope.test.ts +1 -2
- package/src/wirings/scope/scope.types.ts +7 -9
- package/src/wirings/scope/validate-scope-definitions.ts +3 -21
- package/src/wirings/secret/index.ts +1 -1
- package/src/wirings/secret/secret.types.ts +19 -15
- package/src/wirings/secret/validate-secret-definitions.ts +2 -4
- package/src/wirings/trigger/trigger-runner.ts +1 -27
- package/src/wirings/trigger/trigger.types.ts +1 -82
- package/src/wirings/variable/index.ts +1 -1
- package/src/wirings/variable/validate-variable-definitions.ts +2 -4
- package/src/wirings/variable/variable.types.ts +1 -13
- package/src/wirings/virtual-user/index.ts +76 -0
- package/src/wirings/virtual-user/run-virtual-user.test.ts +765 -0
- package/src/wirings/virtual-user/run-virtual-user.ts +671 -0
- package/src/wirings/virtual-user/virtual-user-agents.test.ts +65 -0
- package/src/wirings/virtual-user/virtual-user-agents.ts +57 -0
- package/src/wirings/virtual-user/virtual-user-catalogue.test.ts +215 -0
- package/src/wirings/virtual-user/virtual-user-catalogue.ts +184 -0
- package/src/wirings/virtual-user/virtual-user-derive.test.ts +398 -0
- package/src/wirings/virtual-user/virtual-user-derive.ts +173 -0
- package/src/wirings/virtual-user/virtual-user-dispositions.test.ts +63 -0
- package/src/wirings/virtual-user/virtual-user-dispositions.ts +213 -0
- package/src/wirings/virtual-user/virtual-user-intents.test.ts +208 -0
- package/src/wirings/virtual-user/virtual-user-intents.ts +185 -0
- package/src/wirings/virtual-user/virtual-user-rng.test.ts +72 -0
- package/src/wirings/virtual-user/virtual-user-rng.ts +50 -0
- package/src/wirings/virtual-user/virtual-user-target.ts +47 -0
- package/src/wirings/virtual-user/virtual-user.types.ts +219 -0
- package/src/wirings/workflow/dsl/workflow-dsl.types.ts +5 -4
- package/src/wirings/workflow/dsl/workflow-runner.ts +0 -4
- package/src/wirings/workflow/feature.ts +0 -19
- package/src/wirings/workflow/graph/graph-node.ts +0 -136
- package/src/wirings/workflow/graph/graph-runner.test.ts +20 -19
- package/src/wirings/workflow/graph/graph-runner.ts +6 -41
- package/src/wirings/workflow/graph/wire-workflow-graph.ts +0 -4
- package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -58
- package/src/wirings/workflow/index.ts +10 -44
- package/src/wirings/workflow/pikku-scenario-service.ts +235 -52
- package/src/wirings/workflow/pikku-workflow-service.test.ts +0 -39
- package/src/wirings/workflow/pikku-workflow-service.ts +77 -674
- package/src/wirings/workflow/run-timeline.test.ts +7 -19
- package/src/wirings/workflow/run-timeline.ts +0 -56
- package/src/wirings/workflow/scenario-cookie-jar.test.ts +0 -1
- package/src/wirings/workflow/scenario-cookie-jar.ts +0 -25
- package/src/wirings/workflow/scenario-expectations.test.ts +2 -7
- package/src/wirings/workflow/scenario-hooks.test.ts +2 -7
- package/src/wirings/workflow/scenario-poll.test.ts +0 -2
- package/src/wirings/workflow/scenario-poll.ts +0 -15
- package/src/wirings/workflow/scenario-prose.ts +0 -28
- package/src/wirings/workflow/scenario-service.test.ts +2 -9
- package/src/wirings/workflow/scenario-step-guards.ts +1 -14
- package/src/wirings/workflow/scenario-step.test.ts +159 -14
- package/src/wirings/workflow/scenario-step.types.ts +82 -6
- package/src/wirings/workflow/scenario-surface.test.ts +145 -0
- package/src/wirings/workflow/scenario-surface.ts +71 -0
- package/src/wirings/workflow/workflow-dispatch-durability.test.ts +14 -15
- package/src/wirings/workflow/workflow-dispatch-payload.test.ts +0 -4
- package/src/wirings/workflow/workflow-inline-authority.test.ts +169 -0
- package/src/wirings/workflow/workflow-invocation-id.test.ts +0 -2
- package/src/wirings/workflow/workflow-invocation-id.ts +2 -22
- package/src/wirings/workflow/workflow-mirror.test.ts +0 -7
- package/src/wirings/workflow/workflow-on-error.test.ts +0 -9
- package/src/wirings/workflow/workflow-queue-workers.ts +0 -21
- package/src/wirings/workflow/workflow-replay-snapshot.test.ts +8 -7
- package/src/wirings/workflow/workflow-retry-policy.test.ts +0 -5
- package/src/wirings/workflow/workflow-run-context.test.ts +5 -10
- package/src/wirings/workflow/workflow-run-polling.test.ts +0 -5
- package/src/wirings/workflow/workflow-step-ordinal.test.ts +19 -4
- package/src/wirings/workflow/workflow-step-session.test.ts +0 -7
- package/src/wirings/workflow/workflow.types.ts +0 -203
- package/tsconfig.tsbuildinfo +1 -1
- package/src/middleware/timeout.ts +0 -22
- package/src/pikku-response.ts +0 -5
- package/src/wirings/mcp/mcp-endpoint-registry.test.d.ts +0 -1
- package/src/wirings/workflow/dsl/index.ts +0 -36
- package/src/wirings/workflow/graph/index.ts +0 -15
package/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.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: HTTP route groups cascade config in a fixed, per-field order
|
|
4
|
+
description: basePath concatenates, tags and middleware merge outward-in, auth is overridden by the innermost group
|
|
5
|
+
tags: http
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# HTTP route groups cascade config in a fixed, per-field order
|
|
9
|
+
|
|
10
|
+
`wireHTTPRoutes` in `packages/core/src/wirings/http/http-routes.ts` walks a
|
|
11
|
+
nested route map and merges group config at each level through
|
|
12
|
+
`mergeGroupConfig`. Each field cascades differently, and the differences are the
|
|
13
|
+
contract callers write against:
|
|
14
|
+
|
|
15
|
+
- `basePath` concatenates, outer prefix first, so nesting composes URLs.
|
|
16
|
+
- `tags` merge, parent then child; nothing is replaced.
|
|
17
|
+
- `middleware` merges with the parent's entries first, so outer middleware always
|
|
18
|
+
runs before inner middleware.
|
|
19
|
+
- `auth` is a single value and the innermost declaration wins, which is what lets
|
|
20
|
+
one public route sit inside an authenticated group.
|
|
21
|
+
|
|
22
|
+
`registerRoute` then applies the same rules once more between the group config
|
|
23
|
+
and the individual route before calling `wireHTTP`.
|
|
24
|
+
|
|
25
|
+
**What this rules out:** collapsing `mergeGroupConfig` into an object spread or a
|
|
26
|
+
generic deep-merge. A spread would make the child replace the parent's `tags` and
|
|
27
|
+
`middleware` instead of extending them, and a deep-merge would concatenate `auth`
|
|
28
|
+
or reorder middleware — silently changing which middleware sees a request first.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: The HTTP router matches normalized paths but returns the registered path
|
|
4
|
+
description: Matching normalizes the leading slash while the match result carries the original key, because pikkuState is keyed by the registered string
|
|
5
|
+
tags: http
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# The HTTP router matches normalized paths but returns the registered path
|
|
9
|
+
|
|
10
|
+
`PathToRegexRouter` in `packages/core/src/wirings/http/routers/path-to-regex.ts`
|
|
11
|
+
normalizes every route and every incoming path to a leading `/` before matching,
|
|
12
|
+
so a route registered as `'todos'` still answers a request for `/todos`. The
|
|
13
|
+
`route` field it stores alongside each matcher and static entry is the
|
|
14
|
+
*un-normalized* original, and that is what `MatchResult.route` returns.
|
|
15
|
+
|
|
16
|
+
That asymmetry is load-bearing. `getMatchingRoute` in `http-runner.ts` takes the
|
|
17
|
+
returned route and uses it as a key into `pikkuState(null, 'http', 'routes')` and
|
|
18
|
+
into the HTTP meta record — both of which are keyed by exactly the string the
|
|
19
|
+
author passed to `wireHTTP`. Returning the normalized path instead would miss
|
|
20
|
+
those lookups for any route registered without a leading slash.
|
|
21
|
+
|
|
22
|
+
The same router also compiles channel routes, registered under the `get` method,
|
|
23
|
+
because a WebSocket connection arrives as an HTTP GET upgrade;
|
|
24
|
+
`getMatchingChannelConfig` in `channel-runner.ts` matches through
|
|
25
|
+
`httpRouter.match('get', path)`. Channels and HTTP GET routes therefore share one
|
|
26
|
+
path namespace and can collide with each other.
|
|
27
|
+
|
|
28
|
+
**What this rules out:** simplifying the compile step to store
|
|
29
|
+
`normalizedRoutePath` in both places, and treating the channel routes compiled
|
|
30
|
+
into the GET table as stray entries to be removed from the HTTP router.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: The HTTP runner logs through a trace-scoped logger, functions do not
|
|
4
|
+
description: Only runner-internal logging is scoped to the request id; functions keep the singleton logger for compatibility
|
|
5
|
+
tags: http
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# The HTTP runner logs through a trace-scoped logger, functions do not
|
|
9
|
+
|
|
10
|
+
`fetchData` in `packages/core/src/wirings/http/http-runner.ts` derives
|
|
11
|
+
`scopedLogger` from `singletonServices.logger.scope?.(requestId)` and uses it for
|
|
12
|
+
route-matching and error-handling output only. Functions and middleware continue
|
|
13
|
+
to receive `singletonServices.logger` unscoped, via the services object.
|
|
14
|
+
|
|
15
|
+
The split is deliberate, not an oversight. `scope` is optional on the `Logger`
|
|
16
|
+
interface, so a runtime supplying a plain logger still works — the runner falls
|
|
17
|
+
back to the singleton. Threading the scoped logger into the services object
|
|
18
|
+
instead would change the logger identity that every existing function and
|
|
19
|
+
middleware sees, which breaks implementations that compare or wrap
|
|
20
|
+
`services.logger`, and would make user code depend on an optional method.
|
|
21
|
+
|
|
22
|
+
**What this rules out:** "unifying" the two by overwriting `services.logger` with
|
|
23
|
+
`scopedLogger` before the handler runs, and equally the reverse cleanup of
|
|
24
|
+
dropping `scopedLogger` and logging runner internals through the singleton —
|
|
25
|
+
that loses the request-id correlation on 404s and unhandled errors, which is the
|
|
26
|
+
only place the trace id is attached automatically.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Set-Cookie headers are appended individually, never joined
|
|
4
|
+
description: Every cookie gets its own header line, because Set-Cookie is the one header comma-joining corrupts
|
|
5
|
+
tags: http
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Set-Cookie headers are appended individually, never joined
|
|
9
|
+
|
|
10
|
+
`PikkuFetchHTTPResponse.toResponse` in
|
|
11
|
+
`packages/core/src/wirings/http/pikku-fetch-http-response.ts` serializes each
|
|
12
|
+
cookie separately and calls `headers.append('Set-Cookie', cookie)` per value
|
|
13
|
+
rather than setting one joined string. `collectSetCookieHeaders` in
|
|
14
|
+
`web-request.ts` mirrors this when copying a web `Response` back onto a
|
|
15
|
+
`PikkuHTTPResponse`: it prefers `Headers.getSetCookie()` where the runtime
|
|
16
|
+
provides it, falls back to scanning for the header by name, de-duplicates, and
|
|
17
|
+
passes the values through as an array.
|
|
18
|
+
|
|
19
|
+
RFC 6265 makes `Set-Cookie` the exception to the "fold repeated headers with
|
|
20
|
+
commas" rule — cookie attributes such as `Expires` contain commas themselves, so
|
|
21
|
+
a joined header is parsed as a single malformed cookie and every cookie after the
|
|
22
|
+
first is lost. `Headers.set()` with a joined value, or a generic header-copy loop
|
|
23
|
+
that treats `set-cookie` like any other header, produces exactly that.
|
|
24
|
+
|
|
25
|
+
**What this rules out:** replacing the append loop with a single
|
|
26
|
+
`set('Set-Cookie', cookies.join(', '))`, and dropping the special-cased
|
|
27
|
+
`set-cookie` branch in `applyWebResponse` in favour of the generic
|
|
28
|
+
`headers.forEach` copy.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: HTTP SSE streams flush headers only after middleware has run
|
|
4
|
+
description: SSE responses defer the header flush and register with the eventHub, at the cost of a stricter ordering the runner must preserve
|
|
5
|
+
tags: http
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# HTTP SSE streams flush headers only after middleware has run
|
|
9
|
+
|
|
10
|
+
`executeRoute` in `packages/core/src/wirings/http/http-runner.ts` puts the
|
|
11
|
+
response into `'stream'` mode and sets the SSE content-type up front, but calls
|
|
12
|
+
`http.response.flushHeaders()` only after `runPikkuFunc` returns. Middleware runs
|
|
13
|
+
inside `runPikkuFunc`, and middleware is where CORS, auth and cookie headers are
|
|
14
|
+
set — flushing earlier would send the response head before those headers exist,
|
|
15
|
+
and they can never be added afterwards. `PikkuFetchHTTPResponse.createStream` in
|
|
16
|
+
`pikku-fetch-http-response.ts` enqueues a bare `:\n\n` comment frame on start for
|
|
17
|
+
the same reason on the client side: proxies and browsers do not surface the
|
|
18
|
+
stream until some body bytes arrive.
|
|
19
|
+
|
|
20
|
+
The SSE channel is also registered with `singletonServices.eventHub` when the
|
|
21
|
+
service exposes `onChannelOpened`, wrapped in a minimal object that satisfies
|
|
22
|
+
`PikkuChannelHandler`. That is what makes `eventHub.publish()` reach SSE
|
|
23
|
+
subscribers and not just WebSocket ones, and `channel.close` is rewrapped so the
|
|
24
|
+
eventHub is told about the close. On the delivery side,
|
|
25
|
+
`LocalEventHubService.publish` treats a throwing `channel.send` as a disconnect
|
|
26
|
+
and calls `onChannelClosed` — an SSE `ReadableStream` controller that the browser
|
|
27
|
+
has already abandoned throws rather than reporting closure.
|
|
28
|
+
|
|
29
|
+
**What this rules out:** hoisting `flushHeaders()` next to the other SSE header
|
|
30
|
+
calls; dropping the `:\n\n` priming frame as dead output; treating the eventHub
|
|
31
|
+
registration as WebSocket-only bookkeeping; and letting `publish` propagate a
|
|
32
|
+
send error instead of unregistering the channel.
|