@pikku/core 0.12.71 → 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 +848 -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 +40 -30
- 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 -11
- package/dist/handle-error.js +6 -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 +7 -17
- package/dist/schema.js +30 -18
- 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 +1 -100
- package/dist/wirings/http/http-runner.js +12 -166
- package/dist/wirings/http/http.types.d.ts +16 -55
- package/dist/wirings/http/index.d.ts +2 -1
- package/dist/wirings/http/index.js +1 -1
- 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 +6 -36
- package/dist/wirings/http/pikku-fetch-http-request.js +56 -50
- 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 +2 -0
- package/dist/wirings/mcp/mcp-runner.js +6 -16
- 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 -2
- 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 +75 -7
- package/src/function/function-runner.ts +73 -30
- 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/gopass-secrets-removed.test.ts +51 -0
- package/src/handle-error.test.ts +108 -1
- package/src/handle-error.ts +8 -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.test.ts +103 -0
- package/src/schema.ts +35 -18
- 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 +12 -168
- package/src/wirings/http/http.types.ts +17 -62
- package/src/wirings/http/index.ts +5 -1
- package/src/wirings/http/log-http-routes.ts +0 -4
- package/src/wirings/http/pikku-fetch-http-request.test.ts +88 -7
- package/src/wirings/http/pikku-fetch-http-request.ts +74 -50
- 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.test.ts +40 -0
- package/src/wirings/mcp/mcp-runner.ts +9 -15
- 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/services/gopass-secrets.ts +0 -78
- 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
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
import { parse as parseQuery } from 'picoquery'
|
|
2
2
|
import { parse as parseCookie } from 'cookie'
|
|
3
3
|
import type { HTTPMethod, PikkuHTTPRequest, PikkuQuery } from './http.types.js'
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
PayloadTooLargeError,
|
|
6
|
+
UnprocessableContentError,
|
|
7
|
+
} from '../../errors/errors.js'
|
|
8
|
+
|
|
9
|
+
export const DEFAULT_MAX_BODY_SIZE = 10 * 1024 * 1024
|
|
10
|
+
|
|
11
|
+
export type PikkuFetchHTTPRequestOptions = Partial<{
|
|
12
|
+
/** Maximum request body size in bytes. Defaults to {@link DEFAULT_MAX_BODY_SIZE}. */
|
|
13
|
+
maxBodySize: number
|
|
14
|
+
}>
|
|
5
15
|
|
|
6
16
|
/**
|
|
7
|
-
* Abstract class representing a pikku request.
|
|
8
|
-
* @template In - The type of the request body.
|
|
9
17
|
* @group RequestResponse
|
|
10
18
|
*/
|
|
11
19
|
export class PikkuFetchHTTPRequest<
|
|
@@ -17,9 +25,14 @@ export class PikkuFetchHTTPRequest<
|
|
|
17
25
|
#rawBodyText: string | undefined
|
|
18
26
|
#rawBodyBuffer: ArrayBuffer | undefined
|
|
19
27
|
#rawBufferPromise: Promise<ArrayBuffer> | undefined
|
|
28
|
+
#maxBodySize: number
|
|
20
29
|
|
|
21
|
-
constructor(
|
|
30
|
+
constructor(
|
|
31
|
+
private request: Request,
|
|
32
|
+
{ maxBodySize = DEFAULT_MAX_BODY_SIZE }: PikkuFetchHTTPRequestOptions = {}
|
|
33
|
+
) {
|
|
22
34
|
this.#url = new URL(request.url)
|
|
35
|
+
this.#maxBodySize = maxBodySize
|
|
23
36
|
}
|
|
24
37
|
|
|
25
38
|
public method(): HTTPMethod {
|
|
@@ -30,35 +43,15 @@ export class PikkuFetchHTTPRequest<
|
|
|
30
43
|
return this.#url.pathname
|
|
31
44
|
}
|
|
32
45
|
|
|
33
|
-
/**
|
|
34
|
-
* Retrieves the request body.
|
|
35
|
-
* @returns A promise that resolves to the request body.
|
|
36
|
-
*/
|
|
37
46
|
public async json(): Promise<In> {
|
|
38
47
|
const text = await this.#readRawText()
|
|
39
48
|
return JSON.parse(text) as In
|
|
40
49
|
}
|
|
41
50
|
|
|
42
|
-
/**
|
|
43
|
-
* Retrieves the raw request body as a Buffer.
|
|
44
|
-
* @returns A promise that resolves to the raw request body.
|
|
45
|
-
*/
|
|
46
51
|
public async arrayBuffer(): Promise<ArrayBuffer> {
|
|
47
52
|
return this.#readRawBuffer()
|
|
48
53
|
}
|
|
49
54
|
|
|
50
|
-
/**
|
|
51
|
-
* Reads the underlying single-use request body exactly once and memoises both
|
|
52
|
-
* the in-flight promise and the result. `json()`, `arrayBuffer()`, `body()`
|
|
53
|
-
* and `toWebRequest()` all funnel through here, so a request whose body is
|
|
54
|
-
* consumed in more than one place can no longer race on the underlying stream
|
|
55
|
-
* and fail with "Body has already been used".
|
|
56
|
-
*
|
|
57
|
-
* If a second consumer asks for the body while the first read is still in
|
|
58
|
-
* flight, that is the concurrent double-read that used to crash — now safe,
|
|
59
|
-
* but warned about so the redundant consumer is found and removed at the
|
|
60
|
-
* source rather than silently leaning on this cache.
|
|
61
|
-
*/
|
|
62
55
|
async #readRawBuffer(): Promise<ArrayBuffer> {
|
|
63
56
|
if (this.#rawBodyBuffer !== undefined) {
|
|
64
57
|
return this.#rawBodyBuffer
|
|
@@ -78,13 +71,66 @@ export class PikkuFetchHTTPRequest<
|
|
|
78
71
|
)
|
|
79
72
|
return this.#rawBufferPromise
|
|
80
73
|
}
|
|
81
|
-
this.#rawBufferPromise = this
|
|
74
|
+
this.#rawBufferPromise = this.#readBoundedBuffer().then((buf) => {
|
|
82
75
|
this.#rawBodyBuffer = buf
|
|
83
76
|
return buf
|
|
84
77
|
})
|
|
85
78
|
return this.#rawBufferPromise
|
|
86
79
|
}
|
|
87
80
|
|
|
81
|
+
async #readBoundedBuffer(): Promise<ArrayBuffer> {
|
|
82
|
+
const contentLength = this.request.headers.get('content-length')
|
|
83
|
+
if (contentLength !== null) {
|
|
84
|
+
const declaredSize = Number(contentLength)
|
|
85
|
+
if (Number.isFinite(declaredSize) && declaredSize > this.#maxBodySize) {
|
|
86
|
+
throw this.#payloadTooLarge()
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const stream = this.request.body
|
|
91
|
+
if (stream === null) {
|
|
92
|
+
const buffer = await this.request.arrayBuffer()
|
|
93
|
+
if (buffer.byteLength > this.#maxBodySize) {
|
|
94
|
+
throw this.#payloadTooLarge()
|
|
95
|
+
}
|
|
96
|
+
return buffer
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const reader = stream.getReader()
|
|
100
|
+
const chunks: Uint8Array[] = []
|
|
101
|
+
let size = 0
|
|
102
|
+
try {
|
|
103
|
+
while (true) {
|
|
104
|
+
const { done, value } = await reader.read()
|
|
105
|
+
if (done) {
|
|
106
|
+
break
|
|
107
|
+
}
|
|
108
|
+
size += value.byteLength
|
|
109
|
+
if (size > this.#maxBodySize) {
|
|
110
|
+
await reader.cancel()
|
|
111
|
+
throw this.#payloadTooLarge()
|
|
112
|
+
}
|
|
113
|
+
chunks.push(value)
|
|
114
|
+
}
|
|
115
|
+
} finally {
|
|
116
|
+
reader.releaseLock()
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const body = new Uint8Array(size)
|
|
120
|
+
let offset = 0
|
|
121
|
+
for (const chunk of chunks) {
|
|
122
|
+
body.set(chunk, offset)
|
|
123
|
+
offset += chunk.byteLength
|
|
124
|
+
}
|
|
125
|
+
return body.buffer as ArrayBuffer
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
#payloadTooLarge(): PayloadTooLargeError {
|
|
129
|
+
return new PayloadTooLargeError(
|
|
130
|
+
`Request body exceeds the maximum size of ${this.#maxBodySize} bytes`
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
|
|
88
134
|
async #readRawText(): Promise<string> {
|
|
89
135
|
if (this.#rawBodyText !== undefined) {
|
|
90
136
|
return this.#rawBodyText
|
|
@@ -98,19 +144,10 @@ export class PikkuFetchHTTPRequest<
|
|
|
98
144
|
return Object.fromEntries(this.request.headers.entries())
|
|
99
145
|
}
|
|
100
146
|
|
|
101
|
-
/**
|
|
102
|
-
* Retrieves the value of a specific header.
|
|
103
|
-
* @param headerName - The name of the header to retrieve.
|
|
104
|
-
* @returns The value of the header, or undefined if the header is not found.
|
|
105
|
-
*/
|
|
106
147
|
public header(headerName: string): string | null {
|
|
107
148
|
return this.request.headers.get(headerName.toLowerCase())
|
|
108
149
|
}
|
|
109
150
|
|
|
110
|
-
/**
|
|
111
|
-
* Retrieves the cookies from the request.
|
|
112
|
-
* @returns An object containing the cookies.
|
|
113
|
-
*/
|
|
114
151
|
public cookie(cookieName: string): string | null {
|
|
115
152
|
if (this.#cookies?.[cookieName]) {
|
|
116
153
|
return this.#cookies[cookieName]
|
|
@@ -120,36 +157,20 @@ export class PikkuFetchHTTPRequest<
|
|
|
120
157
|
return this.#cookies[cookieName] || null
|
|
121
158
|
}
|
|
122
159
|
|
|
123
|
-
/**
|
|
124
|
-
* Retrieves the request parameters.
|
|
125
|
-
* @returns An object containing the request parameters.
|
|
126
|
-
*/
|
|
127
160
|
public params(): Partial<Record<string, string | string[]>> {
|
|
128
161
|
return this.#params
|
|
129
162
|
}
|
|
130
163
|
|
|
131
|
-
/**
|
|
132
|
-
* Sets the request parameters.
|
|
133
|
-
* @param params - An object containing the request parameters to set.
|
|
134
|
-
*/
|
|
135
164
|
public setParams(
|
|
136
165
|
params: Record<string, string | string[] | undefined>
|
|
137
166
|
): void {
|
|
138
167
|
this.#params = params
|
|
139
168
|
}
|
|
140
169
|
|
|
141
|
-
/**
|
|
142
|
-
* Retrieves the query parameters from the request.
|
|
143
|
-
* @returns An object containing the query parameters.
|
|
144
|
-
*/
|
|
145
170
|
public query(): PikkuQuery {
|
|
146
171
|
return parseQuery(this.#url.searchParams.toString()) as PikkuQuery
|
|
147
172
|
}
|
|
148
173
|
|
|
149
|
-
/**
|
|
150
|
-
* Retrieves the combined data from the request, including parameters, query, and body.
|
|
151
|
-
* @returns A promise that resolves to an object containing the combined data.
|
|
152
|
-
*/
|
|
153
174
|
public async data(): Promise<In> {
|
|
154
175
|
const body = await this.body()
|
|
155
176
|
const parts = [this.params(), this.query(), body]
|
|
@@ -214,6 +235,9 @@ export class PikkuFetchHTTPRequest<
|
|
|
214
235
|
)
|
|
215
236
|
}
|
|
216
237
|
} catch (e) {
|
|
238
|
+
if (e instanceof PayloadTooLargeError) {
|
|
239
|
+
throw e
|
|
240
|
+
}
|
|
217
241
|
throw new UnprocessableContentError(`Error parsing body: ${e}`)
|
|
218
242
|
}
|
|
219
243
|
return body
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, test } from 'node:test'
|
|
2
2
|
import assert from 'assert'
|
|
3
|
-
import { PikkuFetchHTTPResponse } from './pikku-fetch-http-response.js'
|
|
3
|
+
import { PikkuFetchHTTPResponse } from './pikku-fetch-http-response.js'
|
|
4
4
|
|
|
5
5
|
describe('PikkuFetchHTTPResponse', () => {
|
|
6
6
|
test('sets status code', () => {
|
|
@@ -118,8 +118,6 @@ export class PikkuFetchHTTPResponse implements PikkuHTTPResponse {
|
|
|
118
118
|
const cookieHeader = Array.from(this.#cookies.entries()).map(
|
|
119
119
|
([name, { value, flags }]) => serializeCookie(name, value, flags)
|
|
120
120
|
)
|
|
121
|
-
// Multiple Set-Cookie headers must be appended separately, not joined with commas
|
|
122
|
-
// per HTTP specification (RFC 6265)
|
|
123
121
|
cookieHeader.forEach((cookie) => this.#headers.append('Set-Cookie', cookie))
|
|
124
122
|
return new Response(this.#body, {
|
|
125
123
|
...args,
|
|
@@ -143,7 +141,6 @@ export class PikkuFetchHTTPResponse implements PikkuHTTPResponse {
|
|
|
143
141
|
this.#send = send
|
|
144
142
|
this.#close = close
|
|
145
143
|
|
|
146
|
-
// Force initial flush
|
|
147
144
|
controller.enqueue(encoder.encode(':\n\n'))
|
|
148
145
|
},
|
|
149
146
|
})
|
|
@@ -7,7 +7,6 @@ import type { HTTPMethod } from '../http.types.js'
|
|
|
7
7
|
describe('PathToRegexRouter', () => {
|
|
8
8
|
let router: PathToRegexRouter
|
|
9
9
|
|
|
10
|
-
// Helper to create mock route wiring
|
|
11
10
|
const mockRoute = (route: string) => ({
|
|
12
11
|
route,
|
|
13
12
|
method: 'get' as HTTPMethod,
|
|
@@ -21,7 +20,6 @@ describe('PathToRegexRouter', () => {
|
|
|
21
20
|
|
|
22
21
|
describe('Static Route Optimization', () => {
|
|
23
22
|
test('should correctly identify static routes', () => {
|
|
24
|
-
// Setup test routes
|
|
25
23
|
pikkuState(
|
|
26
24
|
null,
|
|
27
25
|
'http',
|
|
@@ -42,7 +40,6 @@ describe('PathToRegexRouter', () => {
|
|
|
42
40
|
|
|
43
41
|
router.initialize()
|
|
44
42
|
|
|
45
|
-
// Test static routes - should return exact matches with empty params
|
|
46
43
|
const staticResult = router.match('get', '/static')
|
|
47
44
|
assert.ok(staticResult, 'Static route should match')
|
|
48
45
|
assert.strictEqual(staticResult.route, '/static')
|
|
@@ -55,7 +52,6 @@ describe('PathToRegexRouter', () => {
|
|
|
55
52
|
})
|
|
56
53
|
|
|
57
54
|
test('should handle dynamic routes with parameters', () => {
|
|
58
|
-
// Setup test routes with parameters
|
|
59
55
|
pikkuState(
|
|
60
56
|
null,
|
|
61
57
|
'http',
|
|
@@ -78,7 +74,6 @@ describe('PathToRegexRouter', () => {
|
|
|
78
74
|
|
|
79
75
|
router.initialize()
|
|
80
76
|
|
|
81
|
-
// Test dynamic routes - should return matches with extracted parameters
|
|
82
77
|
const userResult = router.match('get', '/api/users/123')
|
|
83
78
|
assert.ok(userResult, 'Dynamic route should match')
|
|
84
79
|
assert.strictEqual(userResult.route, '/api/users/:id')
|
|
@@ -98,7 +93,6 @@ describe('PathToRegexRouter', () => {
|
|
|
98
93
|
})
|
|
99
94
|
|
|
100
95
|
test('should handle multi-parameter routes', () => {
|
|
101
|
-
// Setup routes with multiple parameters
|
|
102
96
|
pikkuState(
|
|
103
97
|
null,
|
|
104
98
|
'http',
|
|
@@ -124,7 +118,6 @@ describe('PathToRegexRouter', () => {
|
|
|
124
118
|
|
|
125
119
|
router.initialize()
|
|
126
120
|
|
|
127
|
-
// Test multi-parameter routes
|
|
128
121
|
const apiResult = router.match('get', '/api/v2/users/456')
|
|
129
122
|
assert.ok(apiResult, 'Multi-parameter route should match')
|
|
130
123
|
assert.strictEqual(apiResult.route, '/api/:version/users/:userId')
|
|
@@ -140,7 +133,6 @@ describe('PathToRegexRouter', () => {
|
|
|
140
133
|
})
|
|
141
134
|
|
|
142
135
|
test('should prioritize static routes over dynamic routes for performance', () => {
|
|
143
|
-
// Setup mixed routes where static could conflict with dynamic
|
|
144
136
|
pikkuState(
|
|
145
137
|
null,
|
|
146
138
|
'http',
|
|
@@ -149,8 +141,8 @@ describe('PathToRegexRouter', () => {
|
|
|
149
141
|
[
|
|
150
142
|
'get',
|
|
151
143
|
new Map([
|
|
152
|
-
['/api/users', mockRoute('/api/users')],
|
|
153
|
-
['/api/:resource', mockRoute('/api/:resource')],
|
|
144
|
+
['/api/users', mockRoute('/api/users')],
|
|
145
|
+
['/api/:resource', mockRoute('/api/:resource')],
|
|
154
146
|
]),
|
|
155
147
|
],
|
|
156
148
|
])
|
|
@@ -160,10 +152,9 @@ describe('PathToRegexRouter', () => {
|
|
|
160
152
|
|
|
161
153
|
router.initialize()
|
|
162
154
|
|
|
163
|
-
// Static route should be found first (O(1) lookup)
|
|
164
155
|
const result = router.match('get', '/api/users')
|
|
165
156
|
assert.ok(result, 'Route should match')
|
|
166
|
-
assert.strictEqual(result.route, '/api/users')
|
|
157
|
+
assert.strictEqual(result.route, '/api/users')
|
|
167
158
|
assert.deepStrictEqual(result.params, {})
|
|
168
159
|
})
|
|
169
160
|
})
|
|
@@ -178,7 +169,7 @@ describe('PathToRegexRouter', () => {
|
|
|
178
169
|
[
|
|
179
170
|
'get',
|
|
180
171
|
new Map([
|
|
181
|
-
['test', mockRoute('test')],
|
|
172
|
+
['test', mockRoute('test')],
|
|
182
173
|
['api/health', mockRoute('api/health')],
|
|
183
174
|
]),
|
|
184
175
|
],
|
|
@@ -189,7 +180,6 @@ describe('PathToRegexRouter', () => {
|
|
|
189
180
|
|
|
190
181
|
router.initialize()
|
|
191
182
|
|
|
192
|
-
// Should match with or without leading slash in request
|
|
193
183
|
const result1 = router.match('get', '/test')
|
|
194
184
|
assert.ok(result1, 'Should match /test')
|
|
195
185
|
assert.strictEqual(result1.route, 'test')
|
|
@@ -220,7 +210,6 @@ describe('PathToRegexRouter', () => {
|
|
|
220
210
|
|
|
221
211
|
router.initialize()
|
|
222
212
|
|
|
223
|
-
// Channel routes should be accessible via GET method
|
|
224
213
|
const wsResult = router.match('get', '/ws/test')
|
|
225
214
|
assert.ok(wsResult, 'Static channel route should match')
|
|
226
215
|
assert.strictEqual(wsResult.route, '/ws/test')
|
|
@@ -259,7 +248,6 @@ describe('PathToRegexRouter', () => {
|
|
|
259
248
|
|
|
260
249
|
const result = router.match('get', '/api/test')
|
|
261
250
|
assert.ok(result, 'Route should match')
|
|
262
|
-
// Router only returns route and params, middleware is handled separately
|
|
263
251
|
assert.strictEqual(result.route, '/api/test')
|
|
264
252
|
assert.deepStrictEqual(result.params, {})
|
|
265
253
|
})
|
|
@@ -310,7 +298,6 @@ describe('PathToRegexRouter', () => {
|
|
|
310
298
|
pikkuState(null, 'http', 'middleware', new Map())
|
|
311
299
|
pikkuState(null, 'channel', 'channels', new Map())
|
|
312
300
|
|
|
313
|
-
// Don't call initialize manually
|
|
314
301
|
const result = router.match('get', '/test')
|
|
315
302
|
assert.ok(result, 'Should auto-initialize and match')
|
|
316
303
|
assert.strictEqual(result.route, '/test')
|
|
@@ -29,7 +29,6 @@ export class PathToRegexRouter implements Router {
|
|
|
29
29
|
const routes = pikkuState(null, 'http', 'routes')
|
|
30
30
|
const channelRoutes = pikkuState(null, 'channel', 'channels')
|
|
31
31
|
|
|
32
|
-
// Helper function to compile routes for a given method
|
|
33
32
|
const compileRoutesForMethod = (
|
|
34
33
|
method: HTTPMethod,
|
|
35
34
|
routeEntries: Iterable<[string, any]>
|
|
@@ -40,28 +39,24 @@ export class PathToRegexRouter implements Router {
|
|
|
40
39
|
this.staticRoutes.get(method) || new Map<string, StaticRoute>()
|
|
41
40
|
|
|
42
41
|
for (const [routePath] of routeEntries) {
|
|
43
|
-
// Normalize route path - ensure it starts with /
|
|
44
42
|
const normalizedRoutePath = routePath.startsWith('/')
|
|
45
43
|
? routePath
|
|
46
44
|
: `/${routePath}`
|
|
47
45
|
|
|
48
|
-
// Check if route is static (no parameters or wildcards)
|
|
49
46
|
const isStaticRoute = !/\*|:/.test(normalizedRoutePath)
|
|
50
47
|
|
|
51
48
|
if (isStaticRoute) {
|
|
52
|
-
// Store static routes for O(1) lookup
|
|
53
49
|
methodStaticRoutes.set(normalizedRoutePath, {
|
|
54
|
-
route: routePath,
|
|
50
|
+
route: routePath,
|
|
55
51
|
})
|
|
56
52
|
} else {
|
|
57
|
-
// Compile dynamic routes with path-to-regexp
|
|
58
53
|
const matcher = match(normalizedRoutePath, {
|
|
59
54
|
decode: decodeURIComponent,
|
|
60
55
|
})
|
|
61
56
|
|
|
62
57
|
methodCompiledRoutes.set(normalizedRoutePath, {
|
|
63
58
|
matcher,
|
|
64
|
-
route: routePath,
|
|
59
|
+
route: routePath,
|
|
65
60
|
})
|
|
66
61
|
}
|
|
67
62
|
}
|
|
@@ -70,12 +65,10 @@ export class PathToRegexRouter implements Router {
|
|
|
70
65
|
this.staticRoutes.set(method, methodStaticRoutes)
|
|
71
66
|
}
|
|
72
67
|
|
|
73
|
-
// Precompile all HTTP route matchers
|
|
74
68
|
for (const [method, routeMap] of routes.entries()) {
|
|
75
69
|
compileRoutesForMethod(method, routeMap.entries())
|
|
76
70
|
}
|
|
77
71
|
|
|
78
|
-
// Precompile all channel route matchers (treating them as GET routes for WebSocket upgrades)
|
|
79
72
|
const channelRoutesArray: Array<[string, any]> = Array.from(
|
|
80
73
|
channelRoutes.entries()
|
|
81
74
|
).map(([, channel]) => [channel.route, channel])
|
|
@@ -89,10 +82,8 @@ export class PathToRegexRouter implements Router {
|
|
|
89
82
|
this.initialize()
|
|
90
83
|
}
|
|
91
84
|
|
|
92
|
-
// Normalize path - ensure it starts with /
|
|
93
85
|
const normalizedPath = path.startsWith('/') ? path : `/${path}`
|
|
94
86
|
|
|
95
|
-
// First, try static routes for O(1) lookup
|
|
96
87
|
const methodStaticRoutes = this.staticRoutes.get(method)
|
|
97
88
|
if (methodStaticRoutes) {
|
|
98
89
|
const staticRoute = methodStaticRoutes.get(normalizedPath)
|
|
@@ -104,13 +95,11 @@ export class PathToRegexRouter implements Router {
|
|
|
104
95
|
}
|
|
105
96
|
}
|
|
106
97
|
|
|
107
|
-
// If no static route matched, try dynamic routes
|
|
108
98
|
const methodRoutes = this.compiledRoutes.get(method)
|
|
109
99
|
if (!methodRoutes) {
|
|
110
100
|
return null
|
|
111
101
|
}
|
|
112
102
|
|
|
113
|
-
// Try each compiled route for this method
|
|
114
103
|
for (const [, compiledRoute] of methodRoutes.entries()) {
|
|
115
104
|
const result = compiledRoute.matcher(normalizedPath)
|
|
116
105
|
if (result) {
|
|
@@ -34,7 +34,7 @@ const createMockResponse = () => {
|
|
|
34
34
|
const state = {
|
|
35
35
|
statusCode: 0,
|
|
36
36
|
headers: {} as Record<string, string | string[]>,
|
|
37
|
-
body: null as string | null,
|
|
37
|
+
body: null as string | Uint8Array | null,
|
|
38
38
|
redirectUrl: null as string | null,
|
|
39
39
|
redirectStatus: null as number | null,
|
|
40
40
|
}
|
|
@@ -55,7 +55,9 @@ const createMockResponse = () => {
|
|
|
55
55
|
return res
|
|
56
56
|
},
|
|
57
57
|
arrayBuffer(data: any) {
|
|
58
|
-
|
|
58
|
+
// Recorded as given. Coercing a non-string to null here would have hidden
|
|
59
|
+
// a body that arrived as bytes, which is the case worth testing.
|
|
60
|
+
state.body = data ?? null
|
|
59
61
|
return res
|
|
60
62
|
},
|
|
61
63
|
redirect(location: string, status?: number) {
|
|
@@ -348,4 +350,33 @@ describe('applyWebResponse', () => {
|
|
|
348
350
|
assert.equal(state.headers['content-length'], undefined)
|
|
349
351
|
assert.equal(state.headers['transfer-encoding'], undefined)
|
|
350
352
|
})
|
|
353
|
+
|
|
354
|
+
test('passes a binary body through byte for byte', async () => {
|
|
355
|
+
// Reading a body as text is lossy for anything that is not valid UTF-8:
|
|
356
|
+
// 0x8e is not, and decoding it produces U+FFFD, which re-encodes to three
|
|
357
|
+
// bytes. A WASM module or a model file goes over the wire bigger than it
|
|
358
|
+
// started and no longer parses, with a 200 and nothing logged either side.
|
|
359
|
+
const { res, state } = createMockResponse()
|
|
360
|
+
const bytes = new Uint8Array([0x00, 0x61, 0x73, 0x6d, 0x01, 0x8e, 0xff])
|
|
361
|
+
const webRes = new Response(bytes, {
|
|
362
|
+
status: 200,
|
|
363
|
+
headers: { 'content-type': 'application/wasm' },
|
|
364
|
+
})
|
|
365
|
+
|
|
366
|
+
await applyWebResponse(res, webRes)
|
|
367
|
+
|
|
368
|
+
assert.deepEqual(new Uint8Array(state.body as Uint8Array), bytes)
|
|
369
|
+
})
|
|
370
|
+
|
|
371
|
+
test('still writes a JSON body as text', async () => {
|
|
372
|
+
const { res, state } = createMockResponse()
|
|
373
|
+
const webRes = new Response('{"ok":true}', {
|
|
374
|
+
status: 200,
|
|
375
|
+
headers: { 'content-type': 'application/json; charset=utf-8' },
|
|
376
|
+
})
|
|
377
|
+
|
|
378
|
+
await applyWebResponse(res, webRes)
|
|
379
|
+
|
|
380
|
+
assert.equal(state.body, '{"ok":true}')
|
|
381
|
+
})
|
|
351
382
|
})
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import type { PikkuHTTPRequest } from './http.types.js'
|
|
2
2
|
import type { PikkuHTTPResponse } from './http.types.js'
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Converts a PikkuHTTPRequest into a Web API Request.
|
|
6
|
-
* Useful for bridging Pikku routes to libraries that expect standard Web Request objects.
|
|
7
|
-
*/
|
|
8
4
|
export function toWebRequest(req: PikkuHTTPRequest, baseUrl?: string): Request {
|
|
9
5
|
const proto = req.header('x-forwarded-proto') ?? 'http'
|
|
10
6
|
const host =
|
|
@@ -30,11 +26,6 @@ export function toWebRequest(req: PikkuHTTPRequest, baseUrl?: string): Request {
|
|
|
30
26
|
return new Request(url, {
|
|
31
27
|
method,
|
|
32
28
|
headers,
|
|
33
|
-
// `pull` (lazy) rather than `start` (eager): the body is only read from the
|
|
34
|
-
// underlying request when this stream is actually consumed. A consumer that
|
|
35
|
-
// builds a web Request just to read its headers (e.g. a session middleware
|
|
36
|
-
// calling getSession({ headers })) never touches the body, so it does zero
|
|
37
|
-
// body I/O and cannot race the route handler's read of the same request.
|
|
38
29
|
body: new ReadableStream({
|
|
39
30
|
async pull(controller) {
|
|
40
31
|
try {
|
|
@@ -42,7 +33,6 @@ export function toWebRequest(req: PikkuHTTPRequest, baseUrl?: string): Request {
|
|
|
42
33
|
if (buffer.byteLength > 0) {
|
|
43
34
|
controller.enqueue(new Uint8Array(buffer))
|
|
44
35
|
} else {
|
|
45
|
-
// arrayBuffer may be empty if body was pre-parsed (e.g., Express middleware)
|
|
46
36
|
const contentType = (
|
|
47
37
|
headers.get('content-type') || ''
|
|
48
38
|
).toLowerCase()
|
|
@@ -63,9 +53,7 @@ export function toWebRequest(req: PikkuHTTPRequest, baseUrl?: string): Request {
|
|
|
63
53
|
controller.enqueue(new TextEncoder().encode(reconstructed))
|
|
64
54
|
}
|
|
65
55
|
}
|
|
66
|
-
} catch {
|
|
67
|
-
// Empty body
|
|
68
|
-
}
|
|
56
|
+
} catch {}
|
|
69
57
|
controller.close()
|
|
70
58
|
},
|
|
71
59
|
}),
|
|
@@ -108,9 +96,34 @@ function collectSetCookieHeaders(webResponse: Response): string[] {
|
|
|
108
96
|
}
|
|
109
97
|
|
|
110
98
|
/**
|
|
111
|
-
*
|
|
112
|
-
*
|
|
99
|
+
* Content types whose bodies are text. Everything else is bytes.
|
|
100
|
+
*
|
|
101
|
+
* The distinction matters because reading a body as text is lossy for anything
|
|
102
|
+
* that is not valid UTF-8: every byte that does not decode becomes U+FFFD, and
|
|
103
|
+
* re-encoding turns each of those into three bytes. A WASM module or an ONNX
|
|
104
|
+
* model served that way arrives larger than it left and no longer parses, with
|
|
105
|
+
* a 200 and no error anywhere to say why.
|
|
106
|
+
*/
|
|
107
|
+
const TEXTUAL_CONTENT_TYPE =
|
|
108
|
+
/^(text\/|application\/(json|javascript|ecmascript|xml|x-www-form-urlencoded)|[^;]*\+(json|xml)\b)/i
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Read a response body as text where that is meaningful, and as bytes
|
|
112
|
+
* otherwise. An absent content type is treated as text, which is what a body
|
|
113
|
+
* built from a string gets by default and so preserves existing behaviour.
|
|
113
114
|
*/
|
|
115
|
+
async function readBody(
|
|
116
|
+
webResponse: Response
|
|
117
|
+
): Promise<string | Uint8Array | null> {
|
|
118
|
+
const contentType = webResponse.headers.get('content-type')
|
|
119
|
+
if (contentType === null || TEXTUAL_CONTENT_TYPE.test(contentType)) {
|
|
120
|
+
const text = await webResponse.text()
|
|
121
|
+
return text === '' ? null : text
|
|
122
|
+
}
|
|
123
|
+
const bytes = new Uint8Array(await webResponse.arrayBuffer())
|
|
124
|
+
return bytes.byteLength === 0 ? null : bytes
|
|
125
|
+
}
|
|
126
|
+
|
|
114
127
|
export async function applyWebResponse(
|
|
115
128
|
res: PikkuHTTPResponse,
|
|
116
129
|
webResponse: Response
|
|
@@ -138,8 +151,8 @@ export async function applyWebResponse(
|
|
|
138
151
|
res.header('Set-Cookie', setCookieValues)
|
|
139
152
|
}
|
|
140
153
|
|
|
141
|
-
const body = await webResponse
|
|
142
|
-
if (body) {
|
|
154
|
+
const body = await readBody(webResponse)
|
|
155
|
+
if (body !== null) {
|
|
143
156
|
if (res.send) {
|
|
144
157
|
res.send(body)
|
|
145
158
|
} else {
|
|
@@ -132,7 +132,6 @@ describe('MCPEndpointRegistry', () => {
|
|
|
132
132
|
})
|
|
133
133
|
|
|
134
134
|
test('should handle empty object gracefully', async () => {
|
|
135
|
-
// Test with empty object
|
|
136
135
|
await registry.loadFromMCPJson({})
|
|
137
136
|
assert.deepStrictEqual(registry.getTools(), [])
|
|
138
137
|
assert.deepStrictEqual(registry.getResources(), [])
|
|
@@ -329,6 +329,46 @@ describe('runMCPTool', () => {
|
|
|
329
329
|
}
|
|
330
330
|
)
|
|
331
331
|
})
|
|
332
|
+
|
|
333
|
+
test('withholds the error message and stack from internal MCP errors in production', async () => {
|
|
334
|
+
pikkuState(null, 'mcp', 'toolsMeta').prodBoom = {
|
|
335
|
+
name: 'prodBoom',
|
|
336
|
+
title: 'Prod Boom',
|
|
337
|
+
description: 'Prod Boom',
|
|
338
|
+
pikkuFuncId: 'prodBoomFunc',
|
|
339
|
+
inputSchema: null,
|
|
340
|
+
outputSchema: null,
|
|
341
|
+
} as never
|
|
342
|
+
registerFunction('prodBoomFunc', async () => {
|
|
343
|
+
throw new Error('secret internal detail')
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
const originalNodeEnv = process.env.NODE_ENV
|
|
347
|
+
process.env.NODE_ENV = 'production'
|
|
348
|
+
try {
|
|
349
|
+
await assert.rejects(
|
|
350
|
+
() =>
|
|
351
|
+
runMCPTool(
|
|
352
|
+
{ jsonrpc: '2.0', id: 'prod-boom-1', params: {} },
|
|
353
|
+
{ mcp: mcpWire as never },
|
|
354
|
+
'prodBoom'
|
|
355
|
+
),
|
|
356
|
+
(error: unknown) => {
|
|
357
|
+
assert.ok(error instanceof MCPError)
|
|
358
|
+
assert.equal(error.error.code, -32603)
|
|
359
|
+
assert.equal(error.error.message, 'Internal error')
|
|
360
|
+
assert.equal(error.error.data, undefined)
|
|
361
|
+
return true
|
|
362
|
+
}
|
|
363
|
+
)
|
|
364
|
+
} finally {
|
|
365
|
+
if (originalNodeEnv === undefined) {
|
|
366
|
+
delete process.env.NODE_ENV
|
|
367
|
+
} else {
|
|
368
|
+
process.env.NODE_ENV = originalNodeEnv
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
})
|
|
332
372
|
})
|
|
333
373
|
|
|
334
374
|
describe('runMCPPrompt', () => {
|