@pikku/core 0.12.79 → 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 +161 -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.js +2 -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/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 +9 -2
- 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 -2
- 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 +28 -147
- package/dist/wirings/workflow/pikku-workflow-service.js +71 -493
- 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/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 +13 -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 +2 -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/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-channel-meta.test.ts +44 -0
- package/src/wirings/gateway/gateway-runner.ts +27 -19
- 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 +22 -0
- package/src/wirings/secret/validate-secret-definitions.ts +2 -2
- 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 +190 -743
- 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-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
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { NotFoundError } from '../../errors/errors.js'
|
|
2
2
|
import { addFunction } from '../../function/function-runner.js'
|
|
3
|
-
import type {
|
|
3
|
+
import type { CorePikkuFunctionConfig } from '../../function/functions.types.js'
|
|
4
4
|
import { pikkuState, getSingletonServices } from '../../pikku-state.js'
|
|
5
5
|
import { coerceTopLevelDataFromSchema, validateSchema } from '../../schema.js'
|
|
6
6
|
import type { SessionService } from '../../services/user-session-service.js'
|
|
7
|
-
import type { CorePikkuMiddleware } from '../../types/core.types.js'
|
|
8
7
|
import { httpRouter } from '../http/routers/http-router.js'
|
|
9
8
|
import type {
|
|
10
9
|
ChannelMeta,
|
|
@@ -13,19 +12,34 @@ import type {
|
|
|
13
12
|
RunChannelParams,
|
|
14
13
|
} from './channel.types.js'
|
|
15
14
|
|
|
15
|
+
type HandlerConfig = CorePikkuFunctionConfig<any, any>
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The config to register for a channel handler: the handler itself when it is a
|
|
19
|
+
* direct function config, or its inner `func` when it is a wrapper.
|
|
20
|
+
*
|
|
21
|
+
* knowledge: decisions/internals/channel-message-handlers-accept-three-config-shapes.md
|
|
22
|
+
*/
|
|
23
|
+
const registeredHandler = (handler: unknown): HandlerConfig => {
|
|
24
|
+
const candidate = handler as { func?: unknown }
|
|
25
|
+
return typeof candidate.func === 'function'
|
|
26
|
+
? (handler as HandlerConfig)
|
|
27
|
+
: (candidate.func as HandlerConfig)
|
|
28
|
+
}
|
|
29
|
+
|
|
16
30
|
export const wireChannel = <
|
|
17
31
|
In,
|
|
18
32
|
Channel extends string,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
33
|
+
ChannelConnect,
|
|
34
|
+
ChannelDisconnect,
|
|
35
|
+
ChannelFunctionMessage,
|
|
22
36
|
>(
|
|
23
37
|
channel: CoreChannel<
|
|
24
38
|
In,
|
|
25
39
|
Channel,
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
40
|
+
ChannelConnect,
|
|
41
|
+
ChannelDisconnect,
|
|
42
|
+
ChannelFunctionMessage
|
|
29
43
|
>
|
|
30
44
|
) => {
|
|
31
45
|
const channelsMeta = pikkuState(null, 'channel', 'meta')
|
|
@@ -38,19 +52,23 @@ export const wireChannel = <
|
|
|
38
52
|
}
|
|
39
53
|
|
|
40
54
|
if (channel.onConnect && channelMeta.connect) {
|
|
41
|
-
addFunction(
|
|
55
|
+
addFunction(
|
|
56
|
+
channelMeta.connect.pikkuFuncId,
|
|
57
|
+
registeredHandler(channel.onConnect)
|
|
58
|
+
)
|
|
42
59
|
}
|
|
43
60
|
|
|
44
61
|
if (channel.onDisconnect && channelMeta.disconnect) {
|
|
45
|
-
addFunction(
|
|
62
|
+
addFunction(
|
|
63
|
+
channelMeta.disconnect.pikkuFuncId,
|
|
64
|
+
registeredHandler(channel.onDisconnect)
|
|
65
|
+
)
|
|
46
66
|
}
|
|
47
67
|
|
|
48
68
|
if (channel.onMessage && channelMeta.message?.pikkuFuncId) {
|
|
49
69
|
addFunction(
|
|
50
70
|
channelMeta.message.pikkuFuncId,
|
|
51
|
-
(channel.onMessage
|
|
52
|
-
? channel.onMessage
|
|
53
|
-
: (channel.onMessage as any).func
|
|
71
|
+
registeredHandler(channel.onMessage)
|
|
54
72
|
)
|
|
55
73
|
}
|
|
56
74
|
|
|
@@ -63,17 +81,12 @@ export const wireChannel = <
|
|
|
63
81
|
const wiringMeta = channelWirings[wiringKey]
|
|
64
82
|
if (!wiringMeta) return
|
|
65
83
|
|
|
66
|
-
addFunction(
|
|
67
|
-
wiringMeta.pikkuFuncId,
|
|
68
|
-
(handler as any).func instanceof Function
|
|
69
|
-
? handler
|
|
70
|
-
: (handler as any).func
|
|
71
|
-
)
|
|
84
|
+
addFunction(wiringMeta.pikkuFuncId, registeredHandler(handler))
|
|
72
85
|
})
|
|
73
86
|
})
|
|
74
87
|
}
|
|
75
88
|
|
|
76
|
-
pikkuState(null, 'channel', 'channels').set(channel.name, channel
|
|
89
|
+
pikkuState(null, 'channel', 'channels').set(channel.name, channel)
|
|
77
90
|
}
|
|
78
91
|
|
|
79
92
|
const getMatchingChannelConfig = (path: string) => {
|
|
@@ -64,6 +64,8 @@ export interface ChannelMeta {
|
|
|
64
64
|
message: ChannelMessageMeta | null
|
|
65
65
|
messageWirings: Record<string, Record<string, ChannelMessageMeta>>
|
|
66
66
|
binary?: boolean | null
|
|
67
|
+
/** Set when the channel was wired by a gateway rather than declared directly. */
|
|
68
|
+
gateway?: boolean
|
|
67
69
|
summary?: string
|
|
68
70
|
description?: string
|
|
69
71
|
errors?: string[]
|
|
@@ -34,7 +34,8 @@ export abstract class PikkuAbstractChannelHandler<
|
|
|
34
34
|
setState: (s) => {
|
|
35
35
|
channelState = s
|
|
36
36
|
},
|
|
37
|
-
|
|
37
|
+
// knowledge: decisions/internals/channel-state-accessors-are-unsound-generics-that-every-implementation-asserts.md
|
|
38
|
+
getState: () => channelState as never,
|
|
38
39
|
clearState: () => {
|
|
39
40
|
channelState = undefined
|
|
40
41
|
},
|
|
@@ -117,7 +117,8 @@ export const runChannelConnect = async ({
|
|
|
117
117
|
channelName: channelConfig.name,
|
|
118
118
|
})
|
|
119
119
|
channel.setState = (state) => channelStore.setState(channelId, state)
|
|
120
|
-
|
|
120
|
+
// knowledge: decisions/internals/channel-state-accessors-are-unsound-generics-that-every-implementation-asserts.md
|
|
121
|
+
channel.getState = () => channelStore.getState(channelId) as never
|
|
121
122
|
channel.clearState = () => channelStore.clearState(channelId)
|
|
122
123
|
|
|
123
124
|
const wire: PikkuRawWire = {
|
|
@@ -198,7 +199,8 @@ export const runChannelDisconnect = async ({
|
|
|
198
199
|
channelName,
|
|
199
200
|
})
|
|
200
201
|
channel.setState = (state) => channelStore.setState(channelId, state)
|
|
201
|
-
|
|
202
|
+
// knowledge: decisions/internals/channel-state-accessors-are-unsound-generics-that-every-implementation-asserts.md
|
|
203
|
+
channel.getState = () => channelStore.getState(channelId) as never
|
|
202
204
|
channel.clearState = () => channelStore.clearState(channelId)
|
|
203
205
|
|
|
204
206
|
const userSession = new PikkuSessionService<CoreUserSession>(
|
|
@@ -271,7 +273,8 @@ export const runChannelMessage = async (
|
|
|
271
273
|
channelName,
|
|
272
274
|
})
|
|
273
275
|
channel.setState = (state) => channelStore.setState(channelId, state)
|
|
274
|
-
|
|
276
|
+
// knowledge: decisions/internals/channel-state-accessors-are-unsound-generics-that-every-implementation-asserts.md
|
|
277
|
+
channel.getState = () => channelStore.getState(channelId) as never
|
|
275
278
|
channel.clearState = () => channelStore.clearState(channelId)
|
|
276
279
|
|
|
277
280
|
const userSession = new PikkuSessionService<CoreUserSession>(
|
|
@@ -90,7 +90,9 @@ export async function executeCLIViaChannel({
|
|
|
90
90
|
return
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
|
|
93
|
+
// A CLI channel response is rendered off-process: there are no services
|
|
94
|
+
// to hand the renderer, and every CLI renderer ignores the argument.
|
|
95
|
+
renderer(null as never, response, undefined)
|
|
94
96
|
}
|
|
95
97
|
|
|
96
98
|
commandRoute.subscribe(commandId, responseHandler)
|
|
@@ -32,7 +32,10 @@ export type CorePikkuCLIClientRender<Data> = (
|
|
|
32
32
|
) => void | Promise<void>
|
|
33
33
|
|
|
34
34
|
/** The normal case once the server owns the command tree. */
|
|
35
|
-
const defaultJSONRenderer: CorePikkuCLIClientRender<any> = (
|
|
35
|
+
const defaultJSONRenderer: CorePikkuCLIClientRender<any> = (
|
|
36
|
+
_services,
|
|
37
|
+
data
|
|
38
|
+
) => {
|
|
36
39
|
console.log(JSON.stringify(data))
|
|
37
40
|
}
|
|
38
41
|
|
|
@@ -16,6 +16,7 @@ import type {
|
|
|
16
16
|
CLIMeta,
|
|
17
17
|
} from './cli.types.js'
|
|
18
18
|
import type {
|
|
19
|
+
CoreConfig,
|
|
19
20
|
CoreSingletonServices,
|
|
20
21
|
CoreServices,
|
|
21
22
|
CreateWireServices,
|
|
@@ -24,7 +25,7 @@ import type {
|
|
|
24
25
|
CreateSingletonServices,
|
|
25
26
|
} from '../../types/core.types.js'
|
|
26
27
|
import type { PikkuChannel } from '../channel/channel.types.js'
|
|
27
|
-
import { unsupportedChannelRemote } from '../channel/channel-rpc.js'
|
|
28
|
+
import { unsupportedChannelRemote } from '../channel/channel-rpc.types.js'
|
|
28
29
|
import {
|
|
29
30
|
PikkuSessionService,
|
|
30
31
|
createMiddlewareSessionWireProps,
|
|
@@ -321,7 +322,8 @@ export async function runCLICommand({
|
|
|
321
322
|
setState: (s) => {
|
|
322
323
|
cliState = s
|
|
323
324
|
},
|
|
324
|
-
|
|
325
|
+
// knowledge: decisions/internals/channel-state-accessors-are-unsound-generics-that-every-implementation-asserts.md
|
|
326
|
+
getState: () => cliState as never,
|
|
325
327
|
clearState: () => {
|
|
326
328
|
cliState = undefined
|
|
327
329
|
},
|
|
@@ -372,7 +374,8 @@ export async function runCLICommand({
|
|
|
372
374
|
if (result !== undefined && !onOutput) {
|
|
373
375
|
const commandRenderer = programData?.renderers[commandId]
|
|
374
376
|
const jsonMode =
|
|
375
|
-
(data as
|
|
377
|
+
(data as { json?: unknown; output?: unknown }).json === true ||
|
|
378
|
+
(data as { json?: unknown; output?: unknown }).output === 'json'
|
|
376
379
|
const finalRenderer: CorePikkuCLIRender<any> | undefined =
|
|
377
380
|
jsonMode && commandRenderer !== undefined
|
|
378
381
|
? defaultJSONRenderer
|
|
@@ -491,7 +494,7 @@ export async function executeCLI({
|
|
|
491
494
|
|
|
492
495
|
const config = createConfig
|
|
493
496
|
? await createConfig(new LocalVariablesService(), data)
|
|
494
|
-
: ({} as
|
|
497
|
+
: ({} as CoreConfig)
|
|
495
498
|
|
|
496
499
|
const singletonServices = await createSingletonServices(config)
|
|
497
500
|
pikkuState(null, 'package', 'singletonServices', singletonServices)
|
|
@@ -197,18 +197,6 @@ export type ValidateParameters<Params extends string, Input> =
|
|
|
197
197
|
? Params
|
|
198
198
|
: never
|
|
199
199
|
|
|
200
|
-
/**
|
|
201
|
-
* Extract output type from a Pikku function config type
|
|
202
|
-
*/
|
|
203
|
-
export type ExtractFunctionOutput<Func> =
|
|
204
|
-
Func extends CorePikkuFunctionConfig<infer FuncType, any, any>
|
|
205
|
-
? FuncType extends
|
|
206
|
-
| CorePikkuFunction<any, infer Output, any, any, any>
|
|
207
|
-
| CorePikkuFunctionSessionless<any, infer Output, any, any, any>
|
|
208
|
-
? Output
|
|
209
|
-
: never
|
|
210
|
-
: never
|
|
211
|
-
|
|
212
200
|
/**
|
|
213
201
|
* CLI command configuration that infers options from function input type.
|
|
214
202
|
* This is a helper type for creating type-safe CLI commands.
|
|
@@ -290,33 +278,6 @@ export type CLICommandShorthand<
|
|
|
290
278
|
>,
|
|
291
279
|
> = PikkuFunctionConfig
|
|
292
280
|
|
|
293
|
-
/**
|
|
294
|
-
* Command definition (either full or shorthand)
|
|
295
|
-
*/
|
|
296
|
-
export type CLICommandDefinition<
|
|
297
|
-
In,
|
|
298
|
-
Out,
|
|
299
|
-
PikkuFunctionConfig extends CorePikkuFunctionConfig<
|
|
300
|
-
| CorePikkuFunction<In, Out, any, any, any>
|
|
301
|
-
| CorePikkuFunctionSessionless<In, Out, any, any, any>
|
|
302
|
-
>,
|
|
303
|
-
PikkuPermission extends CorePikkuPermission<any, any, any>,
|
|
304
|
-
PikkuMiddleware extends CorePikkuMiddleware,
|
|
305
|
-
Options = any,
|
|
306
|
-
Subcommands extends Record<string, CoreCLICommandConfig<any, any, any>> =
|
|
307
|
-
Record<string, CoreCLICommandConfig<any, any, any>>,
|
|
308
|
-
> =
|
|
309
|
-
| CoreCLICommand<
|
|
310
|
-
In,
|
|
311
|
-
Out,
|
|
312
|
-
PikkuFunctionConfig,
|
|
313
|
-
PikkuPermission,
|
|
314
|
-
PikkuMiddleware,
|
|
315
|
-
Options,
|
|
316
|
-
Subcommands
|
|
317
|
-
>
|
|
318
|
-
| CLICommandShorthand<In, Out, PikkuFunctionConfig>
|
|
319
|
-
|
|
320
281
|
/**
|
|
321
282
|
* CLI wiring configuration
|
|
322
283
|
*/
|
|
@@ -710,5 +710,24 @@ describe('Command Parser', () => {
|
|
|
710
710
|
assert.ok(result.errors.some((e) => e.includes('Unknown option: -x')))
|
|
711
711
|
assert.deepStrictEqual(result.warnings, [])
|
|
712
712
|
})
|
|
713
|
+
describe('short-flag cluster is bounded (DoS)', () => {
|
|
714
|
+
test('a huge short-flag cluster yields a single error, not one per char', () => {
|
|
715
|
+
const huge = '-' + 'a'.repeat(200_000)
|
|
716
|
+
const result = parseCLIArguments(
|
|
717
|
+
['greet', 'Alice', huge],
|
|
718
|
+
'test-cli',
|
|
719
|
+
testMeta
|
|
720
|
+
)
|
|
721
|
+
const clusterErrors = result.errors.filter((e) =>
|
|
722
|
+
e.includes('Unknown option')
|
|
723
|
+
)
|
|
724
|
+
// Without the cap this would be ~200k errors (one per character).
|
|
725
|
+
assert.ok(
|
|
726
|
+
clusterErrors.length <= 2,
|
|
727
|
+
`expected the oversized cluster to collapse to a single error, got ${clusterErrors.length}`
|
|
728
|
+
)
|
|
729
|
+
assert.ok(result.errors.some((e) => e.includes('too long')))
|
|
730
|
+
})
|
|
731
|
+
})
|
|
713
732
|
})
|
|
714
733
|
})
|
|
@@ -86,6 +86,15 @@ export interface ParsedCommand {
|
|
|
86
86
|
warnings: string[]
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
/**
|
|
90
|
+
* A real short-flag cluster is a handful of characters (`-abc`). Anything past
|
|
91
|
+
* this is treated as a single malformed token rather than scanned per
|
|
92
|
+
* character — the parser runs over untrusted CLI-channel frames, and a
|
|
93
|
+
* multi-megabyte `-aaaa…` would otherwise be O(length) work that also pushed
|
|
94
|
+
* one error per character.
|
|
95
|
+
*/
|
|
96
|
+
const MAX_SHORT_FLAG_CLUSTER = 64
|
|
97
|
+
|
|
89
98
|
export function parseCLIArguments(
|
|
90
99
|
args: string[],
|
|
91
100
|
programName: string,
|
|
@@ -238,6 +247,13 @@ export function parseCLIArguments(
|
|
|
238
247
|
}
|
|
239
248
|
}
|
|
240
249
|
} else if (arg.startsWith('-') && arg.length > 1) {
|
|
250
|
+
if (arg.length > MAX_SHORT_FLAG_CLUSTER) {
|
|
251
|
+
result.errors.push(
|
|
252
|
+
`Unknown option: ${arg.slice(0, MAX_SHORT_FLAG_CLUSTER)}… (too long)`
|
|
253
|
+
)
|
|
254
|
+
currentIndex++
|
|
255
|
+
continue
|
|
256
|
+
}
|
|
241
257
|
for (let i = 1; i < arg.length; i++) {
|
|
242
258
|
const shortFlag = arg[i]
|
|
243
259
|
|
|
@@ -354,7 +370,7 @@ function parseOptionValue(value: string, optionDef?: CLIOption): any {
|
|
|
354
370
|
return parseFloat(value)
|
|
355
371
|
}
|
|
356
372
|
|
|
357
|
-
if (optionDef.choices && !optionDef.choices.includes(value as
|
|
373
|
+
if (optionDef.choices && !optionDef.choices.includes(value as never)) {
|
|
358
374
|
// Deliberately not an error here — applyOptionDefaults reports bad choices.
|
|
359
375
|
return value
|
|
360
376
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { describe, test } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
|
|
4
|
+
import { pikkuState, resetPikkuState } from '../../pikku-state.js'
|
|
5
|
+
import { wireGateway } from './gateway-runner.js'
|
|
6
|
+
|
|
7
|
+
const wireWebsocketGateway = (name: string) => {
|
|
8
|
+
resetPikkuState()
|
|
9
|
+
wireGateway({
|
|
10
|
+
name,
|
|
11
|
+
type: 'websocket',
|
|
12
|
+
route: `/${name}`,
|
|
13
|
+
adapter: { name: 'test', parse: () => null, send: async () => {} },
|
|
14
|
+
func: { func: async () => undefined },
|
|
15
|
+
} as any)
|
|
16
|
+
return pikkuState(null, 'channel', 'meta')[name]!
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
describe('a gateway-wired websocket channel writes complete channel meta', () => {
|
|
20
|
+
test('the fields every channel reader indexes are present', () => {
|
|
21
|
+
const meta = wireWebsocketGateway('chatGateway')
|
|
22
|
+
|
|
23
|
+
// channel-handler.ts indexes messageWirings without a guard, and the
|
|
24
|
+
// serverless and local runners read disconnect directly.
|
|
25
|
+
assert.deepEqual(
|
|
26
|
+
meta.messageWirings,
|
|
27
|
+
{},
|
|
28
|
+
'messageWirings must be an object — channel-handler indexes it unguarded'
|
|
29
|
+
)
|
|
30
|
+
assert.equal(meta.disconnect, null)
|
|
31
|
+
assert.equal(meta.input, null)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
test('it is marked as gateway-wired', () => {
|
|
35
|
+
assert.equal(wireWebsocketGateway('flagged').gateway, true)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
test('connect and message point at the generated handlers', () => {
|
|
39
|
+
const meta = wireWebsocketGateway('handlers')
|
|
40
|
+
|
|
41
|
+
assert.equal(meta.connect?.pikkuFuncId, 'gateway__handlers__connect')
|
|
42
|
+
assert.equal(meta.message?.pikkuFuncId, 'gateway__handlers__message')
|
|
43
|
+
})
|
|
44
|
+
})
|
|
@@ -3,6 +3,7 @@ import { NotFoundError, UnauthorizedError } from '../../errors/errors.js'
|
|
|
3
3
|
import { addFunction, runPikkuFunc } from '../../function/function-runner.js'
|
|
4
4
|
import { runMiddleware } from '../../middleware-runner.js'
|
|
5
5
|
import { httpRouter } from '../http/routers/http-router.js'
|
|
6
|
+
import type { CoreHTTPFunctionWiring } from '../http/http.types.js'
|
|
6
7
|
import type {
|
|
7
8
|
CoreGateway,
|
|
8
9
|
GatewayAdapter,
|
|
@@ -50,7 +51,7 @@ const registerGatewayHandler = (config: CoreGateway): string => {
|
|
|
50
51
|
outputSchemaName: declared?.outputSchemaName ?? null,
|
|
51
52
|
sessionless: declared?.sessionless ?? true,
|
|
52
53
|
}
|
|
53
|
-
addFunction(funcId, config.func
|
|
54
|
+
addFunction(funcId, config.func)
|
|
54
55
|
return funcId
|
|
55
56
|
}
|
|
56
57
|
|
|
@@ -99,7 +100,7 @@ export const wireGateway = (config: CoreGateway): void => {
|
|
|
99
100
|
break
|
|
100
101
|
default:
|
|
101
102
|
throw new Error(
|
|
102
|
-
`Unknown gateway type '${
|
|
103
|
+
`Unknown gateway type '${config.type}' for gateway '${config.name}'`
|
|
103
104
|
)
|
|
104
105
|
}
|
|
105
106
|
}
|
|
@@ -118,7 +119,7 @@ const wireWebhookGateway = (config: CoreGateway): void => {
|
|
|
118
119
|
func: createWebhookPostHandler(config),
|
|
119
120
|
}
|
|
120
121
|
|
|
121
|
-
addFunction(postFuncId, postHandler
|
|
122
|
+
addFunction(postFuncId, postHandler)
|
|
122
123
|
|
|
123
124
|
if (!routes.has('post')) {
|
|
124
125
|
routes.set('post', new Map())
|
|
@@ -128,7 +129,10 @@ const wireWebhookGateway = (config: CoreGateway): void => {
|
|
|
128
129
|
route,
|
|
129
130
|
func: postHandler,
|
|
130
131
|
auth: false,
|
|
131
|
-
|
|
132
|
+
// A gateway handler takes (services, data, wire) rather than a pikku
|
|
133
|
+
// function's shape, so it never matches CorePikkuFunctionConfig. It is only
|
|
134
|
+
// ever invoked through runPikkuFunc, which is what makes that safe.
|
|
135
|
+
} as unknown as CoreHTTPFunctionWiring<unknown, unknown, string>)
|
|
132
136
|
|
|
133
137
|
// knowledge: decisions/internals/gateway-adapters-resolve-lazily-and-are-promise-cached.md
|
|
134
138
|
if (typeof adapter === 'function' || adapter.verifyWebhook) {
|
|
@@ -139,7 +143,7 @@ const wireWebhookGateway = (config: CoreGateway): void => {
|
|
|
139
143
|
func: createWebhookVerifyHandler(config),
|
|
140
144
|
}
|
|
141
145
|
|
|
142
|
-
addFunction(verifyFuncId, verifyHandler
|
|
146
|
+
addFunction(verifyFuncId, verifyHandler)
|
|
143
147
|
|
|
144
148
|
if (!routes.has('get')) {
|
|
145
149
|
routes.set('get', new Map())
|
|
@@ -151,7 +155,7 @@ const wireWebhookGateway = (config: CoreGateway): void => {
|
|
|
151
155
|
auth: false,
|
|
152
156
|
// knowledge: decisions/internals/gateway-webhook-challenges-echo-bytes-not-json.md
|
|
153
157
|
returnsJSON: false,
|
|
154
|
-
} as
|
|
158
|
+
} as unknown as CoreHTTPFunctionWiring<unknown, unknown, string>)
|
|
155
159
|
}
|
|
156
160
|
|
|
157
161
|
httpRouter.reset()
|
|
@@ -187,17 +191,17 @@ const createWebhookPostHandler = (config: CoreGateway) => {
|
|
|
187
191
|
platform: adapter.name,
|
|
188
192
|
send: (msg: GatewayOutboundMessage) => adapter.send(parsed.senderId, msg),
|
|
189
193
|
}
|
|
190
|
-
|
|
194
|
+
wire.gateway = gateway
|
|
191
195
|
|
|
192
196
|
// Gateway middleware runs outside the gate so it can establish the session the gate checks.
|
|
193
197
|
const invoke = async () => {
|
|
194
|
-
await bridgeMiddlewareSession(wire
|
|
198
|
+
await bridgeMiddlewareSession(wire)
|
|
195
199
|
return await runPikkuFunc('gateway', name, handlerFuncId, {
|
|
196
200
|
singletonServices: services,
|
|
197
201
|
data: () => parsed,
|
|
198
202
|
auth: config.auth,
|
|
199
203
|
inheritedMiddleware,
|
|
200
|
-
wire
|
|
204
|
+
wire,
|
|
201
205
|
})
|
|
202
206
|
}
|
|
203
207
|
|
|
@@ -275,9 +279,12 @@ const wireWebsocketGateway = (config: CoreGateway): void => {
|
|
|
275
279
|
name,
|
|
276
280
|
route,
|
|
277
281
|
gateway: true,
|
|
282
|
+
input: null,
|
|
278
283
|
connect: { pikkuFuncId: connectFuncId },
|
|
284
|
+
disconnect: null,
|
|
279
285
|
message: { pikkuFuncId: messageFuncId },
|
|
280
|
-
|
|
286
|
+
messageWirings: {},
|
|
287
|
+
}
|
|
281
288
|
|
|
282
289
|
const userMiddleware = config.middleware as CorePikkuMiddleware[] | undefined
|
|
283
290
|
const handlerFuncId = registerGatewayHandler(config)
|
|
@@ -287,7 +294,7 @@ const wireWebsocketGateway = (config: CoreGateway): void => {
|
|
|
287
294
|
auth: false,
|
|
288
295
|
func: async (services: any, _data: unknown, wire: PikkuWire) => {
|
|
289
296
|
const adapter = await resolveGatewayAdapter(config, services)
|
|
290
|
-
|
|
297
|
+
wire.gateway = {
|
|
291
298
|
gatewayName: name,
|
|
292
299
|
senderId: '',
|
|
293
300
|
platform: adapter.name,
|
|
@@ -296,7 +303,7 @@ const wireWebsocketGateway = (config: CoreGateway): void => {
|
|
|
296
303
|
},
|
|
297
304
|
} satisfies PikkuGateway
|
|
298
305
|
},
|
|
299
|
-
}
|
|
306
|
+
})
|
|
300
307
|
|
|
301
308
|
addFunction(messageFuncId, {
|
|
302
309
|
auth: false,
|
|
@@ -313,16 +320,16 @@ const wireWebsocketGateway = (config: CoreGateway): void => {
|
|
|
313
320
|
wire.channel?.send(msg)
|
|
314
321
|
},
|
|
315
322
|
}
|
|
316
|
-
|
|
323
|
+
wire.gateway = gateway
|
|
317
324
|
|
|
318
325
|
const invoke = async () => {
|
|
319
|
-
await bridgeMiddlewareSession(wire
|
|
326
|
+
await bridgeMiddlewareSession(wire)
|
|
320
327
|
return await runPikkuFunc('gateway', name, handlerFuncId, {
|
|
321
328
|
singletonServices: services,
|
|
322
329
|
data: () => parsed,
|
|
323
330
|
auth: config.auth,
|
|
324
331
|
inheritedMiddleware,
|
|
325
|
-
wire
|
|
332
|
+
wire,
|
|
326
333
|
})
|
|
327
334
|
}
|
|
328
335
|
|
|
@@ -337,7 +344,7 @@ const wireWebsocketGateway = (config: CoreGateway): void => {
|
|
|
337
344
|
wire.channel?.send(result)
|
|
338
345
|
}
|
|
339
346
|
},
|
|
340
|
-
}
|
|
347
|
+
})
|
|
341
348
|
|
|
342
349
|
// knowledge: decisions/internals/gateway-wiring-is-a-meta-wiring-over-http-and-channels.md
|
|
343
350
|
channels.set(name, {
|
|
@@ -346,7 +353,7 @@ const wireWebsocketGateway = (config: CoreGateway): void => {
|
|
|
346
353
|
auth: false,
|
|
347
354
|
onConnect: { func: async () => {} },
|
|
348
355
|
onMessage: { func: async () => {} },
|
|
349
|
-
}
|
|
356
|
+
})
|
|
350
357
|
|
|
351
358
|
httpRouter.reset()
|
|
352
359
|
}
|
|
@@ -377,7 +384,7 @@ export const createListenerMessageHandler = (
|
|
|
377
384
|
platform: adapter.name,
|
|
378
385
|
send: (msg: GatewayOutboundMessage) => adapter.send(parsed.senderId, msg),
|
|
379
386
|
}
|
|
380
|
-
|
|
387
|
+
wire.gateway = gateway
|
|
381
388
|
|
|
382
389
|
const invoke = async () => {
|
|
383
390
|
await bridgeMiddlewareSession(wire)
|
|
@@ -390,10 +397,11 @@ export const createListenerMessageHandler = (
|
|
|
390
397
|
})
|
|
391
398
|
}
|
|
392
399
|
|
|
400
|
+
// knowledge: decisions/internals/gateway-listener-middleware-runs-without-an-rpc-on-the-wire.md
|
|
393
401
|
const result: any = userMiddleware?.length
|
|
394
402
|
? await runMiddleware(
|
|
395
403
|
singletonServices,
|
|
396
|
-
wire as
|
|
404
|
+
wire as PikkuWire,
|
|
397
405
|
userMiddleware,
|
|
398
406
|
invoke
|
|
399
407
|
)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type {
|
|
2
|
+
CoreHTTPFunctionWiring,
|
|
2
3
|
HTTPRouteConfig,
|
|
3
4
|
HTTPRouteMap,
|
|
4
5
|
HTTPRouteContract,
|
|
@@ -84,7 +85,9 @@ function registerRoute(
|
|
|
84
85
|
timeout: route.timeout,
|
|
85
86
|
headers: route.headers,
|
|
86
87
|
sse: route.sse,
|
|
87
|
-
|
|
88
|
+
// `CoreHTTPFunctionWiring` is discriminated by `method`, and a group builds
|
|
89
|
+
// its routes from a method chosen at runtime — no arm can be narrowed to.
|
|
90
|
+
} as CoreHTTPFunctionWiring<unknown, unknown, string>)
|
|
88
91
|
}
|
|
89
92
|
|
|
90
93
|
function isRouteConfig(value: unknown): value is HTTPRouteConfig {
|
|
@@ -33,8 +33,10 @@ import { isProduction } from '../../env.js'
|
|
|
33
33
|
import { pikkuState } from '../../pikku-state.js'
|
|
34
34
|
import { PikkuFetchHTTPResponse } from './pikku-fetch-http-response.js'
|
|
35
35
|
import { PikkuFetchHTTPRequest } from './pikku-fetch-http-request.js'
|
|
36
|
-
import type { PikkuChannel } from '../channel/channel.types.js'
|
|
37
|
-
|
|
36
|
+
import type { BinaryData, PikkuChannel } from '../channel/channel.types.js'
|
|
37
|
+
// The leaf module, not the channel-rpc barrel: http needs one refusal
|
|
38
|
+
// function, and the barrel drags in 4,932 lines of channel RPC runtime.
|
|
39
|
+
import { unsupportedChannelRemote } from '../channel/channel-rpc.types.js'
|
|
38
40
|
import { addFunction, runPikkuFunc } from '../../function/function-runner.js'
|
|
39
41
|
import { applyWebResponse } from './web-request.js'
|
|
40
42
|
import { httpRouter } from './routers/http-router.js'
|
|
@@ -68,26 +70,6 @@ export const addHTTPMiddleware = <PikkuMiddleware extends CorePikkuMiddleware>(
|
|
|
68
70
|
return middleware
|
|
69
71
|
}
|
|
70
72
|
|
|
71
|
-
/**
|
|
72
|
-
* @deprecated HTTP-route-level permissions were removed in #972 — permissions
|
|
73
|
-
* are now function-scoped only (declare them on the function via
|
|
74
|
-
* `pikkuFunc({ permissions })`). This throwing stub exists solely so the pinned
|
|
75
|
-
* bootstrap CLI (which still generates an `addHTTPPermission` wrapper) can
|
|
76
|
-
* resolve the import at build time; it is never called. Delete once
|
|
77
|
-
* `PIKKU_CLI_VERSION` in the CLI build is bumped past the release that removes
|
|
78
|
-
* HTTP-route permissions.
|
|
79
|
-
*/
|
|
80
|
-
export const addHTTPPermission = (
|
|
81
|
-
_pattern: string,
|
|
82
|
-
_permissions:
|
|
83
|
-
| Record<string, CorePikkuPermission | CorePikkuPermission[]>
|
|
84
|
-
| CorePikkuPermission[]
|
|
85
|
-
): never => {
|
|
86
|
-
throw new Error(
|
|
87
|
-
'addHTTPPermission was removed in #972 — HTTP-route-level permissions no longer exist. Declare permissions on the function definition instead: pikkuFunc({ permissions }).'
|
|
88
|
-
)
|
|
89
|
-
}
|
|
90
|
-
|
|
91
73
|
export const wireHTTP = <
|
|
92
74
|
In,
|
|
93
75
|
Out,
|
|
@@ -126,7 +108,8 @@ export const wireHTTP = <
|
|
|
126
108
|
}
|
|
127
109
|
pikkuState(null, 'http', 'routes')
|
|
128
110
|
.get(httpWiring.method)
|
|
129
|
-
|
|
111
|
+
// knowledge: decisions/internals/wiring-registries-erase-the-generics-their-wire-functions-capture.md
|
|
112
|
+
?.set(httpWiring.route, httpWiring as CoreHTTPFunctionWiring<any, any, any>)
|
|
130
113
|
}
|
|
131
114
|
|
|
132
115
|
const getMatchingRoute = (requestType: string, requestPath: string) => {
|
|
@@ -261,7 +244,8 @@ const executeRoute = async (
|
|
|
261
244
|
setState: (s) => {
|
|
262
245
|
sseState = s
|
|
263
246
|
},
|
|
264
|
-
|
|
247
|
+
// knowledge: decisions/internals/channel-state-accessors-are-unsound-generics-that-every-implementation-asserts.md
|
|
248
|
+
getState: () => sseState as never,
|
|
265
249
|
clearState: () => {
|
|
266
250
|
sseState = undefined
|
|
267
251
|
},
|
|
@@ -275,7 +259,7 @@ const executeRoute = async (
|
|
|
275
259
|
const channelHandler = {
|
|
276
260
|
getChannel: () => channelRef,
|
|
277
261
|
send: (data: unknown, isBinary?: boolean) => {
|
|
278
|
-
if (isBinary) channelRef.sendBinary(data as
|
|
262
|
+
if (isBinary) channelRef.sendBinary(data as BinaryData)
|
|
279
263
|
else channelRef.send(data)
|
|
280
264
|
},
|
|
281
265
|
sendBinary: (data: any) => channelRef.sendBinary(data),
|
|
@@ -424,7 +408,8 @@ export const fetchData = async <In, Out>(
|
|
|
424
408
|
globalMiddleware as CorePikkuMiddleware[]
|
|
425
409
|
)
|
|
426
410
|
}
|
|
427
|
-
|
|
411
|
+
// 204 carries no body, and `json` has no no-content overload.
|
|
412
|
+
response.status(204).json(undefined as never)
|
|
428
413
|
return
|
|
429
414
|
}
|
|
430
415
|
scopedLogger.info({
|