@pikku/core 0.12.78 → 0.12.80
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 +234 -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/function/function-runner.js +20 -42
- package/dist/function/functions.types.d.ts +9 -5
- package/dist/index.d.ts +4 -9
- package/dist/index.js +3 -8
- 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 +12 -5
- package/dist/schema.js +35 -1
- package/dist/services/ai-run-state-service.d.ts +7 -1
- package/dist/services/in-memory-ai-run-state-service.d.ts +1 -1
- package/dist/services/in-memory-ai-run-state-service.js +2 -1
- package/dist/services/in-memory-workflow-service.d.ts +10 -0
- package/dist/services/in-memory-workflow-service.js +25 -0
- 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/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 +226 -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 -1
- package/dist/types/state.types.d.ts +1 -1
- package/dist/utils/node-host-resolver.d.ts +12 -0
- package/dist/utils/node-host-resolver.js +16 -0
- package/dist/utils/safe-fetch.d.ts +18 -0
- package/dist/utils/safe-fetch.js +167 -29
- 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-memory.js +3 -1
- package/dist/wirings/ai-agent/ai-agent-prepare.js +3 -9
- package/dist/wirings/ai-agent/ai-agent-runner.js +28 -107
- package/dist/wirings/ai-agent/ai-agent-stream.js +20 -61
- package/dist/wirings/ai-agent/ai-agent-turn.d.ts +56 -0
- package/dist/wirings/ai-agent/ai-agent-turn.js +81 -0
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +1 -1
- package/dist/wirings/ai-agent/voice-input.js +1 -6
- package/dist/wirings/ai-agent/voice-output.js +2 -12
- 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/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/cli-runner.js +4 -2
- package/dist/wirings/cli/cli.types.d.ts +0 -8
- package/dist/wirings/cli/command-parser.js +13 -0
- package/dist/wirings/gateway/gateway-runner.js +41 -5
- 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 +6 -13
- package/dist/wirings/http/http.types.d.ts +0 -10
- package/dist/wirings/http/index.d.ts +1 -1
- package/dist/wirings/http/index.js +1 -1
- package/dist/wirings/mcp/mcp-runner.d.ts +0 -7
- package/dist/wirings/mcp/mcp-runner.js +0 -6
- package/dist/wirings/rpc/rpc-runner.d.ts +8 -51
- package/dist/wirings/rpc/rpc-runner.js +53 -86
- package/dist/wirings/rpc/rpc-types.d.ts +3 -0
- package/dist/wirings/secret/validate-secret-definitions.js +2 -0
- 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/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 +29 -2
- 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 +7 -2
- package/dist/wirings/workflow/index.js +5 -1
- package/dist/wirings/workflow/pikku-scenario-service.d.ts +17 -3
- package/dist/wirings/workflow/pikku-scenario-service.js +38 -10
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +44 -111
- package/dist/wirings/workflow/pikku-workflow-service.js +86 -404
- package/dist/wirings/workflow/workflow-approval.d.ts +39 -0
- package/dist/wirings/workflow/workflow-approval.js +114 -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-engine.types.js +1 -0
- package/dist/wirings/workflow/workflow-run-ownership.d.ts +16 -0
- package/dist/wirings/workflow/workflow-run-ownership.js +29 -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 +7 -0
- 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/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-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 +38 -26
- 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/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-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 +34 -0
- package/knowledge/decisions/security/an-agent-approval-is-claimed-before-the-tool-runs.md +33 -0
- package/knowledge/decisions/security/an-upload-is-counted-as-it-arrives-not-buffered-then-measured.md +24 -0
- package/knowledge/decisions/security/gateway-handlers-run-through-the-function-runner-gate.md +13 -3
- package/knowledge/decisions/security/index.md +7 -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 +14 -3
- package/scripts/generate-api-report.d.mts +1 -0
- package/scripts/generate-api-report.mjs +89 -0
- package/scripts/generate-api-report.mts +218 -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/function/function-runner.test.ts +1 -1
- package/src/function/function-runner.ts +28 -39
- package/src/function/functions.types.ts +15 -9
- package/src/handle-error.ts +1 -1
- package/src/index.ts +3 -22
- 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 +17 -6
- package/src/public-surface.json +578 -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-run-state-service.ts +7 -1
- package/src/services/audit-service.ts +2 -2
- package/src/services/in-memory-ai-run-state-service.ts +3 -2
- package/src/services/in-memory-workflow-service.ts +25 -0
- package/src/services/index.ts +1 -4
- 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/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 +286 -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 +15 -1
- package/src/types/state.types.ts +1 -1
- package/src/utils/node-host-resolver.ts +20 -0
- package/src/utils/safe-fetch.test.ts +143 -1
- package/src/utils/safe-fetch.ts +200 -25
- 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-interrupt.test.ts +2 -1
- package/src/wirings/ai-agent/ai-agent-memory.ts +8 -1
- package/src/wirings/ai-agent/ai-agent-prepare.ts +10 -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 +49 -120
- package/src/wirings/ai-agent/ai-agent-stream.test.ts +2 -0
- package/src/wirings/ai-agent/ai-agent-stream.ts +36 -63
- package/src/wirings/ai-agent/ai-agent-thread-ownership.test.ts +1 -1
- package/src/wirings/ai-agent/ai-agent-turn.ts +121 -0
- package/src/wirings/ai-agent/ai-agent.types.ts +1 -1
- package/src/wirings/ai-agent/voice-input.ts +1 -6
- package/src/wirings/ai-agent/voice-output.ts +2 -12
- 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/local/local-channel-runner.ts +1 -1
- 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-client-runner.ts +4 -1
- package/src/wirings/cli/cli-runner.ts +7 -4
- 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/gateway/gateway-authorization.test.ts +131 -0
- package/src/wirings/gateway/gateway-channel-meta.test.ts +44 -0
- package/src/wirings/gateway/gateway-runner.ts +62 -22
- package/src/wirings/http/http-routes.ts +4 -1
- package/src/wirings/http/http-runner.ts +11 -26
- package/src/wirings/http/http.types.ts +0 -15
- package/src/wirings/http/index.ts +1 -7
- package/src/wirings/http/pikku-fetch-http-request.ts +2 -2
- package/src/wirings/http/web-request.ts +1 -1
- package/src/wirings/mcp/mcp-runner.ts +2 -16
- 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/queue-runner.ts +1 -1
- package/src/wirings/rpc/addon-auth-tags.test.ts +1 -5
- package/src/wirings/rpc/rpc-runner.ts +58 -136
- package/src/wirings/rpc/rpc-types.ts +7 -0
- package/src/wirings/rpc/wire-addon.ts +3 -1
- package/src/wirings/secret/validate-secret-definitions.test.ts +69 -0
- package/src/wirings/secret/validate-secret-definitions.ts +2 -0
- package/src/wirings/trigger/pikku-trigger-service.ts +0 -5
- package/src/wirings/trigger/trigger-runner.ts +7 -5
- 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 +35 -2
- 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 +4 -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 +12 -4
- package/src/wirings/workflow/pikku-scenario-service.ts +54 -25
- package/src/wirings/workflow/pikku-workflow-service.test.ts +2 -2
- package/src/wirings/workflow/pikku-workflow-service.ts +208 -630
- package/src/wirings/workflow/scenario-hooks.test.ts +51 -0
- package/src/wirings/workflow/workflow-approval.ts +185 -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-dispatch-relay.test.ts +128 -0
- 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 +215 -0
- package/src/wirings/workflow/workflow-run-engine.types.ts +91 -0
- package/src/wirings/workflow/workflow-run-ownership.ts +36 -0
- package/src/wirings/workflow/workflow-suspend.ts +61 -0
- package/src/wirings/workflow/workflow.types.ts +7 -0
- package/src/wirings-stay-decoupled.test.ts +123 -0
- package/tsconfig.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/src/internal.ts +0 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,237 @@
|
|
|
1
|
+
## 0.12.80
|
|
2
|
+
|
|
3
|
+
### Patch Changes
|
|
4
|
+
|
|
5
|
+
- 41c1a95: Move the adapter surface to `@pikku/core/ecosystem` so the root can promise stability
|
|
6
|
+
|
|
7
|
+
The types and helpers a runtime adapter, a service package, the code generator and the CLI implement against sat on the package root, mixed in with the API application code uses. That made the root impossible to commit to: `runPikkuFunc` was reshaped repeatedly over the last year while every field on `PikkuWire` survived untouched, and promising stability on both would mean promising the weaker of the two.
|
|
8
|
+
|
|
9
|
+
They now live on `@pikku/core/ecosystem`. The root is what 0.13's compatibility promise covers.
|
|
10
|
+
|
|
11
|
+
Not `/internal`: generated bootstrap files import from here, so the specifier lands in the user's own `.pikku` directory — telling someone they are touching internals when the code generator put it there is both wrong and self-defeating. Not `/runtime` either: that reads as runtime-versus-compile-time, `packages/runtimes/*` already claims the word, and the CLI is the largest consumer.
|
|
12
|
+
|
|
13
|
+
`./internal` remains as an alias to the same module, because the pinned bootstrap CLI still emits it.
|
|
14
|
+
|
|
15
|
+
Breaking for adapter authors; appropriate pre-0.13.
|
|
16
|
+
|
|
17
|
+
- ce96383: A child workflow now inherits the `pikkuUserId` its parent was running as
|
|
18
|
+
|
|
19
|
+
`PikkuWorkflowService` filled parts of the wire it builds for a workflow body and for a child run from the RPC service it had been handed — `rpcService.wire?.session`, `rpcService.wire?.rpc`, `rpcService.wire?.pikkuUserId`. `PikkuRPC` has no `wire`, and neither does the object the RPC service actually returns, so every one of those reads was `undefined`; the `rpcService: any` parameter type is what kept it quiet. The visible consequence was that a child workflow started from a step ran as nobody.
|
|
20
|
+
|
|
21
|
+
Those reads now come from the run record, which is durable and survives the process boundary a queued step crosses. `session` and `rpc` are not copied at all: `runPikkuFunc` attaches `rpc` lazily per invocation and resolves the session from the session store, so both were overwritten moments later regardless. The wires these paths build are typed `PikkuRawWire`, which is what they have always been.
|
|
22
|
+
|
|
23
|
+
`PikkuRPC` also now declares `rpcWithWire`, which the RPC service has always returned and the workflow service has always called.
|
|
24
|
+
|
|
25
|
+
- 7e60867: Delete exports nothing references
|
|
26
|
+
|
|
27
|
+
A sweep of the `@pikku/core` surface for exports with no consumer anywhere in the repo — no package, template, verifier or e2e project imports them: `ExtractFunctionOutput`, `CLICommandDefinition`, `RequestHeaders`, `HTTPFunctionsMeta`, `HTTPWiringMiddleware`, `JsonRpcError`, `TriggerSourceInfo`, `getMCPResources`, `getMCPPrompts`, `onGraphNodeComplete` and `InputRef`.
|
|
28
|
+
|
|
29
|
+
Every one was a compatibility promise with nothing on the other end of it. Removing them narrows what 0.13 has to keep stable.
|
|
30
|
+
|
|
31
|
+
`isRef` looked like the twelfth, and isn't. It is the type guard that reads what `createRef` writes — the `__isRef` brand marking a graph node input as "substitute another node's output here". Nothing imported it because neither it nor `RefValue` was reachable from any entry point, so the one consumer that needed it, the inspector's graph serializer, had reimplemented the same four conditions privately as `isRefValue` along with its own structural copy of `RefValue`. Deleting `isRef` would have made that duplicate permanent, with the brand's shape asserted in two places free to drift apart.
|
|
32
|
+
|
|
33
|
+
So `isRef` and `RefValue` are exported from `@pikku/core/workflow` instead, and the inspector imports them rather than keeping its own copy.
|
|
34
|
+
|
|
35
|
+
- f8f1244: Fix `onConnect`/`onDisconnect` wrapper handlers, and correct `wireChannel`'s generic arguments
|
|
36
|
+
|
|
37
|
+
`CoreChannel` accepts three shapes for a handler: a function config, a simple wrapper (`{ func, middleware }`), and a wrapper around a function config (`{ func: { func }, middleware }`). `wireChannel` unwrapped the third shape for `onMessage` and `onMessageWiring`, but registered `onConnect` and `onDisconnect` as-is — so the registered config's `func` was an object, and the function runner threw when it tried to call it. All three shapes now register a callable config on every handler.
|
|
38
|
+
|
|
39
|
+
`wireChannel`'s type arguments were also misaligned with `CoreChannel`'s parameter list: `PikkuPermission` was being passed into the `ChannelConnect` slot and `PikkuMiddleware` into `ChannelDisconnect`, which made `wireChannel({ onConnect: { func } })` fail to typecheck with "not assignable to `CorePikkuPermission`". End users did not see this — the CLI's generated `wireChannel` wrapper casts before calling core — but anyone importing `wireChannel` from `@pikku/core/channel` directly did. The signature is now `wireChannel<In, Channel>(channel: CoreChannel<In, Channel>)`; the three surplus type parameters were never used for anything correct and are gone.
|
|
40
|
+
|
|
41
|
+
- dcf20cb: Pin the public API, and declare which modules have import-time side effects
|
|
42
|
+
|
|
43
|
+
Nothing caught a change to what `@pikku/core` publishes. An export could appear, vanish, or have a member's signature change, and the only signal was a downstream break after release.
|
|
44
|
+
|
|
45
|
+
`public-surface.json` now pins every runtime export reachable through a `package.json` `exports` subpath, and `api-report.md` pins the API at **member** level — a method added to an interface is the change that breaks a consumer's build, and an export list cannot see it. Both regenerate from the code and are asserted against it, so widening the API is a visible diff rather than a side effect of an `export *`.
|
|
46
|
+
|
|
47
|
+
The report is written to state what the API _is_ rather than merely list identifiers, so the diff is readable by a reviewer.
|
|
48
|
+
|
|
49
|
+
`sideEffects` is declared as an allowlist rather than `false`: core genuinely has some. The error registry is built by `addError` calls that run on import, so claiming `sideEffects: false` would let a bundler drop it and leave `getErrorResponse` unable to find any error. A test detects the modules that actually have side effects and fails if the allowlist disagrees.
|
|
50
|
+
|
|
51
|
+
- 6512384: feat: give scenarios a `scenario.context` their `before`/`after` hooks can read
|
|
52
|
+
|
|
53
|
+
A hook only ever received the run's _input_, so teardown could not reach an id
|
|
54
|
+
the scenario body minted — which is exactly what a failing run needs to clean
|
|
55
|
+
up. `wire.scenario.context` is a per-run scratch object shared by `before`, the
|
|
56
|
+
body and `after`. It is typed as a `Partial` of the scenario's output, because a
|
|
57
|
+
run that failed early has none of it.
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
pikkuScenario<void, { projectId: string }>({
|
|
61
|
+
func: async (_services, _data, { scenario }) => {
|
|
62
|
+
const { projectId } = await scenario.when('creates a project', 'createsProject', …)
|
|
63
|
+
scenario.context.projectId = projectId
|
|
64
|
+
…
|
|
65
|
+
},
|
|
66
|
+
after: pikkuScenarioHook<void, { projectId: string }>(
|
|
67
|
+
async (_services, _data, { scenario, actors }) => {
|
|
68
|
+
if (scenario.context.projectId) {
|
|
69
|
+
await actors.admin.invoke('deleteProject', { projectId: scenario.context.projectId })
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
),
|
|
73
|
+
})
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Deliberately not a world: it is scoped to a single run, and scenario _steps_
|
|
77
|
+
cannot reach it — state still flows between steps as return values.
|
|
78
|
+
|
|
79
|
+
Feature-level `before`/`after` get the same member, scoped to their feature, so
|
|
80
|
+
group setup can hand group teardown what it created. It is a separate object
|
|
81
|
+
from the scenarios' contexts: one bag shared across a group is the invisible
|
|
82
|
+
coupling a Cucumber world had.
|
|
83
|
+
|
|
84
|
+
- e3b4c14: Remove the `addTagPermission`, `addHTTPPermission` and `ZodLike` compatibility stubs
|
|
85
|
+
|
|
86
|
+
Tag- and HTTP-route-level permissions were removed in #972; `addTagPermission` and `addHTTPPermission` survived only as throwing stubs so the pinned bootstrap CLI could resolve their imports at build time. `@pikku/cli@0.12.96` — the currently pinned bootstrap version — emits neither name, so the stubs and the `packages/cli/build.sh` rewrite rules that fed them are gone.
|
|
87
|
+
|
|
88
|
+
Declare permissions on the function instead: `pikkuFunc({ permissions })`, or app-wide with `addGlobalPermission`.
|
|
89
|
+
|
|
90
|
+
`ZodLike` was an alias for `StandardSchemaV1<T, T>` kept for generated code that no longer references it. Import `StandardSchemaV1` from `@standard-schema/spec` directly.
|
|
91
|
+
|
|
92
|
+
- efd0ed1: **An explicitly-`undefined` property no longer kills a step.** JSON Schema
|
|
93
|
+
cannot describe such a property, so the validator rejected the whole instance
|
|
94
|
+
rather than the field — `{ a: undefined }` threw
|
|
95
|
+
`Instances of "undefined" type are not supported`. Whether a payload could
|
|
96
|
+
contain one depended on how the call travelled: `JSON.stringify` drops those
|
|
97
|
+
keys over HTTP, while an in-process dispatch hands the object over intact, so
|
|
98
|
+
`workflow.do('step', 'rpc', { retries: data.maybeRetries })` failed only when
|
|
99
|
+
the step ran inline. `validateSchema` now strips them first, and an
|
|
100
|
+
explicitly-undefined _required_ field reports as the missing property it is.
|
|
101
|
+
- cba98fb: Security hardening sweep
|
|
102
|
+
- **Content uploads require a signature**, matching reads. `handleUpload` previously validated the path and the size limit and then wrote the file, so an unauthenticated `PUT` to the upload prefix landed on disk. The express server, which verified nothing at all, now verifies both uploads and reads.
|
|
103
|
+
- **The remote-RPC prefix is matched case-insensitively.** The router matches routes case-insensitively, so `/Remote/RPC/fn` reached the same handler while a case-sensitive `startsWith('/remote/rpc/')` let it past the mesh trust gate and the token's `fn` binding.
|
|
104
|
+
- **Dev quick-login refuses proxied requests.** The gate checked the hostname only, so a request forwarded with `Host: localhost` was auto-provisioned a root-admin session. Proxy markers (`forwarded`, `x-forwarded-*`) now refuse regardless of what they claim, and dev login is inert in production.
|
|
105
|
+
- **Logout clears the session cookie** instead of re-signing an absent session into a fresh, unexpired one.
|
|
106
|
+
- **Short-flag cluster parsing is bounded**, closing a CLI-over-channel denial of service.
|
|
107
|
+
- `allowedHosts` is carried into secret definition meta.
|
|
108
|
+
|
|
109
|
+
- ce96383: Split `pikku-workflow-service.ts` into composable modules and report missing workflow metadata as such
|
|
110
|
+
|
|
111
|
+
`PikkuWorkflowService`'s module carried its error catalog, run-engine interfaces, queue routing and queue wiring alongside the class. Those now live in `workflow-errors.ts`, `workflow-run-engine.types.ts`, `workflow-constants.ts`, `workflow-meta-resolver.ts`, `workflow-queue-routing.ts` and `workflow-queue-wiring.ts`, with the approval and recovery paths in `workflow-approval.ts` and `workflow-recovery.ts`. The `@pikku/core/workflow` entry point exports the same names as before.
|
|
112
|
+
|
|
113
|
+
Typing the workflow meta resolver surfaced a crash: a run whose workflow had no generated metadata threw `TypeError: Cannot read properties of undefined` from deep inside the runner, or `WorkflowNotFoundError` — neither of which points at the actual cause. It now throws `PikkuMissingMetaError`, matching how the queue and trigger runners already report the same condition.
|
|
114
|
+
|
|
115
|
+
- f8f1244: Tighten several public types that `as any` was masking
|
|
116
|
+
- `AIStreamEvent`'s `approval-request` variant now declares `runId: string` rather than `runId?: string`. Every emitter already set it, and `AIAgentResult['pendingApprovals']` has always required it — the optional let `undefined` reach a field consumers rely on to resume a suspended run.
|
|
117
|
+
- `PikkuWire` gains an optional `logger`. The no-op audit service already read `wire.logger` before falling back to the singleton, but nothing declared it, so a host had no typed way to attach an invocation-scoped logger.
|
|
118
|
+
- `pikkuAuth`'s marker is now the exported `AuthBranded` type instead of an untyped property, so the brand that agent tool filtering depends on is visible to the type system at both the site that sets it and the sites that read it.
|
|
119
|
+
|
|
120
|
+
Internally this takes core's non-test modules from 108 `as any` casts to none. Each is replaced by an assertion to the type actually wanted, or by a change to the surrounding types that makes the assertion unnecessary. A test holds the count at zero.
|
|
121
|
+
|
|
122
|
+
- f8f1244: Declare `CoreUserSession.readonly` and `ChannelMeta.gateway`, which the runtime already used
|
|
123
|
+
|
|
124
|
+
The function runner throws `ReadonlySessionError` when a session is marked `readonly` and the function is not, but `CoreUserSession` never declared the field — so there was no typed way to build a readonly session, and even core's own test had to cast. Likewise `wireGateway` writes `gateway: true` onto a websocket channel's meta, which `ChannelMeta` did not admit. Both are now declared.
|
|
125
|
+
|
|
126
|
+
The gateway websocket path also wrote channel meta without `input`, `disconnect` or `messageWirings`, all of which `ChannelMeta` requires and `channel-handler` indexes without a guard. It now writes a complete record.
|
|
127
|
+
|
|
128
|
+
- 6e93a35: Give each wire an explicit set of crossovers
|
|
129
|
+
|
|
130
|
+
`wire.rpc.agent` was implemented inline in `rpc-runner.ts`, which put the agent turn logic — run, stream, resume, interrupt, approve — inside the RPC primitive. It moves to `ai-agent/agent-rpc.ts`, next to the runner and stream code it delegates to; `rpc-runner` imports it and the getter stays, so a request that never touches an agent never builds the facade.
|
|
131
|
+
|
|
132
|
+
The wires (`http`, `channel`, `queue`, `scheduler`, `cli`, `rpc`, `ai-agent`, `workflow`) previously imported each other ad hoc, so an accidental edge was indistinguishable from a designed one. Each wire now declares the crossovers it is allowed, and a test walks the import graph to hold it — failing both on an undeclared edge and on a declared crossover that no longer exists, so the declaration cannot rot into a rubber stamp.
|
|
133
|
+
|
|
134
|
+
`unsupportedChannelRemote` moves from `channel-rpc-service.ts` to `channel-rpc.types.ts`, alongside the error it throws.
|
|
135
|
+
|
|
136
|
+
The shared storage conformance suite splits from one 1216-line module into one module per service, so a backend author can read the contract for the service they implement. `defineServiceTests` is unchanged for callers.
|
|
137
|
+
|
|
138
|
+
- 6dada45: fix(workflow,ai-agent): make a run's owner, entry node and step function authoritative
|
|
139
|
+
|
|
140
|
+
A graph run may only start at a node the graph declared in `meta.entryNodeIds`, and
|
|
141
|
+
the generated `POST /workflow/:workflowName/graph/:nodeId` route that let an HTTP
|
|
142
|
+
caller pick the entry node is gone. `startNode` stays for `PikkuTriggerService`,
|
|
143
|
+
which names a declared entry node anyway.
|
|
144
|
+
|
|
145
|
+
`StepState` now records the `rpcName` the workflow dispatched a step with, and the
|
|
146
|
+
step claim rejects a queue message naming a different function with
|
|
147
|
+
`WorkflowStepFunctionMismatchError` before mutating any status — a step runs under
|
|
148
|
+
the run owner's identity and without the `expose` gate, so the message must not
|
|
149
|
+
choose what runs.
|
|
150
|
+
|
|
151
|
+
`approveStep` takes the caller's session, and the generated status routes and
|
|
152
|
+
streams assert the same `assertWorkflowRunOwner` check: a run started through a
|
|
153
|
+
session may only be read and approved by that session's user. A run with no
|
|
154
|
+
recorded owner (trigger, scheduler, unauthenticated route) has nobody to compare
|
|
155
|
+
against and is still gated by the entrypoint's own `auth`/`permissions`.
|
|
156
|
+
|
|
157
|
+
`AIRunStateService.resolveApproval` is now a compare-and-swap returning whether
|
|
158
|
+
_this_ caller made the claim, and both agent resume paths run a tool only for the
|
|
159
|
+
approvals they claimed — concurrent approvals of one tool call no longer all
|
|
160
|
+
execute it.
|
|
161
|
+
|
|
162
|
+
## 0.12.79
|
|
163
|
+
|
|
164
|
+
### Patch Changes
|
|
165
|
+
|
|
166
|
+
- e848eb2: Add `relayUndispatchedSteps()`, which re-drives steps whose queue or scheduler
|
|
167
|
+
dispatch was lost.
|
|
168
|
+
|
|
169
|
+
Arming a step is two writes to two systems — the step row lands `pending`, then
|
|
170
|
+
a job is published — and nothing spans both, so a crash in between leaves a
|
|
171
|
+
durable row nothing will ever pick up. The run then neither finishes nor fails.
|
|
172
|
+
|
|
173
|
+
The step row is the outbox record and this is the relay. It is safe to
|
|
174
|
+
re-dispatch a step that already has a live job because `executeWorkflowStepInner`
|
|
175
|
+
claims the step under `withStepLock` before invoking anything: the loser reads
|
|
176
|
+
`running` and returns. Stores opt in by overriding `findUndispatchedSteps`; the
|
|
177
|
+
default returns nothing, so a store without an atomic step lock gains no
|
|
178
|
+
re-dispatches. Opted in: `kysely-postgres` and `kysely-mysql` (real locks) and
|
|
179
|
+
in-memory (inline, single-process, no queues). Not opted in: `mongodb` and
|
|
180
|
+
`kysely-sqlite`, whose `withStepLock` is a pass-through.
|
|
181
|
+
|
|
182
|
+
Not self-starting — call it from a scheduled task.
|
|
183
|
+
|
|
184
|
+
- b170489: Gateway handlers now run under the metadata their author actually wrote, instead
|
|
185
|
+
of a fabricated meta object.
|
|
186
|
+
|
|
187
|
+
`registerGatewayHandler` used to synthesize `{ sessionless: true,
|
|
188
|
+
inputSchemaName: null, outputSchemaName: null }` for every gateway handler, so a
|
|
189
|
+
function declared with `pikkuFunc` — which records "session required" in meta
|
|
190
|
+
rather than through an `auth` property — was silently made sessionless, and its
|
|
191
|
+
input schema was never validated. It now inherits `sessionless`, the schema
|
|
192
|
+
names, `scopes` and tag middleware from the function the gateway was wired with,
|
|
193
|
+
falling back to the old sessionless default only when nothing was declared (a
|
|
194
|
+
gateway wired by hand rather than through codegen).
|
|
195
|
+
|
|
196
|
+
Tag middleware also reaches gateways for the first time. `addTagMiddleware('x',
|
|
197
|
+
…)` combined with `wireGateway({ tags: ['x'] })` previously resolved to nothing
|
|
198
|
+
at all — the inspector computed the middleware and no runtime path read it — so
|
|
199
|
+
a tag that read like a gate applied none.
|
|
200
|
+
|
|
201
|
+
**Both are tightening changes.** A gateway whose handler declared a session
|
|
202
|
+
requirement, or whose tags name registered middleware, now enforces what it
|
|
203
|
+
already said it enforced.
|
|
204
|
+
|
|
205
|
+
- ae4e898: Carry a secret's `allowedHosts` through code generation, and close three gaps in
|
|
206
|
+
the SSRF guard.
|
|
207
|
+
|
|
208
|
+
`allowedHosts` was declared and enforced but never survived codegen: the
|
|
209
|
+
inspector did not read the property off the `defineSecret` literal, and the meta
|
|
210
|
+
builder rebuilt its objects without it. Enforcement in `assertSecretAllowedForHost`
|
|
211
|
+
then always saw `undefined`, so the egress restriction was a no-op by default —
|
|
212
|
+
and, with `secrets.requireAllowedHosts` set, threw for every secret including the
|
|
213
|
+
ones that correctly declared hosts. Both stages now carry the field, and the
|
|
214
|
+
secrets verifier asserts it against the generated JSON rather than a hand-written
|
|
215
|
+
meta literal, which is why the existing tests stayed green.
|
|
216
|
+
|
|
217
|
+
`isPrivateHost` now checks an explicit CIDR table instead of ad-hoc octet
|
|
218
|
+
comparisons. It previously missed `100.64.0.0/10` — which contains Alibaba
|
|
219
|
+
Cloud's `100.100.100.200` metadata endpoint — along with `192.0.0.0/24`,
|
|
220
|
+
`198.18.0.0/15`, `192.88.99.0/24`, the TEST-NETs, multicast and reserved space.
|
|
221
|
+
IPv6 gains a real parser, so `fec0::/10`, `ff00::/8`, and NAT64 (`64:ff9b::/96`)
|
|
222
|
+
and 6to4 (`2002::/16`) forms wrapping an internal IPv4 address are caught.
|
|
223
|
+
|
|
224
|
+
`safeFetch` takes an optional `resolveHost`, checked on the initial URL and every
|
|
225
|
+
redirect hop, so a _public_ hostname pointing at a private address is refused —
|
|
226
|
+
the `169-254-169-254.nip.io` shape a literal-only check cannot see. Core cannot
|
|
227
|
+
resolve DNS itself (Workers has no DNS API), so the Node resolver ships as
|
|
228
|
+
`@pikku/core/node-host-resolver` and the Node server runtimes install it during
|
|
229
|
+
`init()`. The connection is not pinned to the address that was checked, so a
|
|
230
|
+
rebind between check and connect is still possible.
|
|
231
|
+
|
|
232
|
+
The graph addon's `httpRequest` node called bare `fetch`, bypassing the guard
|
|
233
|
+
entirely; it now goes through `safeFetch`.
|
|
234
|
+
|
|
1
235
|
## 0.12.78
|
|
2
236
|
|
|
3
237
|
### Patch Changes
|
package/dist/dev/hot-reload.js
CHANGED
|
@@ -61,12 +61,7 @@ export async function pikkuDevReloader(options) {
|
|
|
61
61
|
logger.error(`Failed to import: ${relative(process.cwd(), importPath)} (keeping old code)`);
|
|
62
62
|
return;
|
|
63
63
|
}
|
|
64
|
-
//
|
|
65
|
-
// adding new ones. Write into the map captured at startup, NOT pikkuState's
|
|
66
|
-
// current one: a dev-server watcher may have temporarily swapped in a
|
|
67
|
-
// codegen-scoped map, whose writes are discarded when it restores.
|
|
68
|
-
// Schemas are NOT touched here: `input`/`output` hold raw zod schemas while
|
|
69
|
-
// the schema map carries codegen JSON schemas; mixing them crashed reloads.
|
|
64
|
+
// knowledge: decisions/internals/hot-reload-writes-into-the-function-map-captured-at-startup.md
|
|
70
65
|
for (const [exportName, exportValue] of Object.entries(mod)) {
|
|
71
66
|
if (!isFunctionConfig(exportValue))
|
|
72
67
|
continue;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The surface a package in the Pikku ecosystem reaches for — a runtime adapter,
|
|
3
|
+
* a service, the code generator's output, the CLI — and application code does
|
|
4
|
+
* not.
|
|
5
|
+
*
|
|
6
|
+
* Split out from the package root so 1.0's compatibility promise covers what
|
|
7
|
+
* applications actually import. These signatures move when the runtime needs
|
|
8
|
+
* them to — `runPikkuFunc` was reshaped over the last year while every field on
|
|
9
|
+
* `PikkuWire` survived — and promising stability on both would mean promising
|
|
10
|
+
* the weaker of the two.
|
|
11
|
+
*
|
|
12
|
+
* Not `/internal`: generated bootstrap files import from here, so the specifier
|
|
13
|
+
* lands in the user's own `.pikku` directory, and telling someone they are
|
|
14
|
+
* touching internals when the code generator put it there is both wrong and
|
|
15
|
+
* self-defeating — it could never be broken anyway. Not `/runtime` either: that
|
|
16
|
+
* reads as runtime-versus-compile-time, i.e. the real API, and `packages/runtimes/*`
|
|
17
|
+
* already claims the word while the CLI is the largest consumer here.
|
|
18
|
+
*
|
|
19
|
+
* `/internal` stays as an alias because the pinned bootstrap CLI still emits it.
|
|
20
|
+
*
|
|
21
|
+
* knowledge: decisions/internals/the-ecosystem-entry-point-carries-the-adapter-surface.md
|
|
22
|
+
*/
|
|
23
|
+
export { pikkuState, resetPikkuState, getAllPackageStates, getSingletonServices, getCreateWireServices, setSingletonServices, } from './pikku-state.js';
|
|
24
|
+
export { runPikkuFunc, addFunction } from './function/function-runner.js';
|
|
25
|
+
export { addGlobalMiddleware, addTagMiddleware as addMiddleware, } from './middleware-runner.js';
|
|
26
|
+
export { httpRouter } from './wirings/http/routers/http-router.js';
|
|
27
|
+
export type { CreateSingletonServices, CreateWireServices, } from './types/core.types.js';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The surface a package in the Pikku ecosystem reaches for — a runtime adapter,
|
|
3
|
+
* a service, the code generator's output, the CLI — and application code does
|
|
4
|
+
* not.
|
|
5
|
+
*
|
|
6
|
+
* Split out from the package root so 1.0's compatibility promise covers what
|
|
7
|
+
* applications actually import. These signatures move when the runtime needs
|
|
8
|
+
* them to — `runPikkuFunc` was reshaped over the last year while every field on
|
|
9
|
+
* `PikkuWire` survived — and promising stability on both would mean promising
|
|
10
|
+
* the weaker of the two.
|
|
11
|
+
*
|
|
12
|
+
* Not `/internal`: generated bootstrap files import from here, so the specifier
|
|
13
|
+
* lands in the user's own `.pikku` directory, and telling someone they are
|
|
14
|
+
* touching internals when the code generator put it there is both wrong and
|
|
15
|
+
* self-defeating — it could never be broken anyway. Not `/runtime` either: that
|
|
16
|
+
* reads as runtime-versus-compile-time, i.e. the real API, and `packages/runtimes/*`
|
|
17
|
+
* already claims the word while the CLI is the largest consumer here.
|
|
18
|
+
*
|
|
19
|
+
* `/internal` stays as an alias because the pinned bootstrap CLI still emits it.
|
|
20
|
+
*
|
|
21
|
+
* knowledge: decisions/internals/the-ecosystem-entry-point-carries-the-adapter-surface.md
|
|
22
|
+
*/
|
|
23
|
+
export { pikkuState, resetPikkuState, getAllPackageStates, getSingletonServices, getCreateWireServices, setSingletonServices, } from './pikku-state.js';
|
|
24
|
+
export { runPikkuFunc, addFunction } from './function/function-runner.js';
|
|
25
|
+
export { addGlobalMiddleware, addTagMiddleware as addMiddleware, } from './middleware-runner.js';
|
|
26
|
+
export { httpRouter } from './wirings/http/routers/http-router.js';
|
|
@@ -12,7 +12,8 @@ export class PikkuError extends Error {
|
|
|
12
12
|
* plain `Error`. Callers log the message alone for these, the full stack for
|
|
13
13
|
* everything else.
|
|
14
14
|
*/
|
|
15
|
-
export const isExpectedError = (error) => error instanceof PikkuError ||
|
|
15
|
+
export const isExpectedError = (error) => error instanceof PikkuError ||
|
|
16
|
+
error?.expected === true;
|
|
16
17
|
export const addError = (error, { status, message, mcpCode }) => {
|
|
17
18
|
pikkuState(null, 'misc', 'errors').set(error, mcpCode === undefined ? { status, message } : { status, message, mcpCode });
|
|
18
19
|
};
|
|
@@ -31,7 +32,8 @@ export const getErrorResponse = (error) => {
|
|
|
31
32
|
}
|
|
32
33
|
ctor = Object.getPrototypeOf(ctor);
|
|
33
34
|
}
|
|
34
|
-
const name = error
|
|
35
|
+
const name = error
|
|
36
|
+
?.constructor?.name;
|
|
35
37
|
return name
|
|
36
38
|
? Array.from(errors.entries()).find(([e]) => e.name === name)?.[1]
|
|
37
39
|
: undefined;
|
|
@@ -124,6 +124,23 @@ export const runPikkuFunc = async (wireType, wireId, funcName, { singletonServic
|
|
|
124
124
|
const previousAudit = invocationWire.audit;
|
|
125
125
|
const previousAddonNamespace = invocationWire.addonNamespace;
|
|
126
126
|
const previousRpcDescriptor = Object.getOwnPropertyDescriptor(invocationWire, 'rpc');
|
|
127
|
+
// knowledge: decisions/internals/core-function-runner-restores-the-wire-fields-it-overwrites.md
|
|
128
|
+
const restoreInvocationWire = () => {
|
|
129
|
+
if (previousRpcDescriptor) {
|
|
130
|
+
Object.defineProperty(invocationWire, 'rpc', previousRpcDescriptor);
|
|
131
|
+
}
|
|
132
|
+
restoreField('functionId', previousFunctionId);
|
|
133
|
+
restoreField('audit', previousAudit);
|
|
134
|
+
restoreField('addonNamespace', previousAddonNamespace);
|
|
135
|
+
};
|
|
136
|
+
function restoreField(key, previous) {
|
|
137
|
+
if (previous === undefined) {
|
|
138
|
+
delete invocationWire[key];
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
invocationWire[key] = previous;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
127
144
|
invocationWire.functionId = resolvedFunctionId;
|
|
128
145
|
invocationWire.audit = resolvedAuditConfig;
|
|
129
146
|
// Track which addon instance is executing so intra-addon sibling calls
|
|
@@ -187,6 +204,7 @@ export const runPikkuFunc = async (wireType, wireId, funcName, { singletonServic
|
|
|
187
204
|
services: keepsSecrets
|
|
188
205
|
? resolvedSingletonServices
|
|
189
206
|
: withoutSecrets(resolvedSingletonServices, 'a permission'),
|
|
207
|
+
// knowledge: decisions/security/a-permission-gets-a-wire-it-cannot-reply-on.md
|
|
190
208
|
wire: invocationWire,
|
|
191
209
|
data: actualData,
|
|
192
210
|
packageName,
|
|
@@ -244,53 +262,13 @@ export const runPikkuFunc = async (wireType, wireId, funcName, { singletonServic
|
|
|
244
262
|
return (await runMiddleware(resolvedSingletonServices, invocationWire, allMiddleware, executeFunction));
|
|
245
263
|
}
|
|
246
264
|
finally {
|
|
247
|
-
|
|
248
|
-
Object.defineProperty(invocationWire, 'rpc', previousRpcDescriptor);
|
|
249
|
-
}
|
|
250
|
-
if (previousFunctionId === undefined) {
|
|
251
|
-
delete invocationWire.functionId;
|
|
252
|
-
}
|
|
253
|
-
else {
|
|
254
|
-
invocationWire.functionId = previousFunctionId;
|
|
255
|
-
}
|
|
256
|
-
if (previousAudit === undefined) {
|
|
257
|
-
delete invocationWire.audit;
|
|
258
|
-
}
|
|
259
|
-
else {
|
|
260
|
-
invocationWire.audit = previousAudit;
|
|
261
|
-
}
|
|
262
|
-
if (previousAddonNamespace === undefined) {
|
|
263
|
-
delete invocationWire.addonNamespace;
|
|
264
|
-
}
|
|
265
|
-
else {
|
|
266
|
-
invocationWire.addonNamespace = previousAddonNamespace;
|
|
267
|
-
}
|
|
265
|
+
restoreInvocationWire();
|
|
268
266
|
}
|
|
269
267
|
}
|
|
270
268
|
try {
|
|
271
269
|
return (await executeFunction());
|
|
272
270
|
}
|
|
273
271
|
finally {
|
|
274
|
-
|
|
275
|
-
Object.defineProperty(invocationWire, 'rpc', previousRpcDescriptor);
|
|
276
|
-
}
|
|
277
|
-
if (previousFunctionId === undefined) {
|
|
278
|
-
delete invocationWire.functionId;
|
|
279
|
-
}
|
|
280
|
-
else {
|
|
281
|
-
invocationWire.functionId = previousFunctionId;
|
|
282
|
-
}
|
|
283
|
-
if (previousAudit === undefined) {
|
|
284
|
-
delete invocationWire.audit;
|
|
285
|
-
}
|
|
286
|
-
else {
|
|
287
|
-
invocationWire.audit = previousAudit;
|
|
288
|
-
}
|
|
289
|
-
if (previousAddonNamespace === undefined) {
|
|
290
|
-
delete invocationWire.addonNamespace;
|
|
291
|
-
}
|
|
292
|
-
else {
|
|
293
|
-
invocationWire.addonNamespace = previousAddonNamespace;
|
|
294
|
-
}
|
|
272
|
+
restoreInvocationWire();
|
|
295
273
|
}
|
|
296
274
|
};
|
|
@@ -5,11 +5,6 @@ import type { PikkuError } from '../errors/error-handler.js';
|
|
|
5
5
|
import type { CoreNodeConfig } from '../wirings/node/node.types.js';
|
|
6
6
|
import type { ScenarioSurface } from '../wirings/workflow/scenario-step.types.js';
|
|
7
7
|
import type { Safe } from '../secret-value.js';
|
|
8
|
-
/**
|
|
9
|
-
* @deprecated Use StandardSchemaV1 from @standard-schema/spec instead.
|
|
10
|
-
* This alias exists only for backward compatibility with generated code.
|
|
11
|
-
*/
|
|
12
|
-
export type ZodLike<T = any> = StandardSchemaV1<T, T>;
|
|
13
8
|
export type CorePikkuFunction<In, Out, Services extends CoreSecretlessSingletonServices = SecretlessServices<CoreServices>, Session extends CoreUserSession = CoreUserSession, Wire extends PikkuWire<In, Out, true, Session, PikkuRPC, null, string> = PikkuWire<In, Out, true, Session>> = (services: Services, data: In, wire: Wire) => Wire['channel'] extends null ? Promise<Safe<Out>> : Promise<Safe<Out>> | Promise<void>;
|
|
14
9
|
export type CorePikkuFunctionSessionless<In, Out, Services extends CoreSecretlessSingletonServices = SecretlessServices<CoreServices>, Session extends CoreUserSession = CoreUserSession, Wire extends PikkuWire<In, Out, false, Session, PikkuRPC, null, string> = PikkuWire<In, Out, false, Session>> = (services: Services, data: In, wire: Wire) => Wire['channel'] extends null ? Promise<Safe<Out>> : Promise<Safe<Out>> | Promise<void>;
|
|
15
10
|
export type CorePikkuPermission<In = any, Services extends CoreSecretlessSingletonServices = SecretlessServices<CoreServices>, Wire extends PikkuWire<In, never, false, any, PikkuRPC, never, never> = PikkuWire<In, never, false, any, PikkuRPC, never, never>> = (services: Services, data: In, wire: Wire) => Promise<boolean>;
|
|
@@ -33,6 +28,15 @@ export type CorePikkuAuthConfig<Services extends CoreSecretlessSingletonServices
|
|
|
33
28
|
name?: string;
|
|
34
29
|
description?: string;
|
|
35
30
|
};
|
|
31
|
+
/**
|
|
32
|
+
* Marks a permission produced by `pikkuAuth`, so agent tool filtering can tell a
|
|
33
|
+
* session check apart from an ordinary permission.
|
|
34
|
+
*
|
|
35
|
+
* knowledge: decisions/security/permission-auth-filtering-requires-live-permission-functions.md
|
|
36
|
+
*/
|
|
37
|
+
export type AuthBranded = {
|
|
38
|
+
__pikkuAuth?: true;
|
|
39
|
+
};
|
|
36
40
|
export declare const pikkuAuth: <Services extends CoreSecretlessSingletonServices = SecretlessServices<CoreServices>, Session extends CoreUserSession = CoreUserSession>(auth: CorePikkuAuth<Services, Session> | CorePikkuAuthConfig<Services, Session>) => CorePikkuPermission<any, Services, any>;
|
|
37
41
|
export type CorePermissionGroup<PikkuPermission = CorePikkuPermission<any>> = Record<string, PikkuPermission | PikkuPermission[]> | undefined;
|
|
38
42
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -3,22 +3,18 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export type { AuthInstance, CommonWireMeta, CoreConfig, CorePikkuMiddleware, CorePikkuMiddlewareConfig, CorePikkuMiddlewareFactory, CorePikkuMiddlewareGroup, CoreServices, CoreSecretlessSingletonServices, CoreSingletonServices, CoreUserSession, SecretlessServices, CreateConfig, ServerLifecycle, FunctionMeta, FunctionRuntimeMeta, FunctionServicesMeta, FunctionWiresMeta, FunctionsMeta, FunctionsRuntimeMeta, JSONPrimitive, JSONValue, MakeRequired, MiddlewareMetadata, MiddlewarePriority, PermissionMetadata, PickOptional, PickRequired, PikkuAIMiddlewareHooks, PikkuWire, PikkuRawWire, PikkuWiringTypes, PostgresConfig, RequireAtLeastOne, SecurityAuditIssue, SecurityAuditReport, SecurityAuditSummary, SecurityAuditUpdate, SecuritySeverity, SecurityUpdateLevel, SerializedError, WireServices, } from './types/core.types.js';
|
|
5
5
|
export { pikkuAIMiddleware, pikkuChannelMiddleware, pikkuChannelMiddlewareFactory, pikkuMiddleware, pikkuMiddlewareFactory, } from './types/core.types.js';
|
|
6
|
-
export type { CorePikkuAuth, CorePikkuAuthConfig, CorePikkuFunction, CorePikkuFunctionConfig, CorePikkuFunctionHook, CorePikkuPermission, CorePikkuPermissionConfig, CorePikkuPermissionFactory, CorePikkuApprovalDescription, CorePermissionGroup,
|
|
6
|
+
export type { CorePikkuAuth, CorePikkuAuthConfig, CorePikkuFunction, CorePikkuFunctionConfig, CorePikkuFunctionHook, CorePikkuPermission, CorePikkuPermissionConfig, CorePikkuPermissionFactory, CorePikkuApprovalDescription, CorePermissionGroup, } from './function/functions.types.js';
|
|
7
7
|
export { pikkuAuth, pikkuPermission, pikkuPermissionFactory, pikkuApprovalDescription, } from './function/functions.types.js';
|
|
8
|
-
export {
|
|
8
|
+
export { getAllFunctionNames } from './function/index.js';
|
|
9
9
|
export type { ListInput, ListOutput, Filter, LeafFilter, LeafValue, } from './function/list.types.js';
|
|
10
|
+
export { pikkuCLIRender } from './wirings/cli/cli-runner.js';
|
|
10
11
|
export { PikkuRequest } from './pikku-request.js';
|
|
11
12
|
export { getRelativeTimeOffsetFromNow, parseDurationString, } from './time-utils.js';
|
|
12
13
|
export type { RelativeTimeInput } from './time-utils.js';
|
|
13
14
|
export { formatVersionedId, isVersionedId, parseVersionedId, } from './version.js';
|
|
14
|
-
export { runPikkuFunc } from './function/function-runner.js';
|
|
15
15
|
export { AbandonedError, beginChanges, getAbortScope, runInAbortScope, type AbortScope, } from './function/abort-scope.js';
|
|
16
|
-
export { runCLICommand, pikkuCLIRender } from './wirings/cli/cli-runner.js';
|
|
17
16
|
export { fetch } from './wirings/http/http-runner.js';
|
|
18
|
-
export { runMCPTool, runMCPResource, runMCPPrompt, } from './wirings/mcp/mcp-runner.js';
|
|
19
17
|
export type { MCPToolResponse, MCPResourceResponse, MCPPromptResponse, } from './wirings/mcp/mcp.types.js';
|
|
20
|
-
export { runQueueJob } from './wirings/queue/queue-runner.js';
|
|
21
|
-
export { runScheduledTask } from './wirings/scheduler/scheduler-runner.js';
|
|
22
18
|
export { AIProviderAuthError, AIProviderNotConfiguredError, BadGatewayError, BadRequestError, ConflictError, ExpectationFailedError, ForbiddenError, GatewayTimeoutError, GoneError, HTTPVersionNotSupportedError, InternalServerError, InvalidMiddlewareWireError, InvalidOriginError, InvalidSessionError, LengthRequiredError, LocalEnvironmentOnlyError, LockedError, MaxComputeTimeReachedError, MethodNotAllowedError, MissingCredentialError, MissingSchemaError, MissingScopeError, MissingServiceError, MissingSessionError, NotAcceptableError, NotFoundError, NotImplementedError, PayloadTooLargeError, PaymentRequiredError, PikkuMissingMetaError, PreconditionFailedError, ProxyAuthenticationRequiredError, RangeNotSatisfiableError, ReadonlySessionError, RequestTimeoutError, ServiceUnavailableError, TooManyRequestsError, URITooLongError, UnauthorizedError, UnprocessableContentError, UnsupportedMediaTypeError, } from './errors/errors.js';
|
|
23
19
|
export { PikkuError, isExpectedError } from './errors/error-handler.js';
|
|
24
20
|
export type { EventHubService } from './wirings/channel/eventhub-service.js';
|
|
@@ -51,11 +47,10 @@ export type { WireAddonConfig } from './wirings/rpc/wire-addon.js';
|
|
|
51
47
|
export { wireRemoteAddon } from './wirings/rpc/wire-remote-addon.js';
|
|
52
48
|
export type { WireRemoteAddonConfig, RemoteAddonAuth, } from './wirings/rpc/wire-remote-addon.js';
|
|
53
49
|
export type { PikkuPackageState } from './types/state.types.js';
|
|
54
|
-
export { runMiddleware, addTagMiddleware
|
|
50
|
+
export { runMiddleware, addTagMiddleware } from './middleware-runner.js';
|
|
55
51
|
export { addGlobalPermission, checkAuthPermissions } from './permissions.js';
|
|
56
52
|
export { hasScopes, verifyScopes } from './scopes.js';
|
|
57
53
|
export { isSerializable, stopSingletonServices, pikkuServerLifecycle, } from './utils.js';
|
|
58
|
-
export { getSingletonServices, getCreateWireServices, setSingletonServices, } from './pikku-state.js';
|
|
59
54
|
export { clearPikkuRuntimeState } from './test-utils.js';
|
|
60
55
|
export { type ScheduledTaskInfo, type ScheduledTaskSummary, } from './services/scheduler-service.js';
|
|
61
56
|
export { SchedulerService } from './services/scheduler-service.js';
|
package/dist/index.js
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
export { pikkuAIMiddleware, pikkuChannelMiddleware, pikkuChannelMiddlewareFactory, pikkuMiddleware, pikkuMiddlewareFactory, } from './types/core.types.js';
|
|
2
2
|
export { pikkuAuth, pikkuPermission, pikkuPermissionFactory, pikkuApprovalDescription, } from './function/functions.types.js';
|
|
3
|
-
export {
|
|
3
|
+
export { getAllFunctionNames } from './function/index.js';
|
|
4
|
+
export { pikkuCLIRender } from './wirings/cli/cli-runner.js';
|
|
4
5
|
export { PikkuRequest } from './pikku-request.js';
|
|
5
6
|
export { getRelativeTimeOffsetFromNow, parseDurationString, } from './time-utils.js';
|
|
6
7
|
export { formatVersionedId, isVersionedId, parseVersionedId, } from './version.js';
|
|
7
|
-
export { runPikkuFunc } from './function/function-runner.js';
|
|
8
8
|
export { AbandonedError, beginChanges, getAbortScope, runInAbortScope, } from './function/abort-scope.js';
|
|
9
|
-
export { runCLICommand, pikkuCLIRender } from './wirings/cli/cli-runner.js';
|
|
10
9
|
export { fetch } from './wirings/http/http-runner.js';
|
|
11
|
-
export { runMCPTool, runMCPResource, runMCPPrompt, } from './wirings/mcp/mcp-runner.js';
|
|
12
|
-
export { runQueueJob } from './wirings/queue/queue-runner.js';
|
|
13
|
-
export { runScheduledTask } from './wirings/scheduler/scheduler-runner.js';
|
|
14
10
|
export { AIProviderAuthError, AIProviderNotConfiguredError, BadGatewayError, BadRequestError, ConflictError, ExpectationFailedError, ForbiddenError, GatewayTimeoutError, GoneError, HTTPVersionNotSupportedError, InternalServerError, InvalidMiddlewareWireError, InvalidOriginError, InvalidSessionError, LengthRequiredError, LocalEnvironmentOnlyError, LockedError, MaxComputeTimeReachedError, MethodNotAllowedError, MissingCredentialError, MissingSchemaError, MissingScopeError, MissingServiceError, MissingSessionError, NotAcceptableError, NotFoundError, NotImplementedError, PayloadTooLargeError, PaymentRequiredError, PikkuMissingMetaError, PreconditionFailedError, ProxyAuthenticationRequiredError, RangeNotSatisfiableError, ReadonlySessionError, RequestTimeoutError, ServiceUnavailableError, TooManyRequestsError, URITooLongError, UnauthorizedError, UnprocessableContentError, UnsupportedMediaTypeError, } from './errors/errors.js';
|
|
15
11
|
export { PikkuError, isExpectedError } from './errors/error-handler.js';
|
|
16
12
|
export { SecretAccessDeniedError, withoutSecrets, } from './services/secretless.js';
|
|
@@ -19,11 +15,10 @@ export { NoopAuditService, createInvocationAudit, resolveAuditConfig, resolveAud
|
|
|
19
15
|
export { createGraph } from './wirings/workflow/graph/graph-node.js';
|
|
20
16
|
export { wireAddon } from './wirings/rpc/wire-addon.js';
|
|
21
17
|
export { wireRemoteAddon } from './wirings/rpc/wire-remote-addon.js';
|
|
22
|
-
export { runMiddleware, addTagMiddleware
|
|
18
|
+
export { runMiddleware, addTagMiddleware } from './middleware-runner.js';
|
|
23
19
|
export { addGlobalPermission, checkAuthPermissions } from './permissions.js';
|
|
24
20
|
export { hasScopes, verifyScopes } from './scopes.js';
|
|
25
21
|
export { isSerializable, stopSingletonServices, pikkuServerLifecycle, } from './utils.js';
|
|
26
|
-
export { getSingletonServices, getCreateWireServices, setSingletonServices, } from './pikku-state.js';
|
|
27
22
|
export { clearPikkuRuntimeState } from './test-utils.js';
|
|
28
23
|
export { SchedulerService } from './services/scheduler-service.js';
|
|
29
24
|
export { hashToken, unsafeAsWrapped, unsafeAsSealed, unsafeAsHashed, } from './column-form.js';
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import type { SerializeOptions } from 'cookie';
|
|
2
2
|
import type { RelativeTimeInput } from '../time-utils.js';
|
|
3
|
-
/**
|
|
4
|
-
* Reads a JWT session from a cookie, and re-issues the cookie after the
|
|
5
|
-
* request whenever the session changed (e.g. after login).
|
|
6
|
-
*/
|
|
7
3
|
export declare const authCookie: import("../types/core.types.js").CorePikkuMiddlewareFactory<{
|
|
8
4
|
name: string;
|
|
9
5
|
options: SerializeOptions;
|
|
@@ -4,6 +4,26 @@ import { getRelativeTimeOffsetFromNow } from '../time-utils.js';
|
|
|
4
4
|
* Reads a JWT session from a cookie, and re-issues the cookie after the
|
|
5
5
|
* request whenever the session changed (e.g. after login).
|
|
6
6
|
*/
|
|
7
|
+
/** Standard JWT registered claims — present on a token even with no session. */
|
|
8
|
+
const JWT_REGISTERED_CLAIMS = new Set([
|
|
9
|
+
'iat',
|
|
10
|
+
'exp',
|
|
11
|
+
'nbf',
|
|
12
|
+
'iss',
|
|
13
|
+
'aud',
|
|
14
|
+
'sub',
|
|
15
|
+
'jti',
|
|
16
|
+
]);
|
|
17
|
+
/**
|
|
18
|
+
* Whether a decoded payload carries an actual session, as opposed to being
|
|
19
|
+
* absent or a bare JWT envelope of `{ iat, exp }`. True only for a non-null
|
|
20
|
+
* object with at least one key that is not a registered JWT claim.
|
|
21
|
+
*/
|
|
22
|
+
const hasSessionIdentity = (session) => {
|
|
23
|
+
if (!session || typeof session !== 'object')
|
|
24
|
+
return false;
|
|
25
|
+
return Object.keys(session).some((key) => !JWT_REGISTERED_CLAIMS.has(key));
|
|
26
|
+
};
|
|
7
27
|
export const authCookie = pikkuMiddlewareFactory(({ name, options, expiresIn }) => {
|
|
8
28
|
const mergedOptions = {
|
|
9
29
|
httpOnly: true,
|
|
@@ -19,7 +39,12 @@ export const authCookie = pikkuMiddlewareFactory(({ name, options, expiresIn })
|
|
|
19
39
|
const cookieValue = http.request.cookie(name);
|
|
20
40
|
if (cookieValue && jwtService) {
|
|
21
41
|
const userSession = await jwtService.decode(cookieValue);
|
|
22
|
-
|
|
42
|
+
// Not just truthy: a JWT of an absent session still decodes to a
|
|
43
|
+
// `{ iat, exp }` object, which is truthy and which the function runner
|
|
44
|
+
// would accept as a session. Require at least one claim that is not a
|
|
45
|
+
// standard JWT timestamp, so an identity-less token is treated as no
|
|
46
|
+
// session rather than as an authenticated one.
|
|
47
|
+
if (userSession && hasSessionIdentity(userSession)) {
|
|
23
48
|
setSession?.(userSession);
|
|
24
49
|
}
|
|
25
50
|
}
|
|
@@ -29,7 +54,18 @@ export const authCookie = pikkuMiddlewareFactory(({ name, options, expiresIn })
|
|
|
29
54
|
}
|
|
30
55
|
if (hasSessionChanged?.()) {
|
|
31
56
|
const currentSession = await getSession?.();
|
|
32
|
-
|
|
57
|
+
// Logout path: `clearSession()` marks the session changed while leaving
|
|
58
|
+
// it absent. Re-signing that into a fresh, unexpired cookie would hand
|
|
59
|
+
// the browser a credential on the way out — so clear the cookie instead
|
|
60
|
+
// of minting one, and never call `encode` with an absent session.
|
|
61
|
+
if (!hasSessionIdentity(currentSession)) {
|
|
62
|
+
http.response.cookie(name, '', {
|
|
63
|
+
...mergedOptions,
|
|
64
|
+
expires: new Date(0),
|
|
65
|
+
maxAge: 0,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
else if (jwtService) {
|
|
33
69
|
http.response.cookie(name, await jwtService.encode(expiresIn, currentSession), {
|
|
34
70
|
...mergedOptions,
|
|
35
71
|
expires: getRelativeTimeOffsetFromNow(expiresIn),
|
package/dist/middleware/cors.js
CHANGED
|
@@ -45,6 +45,7 @@ export const cors = pikkuMiddlewareFactory(({ origin = '*', methods = ['GET', 'P
|
|
|
45
45
|
}
|
|
46
46
|
if (request.method() === 'options') {
|
|
47
47
|
response.header('Access-Control-Max-Age', String(maxAge));
|
|
48
|
+
// 204 carries no body, and `json` has no no-content overload.
|
|
48
49
|
response.status(204).json(undefined);
|
|
49
50
|
return;
|
|
50
51
|
}
|
|
@@ -5,4 +5,4 @@ export { pikkuRemoteAuthMiddleware } from './remote-auth.js';
|
|
|
5
5
|
export { cors } from './cors.js';
|
|
6
6
|
export { telemetryOuter, telemetryInner } from './telemetry.js';
|
|
7
7
|
export { addTagMiddleware, addTagMiddleware as addMiddleware, addGlobalMiddleware, runMiddleware, } from '../middleware-runner.js';
|
|
8
|
-
export { addGlobalPermission
|
|
8
|
+
export { addGlobalPermission } from '../permissions.js';
|
package/dist/middleware/index.js
CHANGED
|
@@ -5,4 +5,4 @@ export { pikkuRemoteAuthMiddleware } from './remote-auth.js';
|
|
|
5
5
|
export { cors } from './cors.js';
|
|
6
6
|
export { telemetryOuter, telemetryInner } from './telemetry.js';
|
|
7
7
|
export { addTagMiddleware, addTagMiddleware as addMiddleware, addGlobalMiddleware, runMiddleware, } from '../middleware-runner.js';
|
|
8
|
-
export { addGlobalPermission
|
|
8
|
+
export { addGlobalPermission } from '../permissions.js';
|