@pikku/core 0.11.2 → 0.12.1
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 +57 -2
- package/dist/crypto-utils.d.ts +2 -0
- package/dist/crypto-utils.js +78 -0
- package/dist/errors/errors.d.ts +14 -0
- package/dist/errors/errors.js +26 -0
- package/dist/errors/index.d.ts +1 -1
- package/dist/errors/index.js +1 -1
- package/dist/function/function-runner.d.ts +10 -4
- package/dist/function/function-runner.js +126 -45
- package/dist/function/functions.types.d.ts +32 -87
- package/dist/function/functions.types.js +16 -46
- package/dist/function/index.d.ts +2 -2
- package/dist/function/index.js +1 -2
- package/dist/handle-error.d.ts +2 -2
- package/dist/handle-error.js +3 -12
- package/dist/index.d.ts +30 -26
- package/dist/index.js +19 -29
- package/dist/internal.d.ts +3 -0
- package/dist/internal.js +2 -0
- package/dist/middleware/auth-apikey.d.ts +2 -2
- package/dist/middleware/auth-apikey.js +3 -3
- package/dist/middleware/auth-bearer.d.ts +3 -3
- package/dist/middleware/auth-bearer.js +4 -7
- package/dist/middleware/auth-cookie.d.ts +4 -4
- package/dist/middleware/auth-cookie.js +7 -9
- package/dist/middleware/cors.d.ts +46 -0
- package/dist/middleware/cors.js +81 -0
- package/dist/middleware/index.d.ts +5 -3
- package/dist/middleware/index.js +5 -3
- package/dist/middleware/remote-auth.d.ts +5 -0
- package/dist/middleware/remote-auth.js +55 -0
- package/dist/middleware/timeout.d.ts +2 -2
- package/dist/middleware-runner.d.ts +1 -1
- package/dist/middleware-runner.js +8 -10
- package/dist/permissions.d.ts +2 -2
- package/dist/permissions.js +11 -15
- package/dist/pikku-state.d.ts +10 -8
- package/dist/pikku-state.js +48 -25
- package/dist/schema.d.ts +4 -4
- package/dist/schema.js +20 -15
- package/dist/services/ai-agent-runner-service.d.ts +43 -0
- package/dist/services/ai-agent-runner-service.js +1 -0
- package/dist/services/ai-run-state-service.d.ts +13 -0
- package/dist/services/ai-run-state-service.js +1 -0
- package/dist/services/ai-storage-service.d.ts +18 -0
- package/dist/services/ai-storage-service.js +1 -0
- package/dist/services/content-service.d.ts +6 -0
- package/dist/services/deployment-service.d.ts +19 -0
- package/dist/services/deployment-service.js +1 -0
- package/dist/services/gopass-secrets.d.ts +47 -0
- package/dist/services/gopass-secrets.js +97 -0
- package/dist/services/in-memory-ai-run-state-service.d.ts +15 -0
- package/dist/services/in-memory-ai-run-state-service.js +44 -0
- package/dist/services/in-memory-trigger-service.d.ts +22 -0
- package/dist/services/in-memory-trigger-service.js +48 -0
- package/dist/services/in-memory-workflow-service.d.ts +59 -0
- package/dist/services/in-memory-workflow-service.js +287 -0
- package/dist/services/index.d.ts +26 -11
- package/dist/services/index.js +11 -13
- package/dist/services/local-content.d.ts +2 -1
- package/dist/services/local-content.js +6 -1
- package/dist/services/local-secrets.d.ts +25 -2
- package/dist/services/local-secrets.js +45 -0
- package/dist/services/local-variables.d.ts +6 -1
- package/dist/services/local-variables.js +18 -0
- package/dist/services/logger-console.d.ts +2 -1
- package/dist/services/scheduler-service.d.ts +9 -1
- package/dist/services/scheduler-service.js +8 -0
- package/dist/services/schema-service.d.ts +6 -0
- package/dist/services/scoped-secret-service.d.ts +16 -0
- package/dist/services/scoped-secret-service.js +35 -0
- package/dist/services/secret-service.d.ts +25 -4
- package/dist/services/trigger-service.d.ts +16 -0
- package/dist/services/trigger-service.js +1 -0
- package/dist/services/typed-secret-service.d.ts +30 -0
- package/dist/services/typed-secret-service.js +40 -0
- package/dist/services/typed-variables-service.d.ts +27 -0
- package/dist/services/typed-variables-service.js +46 -0
- package/dist/services/user-session-service.d.ts +15 -2
- package/dist/services/user-session-service.js +17 -0
- package/dist/services/variables-service.d.ts +5 -0
- package/dist/services/workflow-service.d.ts +9 -5
- package/dist/types/core.types.d.ts +67 -25
- package/dist/types/core.types.js +8 -1
- package/dist/types/state.types.d.ts +53 -59
- package/dist/utils.d.ts +7 -6
- package/dist/utils.js +27 -12
- package/dist/version.d.ts +6 -0
- package/dist/version.js +19 -0
- package/dist/wirings/ai-agent/ai-agent-assistant-ui.d.ts +5 -0
- package/dist/wirings/ai-agent/ai-agent-assistant-ui.js +146 -0
- package/dist/wirings/ai-agent/ai-agent-helpers.d.ts +28 -0
- package/dist/wirings/ai-agent/ai-agent-helpers.js +40 -0
- package/dist/wirings/ai-agent/ai-agent-memory.d.ts +29 -0
- package/dist/wirings/ai-agent/ai-agent-memory.js +199 -0
- package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +9 -0
- package/dist/wirings/ai-agent/ai-agent-model-config.js +36 -0
- package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +59 -0
- package/dist/wirings/ai-agent/ai-agent-prepare.js +348 -0
- package/dist/wirings/ai-agent/ai-agent-registry.d.ts +15 -0
- package/dist/wirings/ai-agent/ai-agent-registry.js +47 -0
- package/dist/wirings/ai-agent/ai-agent-runner.d.ts +3 -0
- package/dist/wirings/ai-agent/ai-agent-runner.js +195 -0
- package/dist/wirings/ai-agent/ai-agent-stream.d.ts +12 -0
- package/dist/wirings/ai-agent/ai-agent-stream.js +662 -0
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +313 -0
- package/dist/wirings/ai-agent/ai-agent.types.js +1 -0
- package/dist/wirings/ai-agent/index.d.ts +7 -0
- package/dist/wirings/ai-agent/index.js +6 -0
- package/dist/wirings/channel/channel-common.d.ts +8 -5
- package/dist/wirings/channel/channel-common.js +15 -8
- package/dist/wirings/channel/channel-handler.d.ts +3 -3
- package/dist/wirings/channel/channel-handler.js +15 -6
- package/dist/wirings/channel/channel-middleware-runner.d.ts +9 -0
- package/dist/wirings/channel/channel-middleware-runner.js +73 -0
- package/dist/wirings/channel/channel-runner.d.ts +5 -5
- package/dist/wirings/channel/channel-runner.js +10 -9
- package/dist/wirings/channel/channel-store.d.ts +1 -1
- package/dist/wirings/channel/channel.types.d.ts +9 -7
- package/dist/wirings/channel/define-channel-routes.d.ts +21 -0
- package/dist/wirings/channel/define-channel-routes.js +23 -0
- package/dist/wirings/channel/index.d.ts +10 -8
- package/dist/wirings/channel/index.js +7 -8
- package/dist/wirings/channel/local/index.d.ts +3 -3
- package/dist/wirings/channel/local/index.js +3 -3
- package/dist/wirings/channel/local/local-channel-runner.d.ts +7 -2
- package/dist/wirings/channel/local/local-channel-runner.js +22 -9
- package/dist/wirings/channel/local/local-eventhub-service.d.ts +2 -2
- package/dist/wirings/channel/log-channels.d.ts +1 -1
- package/dist/wirings/channel/pikku-abstract-channel-handler.d.ts +1 -1
- package/dist/wirings/channel/serverless/index.d.ts +1 -1
- package/dist/wirings/channel/serverless/index.js +1 -1
- package/dist/wirings/channel/serverless/serverless-channel-runner.d.ts +4 -4
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +40 -23
- package/dist/wirings/cli/channel/cli-channel-runner.d.ts +1 -1
- package/dist/wirings/cli/channel/index.d.ts +1 -1
- package/dist/wirings/cli/channel/index.js +1 -1
- package/dist/wirings/cli/cli-runner.d.ts +3 -3
- package/dist/wirings/cli/cli-runner.js +12 -8
- package/dist/wirings/cli/cli.types.d.ts +9 -9
- package/dist/wirings/cli/command-parser.d.ts +1 -1
- package/dist/wirings/cli/define-cli-commands.d.ts +19 -0
- package/dist/wirings/cli/define-cli-commands.js +20 -0
- package/dist/wirings/cli/index.d.ts +2 -3
- package/dist/wirings/cli/index.js +1 -3
- package/dist/wirings/http/http-routes.d.ts +69 -0
- package/dist/wirings/http/http-routes.js +139 -0
- package/dist/wirings/http/http-runner.d.ts +9 -9
- package/dist/wirings/http/http-runner.js +79 -34
- package/dist/wirings/http/http.types.d.ts +77 -41
- package/dist/wirings/http/index.d.ts +5 -4
- package/dist/wirings/http/index.js +4 -3
- package/dist/wirings/http/log-http-routes.d.ts +1 -1
- package/dist/wirings/http/pikku-fetch-http-request.d.ts +1 -1
- package/dist/wirings/http/pikku-fetch-http-response.d.ts +2 -2
- package/dist/wirings/http/pikku-fetch-http-response.js +6 -1
- package/dist/wirings/http/routers/http-router.d.ts +1 -1
- package/dist/wirings/http/routers/path-to-regex.d.ts +2 -2
- package/dist/wirings/mcp/index.d.ts +4 -3
- package/dist/wirings/mcp/index.js +3 -3
- package/dist/wirings/mcp/mcp-endpoint-registry.d.ts +1 -1
- package/dist/wirings/mcp/mcp-runner.d.ts +1 -6
- package/dist/wirings/mcp/mcp-runner.js +28 -40
- package/dist/wirings/mcp/mcp.types.d.ts +5 -5
- package/dist/wirings/node/index.d.ts +2 -0
- package/dist/wirings/node/index.js +1 -0
- package/dist/wirings/node/node.types.d.ts +20 -0
- package/dist/wirings/node/node.types.js +1 -0
- package/dist/wirings/oauth2/index.d.ts +3 -0
- package/dist/wirings/oauth2/index.js +2 -0
- package/dist/wirings/oauth2/oauth2-client.d.ts +47 -0
- package/dist/wirings/oauth2/oauth2-client.js +267 -0
- package/dist/wirings/oauth2/oauth2.types.d.ts +65 -0
- package/dist/wirings/oauth2/oauth2.types.js +4 -0
- package/dist/wirings/oauth2/wire-oauth2-credential.d.ts +20 -0
- package/dist/wirings/oauth2/wire-oauth2-credential.js +21 -0
- package/dist/wirings/queue/index.d.ts +1 -1
- package/dist/wirings/queue/queue-runner.d.ts +1 -5
- package/dist/wirings/queue/queue-runner.js +11 -8
- package/dist/wirings/queue/queue.types.d.ts +5 -5
- package/dist/wirings/queue/register-queue-helper.d.ts +2 -2
- package/dist/wirings/queue/register-queue-helper.js +1 -1
- package/dist/wirings/queue/validate-worker-config.d.ts +1 -1
- package/dist/wirings/rpc/index.d.ts +3 -1
- package/dist/wirings/rpc/index.js +2 -1
- package/dist/wirings/rpc/rpc-runner.d.ts +58 -8
- package/dist/wirings/rpc/rpc-runner.js +177 -31
- package/dist/wirings/rpc/rpc-types.d.ts +20 -4
- package/dist/wirings/rpc/wire-addon.d.ts +10 -0
- package/dist/wirings/rpc/wire-addon.js +9 -0
- package/dist/wirings/scheduler/index.d.ts +2 -2
- package/dist/wirings/scheduler/index.js +1 -2
- package/dist/wirings/scheduler/log-schedulers.d.ts +1 -1
- package/dist/wirings/scheduler/scheduler-runner.d.ts +3 -5
- package/dist/wirings/scheduler/scheduler-runner.js +11 -14
- package/dist/wirings/scheduler/scheduler.types.d.ts +2 -2
- package/dist/wirings/secret/index.d.ts +3 -0
- package/dist/wirings/secret/index.js +2 -0
- package/dist/wirings/secret/secret.types.d.ts +27 -0
- package/dist/wirings/secret/secret.types.js +1 -0
- package/dist/wirings/secret/validate-secret-definitions.d.ts +6 -0
- package/dist/wirings/secret/validate-secret-definitions.js +55 -0
- package/dist/wirings/trigger/index.d.ts +3 -2
- package/dist/wirings/trigger/index.js +2 -2
- package/dist/wirings/trigger/pikku-trigger-service.d.ts +22 -0
- package/dist/wirings/trigger/pikku-trigger-service.js +70 -0
- package/dist/wirings/trigger/trigger-runner.d.ts +18 -9
- package/dist/wirings/trigger/trigger-runner.js +48 -19
- package/dist/wirings/trigger/trigger.types.d.ts +99 -11
- package/dist/wirings/trigger/trigger.types.js +40 -1
- package/dist/wirings/variable/index.d.ts +3 -0
- package/dist/wirings/variable/index.js +2 -0
- package/dist/wirings/variable/validate-variable-definitions.d.ts +6 -0
- package/dist/wirings/variable/validate-variable-definitions.js +45 -0
- package/dist/wirings/variable/variable.types.d.ts +18 -0
- package/dist/wirings/variable/variable.types.js +1 -0
- package/dist/wirings/workflow/dsl/index.d.ts +1 -1
- package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +7 -1
- package/dist/wirings/workflow/dsl/workflow-runner.js +3 -2
- package/dist/wirings/workflow/graph/graph-node.d.ts +1 -6
- package/dist/wirings/workflow/graph/graph-runner.d.ts +5 -31
- package/dist/wirings/workflow/graph/graph-runner.js +384 -296
- package/dist/wirings/workflow/graph/index.d.ts +4 -3
- package/dist/wirings/workflow/graph/index.js +3 -3
- package/dist/wirings/workflow/graph/template.d.ts +15 -0
- package/dist/wirings/workflow/graph/template.js +27 -0
- package/dist/wirings/workflow/graph/wire-workflow-graph.d.ts +15 -0
- package/dist/wirings/workflow/graph/wire-workflow-graph.js +8 -0
- package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +0 -13
- package/dist/wirings/workflow/index.d.ts +6 -6
- package/dist/wirings/workflow/index.js +6 -4
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +29 -19
- package/dist/wirings/workflow/pikku-workflow-service.js +217 -82
- package/dist/wirings/workflow/workflow-helpers.d.ts +36 -0
- package/dist/wirings/workflow/workflow-helpers.js +38 -0
- package/dist/wirings/workflow/workflow.types.d.ts +42 -95
- package/package.json +14 -15
- package/run-tests.sh +4 -1
- package/src/crypto-utils.test.ts +116 -0
- package/src/crypto-utils.ts +99 -0
- package/src/errors/error.test.ts +143 -2
- package/src/errors/errors.ts +27 -0
- package/src/errors/index.ts +1 -1
- package/src/factory-functions.test.ts +42 -2
- package/src/function/function-runner.test.ts +6 -13
- package/src/function/function-runner.ts +161 -53
- package/src/function/functions.types.ts +63 -132
- package/src/function/index.ts +5 -2
- package/src/handle-error.test.ts +361 -0
- package/src/handle-error.ts +6 -14
- package/src/index.ts +97 -30
- package/src/internal.ts +6 -0
- package/src/middleware/auth-apikey.test.ts +16 -13
- package/src/middleware/auth-apikey.ts +3 -3
- package/src/middleware/auth-bearer.test.ts +18 -15
- package/src/middleware/auth-bearer.ts +27 -32
- package/src/middleware/auth-cookie.test.ts +17 -14
- package/src/middleware/auth-cookie.ts +9 -13
- package/src/middleware/cors.test.ts +424 -0
- package/src/middleware/cors.ts +104 -0
- package/src/middleware/index.ts +5 -3
- package/src/middleware/remote-auth.test.ts +488 -0
- package/src/middleware/remote-auth.ts +68 -0
- package/src/middleware-runner.test.ts +123 -1
- package/src/middleware-runner.ts +13 -13
- package/src/permissions.test.ts +83 -9
- package/src/permissions.ts +17 -19
- package/src/pikku-state.test.ts +224 -0
- package/src/pikku-state.ts +59 -35
- package/src/run-tests-script.test.ts +49 -0
- package/src/schema.test.ts +198 -6
- package/src/schema.ts +28 -21
- package/src/services/ai-agent-runner-service.ts +41 -0
- package/src/services/ai-run-state-service.ts +20 -0
- package/src/services/ai-storage-service.ts +39 -0
- package/src/services/content-service.ts +7 -0
- package/src/services/deployment-service.ts +22 -0
- package/src/services/gopass-secrets.ts +98 -0
- package/src/services/in-memory-ai-run-state-service.ts +73 -0
- package/src/services/in-memory-trigger-service.ts +64 -0
- package/src/services/in-memory-workflow-service.test.ts +351 -0
- package/src/services/in-memory-workflow-service.ts +395 -0
- package/src/services/index.ts +50 -14
- package/src/services/local-content.ts +9 -3
- package/src/services/local-secrets.test.ts +80 -0
- package/src/services/local-secrets.ts +53 -2
- package/src/services/local-variables.test.ts +61 -0
- package/src/services/local-variables.ts +23 -1
- package/src/services/logger-console.test.ts +118 -0
- package/src/services/logger-console.ts +2 -1
- package/src/services/scheduler-service.ts +11 -1
- package/src/services/schema-service.ts +7 -0
- package/src/services/scoped-secret-service.test.ts +74 -0
- package/src/services/scoped-secret-service.ts +41 -0
- package/src/services/secret-service.ts +25 -4
- package/src/services/trigger-service.ts +17 -0
- package/src/services/typed-secret-service.test.ts +93 -0
- package/src/services/typed-secret-service.ts +70 -0
- package/src/services/typed-variables-service.test.ts +73 -0
- package/src/services/typed-variables-service.ts +81 -0
- package/src/services/user-session-service.test.ts +113 -0
- package/src/services/user-session-service.ts +25 -2
- package/src/services/variables-service.ts +5 -0
- package/src/services/workflow-service.ts +23 -13
- package/src/time-utils.test.ts +1 -1
- package/src/types/core.types.ts +95 -24
- package/src/types/state.types.ts +56 -73
- package/src/utils.test.ts +350 -0
- package/src/utils.ts +33 -18
- package/src/version.test.ts +80 -0
- package/src/version.ts +25 -0
- package/src/wirings/ai-agent/ai-agent-assistant-ui.test.ts +363 -0
- package/src/wirings/ai-agent/ai-agent-assistant-ui.ts +214 -0
- package/src/wirings/ai-agent/ai-agent-helpers.test.ts +152 -0
- package/src/wirings/ai-agent/ai-agent-helpers.ts +76 -0
- package/src/wirings/ai-agent/ai-agent-memory.ts +300 -0
- package/src/wirings/ai-agent/ai-agent-model-config.test.ts +115 -0
- package/src/wirings/ai-agent/ai-agent-model-config.ts +43 -0
- package/src/wirings/ai-agent/ai-agent-prepare.ts +504 -0
- package/src/wirings/ai-agent/ai-agent-registry.test.ts +37 -0
- package/src/wirings/ai-agent/ai-agent-registry.ts +82 -0
- package/src/wirings/ai-agent/ai-agent-runner.test.ts +317 -0
- package/src/wirings/ai-agent/ai-agent-runner.ts +251 -0
- package/src/wirings/ai-agent/ai-agent-stream.test.ts +652 -0
- package/src/wirings/ai-agent/ai-agent-stream.ts +1049 -0
- package/src/wirings/ai-agent/ai-agent.types.ts +328 -0
- package/src/wirings/ai-agent/index.ts +39 -0
- package/src/wirings/channel/channel-common.ts +33 -20
- package/src/wirings/channel/channel-handler.ts +26 -9
- package/src/wirings/channel/channel-middleware-runner.ts +119 -0
- package/src/wirings/channel/channel-runner.ts +15 -16
- package/src/wirings/channel/channel-store.ts +1 -1
- package/src/wirings/channel/channel.types.ts +21 -9
- package/src/wirings/channel/define-channel-routes.ts +25 -0
- package/src/wirings/channel/index.ts +23 -8
- package/src/wirings/channel/local/index.ts +3 -3
- package/src/wirings/channel/local/local-channel-runner.test.ts +57 -7
- package/src/wirings/channel/local/local-channel-runner.ts +40 -19
- package/src/wirings/channel/local/local-eventhub-service.test.ts +2 -2
- package/src/wirings/channel/local/local-eventhub-service.ts +2 -2
- package/src/wirings/channel/log-channels.ts +1 -1
- package/src/wirings/channel/pikku-abstract-channel-handler.ts +1 -1
- package/src/wirings/channel/serverless/index.ts +5 -1
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +57 -36
- package/src/wirings/cli/channel/cli-channel-runner.ts +1 -1
- package/src/wirings/cli/channel/index.ts +1 -1
- package/src/wirings/cli/cli-runner.test.ts +10 -10
- package/src/wirings/cli/cli-runner.ts +28 -14
- package/src/wirings/cli/cli.types.ts +14 -14
- package/src/wirings/cli/command-parser.test.ts +9 -9
- package/src/wirings/cli/command-parser.ts +1 -1
- package/src/wirings/cli/define-cli-commands.ts +24 -0
- package/src/wirings/cli/index.ts +10 -4
- package/src/wirings/http/http-routes.test.ts +322 -0
- package/src/wirings/http/http-routes.ts +198 -0
- package/src/wirings/http/http-runner.test.ts +12 -20
- package/src/wirings/http/http-runner.ts +101 -51
- package/src/wirings/http/http.types.ts +119 -48
- package/src/wirings/http/index.ts +16 -4
- package/src/wirings/http/log-http-routes.ts +1 -1
- package/src/wirings/http/pikku-fetch-http-request.ts +1 -1
- package/src/wirings/http/pikku-fetch-http-response.ts +12 -5
- package/src/wirings/http/routers/http-router.ts +1 -1
- package/src/wirings/http/routers/path-to-regex.test.ts +1 -1
- package/src/wirings/http/routers/path-to-regex.ts +4 -3
- package/src/wirings/mcp/index.ts +27 -3
- package/src/wirings/mcp/mcp-endpoint-registry.test.ts +3 -3
- package/src/wirings/mcp/mcp-endpoint-registry.ts +5 -1
- package/src/wirings/mcp/mcp-runner.ts +48 -65
- package/src/wirings/mcp/mcp.types.ts +5 -5
- package/src/wirings/node/index.ts +2 -0
- package/src/wirings/node/node.types.ts +23 -0
- package/src/wirings/oauth2/index.ts +3 -0
- package/src/wirings/oauth2/oauth2-client.test.ts +929 -0
- package/src/wirings/oauth2/oauth2-client.ts +335 -0
- package/src/wirings/oauth2/oauth2.types.ts +69 -0
- package/src/wirings/oauth2/wire-oauth2-credential.ts +23 -0
- package/src/wirings/queue/index.ts +13 -2
- package/src/wirings/queue/queue-runner.test.ts +142 -73
- package/src/wirings/queue/queue-runner.ts +18 -14
- package/src/wirings/queue/queue.types.ts +5 -5
- package/src/wirings/queue/register-queue-helper.ts +3 -5
- package/src/wirings/queue/validate-worker-config.test.ts +108 -0
- package/src/wirings/queue/validate-worker-config.ts +4 -1
- package/src/wirings/rpc/index.ts +3 -1
- package/src/wirings/rpc/rpc-runner.ts +254 -41
- package/src/wirings/rpc/rpc-types.ts +28 -4
- package/src/wirings/rpc/wire-addon.ts +20 -0
- package/src/wirings/scheduler/index.ts +6 -4
- package/src/wirings/scheduler/log-schedulers.ts +1 -1
- package/src/wirings/scheduler/scheduler-runner.test.ts +78 -45
- package/src/wirings/scheduler/scheduler-runner.ts +20 -27
- package/src/wirings/scheduler/scheduler.types.ts +2 -2
- package/src/wirings/secret/index.ts +9 -0
- package/src/wirings/secret/secret.types.ts +32 -0
- package/src/wirings/secret/validate-secret-definitions.test.ts +140 -0
- package/src/wirings/secret/validate-secret-definitions.ts +82 -0
- package/src/wirings/trigger/index.ts +10 -2
- package/src/wirings/trigger/pikku-trigger-service.ts +112 -0
- package/src/wirings/trigger/trigger-runner.test.ts +79 -0
- package/src/wirings/trigger/trigger-runner.ts +80 -41
- package/src/wirings/trigger/trigger.types.ts +144 -22
- package/src/wirings/variable/index.ts +8 -0
- package/src/wirings/variable/validate-variable-definitions.test.ts +91 -0
- package/src/wirings/variable/validate-variable-definitions.ts +69 -0
- package/src/wirings/variable/variable.types.ts +22 -0
- package/src/wirings/workflow/dsl/index.ts +1 -0
- package/src/wirings/workflow/dsl/workflow-dsl.types.ts +9 -1
- package/src/wirings/workflow/dsl/workflow-runner.ts +4 -3
- package/src/wirings/workflow/graph/graph-node.ts +1 -6
- package/src/wirings/workflow/graph/graph-runner.test.ts +487 -0
- package/src/wirings/workflow/graph/graph-runner.ts +496 -374
- package/src/wirings/workflow/graph/index.ts +14 -3
- package/src/wirings/workflow/graph/template.test.ts +49 -0
- package/src/wirings/workflow/graph/template.ts +42 -0
- package/src/wirings/workflow/graph/wire-workflow-graph.ts +29 -0
- package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -22
- package/src/wirings/workflow/index.ts +21 -10
- package/src/wirings/workflow/pikku-workflow-service.test.ts +200 -0
- package/src/wirings/workflow/pikku-workflow-service.ts +308 -105
- package/src/wirings/workflow/workflow-helpers.test.ts +129 -0
- package/src/wirings/workflow/workflow-helpers.ts +79 -0
- package/src/wirings/workflow/workflow.types.ts +47 -92
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/wirings/forge-node/forge-node.types.d.ts +0 -120
- package/dist/wirings/forge-node/forge-node.types.js +0 -38
- package/dist/wirings/forge-node/index.d.ts +0 -1
- package/dist/wirings/forge-node/index.js +0 -1
- package/dist/wirings/workflow/wire-workflow.d.ts +0 -42
- package/dist/wirings/workflow/wire-workflow.js +0 -53
- package/dist/wirings/workflow/workflow-utils.d.ts +0 -23
- package/dist/wirings/workflow/workflow-utils.js +0 -66
- package/src/wirings/forge-node/forge-node.types.ts +0 -135
- package/src/wirings/forge-node/index.ts +0 -1
- package/src/wirings/workflow/wire-workflow.ts +0 -94
- package/src/wirings/workflow/workflow-utils.ts +0 -120
|
@@ -1,112 +1,112 @@
|
|
|
1
|
-
import { createRef, isRef } from './workflow-graph.types.js';
|
|
2
1
|
import { pikkuState } from '../../../pikku-state.js';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
2
|
+
import { RPCNotFoundError } from '../../rpc/rpc-runner.js';
|
|
3
|
+
function buildTemplateRegex(nodeId) {
|
|
4
|
+
if (!nodeId.includes('${'))
|
|
5
|
+
return null;
|
|
6
|
+
const escaped = nodeId
|
|
7
|
+
.split(/\$\{[^}]+\}/)
|
|
8
|
+
.map((part) => part.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))
|
|
9
|
+
.join('.+');
|
|
10
|
+
return new RegExp(`^${escaped}$`);
|
|
11
|
+
}
|
|
12
|
+
function remapStepNamesToNodeIds(stepNames, nodes, graphName) {
|
|
13
|
+
const templatePatterns = new Map();
|
|
14
|
+
for (const nodeId of Object.keys(nodes)) {
|
|
15
|
+
const regex = buildTemplateRegex(nodeId);
|
|
16
|
+
if (regex)
|
|
17
|
+
templatePatterns.set(nodeId, regex);
|
|
18
|
+
}
|
|
19
|
+
if (templatePatterns.size === 0)
|
|
20
|
+
return stepNames;
|
|
21
|
+
return stepNames.map((name) => {
|
|
22
|
+
if (nodes[name])
|
|
23
|
+
return name;
|
|
24
|
+
const matches = [];
|
|
25
|
+
for (const [nodeId, regex] of templatePatterns) {
|
|
26
|
+
if (regex.test(name))
|
|
27
|
+
matches.push(nodeId);
|
|
28
|
+
}
|
|
29
|
+
if (matches.length > 1) {
|
|
30
|
+
throw new Error(`Workflow graph '${graphName}': ambiguous template node match for '${name}' (${matches.join(', ')})`);
|
|
31
|
+
}
|
|
32
|
+
if (matches.length === 1) {
|
|
33
|
+
return matches[0];
|
|
34
|
+
}
|
|
35
|
+
return name;
|
|
20
36
|
});
|
|
21
|
-
};
|
|
22
|
-
/**
|
|
23
|
-
* Get a registered workflow graph by name
|
|
24
|
-
*/
|
|
25
|
-
export function getWorkflowGraph(name) {
|
|
26
|
-
const registrations = pikkuState(null, 'workflows', 'graphRegistrations');
|
|
27
|
-
return registrations.get(name);
|
|
28
37
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if (
|
|
37
|
-
return
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
38
|
+
function remapBranchKeys(branchKeys, nodes, graphName) {
|
|
39
|
+
const templatePatterns = new Map();
|
|
40
|
+
for (const nodeId of Object.keys(nodes)) {
|
|
41
|
+
const regex = buildTemplateRegex(nodeId);
|
|
42
|
+
if (regex)
|
|
43
|
+
templatePatterns.set(nodeId, regex);
|
|
44
|
+
}
|
|
45
|
+
if (templatePatterns.size === 0)
|
|
46
|
+
return branchKeys;
|
|
47
|
+
const remapped = {};
|
|
48
|
+
for (const [key, value] of Object.entries(branchKeys)) {
|
|
49
|
+
let mappedKey = key;
|
|
50
|
+
if (!nodes[key]) {
|
|
51
|
+
const matches = [];
|
|
52
|
+
for (const [nodeId, regex] of templatePatterns) {
|
|
53
|
+
if (regex.test(key))
|
|
54
|
+
matches.push(nodeId);
|
|
55
|
+
}
|
|
56
|
+
if (matches.length > 1) {
|
|
57
|
+
throw new Error(`Workflow graph '${graphName}': ambiguous template branch key match for '${key}' (${matches.join(', ')})`);
|
|
58
|
+
}
|
|
59
|
+
if (matches.length === 1) {
|
|
60
|
+
mappedKey = matches[0];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
remapped[mappedKey] = value;
|
|
64
|
+
}
|
|
65
|
+
return remapped;
|
|
66
|
+
}
|
|
67
|
+
function isDataRef(value) {
|
|
68
|
+
return (typeof value === 'object' &&
|
|
69
|
+
value !== null &&
|
|
70
|
+
'$ref' in value &&
|
|
71
|
+
typeof value.$ref === 'string');
|
|
45
72
|
}
|
|
46
|
-
/**
|
|
47
|
-
* Check if a value is a template
|
|
48
|
-
*/
|
|
49
73
|
function isTemplate(value) {
|
|
50
74
|
return (typeof value === 'object' &&
|
|
51
75
|
value !== null &&
|
|
52
76
|
'$template' in value &&
|
|
53
77
|
typeof value.$template === 'object');
|
|
54
78
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
function createTemplate(templateStr, refs) {
|
|
59
|
-
const parts = [];
|
|
60
|
-
const expressions = [];
|
|
61
|
-
const regex = /\$(\d+)/g;
|
|
62
|
-
let lastIndex = 0;
|
|
63
|
-
let match;
|
|
64
|
-
while ((match = regex.exec(templateStr)) !== null) {
|
|
65
|
-
parts.push(templateStr.slice(lastIndex, match.index));
|
|
66
|
-
const refIndex = parseInt(match[1], 10);
|
|
67
|
-
const refValue = refs[refIndex];
|
|
68
|
-
if (refValue) {
|
|
69
|
-
expressions.push({ $ref: refValue.nodeId, path: refValue.path });
|
|
70
|
-
}
|
|
71
|
-
else {
|
|
72
|
-
expressions.push({ $ref: 'unknown' });
|
|
73
|
-
}
|
|
74
|
-
lastIndex = regex.lastIndex;
|
|
75
|
-
}
|
|
76
|
-
parts.push(templateStr.slice(lastIndex));
|
|
77
|
-
return { $template: { parts, expressions } };
|
|
79
|
+
function getWorkflowMeta(name) {
|
|
80
|
+
const meta = pikkuState(null, 'workflows', 'meta');
|
|
81
|
+
return meta[name];
|
|
78
82
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
83
|
+
function resolveNextFromConfig(next, branchKey) {
|
|
84
|
+
if (!next)
|
|
85
|
+
return [];
|
|
86
|
+
if (typeof next === 'string')
|
|
87
|
+
return [next];
|
|
88
|
+
if (Array.isArray(next))
|
|
89
|
+
return next;
|
|
90
|
+
if (typeof next === 'object' && next !== null) {
|
|
91
|
+
if (!branchKey || !(branchKey in next))
|
|
92
|
+
return [];
|
|
93
|
+
const branchNext = next[branchKey];
|
|
94
|
+
return Array.isArray(branchNext) ? branchNext : [branchNext];
|
|
95
|
+
}
|
|
96
|
+
return [];
|
|
89
97
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
for (const
|
|
96
|
-
if (
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
else if (isTemplate(value)) {
|
|
100
|
-
for (const expr of value.$template.expressions) {
|
|
101
|
-
nodeIds.push(expr.$ref);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
98
|
+
function getValueAtPath(obj, path) {
|
|
99
|
+
if (!path)
|
|
100
|
+
return obj;
|
|
101
|
+
const parts = path.split('.');
|
|
102
|
+
let current = obj;
|
|
103
|
+
for (const part of parts) {
|
|
104
|
+
if (current == null)
|
|
105
|
+
return undefined;
|
|
106
|
+
current = current[part];
|
|
104
107
|
}
|
|
105
|
-
return
|
|
108
|
+
return current;
|
|
106
109
|
}
|
|
107
|
-
/**
|
|
108
|
-
* Resolve a template value using node results
|
|
109
|
-
*/
|
|
110
110
|
function resolveTemplate(template, nodeResults) {
|
|
111
111
|
const { parts, expressions } = template.$template;
|
|
112
112
|
let result = '';
|
|
@@ -123,113 +123,192 @@ function resolveTemplate(template, nodeResults) {
|
|
|
123
123
|
}
|
|
124
124
|
return result;
|
|
125
125
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
126
|
+
function resolveValue(value, nodeResults) {
|
|
127
|
+
if (isDataRef(value)) {
|
|
128
|
+
const source = nodeResults[value.$ref];
|
|
129
|
+
return value.path ? getValueAtPath(source, value.path) : source;
|
|
130
|
+
}
|
|
131
|
+
if (isTemplate(value)) {
|
|
132
|
+
return resolveTemplate(value, nodeResults);
|
|
133
|
+
}
|
|
134
|
+
if (Array.isArray(value)) {
|
|
135
|
+
return value.map((item) => resolveValue(item, nodeResults));
|
|
136
|
+
}
|
|
137
|
+
if (typeof value === 'object' && value !== null) {
|
|
138
|
+
const resolved = {};
|
|
139
|
+
for (const [k, v] of Object.entries(value)) {
|
|
140
|
+
resolved[k] = resolveValue(v, nodeResults);
|
|
141
|
+
}
|
|
142
|
+
return resolved;
|
|
143
|
+
}
|
|
144
|
+
return value;
|
|
145
|
+
}
|
|
146
|
+
function resolveSerializedInput(input, nodeResults) {
|
|
147
|
+
if (!input || Object.keys(input).length === 0)
|
|
148
|
+
return {};
|
|
130
149
|
const resolved = {};
|
|
131
|
-
for (const [key, value] of Object.entries(
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
150
|
+
for (const [key, value] of Object.entries(input)) {
|
|
151
|
+
resolved[key] = resolveValue(value, nodeResults);
|
|
152
|
+
}
|
|
153
|
+
return resolved;
|
|
154
|
+
}
|
|
155
|
+
function collectReferencedNodeIds(value, nodeIds) {
|
|
156
|
+
if (isDataRef(value)) {
|
|
157
|
+
nodeIds.push(value.$ref);
|
|
158
|
+
}
|
|
159
|
+
else if (isTemplate(value)) {
|
|
160
|
+
for (const expr of value.$template.expressions) {
|
|
161
|
+
nodeIds.push(expr.$ref);
|
|
137
162
|
}
|
|
138
|
-
|
|
139
|
-
|
|
163
|
+
}
|
|
164
|
+
else if (Array.isArray(value)) {
|
|
165
|
+
for (const item of value) {
|
|
166
|
+
collectReferencedNodeIds(item, nodeIds);
|
|
140
167
|
}
|
|
141
|
-
|
|
142
|
-
|
|
168
|
+
}
|
|
169
|
+
else if (typeof value === 'object' && value !== null) {
|
|
170
|
+
for (const v of Object.values(value)) {
|
|
171
|
+
collectReferencedNodeIds(v, nodeIds);
|
|
143
172
|
}
|
|
144
173
|
}
|
|
145
|
-
return resolved;
|
|
146
174
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
175
|
+
function extractReferencedNodeIds(input) {
|
|
176
|
+
if (!input)
|
|
177
|
+
return [];
|
|
178
|
+
const nodeIds = [];
|
|
179
|
+
for (const value of Object.values(input)) {
|
|
180
|
+
collectReferencedNodeIds(value, nodeIds);
|
|
181
|
+
}
|
|
182
|
+
return [...new Set(nodeIds)];
|
|
183
|
+
}
|
|
184
|
+
const IGNORED_REFS = new Set(['trigger', '$item', 'unknown']);
|
|
185
|
+
function normalizeNodeTargets(value) {
|
|
186
|
+
if (!value)
|
|
187
|
+
return [];
|
|
188
|
+
if (typeof value === 'string')
|
|
189
|
+
return [value];
|
|
190
|
+
if (Array.isArray(value))
|
|
191
|
+
return value.filter((v) => typeof v === 'string');
|
|
192
|
+
if (typeof value === 'object') {
|
|
193
|
+
const targets = [];
|
|
194
|
+
for (const branchTarget of Object.values(value)) {
|
|
195
|
+
targets.push(...normalizeNodeTargets(branchTarget));
|
|
196
|
+
}
|
|
197
|
+
return targets;
|
|
198
|
+
}
|
|
199
|
+
return [];
|
|
200
|
+
}
|
|
201
|
+
function validateGraphReferences(graphName, nodes, entryNodes) {
|
|
202
|
+
const nodeIds = new Set(Object.keys(nodes));
|
|
203
|
+
for (const entryId of entryNodes) {
|
|
204
|
+
if (!nodeIds.has(entryId)) {
|
|
205
|
+
throw new Error(`Workflow graph '${graphName}': entry node '${entryId}' is not defined`);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
for (const [nodeId, node] of Object.entries(nodes)) {
|
|
209
|
+
const inputRefs = extractReferencedNodeIds(node.input).filter((id) => !IGNORED_REFS.has(id));
|
|
210
|
+
for (const refId of inputRefs) {
|
|
211
|
+
if (!nodeIds.has(refId)) {
|
|
212
|
+
throw new Error(`Workflow graph '${graphName}': node '${nodeId}' references unknown node '${refId}' in input`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
const nextTargets = normalizeNodeTargets(node.next);
|
|
216
|
+
for (const nextId of nextTargets) {
|
|
217
|
+
if (!nodeIds.has(nextId)) {
|
|
218
|
+
throw new Error(`Workflow graph '${graphName}': node '${nodeId}' routes to unknown node '${nextId}'`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
const errorTargets = normalizeNodeTargets(node.onError);
|
|
222
|
+
for (const errorId of errorTargets) {
|
|
223
|
+
if (!nodeIds.has(errorId)) {
|
|
224
|
+
throw new Error(`Workflow graph '${graphName}': node '${nodeId}' onError targets unknown node '${errorId}'`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
159
227
|
}
|
|
160
|
-
return current;
|
|
161
228
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
*/
|
|
166
|
-
function getRpcName(node) {
|
|
167
|
-
const func = node.func;
|
|
168
|
-
// If func is a string, use it directly as the RPC name
|
|
169
|
-
if (typeof func === 'string') {
|
|
170
|
-
return func;
|
|
171
|
-
}
|
|
172
|
-
// Otherwise, it's a function reference - use its name
|
|
173
|
-
return func?.name || 'unknown';
|
|
229
|
+
function areDependenciesSatisfied(node, completedNodeIds) {
|
|
230
|
+
const deps = extractReferencedNodeIds(node.input).filter((id) => !IGNORED_REFS.has(id));
|
|
231
|
+
return deps.every((dep) => completedNodeIds.has(dep));
|
|
174
232
|
}
|
|
175
|
-
/**
|
|
176
|
-
* Queue a graph node for execution
|
|
177
|
-
*/
|
|
178
233
|
async function queueGraphNode(workflowService, runId, _graphName, nodeId, rpcName, input) {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
await workflowService.
|
|
234
|
+
await workflowService.insertStepState(runId, nodeId, rpcName, input, {
|
|
235
|
+
retries: 0,
|
|
236
|
+
});
|
|
237
|
+
await workflowService.queueStepWorker(runId, nodeId, rpcName, input);
|
|
183
238
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
|
|
239
|
+
export async function continueGraph(workflowService, runId, graphName, overrideMeta) {
|
|
240
|
+
const meta = overrideMeta ?? getWorkflowMeta(graphName);
|
|
241
|
+
if (!meta?.nodes) {
|
|
242
|
+
throw new Error(`Workflow graph meta '${graphName}' not found`);
|
|
243
|
+
}
|
|
244
|
+
const nodes = meta.nodes;
|
|
245
|
+
validateGraphReferences(graphName, nodes, meta.entryNodeIds ?? []);
|
|
246
|
+
const { completedNodeIds: rawCompleted, failedNodeIds: rawFailed, branchKeys: rawBranch, } = await workflowService.getCompletedGraphState(runId);
|
|
247
|
+
const completedNodeIds = remapStepNamesToNodeIds(rawCompleted, nodes, graphName);
|
|
248
|
+
const completedNodeIdSet = new Set(completedNodeIds);
|
|
249
|
+
const failedNodeIds = remapStepNamesToNodeIds(rawFailed, nodes, graphName);
|
|
250
|
+
const branchKeys = remapBranchKeys(rawBranch, nodes, graphName);
|
|
251
|
+
if (failedNodeIds.length > 0) {
|
|
252
|
+
const failedNode = failedNodeIds[0];
|
|
253
|
+
await workflowService.updateRunStatus(runId, 'failed', undefined, {
|
|
254
|
+
message: `Graph node '${failedNode}' failed after exhausting retries`,
|
|
255
|
+
stack: '',
|
|
256
|
+
code: 'GRAPH_NODE_FAILED',
|
|
257
|
+
});
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
const currentRun = await workflowService.getRun(runId);
|
|
261
|
+
if (currentRun?.status === 'suspended') {
|
|
262
|
+
return;
|
|
192
263
|
}
|
|
193
|
-
const
|
|
194
|
-
// Get completed node IDs + branch keys (lightweight, no results)
|
|
195
|
-
const { completedNodeIds, branchKeys } = await workflowService.getCompletedGraphState(runId);
|
|
196
|
-
// Find candidate next nodes from completed nodes
|
|
197
|
-
const candidateNodes = [];
|
|
264
|
+
const candidateNodes = new Set();
|
|
198
265
|
for (const nodeId of completedNodeIds) {
|
|
199
|
-
const node =
|
|
266
|
+
const node = nodes[nodeId];
|
|
200
267
|
if (!node?.next)
|
|
201
268
|
continue;
|
|
202
269
|
const nextNodes = resolveNextFromConfig(node.next, branchKeys[nodeId]);
|
|
203
|
-
|
|
270
|
+
for (const nextNode of nextNodes) {
|
|
271
|
+
candidateNodes.add(nextNode);
|
|
272
|
+
}
|
|
204
273
|
}
|
|
205
|
-
|
|
206
|
-
|
|
274
|
+
for (const entryId of meta.entryNodeIds ?? []) {
|
|
275
|
+
candidateNodes.add(entryId);
|
|
276
|
+
}
|
|
277
|
+
if (candidateNodes.size === 0 && completedNodeIds.length > 0) {
|
|
207
278
|
await workflowService.updateRunStatus(runId, 'completed');
|
|
208
279
|
return;
|
|
209
280
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
281
|
+
const unstartedNodes = await workflowService.getNodesWithoutSteps(runId, [
|
|
282
|
+
...candidateNodes,
|
|
283
|
+
]);
|
|
284
|
+
const nodesToQueue = unstartedNodes.filter((nodeId) => {
|
|
285
|
+
const node = nodes[nodeId];
|
|
286
|
+
return node && areDependenciesSatisfied(node, completedNodeIdSet);
|
|
287
|
+
});
|
|
288
|
+
if (nodesToQueue.length === 0) {
|
|
289
|
+
const allRpcNodes = Object.entries(nodes)
|
|
290
|
+
.filter(([_, n]) => n.rpcName)
|
|
291
|
+
.map(([id]) => id);
|
|
292
|
+
const allRpcCompleted = allRpcNodes.every((id) => completedNodeIdSet.has(id));
|
|
293
|
+
if (allRpcCompleted) {
|
|
294
|
+
await workflowService.updateRunStatus(runId, 'completed');
|
|
295
|
+
}
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
const run = await workflowService.getRun(runId);
|
|
299
|
+
const triggerInput = run?.input;
|
|
213
300
|
for (const nodeId of nodesToQueue) {
|
|
214
|
-
const node =
|
|
215
|
-
if (!node)
|
|
301
|
+
const node = nodes[nodeId];
|
|
302
|
+
if (!node?.rpcName)
|
|
216
303
|
continue;
|
|
217
|
-
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
const resolvedInput = resolveInputMapping(inputMapping, nodeResults);
|
|
223
|
-
const rpcName = getRpcName(node);
|
|
224
|
-
await queueGraphNode(workflowService, runId, graphName, nodeId, rpcName, resolvedInput);
|
|
304
|
+
const referencedNodeIds = extractReferencedNodeIds(node.input).filter((id) => !IGNORED_REFS.has(id));
|
|
305
|
+
const fetchedResults = await workflowService.getNodeResults(runId, referencedNodeIds);
|
|
306
|
+
const nodeResults = { trigger: triggerInput, ...fetchedResults };
|
|
307
|
+
const resolvedInput = resolveSerializedInput(node.input, nodeResults);
|
|
308
|
+
await queueGraphNode(workflowService, runId, graphName, nodeId, node.rpcName, resolvedInput);
|
|
225
309
|
}
|
|
226
310
|
}
|
|
227
|
-
|
|
228
|
-
* Execute a graph step with wire context.
|
|
229
|
-
* Called by the step worker when executing graph nodes.
|
|
230
|
-
*/
|
|
231
|
-
export async function executeGraphStep(workflowService, rpcService, runId, stepId, stepName, rpcName, data, graphName) {
|
|
232
|
-
const nodeId = stepName.replace(/^node:/, '');
|
|
311
|
+
export async function executeGraphStep(workflowService, rpcService, runId, stepId, nodeId, rpcName, data, graphName) {
|
|
233
312
|
const wireState = {};
|
|
234
313
|
const graphWire = {
|
|
235
314
|
runId,
|
|
@@ -242,61 +321,54 @@ export async function executeGraphStep(workflowService, rpcService, runId, stepI
|
|
|
242
321
|
getState: () => workflowService.getRunState(runId),
|
|
243
322
|
};
|
|
244
323
|
try {
|
|
245
|
-
// Execute the RPC with graph wire context
|
|
246
324
|
const result = await rpcService.rpcWithWire(rpcName, data, {
|
|
247
325
|
graph: graphWire,
|
|
248
326
|
});
|
|
249
|
-
// If branch was called, store the branch key
|
|
250
327
|
if (wireState.branchKey) {
|
|
251
328
|
await workflowService.setBranchTaken(stepId, wireState.branchKey);
|
|
252
329
|
}
|
|
253
330
|
return result;
|
|
254
331
|
}
|
|
255
332
|
catch (error) {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
333
|
+
if (error instanceof RPCNotFoundError) {
|
|
334
|
+
await workflowService.updateRunStatus(runId, 'suspended', undefined, {
|
|
335
|
+
message: `RPC '${rpcName}' not found. Deploy the missing function and resume.`,
|
|
336
|
+
code: 'RPC_NOT_FOUND',
|
|
337
|
+
});
|
|
338
|
+
throw error;
|
|
339
|
+
}
|
|
340
|
+
const meta = getWorkflowMeta(graphName);
|
|
341
|
+
if (meta?.nodes) {
|
|
342
|
+
const node = meta.nodes[nodeId];
|
|
260
343
|
if (node?.onError) {
|
|
261
|
-
// Route to error handler nodes
|
|
262
344
|
const errorNodes = Array.isArray(node.onError)
|
|
263
345
|
? node.onError
|
|
264
346
|
: [node.onError];
|
|
265
347
|
for (const errorNodeId of errorNodes) {
|
|
266
|
-
const errorNode =
|
|
348
|
+
const errorNode = meta.nodes[errorNodeId];
|
|
267
349
|
if (errorNode) {
|
|
268
|
-
|
|
269
|
-
// Queue error node with the error as input
|
|
270
|
-
await queueGraphNode(workflowService, runId, graphName, errorNodeId, errorRpcName, { error: { message: error.message } });
|
|
350
|
+
await queueGraphNode(workflowService, runId, graphName, errorNodeId, errorNode.rpcName, { error: { message: error.message } });
|
|
271
351
|
}
|
|
272
352
|
}
|
|
273
|
-
|
|
274
|
-
return;
|
|
353
|
+
throw error;
|
|
275
354
|
}
|
|
276
355
|
}
|
|
277
|
-
// No error handler - rethrow
|
|
278
356
|
throw error;
|
|
279
357
|
}
|
|
280
358
|
}
|
|
281
|
-
/**
|
|
282
|
-
* Handle node completion - re-triggers graph continuation
|
|
283
|
-
*/
|
|
284
359
|
export async function onGraphNodeComplete(workflowService, runId, graphName) {
|
|
285
360
|
await continueGraph(workflowService, runId, graphName);
|
|
286
361
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
async function executeGraphNodeInline(workflowService, rpcService, runId, graphName, nodeId, input,
|
|
291
|
-
const node =
|
|
362
|
+
export async function runFromMeta(workflowService, runId, meta, _rpcService) {
|
|
363
|
+
await continueGraph(workflowService, runId, meta.name, meta);
|
|
364
|
+
}
|
|
365
|
+
async function executeGraphNodeInline(workflowService, rpcService, runId, graphName, nodeId, input, nodes) {
|
|
366
|
+
const node = nodes[nodeId];
|
|
292
367
|
if (!node)
|
|
293
368
|
return;
|
|
294
|
-
const rpcName =
|
|
295
|
-
const
|
|
296
|
-
// Insert step state
|
|
297
|
-
const stepState = await workflowService.insertStepState(runId, stepName, rpcName, input, { retries: 3 });
|
|
369
|
+
const rpcName = node.rpcName;
|
|
370
|
+
const stepState = await workflowService.insertStepState(runId, nodeId, rpcName, input, { retries: 3 });
|
|
298
371
|
await workflowService.setStepRunning(stepState.stepId);
|
|
299
|
-
// Execute with graph wire context
|
|
300
372
|
const wireState = {};
|
|
301
373
|
const graphWire = {
|
|
302
374
|
runId,
|
|
@@ -312,141 +384,157 @@ async function executeGraphNodeInline(workflowService, rpcService, runId, graphN
|
|
|
312
384
|
const result = await rpcService.rpcWithWire(rpcName, input, {
|
|
313
385
|
graph: graphWire,
|
|
314
386
|
});
|
|
315
|
-
// If branch was called, store the branch key
|
|
316
387
|
if (wireState.branchKey) {
|
|
317
388
|
await workflowService.setBranchTaken(stepState.stepId, wireState.branchKey);
|
|
318
389
|
}
|
|
319
390
|
await workflowService.setStepResult(stepState.stepId, result);
|
|
320
391
|
}
|
|
321
392
|
catch (error) {
|
|
393
|
+
if (error instanceof RPCNotFoundError) {
|
|
394
|
+
await workflowService.setStepError(stepState.stepId, error);
|
|
395
|
+
await workflowService.updateRunStatus(runId, 'suspended', undefined, {
|
|
396
|
+
message: `RPC '${rpcName}' not found. Deploy the missing function and resume.`,
|
|
397
|
+
code: 'RPC_NOT_FOUND',
|
|
398
|
+
});
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
322
401
|
await workflowService.setStepError(stepState.stepId, error);
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
const errorNodes = Array.isArray(node.onError)
|
|
330
|
-
? node.onError
|
|
331
|
-
: [node.onError];
|
|
332
|
-
await Promise.all(errorNodes.map((errorNodeId) => executeGraphNodeInline(workflowService, rpcService, runId, graphName, errorNodeId, { error: { message: error.message } }, graph)));
|
|
333
|
-
return;
|
|
334
|
-
}
|
|
402
|
+
if (node?.onError) {
|
|
403
|
+
const errorNodes = Array.isArray(node.onError)
|
|
404
|
+
? node.onError
|
|
405
|
+
: [node.onError];
|
|
406
|
+
await Promise.all(errorNodes.map((errorNodeId) => executeGraphNodeInline(workflowService, rpcService, runId, graphName, errorNodeId, { error: { message: error.message } }, nodes)));
|
|
407
|
+
return;
|
|
335
408
|
}
|
|
336
|
-
// No error handler - rethrow
|
|
337
409
|
throw error;
|
|
338
410
|
}
|
|
339
411
|
}
|
|
340
|
-
|
|
341
|
-
* Continue graph execution inline (without queue)
|
|
342
|
-
* Executes nodes in parallel where possible using Promise.all
|
|
343
|
-
*/
|
|
344
|
-
async function continueGraphInline(workflowService, rpcService, runId, graphName, graph, triggerInput) {
|
|
412
|
+
async function continueGraphInline(workflowService, rpcService, runId, graphName, nodes, triggerInput, entryNodeIds) {
|
|
345
413
|
while (true) {
|
|
346
|
-
|
|
347
|
-
const
|
|
348
|
-
|
|
349
|
-
const
|
|
414
|
+
const { completedNodeIds: rawCompleted, failedNodeIds: rawFailed, branchKeys: rawBranch, } = await workflowService.getCompletedGraphState(runId);
|
|
415
|
+
const completedNodeIds = remapStepNamesToNodeIds(rawCompleted, nodes, graphName);
|
|
416
|
+
const completedNodeIdSet = new Set(completedNodeIds);
|
|
417
|
+
const failedNodeIds = remapStepNamesToNodeIds(rawFailed, nodes, graphName);
|
|
418
|
+
const branchKeys = remapBranchKeys(rawBranch, nodes, graphName);
|
|
419
|
+
if (failedNodeIds.length > 0) {
|
|
420
|
+
const failedNode = failedNodeIds[0];
|
|
421
|
+
await workflowService.updateRunStatus(runId, 'failed', undefined, {
|
|
422
|
+
message: `Graph node '${failedNode}' failed after exhausting retries`,
|
|
423
|
+
stack: '',
|
|
424
|
+
code: 'GRAPH_NODE_FAILED',
|
|
425
|
+
});
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
const candidateNodes = new Set();
|
|
350
429
|
for (const nodeId of completedNodeIds) {
|
|
351
|
-
const node =
|
|
430
|
+
const node = nodes[nodeId];
|
|
352
431
|
if (!node?.next)
|
|
353
432
|
continue;
|
|
354
433
|
const nextNodes = resolveNextFromConfig(node.next, branchKeys[nodeId]);
|
|
355
|
-
|
|
434
|
+
for (const nextNode of nextNodes) {
|
|
435
|
+
candidateNodes.add(nextNode);
|
|
436
|
+
}
|
|
356
437
|
}
|
|
357
|
-
|
|
358
|
-
|
|
438
|
+
for (const entryId of entryNodeIds) {
|
|
439
|
+
candidateNodes.add(entryId);
|
|
440
|
+
}
|
|
441
|
+
if (candidateNodes.size === 0 && completedNodeIds.length > 0) {
|
|
359
442
|
await workflowService.updateRunStatus(runId, 'completed');
|
|
360
443
|
return;
|
|
361
444
|
}
|
|
362
|
-
|
|
363
|
-
|
|
445
|
+
const unstartedNodes = await workflowService.getNodesWithoutSteps(runId, [
|
|
446
|
+
...candidateNodes,
|
|
447
|
+
]);
|
|
448
|
+
const nodesToExecute = unstartedNodes.filter((nodeId) => {
|
|
449
|
+
const node = nodes[nodeId];
|
|
450
|
+
return node && areDependenciesSatisfied(node, completedNodeIdSet);
|
|
451
|
+
});
|
|
364
452
|
if (nodesToExecute.length === 0) {
|
|
365
|
-
|
|
366
|
-
// This handles branching where only some paths are taken
|
|
367
|
-
if (completedNodeIds.length > 0) {
|
|
453
|
+
if (completedNodeIds.length > 0 && unstartedNodes.length === 0) {
|
|
368
454
|
await workflowService.updateRunStatus(runId, 'completed');
|
|
369
455
|
}
|
|
370
456
|
return;
|
|
371
457
|
}
|
|
372
|
-
// Execute all nodes in parallel
|
|
373
458
|
await Promise.all(nodesToExecute.map(async (nodeId) => {
|
|
374
|
-
const node =
|
|
375
|
-
if (!node)
|
|
459
|
+
const node = nodes[nodeId];
|
|
460
|
+
if (!node?.rpcName)
|
|
376
461
|
return;
|
|
377
|
-
|
|
378
|
-
const inputMapping = evaluateInputCallback(node);
|
|
379
|
-
// Only fetch results for nodes referenced in this node's input (excluding trigger)
|
|
380
|
-
const referencedNodeIds = extractReferencedNodeIds(inputMapping).filter((id) => id !== 'trigger');
|
|
462
|
+
const referencedNodeIds = extractReferencedNodeIds(node.input).filter((id) => !IGNORED_REFS.has(id));
|
|
381
463
|
const fetchedResults = await workflowService.getNodeResults(runId, referencedNodeIds);
|
|
382
|
-
// Merge fetched results with trigger input
|
|
383
464
|
const nodeResults = { trigger: triggerInput, ...fetchedResults };
|
|
384
|
-
const resolvedInput =
|
|
385
|
-
await executeGraphNodeInline(workflowService, rpcService, runId, graphName, nodeId, resolvedInput,
|
|
465
|
+
const resolvedInput = resolveSerializedInput(node.input, nodeResults);
|
|
466
|
+
await executeGraphNodeInline(workflowService, rpcService, runId, graphName, nodeId, resolvedInput, nodes);
|
|
386
467
|
}));
|
|
387
468
|
}
|
|
388
469
|
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
*/
|
|
393
|
-
export async function runWorkflowGraph(workflowService, graphName, triggerInput, rpcService, inline, startNode) {
|
|
394
|
-
const definition = getWorkflowGraph(graphName);
|
|
395
|
-
if (!definition) {
|
|
470
|
+
export async function runWorkflowGraph(workflowService, graphName, triggerInput, rpcService, inline, startNode, wire) {
|
|
471
|
+
const meta = getWorkflowMeta(graphName);
|
|
472
|
+
if (!meta?.nodes) {
|
|
396
473
|
throw new Error(`Workflow graph '${graphName}' not found`);
|
|
397
474
|
}
|
|
398
|
-
|
|
399
|
-
const
|
|
400
|
-
|
|
475
|
+
const nodes = meta.nodes;
|
|
476
|
+
const entryNodes = startNode
|
|
477
|
+
? [startNode]
|
|
478
|
+
: (meta.entryNodeIds ?? []);
|
|
479
|
+
validateGraphReferences(graphName, nodes, entryNodes);
|
|
401
480
|
if (entryNodes.length === 0) {
|
|
402
|
-
throw new Error(`Workflow graph '${graphName}'
|
|
481
|
+
throw new Error(`Workflow graph '${graphName}': no entry nodes found in meta or startNode`);
|
|
482
|
+
}
|
|
483
|
+
const readyEntryNodes = entryNodes.filter((nodeId) => {
|
|
484
|
+
const node = nodes[nodeId];
|
|
485
|
+
return node && areDependenciesSatisfied(node, new Set());
|
|
486
|
+
});
|
|
487
|
+
if (readyEntryNodes.length === 0) {
|
|
488
|
+
throw new Error(`Workflow graph '${graphName}': no entry nodes have satisfied dependencies`);
|
|
403
489
|
}
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
490
|
+
if (!meta.graphHash) {
|
|
491
|
+
throw new Error(`Workflow graph '${graphName}': missing graphHash in meta`);
|
|
492
|
+
}
|
|
493
|
+
const runId = await workflowService.createRun(graphName, triggerInput, inline ?? false, meta.graphHash, wire ?? { type: 'unknown' });
|
|
407
494
|
if (inline) {
|
|
408
495
|
workflowService.registerInlineRun(runId);
|
|
409
496
|
}
|
|
410
|
-
// Create nodeResults with trigger for resolving entry node inputs
|
|
411
497
|
const triggerNodeResults = { trigger: triggerInput };
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
await
|
|
425
|
-
}));
|
|
426
|
-
// Continue executing remaining nodes inline
|
|
427
|
-
await continueGraphInline(workflowService, rpcService, runId, graphName, graph, triggerInput);
|
|
428
|
-
}
|
|
429
|
-
else {
|
|
430
|
-
// Queue-based mode
|
|
431
|
-
for (const nodeId of entryNodes) {
|
|
432
|
-
const node = graph[nodeId];
|
|
433
|
-
if (!node)
|
|
434
|
-
continue;
|
|
435
|
-
// Evaluate and resolve entry node input
|
|
436
|
-
const inputMapping = evaluateInputCallback(node);
|
|
437
|
-
const resolvedInput = Object.keys(inputMapping).length > 0
|
|
438
|
-
? resolveInputMapping(inputMapping, triggerNodeResults)
|
|
439
|
-
: triggerInput;
|
|
440
|
-
const rpcName = getRpcName(node);
|
|
441
|
-
await queueGraphNode(workflowService, runId, graphName, nodeId, rpcName, resolvedInput);
|
|
498
|
+
if (inline && rpcService) {
|
|
499
|
+
const executeInline = async () => {
|
|
500
|
+
try {
|
|
501
|
+
await Promise.all(readyEntryNodes.map(async (nodeId) => {
|
|
502
|
+
const node = nodes[nodeId];
|
|
503
|
+
if (!node?.rpcName)
|
|
504
|
+
return;
|
|
505
|
+
const resolvedInput = node.input && Object.keys(node.input).length > 0
|
|
506
|
+
? resolveSerializedInput(node.input, triggerNodeResults)
|
|
507
|
+
: triggerInput;
|
|
508
|
+
await executeGraphNodeInline(workflowService, rpcService, runId, graphName, nodeId, resolvedInput, nodes);
|
|
509
|
+
}));
|
|
510
|
+
await continueGraphInline(workflowService, rpcService, runId, graphName, nodes, triggerInput, entryNodes);
|
|
442
511
|
}
|
|
443
|
-
|
|
444
|
-
|
|
512
|
+
catch (error) {
|
|
513
|
+
await workflowService.updateRunStatus(runId, 'failed', undefined, {
|
|
514
|
+
message: error.message,
|
|
515
|
+
stack: error.stack || '',
|
|
516
|
+
code: 'GRAPH_NODE_FAILED',
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
finally {
|
|
520
|
+
workflowService.unregisterInlineRun(runId);
|
|
521
|
+
}
|
|
522
|
+
};
|
|
523
|
+
await executeInline();
|
|
445
524
|
}
|
|
446
|
-
|
|
447
|
-
|
|
525
|
+
else {
|
|
526
|
+
for (const nodeId of readyEntryNodes) {
|
|
527
|
+
const node = nodes[nodeId];
|
|
528
|
+
if (!node?.rpcName)
|
|
529
|
+
continue;
|
|
530
|
+
const resolvedInput = node.input && Object.keys(node.input).length > 0
|
|
531
|
+
? resolveSerializedInput(node.input, triggerNodeResults)
|
|
532
|
+
: triggerInput;
|
|
533
|
+
await queueGraphNode(workflowService, runId, graphName, nodeId, node.rpcName, resolvedInput);
|
|
534
|
+
}
|
|
448
535
|
if (inline) {
|
|
449
536
|
workflowService.unregisterInlineRun(runId);
|
|
450
537
|
}
|
|
451
538
|
}
|
|
539
|
+
return { runId };
|
|
452
540
|
}
|