@pikku/core 0.12.79 → 0.12.82
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +473 -0
- package/dist/dev/hot-reload.js +1 -6
- package/dist/ecosystem.d.ts +27 -0
- package/dist/ecosystem.js +26 -0
- package/dist/errors/error-handler.js +4 -2
- package/dist/errors/index.d.ts +1 -1
- package/dist/errors/index.js +1 -1
- package/dist/function/function-runner.js +22 -47
- package/dist/function/functions.types.d.ts +9 -5
- package/dist/function/index.d.ts +1 -1
- package/dist/index.d.ts +14 -19
- package/dist/index.js +6 -11
- package/dist/middleware/auth-cookie.d.ts +0 -4
- package/dist/middleware/auth-cookie.js +38 -2
- package/dist/middleware/cors.js +1 -0
- package/dist/middleware/index.d.ts +1 -1
- package/dist/middleware/index.js +1 -1
- package/dist/middleware/remote-auth.js +14 -3
- package/dist/permissions.d.ts +8 -10
- package/dist/permissions.js +0 -11
- package/dist/pikku-state.js +16 -5
- package/dist/schema.js +35 -1
- package/dist/services/ai-agent-runner-service.d.ts +7 -0
- package/dist/services/ai-run-state-service.d.ts +17 -1
- package/dist/services/in-memory-ai-run-state-service.d.ts +6 -2
- package/dist/services/in-memory-ai-run-state-service.js +11 -1
- package/dist/services/in-memory-workflow-service.js +2 -0
- package/dist/services/index.d.ts +15 -15
- package/dist/services/index.js +5 -5
- package/dist/services/local-content-request-handler.d.ts +21 -0
- package/dist/services/local-content-request-handler.js +72 -53
- package/dist/services/local-content.d.ts +6 -0
- package/dist/services/local-content.js +14 -1
- package/dist/services/scoped-credential-service.d.ts +21 -0
- package/dist/services/scoped-credential-service.js +53 -0
- package/dist/services/workflow-service.d.ts +4 -2
- package/dist/testing/service-tests/agent-run-service-tests.d.ts +10 -0
- package/dist/testing/service-tests/agent-run-service-tests.js +72 -0
- package/dist/testing/service-tests/ai-storage-service-tests.d.ts +3 -0
- package/dist/testing/service-tests/ai-storage-service-tests.js +302 -0
- package/dist/testing/service-tests/channel-store-tests.d.ts +3 -0
- package/dist/testing/service-tests/channel-store-tests.js +72 -0
- package/dist/testing/service-tests/credential-service-tests.d.ts +3 -0
- package/dist/testing/service-tests/credential-service-tests.js +109 -0
- package/dist/testing/service-tests/deployment-service-tests.d.ts +3 -0
- package/dist/testing/service-tests/deployment-service-tests.js +21 -0
- package/dist/testing/service-tests/event-hub-store-tests.d.ts +3 -0
- package/dist/testing/service-tests/event-hub-store-tests.js +34 -0
- package/dist/testing/service-tests/secret-service-tests.d.ts +3 -0
- package/dist/testing/service-tests/secret-service-tests.js +80 -0
- package/dist/testing/service-tests/session-store-tests.d.ts +3 -0
- package/dist/testing/service-tests/session-store-tests.js +43 -0
- package/dist/testing/service-tests/workflow-run-service-tests.d.ts +3 -0
- package/dist/testing/service-tests/workflow-run-service-tests.js +42 -0
- package/dist/testing/service-tests/workflow-service-tests.d.ts +3 -0
- package/dist/testing/service-tests/workflow-service-tests.js +150 -0
- package/dist/testing/service-tests.d.ts +6 -0
- package/dist/testing/service-tests.js +26 -791
- package/dist/types/core.types.d.ts +11 -3
- package/dist/types/state.types.d.ts +14 -1
- package/dist/wirings/actor-flow/index.d.ts +1 -1
- package/dist/wirings/actor-flow/run-conversation.js +1 -6
- package/dist/wirings/ai-agent/agent-rpc.d.ts +15 -0
- package/dist/wirings/ai-agent/agent-rpc.js +53 -0
- package/dist/wirings/ai-agent/ai-agent-agui.js +1 -5
- package/dist/wirings/ai-agent/ai-agent-finalize.d.ts +58 -0
- package/dist/wirings/ai-agent/ai-agent-finalize.js +138 -0
- package/dist/wirings/ai-agent/ai-agent-interrupt.js +1 -0
- package/dist/wirings/ai-agent/ai-agent-memory.d.ts +2 -8
- package/dist/wirings/ai-agent/ai-agent-memory.js +37 -18
- package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +7 -0
- package/dist/wirings/ai-agent/ai-agent-model-config.js +44 -1
- package/dist/wirings/ai-agent/ai-agent-prepare.js +5 -9
- package/dist/wirings/ai-agent/ai-agent-runner.js +89 -147
- package/dist/wirings/ai-agent/ai-agent-stream.js +109 -97
- package/dist/wirings/ai-agent/ai-agent-turn.d.ts +57 -0
- package/dist/wirings/ai-agent/ai-agent-turn.js +82 -0
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +47 -2
- package/dist/wirings/ai-agent/index.d.ts +8 -7
- package/dist/wirings/ai-agent/index.js +5 -4
- package/dist/wirings/ai-agent/voice-input.js +1 -6
- package/dist/wirings/ai-agent/voice-output.js +2 -12
- package/dist/wirings/ai-scorer/ai-scorer-grade.d.ts +26 -0
- package/dist/wirings/ai-scorer/ai-scorer-grade.js +33 -0
- package/dist/wirings/ai-scorer/ai-scorer-judge.d.ts +17 -0
- package/dist/wirings/ai-scorer/ai-scorer-judge.js +92 -0
- package/dist/wirings/ai-scorer/ai-scorer-live.d.ts +15 -0
- package/dist/wirings/ai-scorer/ai-scorer-live.js +38 -0
- package/dist/wirings/ai-scorer/ai-scorer-registry.d.ts +18 -0
- package/dist/wirings/ai-scorer/ai-scorer-registry.js +46 -0
- package/dist/wirings/ai-scorer/ai-scorer-sampling.d.ts +8 -0
- package/dist/wirings/ai-scorer/ai-scorer-sampling.js +31 -0
- package/dist/wirings/ai-scorer/ai-scorer-snapshots.d.ts +10 -0
- package/dist/wirings/ai-scorer/ai-scorer-snapshots.js +40 -0
- package/dist/wirings/ai-scorer/ai-scorer-worker.d.ts +15 -0
- package/dist/wirings/ai-scorer/ai-scorer-worker.js +58 -0
- package/dist/wirings/ai-scorer/ai-scorer.d.ts +39 -0
- package/dist/wirings/ai-scorer/ai-scorer.js +40 -0
- package/dist/wirings/ai-scorer/ai-scorer.types.d.ts +90 -0
- package/dist/wirings/ai-scorer/ai-scorer.types.js +4 -0
- package/dist/wirings/ai-scorer/index.d.ts +6 -0
- package/dist/wirings/ai-scorer/index.js +5 -0
- package/dist/wirings/channel/channel-common.js +1 -0
- package/dist/wirings/channel/channel-handler.js +3 -5
- package/dist/wirings/channel/channel-rpc-service.d.ts +0 -6
- package/dist/wirings/channel/channel-rpc-service.js +0 -8
- package/dist/wirings/channel/channel-rpc.types.d.ts +6 -0
- package/dist/wirings/channel/channel-rpc.types.js +8 -0
- package/dist/wirings/channel/channel-runner.d.ts +1 -3
- package/dist/wirings/channel/channel-runner.js +16 -8
- package/dist/wirings/channel/channel.types.d.ts +2 -0
- package/dist/wirings/channel/index.d.ts +5 -6
- package/dist/wirings/channel/index.js +3 -4
- package/dist/wirings/channel/local/local-channel-runner.js +8 -1
- package/dist/wirings/channel/pikku-abstract-channel-handler.js +1 -0
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +3 -0
- package/dist/wirings/cli/channel/cli-channel-runner.js +2 -0
- package/dist/wirings/cli/channel/cli-raw-channel-runner.js +9 -1
- package/dist/wirings/cli/channel/index.d.ts +1 -2
- package/dist/wirings/cli/channel/index.js +0 -1
- package/dist/wirings/cli/cli-runner.js +17 -3
- package/dist/wirings/cli/cli.types.d.ts +0 -8
- package/dist/wirings/cli/command-parser.js +13 -0
- package/dist/wirings/credential/index.d.ts +1 -1
- package/dist/wirings/gateway/gateway-runner.js +9 -2
- package/dist/wirings/gateway/index.d.ts +1 -1
- package/dist/wirings/http/http-routes.js +2 -0
- package/dist/wirings/http/http-runner.d.ts +0 -10
- package/dist/wirings/http/http-runner.js +14 -15
- package/dist/wirings/http/http.types.d.ts +0 -10
- package/dist/wirings/http/index.d.ts +2 -3
- package/dist/wirings/http/index.js +1 -1
- package/dist/wirings/mcp/index.d.ts +1 -1
- package/dist/wirings/mcp/mcp-runner.d.ts +15 -7
- package/dist/wirings/mcp/mcp-runner.js +18 -11
- package/dist/wirings/persona/index.d.ts +3 -4
- package/dist/wirings/persona/index.js +2 -3
- package/dist/wirings/queue/index.d.ts +1 -3
- package/dist/wirings/queue/index.js +1 -3
- package/dist/wirings/rpc/addon-runner.d.ts +4 -0
- package/dist/wirings/rpc/addon-runner.js +19 -3
- package/dist/wirings/rpc/rpc-runner.d.ts +8 -51
- package/dist/wirings/rpc/rpc-runner.js +55 -86
- package/dist/wirings/rpc/rpc-types.d.ts +7 -0
- package/dist/wirings/rpc/wire-addon.d.ts +13 -0
- package/dist/wirings/rpc/wire-addon.js +4 -0
- package/dist/wirings/scheduler/index.d.ts +1 -1
- package/dist/wirings/secret/validate-secret-definitions.js +2 -2
- package/dist/wirings/trigger/index.d.ts +1 -1
- package/dist/wirings/trigger/pikku-trigger-service.d.ts +0 -4
- package/dist/wirings/trigger/trigger-runner.js +1 -0
- package/dist/wirings/virtual-user/index.d.ts +5 -6
- package/dist/wirings/virtual-user/index.js +2 -4
- package/dist/wirings/virtual-user/run-virtual-user.js +11 -11
- package/dist/wirings/virtual-user/virtual-user-derive.js +4 -25
- package/dist/wirings/virtual-user/virtual-user-dispositions.js +1 -4
- package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +100 -3
- package/dist/wirings/workflow/feature.js +7 -4
- package/dist/wirings/workflow/graph/graph-runner.d.ts +1 -2
- package/dist/wirings/workflow/graph/graph-runner.js +8 -7
- package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +0 -4
- package/dist/wirings/workflow/index.d.ts +12 -7
- package/dist/wirings/workflow/index.js +7 -3
- package/dist/wirings/workflow/pikku-scenario-service.d.ts +17 -3
- package/dist/wirings/workflow/pikku-scenario-service.js +64 -10
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +28 -147
- package/dist/wirings/workflow/pikku-workflow-service.js +85 -493
- package/dist/wirings/workflow/scenario-step.types.d.ts +8 -0
- package/dist/wirings/workflow/workflow-approval-audit.d.ts +16 -0
- package/dist/wirings/workflow/workflow-approval-audit.js +40 -0
- package/dist/wirings/workflow/workflow-approval-policy.d.ts +20 -0
- package/dist/wirings/workflow/workflow-approval-policy.js +48 -0
- package/dist/wirings/workflow/workflow-approval.d.ts +67 -0
- package/dist/wirings/workflow/workflow-approval.js +177 -0
- package/dist/wirings/workflow/workflow-constants.d.ts +26 -0
- package/dist/wirings/workflow/workflow-constants.js +35 -0
- package/dist/wirings/workflow/workflow-errors.d.ts +58 -0
- package/dist/wirings/workflow/workflow-errors.js +112 -0
- package/dist/wirings/workflow/workflow-meta-resolver.d.ts +11 -0
- package/dist/wirings/workflow/workflow-meta-resolver.js +31 -0
- package/dist/wirings/workflow/workflow-queue-routing.d.ts +8 -0
- package/dist/wirings/workflow/workflow-queue-routing.js +38 -0
- package/dist/wirings/workflow/workflow-queue-wiring.d.ts +20 -0
- package/dist/wirings/workflow/workflow-queue-wiring.js +79 -0
- package/dist/wirings/workflow/workflow-recovery.d.ts +68 -0
- package/dist/wirings/workflow/workflow-recovery.js +101 -0
- package/dist/wirings/workflow/workflow-run-engine.types.d.ts +54 -0
- package/dist/wirings/workflow/workflow-run-ownership.d.ts +17 -0
- package/dist/wirings/workflow/workflow-run-ownership.js +30 -0
- package/dist/wirings/workflow/workflow-suspend.d.ts +12 -0
- package/dist/wirings/workflow/workflow-suspend.js +33 -0
- package/dist/wirings/workflow/workflow.types.d.ts +8 -1
- package/knowledge/decisions/internals/a-non-streaming-agent-run-registers-with-airunstate-too.md +22 -0
- package/knowledge/decisions/internals/a-resumed-agent-turn-is-as-interruptible-as-the-first.md +20 -0
- package/knowledge/decisions/internals/a-scenario-step-template-is-offered-unfilled.md +21 -0
- package/knowledge/decisions/internals/a-virtual-user-decides-whether-to-trust-memory-once-per-turn.md +21 -0
- package/knowledge/decisions/internals/a-wall-clock-threshold-is-a-load-test-in-disguise.md +46 -0
- package/knowledge/decisions/internals/a-workflow-wire-is-built-from-the-run-not-from-the-rpc-service.md +45 -0
- package/knowledge/decisions/internals/addon-pikku-meta-ships-at-the-package-root-or-under-dist.md +32 -0
- package/knowledge/decisions/internals/agent-context-waits-for-a-tool-result-still-being-written.md +21 -0
- package/knowledge/decisions/internals/agent-speech-travels-as-a-custom-agui-event.md +22 -0
- package/knowledge/decisions/internals/an-addon-scope-root-loses-to-a-root-the-host-already-declares.md +39 -0
- package/knowledge/decisions/internals/an-agent-interrupt-is-not-a-failure.md +23 -0
- package/knowledge/decisions/internals/an-agent-run-owned-by-another-instance-says-so.md +25 -0
- package/knowledge/decisions/internals/an-agent-stream-send-must-return-the-inner-sends-promise.md +22 -0
- package/knowledge/decisions/internals/an-empty-text-part-is-omitted-from-an-agent-message.md +20 -0
- package/knowledge/decisions/internals/an-empty-transcript-is-not-recorded.md +22 -0
- package/knowledge/decisions/internals/an-unref-d-timer-cannot-be-awaited-under-node-test.md +66 -0
- package/knowledge/decisions/internals/channel-state-accessors-are-unsound-generics-that-every-implementation-asserts.md +33 -0
- package/knowledge/decisions/internals/gateway-listener-middleware-runs-without-an-rpc-on-the-wire.md +43 -0
- package/knowledge/decisions/internals/hot-reload-writes-into-the-function-map-captured-at-startup.md +26 -0
- package/knowledge/decisions/internals/index.md +42 -3
- package/knowledge/decisions/internals/only-exposed-functions-enter-a-virtual-user-catalogue.md +21 -0
- package/knowledge/decisions/internals/scenario-given-and-when-are-sugar-but-then-is-not.md +24 -0
- package/knowledge/decisions/internals/side-effects-are-an-allowlist-not-a-boolean.md +34 -0
- package/knowledge/decisions/internals/speech-synthesis-picks-a-voice-per-sentence-and-warns-once.md +24 -0
- package/knowledge/decisions/internals/the-actor-prompt-says-json-because-of-json-object-mode.md +22 -0
- package/knowledge/decisions/internals/the-agent-done-event-goes-through-the-middleware-and-is-awaited.md +26 -0
- package/knowledge/decisions/internals/the-api-report-pins-members-not-just-names.md +43 -0
- package/knowledge/decisions/internals/the-ecosystem-entry-point-carries-the-adapter-surface.md +58 -0
- package/knowledge/decisions/internals/the-middleware-resolution-cache-is-deliberately-unbounded.md +40 -0
- package/knowledge/decisions/internals/the-per-invocation-rpc-view-is-a-class.md +40 -0
- package/knowledge/decisions/internals/the-persona-runtime-is-exported-from-the-persona-entry-point.md +28 -0
- package/knowledge/decisions/internals/the-transcript-event-is-sent-ahead-of-the-run.md +25 -0
- package/knowledge/decisions/internals/the-virtual-user-catalogue-is-the-only-gate-on-what-may-be-called.md +21 -0
- package/knowledge/decisions/internals/the-worker-disposition-is-the-one-that-is-not-testing.md +22 -0
- package/knowledge/decisions/internals/thread-history-records-the-transcript-not-the-audio.md +25 -0
- package/knowledge/decisions/internals/validate-runs-checks-by-precondition.md +115 -0
- package/knowledge/decisions/internals/virtual-user-step-order-comes-from-insertion-order.md +21 -0
- package/knowledge/decisions/internals/voice-output-speaks-unless-voice-input-explicitly-says-otherwise.md +24 -0
- package/knowledge/decisions/internals/wiring-registries-erase-the-generics-their-wire-functions-capture.md +35 -0
- package/knowledge/decisions/security/a-dropped-audit-write-is-always-logged.md +4 -2
- package/knowledge/decisions/security/a-function-never-receives-the-secret-service.md +37 -0
- package/knowledge/decisions/security/a-graph-run-starts-at-an-entry-node-the-graph-declared.md +33 -0
- package/knowledge/decisions/security/a-permission-gets-a-wire-it-cannot-reply-on.md +33 -0
- package/knowledge/decisions/security/a-step-runs-the-function-the-workflow-dispatched-it-with.md +37 -0
- package/knowledge/decisions/security/a-virtual-user-is-never-offered-a-step-that-would-forge-its-own-oracle.md +28 -0
- package/knowledge/decisions/security/a-workflow-run-is-read-and-approved-by-its-owner.md +50 -0
- package/knowledge/decisions/security/an-agent-approval-is-claimed-before-the-tool-runs.md +33 -0
- package/knowledge/decisions/security/an-approval-answer-outlives-the-run-it-answered.md +59 -0
- package/knowledge/decisions/security/an-upload-is-counted-as-it-arrives-not-buffered-then-measured.md +24 -0
- package/knowledge/decisions/security/index.md +9 -0
- package/knowledge/questions/channel-middleware-accepts-bare-factories-that-nothing-resolves.md +35 -0
- package/knowledge/questions/index.md +2 -1
- package/knowledge/questions/unauthorized-channel-replies-escape-the-declared-out-type.md +44 -0
- package/package.json +15 -3
- package/scripts/generate-api-report.d.mts +1 -0
- package/scripts/generate-api-report.mjs +89 -0
- package/scripts/generate-api-report.mts +343 -0
- package/src/api-report.test.ts +69 -0
- package/src/column-form.ts +1 -4
- package/src/crypto-utils.test.ts +15 -2
- package/src/dev/hot-reload.ts +2 -7
- package/src/ecosystem.ts +40 -0
- package/src/errors/error-handler.ts +5 -3
- package/src/errors/error.test.ts +4 -1
- package/src/errors/index.ts +1 -1
- package/src/function/function-runner.test.ts +53 -1
- package/src/function/function-runner.ts +33 -48
- package/src/function/functions.types.ts +15 -9
- package/src/function/index.ts +0 -2
- package/src/handle-error.ts +1 -1
- package/src/index.ts +3 -57
- package/src/middleware/auth-cookie.test.ts +50 -0
- package/src/middleware/auth-cookie.ts +38 -2
- package/src/middleware/cors.ts +2 -1
- package/src/middleware/index.ts +1 -1
- package/src/middleware/remote-auth.test.ts +43 -0
- package/src/middleware/remote-auth.ts +17 -3
- package/src/middleware-runner.ts +4 -2
- package/src/no-any-casts.test.ts +57 -0
- package/src/permissions.test.ts +3 -1
- package/src/permissions.ts +22 -24
- package/src/pikku-state.ts +22 -6
- package/src/public-surface.json +554 -0
- package/src/public-surface.json.README +25 -0
- package/src/public-surface.test.ts +105 -0
- package/src/removed-legacy-exports.test.ts +62 -0
- package/src/schema.test.ts +78 -0
- package/src/schema.ts +36 -1
- package/src/services/ai-agent-runner-service.ts +12 -1
- package/src/services/ai-run-state-service.ts +18 -1
- package/src/services/audit-service.ts +2 -2
- package/src/services/in-memory-ai-run-state-service.ts +16 -2
- package/src/services/in-memory-workflow-service.ts +2 -0
- package/src/services/index.ts +4 -47
- package/src/services/local-content-request-handler.test.ts +43 -5
- package/src/services/local-content-request-handler.ts +103 -74
- package/src/services/local-content.ts +15 -1
- package/src/services/local-email-service.ts +5 -1
- package/src/services/scoped-credential-service.test.ts +86 -0
- package/src/services/scoped-credential-service.ts +63 -0
- package/src/services/system-role-guard.test.ts +4 -1
- package/src/services/workflow-service.ts +9 -2
- package/src/side-effects-are-declared.test.ts +84 -0
- package/src/source-files-stay-composable.test.ts +41 -0
- package/src/testing/service-tests/agent-run-service-tests.ts +98 -0
- package/src/testing/service-tests/ai-storage-service-tests.ts +379 -0
- package/src/testing/service-tests/channel-store-tests.ts +98 -0
- package/src/testing/service-tests/credential-service-tests.ts +143 -0
- package/src/testing/service-tests/deployment-service-tests.ts +33 -0
- package/src/testing/service-tests/event-hub-store-tests.ts +48 -0
- package/src/testing/service-tests/secret-service-tests.ts +105 -0
- package/src/testing/service-tests/session-store-tests.ts +62 -0
- package/src/testing/service-tests/workflow-run-service-tests.ts +59 -0
- package/src/testing/service-tests/workflow-service-tests.ts +308 -0
- package/src/testing/service-tests.ts +31 -1111
- package/src/types/core.types.ts +14 -3
- package/src/types/state.types.ts +17 -1
- package/src/wirings/actor-flow/index.ts +0 -3
- package/src/wirings/actor-flow/run-conversation.ts +1 -6
- package/src/wirings/ai-agent/agent-rpc.ts +120 -0
- package/src/wirings/ai-agent/ai-agent-agui.ts +1 -5
- package/src/wirings/ai-agent/ai-agent-finalize.test.ts +186 -0
- package/src/wirings/ai-agent/ai-agent-finalize.ts +197 -0
- package/src/wirings/ai-agent/ai-agent-interrupt.test.ts +2 -1
- package/src/wirings/ai-agent/ai-agent-interrupt.ts +1 -0
- package/src/wirings/ai-agent/ai-agent-memory.ts +62 -39
- package/src/wirings/ai-agent/ai-agent-model-config.test.ts +72 -3
- package/src/wirings/ai-agent/ai-agent-model-config.ts +49 -1
- package/src/wirings/ai-agent/ai-agent-prepare.ts +12 -12
- package/src/wirings/ai-agent/ai-agent-resume-authorization.test.ts +1 -0
- package/src/wirings/ai-agent/ai-agent-runner.test.ts +82 -2
- package/src/wirings/ai-agent/ai-agent-runner.ts +120 -160
- package/src/wirings/ai-agent/ai-agent-stream-output-hooks.test.ts +353 -0
- package/src/wirings/ai-agent/ai-agent-stream.test.ts +2 -0
- package/src/wirings/ai-agent/ai-agent-stream.ts +152 -117
- package/src/wirings/ai-agent/ai-agent-thread-ownership.test.ts +1 -1
- package/src/wirings/ai-agent/ai-agent-turn.test.ts +67 -0
- package/src/wirings/ai-agent/ai-agent-turn.ts +122 -0
- package/src/wirings/ai-agent/ai-agent.types.ts +65 -5
- package/src/wirings/ai-agent/index.ts +2 -16
- package/src/wirings/ai-agent/voice-input.ts +1 -6
- package/src/wirings/ai-agent/voice-output.ts +2 -12
- package/src/wirings/ai-scorer/ai-scorer-grade.test.ts +106 -0
- package/src/wirings/ai-scorer/ai-scorer-grade.ts +55 -0
- package/src/wirings/ai-scorer/ai-scorer-judge.test.ts +143 -0
- package/src/wirings/ai-scorer/ai-scorer-judge.ts +120 -0
- package/src/wirings/ai-scorer/ai-scorer-live.test.ts +174 -0
- package/src/wirings/ai-scorer/ai-scorer-live.ts +56 -0
- package/src/wirings/ai-scorer/ai-scorer-registry.ts +63 -0
- package/src/wirings/ai-scorer/ai-scorer-sampling.test.ts +34 -0
- package/src/wirings/ai-scorer/ai-scorer-sampling.ts +36 -0
- package/src/wirings/ai-scorer/ai-scorer-snapshots.test.ts +49 -0
- package/src/wirings/ai-scorer/ai-scorer-snapshots.ts +46 -0
- package/src/wirings/ai-scorer/ai-scorer-worker.test.ts +122 -0
- package/src/wirings/ai-scorer/ai-scorer-worker.ts +69 -0
- package/src/wirings/ai-scorer/ai-scorer.ts +76 -0
- package/src/wirings/ai-scorer/ai-scorer.types.ts +107 -0
- package/src/wirings/ai-scorer/index.ts +24 -0
- package/src/wirings/channel/channel-common.ts +5 -2
- package/src/wirings/channel/channel-handler-shapes.test.ts +72 -0
- package/src/wirings/channel/channel-handler.ts +7 -7
- package/src/wirings/channel/channel-rpc-service.ts +0 -14
- package/src/wirings/channel/channel-rpc.test.ts +25 -4
- package/src/wirings/channel/channel-rpc.types.ts +14 -0
- package/src/wirings/channel/channel-runner.ts +33 -20
- package/src/wirings/channel/channel.types.ts +2 -0
- package/src/wirings/channel/index.ts +1 -20
- package/src/wirings/channel/local/local-channel-runner.test.ts +68 -0
- package/src/wirings/channel/local/local-channel-runner.ts +9 -2
- package/src/wirings/channel/pikku-abstract-channel-handler.ts +2 -1
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +6 -3
- package/src/wirings/cli/channel/cli-channel-runner.ts +3 -1
- package/src/wirings/cli/channel/cli-raw-channel-runner.test.ts +23 -0
- package/src/wirings/cli/channel/cli-raw-channel-runner.ts +12 -1
- package/src/wirings/cli/channel/cli-raw-client-runner.ts +4 -1
- package/src/wirings/cli/channel/index.ts +0 -7
- package/src/wirings/cli/cli-runner.test.ts +68 -0
- package/src/wirings/cli/cli-runner.ts +25 -5
- package/src/wirings/cli/cli.types.ts +0 -39
- package/src/wirings/cli/command-parser.test.ts +19 -0
- package/src/wirings/cli/command-parser.ts +17 -1
- package/src/wirings/credential/index.ts +0 -1
- package/src/wirings/gateway/gateway-channel-meta.test.ts +44 -0
- package/src/wirings/gateway/gateway-runner.ts +27 -19
- package/src/wirings/gateway/index.ts +0 -3
- package/src/wirings/http/http-routes.ts +4 -1
- package/src/wirings/http/http-runner.test.ts +66 -0
- package/src/wirings/http/http-runner.ts +21 -28
- package/src/wirings/http/http.types.ts +0 -15
- package/src/wirings/http/index.ts +2 -8
- package/src/wirings/http/pikku-fetch-http-request.ts +2 -2
- package/src/wirings/http/web-request.ts +1 -1
- package/src/wirings/mcp/index.ts +0 -1
- package/src/wirings/mcp/mcp-runner.test.ts +181 -0
- package/src/wirings/mcp/mcp-runner.ts +37 -21
- package/src/wirings/persona/index.ts +0 -8
- package/src/wirings/persona/persona-environments.test.ts +14 -3
- package/src/wirings/persona/persona.test.ts +13 -3
- package/src/wirings/persona/validate-personas.ts +5 -1
- package/src/wirings/queue/index.ts +0 -14
- package/src/wirings/queue/queue-runner.ts +1 -1
- package/src/wirings/rpc/addon-auth-tags.test.ts +1 -5
- package/src/wirings/rpc/addon-runner.ts +34 -3
- package/src/wirings/rpc/addon-secrets.test.ts +261 -0
- package/src/wirings/rpc/rpc-runner.test.ts +2 -0
- package/src/wirings/rpc/rpc-runner.ts +60 -136
- package/src/wirings/rpc/rpc-types.ts +11 -0
- package/src/wirings/rpc/wire-addon.ts +20 -1
- package/src/wirings/scheduler/index.ts +0 -1
- package/src/wirings/secret/validate-secret-definitions.test.ts +22 -0
- package/src/wirings/secret/validate-secret-definitions.ts +2 -2
- package/src/wirings/trigger/index.ts +0 -1
- package/src/wirings/trigger/pikku-trigger-service.ts +0 -5
- package/src/wirings/trigger/trigger-runner.ts +7 -5
- package/src/wirings/virtual-user/index.ts +0 -16
- package/src/wirings/virtual-user/run-virtual-user.test.ts +18 -9
- package/src/wirings/virtual-user/run-virtual-user.ts +28 -15
- package/src/wirings/virtual-user/virtual-user-agents.test.ts +4 -1
- package/src/wirings/virtual-user/virtual-user-derive.ts +4 -25
- package/src/wirings/virtual-user/virtual-user-dispositions.test.ts +7 -2
- package/src/wirings/virtual-user/virtual-user-dispositions.ts +1 -4
- package/src/wirings/virtual-user/virtual-user-intents.test.ts +13 -3
- package/src/wirings/workflow/dsl/workflow-dsl.types.ts +117 -4
- package/src/wirings/workflow/feature.ts +7 -4
- package/src/wirings/workflow/graph/graph-node.ts +1 -1
- package/src/wirings/workflow/graph/graph-runner.test.ts +76 -2
- package/src/wirings/workflow/graph/graph-runner.ts +13 -16
- package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -5
- package/src/wirings/workflow/index.ts +14 -24
- package/src/wirings/workflow/pikku-scenario-service.ts +101 -27
- package/src/wirings/workflow/pikku-workflow-service.test.ts +15 -14
- package/src/wirings/workflow/pikku-workflow-service.ts +214 -743
- package/src/wirings/workflow/scenario-expectations.test.ts +75 -0
- package/src/wirings/workflow/scenario-hooks.test.ts +52 -0
- package/src/wirings/workflow/scenario-step.types.ts +8 -0
- package/src/wirings/workflow/workflow-approval-audit.ts +47 -0
- package/src/wirings/workflow/workflow-approval-policy.test.ts +524 -0
- package/src/wirings/workflow/workflow-approval-policy.ts +68 -0
- package/src/wirings/workflow/workflow-approval.ts +289 -0
- package/src/wirings/workflow/workflow-child-run-session.test.ts +89 -0
- package/src/wirings/workflow/workflow-constants.ts +47 -0
- package/src/wirings/workflow/workflow-dispatch-durability.test.ts +1 -1
- package/src/wirings/workflow/workflow-errors.ts +128 -0
- package/src/wirings/workflow/workflow-inline-authority.test.ts +12 -6
- package/src/wirings/workflow/workflow-meta-resolver.ts +45 -0
- package/src/wirings/workflow/workflow-missing-meta.test.ts +92 -0
- package/src/wirings/workflow/workflow-queue-routing.ts +85 -0
- package/src/wirings/workflow/workflow-queue-wiring.ts +149 -0
- package/src/wirings/workflow/workflow-recovery.ts +162 -0
- package/src/wirings/workflow/workflow-retry-policy.test.ts +1 -1
- package/src/wirings/workflow/workflow-run-authority.test.ts +212 -0
- package/src/wirings/workflow/workflow-run-engine.types.ts +91 -0
- package/src/wirings/workflow/workflow-run-ownership.ts +37 -0
- package/src/wirings/workflow/workflow-suspend.ts +61 -0
- package/src/wirings/workflow/workflow.types.ts +7 -9
- package/src/wirings-stay-decoupled.test.ts +127 -0
- package/tsconfig.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/internal.d.ts +0 -3
- package/dist/internal.js +0 -2
- package/dist/middleware/timeout.d.ts +0 -9
- package/dist/middleware/timeout.js +0 -15
- package/dist/pikku-response.d.ts +0 -6
- package/dist/pikku-response.js +0 -6
- package/dist/services/gopass-secrets.d.ts +0 -15
- package/dist/services/gopass-secrets.js +0 -76
- package/dist/services/http-scenario-actors.d.ts +0 -75
- package/dist/services/http-scenario-actors.js +0 -195
- package/dist/services/http-user-flow-actors.d.ts +0 -67
- package/dist/services/http-user-flow-actors.js +0 -193
- package/dist/services/scenario-actors-service.d.ts +0 -127
- package/dist/services/scenario-actors-service.js +0 -40
- package/dist/services/user-flow-actors-service.d.ts +0 -39
- package/dist/wirings/credential/wire-credential.d.ts +0 -48
- package/dist/wirings/credential/wire-credential.js +0 -47
- package/dist/wirings/oauth2/oauth2-client.d.ts +0 -47
- package/dist/wirings/oauth2/oauth2-client.js +0 -263
- package/dist/wirings/oauth2/oauth2-routes.d.ts +0 -35
- package/dist/wirings/oauth2/oauth2-routes.js +0 -146
- package/dist/wirings/scope/wire-scope.d.ts +0 -33
- package/dist/wirings/scope/wire-scope.js +0 -32
- package/dist/wirings/workflow/dsl/index.d.ts +0 -5
- package/dist/wirings/workflow/dsl/index.js +0 -4
- package/dist/wirings/workflow/graph/index.d.ts +0 -5
- package/dist/wirings/workflow/graph/index.js +0 -4
- package/src/internal.ts +0 -10
- /package/dist/{services/user-flow-actors-service.js → wirings/workflow/workflow-run-engine.types.js} +0 -0
|
@@ -206,14 +206,21 @@ export const runLocalChannel = async ({
|
|
|
206
206
|
|
|
207
207
|
const { onMessage, onBinaryMessage } = processMessageHandlers(
|
|
208
208
|
services,
|
|
209
|
-
channelConfig
|
|
209
|
+
channelConfig,
|
|
210
210
|
channelHandler,
|
|
211
211
|
userSession
|
|
212
212
|
)
|
|
213
213
|
channelHandler.registerOnMessage(async (data) => {
|
|
214
214
|
try {
|
|
215
215
|
const result = await onMessage(data)
|
|
216
|
-
|
|
216
|
+
// Guarded exactly as the connect path above is. A handler with nothing
|
|
217
|
+
// to say is normal — a gateway websocket's generated message handler
|
|
218
|
+
// always returns undefined — and sending that raised `send requires a
|
|
219
|
+
// non-empty message`, which surfaced as a channel that accepted a
|
|
220
|
+
// connection and then silently delivered nothing.
|
|
221
|
+
if (result !== undefined) {
|
|
222
|
+
await channel.send(result)
|
|
223
|
+
}
|
|
217
224
|
} catch (e: any) {
|
|
218
225
|
singletonServices.logger.error(e)
|
|
219
226
|
const errorResponse = getErrorResponse(e)
|
|
@@ -34,7 +34,8 @@ export abstract class PikkuAbstractChannelHandler<
|
|
|
34
34
|
setState: (s) => {
|
|
35
35
|
channelState = s
|
|
36
36
|
},
|
|
37
|
-
|
|
37
|
+
// knowledge: decisions/internals/channel-state-accessors-are-unsound-generics-that-every-implementation-asserts.md
|
|
38
|
+
getState: () => channelState as never,
|
|
38
39
|
clearState: () => {
|
|
39
40
|
channelState = undefined
|
|
40
41
|
},
|
|
@@ -117,7 +117,8 @@ export const runChannelConnect = async ({
|
|
|
117
117
|
channelName: channelConfig.name,
|
|
118
118
|
})
|
|
119
119
|
channel.setState = (state) => channelStore.setState(channelId, state)
|
|
120
|
-
|
|
120
|
+
// knowledge: decisions/internals/channel-state-accessors-are-unsound-generics-that-every-implementation-asserts.md
|
|
121
|
+
channel.getState = () => channelStore.getState(channelId) as never
|
|
121
122
|
channel.clearState = () => channelStore.clearState(channelId)
|
|
122
123
|
|
|
123
124
|
const wire: PikkuRawWire = {
|
|
@@ -198,7 +199,8 @@ export const runChannelDisconnect = async ({
|
|
|
198
199
|
channelName,
|
|
199
200
|
})
|
|
200
201
|
channel.setState = (state) => channelStore.setState(channelId, state)
|
|
201
|
-
|
|
202
|
+
// knowledge: decisions/internals/channel-state-accessors-are-unsound-generics-that-every-implementation-asserts.md
|
|
203
|
+
channel.getState = () => channelStore.getState(channelId) as never
|
|
202
204
|
channel.clearState = () => channelStore.clearState(channelId)
|
|
203
205
|
|
|
204
206
|
const userSession = new PikkuSessionService<CoreUserSession>(
|
|
@@ -271,7 +273,8 @@ export const runChannelMessage = async (
|
|
|
271
273
|
channelName,
|
|
272
274
|
})
|
|
273
275
|
channel.setState = (state) => channelStore.setState(channelId, state)
|
|
274
|
-
|
|
276
|
+
// knowledge: decisions/internals/channel-state-accessors-are-unsound-generics-that-every-implementation-asserts.md
|
|
277
|
+
channel.getState = () => channelStore.getState(channelId) as never
|
|
275
278
|
channel.clearState = () => channelStore.clearState(channelId)
|
|
276
279
|
|
|
277
280
|
const userSession = new PikkuSessionService<CoreUserSession>(
|
|
@@ -90,7 +90,9 @@ export async function executeCLIViaChannel({
|
|
|
90
90
|
return
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
|
|
93
|
+
// A CLI channel response is rendered off-process: there are no services
|
|
94
|
+
// to hand the renderer, and every CLI renderer ignores the argument.
|
|
95
|
+
renderer(null as never, response, undefined)
|
|
94
96
|
}
|
|
95
97
|
|
|
96
98
|
commandRoute.subscribe(commandId, responseHandler)
|
|
@@ -103,6 +103,29 @@ describe('handleRawCLI', () => {
|
|
|
103
103
|
assert.match(result.error!, /deploy plan is red/)
|
|
104
104
|
})
|
|
105
105
|
|
|
106
|
+
test('masks the raw error message to the client in production', async () => {
|
|
107
|
+
const prior = process.env.NODE_ENV
|
|
108
|
+
process.env.NODE_ENV = 'production'
|
|
109
|
+
try {
|
|
110
|
+
wireTestCLI(() => {
|
|
111
|
+
throw new Error('connection to internal-db:5432 failed: bad password')
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
const result = await handleRawCLI({
|
|
115
|
+
programName: 'fabric',
|
|
116
|
+
args: ['deploy'],
|
|
117
|
+
singletonServices,
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
assert.equal(result.exitCode, 1)
|
|
121
|
+
assert.equal(result.error, 'Command failed')
|
|
122
|
+
assert.doesNotMatch(result.error!, /internal-db|password/)
|
|
123
|
+
} finally {
|
|
124
|
+
if (prior === undefined) delete process.env.NODE_ENV
|
|
125
|
+
else process.env.NODE_ENV = prior
|
|
126
|
+
}
|
|
127
|
+
})
|
|
128
|
+
|
|
106
129
|
test('exits 0 on help and 1 on an unknown command', async () => {
|
|
107
130
|
wireTestCLI(() => ({}))
|
|
108
131
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { pikkuState } from '../../../pikku-state.js'
|
|
2
|
+
import { isProduction } from '../../../env.js'
|
|
2
3
|
import type { CLIMeta } from '../cli.types.js'
|
|
3
4
|
import { parseCLIArguments, generateCommandHelp } from '../command-parser.js'
|
|
4
5
|
import { runCLICommand } from '../cli-runner.js'
|
|
@@ -132,6 +133,16 @@ export async function handleRawCLI({
|
|
|
132
133
|
// A command can throw anything; `.message` off a string is undefined, and
|
|
133
134
|
// the run would then exit 1 saying nothing at all.
|
|
134
135
|
const message = e instanceof Error ? e.message : String(e)
|
|
135
|
-
|
|
136
|
+
// The raw message can carry internals (a stack, a DB error, a path). This
|
|
137
|
+
// runs over a channel that may be remote, so return a generic error in
|
|
138
|
+
// production and keep the detail server-side. Dev keeps the message inline.
|
|
139
|
+
singletonServices.logger.error?.(
|
|
140
|
+
`CLI channel command failed: ${message}`,
|
|
141
|
+
e
|
|
142
|
+
)
|
|
143
|
+
const clientError = isProduction()
|
|
144
|
+
? 'Command failed'
|
|
145
|
+
: message || 'Command failed'
|
|
146
|
+
return { error: clientError, exitCode: 1, commandId }
|
|
136
147
|
}
|
|
137
148
|
}
|
|
@@ -32,7 +32,10 @@ export type CorePikkuCLIClientRender<Data> = (
|
|
|
32
32
|
) => void | Promise<void>
|
|
33
33
|
|
|
34
34
|
/** The normal case once the server owns the command tree. */
|
|
35
|
-
const defaultJSONRenderer: CorePikkuCLIClientRender<any> = (
|
|
35
|
+
const defaultJSONRenderer: CorePikkuCLIClientRender<any> = (
|
|
36
|
+
_services,
|
|
37
|
+
data
|
|
38
|
+
) => {
|
|
36
39
|
console.log(JSON.stringify(data))
|
|
37
40
|
}
|
|
38
41
|
|
|
@@ -3,13 +3,6 @@ export { handleRawCLI } from './cli-raw-channel-runner.js'
|
|
|
3
3
|
export type { RawCLIFrame, RawCLIResult } from './cli-raw-channel-runner.js'
|
|
4
4
|
export { executeRawCLIViaChannel } from './cli-raw-client-runner.js'
|
|
5
5
|
export type {
|
|
6
|
-
ClientCLIRenderServices,
|
|
7
6
|
CorePikkuCLIClientRender,
|
|
8
7
|
} from './cli-raw-client-runner.js'
|
|
9
|
-
export {
|
|
10
|
-
APPROVAL_FLAGS,
|
|
11
|
-
approverForMode,
|
|
12
|
-
createTerminalApprover,
|
|
13
|
-
takeApprovalFlags,
|
|
14
|
-
} from './cli-approval.js'
|
|
15
8
|
export type { ApprovalMode } from './cli-approval.js'
|
|
@@ -396,6 +396,74 @@ describe('CLI Runner', () => {
|
|
|
396
396
|
const programs = pikkuState(null, 'cli', 'programs')
|
|
397
397
|
assert.strictEqual(programs['nonexistent'], undefined)
|
|
398
398
|
})
|
|
399
|
+
|
|
400
|
+
test('enforces command-level permissions declared on a CLI command', async () => {
|
|
401
|
+
let functionRan = false
|
|
402
|
+
|
|
403
|
+
pikkuState(null, 'cli', 'meta', {
|
|
404
|
+
programs: {
|
|
405
|
+
'sec-cli': {
|
|
406
|
+
program: 'sec-cli',
|
|
407
|
+
commands: {
|
|
408
|
+
secret: {
|
|
409
|
+
command: 'secret',
|
|
410
|
+
pikkuFuncId: 'secretFunc',
|
|
411
|
+
positionals: [],
|
|
412
|
+
options: {},
|
|
413
|
+
},
|
|
414
|
+
},
|
|
415
|
+
options: {},
|
|
416
|
+
},
|
|
417
|
+
},
|
|
418
|
+
renderers: {},
|
|
419
|
+
})
|
|
420
|
+
pikkuState(null, 'function', 'meta', {
|
|
421
|
+
secretFunc: {
|
|
422
|
+
pikkuFuncId: 'secretFunc',
|
|
423
|
+
inputSchemaName: null,
|
|
424
|
+
outputSchemaName: null,
|
|
425
|
+
sessionless: true,
|
|
426
|
+
},
|
|
427
|
+
})
|
|
428
|
+
|
|
429
|
+
wireCLI({
|
|
430
|
+
program: 'sec-cli',
|
|
431
|
+
commands: {
|
|
432
|
+
// command.func is a function-config object, so unwrapFunc reads the
|
|
433
|
+
// inner func's auth/permissions and previously dropped the
|
|
434
|
+
// command-level ones — the branch this fix restores.
|
|
435
|
+
secret: {
|
|
436
|
+
func: {
|
|
437
|
+
func: async () => {
|
|
438
|
+
functionRan = true
|
|
439
|
+
return {}
|
|
440
|
+
},
|
|
441
|
+
},
|
|
442
|
+
// A permission that always denies.
|
|
443
|
+
permissions: { deny: async () => false },
|
|
444
|
+
} as any,
|
|
445
|
+
},
|
|
446
|
+
})
|
|
447
|
+
|
|
448
|
+
const result = await runCLICommand({
|
|
449
|
+
program: 'sec-cli',
|
|
450
|
+
commandPath: ['secret'],
|
|
451
|
+
data: {},
|
|
452
|
+
singletonServices,
|
|
453
|
+
createWireServices,
|
|
454
|
+
}).catch((error) => ({ success: false, error }))
|
|
455
|
+
|
|
456
|
+
assert.equal(
|
|
457
|
+
functionRan,
|
|
458
|
+
false,
|
|
459
|
+
'the function must not run when a declared permission denies'
|
|
460
|
+
)
|
|
461
|
+
assert.notEqual(
|
|
462
|
+
(result as any).success,
|
|
463
|
+
true,
|
|
464
|
+
'the command must not report success when permission is denied'
|
|
465
|
+
)
|
|
466
|
+
})
|
|
399
467
|
})
|
|
400
468
|
|
|
401
469
|
describe('pikkuCLIRender', () => {
|
|
@@ -16,6 +16,7 @@ import type {
|
|
|
16
16
|
CLIMeta,
|
|
17
17
|
} from './cli.types.js'
|
|
18
18
|
import type {
|
|
19
|
+
CoreConfig,
|
|
19
20
|
CoreSingletonServices,
|
|
20
21
|
CoreServices,
|
|
21
22
|
CreateWireServices,
|
|
@@ -24,7 +25,7 @@ import type {
|
|
|
24
25
|
CreateSingletonServices,
|
|
25
26
|
} from '../../types/core.types.js'
|
|
26
27
|
import type { PikkuChannel } from '../channel/channel.types.js'
|
|
27
|
-
import { unsupportedChannelRemote } from '../channel/channel-rpc.js'
|
|
28
|
+
import { unsupportedChannelRemote } from '../channel/channel-rpc.types.js'
|
|
28
29
|
import {
|
|
29
30
|
PikkuSessionService,
|
|
30
31
|
createMiddlewareSessionWireProps,
|
|
@@ -168,7 +169,24 @@ function registerCLICommands(
|
|
|
168
169
|
}
|
|
169
170
|
}
|
|
170
171
|
|
|
171
|
-
|
|
172
|
+
// Merge the command-level auth/permissions into the registered config so
|
|
173
|
+
// they are actually enforced by the function runner. They were accepted by
|
|
174
|
+
// the types but dropped here, making a command's declared access control a
|
|
175
|
+
// silent no-op. Command-level wins over the handler's own, then falls back
|
|
176
|
+
// to it.
|
|
177
|
+
const unwrapped = unwrapFunc(command)
|
|
178
|
+
const commandAuth = typeof command === 'object' ? command.auth : undefined
|
|
179
|
+
const commandPermissions =
|
|
180
|
+
typeof command === 'object' ? command.permissions : undefined
|
|
181
|
+
addFunction(
|
|
182
|
+
funcName,
|
|
183
|
+
{
|
|
184
|
+
...unwrapped,
|
|
185
|
+
auth: commandAuth ?? unwrapped.auth,
|
|
186
|
+
permissions: commandPermissions ?? unwrapped.permissions,
|
|
187
|
+
},
|
|
188
|
+
currentMeta?.packageName
|
|
189
|
+
)
|
|
172
190
|
|
|
173
191
|
if (typeof command === 'object' && command.render) {
|
|
174
192
|
if (programs[program]) {
|
|
@@ -321,7 +339,8 @@ export async function runCLICommand({
|
|
|
321
339
|
setState: (s) => {
|
|
322
340
|
cliState = s
|
|
323
341
|
},
|
|
324
|
-
|
|
342
|
+
// knowledge: decisions/internals/channel-state-accessors-are-unsound-generics-that-every-implementation-asserts.md
|
|
343
|
+
getState: () => cliState as never,
|
|
325
344
|
clearState: () => {
|
|
326
345
|
cliState = undefined
|
|
327
346
|
},
|
|
@@ -372,7 +391,8 @@ export async function runCLICommand({
|
|
|
372
391
|
if (result !== undefined && !onOutput) {
|
|
373
392
|
const commandRenderer = programData?.renderers[commandId]
|
|
374
393
|
const jsonMode =
|
|
375
|
-
(data as
|
|
394
|
+
(data as { json?: unknown; output?: unknown }).json === true ||
|
|
395
|
+
(data as { json?: unknown; output?: unknown }).output === 'json'
|
|
376
396
|
const finalRenderer: CorePikkuCLIRender<any> | undefined =
|
|
377
397
|
jsonMode && commandRenderer !== undefined
|
|
378
398
|
? defaultJSONRenderer
|
|
@@ -491,7 +511,7 @@ export async function executeCLI({
|
|
|
491
511
|
|
|
492
512
|
const config = createConfig
|
|
493
513
|
? await createConfig(new LocalVariablesService(), data)
|
|
494
|
-
: ({} as
|
|
514
|
+
: ({} as CoreConfig)
|
|
495
515
|
|
|
496
516
|
const singletonServices = await createSingletonServices(config)
|
|
497
517
|
pikkuState(null, 'package', 'singletonServices', singletonServices)
|
|
@@ -197,18 +197,6 @@ export type ValidateParameters<Params extends string, Input> =
|
|
|
197
197
|
? Params
|
|
198
198
|
: never
|
|
199
199
|
|
|
200
|
-
/**
|
|
201
|
-
* Extract output type from a Pikku function config type
|
|
202
|
-
*/
|
|
203
|
-
export type ExtractFunctionOutput<Func> =
|
|
204
|
-
Func extends CorePikkuFunctionConfig<infer FuncType, any, any>
|
|
205
|
-
? FuncType extends
|
|
206
|
-
| CorePikkuFunction<any, infer Output, any, any, any>
|
|
207
|
-
| CorePikkuFunctionSessionless<any, infer Output, any, any, any>
|
|
208
|
-
? Output
|
|
209
|
-
: never
|
|
210
|
-
: never
|
|
211
|
-
|
|
212
200
|
/**
|
|
213
201
|
* CLI command configuration that infers options from function input type.
|
|
214
202
|
* This is a helper type for creating type-safe CLI commands.
|
|
@@ -290,33 +278,6 @@ export type CLICommandShorthand<
|
|
|
290
278
|
>,
|
|
291
279
|
> = PikkuFunctionConfig
|
|
292
280
|
|
|
293
|
-
/**
|
|
294
|
-
* Command definition (either full or shorthand)
|
|
295
|
-
*/
|
|
296
|
-
export type CLICommandDefinition<
|
|
297
|
-
In,
|
|
298
|
-
Out,
|
|
299
|
-
PikkuFunctionConfig extends CorePikkuFunctionConfig<
|
|
300
|
-
| CorePikkuFunction<In, Out, any, any, any>
|
|
301
|
-
| CorePikkuFunctionSessionless<In, Out, any, any, any>
|
|
302
|
-
>,
|
|
303
|
-
PikkuPermission extends CorePikkuPermission<any, any, any>,
|
|
304
|
-
PikkuMiddleware extends CorePikkuMiddleware,
|
|
305
|
-
Options = any,
|
|
306
|
-
Subcommands extends Record<string, CoreCLICommandConfig<any, any, any>> =
|
|
307
|
-
Record<string, CoreCLICommandConfig<any, any, any>>,
|
|
308
|
-
> =
|
|
309
|
-
| CoreCLICommand<
|
|
310
|
-
In,
|
|
311
|
-
Out,
|
|
312
|
-
PikkuFunctionConfig,
|
|
313
|
-
PikkuPermission,
|
|
314
|
-
PikkuMiddleware,
|
|
315
|
-
Options,
|
|
316
|
-
Subcommands
|
|
317
|
-
>
|
|
318
|
-
| CLICommandShorthand<In, Out, PikkuFunctionConfig>
|
|
319
|
-
|
|
320
281
|
/**
|
|
321
282
|
* CLI wiring configuration
|
|
322
283
|
*/
|
|
@@ -710,5 +710,24 @@ describe('Command Parser', () => {
|
|
|
710
710
|
assert.ok(result.errors.some((e) => e.includes('Unknown option: -x')))
|
|
711
711
|
assert.deepStrictEqual(result.warnings, [])
|
|
712
712
|
})
|
|
713
|
+
describe('short-flag cluster is bounded (DoS)', () => {
|
|
714
|
+
test('a huge short-flag cluster yields a single error, not one per char', () => {
|
|
715
|
+
const huge = '-' + 'a'.repeat(200_000)
|
|
716
|
+
const result = parseCLIArguments(
|
|
717
|
+
['greet', 'Alice', huge],
|
|
718
|
+
'test-cli',
|
|
719
|
+
testMeta
|
|
720
|
+
)
|
|
721
|
+
const clusterErrors = result.errors.filter((e) =>
|
|
722
|
+
e.includes('Unknown option')
|
|
723
|
+
)
|
|
724
|
+
// Without the cap this would be ~200k errors (one per character).
|
|
725
|
+
assert.ok(
|
|
726
|
+
clusterErrors.length <= 2,
|
|
727
|
+
`expected the oversized cluster to collapse to a single error, got ${clusterErrors.length}`
|
|
728
|
+
)
|
|
729
|
+
assert.ok(result.errors.some((e) => e.includes('too long')))
|
|
730
|
+
})
|
|
731
|
+
})
|
|
713
732
|
})
|
|
714
733
|
})
|
|
@@ -86,6 +86,15 @@ export interface ParsedCommand {
|
|
|
86
86
|
warnings: string[]
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
/**
|
|
90
|
+
* A real short-flag cluster is a handful of characters (`-abc`). Anything past
|
|
91
|
+
* this is treated as a single malformed token rather than scanned per
|
|
92
|
+
* character — the parser runs over untrusted CLI-channel frames, and a
|
|
93
|
+
* multi-megabyte `-aaaa…` would otherwise be O(length) work that also pushed
|
|
94
|
+
* one error per character.
|
|
95
|
+
*/
|
|
96
|
+
const MAX_SHORT_FLAG_CLUSTER = 64
|
|
97
|
+
|
|
89
98
|
export function parseCLIArguments(
|
|
90
99
|
args: string[],
|
|
91
100
|
programName: string,
|
|
@@ -238,6 +247,13 @@ export function parseCLIArguments(
|
|
|
238
247
|
}
|
|
239
248
|
}
|
|
240
249
|
} else if (arg.startsWith('-') && arg.length > 1) {
|
|
250
|
+
if (arg.length > MAX_SHORT_FLAG_CLUSTER) {
|
|
251
|
+
result.errors.push(
|
|
252
|
+
`Unknown option: ${arg.slice(0, MAX_SHORT_FLAG_CLUSTER)}… (too long)`
|
|
253
|
+
)
|
|
254
|
+
currentIndex++
|
|
255
|
+
continue
|
|
256
|
+
}
|
|
241
257
|
for (let i = 1; i < arg.length; i++) {
|
|
242
258
|
const shortFlag = arg[i]
|
|
243
259
|
|
|
@@ -354,7 +370,7 @@ function parseOptionValue(value: string, optionDef?: CLIOption): any {
|
|
|
354
370
|
return parseFloat(value)
|
|
355
371
|
}
|
|
356
372
|
|
|
357
|
-
if (optionDef.choices && !optionDef.choices.includes(value as
|
|
373
|
+
if (optionDef.choices && !optionDef.choices.includes(value as never)) {
|
|
358
374
|
// Deliberately not an error here — applyOptionDefaults reports bad choices.
|
|
359
375
|
return value
|
|
360
376
|
}
|
|
@@ -2,7 +2,6 @@ export { defineCredential } from './define-credential.js'
|
|
|
2
2
|
export { validateAndBuildCredentialDefinitionsMeta } from './validate-credential-definitions.js'
|
|
3
3
|
export type {
|
|
4
4
|
CoreCredential,
|
|
5
|
-
CredentialDefinitionMeta,
|
|
6
5
|
CredentialDefinitionsMeta,
|
|
7
6
|
CredentialDefinitions,
|
|
8
7
|
} from './credential.types.js'
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { describe, test } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
|
|
4
|
+
import { pikkuState, resetPikkuState } from '../../pikku-state.js'
|
|
5
|
+
import { wireGateway } from './gateway-runner.js'
|
|
6
|
+
|
|
7
|
+
const wireWebsocketGateway = (name: string) => {
|
|
8
|
+
resetPikkuState()
|
|
9
|
+
wireGateway({
|
|
10
|
+
name,
|
|
11
|
+
type: 'websocket',
|
|
12
|
+
route: `/${name}`,
|
|
13
|
+
adapter: { name: 'test', parse: () => null, send: async () => {} },
|
|
14
|
+
func: { func: async () => undefined },
|
|
15
|
+
} as any)
|
|
16
|
+
return pikkuState(null, 'channel', 'meta')[name]!
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
describe('a gateway-wired websocket channel writes complete channel meta', () => {
|
|
20
|
+
test('the fields every channel reader indexes are present', () => {
|
|
21
|
+
const meta = wireWebsocketGateway('chatGateway')
|
|
22
|
+
|
|
23
|
+
// channel-handler.ts indexes messageWirings without a guard, and the
|
|
24
|
+
// serverless and local runners read disconnect directly.
|
|
25
|
+
assert.deepEqual(
|
|
26
|
+
meta.messageWirings,
|
|
27
|
+
{},
|
|
28
|
+
'messageWirings must be an object — channel-handler indexes it unguarded'
|
|
29
|
+
)
|
|
30
|
+
assert.equal(meta.disconnect, null)
|
|
31
|
+
assert.equal(meta.input, null)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
test('it is marked as gateway-wired', () => {
|
|
35
|
+
assert.equal(wireWebsocketGateway('flagged').gateway, true)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
test('connect and message point at the generated handlers', () => {
|
|
39
|
+
const meta = wireWebsocketGateway('handlers')
|
|
40
|
+
|
|
41
|
+
assert.equal(meta.connect?.pikkuFuncId, 'gateway__handlers__connect')
|
|
42
|
+
assert.equal(meta.message?.pikkuFuncId, 'gateway__handlers__message')
|
|
43
|
+
})
|
|
44
|
+
})
|
|
@@ -3,6 +3,7 @@ import { NotFoundError, UnauthorizedError } from '../../errors/errors.js'
|
|
|
3
3
|
import { addFunction, runPikkuFunc } from '../../function/function-runner.js'
|
|
4
4
|
import { runMiddleware } from '../../middleware-runner.js'
|
|
5
5
|
import { httpRouter } from '../http/routers/http-router.js'
|
|
6
|
+
import type { CoreHTTPFunctionWiring } from '../http/http.types.js'
|
|
6
7
|
import type {
|
|
7
8
|
CoreGateway,
|
|
8
9
|
GatewayAdapter,
|
|
@@ -50,7 +51,7 @@ const registerGatewayHandler = (config: CoreGateway): string => {
|
|
|
50
51
|
outputSchemaName: declared?.outputSchemaName ?? null,
|
|
51
52
|
sessionless: declared?.sessionless ?? true,
|
|
52
53
|
}
|
|
53
|
-
addFunction(funcId, config.func
|
|
54
|
+
addFunction(funcId, config.func)
|
|
54
55
|
return funcId
|
|
55
56
|
}
|
|
56
57
|
|
|
@@ -99,7 +100,7 @@ export const wireGateway = (config: CoreGateway): void => {
|
|
|
99
100
|
break
|
|
100
101
|
default:
|
|
101
102
|
throw new Error(
|
|
102
|
-
`Unknown gateway type '${
|
|
103
|
+
`Unknown gateway type '${config.type}' for gateway '${config.name}'`
|
|
103
104
|
)
|
|
104
105
|
}
|
|
105
106
|
}
|
|
@@ -118,7 +119,7 @@ const wireWebhookGateway = (config: CoreGateway): void => {
|
|
|
118
119
|
func: createWebhookPostHandler(config),
|
|
119
120
|
}
|
|
120
121
|
|
|
121
|
-
addFunction(postFuncId, postHandler
|
|
122
|
+
addFunction(postFuncId, postHandler)
|
|
122
123
|
|
|
123
124
|
if (!routes.has('post')) {
|
|
124
125
|
routes.set('post', new Map())
|
|
@@ -128,7 +129,10 @@ const wireWebhookGateway = (config: CoreGateway): void => {
|
|
|
128
129
|
route,
|
|
129
130
|
func: postHandler,
|
|
130
131
|
auth: false,
|
|
131
|
-
|
|
132
|
+
// A gateway handler takes (services, data, wire) rather than a pikku
|
|
133
|
+
// function's shape, so it never matches CorePikkuFunctionConfig. It is only
|
|
134
|
+
// ever invoked through runPikkuFunc, which is what makes that safe.
|
|
135
|
+
} as unknown as CoreHTTPFunctionWiring<unknown, unknown, string>)
|
|
132
136
|
|
|
133
137
|
// knowledge: decisions/internals/gateway-adapters-resolve-lazily-and-are-promise-cached.md
|
|
134
138
|
if (typeof adapter === 'function' || adapter.verifyWebhook) {
|
|
@@ -139,7 +143,7 @@ const wireWebhookGateway = (config: CoreGateway): void => {
|
|
|
139
143
|
func: createWebhookVerifyHandler(config),
|
|
140
144
|
}
|
|
141
145
|
|
|
142
|
-
addFunction(verifyFuncId, verifyHandler
|
|
146
|
+
addFunction(verifyFuncId, verifyHandler)
|
|
143
147
|
|
|
144
148
|
if (!routes.has('get')) {
|
|
145
149
|
routes.set('get', new Map())
|
|
@@ -151,7 +155,7 @@ const wireWebhookGateway = (config: CoreGateway): void => {
|
|
|
151
155
|
auth: false,
|
|
152
156
|
// knowledge: decisions/internals/gateway-webhook-challenges-echo-bytes-not-json.md
|
|
153
157
|
returnsJSON: false,
|
|
154
|
-
} as
|
|
158
|
+
} as unknown as CoreHTTPFunctionWiring<unknown, unknown, string>)
|
|
155
159
|
}
|
|
156
160
|
|
|
157
161
|
httpRouter.reset()
|
|
@@ -187,17 +191,17 @@ const createWebhookPostHandler = (config: CoreGateway) => {
|
|
|
187
191
|
platform: adapter.name,
|
|
188
192
|
send: (msg: GatewayOutboundMessage) => adapter.send(parsed.senderId, msg),
|
|
189
193
|
}
|
|
190
|
-
|
|
194
|
+
wire.gateway = gateway
|
|
191
195
|
|
|
192
196
|
// Gateway middleware runs outside the gate so it can establish the session the gate checks.
|
|
193
197
|
const invoke = async () => {
|
|
194
|
-
await bridgeMiddlewareSession(wire
|
|
198
|
+
await bridgeMiddlewareSession(wire)
|
|
195
199
|
return await runPikkuFunc('gateway', name, handlerFuncId, {
|
|
196
200
|
singletonServices: services,
|
|
197
201
|
data: () => parsed,
|
|
198
202
|
auth: config.auth,
|
|
199
203
|
inheritedMiddleware,
|
|
200
|
-
wire
|
|
204
|
+
wire,
|
|
201
205
|
})
|
|
202
206
|
}
|
|
203
207
|
|
|
@@ -275,9 +279,12 @@ const wireWebsocketGateway = (config: CoreGateway): void => {
|
|
|
275
279
|
name,
|
|
276
280
|
route,
|
|
277
281
|
gateway: true,
|
|
282
|
+
input: null,
|
|
278
283
|
connect: { pikkuFuncId: connectFuncId },
|
|
284
|
+
disconnect: null,
|
|
279
285
|
message: { pikkuFuncId: messageFuncId },
|
|
280
|
-
|
|
286
|
+
messageWirings: {},
|
|
287
|
+
}
|
|
281
288
|
|
|
282
289
|
const userMiddleware = config.middleware as CorePikkuMiddleware[] | undefined
|
|
283
290
|
const handlerFuncId = registerGatewayHandler(config)
|
|
@@ -287,7 +294,7 @@ const wireWebsocketGateway = (config: CoreGateway): void => {
|
|
|
287
294
|
auth: false,
|
|
288
295
|
func: async (services: any, _data: unknown, wire: PikkuWire) => {
|
|
289
296
|
const adapter = await resolveGatewayAdapter(config, services)
|
|
290
|
-
|
|
297
|
+
wire.gateway = {
|
|
291
298
|
gatewayName: name,
|
|
292
299
|
senderId: '',
|
|
293
300
|
platform: adapter.name,
|
|
@@ -296,7 +303,7 @@ const wireWebsocketGateway = (config: CoreGateway): void => {
|
|
|
296
303
|
},
|
|
297
304
|
} satisfies PikkuGateway
|
|
298
305
|
},
|
|
299
|
-
}
|
|
306
|
+
})
|
|
300
307
|
|
|
301
308
|
addFunction(messageFuncId, {
|
|
302
309
|
auth: false,
|
|
@@ -313,16 +320,16 @@ const wireWebsocketGateway = (config: CoreGateway): void => {
|
|
|
313
320
|
wire.channel?.send(msg)
|
|
314
321
|
},
|
|
315
322
|
}
|
|
316
|
-
|
|
323
|
+
wire.gateway = gateway
|
|
317
324
|
|
|
318
325
|
const invoke = async () => {
|
|
319
|
-
await bridgeMiddlewareSession(wire
|
|
326
|
+
await bridgeMiddlewareSession(wire)
|
|
320
327
|
return await runPikkuFunc('gateway', name, handlerFuncId, {
|
|
321
328
|
singletonServices: services,
|
|
322
329
|
data: () => parsed,
|
|
323
330
|
auth: config.auth,
|
|
324
331
|
inheritedMiddleware,
|
|
325
|
-
wire
|
|
332
|
+
wire,
|
|
326
333
|
})
|
|
327
334
|
}
|
|
328
335
|
|
|
@@ -337,7 +344,7 @@ const wireWebsocketGateway = (config: CoreGateway): void => {
|
|
|
337
344
|
wire.channel?.send(result)
|
|
338
345
|
}
|
|
339
346
|
},
|
|
340
|
-
}
|
|
347
|
+
})
|
|
341
348
|
|
|
342
349
|
// knowledge: decisions/internals/gateway-wiring-is-a-meta-wiring-over-http-and-channels.md
|
|
343
350
|
channels.set(name, {
|
|
@@ -346,7 +353,7 @@ const wireWebsocketGateway = (config: CoreGateway): void => {
|
|
|
346
353
|
auth: false,
|
|
347
354
|
onConnect: { func: async () => {} },
|
|
348
355
|
onMessage: { func: async () => {} },
|
|
349
|
-
}
|
|
356
|
+
})
|
|
350
357
|
|
|
351
358
|
httpRouter.reset()
|
|
352
359
|
}
|
|
@@ -377,7 +384,7 @@ export const createListenerMessageHandler = (
|
|
|
377
384
|
platform: adapter.name,
|
|
378
385
|
send: (msg: GatewayOutboundMessage) => adapter.send(parsed.senderId, msg),
|
|
379
386
|
}
|
|
380
|
-
|
|
387
|
+
wire.gateway = gateway
|
|
381
388
|
|
|
382
389
|
const invoke = async () => {
|
|
383
390
|
await bridgeMiddlewareSession(wire)
|
|
@@ -390,10 +397,11 @@ export const createListenerMessageHandler = (
|
|
|
390
397
|
})
|
|
391
398
|
}
|
|
392
399
|
|
|
400
|
+
// knowledge: decisions/internals/gateway-listener-middleware-runs-without-an-rpc-on-the-wire.md
|
|
393
401
|
const result: any = userMiddleware?.length
|
|
394
402
|
? await runMiddleware(
|
|
395
403
|
singletonServices,
|
|
396
|
-
wire as
|
|
404
|
+
wire as PikkuWire,
|
|
397
405
|
userMiddleware,
|
|
398
406
|
invoke
|
|
399
407
|
)
|
|
@@ -6,13 +6,10 @@ export {
|
|
|
6
6
|
export type {
|
|
7
7
|
GatewayAdapter,
|
|
8
8
|
GatewayAdapterFactory,
|
|
9
|
-
GatewayAttachment,
|
|
10
9
|
GatewayInboundMessage,
|
|
11
10
|
GatewayOutboundMessage,
|
|
12
|
-
GatewayMeta,
|
|
13
11
|
GatewaysMeta,
|
|
14
12
|
GatewayTransportType,
|
|
15
13
|
CoreGateway,
|
|
16
|
-
PikkuGateway,
|
|
17
14
|
WebhookVerificationResult,
|
|
18
15
|
} from './gateway.types.js'
|