@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,75 +1,89 @@
|
|
|
1
1
|
import type { PikkuWorkflowService } from '../pikku-workflow-service.js'
|
|
2
|
-
import type {
|
|
3
|
-
GraphNodeConfig,
|
|
4
|
-
RefValue,
|
|
5
|
-
RefFn,
|
|
6
|
-
NextConfig,
|
|
7
|
-
GraphWireState,
|
|
8
|
-
PikkuGraphWire,
|
|
9
|
-
WorkflowGraphDefinition,
|
|
10
|
-
} from './workflow-graph.types.js'
|
|
11
|
-
import { createRef, isRef } from './workflow-graph.types.js'
|
|
2
|
+
import type { GraphWireState, PikkuGraphWire } from './workflow-graph.types.js'
|
|
12
3
|
import { pikkuState } from '../../../pikku-state.js'
|
|
4
|
+
import type { WorkflowRuntimeMeta, WorkflowRunWire } from '../workflow.types.js'
|
|
5
|
+
import { RPCNotFoundError } from '../../rpc/rpc-runner.js'
|
|
6
|
+
|
|
7
|
+
function buildTemplateRegex(nodeId: string): RegExp | null {
|
|
8
|
+
if (!nodeId.includes('${')) return null
|
|
9
|
+
const escaped = nodeId
|
|
10
|
+
.split(/\$\{[^}]+\}/)
|
|
11
|
+
.map((part) => part.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))
|
|
12
|
+
.join('.+')
|
|
13
|
+
return new RegExp(`^${escaped}$`)
|
|
14
|
+
}
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const meta = pikkuState(null, 'workflows', 'meta')
|
|
24
|
-
const workflowMeta = meta[workflowName]
|
|
25
|
-
if (!workflowMeta) {
|
|
26
|
-
throw new Error(
|
|
27
|
-
`Workflow metadata not found for '${workflowName}'. Make sure to run the CLI to generate metadata.`
|
|
28
|
-
)
|
|
16
|
+
function remapStepNamesToNodeIds(
|
|
17
|
+
stepNames: string[],
|
|
18
|
+
nodes: Record<string, any>,
|
|
19
|
+
graphName: string
|
|
20
|
+
): string[] {
|
|
21
|
+
const templatePatterns = new Map<string, RegExp>()
|
|
22
|
+
for (const nodeId of Object.keys(nodes)) {
|
|
23
|
+
const regex = buildTemplateRegex(nodeId)
|
|
24
|
+
if (regex) templatePatterns.set(nodeId, regex)
|
|
29
25
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
26
|
+
if (templatePatterns.size === 0) return stepNames
|
|
27
|
+
return stepNames.map((name) => {
|
|
28
|
+
if (nodes[name]) return name
|
|
29
|
+
const matches: string[] = []
|
|
30
|
+
for (const [nodeId, regex] of templatePatterns) {
|
|
31
|
+
if (regex.test(name)) matches.push(nodeId)
|
|
32
|
+
}
|
|
33
|
+
if (matches.length > 1) {
|
|
34
|
+
throw new Error(
|
|
35
|
+
`Workflow graph '${graphName}': ambiguous template node match for '${name}' (${matches.join(', ')})`
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
if (matches.length === 1) {
|
|
39
|
+
return matches[0]!
|
|
40
|
+
}
|
|
41
|
+
return name
|
|
37
42
|
})
|
|
38
43
|
}
|
|
39
44
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
|
|
45
|
+
function remapBranchKeys(
|
|
46
|
+
branchKeys: Record<string, string>,
|
|
47
|
+
nodes: Record<string, any>,
|
|
48
|
+
graphName: string
|
|
49
|
+
): Record<string, string> {
|
|
50
|
+
const templatePatterns = new Map<string, RegExp>()
|
|
51
|
+
for (const nodeId of Object.keys(nodes)) {
|
|
52
|
+
const regex = buildTemplateRegex(nodeId)
|
|
53
|
+
if (regex) templatePatterns.set(nodeId, regex)
|
|
54
|
+
}
|
|
55
|
+
if (templatePatterns.size === 0) return branchKeys
|
|
56
|
+
const remapped: Record<string, string> = {}
|
|
57
|
+
for (const [key, value] of Object.entries(branchKeys)) {
|
|
58
|
+
let mappedKey = key
|
|
59
|
+
if (!nodes[key]) {
|
|
60
|
+
const matches: string[] = []
|
|
61
|
+
for (const [nodeId, regex] of templatePatterns) {
|
|
62
|
+
if (regex.test(key)) matches.push(nodeId)
|
|
63
|
+
}
|
|
64
|
+
if (matches.length > 1) {
|
|
65
|
+
throw new Error(
|
|
66
|
+
`Workflow graph '${graphName}': ambiguous template branch key match for '${key}' (${matches.join(', ')})`
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
if (matches.length === 1) {
|
|
70
|
+
mappedKey = matches[0]!
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
remapped[mappedKey] = value
|
|
74
|
+
}
|
|
75
|
+
return remapped
|
|
48
76
|
}
|
|
49
77
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
): string[] {
|
|
58
|
-
if (!next) return []
|
|
59
|
-
|
|
60
|
-
if (typeof next === 'string') return [next]
|
|
61
|
-
if (Array.isArray(next)) return next
|
|
62
|
-
|
|
63
|
-
// Record (branching) - use branch key set by graph.branch()
|
|
64
|
-
if (!branchKey || !(branchKey in next)) return []
|
|
65
|
-
|
|
66
|
-
const branchNext = next[branchKey]
|
|
67
|
-
return Array.isArray(branchNext) ? branchNext : [branchNext]
|
|
78
|
+
function isDataRef(value: unknown): value is { $ref: string; path?: string } {
|
|
79
|
+
return (
|
|
80
|
+
typeof value === 'object' &&
|
|
81
|
+
value !== null &&
|
|
82
|
+
'$ref' in value &&
|
|
83
|
+
typeof (value as any).$ref === 'string'
|
|
84
|
+
)
|
|
68
85
|
}
|
|
69
86
|
|
|
70
|
-
/**
|
|
71
|
-
* Template value - represents a string template with variable interpolation
|
|
72
|
-
*/
|
|
73
87
|
interface TemplateValue {
|
|
74
88
|
$template: {
|
|
75
89
|
parts: string[]
|
|
@@ -77,9 +91,6 @@ interface TemplateValue {
|
|
|
77
91
|
}
|
|
78
92
|
}
|
|
79
93
|
|
|
80
|
-
/**
|
|
81
|
-
* Check if a value is a template
|
|
82
|
-
*/
|
|
83
94
|
function isTemplate(value: unknown): value is TemplateValue {
|
|
84
95
|
return (
|
|
85
96
|
typeof value === 'object' &&
|
|
@@ -89,73 +100,37 @@ function isTemplate(value: unknown): value is TemplateValue {
|
|
|
89
100
|
)
|
|
90
101
|
}
|
|
91
102
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
function createTemplate(templateStr: string, refs: RefValue[]): TemplateValue {
|
|
96
|
-
const parts: string[] = []
|
|
97
|
-
const expressions: Array<{ $ref: string; path?: string }> = []
|
|
98
|
-
|
|
99
|
-
const regex = /\$(\d+)/g
|
|
100
|
-
let lastIndex = 0
|
|
101
|
-
let match
|
|
102
|
-
|
|
103
|
-
while ((match = regex.exec(templateStr)) !== null) {
|
|
104
|
-
parts.push(templateStr.slice(lastIndex, match.index))
|
|
105
|
-
const refIndex = parseInt(match[1]!, 10)
|
|
106
|
-
const refValue = refs[refIndex]
|
|
107
|
-
if (refValue) {
|
|
108
|
-
expressions.push({ $ref: refValue.nodeId, path: refValue.path })
|
|
109
|
-
} else {
|
|
110
|
-
expressions.push({ $ref: 'unknown' })
|
|
111
|
-
}
|
|
112
|
-
lastIndex = regex.lastIndex
|
|
113
|
-
}
|
|
114
|
-
parts.push(templateStr.slice(lastIndex))
|
|
115
|
-
|
|
116
|
-
return { $template: { parts, expressions } }
|
|
103
|
+
function getWorkflowMeta(name: string): WorkflowRuntimeMeta | undefined {
|
|
104
|
+
const meta = pikkuState(null, 'workflows', 'meta')
|
|
105
|
+
return meta[name]
|
|
117
106
|
}
|
|
118
107
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
*/
|
|
122
|
-
function evaluateInputCallback(
|
|
123
|
-
node: GraphNodeConfig
|
|
124
|
-
): Record<string, unknown | RefValue | TemplateValue> {
|
|
125
|
-
if (!node.input) return {}
|
|
108
|
+
function resolveNextFromConfig(next: unknown, branchKey?: string): string[] {
|
|
109
|
+
if (!next) return []
|
|
126
110
|
|
|
127
|
-
|
|
128
|
-
|
|
111
|
+
if (typeof next === 'string') return [next]
|
|
112
|
+
if (Array.isArray(next)) return next
|
|
129
113
|
|
|
130
|
-
|
|
131
|
-
|
|
114
|
+
if (typeof next === 'object' && next !== null) {
|
|
115
|
+
if (!branchKey || !(branchKey in next)) return []
|
|
116
|
+
const branchNext = (next as Record<string, string | string[]>)[branchKey]!
|
|
117
|
+
return Array.isArray(branchNext) ? branchNext : [branchNext]
|
|
118
|
+
}
|
|
132
119
|
|
|
133
|
-
|
|
134
|
-
return (node.input as any)(ref, template)
|
|
120
|
+
return []
|
|
135
121
|
}
|
|
136
122
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
)
|
|
143
|
-
|
|
144
|
-
for (const value of Object.values(inputMapping)) {
|
|
145
|
-
if (isRef(value)) {
|
|
146
|
-
nodeIds.push(value.nodeId)
|
|
147
|
-
} else if (isTemplate(value)) {
|
|
148
|
-
for (const expr of value.$template.expressions) {
|
|
149
|
-
nodeIds.push(expr.$ref)
|
|
150
|
-
}
|
|
151
|
-
}
|
|
123
|
+
function getValueAtPath(obj: any, path: string): any {
|
|
124
|
+
if (!path) return obj
|
|
125
|
+
const parts = path.split('.')
|
|
126
|
+
let current = obj
|
|
127
|
+
for (const part of parts) {
|
|
128
|
+
if (current == null) return undefined
|
|
129
|
+
current = current[part]
|
|
152
130
|
}
|
|
153
|
-
return
|
|
131
|
+
return current
|
|
154
132
|
}
|
|
155
133
|
|
|
156
|
-
/**
|
|
157
|
-
* Resolve a template value using node results
|
|
158
|
-
*/
|
|
159
134
|
function resolveTemplate(
|
|
160
135
|
template: TemplateValue,
|
|
161
136
|
nodeResults: Record<string, any>
|
|
@@ -165,7 +140,7 @@ function resolveTemplate(
|
|
|
165
140
|
for (let i = 0; i < parts.length; i++) {
|
|
166
141
|
result += parts[i]
|
|
167
142
|
if (i < expressions.length) {
|
|
168
|
-
const expr = expressions[i]
|
|
143
|
+
const expr = expressions[i]!
|
|
169
144
|
const nodeResult = nodeResults[expr.$ref]
|
|
170
145
|
const value = expr.path
|
|
171
146
|
? getValueAtPath(nodeResult, expr.path)
|
|
@@ -176,62 +151,144 @@ function resolveTemplate(
|
|
|
176
151
|
return result
|
|
177
152
|
}
|
|
178
153
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
154
|
+
function resolveValue(value: unknown, nodeResults: Record<string, any>): any {
|
|
155
|
+
if (isDataRef(value)) {
|
|
156
|
+
const source = nodeResults[value.$ref]
|
|
157
|
+
return value.path ? getValueAtPath(source, value.path) : source
|
|
158
|
+
}
|
|
159
|
+
if (isTemplate(value)) {
|
|
160
|
+
return resolveTemplate(value, nodeResults)
|
|
161
|
+
}
|
|
162
|
+
if (Array.isArray(value)) {
|
|
163
|
+
return value.map((item) => resolveValue(item, nodeResults))
|
|
164
|
+
}
|
|
165
|
+
if (typeof value === 'object' && value !== null) {
|
|
166
|
+
const resolved: Record<string, any> = {}
|
|
167
|
+
for (const [k, v] of Object.entries(value)) {
|
|
168
|
+
resolved[k] = resolveValue(v, nodeResults)
|
|
169
|
+
}
|
|
170
|
+
return resolved
|
|
171
|
+
}
|
|
172
|
+
return value
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function resolveSerializedInput(
|
|
176
|
+
input: Record<string, unknown> | undefined,
|
|
184
177
|
nodeResults: Record<string, any>
|
|
185
178
|
): Record<string, any> {
|
|
179
|
+
if (!input || Object.keys(input).length === 0) return {}
|
|
180
|
+
|
|
186
181
|
const resolved: Record<string, any> = {}
|
|
182
|
+
for (const [key, value] of Object.entries(input)) {
|
|
183
|
+
resolved[key] = resolveValue(value, nodeResults)
|
|
184
|
+
}
|
|
185
|
+
return resolved
|
|
186
|
+
}
|
|
187
187
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
188
|
+
function collectReferencedNodeIds(value: unknown, nodeIds: string[]): void {
|
|
189
|
+
if (isDataRef(value)) {
|
|
190
|
+
nodeIds.push(value.$ref)
|
|
191
|
+
} else if (isTemplate(value)) {
|
|
192
|
+
for (const expr of value.$template.expressions) {
|
|
193
|
+
nodeIds.push(expr.$ref)
|
|
194
|
+
}
|
|
195
|
+
} else if (Array.isArray(value)) {
|
|
196
|
+
for (const item of value) {
|
|
197
|
+
collectReferencedNodeIds(item, nodeIds)
|
|
198
|
+
}
|
|
199
|
+
} else if (typeof value === 'object' && value !== null) {
|
|
200
|
+
for (const v of Object.values(value)) {
|
|
201
|
+
collectReferencedNodeIds(v, nodeIds)
|
|
198
202
|
}
|
|
199
203
|
}
|
|
204
|
+
}
|
|
200
205
|
|
|
201
|
-
|
|
206
|
+
function extractReferencedNodeIds(
|
|
207
|
+
input: Record<string, unknown> | undefined
|
|
208
|
+
): string[] {
|
|
209
|
+
if (!input) return []
|
|
210
|
+
const nodeIds: string[] = []
|
|
211
|
+
for (const value of Object.values(input)) {
|
|
212
|
+
collectReferencedNodeIds(value, nodeIds)
|
|
213
|
+
}
|
|
214
|
+
return [...new Set(nodeIds)]
|
|
202
215
|
}
|
|
203
216
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
if (
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
217
|
+
const IGNORED_REFS = new Set(['trigger', '$item', 'unknown'])
|
|
218
|
+
|
|
219
|
+
function normalizeNodeTargets(value: unknown): string[] {
|
|
220
|
+
if (!value) return []
|
|
221
|
+
if (typeof value === 'string') return [value]
|
|
222
|
+
if (Array.isArray(value)) return value.filter((v) => typeof v === 'string')
|
|
223
|
+
if (typeof value === 'object') {
|
|
224
|
+
const targets: string[] = []
|
|
225
|
+
for (const branchTarget of Object.values(
|
|
226
|
+
value as Record<string, unknown>
|
|
227
|
+
)) {
|
|
228
|
+
targets.push(...normalizeNodeTargets(branchTarget))
|
|
229
|
+
}
|
|
230
|
+
return targets
|
|
214
231
|
}
|
|
215
|
-
return
|
|
232
|
+
return []
|
|
216
233
|
}
|
|
217
234
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
235
|
+
function validateGraphReferences(
|
|
236
|
+
graphName: string,
|
|
237
|
+
nodes: Record<string, any>,
|
|
238
|
+
entryNodes: string[]
|
|
239
|
+
): void {
|
|
240
|
+
const nodeIds = new Set(Object.keys(nodes))
|
|
241
|
+
|
|
242
|
+
for (const entryId of entryNodes) {
|
|
243
|
+
if (!nodeIds.has(entryId)) {
|
|
244
|
+
throw new Error(
|
|
245
|
+
`Workflow graph '${graphName}': entry node '${entryId}' is not defined`
|
|
246
|
+
)
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
for (const [nodeId, node] of Object.entries(nodes)) {
|
|
251
|
+
const inputRefs = extractReferencedNodeIds(node.input).filter(
|
|
252
|
+
(id) => !IGNORED_REFS.has(id)
|
|
253
|
+
)
|
|
254
|
+
for (const refId of inputRefs) {
|
|
255
|
+
if (!nodeIds.has(refId)) {
|
|
256
|
+
throw new Error(
|
|
257
|
+
`Workflow graph '${graphName}': node '${nodeId}' references unknown node '${refId}' in input`
|
|
258
|
+
)
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const nextTargets = normalizeNodeTargets(node.next)
|
|
263
|
+
for (const nextId of nextTargets) {
|
|
264
|
+
if (!nodeIds.has(nextId)) {
|
|
265
|
+
throw new Error(
|
|
266
|
+
`Workflow graph '${graphName}': node '${nodeId}' routes to unknown node '${nextId}'`
|
|
267
|
+
)
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const errorTargets = normalizeNodeTargets(node.onError)
|
|
272
|
+
for (const errorId of errorTargets) {
|
|
273
|
+
if (!nodeIds.has(errorId)) {
|
|
274
|
+
throw new Error(
|
|
275
|
+
`Workflow graph '${graphName}': node '${nodeId}' onError targets unknown node '${errorId}'`
|
|
276
|
+
)
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function areDependenciesSatisfied(
|
|
283
|
+
node: { input?: Record<string, unknown> },
|
|
284
|
+
completedNodeIds: Set<string>
|
|
285
|
+
): boolean {
|
|
286
|
+
const deps = extractReferencedNodeIds(node.input).filter(
|
|
287
|
+
(id) => !IGNORED_REFS.has(id)
|
|
288
|
+
)
|
|
289
|
+
return deps.every((dep) => completedNodeIds.has(dep))
|
|
230
290
|
}
|
|
231
291
|
|
|
232
|
-
/**
|
|
233
|
-
* Queue a graph node for execution
|
|
234
|
-
*/
|
|
235
292
|
async function queueGraphNode(
|
|
236
293
|
workflowService: PikkuWorkflowService,
|
|
237
294
|
runId: string,
|
|
@@ -240,105 +297,137 @@ async function queueGraphNode(
|
|
|
240
297
|
rpcName: string,
|
|
241
298
|
input: any
|
|
242
299
|
): Promise<void> {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
`node:${nodeId}`,
|
|
248
|
-
rpcName,
|
|
249
|
-
input,
|
|
250
|
-
{ retries: 3 }
|
|
251
|
-
)
|
|
252
|
-
await workflowService.resumeWorkflow(runId)
|
|
300
|
+
await workflowService.insertStepState(runId, nodeId, rpcName, input, {
|
|
301
|
+
retries: 0,
|
|
302
|
+
})
|
|
303
|
+
await workflowService.queueStepWorker(runId, nodeId, rpcName, input)
|
|
253
304
|
}
|
|
254
305
|
|
|
255
|
-
/**
|
|
256
|
-
* Continue graph execution
|
|
257
|
-
* Non-blocking - finds pending nodes, resolves inputs, queues them for execution
|
|
258
|
-
*/
|
|
259
306
|
export async function continueGraph(
|
|
260
307
|
workflowService: PikkuWorkflowService,
|
|
261
308
|
runId: string,
|
|
262
|
-
graphName: string
|
|
309
|
+
graphName: string,
|
|
310
|
+
overrideMeta?: WorkflowRuntimeMeta
|
|
263
311
|
): Promise<void> {
|
|
264
|
-
const
|
|
265
|
-
if (!
|
|
266
|
-
throw new Error(`Workflow graph '${graphName}' not found`)
|
|
312
|
+
const meta = overrideMeta ?? getWorkflowMeta(graphName)
|
|
313
|
+
if (!meta?.nodes) {
|
|
314
|
+
throw new Error(`Workflow graph meta '${graphName}' not found`)
|
|
267
315
|
}
|
|
268
316
|
|
|
269
|
-
const
|
|
317
|
+
const nodes = meta.nodes
|
|
318
|
+
validateGraphReferences(graphName, nodes, meta.entryNodeIds ?? [])
|
|
319
|
+
|
|
320
|
+
const {
|
|
321
|
+
completedNodeIds: rawCompleted,
|
|
322
|
+
failedNodeIds: rawFailed,
|
|
323
|
+
branchKeys: rawBranch,
|
|
324
|
+
} = await workflowService.getCompletedGraphState(runId)
|
|
325
|
+
const completedNodeIds = remapStepNamesToNodeIds(
|
|
326
|
+
rawCompleted,
|
|
327
|
+
nodes,
|
|
328
|
+
graphName
|
|
329
|
+
)
|
|
330
|
+
const completedNodeIdSet = new Set(completedNodeIds)
|
|
331
|
+
const failedNodeIds = remapStepNamesToNodeIds(rawFailed, nodes, graphName)
|
|
332
|
+
const branchKeys = remapBranchKeys(rawBranch, nodes, graphName)
|
|
333
|
+
|
|
334
|
+
if (failedNodeIds.length > 0) {
|
|
335
|
+
const failedNode = failedNodeIds[0]!
|
|
336
|
+
await workflowService.updateRunStatus(runId, 'failed', undefined, {
|
|
337
|
+
message: `Graph node '${failedNode}' failed after exhausting retries`,
|
|
338
|
+
stack: '',
|
|
339
|
+
code: 'GRAPH_NODE_FAILED',
|
|
340
|
+
})
|
|
341
|
+
return
|
|
342
|
+
}
|
|
270
343
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
344
|
+
const currentRun = await workflowService.getRun(runId)
|
|
345
|
+
if (currentRun?.status === 'suspended') {
|
|
346
|
+
return
|
|
347
|
+
}
|
|
274
348
|
|
|
275
|
-
|
|
276
|
-
const candidateNodes: string[] = []
|
|
349
|
+
const candidateNodes = new Set<string>()
|
|
277
350
|
|
|
278
351
|
for (const nodeId of completedNodeIds) {
|
|
279
|
-
const node =
|
|
352
|
+
const node = nodes[nodeId]
|
|
280
353
|
if (!node?.next) continue
|
|
281
354
|
|
|
282
355
|
const nextNodes = resolveNextFromConfig(node.next, branchKeys[nodeId])
|
|
283
|
-
|
|
356
|
+
for (const nextNode of nextNodes) {
|
|
357
|
+
candidateNodes.add(nextNode)
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
for (const entryId of meta.entryNodeIds ?? []) {
|
|
362
|
+
candidateNodes.add(entryId)
|
|
284
363
|
}
|
|
285
364
|
|
|
286
|
-
if (candidateNodes.
|
|
287
|
-
// No more nodes to run - graph complete
|
|
365
|
+
if (candidateNodes.size === 0 && completedNodeIds.length > 0) {
|
|
288
366
|
await workflowService.updateRunStatus(runId, 'completed')
|
|
289
367
|
return
|
|
290
368
|
}
|
|
291
369
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
candidateNodes
|
|
296
|
-
)
|
|
370
|
+
const unstartedNodes = await workflowService.getNodesWithoutSteps(runId, [
|
|
371
|
+
...candidateNodes,
|
|
372
|
+
])
|
|
297
373
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
374
|
+
const nodesToQueue = unstartedNodes.filter((nodeId) => {
|
|
375
|
+
const node = nodes[nodeId]
|
|
376
|
+
return node && areDependenciesSatisfied(node, completedNodeIdSet)
|
|
377
|
+
})
|
|
302
378
|
|
|
303
|
-
|
|
304
|
-
const
|
|
379
|
+
if (nodesToQueue.length === 0) {
|
|
380
|
+
const allRpcNodes = Object.entries(nodes)
|
|
381
|
+
.filter(([_, n]) => n.rpcName)
|
|
382
|
+
.map(([id]) => id)
|
|
383
|
+
const allRpcCompleted = allRpcNodes.every((id) =>
|
|
384
|
+
completedNodeIdSet.has(id)
|
|
385
|
+
)
|
|
386
|
+
if (allRpcCompleted) {
|
|
387
|
+
await workflowService.updateRunStatus(runId, 'completed')
|
|
388
|
+
}
|
|
389
|
+
return
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const run = await workflowService.getRun(runId)
|
|
393
|
+
const triggerInput = run?.input
|
|
394
|
+
|
|
395
|
+
for (const nodeId of nodesToQueue) {
|
|
396
|
+
const node = nodes[nodeId]
|
|
397
|
+
if (!node?.rpcName) continue
|
|
305
398
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
399
|
+
const referencedNodeIds = extractReferencedNodeIds(node.input).filter(
|
|
400
|
+
(id) => !IGNORED_REFS.has(id)
|
|
401
|
+
)
|
|
402
|
+
const fetchedResults = await workflowService.getNodeResults(
|
|
309
403
|
runId,
|
|
310
404
|
referencedNodeIds
|
|
311
405
|
)
|
|
312
406
|
|
|
313
|
-
const
|
|
314
|
-
const
|
|
407
|
+
const nodeResults = { trigger: triggerInput, ...fetchedResults }
|
|
408
|
+
const resolvedInput = resolveSerializedInput(node.input, nodeResults)
|
|
315
409
|
|
|
316
410
|
await queueGraphNode(
|
|
317
411
|
workflowService,
|
|
318
412
|
runId,
|
|
319
413
|
graphName,
|
|
320
414
|
nodeId,
|
|
321
|
-
rpcName,
|
|
415
|
+
node.rpcName,
|
|
322
416
|
resolvedInput
|
|
323
417
|
)
|
|
324
418
|
}
|
|
325
419
|
}
|
|
326
420
|
|
|
327
|
-
/**
|
|
328
|
-
* Execute a graph step with wire context.
|
|
329
|
-
* Called by the step worker when executing graph nodes.
|
|
330
|
-
*/
|
|
331
421
|
export async function executeGraphStep(
|
|
332
422
|
workflowService: PikkuWorkflowService,
|
|
333
423
|
rpcService: any,
|
|
334
424
|
runId: string,
|
|
335
425
|
stepId: string,
|
|
336
|
-
|
|
426
|
+
nodeId: string,
|
|
337
427
|
rpcName: string,
|
|
338
428
|
data: any,
|
|
339
429
|
graphName: string
|
|
340
430
|
): Promise<any> {
|
|
341
|
-
const nodeId = stepName.replace(/^node:/, '')
|
|
342
431
|
const wireState: GraphWireState = {}
|
|
343
432
|
const graphWire: PikkuGraphWire = {
|
|
344
433
|
runId,
|
|
@@ -353,54 +442,50 @@ export async function executeGraphStep(
|
|
|
353
442
|
}
|
|
354
443
|
|
|
355
444
|
try {
|
|
356
|
-
// Execute the RPC with graph wire context
|
|
357
445
|
const result = await rpcService.rpcWithWire(rpcName, data, {
|
|
358
446
|
graph: graphWire,
|
|
359
447
|
})
|
|
360
448
|
|
|
361
|
-
// If branch was called, store the branch key
|
|
362
449
|
if (wireState.branchKey) {
|
|
363
450
|
await workflowService.setBranchTaken(stepId, wireState.branchKey)
|
|
364
451
|
}
|
|
365
452
|
|
|
366
453
|
return result
|
|
367
454
|
} catch (error) {
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
455
|
+
if (error instanceof RPCNotFoundError) {
|
|
456
|
+
await workflowService.updateRunStatus(runId, 'suspended', undefined, {
|
|
457
|
+
message: `RPC '${rpcName}' not found. Deploy the missing function and resume.`,
|
|
458
|
+
code: 'RPC_NOT_FOUND',
|
|
459
|
+
})
|
|
460
|
+
throw error
|
|
461
|
+
}
|
|
462
|
+
const meta = getWorkflowMeta(graphName)
|
|
463
|
+
if (meta?.nodes) {
|
|
464
|
+
const node = meta.nodes[nodeId]
|
|
372
465
|
if (node?.onError) {
|
|
373
|
-
// Route to error handler nodes
|
|
374
466
|
const errorNodes = Array.isArray(node.onError)
|
|
375
467
|
? node.onError
|
|
376
468
|
: [node.onError]
|
|
377
469
|
for (const errorNodeId of errorNodes) {
|
|
378
|
-
const errorNode =
|
|
470
|
+
const errorNode = meta.nodes[errorNodeId]
|
|
379
471
|
if (errorNode) {
|
|
380
|
-
const errorRpcName = getRpcName(errorNode)
|
|
381
|
-
// Queue error node with the error as input
|
|
382
472
|
await queueGraphNode(
|
|
383
473
|
workflowService,
|
|
384
474
|
runId,
|
|
385
475
|
graphName,
|
|
386
476
|
errorNodeId,
|
|
387
|
-
|
|
477
|
+
errorNode.rpcName,
|
|
388
478
|
{ error: { message: (error as Error).message } }
|
|
389
479
|
)
|
|
390
480
|
}
|
|
391
481
|
}
|
|
392
|
-
|
|
393
|
-
return
|
|
482
|
+
throw error
|
|
394
483
|
}
|
|
395
484
|
}
|
|
396
|
-
// No error handler - rethrow
|
|
397
485
|
throw error
|
|
398
486
|
}
|
|
399
487
|
}
|
|
400
488
|
|
|
401
|
-
/**
|
|
402
|
-
* Handle node completion - re-triggers graph continuation
|
|
403
|
-
*/
|
|
404
489
|
export async function onGraphNodeComplete(
|
|
405
490
|
workflowService: PikkuWorkflowService,
|
|
406
491
|
runId: string,
|
|
@@ -409,9 +494,15 @@ export async function onGraphNodeComplete(
|
|
|
409
494
|
await continueGraph(workflowService, runId, graphName)
|
|
410
495
|
}
|
|
411
496
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
497
|
+
export async function runFromMeta(
|
|
498
|
+
workflowService: PikkuWorkflowService,
|
|
499
|
+
runId: string,
|
|
500
|
+
meta: WorkflowRuntimeMeta,
|
|
501
|
+
_rpcService: any
|
|
502
|
+
): Promise<void> {
|
|
503
|
+
await continueGraph(workflowService, runId, meta.name, meta)
|
|
504
|
+
}
|
|
505
|
+
|
|
415
506
|
async function executeGraphNodeInline(
|
|
416
507
|
workflowService: PikkuWorkflowService,
|
|
417
508
|
rpcService: any,
|
|
@@ -419,18 +510,16 @@ async function executeGraphNodeInline(
|
|
|
419
510
|
graphName: string,
|
|
420
511
|
nodeId: string,
|
|
421
512
|
input: any,
|
|
422
|
-
|
|
513
|
+
nodes: Record<string, any>
|
|
423
514
|
): Promise<void> {
|
|
424
|
-
const node =
|
|
515
|
+
const node = nodes[nodeId]
|
|
425
516
|
if (!node) return
|
|
426
517
|
|
|
427
|
-
const rpcName =
|
|
428
|
-
const stepName = `node:${nodeId}`
|
|
518
|
+
const rpcName = node.rpcName
|
|
429
519
|
|
|
430
|
-
// Insert step state
|
|
431
520
|
const stepState = await workflowService.insertStepState(
|
|
432
521
|
runId,
|
|
433
|
-
|
|
522
|
+
nodeId,
|
|
434
523
|
rpcName,
|
|
435
524
|
input,
|
|
436
525
|
{ retries: 3 }
|
|
@@ -438,7 +527,6 @@ async function executeGraphNodeInline(
|
|
|
438
527
|
|
|
439
528
|
await workflowService.setStepRunning(stepState.stepId)
|
|
440
529
|
|
|
441
|
-
// Execute with graph wire context
|
|
442
530
|
const wireState: GraphWireState = {}
|
|
443
531
|
const graphWire: PikkuGraphWire = {
|
|
444
532
|
runId,
|
|
@@ -457,7 +545,6 @@ async function executeGraphNodeInline(
|
|
|
457
545
|
graph: graphWire,
|
|
458
546
|
})
|
|
459
547
|
|
|
460
|
-
// If branch was called, store the branch key
|
|
461
548
|
if (wireState.branchKey) {
|
|
462
549
|
await workflowService.setBranchTaken(
|
|
463
550
|
stepState.stepId,
|
|
@@ -467,109 +554,125 @@ async function executeGraphNodeInline(
|
|
|
467
554
|
|
|
468
555
|
await workflowService.setStepResult(stepState.stepId, result)
|
|
469
556
|
} catch (error) {
|
|
557
|
+
if (error instanceof RPCNotFoundError) {
|
|
558
|
+
await workflowService.setStepError(stepState.stepId, error as Error)
|
|
559
|
+
await workflowService.updateRunStatus(runId, 'suspended', undefined, {
|
|
560
|
+
message: `RPC '${rpcName}' not found. Deploy the missing function and resume.`,
|
|
561
|
+
code: 'RPC_NOT_FOUND',
|
|
562
|
+
})
|
|
563
|
+
return
|
|
564
|
+
}
|
|
470
565
|
await workflowService.setStepError(stepState.stepId, error as Error)
|
|
471
566
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
runId,
|
|
487
|
-
graphName,
|
|
488
|
-
errorNodeId,
|
|
489
|
-
{ error: { message: (error as Error).message } },
|
|
490
|
-
graph
|
|
491
|
-
)
|
|
567
|
+
if (node?.onError) {
|
|
568
|
+
const errorNodes = Array.isArray(node.onError)
|
|
569
|
+
? node.onError
|
|
570
|
+
: [node.onError]
|
|
571
|
+
await Promise.all(
|
|
572
|
+
errorNodes.map((errorNodeId: string) =>
|
|
573
|
+
executeGraphNodeInline(
|
|
574
|
+
workflowService,
|
|
575
|
+
rpcService,
|
|
576
|
+
runId,
|
|
577
|
+
graphName,
|
|
578
|
+
errorNodeId,
|
|
579
|
+
{ error: { message: (error as Error).message } },
|
|
580
|
+
nodes
|
|
492
581
|
)
|
|
493
582
|
)
|
|
494
|
-
|
|
495
|
-
|
|
583
|
+
)
|
|
584
|
+
return
|
|
496
585
|
}
|
|
497
|
-
// No error handler - rethrow
|
|
498
586
|
throw error
|
|
499
587
|
}
|
|
500
588
|
}
|
|
501
589
|
|
|
502
|
-
/**
|
|
503
|
-
* Continue graph execution inline (without queue)
|
|
504
|
-
* Executes nodes in parallel where possible using Promise.all
|
|
505
|
-
*/
|
|
506
590
|
async function continueGraphInline(
|
|
507
591
|
workflowService: PikkuWorkflowService,
|
|
508
592
|
rpcService: any,
|
|
509
593
|
runId: string,
|
|
510
594
|
graphName: string,
|
|
511
|
-
|
|
512
|
-
triggerInput: any
|
|
595
|
+
nodes: Record<string, any>,
|
|
596
|
+
triggerInput: any,
|
|
597
|
+
entryNodeIds: string[]
|
|
513
598
|
): Promise<void> {
|
|
514
599
|
while (true) {
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
600
|
+
const {
|
|
601
|
+
completedNodeIds: rawCompleted,
|
|
602
|
+
failedNodeIds: rawFailed,
|
|
603
|
+
branchKeys: rawBranch,
|
|
604
|
+
} = await workflowService.getCompletedGraphState(runId)
|
|
605
|
+
const completedNodeIds = remapStepNamesToNodeIds(
|
|
606
|
+
rawCompleted,
|
|
607
|
+
nodes,
|
|
608
|
+
graphName
|
|
609
|
+
)
|
|
610
|
+
const completedNodeIdSet = new Set(completedNodeIds)
|
|
611
|
+
const failedNodeIds = remapStepNamesToNodeIds(rawFailed, nodes, graphName)
|
|
612
|
+
const branchKeys = remapBranchKeys(rawBranch, nodes, graphName)
|
|
613
|
+
|
|
614
|
+
if (failedNodeIds.length > 0) {
|
|
615
|
+
const failedNode = failedNodeIds[0]!
|
|
616
|
+
await workflowService.updateRunStatus(runId, 'failed', undefined, {
|
|
617
|
+
message: `Graph node '${failedNode}' failed after exhausting retries`,
|
|
618
|
+
stack: '',
|
|
619
|
+
code: 'GRAPH_NODE_FAILED',
|
|
620
|
+
})
|
|
621
|
+
return
|
|
622
|
+
}
|
|
518
623
|
|
|
519
|
-
|
|
520
|
-
const candidateNodes: string[] = []
|
|
624
|
+
const candidateNodes = new Set<string>()
|
|
521
625
|
|
|
522
626
|
for (const nodeId of completedNodeIds) {
|
|
523
|
-
const node =
|
|
627
|
+
const node = nodes[nodeId]
|
|
524
628
|
if (!node?.next) continue
|
|
525
629
|
|
|
526
630
|
const nextNodes = resolveNextFromConfig(node.next, branchKeys[nodeId])
|
|
527
|
-
|
|
631
|
+
for (const nextNode of nextNodes) {
|
|
632
|
+
candidateNodes.add(nextNode)
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
for (const entryId of entryNodeIds) {
|
|
637
|
+
candidateNodes.add(entryId)
|
|
528
638
|
}
|
|
529
639
|
|
|
530
|
-
if (candidateNodes.
|
|
531
|
-
// No more nodes to run - graph complete
|
|
640
|
+
if (candidateNodes.size === 0 && completedNodeIds.length > 0) {
|
|
532
641
|
await workflowService.updateRunStatus(runId, 'completed')
|
|
533
642
|
return
|
|
534
643
|
}
|
|
535
644
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
)
|
|
645
|
+
const unstartedNodes = await workflowService.getNodesWithoutSteps(runId, [
|
|
646
|
+
...candidateNodes,
|
|
647
|
+
])
|
|
648
|
+
|
|
649
|
+
const nodesToExecute = unstartedNodes.filter((nodeId) => {
|
|
650
|
+
const node = nodes[nodeId]
|
|
651
|
+
return node && areDependenciesSatisfied(node, completedNodeIdSet)
|
|
652
|
+
})
|
|
541
653
|
|
|
542
654
|
if (nodesToExecute.length === 0) {
|
|
543
|
-
|
|
544
|
-
// This handles branching where only some paths are taken
|
|
545
|
-
if (completedNodeIds.length > 0) {
|
|
655
|
+
if (completedNodeIds.length > 0 && unstartedNodes.length === 0) {
|
|
546
656
|
await workflowService.updateRunStatus(runId, 'completed')
|
|
547
657
|
}
|
|
548
658
|
return
|
|
549
659
|
}
|
|
550
660
|
|
|
551
|
-
// Execute all nodes in parallel
|
|
552
661
|
await Promise.all(
|
|
553
662
|
nodesToExecute.map(async (nodeId) => {
|
|
554
|
-
const node =
|
|
555
|
-
if (!node) return
|
|
663
|
+
const node = nodes[nodeId]
|
|
664
|
+
if (!node?.rpcName) return
|
|
556
665
|
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
// Only fetch results for nodes referenced in this node's input (excluding trigger)
|
|
561
|
-
const referencedNodeIds = extractReferencedNodeIds(inputMapping).filter(
|
|
562
|
-
(id) => id !== 'trigger'
|
|
666
|
+
const referencedNodeIds = extractReferencedNodeIds(node.input).filter(
|
|
667
|
+
(id) => !IGNORED_REFS.has(id)
|
|
563
668
|
)
|
|
564
669
|
const fetchedResults = await workflowService.getNodeResults(
|
|
565
670
|
runId,
|
|
566
671
|
referencedNodeIds
|
|
567
672
|
)
|
|
568
673
|
|
|
569
|
-
// Merge fetched results with trigger input
|
|
570
674
|
const nodeResults = { trigger: triggerInput, ...fetchedResults }
|
|
571
|
-
|
|
572
|
-
const resolvedInput = resolveInputMapping(inputMapping, nodeResults)
|
|
675
|
+
const resolvedInput = resolveSerializedInput(node.input, nodeResults)
|
|
573
676
|
|
|
574
677
|
await executeGraphNodeInline(
|
|
575
678
|
workflowService,
|
|
@@ -578,117 +681,136 @@ async function continueGraphInline(
|
|
|
578
681
|
graphName,
|
|
579
682
|
nodeId,
|
|
580
683
|
resolvedInput,
|
|
581
|
-
|
|
684
|
+
nodes
|
|
582
685
|
)
|
|
583
686
|
})
|
|
584
687
|
)
|
|
585
688
|
}
|
|
586
689
|
}
|
|
587
690
|
|
|
588
|
-
/**
|
|
589
|
-
* Start a workflow graph execution
|
|
590
|
-
* @param startNode - Optional starting node ID (from wire config). If not provided, uses wires.api from graph definition.
|
|
591
|
-
*/
|
|
592
691
|
export async function runWorkflowGraph(
|
|
593
692
|
workflowService: PikkuWorkflowService,
|
|
594
693
|
graphName: string,
|
|
595
694
|
triggerInput: any,
|
|
596
695
|
rpcService?: any,
|
|
597
696
|
inline?: boolean,
|
|
598
|
-
startNode?: string
|
|
697
|
+
startNode?: string,
|
|
698
|
+
wire?: WorkflowRunWire
|
|
599
699
|
): Promise<{ runId: string }> {
|
|
600
|
-
const
|
|
601
|
-
if (!
|
|
700
|
+
const meta = getWorkflowMeta(graphName)
|
|
701
|
+
if (!meta?.nodes) {
|
|
602
702
|
throw new Error(`Workflow graph '${graphName}' not found`)
|
|
603
703
|
}
|
|
604
704
|
|
|
605
|
-
|
|
606
|
-
const
|
|
607
|
-
|
|
705
|
+
const nodes = meta.nodes
|
|
706
|
+
const entryNodes: string[] = startNode
|
|
707
|
+
? [startNode]
|
|
708
|
+
: (meta.entryNodeIds ?? [])
|
|
709
|
+
validateGraphReferences(graphName, nodes, entryNodes)
|
|
608
710
|
|
|
609
711
|
if (entryNodes.length === 0) {
|
|
610
712
|
throw new Error(
|
|
611
|
-
`Workflow graph '${graphName}'
|
|
713
|
+
`Workflow graph '${graphName}': no entry nodes found in meta or startNode`
|
|
714
|
+
)
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
const readyEntryNodes = entryNodes.filter((nodeId) => {
|
|
718
|
+
const node = nodes[nodeId]
|
|
719
|
+
return node && areDependenciesSatisfied(node, new Set())
|
|
720
|
+
})
|
|
721
|
+
|
|
722
|
+
if (readyEntryNodes.length === 0) {
|
|
723
|
+
throw new Error(
|
|
724
|
+
`Workflow graph '${graphName}': no entry nodes have satisfied dependencies`
|
|
612
725
|
)
|
|
613
726
|
}
|
|
614
727
|
|
|
615
|
-
|
|
616
|
-
|
|
728
|
+
if (!meta.graphHash) {
|
|
729
|
+
throw new Error(`Workflow graph '${graphName}': missing graphHash in meta`)
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
const runId = await workflowService.createRun(
|
|
733
|
+
graphName,
|
|
734
|
+
triggerInput,
|
|
735
|
+
inline ?? false,
|
|
736
|
+
meta.graphHash,
|
|
737
|
+
wire ?? { type: 'unknown' }
|
|
738
|
+
)
|
|
617
739
|
|
|
618
|
-
// Register as inline for fast lookup
|
|
619
740
|
if (inline) {
|
|
620
741
|
workflowService.registerInlineRun(runId)
|
|
621
742
|
}
|
|
622
743
|
|
|
623
|
-
// Create nodeResults with trigger for resolving entry node inputs
|
|
624
744
|
const triggerNodeResults = { trigger: triggerInput }
|
|
625
745
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
// Evaluate and resolve entry node input
|
|
635
|
-
const inputMapping = evaluateInputCallback(node)
|
|
636
|
-
const resolvedInput =
|
|
637
|
-
Object.keys(inputMapping).length > 0
|
|
638
|
-
? resolveInputMapping(inputMapping, triggerNodeResults)
|
|
639
|
-
: triggerInput
|
|
640
|
-
|
|
641
|
-
await executeGraphNodeInline(
|
|
642
|
-
workflowService,
|
|
643
|
-
rpcService,
|
|
644
|
-
runId,
|
|
645
|
-
graphName,
|
|
646
|
-
nodeId,
|
|
647
|
-
resolvedInput,
|
|
648
|
-
graph
|
|
649
|
-
)
|
|
650
|
-
})
|
|
651
|
-
)
|
|
746
|
+
if (inline && rpcService) {
|
|
747
|
+
const executeInline = async () => {
|
|
748
|
+
try {
|
|
749
|
+
await Promise.all(
|
|
750
|
+
readyEntryNodes.map(async (nodeId) => {
|
|
751
|
+
const node = nodes[nodeId]
|
|
752
|
+
if (!node?.rpcName) return
|
|
652
753
|
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
Object.keys(inputMapping).length > 0
|
|
672
|
-
? resolveInputMapping(inputMapping, triggerNodeResults)
|
|
673
|
-
: triggerInput
|
|
674
|
-
|
|
675
|
-
const rpcName = getRpcName(node)
|
|
676
|
-
await queueGraphNode(
|
|
754
|
+
const resolvedInput =
|
|
755
|
+
node.input && Object.keys(node.input).length > 0
|
|
756
|
+
? resolveSerializedInput(node.input, triggerNodeResults)
|
|
757
|
+
: triggerInput
|
|
758
|
+
|
|
759
|
+
await executeGraphNodeInline(
|
|
760
|
+
workflowService,
|
|
761
|
+
rpcService,
|
|
762
|
+
runId,
|
|
763
|
+
graphName,
|
|
764
|
+
nodeId,
|
|
765
|
+
resolvedInput,
|
|
766
|
+
nodes
|
|
767
|
+
)
|
|
768
|
+
})
|
|
769
|
+
)
|
|
770
|
+
|
|
771
|
+
await continueGraphInline(
|
|
677
772
|
workflowService,
|
|
773
|
+
rpcService,
|
|
678
774
|
runId,
|
|
679
775
|
graphName,
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
776
|
+
nodes,
|
|
777
|
+
triggerInput,
|
|
778
|
+
entryNodes
|
|
683
779
|
)
|
|
780
|
+
} catch (error) {
|
|
781
|
+
await workflowService.updateRunStatus(runId, 'failed', undefined, {
|
|
782
|
+
message: (error as Error).message,
|
|
783
|
+
stack: (error as Error).stack || '',
|
|
784
|
+
code: 'GRAPH_NODE_FAILED',
|
|
785
|
+
})
|
|
786
|
+
} finally {
|
|
787
|
+
workflowService.unregisterInlineRun(runId)
|
|
684
788
|
}
|
|
685
789
|
}
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
790
|
+
await executeInline()
|
|
791
|
+
} else {
|
|
792
|
+
for (const nodeId of readyEntryNodes) {
|
|
793
|
+
const node = nodes[nodeId]
|
|
794
|
+
if (!node?.rpcName) continue
|
|
795
|
+
|
|
796
|
+
const resolvedInput =
|
|
797
|
+
node.input && Object.keys(node.input).length > 0
|
|
798
|
+
? resolveSerializedInput(node.input, triggerNodeResults)
|
|
799
|
+
: triggerInput
|
|
800
|
+
|
|
801
|
+
await queueGraphNode(
|
|
802
|
+
workflowService,
|
|
803
|
+
runId,
|
|
804
|
+
graphName,
|
|
805
|
+
nodeId,
|
|
806
|
+
node.rpcName,
|
|
807
|
+
resolvedInput
|
|
808
|
+
)
|
|
809
|
+
}
|
|
690
810
|
if (inline) {
|
|
691
811
|
workflowService.unregisterInlineRun(runId)
|
|
692
812
|
}
|
|
693
813
|
}
|
|
814
|
+
|
|
815
|
+
return { runId }
|
|
694
816
|
}
|