@pikku/core 0.12.142 → 0.12.144
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/dist/analytics/analytics.d.ts +14 -0
- package/dist/analytics/analytics.js +14 -0
- package/dist/analytics/analytics.types.d.ts +1 -0
- package/dist/analytics/anonymous-analytics-identity.d.ts +1 -0
- package/dist/analytics/cookie-analytics-identity.d.ts +1 -0
- package/dist/analytics/mint-cookie.d.ts +1 -0
- package/dist/{wirings/channel/channel-middleware-runner.d.ts → channel-middleware-runner.d.ts} +17 -3
- package/dist/{wirings/channel/channel-middleware-runner.js → channel-middleware-runner.js} +24 -8
- package/dist/classification/data-classification.d.ts +13 -0
- package/dist/classification/secret-value.d.ts +7 -0
- package/dist/classification/secret-value.js +7 -0
- package/dist/crypto-utils.d.ts +93 -0
- package/dist/crypto-utils.js +92 -0
- package/dist/dev/hot-reload.d.ts +16 -0
- package/dist/dev/hot-reload.js +16 -1
- package/dist/dev/module-runner.js +7 -3
- package/dist/dev/reload-meta.js +1 -1
- package/dist/errors/error-handler.d.ts +9 -0
- package/dist/errors/error-handler.js +8 -0
- package/dist/errors/errors.d.ts +219 -0
- package/dist/errors/errors.js +227 -0
- package/dist/errors/serialized-error.d.ts +4 -0
- package/dist/function/abort-scope.d.ts +5 -0
- package/dist/function/function-meta.types.d.ts +20 -0
- package/dist/function/function-runner.d.ts +41 -0
- package/dist/function/function-runner.js +57 -11
- package/dist/function/functions.types.d.ts +59 -0
- package/dist/function/functions.types.js +23 -0
- package/dist/function/list.types.d.ts +4 -0
- package/dist/lifecycle.d.ts +12 -1
- package/dist/lifecycle.js +12 -1
- package/dist/middleware/addon-scope-cap.d.ts +4 -0
- package/dist/middleware/addon-scope-cap.js +7 -3
- package/dist/middleware/auth-apikey.js +3 -3
- package/dist/middleware/auth-bearer.js +5 -13
- package/dist/middleware/auth-cookie.js +3 -3
- package/dist/middleware/middleware-factories.d.ts +17 -0
- package/dist/middleware/middleware-factories.js +17 -0
- package/dist/middleware/middleware.types.d.ts +23 -0
- package/dist/middleware/remote-auth.d.ts +15 -0
- package/dist/middleware/remote-auth.js +18 -3
- package/dist/middleware/remote-jobs-secret.js +2 -10
- package/dist/middleware-runner.d.ts +7 -0
- package/dist/middleware-runner.js +23 -7
- package/dist/permissions.d.ts +13 -0
- package/dist/permissions.js +13 -0
- package/dist/pikku-state.d.ts +49 -0
- package/dist/pikku-state.js +49 -0
- package/dist/remote.js +20 -5
- package/dist/schema.d.ts +36 -0
- package/dist/schema.js +36 -0
- package/dist/services/agent-run-state-service.d.ts +8 -0
- package/dist/services/agent-runner-service.d.ts +24 -0
- package/dist/services/agent-storage-service.d.ts +8 -0
- package/dist/services/ai-embedding-service.d.ts +4 -0
- package/dist/services/audit-service.d.ts +48 -0
- package/dist/services/audit-service.js +22 -0
- package/dist/services/content-service.d.ts +34 -0
- package/dist/services/credential-wire-service.d.ts +9 -0
- package/dist/services/credential-wire-service.js +9 -0
- package/dist/services/deployment-service.d.ts +14 -0
- package/dist/services/email-service.d.ts +20 -0
- package/dist/services/email-template.d.ts +24 -0
- package/dist/services/email-template.js +12 -0
- package/dist/services/file-scenario-run-store.d.ts +5 -0
- package/dist/services/file-scenario-run-store.js +4 -0
- package/dist/services/gateway-service.d.ts +5 -0
- package/dist/services/in-memory-agent-run-state-service.d.ts +5 -0
- package/dist/services/in-memory-agent-run-state-service.js +5 -0
- package/dist/services/in-memory-lease-service.d.ts +5 -0
- package/dist/services/in-memory-lease-service.js +5 -0
- package/dist/services/in-memory-session-store.d.ts +4 -0
- package/dist/services/in-memory-session-store.js +4 -0
- package/dist/services/incoming-webhook-queue.d.ts +2 -0
- package/dist/services/incoming-webhook-queue.js +2 -0
- package/dist/services/incoming-webhook-service.d.ts +11 -1
- package/dist/services/incoming-webhook-service.js +5 -1
- package/dist/services/index.d.ts +1 -5
- package/dist/services/index.js +1 -5
- package/dist/services/jwt-service.d.ts +8 -0
- package/dist/services/lease-service.d.ts +5 -0
- package/dist/services/lease-service.js +1 -0
- package/dist/services/local-content-request-handler.d.ts +20 -0
- package/dist/services/local-content-request-handler.js +11 -0
- package/dist/services/local-content.d.ts +45 -0
- package/dist/services/local-content.js +35 -0
- package/dist/services/local-credential-service.d.ts +5 -0
- package/dist/services/local-credential-service.js +5 -0
- package/dist/services/local-email-service.d.ts +7 -0
- package/dist/services/local-email-service.js +7 -0
- package/dist/services/local-secrets.d.ts +8 -0
- package/dist/services/local-secrets.js +8 -0
- package/dist/services/local-variables.d.ts +6 -0
- package/dist/services/local-variables.js +6 -0
- package/dist/services/logger.d.ts +4 -0
- package/dist/services/logger.js +4 -0
- package/dist/services/meta-service.d.ts +38 -0
- package/dist/services/meta-service.js +6 -0
- package/dist/services/queue-webhook-service.d.ts +19 -0
- package/dist/services/queue-webhook-service.js +19 -0
- package/dist/services/remote-jobs.d.ts +8 -13
- package/dist/services/remote-jobs.js +3 -54
- package/dist/services/scenario-cookie-jar.d.ts +4 -0
- package/dist/services/scheduler-service.d.ts +16 -0
- package/dist/services/scheduler-service.js +12 -0
- package/dist/services/schema-service.d.ts +9 -0
- package/dist/services/scope-service.d.ts +10 -0
- package/dist/services/scoped-secret-service.d.ts +5 -0
- package/dist/services/scoped-secret-service.js +5 -0
- package/dist/services/secret-host-binding.d.ts +5 -0
- package/dist/services/secret-host-binding.js +5 -0
- package/dist/services/secret-service.d.ts +19 -1
- package/dist/services/secretless.d.ts +6 -0
- package/dist/services/secretless.js +6 -0
- package/dist/services/session-store.d.ts +5 -0
- package/dist/services/stub-tracker.d.ts +1 -0
- package/dist/services/temporary-file-service.d.ts +9 -0
- package/dist/services/temporary-file-service.js +9 -0
- package/dist/services/trigger-service.d.ts +4 -0
- package/dist/services/trigger-source-store.d.ts +13 -0
- package/dist/services/trigger-source-store.js +7 -0
- package/dist/services/typed-credential-service.d.ts +6 -0
- package/dist/services/typed-credential-service.js +5 -0
- package/dist/services/typed-secret-service.d.ts +12 -0
- package/dist/services/typed-secret-service.js +11 -0
- package/dist/services/typed-variables-service.d.ts +1 -0
- package/dist/services/user-session-service.d.ts +31 -1
- package/dist/services/user-session-service.js +29 -3
- package/dist/services/v8-coverage-service.d.ts +27 -0
- package/dist/services/v8-coverage-service.js +5 -0
- package/dist/services/variables-service.d.ts +8 -0
- package/dist/services/virtual-user-sign-in.d.ts +1 -0
- package/dist/services/virtual-user-statement.d.ts +8 -0
- package/dist/services/virtual-user-statement.js +4 -0
- package/dist/services/webhook-service.d.ts +25 -0
- package/dist/services/webhook-service.js +15 -0
- package/dist/services/workflow-service.d.ts +6 -0
- package/dist/test-utils.js +1 -1
- package/dist/testing/service-tests.d.ts +4 -0
- package/dist/time-utils.d.ts +15 -0
- package/dist/time-utils.js +14 -0
- package/dist/types/core.types.d.ts +80 -0
- package/dist/types/state.types.d.ts +4 -0
- package/dist/utils/hmac.d.ts +3 -0
- package/dist/utils/safe-fetch.d.ts +14 -0
- package/dist/utils/safe-fetch.js +13 -0
- package/dist/utils/stable-stringify.d.ts +11 -0
- package/dist/utils/stable-stringify.js +33 -0
- package/dist/utils.d.ts +28 -0
- package/dist/utils.js +22 -0
- package/dist/version.d.ts +7 -0
- package/dist/version.js +7 -0
- package/dist/wirings/addon/define-screens.d.ts +2 -0
- package/dist/wirings/addon/remote-addon-auth.d.ts +9 -0
- package/dist/wirings/addon/remote-addon-auth.js +5 -0
- package/dist/wirings/addon/wire-addon.d.ts +4 -0
- package/dist/wirings/addon/wire-remote-addon.d.ts +1 -0
- package/dist/wirings/agent/agent-agui.d.ts +14 -5
- package/dist/wirings/agent/agent-agui.js +17 -6
- package/dist/wirings/agent/agent-helpers.d.ts +61 -1
- package/dist/wirings/agent/agent-helpers.js +62 -2
- package/dist/wirings/agent/agent-interrupt.d.ts +5 -0
- package/dist/wirings/agent/agent-output.d.ts +20 -0
- package/dist/wirings/agent/agent-output.js +69 -0
- package/dist/wirings/agent/agent-prepare.d.ts +41 -0
- package/dist/wirings/agent/agent-prepare.js +38 -2
- package/dist/wirings/agent/agent-registry.d.ts +8 -0
- package/dist/wirings/agent/agent-registry.js +10 -4
- package/dist/wirings/agent/agent-runner.d.ts +33 -0
- package/dist/wirings/agent/agent-runner.js +40 -7
- package/dist/wirings/agent/agent-stream.d.ts +30 -0
- package/dist/wirings/agent/agent-stream.js +33 -11
- package/dist/wirings/agent/agent.types.d.ts +43 -0
- package/dist/wirings/agent/voice-input.d.ts +12 -0
- package/dist/wirings/agent/voice-input.js +12 -0
- package/dist/wirings/agent/voice-output.d.ts +14 -0
- package/dist/wirings/agent/voice-output.js +10 -0
- package/dist/wirings/agent-scorer/agent-scorer-judge.js +1 -2
- package/dist/wirings/agent-scorer/agent-scorer-registry.d.ts +10 -0
- package/dist/wirings/agent-scorer/agent-scorer-registry.js +10 -0
- package/dist/wirings/agent-scorer/agent-scorer-snapshots.d.ts +1 -0
- package/dist/wirings/agent-scorer/agent-scorer-snapshots.js +1 -0
- package/dist/wirings/agent-scorer/agent-scorer.types.d.ts +7 -0
- package/dist/wirings/channel/channel-common.js +1 -1
- package/dist/wirings/channel/channel-rpc.types.d.ts +5 -0
- package/dist/wirings/channel/channel-runner.d.ts +22 -0
- package/dist/wirings/channel/channel-runner.js +22 -0
- package/dist/wirings/channel/channel-store.d.ts +8 -0
- package/dist/wirings/channel/channel-store.js +7 -0
- package/dist/wirings/channel/channel.types.d.ts +18 -0
- package/dist/wirings/channel/define-channel-routes.d.ts +5 -0
- package/dist/wirings/channel/define-channel-routes.js +5 -0
- package/dist/wirings/channel/eventhub-service.d.ts +9 -0
- package/dist/wirings/channel/eventhub-store.d.ts +1 -0
- package/dist/wirings/channel/eventhub-store.js +1 -0
- package/dist/wirings/channel/index.d.ts +1 -1
- package/dist/wirings/channel/index.js +1 -1
- package/dist/wirings/channel/local/local-channel-handler.d.ts +1 -0
- package/dist/wirings/channel/local/local-channel-handler.js +1 -0
- package/dist/wirings/channel/local/local-channel-runner.d.ts +13 -0
- package/dist/wirings/channel/local/local-channel-runner.js +13 -0
- package/dist/wirings/channel/local/local-eventhub-service.d.ts +1 -0
- package/dist/wirings/channel/local/local-eventhub-service.js +1 -0
- package/dist/wirings/channel/log-channels.d.ts +1 -0
- package/dist/wirings/channel/log-channels.js +1 -0
- package/dist/wirings/channel/pikku-abstract-channel-handler.d.ts +5 -0
- package/dist/wirings/channel/pikku-abstract-channel-handler.js +5 -0
- package/dist/wirings/channel/serverless/serverless-channel-runner.d.ts +32 -0
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +31 -0
- package/dist/wirings/cli/channel/cli-channel-runner.d.ts +8 -0
- package/dist/wirings/cli/channel/cli-channel-runner.js +8 -0
- package/dist/wirings/cli/channel/cli-raw-channel-runner.d.ts +1 -0
- package/dist/wirings/cli/cli-runner.d.ts +43 -0
- package/dist/wirings/cli/cli-runner.js +43 -0
- package/dist/wirings/cli/command-parser.d.ts +13 -0
- package/dist/wirings/cli/command-parser.js +12 -0
- package/dist/wirings/credential/credential-overrides.d.ts +1 -0
- package/dist/wirings/credential/credential.types.d.ts +7 -0
- package/dist/wirings/credential/validate-credential-definitions.d.ts +7 -0
- package/dist/wirings/credential/validate-credential-definitions.js +7 -0
- package/dist/wirings/flag/cached-flag-source.d.ts +1 -0
- package/dist/wirings/flag/flag.types.d.ts +3 -0
- package/dist/wirings/gateway/gateway-runner.d.ts +23 -0
- package/dist/wirings/gateway/gateway-runner.js +23 -0
- package/dist/wirings/gateway/gateway.types.d.ts +3 -0
- package/dist/wirings/gateway/local-gateway-service.d.ts +10 -0
- package/dist/{services → wirings/gateway}/local-gateway-service.js +6 -2
- package/dist/wirings/http/http-routes.d.ts +21 -0
- package/dist/wirings/http/http-routes.js +11 -0
- package/dist/wirings/http/http-runner.d.ts +71 -0
- package/dist/wirings/http/http-runner.js +73 -5
- package/dist/wirings/http/http.types.d.ts +27 -0
- package/dist/wirings/http/index.d.ts +1 -0
- package/dist/wirings/http/index.js +1 -0
- package/dist/wirings/http/log-http-routes.d.ts +1 -0
- package/dist/wirings/http/log-http-routes.js +1 -0
- package/dist/wirings/http/merge-request-data.d.ts +12 -0
- package/dist/wirings/http/merge-request-data.js +42 -0
- package/dist/wirings/http/pikku-fetch-http-request.d.ts +1 -0
- package/dist/wirings/http/pikku-fetch-http-request.js +3 -32
- package/dist/wirings/http/pikku-fetch-http-response.d.ts +1 -0
- package/dist/wirings/http/pikku-fetch-http-response.js +1 -0
- package/dist/wirings/http/routers/http-router.d.ts +6 -0
- package/dist/wirings/http/routers/http-router.js +6 -0
- package/dist/wirings/http/web-request.d.ts +17 -0
- package/dist/wirings/http/web-request.js +17 -0
- package/dist/wirings/mcp/mcp-endpoint-registry.d.ts +7 -0
- package/dist/wirings/mcp/mcp-endpoint-registry.js +7 -0
- package/dist/wirings/mcp/mcp-runner.d.ts +63 -0
- package/dist/wirings/mcp/mcp-runner.js +62 -0
- package/dist/wirings/mcp/mcp.types.d.ts +12 -0
- package/dist/wirings/node/node.types.d.ts +4 -0
- package/dist/wirings/oauth2/oauth2.types.d.ts +2 -0
- package/dist/wirings/queue/in-memory-queue-service.d.ts +23 -0
- package/dist/wirings/queue/in-memory-queue-service.js +129 -0
- package/dist/wirings/queue/index.d.ts +2 -1
- package/dist/wirings/queue/index.js +1 -0
- package/dist/wirings/queue/queue-identity.js +2 -14
- package/dist/wirings/queue/queue-runner.d.ts +37 -0
- package/dist/wirings/queue/queue-runner.js +37 -0
- package/dist/wirings/queue/queue.types.d.ts +56 -0
- package/dist/wirings/queue/register-queue-helper.d.ts +12 -0
- package/dist/wirings/queue/register-queue-helper.js +11 -0
- package/dist/wirings/queue/remote-queue-job.d.ts +11 -0
- package/dist/wirings/queue/remote-queue-job.js +41 -0
- package/dist/wirings/queue/signed-queue-service.d.ts +4 -1
- package/dist/wirings/queue/signed-queue-service.js +3 -0
- package/dist/wirings/queue/validate-worker-config.d.ts +1 -0
- package/dist/wirings/role/role.types.d.ts +3 -0
- package/dist/wirings/rpc/rpc-runner.d.ts +24 -0
- package/dist/wirings/rpc/rpc-runner.js +37 -2
- package/dist/wirings/rpc/rpc-types.d.ts +2 -0
- package/dist/wirings/scheduler/index.d.ts +2 -1
- package/dist/wirings/scheduler/index.js +1 -0
- package/dist/wirings/scheduler/log-schedulers.d.ts +1 -0
- package/dist/wirings/scheduler/log-schedulers.js +1 -0
- package/dist/wirings/scheduler/remote-scheduled-job.d.ts +11 -0
- package/dist/wirings/scheduler/remote-scheduled-job.js +20 -0
- package/dist/wirings/scheduler/scheduler-runner.d.ts +29 -0
- package/dist/wirings/scheduler/scheduler-runner.js +28 -0
- package/dist/wirings/scheduler/scheduler.types.d.ts +15 -0
- package/dist/wirings/scope/scope.types.d.ts +5 -0
- package/dist/wirings/secret/index.d.ts +2 -2
- package/dist/wirings/secret/index.js +1 -1
- package/dist/wirings/secret/secret.types.d.ts +26 -1
- package/dist/wirings/secret/secret.types.js +1 -0
- package/dist/wirings/secret/validate-secret-definitions.d.ts +8 -0
- package/dist/wirings/secret/validate-secret-definitions.js +15 -0
- package/dist/wirings/trigger/in-memory-trigger-service.d.ts +11 -0
- package/dist/{services → wirings/trigger}/in-memory-trigger-service.js +10 -3
- package/dist/wirings/trigger/index.d.ts +1 -1
- package/dist/wirings/trigger/pikku-trigger-service.d.ts +8 -3
- package/dist/wirings/trigger/pikku-trigger-service.js +14 -3
- package/dist/wirings/trigger/trigger-runner.d.ts +27 -2
- package/dist/wirings/trigger/trigger-runner.js +35 -2
- package/dist/wirings/trigger/trigger.types.d.ts +26 -4
- package/dist/wirings/trigger/webhook-source-runner.d.ts +24 -0
- package/dist/wirings/trigger/webhook-source-runner.js +19 -0
- package/dist/wirings/trigger/webhook-source.types.d.ts +12 -2
- package/dist/wirings/trigger/webhook-source.types.js +1 -1
- package/dist/wirings/variable/validate-variable-definitions.d.ts +7 -0
- package/dist/wirings/variable/validate-variable-definitions.js +7 -0
- package/dist/wirings/variable/variable.types.d.ts +7 -0
- package/dist/wirings/virtual-user/conversation/conversation.types.d.ts +5 -0
- package/dist/wirings/virtual-user/conversation/run-conversation.d.ts +6 -0
- package/dist/wirings/virtual-user/conversation/run-conversation.js +1 -1
- package/dist/{services → wirings/virtual-user}/http-virtual-users.d.ts +4 -3
- package/dist/{services → wirings/virtual-user}/http-virtual-users.js +6 -6
- package/dist/wirings/virtual-user/index.d.ts +1 -1
- package/dist/wirings/virtual-user/index.js +1 -1
- package/dist/wirings/virtual-user/run-virtual-user.d.ts +2 -1
- package/dist/wirings/virtual-user/run-virtual-user.js +1 -14
- package/dist/wirings/virtual-user/virtual-user-declaration.types.d.ts +4 -0
- package/dist/wirings/virtual-user/virtual-user-scaffold.d.ts +10 -1
- package/dist/wirings/virtual-user/virtual-user-scaffold.js +5 -0
- package/dist/wirings/virtual-user/virtual-user-schedule.d.ts +5 -0
- package/dist/wirings/virtual-user/virtual-user-schedule.js +1 -0
- package/dist/wirings/virtual-user/virtual-user-target.d.ts +1 -0
- package/dist/wirings/webhook/define-outgoing-webhook.d.ts +20 -0
- package/dist/wirings/webhook/define-outgoing-webhook.js +9 -0
- package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +8 -4
- package/dist/wirings/workflow/dsl/workflow-runner.d.ts +7 -0
- package/dist/wirings/workflow/dsl/workflow-runner.js +7 -0
- package/dist/wirings/workflow/feature.d.ts +12 -0
- package/dist/wirings/workflow/feature.js +12 -0
- package/dist/wirings/workflow/graph/graph-node.d.ts +5 -0
- package/dist/wirings/workflow/graph/graph-node.js +5 -0
- package/dist/wirings/workflow/graph/template.d.ts +6 -0
- package/dist/wirings/workflow/graph/template.js +5 -0
- package/dist/wirings/workflow/graph/wire-workflow-graph.d.ts +12 -0
- package/dist/wirings/workflow/graph/wire-workflow-graph.js +10 -0
- package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +11 -0
- package/dist/wirings/workflow/graph/workflow-graph.types.js +1 -0
- package/dist/{services → wirings/workflow}/in-memory-workflow-service.d.ts +8 -3
- package/dist/{services → wirings/workflow}/in-memory-workflow-service.js +9 -4
- package/dist/wirings/workflow/pikku-scenario-service.d.ts +1 -1
- package/dist/wirings/workflow/pikku-scenario-service.js +2 -2
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +1 -0
- package/dist/wirings/workflow/pikku-workflow-service.js +1 -0
- package/dist/wirings/workflow/run-timeline.d.ts +21 -0
- package/dist/wirings/workflow/run-timeline.js +15 -7
- package/dist/wirings/workflow/scenario-coverage.d.ts +1 -0
- package/dist/wirings/workflow/scenario-poll.d.ts +1 -0
- package/dist/wirings/workflow/scenario-prose.d.ts +6 -0
- package/dist/wirings/workflow/scenario-prose.js +6 -0
- package/dist/wirings/workflow/scenario-run.types.d.ts +3 -0
- package/dist/wirings/workflow/scenario-step.types.d.ts +1 -0
- package/dist/wirings/workflow/scenario-step.types.js +1 -0
- package/dist/wirings/workflow/scenario-surface.js +1 -13
- package/dist/wirings/workflow/scenario.types.d.ts +6 -0
- package/dist/wirings/workflow/workflow-approval-policy.d.ts +6 -0
- package/dist/wirings/workflow/workflow-approval-policy.js +6 -0
- package/dist/wirings/workflow/workflow-constants.d.ts +7 -1
- package/dist/wirings/workflow/workflow-constants.js +10 -1
- package/dist/wirings/workflow/workflow-errors.d.ts +13 -0
- package/dist/wirings/workflow/workflow-errors.js +13 -0
- package/dist/wirings/workflow/workflow-invocation-id.d.ts +4 -0
- package/dist/wirings/workflow/workflow-invocation-id.js +4 -0
- package/dist/wirings/workflow/workflow-queue-workers.d.ts +3 -0
- package/dist/wirings/workflow/workflow-run-ownership.d.ts +1 -0
- package/dist/wirings/workflow/workflow-run-ownership.js +1 -0
- package/dist/wirings/workflow/workflow-status-stream.d.ts +1 -0
- package/dist/wirings/workflow/workflow-unwind-plan.js +2 -7
- package/dist/wirings/workflow/workflow.types.d.ts +40 -0
- package/package.json +26 -9
- package/CHANGELOG.md +0 -6961
- package/dist/services/in-memory-queue-service.d.ts +0 -8
- package/dist/services/in-memory-queue-service.js +0 -54
- package/dist/services/in-memory-trigger-service.d.ts +0 -4
- package/dist/services/local-gateway-service.d.ts +0 -6
- package/dist/utils/hash.d.ts +0 -2
- package/dist/utils/hash.js +0 -23
- package/knowledge/decisions/index.md +0 -19
- package/knowledge/decisions/internals/a-credential-name-declared-twice-must-agree-on-schema-and-type.md +0 -29
- package/knowledge/decisions/internals/a-grant-can-name-a-scope-declared-without-its-addon.md +0 -29
- package/knowledge/decisions/internals/a-held-run-is-woken-later-not-retried.md +0 -28
- package/knowledge/decisions/internals/a-non-streaming-agent-run-registers-with-agentrunstate-too.md +0 -22
- package/knowledge/decisions/internals/a-reset-suite-makes-the-dev-seed-the-fixture.md +0 -50
- package/knowledge/decisions/internals/a-resumed-agent-turn-is-as-interruptible-as-the-first.md +0 -20
- package/knowledge/decisions/internals/a-scenario-step-template-is-offered-unfilled.md +0 -21
- package/knowledge/decisions/internals/a-scheduled-task-writes-its-caller-session-before-it-runs.md +0 -22
- package/knowledge/decisions/internals/a-secret-set-in-memory-shadows-the-variable-of-the-same-name.md +0 -28
- package/knowledge/decisions/internals/a-secret-that-fails-to-decrypt-fails-the-whole-read.md +0 -49
- package/knowledge/decisions/internals/a-virtual-user-acts-through-invokeraw-so-a-refusal-is-data.md +0 -32
- package/knowledge/decisions/internals/a-virtual-user-cadence-is-a-row-not-a-timer.md +0 -66
- package/knowledge/decisions/internals/a-virtual-user-converse-signs-in-before-its-first-turn.md +0 -24
- package/knowledge/decisions/internals/a-virtual-user-decides-whether-to-trust-memory-once-per-turn.md +0 -21
- package/knowledge/decisions/internals/a-virtual-user-email-is-computed-with-the-run-id-as-a-sub-address.md +0 -34
- package/knowledge/decisions/internals/a-virtual-user-run-is-not-a-workflow-but-it-needs-a-trigger.md +0 -65
- package/knowledge/decisions/internals/a-wall-clock-threshold-is-a-load-test-in-disguise.md +0 -46
- package/knowledge/decisions/internals/a-workflow-wire-is-built-from-the-run-not-from-the-rpc-service.md +0 -45
- package/knowledge/decisions/internals/addon-package-roots-resolve-by-walking-node-module-search-paths.md +0 -26
- package/knowledge/decisions/internals/addon-pikku-meta-ships-at-the-package-root-or-under-dist.md +0 -32
- package/knowledge/decisions/internals/addon-singleton-services-are-cached-per-namespace-not-per-package.md +0 -33
- package/knowledge/decisions/internals/addon-workflow-names-are-prefixed-with-the-consumer-namespace.md +0 -28
- package/knowledge/decisions/internals/agent-agui-bridge-obeys-the-client-ordering-contract.md +0 -29
- package/knowledge/decisions/internals/agent-audio-chunks-carry-the-format-the-provider-returned.md +0 -20
- package/knowledge/decisions/internals/agent-context-waits-for-a-tool-result-still-being-written.md +0 -21
- package/knowledge/decisions/internals/agent-credential-suspensions-hide-the-tool-result.md +0 -26
- package/knowledge/decisions/internals/agent-delegate-and-supervise-hide-different-text.md +0 -26
- package/knowledge/decisions/internals/agent-llm-tool-arguments-have-nulls-stripped.md +0 -23
- package/knowledge/decisions/internals/agent-model-config-stays-a-single-resolution-seam.md +0 -25
- package/knowledge/decisions/internals/agent-onerror-hooks-cannot-change-the-failure.md +0 -22
- package/knowledge/decisions/internals/agent-runner-methods-must-keep-their-receiver.md +0 -22
- package/knowledge/decisions/internals/agent-speech-travels-as-a-custom-agui-event.md +0 -22
- package/knowledge/decisions/internals/agent-stream-persistence-is-best-effort.md +0 -27
- package/knowledge/decisions/internals/agent-sub-agents-inherit-the-parent-context-block.md +0 -26
- package/knowledge/decisions/internals/agent-tool-execute-failures-are-logged-unconditionally.md +0 -25
- package/knowledge/decisions/internals/agent-voice-input-transcribes-audio-parts-in-place.md +0 -22
- package/knowledge/decisions/internals/agent-working-memory-is-persisted-only-when-valid.md +0 -25
- package/knowledge/decisions/internals/an-addon-scope-root-loses-to-a-root-the-host-already-declares.md +0 -39
- package/knowledge/decisions/internals/an-agent-interrupt-is-not-a-failure.md +0 -23
- package/knowledge/decisions/internals/an-agent-is-offered-under-its-registry-key-and-only-within-the-virtual-users-scopes.md +0 -27
- package/knowledge/decisions/internals/an-agent-run-owned-by-another-instance-says-so.md +0 -25
- package/knowledge/decisions/internals/an-agent-stream-send-must-return-the-inner-sends-promise.md +0 -22
- package/knowledge/decisions/internals/an-empty-text-part-is-omitted-from-an-agent-message.md +0 -20
- package/knowledge/decisions/internals/an-empty-transcript-is-not-recorded.md +0 -22
- package/knowledge/decisions/internals/an-oauth2-credential-implies-an-optional-app-secret.md +0 -26
- package/knowledge/decisions/internals/an-unref-d-timer-cannot-be-awaited-under-node-test.md +0 -66
- package/knowledge/decisions/internals/analytics-identity-resolvers-run-in-declared-order.md +0 -22
- package/knowledge/decisions/internals/channel-message-handlers-accept-three-config-shapes.md +0 -30
- package/knowledge/decisions/internals/channel-middleware-caches-only-statically-resolved-middleware.md +0 -31
- package/knowledge/decisions/internals/channel-state-accessors-are-unsound-generics-that-every-implementation-asserts.md +0 -33
- package/knowledge/decisions/internals/channel-state-is-per-socket-session-state-is-per-user.md +0 -29
- package/knowledge/decisions/internals/channel-user-id-is-persisted-after-onconnect-middleware-runs.md +0 -28
- package/knowledge/decisions/internals/cli-option-names-are-camelcase-in-state-and-kebab-on-the-command-line.md +0 -27
- package/knowledge/decisions/internals/cli-parse-errors-are-routed-by-message-prefix.md +0 -28
- package/knowledge/decisions/internals/cli-stdout-is-reserved-for-machine-readable-output.md +0 -34
- package/knowledge/decisions/internals/cli-unknown-long-options-warn-instead-of-failing.md +0 -29
- package/knowledge/decisions/internals/core-column-form-is-an-axis-of-its-own.md +0 -84
- package/knowledge/decisions/internals/core-data-classification-brand-is-an-optional-property.md +0 -41
- package/knowledge/decisions/internals/core-function-runner-restores-the-wire-fields-it-overwrites.md +0 -44
- package/knowledge/decisions/internals/core-hot-reload-merges-generated-meta-never-replaces-it.md +0 -39
- package/knowledge/decisions/internals/core-hot-reload-owns-its-module-registry.md +0 -42
- package/knowledge/decisions/internals/core-middleware-order-is-scope-then-priority.md +0 -39
- package/knowledge/decisions/internals/core-schema-defaults-apply-on-every-transport.md +0 -43
- package/knowledge/decisions/internals/core-scopes-are-an-and-gate-separate-from-permissions.md +0 -38
- package/knowledge/decisions/internals/core-state-is-a-global-map-written-only-at-registration-time.md +0 -44
- package/knowledge/decisions/internals/email-meta-is-read-uncached-because-codegen-rewrites-it-mid-session.md +0 -27
- package/knowledge/decisions/internals/feature-flag-declarations-refuse-an-empty-anyof-and-conflicting-scopes.md +0 -22
- package/knowledge/decisions/internals/feature-flags-fail-open-and-never-enforce-access.md +0 -28
- package/knowledge/decisions/internals/flag-sync-rewrites-only-the-declared-text.md +0 -24
- package/knowledge/decisions/internals/gateway-adapters-resolve-lazily-and-are-promise-cached.md +0 -32
- package/knowledge/decisions/internals/gateway-listener-middleware-runs-without-an-rpc-on-the-wire.md +0 -43
- package/knowledge/decisions/internals/gateway-webhook-challenges-echo-bytes-not-json.md +0 -28
- package/knowledge/decisions/internals/gateway-wiring-is-a-meta-wiring-over-http-and-channels.md +0 -31
- package/knowledge/decisions/internals/generated-src-paths-in-pikku-meta-are-absolute.md +0 -26
- package/knowledge/decisions/internals/global-middleware-resolves-from-the-root-namespace-too.md +0 -32
- package/knowledge/decisions/internals/hot-reload-reads-the-changed-source-never-a-compiled-copy.md +0 -38
- package/knowledge/decisions/internals/hot-reload-writes-into-the-function-map-captured-at-startup.md +0 -26
- package/knowledge/decisions/internals/http-request-bodies-are-read-once-and-shared.md +0 -32
- package/knowledge/decisions/internals/http-route-groups-cascade-config-in-a-fixed-order.md +0 -28
- package/knowledge/decisions/internals/http-router-matches-normalized-paths-but-returns-registered-ones.md +0 -30
- package/knowledge/decisions/internals/http-runner-logs-through-a-trace-scoped-logger-functions-do-not.md +0 -26
- package/knowledge/decisions/internals/http-set-cookie-headers-are-appended-never-joined.md +0 -28
- package/knowledge/decisions/internals/http-sse-streams-flush-headers-only-after-middleware.md +0 -32
- package/knowledge/decisions/internals/http-wiring-without-metadata-is-skipped-not-fatal.md +0 -26
- package/knowledge/decisions/internals/in-a-scenario-a-4xx-is-data-not-an-exception.md +0 -25
- package/knowledge/decisions/internals/in-memory-workflow-history-aliases-the-live-step-object.md +0 -26
- package/knowledge/decisions/internals/index.md +0 -181
- package/knowledge/decisions/internals/istanbul-statement-counts-attach-to-the-start-line-only.md +0 -25
- package/knowledge/decisions/internals/local-trigger-and-gateway-services-assume-a-single-process.md +0 -26
- package/knowledge/decisions/internals/mcp-wire-names-are-assigned-over-the-whole-registry.md +0 -39
- package/knowledge/decisions/internals/node-only-builtins-are-imported-dynamically.md +0 -24
- package/knowledge/decisions/internals/one-project-shape-check-two-validators.md +0 -53
- package/knowledge/decisions/internals/only-exposed-functions-enter-a-virtual-user-catalogue.md +0 -21
- package/knowledge/decisions/internals/queue-group-concurrency-keeps-one-shared-queue-fair.md +0 -28
- package/knowledge/decisions/internals/queue-jobs-always-carry-an-explicit-attempts-count.md +0 -27
- package/knowledge/decisions/internals/remote-addons-dispatch-over-http-instead-of-local-meta.md +0 -31
- package/knowledge/decisions/internals/role-names-cannot-contain-the-scope-separator.md +0 -30
- package/knowledge/decisions/internals/rpc-names-resolve-through-package-scope-before-root.md +0 -32
- package/knowledge/decisions/internals/scenario-agent-calls-sign-in-on-401-only.md +0 -31
- package/knowledge/decisions/internals/scenario-given-and-when-are-sugar-but-then-is-not.md +0 -24
- package/knowledge/decisions/internals/scenario-meta-lives-apart-from-app-meta-but-merges-when-read-off-disk.md +0 -26
- package/knowledge/decisions/internals/scenario-steps-return-drained-response-records.md +0 -27
- package/knowledge/decisions/internals/scenarios-live-in-files-named-for-them.md +0 -48
- package/knowledge/decisions/internals/scope-roots-may-be-co-declared-by-an-addon-and-its-host-app.md +0 -30
- package/knowledge/decisions/internals/serverless-channel-disconnect-must-tolerate-a-missing-channel.md +0 -28
- package/knowledge/decisions/internals/side-effects-are-an-allowlist-not-a-boolean.md +0 -34
- package/knowledge/decisions/internals/speech-synthesis-picks-a-voice-per-sentence-and-warns-once.md +0 -24
- package/knowledge/decisions/internals/the-agent-done-event-goes-through-the-middleware-and-is-awaited.md +0 -26
- package/knowledge/decisions/internals/the-api-report-pins-members-not-just-names.md +0 -43
- package/knowledge/decisions/internals/the-core-scope-validator-refuses-separator-wildcard-and-empty-segments.md +0 -22
- package/knowledge/decisions/internals/the-dev-queue-copies-prod-timing-and-serialization-semantics.md +0 -30
- package/knowledge/decisions/internals/the-ecosystem-entry-point-carries-the-adapter-surface.md +0 -83
- package/knowledge/decisions/internals/the-embedding-model-is-pinned-per-service-and-doc-query-embedding-is-split.md +0 -29
- package/knowledge/decisions/internals/the-in-memory-workflow-service-is-inline-only-and-single-process.md +0 -27
- package/knowledge/decisions/internals/the-kek-salt-is-scoped-to-the-key-version.md +0 -40
- package/knowledge/decisions/internals/the-mcp-handshake-is-challenged-only-when-every-target-is-gated.md +0 -29
- package/knowledge/decisions/internals/the-middleware-resolution-cache-is-deliberately-unbounded.md +0 -40
- package/knowledge/decisions/internals/the-per-invocation-rpc-view-is-a-class.md +0 -40
- package/knowledge/decisions/internals/the-pikku-user-id-resolves-in-a-fixed-order.md +0 -24
- package/knowledge/decisions/internals/the-runner-resolves-wire-services-itself.md +0 -31
- package/knowledge/decisions/internals/the-schema-service-is-never-stubbed.md +0 -26
- package/knowledge/decisions/internals/the-transcript-event-is-sent-ahead-of-the-run.md +0 -25
- package/knowledge/decisions/internals/the-virtual-user-catalogue-is-the-only-gate-on-what-may-be-called.md +0 -21
- package/knowledge/decisions/internals/the-virtual-user-prompt-says-json-because-of-json-object-mode.md +0 -22
- package/knowledge/decisions/internals/the-virtual-user-runtime-is-exported-from-the-virtual-user-entry-point.md +0 -28
- package/knowledge/decisions/internals/the-worker-disposition-is-the-one-that-is-not-testing.md +0 -22
- package/knowledge/decisions/internals/thread-history-records-the-transcript-not-the-audio.md +0 -25
- package/knowledge/decisions/internals/trigger-declaration-is-split-from-trigger-source.md +0 -33
- package/knowledge/decisions/internals/typed-secret-service-caches-for-the-process-lifetime.md +0 -26
- package/knowledge/decisions/internals/validate-checks-virtual-users-through-a-shared-module.md +0 -43
- package/knowledge/decisions/internals/validate-runs-checks-by-precondition.md +0 -115
- package/knowledge/decisions/internals/virtual-user-conversation-drives-the-target-through-a-transport-seam.md +0 -24
- package/knowledge/decisions/internals/virtual-user-conversation-verdicts-are-llm-self-evaluations.md +0 -25
- package/knowledge/decisions/internals/virtual-user-conversations-seed-a-hidden-kickoff-message.md +0 -23
- package/knowledge/decisions/internals/virtual-user-step-order-comes-from-insertion-order.md +0 -21
- package/knowledge/decisions/internals/virtual-users-are-declared-in-one-definevirtualusers-call-per-codebase.md +0 -30
- package/knowledge/decisions/internals/voice-output-speaks-unless-voice-input-explicitly-says-otherwise.md +0 -24
- package/knowledge/decisions/internals/webhook-delivery-history-records-every-attempt-best-effort.md +0 -26
- package/knowledge/decisions/internals/webhook-service-collaborators-are-constructor-args-not-locator-lookups.md +0 -25
- package/knowledge/decisions/internals/whether-a-run-is-inline-is-read-from-the-run-record.md +0 -58
- package/knowledge/decisions/internals/wiring-registries-erase-the-generics-their-wire-functions-capture.md +0 -35
- package/knowledge/decisions/internals/workflow-approval-expiry-is-decided-from-a-recorded-deadline.md +0 -34
- package/knowledge/decisions/internals/workflow-core-never-imports-a-browser-driver.md +0 -42
- package/knowledge/decisions/internals/workflow-dsl-meta-separates-runtime-expressions-from-literals.md +0 -38
- package/knowledge/decisions/internals/workflow-features-resolve-scenarios-by-object-identity.md +0 -29
- package/knowledge/decisions/internals/workflow-graph-inline-and-queued-runs-share-one-planner.md +0 -42
- package/knowledge/decisions/internals/workflow-graph-node-notes-are-excluded-from-the-graph-hash.md +0 -25
- package/knowledge/decisions/internals/workflow-inline-runs-report-their-run-id-before-they-can-fail.md +0 -29
- package/knowledge/decisions/internals/workflow-invocation-id-is-the-dedupe-key-not-step-id.md +0 -43
- package/knowledge/decisions/internals/workflow-queued-step-dispatch-requires-an-explicit-opt-in.md +0 -29
- package/knowledge/decisions/internals/workflow-queues-are-per-workflow-by-default.md +0 -42
- package/knowledge/decisions/internals/workflow-repeated-step-names-get-an-ordinal-suffix.md +0 -33
- package/knowledge/decisions/internals/workflow-replay-reads-its-steps-once-and-caches-only-the-immutable-half.md +0 -32
- package/knowledge/decisions/internals/workflow-retries-are-owned-by-the-workflow-not-the-queue.md +0 -31
- package/knowledge/decisions/internals/workflow-run-capabilities-are-extensions-not-subclasses.md +0 -39
- package/knowledge/decisions/internals/workflow-run-mirror-is-never-a-source-of-truth.md +0 -29
- package/knowledge/decisions/internals/workflow-run-polling-backs-off-to-the-callers-ceiling.md +0 -33
- package/knowledge/decisions/internals/workflow-run-timeline-is-a-pure-fold-over-durable-history.md +0 -37
- package/knowledge/decisions/internals/workflow-scenario-assertions-never-retry-and-record-one-step.md +0 -54
- package/knowledge/decisions/internals/workflow-scenario-hooks-are-a-scenario-only-affordance.md +0 -43
- package/knowledge/decisions/internals/workflow-scenario-prose-is-rendered-from-typed-calls-not-parsed-from-english.md +0 -32
- package/knowledge/decisions/internals/workflow-scenario-quarantine-reason-lives-in-code.md +0 -18
- package/knowledge/decisions/internals/workflow-scenario-step-targets-are-string-literals-for-the-inspector.md +0 -34
- package/knowledge/decisions/internals/workflow-step-compensation-runs-as-its-own-durable-step.md +0 -29
- package/knowledge/decisions/internals/workflow-step-dispatch-failure-is-transient-not-a-run-failure.md +0 -33
- package/knowledge/decisions/internals/workflow-step-lock-is-held-only-to-claim-the-step.md +0 -34
- package/knowledge/decisions/internals/workflow-step-rpc-name-is-provenance-only.md +0 -34
- package/knowledge/decisions/internals/workflow-suspend-and-approval-reasons-are-durable-step-identities.md +0 -38
- package/knowledge/decisions/internals/workflow-suspended-runs-keep-their-in-process-context.md +0 -30
- package/knowledge/decisions/security/a-bearer-token-checked-against-a-secret-reads-it-per-request.md +0 -26
- package/knowledge/decisions/security/a-call-without-a-session-raises-missing-session-not-forbidden.md +0 -20
- package/knowledge/decisions/security/a-caller-cookie-wins-over-the-jar-for-the-same-name.md +0 -23
- package/knowledge/decisions/security/a-channel-lifecycle-acts-as-the-socket-upgrade-session.md +0 -16
- package/knowledge/decisions/security/a-channel-requires-a-session-unless-it-says-auth-false.md +0 -26
- package/knowledge/decisions/security/a-credential-read-path-follows-its-declared-type-not-absence.md +0 -32
- package/knowledge/decisions/security/a-credential-type-is-a-literal-the-inspector-checks-at-declaration.md +0 -27
- package/knowledge/decisions/security/a-dropped-audit-write-is-always-logged.md +0 -28
- package/knowledge/decisions/security/a-first-party-cookie-is-written-only-after-its-purposes-consent.md +0 -33
- package/knowledge/decisions/security/a-function-never-receives-the-secret-service.md +0 -37
- package/knowledge/decisions/security/a-graph-run-starts-at-an-entry-node-the-graph-declared.md +0 -33
- package/knowledge/decisions/security/a-permission-gets-a-wire-it-cannot-reply-on.md +0 -33
- package/knowledge/decisions/security/a-public-function-says-so-with-auth-false.md +0 -34
- package/knowledge/decisions/security/a-readonly-session-reaches-only-readonly-functions.md +0 -25
- package/knowledge/decisions/security/a-scaffold-flag-says-a-surface-exists-not-who-may-call-it.md +0 -52
- package/knowledge/decisions/security/a-scheduled-virtual-user-run-needs-no-admin-at-run-time.md +0 -27
- package/knowledge/decisions/security/a-scoped-credential-view-is-limited-to-declared-names.md +0 -26
- package/knowledge/decisions/security/a-scoped-secret-view-reads-only-declared-keys-and-never-writes.md +0 -25
- package/knowledge/decisions/security/a-secret-is-sent-only-to-the-hosts-it-declares.md +0 -29
- package/knowledge/decisions/security/a-step-can-name-an-identity-no-virtual-user-holds-through-per-call-headers.md +0 -25
- package/knowledge/decisions/security/a-step-runs-the-function-the-workflow-dispatched-it-with.md +0 -37
- package/knowledge/decisions/security/a-stopped-run-by-id-skips-the-ownership-check.md +0 -24
- package/knowledge/decisions/security/a-vault-secret-redacts-on-serialization-and-throws-on-coercion.md +0 -29
- package/knowledge/decisions/security/a-virtual-user-catalogue-entry-is-filtered-by-scope-and-approval-is-denied-by-default.md +0 -30
- package/knowledge/decisions/security/a-virtual-user-environment-fails-closed.md +0 -38
- package/knowledge/decisions/security/a-virtual-user-is-never-offered-a-step-that-would-forge-its-own-oracle.md +0 -27
- package/knowledge/decisions/security/a-virtual-user-never-runs-against-production.md +0 -23
- package/knowledge/decisions/security/a-virtual-user-reads-its-roles-from-the-apps-own-rpc-before-better-auth.md +0 -27
- package/knowledge/decisions/security/a-virtual-user-run-treats-an-unresolved-environment-as-production.md +0 -41
- package/knowledge/decisions/security/a-virtual-user-scopes-are-expanded-from-its-roles-once-at-run-preparation.md +0 -25
- package/knowledge/decisions/security/a-virtual-user-whose-roles-drift-from-the-declaration-refuses-to-run.md +0 -32
- package/knowledge/decisions/security/a-workflow-run-is-read-and-approved-by-its-owner.md +0 -50
- package/knowledge/decisions/security/addon-auth-and-tags-only-tighten.md +0 -43
- package/knowledge/decisions/security/addon-config-gates-apply-only-at-the-namespaced-rpc-boundary.md +0 -52
- package/knowledge/decisions/security/addon-scopes-are-resolved-where-the-function-runs.md +0 -46
- package/knowledge/decisions/security/addon-screen-scopes-hide-and-do-not-enforce.md +0 -20
- package/knowledge/decisions/security/agent-approval-forwarding-requires-a-symbol-brand.md +0 -27
- package/knowledge/decisions/security/agent-credential-requests-are-symbol-branded.md +0 -37
- package/knowledge/decisions/security/agent-gate-requires-a-session-only-when-auth-is-true.md +0 -31
- package/knowledge/decisions/security/agent-ownership-failures-never-echo-the-resource.md +0 -23
- package/knowledge/decisions/security/agent-resume-re-runs-the-authorization-gate.md +0 -22
- package/knowledge/decisions/security/agent-sessionless-deployments-have-no-thread-ownership.md +0 -39
- package/knowledge/decisions/security/agent-thread-ownership-composes-the-session-principal.md +0 -30
- package/knowledge/decisions/security/agent-tool-filtering-reads-the-live-function-config.md +0 -24
- package/knowledge/decisions/security/an-addon-header-can-only-narrow-the-session.md +0 -26
- package/knowledge/decisions/security/an-addon-instance-reads-only-the-secrets-and-credentials-it-is-named.md +0 -33
- package/knowledge/decisions/security/an-addon-may-reach-only-itself-and-the-addons-it-uses.md +0 -16
- package/knowledge/decisions/security/an-agent-approval-is-claimed-before-the-tool-runs.md +0 -33
- package/knowledge/decisions/security/an-api-key-is-jwt-decoded-into-the-session.md +0 -26
- package/knowledge/decisions/security/an-approval-answer-outlives-the-run-it-answered.md +0 -59
- package/knowledge/decisions/security/an-empty-owners-constraint-matches-nothing.md +0 -30
- package/knowledge/decisions/security/an-exposed-ungated-function-is-a-codegen-warning.md +0 -52
- package/knowledge/decisions/security/an-external-virtual-user-caller-presents-one-signed-statement.md +0 -38
- package/knowledge/decisions/security/an-inbound-webhook-source-dispatches-only-verified-requests.md +0 -31
- package/knowledge/decisions/security/an-mcp-call-with-no-http-request-stays-anonymous.md +0 -18
- package/knowledge/decisions/security/an-mcp-refusal-is-decided-before-dispatch.md +0 -48
- package/knowledge/decisions/security/an-oauth2-credential-is-read-by-its-account-row.md +0 -40
- package/knowledge/decisions/security/an-omitted-user-id-addresses-the-platform-credential.md +0 -32
- package/knowledge/decisions/security/an-upload-is-counted-as-it-arrives-not-buffered-then-measured.md +0 -24
- package/knowledge/decisions/security/analytics-identity-is-stamped-from-the-session-not-the-event.md +0 -24
- package/knowledge/decisions/security/app-access-is-a-scope-tree-synthesised-from-virtual-users.md +0 -26
- package/knowledge/decisions/security/approval-policy-decides-who-answers-a-tool-call.md +0 -27
- package/knowledge/decisions/security/auth-false-on-a-session-function-warns-and-still-requires-one.md +0 -25
- package/knowledge/decisions/security/bearer-token-hashes-are-unpeppered-sha256.md +0 -18
- package/knowledge/decisions/security/consent-is-read-from-a-cookie-and-a-recognised-denial-counts-as-refusal.md +0 -29
- package/knowledge/decisions/security/console-addon-privileged-functions-gate-themselves.md +0 -84
- package/knowledge/decisions/security/core-safe-fetch-blocks-ssrf-by-host-literal-not-dns.md +0 -39
- package/knowledge/decisions/security/core-secrets-use-a-per-secret-dek-wrapped-by-a-kek.md +0 -37
- package/knowledge/decisions/security/cors-defaults-to-any-origin-and-refuses-the-wildcard-with-credentials.md +0 -22
- package/knowledge/decisions/security/credential-backends-share-one-conformance-suite-for-per-user-isolation.md +0 -29
- package/knowledge/decisions/security/each-stage-has-one-virtual-user-key-pair.md +0 -27
- package/knowledge/decisions/security/gateway-handlers-run-through-the-function-runner-gate.md +0 -41
- package/knowledge/decisions/security/gateway-middleware-sessions-must-be-bridged-onto-the-wire.md +0 -30
- package/knowledge/decisions/security/global-permissions-and-function-permissions-are-independent-gates.md +0 -40
- package/knowledge/decisions/security/hmac-verification-fails-closed-on-empty-inputs.md +0 -25
- package/knowledge/decisions/security/http-error-detail-is-withheld-from-clients-in-production.md +0 -33
- package/knowledge/decisions/security/http-request-bodies-are-bounded-before-they-are-buffered.md +0 -46
- package/knowledge/decisions/security/index.md +0 -135
- package/knowledge/decisions/security/local-content-refuses-private-buckets-under-the-public-segment.md +0 -21
- package/knowledge/decisions/security/mail-is-allowlisted-before-a-virtual-user-run-sees-it.md +0 -38
- package/knowledge/decisions/security/mcp-internal-error-details-are-double-gated-on-production.md +0 -27
- package/knowledge/decisions/security/mcp-resources-tools-and-prompts-take-sessionless-functions.md +0 -18
- package/knowledge/decisions/security/origin-locked-routes-match-the-origin-exactly.md +0 -22
- package/knowledge/decisions/security/oss-auth-works-without-pikku-studio-cloud.md +0 -26
- package/knowledge/decisions/security/outbound-webhooks-use-an-allowlist-when-configured.md +0 -24
- package/knowledge/decisions/security/passphrases-are-stretched-key-material-is-expanded.md +0 -40
- package/knowledge/decisions/security/permission-auth-filtering-requires-live-permission-functions.md +0 -31
- package/knowledge/decisions/security/pikku-carries-virtual-user-scopes-as-data-and-the-app-grants-them.md +0 -35
- package/knowledge/decisions/security/queue-job-identities-are-signed-at-enqueue.md +0 -69
- package/knowledge/decisions/security/queue-jobs-carry-the-producers-pikku-user-id.md +0 -39
- package/knowledge/decisions/security/remote-addon-tokens-are-client-credentials-not-mesh-trust.md +0 -34
- package/knowledge/decisions/security/scaffold-features-are-authenticated-unless-opted-out.md +0 -55
- package/knowledge/decisions/security/scenario-step-functions-are-never-externally-invocable.md +0 -30
- package/knowledge/decisions/security/scope-resolution-happens-at-the-session-boundary-and-sync-never-deletes.md +0 -28
- package/knowledge/decisions/security/scoped-content-access-is-a-root-folder-with-longest-prefix-grants.md +0 -31
- package/knowledge/decisions/security/self-authentication-is-declared-not-detected.md +0 -34
- package/knowledge/decisions/security/services-without-secrets-get-a-throwing-secrets-accessor.md +0 -22
- package/knowledge/decisions/security/shared-guards-refuse-to-mutate-or-shadow-a-system-role.md +0 -34
- package/knowledge/decisions/security/signed-content-urls-bind-the-request-path.md +0 -37
- package/knowledge/decisions/security/signed-uploads-are-verified-by-the-same-check-as-signed-reads.md +0 -26
- package/knowledge/decisions/security/system-role-scopes-must-be-declared-with-define-scope.md +0 -24
- package/knowledge/decisions/security/system-roles-are-additive-and-immutable.md +0 -16
- package/knowledge/decisions/security/the-channel-rpc-does-not-send-the-callers-session.md +0 -21
- package/knowledge/decisions/security/the-remote-jobs-inbox-fails-closed-without-a-secret.md +0 -24
- package/knowledge/decisions/security/the-remote-rpc-gate-fails-closed-and-binds-the-token-to-its-function.md +0 -34
- package/knowledge/decisions/security/the-workflow-status-stream-rechecks-ownership-on-every-poll.md +0 -16
- package/knowledge/decisions/security/two-credentials-on-one-key-must-share-a-read-mode.md +0 -29
- package/knowledge/decisions/security/verified-bearer-claims-are-pass-through-data-that-core-never-fills.md +0 -23
- package/knowledge/decisions/security/virtual-user-catalogue-excludes-the-machinery-that-runs-virtual-users.md +0 -25
- package/knowledge/decisions/security/virtual-user-conversation-missing-approval-decisions-default-to-denied.md +0 -22
- package/knowledge/decisions/security/virtual-user-run-records-are-gated-behind-a-read-scope.md +0 -18
- package/knowledge/decisions/security/virtual-user-sign-in-does-not-exist-in-production.md +0 -25
- package/knowledge/decisions/security/virtual-user-sign-in-has-one-door.md +0 -42
- package/knowledge/decisions/security/virtual-user-sign-in-is-proven-by-set-cookie-not-a-non-empty-jar.md +0 -29
- package/knowledge/decisions/security/virtual-user-sign-in-only-works-for-virtual-user-flagged-users.md +0 -29
- package/knowledge/decisions/security/webhook-bodies-are-signed-before-they-are-enqueued.md +0 -25
- package/knowledge/decisions/security/wire-addon-expose-selects-the-rpc-surface.md +0 -51
- package/knowledge/decisions/security/workflow-approval-payloads-are-validated-on-replay-inside-the-workflow.md +0 -40
- package/knowledge/decisions/security/workflow-helper-functions-are-sessionless-by-declaration.md +0 -18
- package/knowledge/decisions/security/workflow-queued-steps-rehydrate-their-session-from-the-run-wire.md +0 -32
- package/knowledge/decisions/security/workflow-scenario-sessions-are-isolated-per-virtual-user-and-per-scenario.md +0 -32
- package/knowledge/decisions/security/workflow-scenario-steps-are-never-network-invocable.md +0 -31
- package/knowledge/decisions/security/workflow-virtual-user-steps-always-use-the-real-transport.md +0 -34
- package/knowledge/decisions/security/writing-a-virtual-user-schedule-is-gated-by-its-own-scope.md +0 -18
- package/knowledge/index.md +0 -24
- package/knowledge/questions/a-bearer-jwt-with-no-identity-becomes-a-session.md +0 -24
- package/knowledge/questions/channel-middleware-accepts-bare-factories-that-nothing-resolves.md +0 -35
- package/knowledge/questions/dev-quick-login-as-impersonation.md +0 -25
- package/knowledge/questions/does-a-delayed-rpc-run-as-the-session-it-was-scheduled-with.md +0 -26
- package/knowledge/questions/does-a-user-id-with-a-colon-read-another-users-credentials.md +0 -27
- package/knowledge/questions/does-a-wirecli-command-need-a-session-by-default.md +0 -26
- package/knowledge/questions/does-an-adversarial-in-scope-success-count-as-a-finding.md +0 -26
- package/knowledge/questions/does-approve-step-need-the-run-owners-session-or-the-gates-approvers.md +0 -34
- package/knowledge/questions/does-cors-origin-true-reflect-any-origin-with-credentials.md +0 -20
- package/knowledge/questions/does-skip-user-session-do-anything-on-a-channel.md +0 -24
- package/knowledge/questions/does-the-store-session-match-the-other-two.md +0 -19
- package/knowledge/questions/index.md +0 -41
- package/knowledge/questions/is-the-agent-score-worker-reachable-without-a-session.md +0 -21
- package/knowledge/questions/live-scheduled-tests-may-write.md +0 -19
- package/knowledge/questions/provision-virtual-users-has-no-caller-in-this-repo.md +0 -23
- package/knowledge/questions/remote-secret-refuses-requests-without-a-remote-token-on-every-path.md +0 -32
- package/knowledge/questions/should-a-middleware-set-session-persist-to-the-store.md +0 -25
- package/knowledge/questions/should-a-scoped-secret-view-throw-from-has-secret-for-a-disallowed-key.md +0 -23
- package/knowledge/questions/should-a-wrong-bearer-token-be-anonymous-or-refused.md +0 -35
- package/knowledge/questions/should-an-empty-webhook-signing-secret-send-unsigned.md +0 -23
- package/knowledge/questions/should-http-virtual-user-sessions-reset-between-scenarios-in-one-run.md +0 -27
- package/knowledge/questions/should-the-cookie-jar-scope-cookies-to-the-api-origin.md +0 -26
- package/knowledge/questions/should-voice-input-fetch-audio-urls-without-a-host-allowlist.md +0 -20
- package/knowledge/questions/staging-impersonation-rules.md +0 -27
- package/knowledge/questions/unauthorized-channel-replies-escape-the-declared-out-type.md +0 -44
- package/knowledge/questions/virtual-user-keys-on-cloud-stages-are-pikku-studios-to-build.md +0 -34
- package/knowledge/questions/virtual-user-statement-replay-is-per-process.md +0 -20
- package/knowledge/questions/what-an-impersonated-session-carries.md +0 -22
- package/run-tests.sh +0 -68
- package/scripts/generate-api-report.d.mts +0 -1
- package/scripts/generate-api-report.mjs +0 -96
- package/scripts/generate-api-report.mts +0 -333
- package/src/public-surface.json +0 -637
- package/src/public-surface.json.README +0 -43
- /package/dist/{function/compensation-name.d.ts → compensation-name.d.ts} +0 -0
- /package/dist/{function/compensation-name.js → compensation-name.js} +0 -0
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: decision
|
|
3
|
-
title: A column's at-rest form is an axis of its own
|
|
4
|
-
description: How a value is stored is independent of how sensitive it is, so form carries a required nominal brand on writes while classification stays optional on reads
|
|
5
|
-
tags: core
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# A column's at-rest form is an axis of its own
|
|
9
|
-
|
|
10
|
-
`ColumnForm` in `packages/core/src/data-classification.ts` is a second,
|
|
11
|
-
independent annotation on a column: `plain | hashed | wrapped | sealed`. It
|
|
12
|
-
answers "how are these bytes held?", where `Classification` answers "may this
|
|
13
|
-
value leave the process?".
|
|
14
|
-
|
|
15
|
-
The two axes were one field before this, with `security: 'encrypted'` sitting
|
|
16
|
-
alongside `secret` as though they were alternatives. They are not, and the
|
|
17
|
-
conflation made the field unanswerable: a token hash and a live bearer token are
|
|
18
|
-
both `secret`, one must never be encrypted — the digest _is_ the lookup key —
|
|
19
|
-
and the other must always be. Nothing in a single enum could tell them apart, so
|
|
20
|
-
nothing could check either.
|
|
21
|
-
|
|
22
|
-
## Why `wrapped` and `sealed` rather than `encrypted`
|
|
23
|
-
|
|
24
|
-
Sealed values _are_ encrypted, so an `encrypted` member sitting beside `sealed`
|
|
25
|
-
would be a supertype posing as a sibling, and every new column would be an
|
|
26
|
-
even-odds guess. What actually separates them is who can read the value back:
|
|
27
|
-
`wrapped` is symmetric and the application holds the key; `sealed` is asymmetric
|
|
28
|
-
and the application holds only the public half. Writing one where the other
|
|
29
|
-
belongs produces a row nobody can ever open, which is why the type system is
|
|
30
|
-
made to know the difference.
|
|
31
|
-
|
|
32
|
-
## Why these brands are required when `Secret<T>` is optional
|
|
33
|
-
|
|
34
|
-
`WrappedValue`, `SealedValue` and `HashedValue` are `string & { readonly [sym]:
|
|
35
|
-
true }` with a `unique symbol` — nominal, and **required**, which
|
|
36
|
-
[the classification-brand decision](core-data-classification-brand-is-an-optional-property.md)
|
|
37
|
-
explicitly rules out for `Private`/`Pii`/`Secret`. That decision still stands and
|
|
38
|
-
this does not weaken it. It applies to a different side of a different set of
|
|
39
|
-
columns:
|
|
40
|
-
|
|
41
|
-
- `Secret<T>` brands **every** classified column's SELECT type. A required brand
|
|
42
|
-
there would break `where('email', '=', someString)` in every downstream
|
|
43
|
-
project.
|
|
44
|
-
- A form brands **only** the INSERT/UPDATE type, and only on the columns that
|
|
45
|
-
opt in by declaring a form. There is nothing to break, because a column
|
|
46
|
-
without a form generates exactly what it generated before.
|
|
47
|
-
|
|
48
|
-
The brands compose rather than compete: a wrapped secret column selects as
|
|
49
|
-
`Secret<WrappedValue>`, so the inspector's PKU910 check still finds
|
|
50
|
-
`__classification__`, while a row read back is already a `WrappedValue` and
|
|
51
|
-
flows into a rewrap or re-seal without a cast.
|
|
52
|
-
|
|
53
|
-
Each brand widens to `string`, so query operands, serialization and template
|
|
54
|
-
literals are unaffected. The constraint is on **construction**: the only way to
|
|
55
|
-
produce one is `envelopeEncrypt`/`envelopeRewrap`/`wrapDEK` (wrapped) or
|
|
56
|
-
`hashToken` (hashed), or the deliberately-named `unsafeAs*` assertions in
|
|
57
|
-
`column-form.ts` for the three cases a bare string legitimately arrives —
|
|
58
|
-
backfill migrations, test fixtures, and values sealed by another service.
|
|
59
|
-
|
|
60
|
-
## What is deliberately NOT enforced
|
|
61
|
-
|
|
62
|
-
`envelopeDecrypt` and `unwrapDEK` take plain `string`, not the brand. Requiring
|
|
63
|
-
it would buy nothing — feeding in the wrong string already fails at the AEAD tag
|
|
64
|
-
— while forcing a cast into every path that reads ciphertext out of a row or off
|
|
65
|
-
the wire, which is where casts are least reviewable.
|
|
66
|
-
|
|
67
|
-
The brand proves _provenance_, not correctness. It cannot know a value was
|
|
68
|
-
wrapped under the right key, and making it know would mean phantom-typing key
|
|
69
|
-
ids per scope, which the multi-recipient path would fight constantly.
|
|
70
|
-
|
|
71
|
-
## The plain-secret diagnostic
|
|
72
|
-
|
|
73
|
-
A `secret` column with no declared form raises **PKU483** as a warning, not an
|
|
74
|
-
error. Every project predating the axis has such columns, and failing their next
|
|
75
|
-
`db migrate` would be a breaking change for a diagnosis they have not had a
|
|
76
|
-
chance to act on. `pikku db --fail-on-warn` is how a project opts into the
|
|
77
|
-
ratchet. An explicit `form: 'plain'` silences it — that is the acknowledgement
|
|
78
|
-
that reading the row is _meant_ to yield a usable credential.
|
|
79
|
-
|
|
80
|
-
**What this rules out:** collapsing `wrapped` and `sealed` back into one
|
|
81
|
-
`encrypted`; making the form brands optional (they would enforce nothing);
|
|
82
|
-
re-declaring them in generated schema files, since a local `unique symbol` is a
|
|
83
|
-
distinct nominal type and core's own ciphertext would not be assignable to the
|
|
84
|
-
column it belongs in — `db-codegen` imports them from `@pikku/core` instead.
|
package/knowledge/decisions/internals/core-data-classification-brand-is-an-optional-property.md
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: decision
|
|
3
|
-
title: The data-classification brand is an optional property
|
|
4
|
-
description: Making __classification__ required would break ordinary Kysely operands, so the brand only constrains values flowing out
|
|
5
|
-
tags: core
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# The data-classification brand is an optional property
|
|
9
|
-
|
|
10
|
-
`Private<T>`, `Pii<T>` and `Secret<T>` in
|
|
11
|
-
`packages/core/src/data-classification.ts` brand a type with
|
|
12
|
-
`{ readonly __classification__?: 'private' | 'pii' | 'secret' }` — and the
|
|
13
|
-
marker is **optional on purpose**.
|
|
14
|
-
|
|
15
|
-
A required property would make a plain value unassignable to a branded column: a
|
|
16
|
-
`string` could no longer be passed where `Private<string>` is expected, which
|
|
17
|
-
breaks every ordinary Kysely query operand — `where('email', '=', someString)`,
|
|
18
|
-
inserts, and `.set(...)`. Making it optional keeps the brand structurally present
|
|
19
|
-
so static analysis still sees it, while letting plain values flow _in_. The
|
|
20
|
-
asymmetry is the point: the brand constrains what comes out of a query, not what
|
|
21
|
-
goes into one.
|
|
22
|
-
|
|
23
|
-
The consumer is `@pikku/inspector`, whose `findPiiPaths` reads the level union
|
|
24
|
-
directly and whose PKU910 output check detects the brand on a function's return
|
|
25
|
-
type. The brands are populated from the hand-authored `db/annotations.ts`
|
|
26
|
-
(`DbClassificationMap`) via `pikku db migrate`, which regenerates
|
|
27
|
-
`outDir/db/schema.d.ts` and `outDir/db/classification.gen.ts`.
|
|
28
|
-
|
|
29
|
-
A column's **at-rest form** is a separate axis making the opposite trade — see
|
|
30
|
-
[form is an axis of its own](core-column-form-is-an-axis-of-its-own.md). Its
|
|
31
|
-
brands are nominal and required, which is safe precisely because they land on
|
|
32
|
-
the INSERT/UPDATE side of the columns that opt in, rather than on the SELECT
|
|
33
|
-
side of every classified column. That is not an exception to the rule below; it
|
|
34
|
-
is a different rule about a different side.
|
|
35
|
-
|
|
36
|
-
**What this rules out:** making `__classification__` required to get stronger
|
|
37
|
-
guarantees, or replacing the optional property with a unique symbol / nominal
|
|
38
|
-
brand that behaves like a required one. Either change compiles here and then
|
|
39
|
-
breaks every generated Kysely call site in every downstream project. It also
|
|
40
|
-
rules out renaming the property or narrowing its literal union without updating
|
|
41
|
-
`findPiiPaths` in the inspector, which matches on both.
|
package/knowledge/decisions/internals/core-function-runner-restores-the-wire-fields-it-overwrites.md
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
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.
|
|
@@ -1,42 +0,0 @@
|
|
|
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.
|
|
@@ -1,39 +0,0 @@
|
|
|
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.
|
|
@@ -1,43 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
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.
|
|
@@ -1,44 +0,0 @@
|
|
|
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.
|
|
@@ -1,27 +0,0 @@
|
|
|
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.
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: decision
|
|
3
|
-
title: Feature flag declarations refuse an empty anyOf and conflicting scopes
|
|
4
|
-
description: validateAndBuildFeatureFlagDefinitionsMeta throws on an anyOf that is an empty list, and on a repeated flag name whose scopes differ between declarations
|
|
5
|
-
tags: core, flags, validation
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Feature flag declarations refuse an empty anyOf and conflicting scopes
|
|
9
|
-
|
|
10
|
-
`validateAndBuildFeatureFlagDefinitionsMeta` in
|
|
11
|
-
`packages/core/src/wirings/flag/validate-flag-definitions.ts:70-98` checks each
|
|
12
|
-
declaration in two ways.
|
|
13
|
-
|
|
14
|
-
An `anyOf` that is an empty array throws (`:78-84`). The message says an empty
|
|
15
|
-
list satisfies nobody, and that a pure switch should omit `anyOf`.
|
|
16
|
-
|
|
17
|
-
When a flag name is declared twice, the two `anyOf` lists are compared as sorted
|
|
18
|
-
JSON (`:86-90`). A difference throws (`:91-97`), and the message says flags sharing
|
|
19
|
-
a name must name the same scopes.
|
|
20
|
-
|
|
21
|
-
**What this rules out:** a flag that no session can satisfy, and two declarations
|
|
22
|
-
of one flag that disagree about who may see it.
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: decision
|
|
3
|
-
title: Feature flags fail open on availability and never enforce access
|
|
4
|
-
description: A flag with no config row is available by default, anyOf decides only the advisory capable half, and the runner's assertFeatureAvailable checks availability alone
|
|
5
|
-
tags: core, flags, authorization
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Feature flags fail open on availability and never enforce access
|
|
9
|
-
|
|
10
|
-
`resolveFlag` in `packages/core/src/wirings/flag/resolve-flag.ts:54-95`
|
|
11
|
-
separates two halves. `capable` is true when `anyOf` is absent, and otherwise
|
|
12
|
-
comes from `hasAnyScope` on the session's scopes (`:68-69`). If the flag has no
|
|
13
|
-
config row, the result is `available: true` (`:72-74`). The doc comment at `:54-59`
|
|
14
|
-
says this fail-open is safe only because `capable` comes from the session and
|
|
15
|
-
`scopes:` is not changed by a flag.
|
|
16
|
-
|
|
17
|
-
`FlagState` in `packages/core/src/wirings/flag/flag.types.ts:97-104` says the same
|
|
18
|
-
thing: `available` is the only half the runner enforces, and `capable` is advisory
|
|
19
|
-
and "protects nothing". `flag.types.ts:14-18` says `anyOf` is an OR over scopes,
|
|
20
|
-
deliberately the opposite of `scopes`, which is an AND.
|
|
21
|
-
|
|
22
|
-
`assertFeatureAvailable` in `packages/core/src/wirings/flag/assert-feature-available.ts`
|
|
23
|
-
calls `resolveFlag` and throws only when `available` is false (`:28-30`). It does
|
|
24
|
-
nothing when no feature-flag source is registered (`:24-26`). The doc comment at
|
|
25
|
-
`:10-12` says enforcing `capable` here would make a second authorization path.
|
|
26
|
-
|
|
27
|
-
**What this rules out:** using a flag as an access check, and a store outage
|
|
28
|
-
turning every flagged feature off.
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: decision
|
|
3
|
-
title: Flag declaration sync rewrites only the description and anyOf
|
|
4
|
-
description: The FeatureFlagStore contract re-syncs a flag's description and anyOf on deploy and leaves enabled, rollout and overrides to the operator
|
|
5
|
-
tags: core, flags, services
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Flag declaration sync rewrites only the description and anyOf
|
|
9
|
-
|
|
10
|
-
The `FeatureFlagStore` interface in `packages/core/src/services/feature-flag-service.ts:79-90`
|
|
11
|
-
declares `syncFlags`. Its doc comment says a flag's `description` and `anyOf` are
|
|
12
|
-
re-synced on each deploy, because that is the declaration's whole content. It also
|
|
13
|
-
says `enabled`, the rollout and every override belong to the operator and are never
|
|
14
|
-
touched.
|
|
15
|
-
|
|
16
|
-
Lines `:80-83` say a removed declaration leaves its row marked `declared: false`
|
|
17
|
-
rather than deleting the operator's switch.
|
|
18
|
-
|
|
19
|
-
Core defines only the interface here. The implementing store is not in this
|
|
20
|
-
package, so the rule is the contract's, and was not verified against an
|
|
21
|
-
implementation.
|
|
22
|
-
|
|
23
|
-
**What this rules out:** a deploy overwriting an operator's enabled state, rollout
|
|
24
|
-
or overrides, and deleting a flag row because its declaration was removed.
|
package/knowledge/decisions/internals/gateway-adapters-resolve-lazily-and-are-promise-cached.md
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
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.
|
package/knowledge/decisions/internals/gateway-listener-middleware-runs-without-an-rpc-on-the-wire.md
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: decision
|
|
3
|
-
title: Gateway middleware sees wire.rpc on webhook and websocket, but not on listener
|
|
4
|
-
description: The listener transport invokes its handler directly, so middleware runs outside any runPikkuFunc call and the lazily-attached rpc is absent
|
|
5
|
-
tags: core, gateway
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Gateway middleware sees `wire.rpc` on webhook and websocket, but not on listener
|
|
9
|
-
|
|
10
|
-
`runPikkuFunc` in `packages/core/src/function/function-runner.ts` attaches `rpc`
|
|
11
|
-
to the invocation wire with `Object.defineProperty`, as a lazy getter that
|
|
12
|
-
replaces itself on first read — and restores the previous descriptor in its
|
|
13
|
-
`finally`. `rpc` therefore exists on a wire _only for the duration of a function
|
|
14
|
-
invocation_. That is why `PikkuRawWire` is `Omit<PikkuWire, 'rpc'>`: it is the
|
|
15
|
-
wire as a runner constructs it, before the function runner adds `rpc`.
|
|
16
|
-
|
|
17
|
-
The three gateway transports reach middleware differently:
|
|
18
|
-
|
|
19
|
-
- **webhook** and **websocket** register their handlers with `addFunction`, so
|
|
20
|
-
the handler body already runs inside a `runPikkuFunc` invocation. The `wire`
|
|
21
|
-
it receives is a full `PikkuWire`, and `config.middleware` runs inside that
|
|
22
|
-
same invocation — `wire.rpc` is live.
|
|
23
|
-
- **listener** has no such wrapper. `createListenerMessageHandler` is handed
|
|
24
|
-
straight to `adapter.init()` by the `GatewayService`, builds
|
|
25
|
-
`const wire: PikkuRawWire = {}` itself, and runs `config.middleware` _before_
|
|
26
|
-
`invoke()` reaches `runPikkuFunc`. There is no invocation in progress, so
|
|
27
|
-
`wire.rpc` is `undefined`.
|
|
28
|
-
|
|
29
|
-
A gateway middleware that calls `wire.rpc.invoke(...)` therefore works on two
|
|
30
|
-
transports and throws on the third, with nothing in the types to say so — the
|
|
31
|
-
call into `runMiddleware` needs an assertion, because `runMiddleware` is typed
|
|
32
|
-
off `CorePikkuMiddleware`, whose wire parameter is `PikkuWire`.
|
|
33
|
-
|
|
34
|
-
**What this rules out:** treating the assertion at that call as noise to be
|
|
35
|
-
deleted. It is naming a real gap. It also rules out "just widen
|
|
36
|
-
`CorePikkuMiddleware` to accept `PikkuRawWire`" as a free fix — that would make
|
|
37
|
-
`rpc` optional for _every_ middleware in the framework, pushing the problem onto
|
|
38
|
-
every consumer to satisfy one transport.
|
|
39
|
-
|
|
40
|
-
**Still open:** whether the listener path should wrap its handler in a
|
|
41
|
-
`runPikkuFunc` invocation the way the other two do, which would make the three
|
|
42
|
-
transports behave identically and remove the assertion. Nobody has argued
|
|
43
|
-
against it; it simply has not been done.
|
|
@@ -1,28 +0,0 @@
|
|
|
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.
|