@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
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
combineChannelMiddleware,
|
|
5
5
|
wrapChannelWithMiddleware,
|
|
6
6
|
} from '../wirings/channel/channel-middleware-runner.js'
|
|
7
|
-
import { runPermissions } from '../permissions.js'
|
|
7
|
+
import { runPermissions, type PermissionWire } from '../permissions.js'
|
|
8
8
|
import { withoutSecrets } from '../services/secretless.js'
|
|
9
9
|
import { pikkuState } from '../pikku-state.js'
|
|
10
10
|
import {
|
|
@@ -177,8 +177,6 @@ export const runPikkuFunc = async <In = any, Out = any>(
|
|
|
177
177
|
|
|
178
178
|
const resolvedFunctionId = funcMeta.pikkuFuncId ?? funcName
|
|
179
179
|
|
|
180
|
-
const keepsSecrets = funcMeta.secretBroker === true
|
|
181
|
-
|
|
182
180
|
const resolvedSingletonServices = packageName
|
|
183
181
|
? await getOrCreatePackageSingletonServices(
|
|
184
182
|
packageName,
|
|
@@ -248,6 +246,28 @@ export const runPikkuFunc = async <In = any, Out = any>(
|
|
|
248
246
|
invocationWire,
|
|
249
247
|
'rpc'
|
|
250
248
|
)
|
|
249
|
+
|
|
250
|
+
// knowledge: decisions/internals/core-function-runner-restores-the-wire-fields-it-overwrites.md
|
|
251
|
+
const restoreInvocationWire = () => {
|
|
252
|
+
if (previousRpcDescriptor) {
|
|
253
|
+
Object.defineProperty(invocationWire, 'rpc', previousRpcDescriptor)
|
|
254
|
+
}
|
|
255
|
+
restoreField('functionId', previousFunctionId)
|
|
256
|
+
restoreField('audit', previousAudit)
|
|
257
|
+
restoreField('addonNamespace', previousAddonNamespace)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function restoreField<K extends 'functionId' | 'audit' | 'addonNamespace'>(
|
|
261
|
+
key: K,
|
|
262
|
+
previous: PikkuWire[K]
|
|
263
|
+
) {
|
|
264
|
+
if (previous === undefined) {
|
|
265
|
+
delete invocationWire[key]
|
|
266
|
+
} else {
|
|
267
|
+
invocationWire[key] = previous
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
251
271
|
invocationWire.functionId = resolvedFunctionId
|
|
252
272
|
invocationWire.audit = resolvedAuditConfig
|
|
253
273
|
// Track which addon instance is executing so intra-addon sibling calls
|
|
@@ -294,7 +314,7 @@ export const runPikkuFunc = async <In = any, Out = any>(
|
|
|
294
314
|
}
|
|
295
315
|
}
|
|
296
316
|
|
|
297
|
-
if (
|
|
317
|
+
if (session?.readonly && !funcMeta.readonly) {
|
|
298
318
|
throw new ReadonlySessionError()
|
|
299
319
|
}
|
|
300
320
|
|
|
@@ -341,13 +361,12 @@ export const runPikkuFunc = async <In = any, Out = any>(
|
|
|
341
361
|
|
|
342
362
|
await runPermissions({
|
|
343
363
|
funcPermissions: funcConfig.permissions,
|
|
344
|
-
services:
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
wire: invocationWire as any,
|
|
364
|
+
services: withoutSecrets(
|
|
365
|
+
resolvedSingletonServices,
|
|
366
|
+
'a permission'
|
|
367
|
+
) as CoreSingletonServices,
|
|
368
|
+
// knowledge: decisions/security/a-permission-gets-a-wire-it-cannot-reply-on.md
|
|
369
|
+
wire: invocationWire as PermissionWire,
|
|
351
370
|
data: actualData,
|
|
352
371
|
packageName,
|
|
353
372
|
})
|
|
@@ -397,7 +416,7 @@ export const runPikkuFunc = async <In = any, Out = any>(
|
|
|
397
416
|
enumerable: true,
|
|
398
417
|
})
|
|
399
418
|
return await funcConfig.func(
|
|
400
|
-
|
|
419
|
+
withoutSecrets(services, 'a pikku function'),
|
|
401
420
|
actualData,
|
|
402
421
|
invocationWire
|
|
403
422
|
)
|
|
@@ -435,47 +454,13 @@ export const runPikkuFunc = async <In = any, Out = any>(
|
|
|
435
454
|
executeFunction
|
|
436
455
|
)) as Out
|
|
437
456
|
} finally {
|
|
438
|
-
|
|
439
|
-
Object.defineProperty(invocationWire, 'rpc', previousRpcDescriptor)
|
|
440
|
-
}
|
|
441
|
-
if (previousFunctionId === undefined) {
|
|
442
|
-
delete (invocationWire as any).functionId
|
|
443
|
-
} else {
|
|
444
|
-
invocationWire.functionId = previousFunctionId
|
|
445
|
-
}
|
|
446
|
-
if (previousAudit === undefined) {
|
|
447
|
-
delete (invocationWire as any).audit
|
|
448
|
-
} else {
|
|
449
|
-
invocationWire.audit = previousAudit
|
|
450
|
-
}
|
|
451
|
-
if (previousAddonNamespace === undefined) {
|
|
452
|
-
delete (invocationWire as any).addonNamespace
|
|
453
|
-
} else {
|
|
454
|
-
invocationWire.addonNamespace = previousAddonNamespace
|
|
455
|
-
}
|
|
457
|
+
restoreInvocationWire()
|
|
456
458
|
}
|
|
457
459
|
}
|
|
458
460
|
|
|
459
461
|
try {
|
|
460
462
|
return (await executeFunction()) as Out
|
|
461
463
|
} finally {
|
|
462
|
-
|
|
463
|
-
Object.defineProperty(invocationWire, 'rpc', previousRpcDescriptor)
|
|
464
|
-
}
|
|
465
|
-
if (previousFunctionId === undefined) {
|
|
466
|
-
delete (invocationWire as any).functionId
|
|
467
|
-
} else {
|
|
468
|
-
invocationWire.functionId = previousFunctionId
|
|
469
|
-
}
|
|
470
|
-
if (previousAudit === undefined) {
|
|
471
|
-
delete (invocationWire as any).audit
|
|
472
|
-
} else {
|
|
473
|
-
invocationWire.audit = previousAudit
|
|
474
|
-
}
|
|
475
|
-
if (previousAddonNamespace === undefined) {
|
|
476
|
-
delete (invocationWire as any).addonNamespace
|
|
477
|
-
} else {
|
|
478
|
-
invocationWire.addonNamespace = previousAddonNamespace
|
|
479
|
-
}
|
|
464
|
+
restoreInvocationWire()
|
|
480
465
|
}
|
|
481
466
|
}
|
|
@@ -14,12 +14,6 @@ import type { CoreNodeConfig } from '../wirings/node/node.types.js'
|
|
|
14
14
|
import type { ScenarioSurface } from '../wirings/workflow/scenario-step.types.js'
|
|
15
15
|
import type { Safe } from '../secret-value.js'
|
|
16
16
|
|
|
17
|
-
/**
|
|
18
|
-
* @deprecated Use StandardSchemaV1 from @standard-schema/spec instead.
|
|
19
|
-
* This alias exists only for backward compatibility with generated code.
|
|
20
|
-
*/
|
|
21
|
-
export type ZodLike<T = any> = StandardSchemaV1<T, T>
|
|
22
|
-
|
|
23
17
|
export type CorePikkuFunction<
|
|
24
18
|
In,
|
|
25
19
|
Out,
|
|
@@ -141,6 +135,14 @@ export type CorePikkuAuthConfig<
|
|
|
141
135
|
description?: string
|
|
142
136
|
}
|
|
143
137
|
|
|
138
|
+
/**
|
|
139
|
+
* Marks a permission produced by `pikkuAuth`, so agent tool filtering can tell a
|
|
140
|
+
* session check apart from an ordinary permission.
|
|
141
|
+
*
|
|
142
|
+
* knowledge: decisions/security/permission-auth-filtering-requires-live-permission-functions.md
|
|
143
|
+
*/
|
|
144
|
+
export type AuthBranded = { __pikkuAuth?: true }
|
|
145
|
+
|
|
144
146
|
export const pikkuAuth = <
|
|
145
147
|
Services extends CoreSecretlessSingletonServices =
|
|
146
148
|
SecretlessServices<CoreServices>,
|
|
@@ -151,13 +153,17 @@ export const pikkuAuth = <
|
|
|
151
153
|
| CorePikkuAuthConfig<Services, Session>
|
|
152
154
|
): CorePikkuPermission<any, Services, any> => {
|
|
153
155
|
const fn = typeof auth === 'function' ? auth : auth.func
|
|
154
|
-
const wrapper
|
|
156
|
+
const wrapper: CorePikkuPermission<any, Services, any> & AuthBranded = async (
|
|
157
|
+
services: Services,
|
|
158
|
+
_data: any,
|
|
159
|
+
wire: any
|
|
160
|
+
) => {
|
|
155
161
|
const session = wire.session
|
|
156
162
|
if (!session) return false
|
|
157
163
|
return fn(services, session as Session)
|
|
158
164
|
}
|
|
159
|
-
|
|
160
|
-
return wrapper
|
|
165
|
+
wrapper.__pikkuAuth = true
|
|
166
|
+
return wrapper
|
|
161
167
|
}
|
|
162
168
|
|
|
163
169
|
export type CorePermissionGroup<PikkuPermission = CorePikkuPermission<any>> =
|
package/src/function/index.ts
CHANGED
package/src/handle-error.ts
CHANGED
|
@@ -33,7 +33,7 @@ export const handleHTTPError = (
|
|
|
33
33
|
e.message !== 'An error occurred'
|
|
34
34
|
? e.message
|
|
35
35
|
: errorResponse.message,
|
|
36
|
-
payload: clientFacing ? (e as
|
|
36
|
+
payload: clientFacing ? (e as { payload?: unknown }).payload : undefined,
|
|
37
37
|
errorId: traceId,
|
|
38
38
|
})
|
|
39
39
|
|
package/src/index.ts
CHANGED
|
@@ -17,12 +17,10 @@ export type {
|
|
|
17
17
|
CreateConfig,
|
|
18
18
|
ServerLifecycle,
|
|
19
19
|
FunctionMeta,
|
|
20
|
-
FunctionRuntimeMeta,
|
|
21
20
|
FunctionServicesMeta,
|
|
22
21
|
FunctionWiresMeta,
|
|
23
22
|
FunctionsMeta,
|
|
24
23
|
FunctionsRuntimeMeta,
|
|
25
|
-
JSONPrimitive,
|
|
26
24
|
JSONValue,
|
|
27
25
|
MakeRequired,
|
|
28
26
|
MiddlewareMetadata,
|
|
@@ -43,7 +41,6 @@ export type {
|
|
|
43
41
|
SecuritySeverity,
|
|
44
42
|
SecurityUpdateLevel,
|
|
45
43
|
SerializedError,
|
|
46
|
-
WireServices,
|
|
47
44
|
} from './types/core.types.js'
|
|
48
45
|
export {
|
|
49
46
|
pikkuAIMiddleware,
|
|
@@ -57,13 +54,11 @@ export type {
|
|
|
57
54
|
CorePikkuAuthConfig,
|
|
58
55
|
CorePikkuFunction,
|
|
59
56
|
CorePikkuFunctionConfig,
|
|
60
|
-
CorePikkuFunctionHook,
|
|
61
57
|
CorePikkuPermission,
|
|
62
58
|
CorePikkuPermissionConfig,
|
|
63
59
|
CorePikkuPermissionFactory,
|
|
64
60
|
CorePikkuApprovalDescription,
|
|
65
61
|
CorePermissionGroup,
|
|
66
|
-
ZodLike,
|
|
67
62
|
} from './function/functions.types.js'
|
|
68
63
|
export {
|
|
69
64
|
pikkuAuth,
|
|
@@ -71,14 +66,13 @@ export {
|
|
|
71
66
|
pikkuPermissionFactory,
|
|
72
67
|
pikkuApprovalDescription,
|
|
73
68
|
} from './function/functions.types.js'
|
|
74
|
-
export {
|
|
69
|
+
export { getAllFunctionNames } from './function/index.js'
|
|
75
70
|
export type {
|
|
76
71
|
ListInput,
|
|
77
72
|
ListOutput,
|
|
78
73
|
Filter,
|
|
79
|
-
LeafFilter,
|
|
80
|
-
LeafValue,
|
|
81
74
|
} from './function/list.types.js'
|
|
75
|
+
export { pikkuCLIRender } from './wirings/cli/cli-runner.js'
|
|
82
76
|
export { PikkuRequest } from './pikku-request.js'
|
|
83
77
|
export {
|
|
84
78
|
getRelativeTimeOffsetFromNow,
|
|
@@ -90,28 +84,16 @@ export {
|
|
|
90
84
|
isVersionedId,
|
|
91
85
|
parseVersionedId,
|
|
92
86
|
} from './version.js'
|
|
93
|
-
export { runPikkuFunc } from './function/function-runner.js'
|
|
94
87
|
export {
|
|
95
88
|
AbandonedError,
|
|
96
|
-
beginChanges,
|
|
97
|
-
getAbortScope,
|
|
98
|
-
runInAbortScope,
|
|
99
89
|
type AbortScope,
|
|
100
90
|
} from './function/abort-scope.js'
|
|
101
|
-
export { runCLICommand, pikkuCLIRender } from './wirings/cli/cli-runner.js'
|
|
102
91
|
export { fetch } from './wirings/http/http-runner.js'
|
|
103
|
-
export {
|
|
104
|
-
runMCPTool,
|
|
105
|
-
runMCPResource,
|
|
106
|
-
runMCPPrompt,
|
|
107
|
-
} from './wirings/mcp/mcp-runner.js'
|
|
108
92
|
export type {
|
|
109
93
|
MCPToolResponse,
|
|
110
94
|
MCPResourceResponse,
|
|
111
95
|
MCPPromptResponse,
|
|
112
96
|
} from './wirings/mcp/mcp.types.js'
|
|
113
|
-
export { runQueueJob } from './wirings/queue/queue-runner.js'
|
|
114
|
-
export { runScheduledTask } from './wirings/scheduler/scheduler-runner.js'
|
|
115
97
|
export {
|
|
116
98
|
AIProviderAuthError,
|
|
117
99
|
AIProviderNotConfiguredError,
|
|
@@ -161,7 +143,6 @@ export type { QueueService } from './wirings/queue/queue.types.js'
|
|
|
161
143
|
export type { JWTService } from './services/jwt-service.js'
|
|
162
144
|
export type {
|
|
163
145
|
EmailService,
|
|
164
|
-
EmailTemplateReference,
|
|
165
146
|
SendEmailInput,
|
|
166
147
|
SendEmailResult,
|
|
167
148
|
SendHTMLEmailInput,
|
|
@@ -197,8 +178,6 @@ export type { SessionService } from './services/user-session-service.js'
|
|
|
197
178
|
export {
|
|
198
179
|
NoopAuditService,
|
|
199
180
|
createInvocationAudit,
|
|
200
|
-
resolveAuditConfig,
|
|
201
|
-
resolveAuditUserIdentityFromWire,
|
|
202
181
|
} from './services/audit-service.js'
|
|
203
182
|
export type {
|
|
204
183
|
AuditConfig,
|
|
@@ -207,31 +186,14 @@ export type {
|
|
|
207
186
|
AuditEventBatch,
|
|
208
187
|
AuditFacets,
|
|
209
188
|
AuditLog,
|
|
210
|
-
AuditLogWriteInput,
|
|
211
|
-
AuditOutcome,
|
|
212
189
|
AuditQuery,
|
|
213
190
|
AuditQueryResult,
|
|
214
191
|
AuditService,
|
|
215
|
-
AuditSource,
|
|
216
192
|
AuditUserIdentity,
|
|
217
193
|
ResolvedAuditConfig,
|
|
218
194
|
} from './services/audit-service.js'
|
|
219
195
|
export type {
|
|
220
196
|
AIAgentRunnerService,
|
|
221
|
-
AIEmbedManyParams,
|
|
222
|
-
AIEmbedManyResult,
|
|
223
|
-
AIEmbedParams,
|
|
224
|
-
AIEmbedResult,
|
|
225
|
-
AIGenerateImageParams,
|
|
226
|
-
AIGenerateImagePrompt,
|
|
227
|
-
AIGenerateImageResult,
|
|
228
|
-
AIGenerateSpeechParams,
|
|
229
|
-
AIGenerateSpeechResult,
|
|
230
|
-
AIProviderOptions,
|
|
231
|
-
AIRerankParams,
|
|
232
|
-
AIRerankResult,
|
|
233
|
-
AITranscriptionParams,
|
|
234
|
-
AITranscriptionResult,
|
|
235
197
|
} from './services/ai-agent-runner-service.js'
|
|
236
198
|
export type { AIEmbeddingService } from './services/ai-embedding-service.js'
|
|
237
199
|
export type { AIRunStateService } from './services/ai-run-state-service.js'
|
|
@@ -239,8 +201,6 @@ export type { AIStorageService } from './services/ai-storage-service.js'
|
|
|
239
201
|
export type {
|
|
240
202
|
EmailsMeta,
|
|
241
203
|
EmailTemplateMeta,
|
|
242
|
-
EmailTemplateLocaleMeta,
|
|
243
|
-
EmailTemplateAssets,
|
|
244
204
|
MetaService,
|
|
245
205
|
} from './services/meta-service.js'
|
|
246
206
|
export type { HTTPMethod } from './wirings/http/http.types.js'
|
|
@@ -254,12 +214,7 @@ export type {
|
|
|
254
214
|
RemoteAddonAuth,
|
|
255
215
|
} from './wirings/rpc/wire-remote-addon.js'
|
|
256
216
|
export type { PikkuPackageState } from './types/state.types.js'
|
|
257
|
-
export {
|
|
258
|
-
runMiddleware,
|
|
259
|
-
addTagMiddleware,
|
|
260
|
-
addTagMiddleware as addMiddleware,
|
|
261
|
-
addGlobalMiddleware,
|
|
262
|
-
} from './middleware-runner.js'
|
|
217
|
+
export { runMiddleware, addTagMiddleware } from './middleware-runner.js'
|
|
263
218
|
export { addGlobalPermission, checkAuthPermissions } from './permissions.js'
|
|
264
219
|
export { hasScopes, verifyScopes } from './scopes.js'
|
|
265
220
|
export {
|
|
@@ -267,11 +222,6 @@ export {
|
|
|
267
222
|
stopSingletonServices,
|
|
268
223
|
pikkuServerLifecycle,
|
|
269
224
|
} from './utils.js'
|
|
270
|
-
export {
|
|
271
|
-
getSingletonServices,
|
|
272
|
-
getCreateWireServices,
|
|
273
|
-
setSingletonServices,
|
|
274
|
-
} from './pikku-state.js'
|
|
275
225
|
export { clearPikkuRuntimeState } from './test-utils.js'
|
|
276
226
|
export {
|
|
277
227
|
type ScheduledTaskInfo,
|
|
@@ -285,7 +235,6 @@ export type {
|
|
|
285
235
|
Secret,
|
|
286
236
|
Classification,
|
|
287
237
|
AnonymizeStrategy,
|
|
288
|
-
ColumnClassification,
|
|
289
238
|
ClassificationManifest,
|
|
290
239
|
ColumnForm,
|
|
291
240
|
WrappedValue,
|
|
@@ -295,9 +244,6 @@ export type {
|
|
|
295
244
|
|
|
296
245
|
export {
|
|
297
246
|
hashToken,
|
|
298
|
-
unsafeAsWrapped,
|
|
299
|
-
unsafeAsSealed,
|
|
300
|
-
unsafeAsHashed,
|
|
301
247
|
} from './column-form.js'
|
|
302
248
|
|
|
303
249
|
export type { SecretValue, Safe } from './secret-value.js'
|
|
@@ -131,6 +131,56 @@ describe('authCookie middleware', () => {
|
|
|
131
131
|
assert(setCookies[0].options.expires instanceof Date)
|
|
132
132
|
})
|
|
133
133
|
|
|
134
|
+
test('clears the cookie on logout instead of re-minting a credential', async () => {
|
|
135
|
+
const SessionService = new PikkuSessionService<CoreUserSession>()
|
|
136
|
+
let encodeCalled = false
|
|
137
|
+
const jwtService = {
|
|
138
|
+
// A JWT of an absent session still decodes to a truthy {iat,exp} the
|
|
139
|
+
// runner accepts — so encode must never be called on logout.
|
|
140
|
+
encode: async () => {
|
|
141
|
+
encodeCalled = true
|
|
142
|
+
return 'reminted-jwt'
|
|
143
|
+
},
|
|
144
|
+
decode: async () => ({ userId: 'user123' }),
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const middleware = authCookie({
|
|
148
|
+
name: 'session',
|
|
149
|
+
expiresIn: { value: 30, unit: 'day' },
|
|
150
|
+
options: { httpOnly: true },
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
const mockResponse = createMockHTTPResponse()
|
|
154
|
+
|
|
155
|
+
await middleware(
|
|
156
|
+
{ jwt: jwtService, logger: createMockLogger() } as any,
|
|
157
|
+
{
|
|
158
|
+
...createMiddlewareSessionWireProps(SessionService),
|
|
159
|
+
http: {
|
|
160
|
+
request: createMockHTTPRequest({ session: 'existing-jwt' }),
|
|
161
|
+
response: mockResponse,
|
|
162
|
+
},
|
|
163
|
+
} as any,
|
|
164
|
+
async () => {
|
|
165
|
+
// The logout handler clears the session.
|
|
166
|
+
SessionService.clear()
|
|
167
|
+
}
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
const setCookies = mockResponse.getCookies()
|
|
171
|
+
assert.equal(setCookies.length, 1, 'a clearing cookie must be written')
|
|
172
|
+
const cleared = setCookies[0]!
|
|
173
|
+
assert.equal(cleared.name, 'session')
|
|
174
|
+
assert.equal(cleared.value, '', 'the cookie value must be empty')
|
|
175
|
+
assert.equal(cleared.options.maxAge, 0)
|
|
176
|
+
assert.ok(
|
|
177
|
+
cleared.options.expires instanceof Date &&
|
|
178
|
+
cleared.options.expires.getTime() === 0,
|
|
179
|
+
'the cookie must expire at the epoch'
|
|
180
|
+
)
|
|
181
|
+
assert.equal(encodeCalled, false, 'must not sign an absent session')
|
|
182
|
+
})
|
|
183
|
+
|
|
134
184
|
test('should not set cookie when session does not change', async () => {
|
|
135
185
|
const mockUserSession: CoreUserSession = { userId: 'user789' }
|
|
136
186
|
const SessionService = new PikkuSessionService<CoreUserSession>()
|
|
@@ -7,6 +7,27 @@ import { getRelativeTimeOffsetFromNow } from '../time-utils.js'
|
|
|
7
7
|
* Reads a JWT session from a cookie, and re-issues the cookie after the
|
|
8
8
|
* request whenever the session changed (e.g. after login).
|
|
9
9
|
*/
|
|
10
|
+
/** Standard JWT registered claims — present on a token even with no session. */
|
|
11
|
+
const JWT_REGISTERED_CLAIMS = new Set([
|
|
12
|
+
'iat',
|
|
13
|
+
'exp',
|
|
14
|
+
'nbf',
|
|
15
|
+
'iss',
|
|
16
|
+
'aud',
|
|
17
|
+
'sub',
|
|
18
|
+
'jti',
|
|
19
|
+
])
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Whether a decoded payload carries an actual session, as opposed to being
|
|
23
|
+
* absent or a bare JWT envelope of `{ iat, exp }`. True only for a non-null
|
|
24
|
+
* object with at least one key that is not a registered JWT claim.
|
|
25
|
+
*/
|
|
26
|
+
const hasSessionIdentity = (session: unknown): boolean => {
|
|
27
|
+
if (!session || typeof session !== 'object') return false
|
|
28
|
+
return Object.keys(session).some((key) => !JWT_REGISTERED_CLAIMS.has(key))
|
|
29
|
+
}
|
|
30
|
+
|
|
10
31
|
export const authCookie = pikkuMiddlewareFactory<{
|
|
11
32
|
name: string
|
|
12
33
|
options: SerializeOptions
|
|
@@ -32,7 +53,12 @@ export const authCookie = pikkuMiddlewareFactory<{
|
|
|
32
53
|
const cookieValue = http.request.cookie(name)
|
|
33
54
|
if (cookieValue && jwtService) {
|
|
34
55
|
const userSession = await jwtService.decode(cookieValue)
|
|
35
|
-
|
|
56
|
+
// Not just truthy: a JWT of an absent session still decodes to a
|
|
57
|
+
// `{ iat, exp }` object, which is truthy and which the function runner
|
|
58
|
+
// would accept as a session. Require at least one claim that is not a
|
|
59
|
+
// standard JWT timestamp, so an identity-less token is treated as no
|
|
60
|
+
// session rather than as an authenticated one.
|
|
61
|
+
if (userSession && hasSessionIdentity(userSession)) {
|
|
36
62
|
setSession?.(userSession)
|
|
37
63
|
}
|
|
38
64
|
}
|
|
@@ -45,7 +71,17 @@ export const authCookie = pikkuMiddlewareFactory<{
|
|
|
45
71
|
|
|
46
72
|
if (hasSessionChanged?.()) {
|
|
47
73
|
const currentSession = await getSession?.()
|
|
48
|
-
|
|
74
|
+
// Logout path: `clearSession()` marks the session changed while leaving
|
|
75
|
+
// it absent. Re-signing that into a fresh, unexpired cookie would hand
|
|
76
|
+
// the browser a credential on the way out — so clear the cookie instead
|
|
77
|
+
// of minting one, and never call `encode` with an absent session.
|
|
78
|
+
if (!hasSessionIdentity(currentSession)) {
|
|
79
|
+
http.response.cookie(name, '', {
|
|
80
|
+
...mergedOptions,
|
|
81
|
+
expires: new Date(0),
|
|
82
|
+
maxAge: 0,
|
|
83
|
+
})
|
|
84
|
+
} else if (jwtService) {
|
|
49
85
|
http.response.cookie(
|
|
50
86
|
name,
|
|
51
87
|
await jwtService.encode(expiresIn, currentSession),
|
package/src/middleware/cors.ts
CHANGED
|
@@ -72,7 +72,8 @@ export const cors = pikkuMiddlewareFactory<{
|
|
|
72
72
|
|
|
73
73
|
if (request.method() === 'options') {
|
|
74
74
|
response.header('Access-Control-Max-Age', String(maxAge))
|
|
75
|
-
|
|
75
|
+
// 204 carries no body, and `json` has no no-content overload.
|
|
76
|
+
response.status(204).json(undefined as never)
|
|
76
77
|
return
|
|
77
78
|
}
|
|
78
79
|
|
package/src/middleware/index.ts
CHANGED
|
@@ -263,6 +263,49 @@ describe('pikkuRemoteAuthMiddleware', () => {
|
|
|
263
263
|
)
|
|
264
264
|
})
|
|
265
265
|
|
|
266
|
+
test('enforces the fn binding even when the path prefix varies in case', async () => {
|
|
267
|
+
// The router matches /remote/rpc/ case-insensitively, so /Remote/RPC/
|
|
268
|
+
// reaches the same handler. The fn-binding check must run for it too, or
|
|
269
|
+
// a token scoped to one function invokes any other by varying the case.
|
|
270
|
+
await assert.rejects(
|
|
271
|
+
() =>
|
|
272
|
+
pikkuRemoteAuthMiddleware(
|
|
273
|
+
{
|
|
274
|
+
secrets: createMockSecrets(TEST_SECRET),
|
|
275
|
+
jwt: createMockJWT({ aud: 'pikku-remote', fn: 'allowedFunc' }),
|
|
276
|
+
} as any,
|
|
277
|
+
{
|
|
278
|
+
http: {
|
|
279
|
+
request: createMockRequest(
|
|
280
|
+
{ authorization: 'Bearer valid-token' },
|
|
281
|
+
'/Remote/RPC/otherFunc'
|
|
282
|
+
),
|
|
283
|
+
},
|
|
284
|
+
} as any,
|
|
285
|
+
async () => {}
|
|
286
|
+
),
|
|
287
|
+
(err: any) => err instanceof UnauthorizedError
|
|
288
|
+
)
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
test('requires authorization for a case-varied remote path when no secret is set', async () => {
|
|
292
|
+
// The no-secret branch must also treat /REMOTE/RPC/ as remote, or a
|
|
293
|
+
// misconfigured mesh silently serves it unauthenticated.
|
|
294
|
+
await assert.rejects(
|
|
295
|
+
() =>
|
|
296
|
+
pikkuRemoteAuthMiddleware(
|
|
297
|
+
{ secrets: createMockSecrets(undefined) } as any,
|
|
298
|
+
{
|
|
299
|
+
http: {
|
|
300
|
+
request: createMockRequest({}, '/REMOTE/RPC/anyFunc'),
|
|
301
|
+
},
|
|
302
|
+
} as any,
|
|
303
|
+
async () => {}
|
|
304
|
+
),
|
|
305
|
+
(err: any) => err instanceof UnauthorizedError
|
|
306
|
+
)
|
|
307
|
+
})
|
|
308
|
+
|
|
266
309
|
test('should allow when token fn matches requested function', async () => {
|
|
267
310
|
let nextCalled = false
|
|
268
311
|
await pikkuRemoteAuthMiddleware(
|
|
@@ -6,6 +6,18 @@ import {
|
|
|
6
6
|
REMOTE_SESSION_INFO,
|
|
7
7
|
} from '../crypto-utils.js'
|
|
8
8
|
|
|
9
|
+
const REMOTE_RPC_PREFIX = '/remote/rpc/'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Whether this request targets the remote-RPC surface. Compared case-insensitively
|
|
13
|
+
* because the router matches routes that way (path-to-regexp defaults to
|
|
14
|
+
* `sensitive: false`), so `/Remote/RPC/fn` reaches the same handler as
|
|
15
|
+
* `/remote/rpc/fn`. A case-sensitive check here let a case-varied path slip
|
|
16
|
+
* past the trust gate and the token's `fn` binding while still being dispatched.
|
|
17
|
+
*/
|
|
18
|
+
const isRemoteRpcPath = (path: string): boolean =>
|
|
19
|
+
path.toLowerCase().startsWith(REMOTE_RPC_PREFIX)
|
|
20
|
+
|
|
9
21
|
export const pikkuRemoteAuthMiddleware = pikkuMiddleware(
|
|
10
22
|
async ({ secrets, jwt }, { http, setSession }, next) => {
|
|
11
23
|
if (!http?.request || !secrets) {
|
|
@@ -16,7 +28,7 @@ export const pikkuRemoteAuthMiddleware = pikkuMiddleware(
|
|
|
16
28
|
try {
|
|
17
29
|
secret = (await secrets.getSecret('PIKKU_REMOTE_SECRET')).reveal()
|
|
18
30
|
} catch {
|
|
19
|
-
if (http.request.path()
|
|
31
|
+
if (isRemoteRpcPath(http.request.path())) {
|
|
20
32
|
throw new UnauthorizedError()
|
|
21
33
|
}
|
|
22
34
|
return next()
|
|
@@ -51,9 +63,11 @@ export const pikkuRemoteAuthMiddleware = pikkuMiddleware(
|
|
|
51
63
|
throw new UnauthorizedError()
|
|
52
64
|
}
|
|
53
65
|
|
|
54
|
-
if (payload?.fn && http.request.path()
|
|
66
|
+
if (payload?.fn && isRemoteRpcPath(http.request.path())) {
|
|
67
|
+
// The prefix length is the same in any case, so slicing the raw path
|
|
68
|
+
// keeps the requested function name in its original case for the compare.
|
|
55
69
|
const fn = decodeURIComponent(
|
|
56
|
-
http.request.path().slice(
|
|
70
|
+
http.request.path().slice(REMOTE_RPC_PREFIX.length)
|
|
57
71
|
)
|
|
58
72
|
if (fn && payload.fn !== fn) {
|
|
59
73
|
throw new UnauthorizedError()
|
package/src/middleware-runner.ts
CHANGED
|
@@ -47,8 +47,10 @@ export const runMiddleware = async <
|
|
|
47
47
|
let result: any
|
|
48
48
|
const dispatch = async (index: number): Promise<any> => {
|
|
49
49
|
if (sorted && index < sorted.length) {
|
|
50
|
-
return await sorted[index]!(
|
|
51
|
-
|
|
50
|
+
return await sorted[index]!(
|
|
51
|
+
services as Parameters<Middleware>[0],
|
|
52
|
+
wire,
|
|
53
|
+
() => dispatch(index + 1)
|
|
52
54
|
)
|
|
53
55
|
} else if (main) {
|
|
54
56
|
result = await main()
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { describe, test } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import { readFileSync, readdirSync } from 'node:fs'
|
|
4
|
+
import { fileURLToPath } from 'node:url'
|
|
5
|
+
import { join, dirname, relative } from 'node:path'
|
|
6
|
+
|
|
7
|
+
const srcRoot = dirname(fileURLToPath(import.meta.url))
|
|
8
|
+
const thisFile = fileURLToPath(import.meta.url)
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* `as any` in a cast position. The word boundary and the following delimiter
|
|
12
|
+
* keep prose such as "as any URL a browser can load" out of the match.
|
|
13
|
+
*/
|
|
14
|
+
const AS_ANY = /\bas any\b(?!\s+[A-Za-z])/
|
|
15
|
+
|
|
16
|
+
const collectSourceFiles = (directory: string): string[] =>
|
|
17
|
+
readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
|
|
18
|
+
const entryPath = join(directory, entry.name)
|
|
19
|
+
if (entry.isDirectory()) {
|
|
20
|
+
return entry.name === 'dist' ? [] : collectSourceFiles(entryPath)
|
|
21
|
+
}
|
|
22
|
+
return entry.name.endsWith('.ts') && !entry.name.endsWith('.test.ts')
|
|
23
|
+
? [entryPath]
|
|
24
|
+
: []
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
describe('core asserts to named types, never to any', () => {
|
|
28
|
+
test('no non-test module casts through `as any`', () => {
|
|
29
|
+
const offenders = collectSourceFiles(srcRoot)
|
|
30
|
+
.filter((file) => file !== thisFile)
|
|
31
|
+
.flatMap((file) =>
|
|
32
|
+
readFileSync(file, 'utf-8')
|
|
33
|
+
.split('\n')
|
|
34
|
+
.flatMap((line, index) =>
|
|
35
|
+
AS_ANY.test(line)
|
|
36
|
+
? [`${relative(srcRoot, file)}:${index + 1} ${line.trim()}`]
|
|
37
|
+
: []
|
|
38
|
+
)
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
assert.deepEqual(
|
|
42
|
+
offenders,
|
|
43
|
+
[],
|
|
44
|
+
'`as any` discards the target type, so a wrong value passes as readily as ' +
|
|
45
|
+
'a right one. Assert to the type actually wanted — and if the narrowing ' +
|
|
46
|
+
'cannot be expressed, say why in a knowledge note and point at it:\n' +
|
|
47
|
+
offenders.join('\n')
|
|
48
|
+
)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
test('the matcher finds a cast and ignores the prose that reads like one', () => {
|
|
52
|
+
// Guards the test above: a regex that matched nothing would pass forever.
|
|
53
|
+
assert.equal(AS_ANY.test('const x = y as any'), true)
|
|
54
|
+
assert.equal(AS_ANY.test('foo(bar as any)'), true)
|
|
55
|
+
assert.equal(AS_ANY.test('a picture, as any URL a browser can load'), false)
|
|
56
|
+
})
|
|
57
|
+
})
|