@pikku/core 0.11.2 → 0.12.0
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 +33 -2
- package/dist/crypto-utils.d.ts +2 -0
- package/dist/crypto-utils.js +78 -0
- package/dist/errors/errors.d.ts +8 -0
- package/dist/errors/errors.js +16 -0
- package/dist/errors/index.d.ts +0 -1
- package/dist/errors/index.js +0 -1
- package/dist/function/function-runner.d.ts +7 -1
- package/dist/function/function-runner.js +82 -23
- package/dist/function/functions.types.d.ts +31 -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.js +1 -10
- package/dist/index.d.ts +28 -26
- package/dist/index.js +18 -29
- package/dist/middleware/auth-apikey.d.ts +2 -2
- package/dist/middleware/auth-apikey.js +3 -3
- package/dist/middleware/auth-bearer.d.ts +2 -2
- package/dist/middleware/auth-bearer.js +3 -6
- package/dist/middleware/auth-cookie.d.ts +2 -2
- package/dist/middleware/auth-cookie.js +6 -8
- package/dist/middleware/cors.d.ts +46 -0
- package/dist/middleware/cors.js +73 -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.js +8 -10
- package/dist/permissions.js +11 -15
- package/dist/pikku-state.d.ts +1 -0
- package/dist/pikku-state.js +18 -8
- package/dist/schema.js +12 -11
- package/dist/services/ai-agent-runner-service.d.ts +24 -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/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 +94 -0
- package/dist/services/in-memory-trigger-service.d.ts +23 -0
- package/dist/services/in-memory-trigger-service.js +50 -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 +25 -11
- package/dist/services/index.js +10 -13
- package/dist/services/local-secrets.d.ts +23 -0
- package/dist/services/local-secrets.js +45 -0
- package/dist/services/local-variables.d.ts +5 -0
- package/dist/services/local-variables.js +18 -0
- package/dist/services/scheduler-service.d.ts +21 -1
- package/dist/services/scheduler-service.js +14 -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 +23 -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 +13 -0
- 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 -4
- package/dist/types/core.types.d.ts +48 -12
- package/dist/types/core.types.js +8 -1
- package/dist/types/state.types.d.ts +43 -51
- package/dist/utils.d.ts +3 -2
- package/dist/utils.js +15 -3
- package/dist/version.d.ts +6 -0
- package/dist/version.js +19 -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 +60 -0
- package/dist/wirings/ai-agent/ai-agent-prepare.js +312 -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 +96 -0
- package/dist/wirings/ai-agent/ai-agent-stream.d.ts +11 -0
- package/dist/wirings/ai-agent/ai-agent-stream.js +503 -0
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +254 -0
- package/dist/wirings/ai-agent/ai-agent.types.js +1 -0
- package/dist/wirings/ai-agent/index.d.ts +5 -0
- package/dist/wirings/ai-agent/index.js +4 -0
- package/dist/wirings/channel/channel-common.d.ts +7 -4
- package/dist/wirings/channel/channel-common.js +15 -8
- package/dist/wirings/channel/channel-handler.js +12 -3
- 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.js +7 -7
- package/dist/wirings/channel/channel.types.d.ts +5 -1
- 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.js +18 -6
- 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.js +15 -4
- 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 +1 -1
- package/dist/wirings/cli/cli-runner.js +12 -8
- package/dist/wirings/cli/cli.types.d.ts +6 -6
- 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.js +49 -23
- package/dist/wirings/http/http.types.d.ts +78 -38
- package/dist/wirings/http/index.d.ts +5 -4
- package/dist/wirings/http/index.js +4 -3
- package/dist/wirings/mcp/index.d.ts +4 -3
- package/dist/wirings/mcp/index.js +3 -3
- package/dist/wirings/mcp/mcp-runner.d.ts +1 -3
- package/dist/wirings/mcp/mcp-runner.js +25 -39
- package/dist/wirings/mcp/mcp.types.d.ts +3 -3
- 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 +2 -2
- package/dist/wirings/queue/index.js +1 -1
- package/dist/wirings/queue/queue-runner.d.ts +7 -0
- package/dist/wirings/queue/queue-runner.js +17 -6
- package/dist/wirings/queue/queue.types.d.ts +8 -2
- package/dist/wirings/rpc/index.d.ts +1 -1
- package/dist/wirings/rpc/index.js +1 -1
- package/dist/wirings/rpc/rpc-runner.d.ts +33 -5
- package/dist/wirings/rpc/rpc-runner.js +134 -16
- package/dist/wirings/rpc/rpc-types.d.ts +8 -4
- package/dist/wirings/scheduler/index.d.ts +3 -3
- package/dist/wirings/scheduler/index.js +2 -3
- package/dist/wirings/scheduler/scheduler-runner.d.ts +5 -0
- package/dist/wirings/scheduler/scheduler-runner.js +23 -5
- 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 +26 -0
- package/dist/wirings/trigger/pikku-trigger-service.js +75 -0
- package/dist/wirings/trigger/trigger-runner.d.ts +21 -8
- package/dist/wirings/trigger/trigger-runner.js +46 -18
- 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 +28 -14
- package/dist/wirings/workflow/pikku-workflow-service.js +200 -56
- package/dist/wirings/workflow/workflow-helpers.d.ts +36 -0
- package/dist/wirings/workflow/workflow-helpers.js +38 -0
- package/dist/wirings/workflow/workflow-utils.d.ts +1 -23
- package/dist/wirings/workflow/workflow-utils.js +1 -66
- package/dist/wirings/workflow/workflow.types.d.ts +40 -93
- package/package.json +13 -15
- package/run-tests.sh +4 -1
- package/src/crypto-utils.ts +99 -0
- package/src/errors/errors.ts +17 -0
- package/src/errors/index.ts +0 -1
- package/src/factory-functions.test.ts +42 -2
- package/src/function/function-runner.test.ts +4 -11
- package/src/function/function-runner.ts +114 -29
- package/src/function/functions.types.ts +62 -132
- package/src/function/index.ts +5 -2
- package/src/handle-error.ts +2 -10
- package/src/index.ts +99 -25
- package/src/middleware/auth-apikey.test.ts +15 -12
- package/src/middleware/auth-apikey.ts +3 -3
- package/src/middleware/auth-bearer.test.ts +17 -14
- package/src/middleware/auth-bearer.ts +25 -27
- package/src/middleware/auth-cookie.test.ts +16 -13
- package/src/middleware/auth-cookie.ts +6 -8
- package/src/middleware/cors.ts +96 -0
- package/src/middleware/index.ts +5 -3
- package/src/middleware/remote-auth.ts +68 -0
- package/src/middleware-runner.test.ts +122 -0
- package/src/middleware-runner.ts +12 -12
- package/src/permissions.test.ts +81 -7
- package/src/permissions.ts +15 -17
- package/src/pikku-state.ts +20 -8
- package/src/run-tests-script.test.ts +49 -0
- package/src/schema.ts +18 -15
- package/src/services/ai-agent-runner-service.ts +29 -0
- package/src/services/ai-run-state-service.ts +20 -0
- package/src/services/ai-storage-service.ts +39 -0
- package/src/services/deployment-service.ts +22 -0
- package/src/services/gopass-secrets.ts +95 -0
- package/src/services/in-memory-trigger-service.ts +68 -0
- package/src/services/in-memory-workflow-service.ts +395 -0
- package/src/services/index.ts +49 -14
- package/src/services/local-secrets.ts +51 -0
- package/src/services/local-variables.ts +22 -0
- package/src/services/scheduler-service.ts +29 -1
- package/src/services/schema-service.ts +7 -0
- package/src/services/scoped-secret-service.ts +41 -0
- package/src/services/secret-service.ts +25 -4
- package/src/services/trigger-service.ts +38 -0
- package/src/services/typed-secret-service.ts +70 -0
- package/src/services/typed-variables-service.ts +81 -0
- package/src/services/user-session-service.ts +23 -0
- package/src/services/variables-service.ts +5 -0
- package/src/services/workflow-service.ts +22 -2
- package/src/types/core.types.ts +76 -11
- package/src/types/state.types.ts +37 -63
- package/src/utils.ts +20 -6
- package/src/version.test.ts +80 -0
- package/src/version.ts +25 -0
- package/src/wirings/ai-agent/ai-agent-memory.ts +300 -0
- package/src/wirings/ai-agent/ai-agent-model-config.ts +43 -0
- package/src/wirings/ai-agent/ai-agent-prepare.ts +470 -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 +75 -0
- package/src/wirings/ai-agent/ai-agent-runner.ts +137 -0
- package/src/wirings/ai-agent/ai-agent-stream.test.ts +246 -0
- package/src/wirings/ai-agent/ai-agent-stream.ts +774 -0
- package/src/wirings/ai-agent/ai-agent.types.ts +273 -0
- package/src/wirings/ai-agent/index.ts +28 -0
- package/src/wirings/channel/channel-common.ts +32 -19
- package/src/wirings/channel/channel-handler.ts +17 -4
- package/src/wirings/channel/channel-middleware-runner.ts +119 -0
- package/src/wirings/channel/channel-runner.ts +9 -10
- package/src/wirings/channel/channel.types.ts +17 -1
- 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 +44 -1
- package/src/wirings/channel/local/local-channel-runner.ts +22 -6
- package/src/wirings/channel/serverless/index.ts +5 -1
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +20 -4
- package/src/wirings/cli/channel/index.ts +1 -1
- package/src/wirings/cli/cli-runner.test.ts +9 -9
- package/src/wirings/cli/cli-runner.ts +17 -10
- package/src/wirings/cli/cli.types.ts +11 -11
- package/src/wirings/cli/command-parser.test.ts +8 -8
- 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 +3 -3
- package/src/wirings/http/http-runner.ts +63 -29
- package/src/wirings/http/http.types.ts +121 -37
- package/src/wirings/http/index.ts +16 -4
- package/src/wirings/mcp/index.ts +27 -3
- package/src/wirings/mcp/mcp-endpoint-registry.test.ts +3 -3
- package/src/wirings/mcp/mcp-runner.ts +39 -50
- package/src/wirings/mcp/mcp.types.ts +3 -3
- 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 +14 -2
- package/src/wirings/queue/queue-runner.test.ts +97 -55
- package/src/wirings/queue/queue-runner.ts +33 -7
- package/src/wirings/queue/queue.types.ts +12 -2
- package/src/wirings/rpc/index.ts +1 -1
- package/src/wirings/rpc/rpc-runner.ts +187 -17
- package/src/wirings/rpc/rpc-types.ts +13 -4
- package/src/wirings/scheduler/index.ts +7 -4
- package/src/wirings/scheduler/scheduler-runner.test.ts +70 -26
- package/src/wirings/scheduler/scheduler-runner.ts +45 -5
- package/src/wirings/secret/index.ts +9 -0
- package/src/wirings/secret/secret.types.ts +32 -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 +134 -0
- package/src/wirings/trigger/trigger-runner.ts +80 -38
- package/src/wirings/trigger/trigger.types.ts +144 -22
- package/src/wirings/variable/index.ts +8 -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 +495 -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.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 +212 -0
- package/src/wirings/workflow/pikku-workflow-service.ts +285 -66
- package/src/wirings/workflow/workflow-helpers.ts +79 -0
- package/src/wirings/workflow/workflow-utils.ts +0 -120
- package/src/wirings/workflow/workflow.types.ts +45 -90
- 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/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
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
VariableDefinitions,
|
|
3
|
+
VariableDefinitionsMeta,
|
|
4
|
+
} from './variable.types.js'
|
|
5
|
+
|
|
6
|
+
export interface SchemaRefLike {
|
|
7
|
+
variableName: string
|
|
8
|
+
sourceFile: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function validateAndBuildVariableDefinitionsMeta(
|
|
12
|
+
definitions: VariableDefinitions,
|
|
13
|
+
schemaLookup: Map<string, SchemaRefLike>
|
|
14
|
+
): VariableDefinitionsMeta {
|
|
15
|
+
const meta: VariableDefinitionsMeta = {}
|
|
16
|
+
const variableIdToDefinition: Map<string, VariableDefinitions[0]> = new Map()
|
|
17
|
+
|
|
18
|
+
for (const def of definitions) {
|
|
19
|
+
const existingDef = variableIdToDefinition.get(def.variableId)
|
|
20
|
+
|
|
21
|
+
if (existingDef) {
|
|
22
|
+
if (def.schema && existingDef.schema) {
|
|
23
|
+
const defSchemaRef = schemaLookup.get(def.schema as string)
|
|
24
|
+
const existingSchemaRef = schemaLookup.get(existingDef.schema as string)
|
|
25
|
+
|
|
26
|
+
if (defSchemaRef && existingSchemaRef) {
|
|
27
|
+
if (
|
|
28
|
+
defSchemaRef.variableName !== existingSchemaRef.variableName ||
|
|
29
|
+
defSchemaRef.sourceFile !== existingSchemaRef.sourceFile
|
|
30
|
+
) {
|
|
31
|
+
throw new Error(
|
|
32
|
+
`Variable '${def.variableId}' is defined with different schemas.\n` +
|
|
33
|
+
` First definition: ${existingDef.sourceFile} (schema: ${existingSchemaRef.variableName})\n` +
|
|
34
|
+
` Second definition: ${def.sourceFile} (schema: ${defSchemaRef.variableName})\n` +
|
|
35
|
+
`Variables sharing a variableId must use the same schema.`
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!meta[def.name]) {
|
|
42
|
+
meta[def.name] = {
|
|
43
|
+
name: def.name,
|
|
44
|
+
displayName: def.displayName,
|
|
45
|
+
description: def.description,
|
|
46
|
+
variableId: def.variableId,
|
|
47
|
+
schema: def.schema,
|
|
48
|
+
sourceFile: def.sourceFile,
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
continue
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
variableIdToDefinition.set(def.variableId, def)
|
|
55
|
+
|
|
56
|
+
if (!meta[def.name]) {
|
|
57
|
+
meta[def.name] = {
|
|
58
|
+
name: def.name,
|
|
59
|
+
displayName: def.displayName,
|
|
60
|
+
description: def.description,
|
|
61
|
+
variableId: def.variableId,
|
|
62
|
+
schema: def.schema,
|
|
63
|
+
sourceFile: def.sourceFile,
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return meta
|
|
69
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type CoreVariable<T = unknown> = {
|
|
2
|
+
name: string
|
|
3
|
+
displayName: string
|
|
4
|
+
description?: string
|
|
5
|
+
variableId: string
|
|
6
|
+
schema: T
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type VariableDefinitionMeta = {
|
|
10
|
+
name: string
|
|
11
|
+
displayName: string
|
|
12
|
+
description?: string
|
|
13
|
+
variableId: string
|
|
14
|
+
schema?: Record<string, unknown> | string
|
|
15
|
+
sourceFile?: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type VariableDefinitionsMeta = Record<string, VariableDefinitionMeta>
|
|
19
|
+
|
|
20
|
+
export type VariableDefinitions = VariableDefinitionMeta[]
|
|
21
|
+
|
|
22
|
+
export const wireVariable = <T>(_config: CoreVariable<T>): void => {}
|
|
@@ -45,6 +45,11 @@ export type WorkflowWireSleep = (
|
|
|
45
45
|
duration: string
|
|
46
46
|
) => Promise<void>
|
|
47
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Type signature for workflow.suspend() - used by inspector
|
|
50
|
+
*/
|
|
51
|
+
export type WorkflowWireSuspend = (reason: string) => Promise<void>
|
|
52
|
+
|
|
48
53
|
/**
|
|
49
54
|
* Input source for step arguments in DSL workflows
|
|
50
55
|
*/
|
|
@@ -298,7 +303,7 @@ export interface WorkflowStepWire {
|
|
|
298
303
|
*/
|
|
299
304
|
export interface PikkuWorkflowWire {
|
|
300
305
|
/** The workflow name */
|
|
301
|
-
|
|
306
|
+
name: string
|
|
302
307
|
/** The current run ID */
|
|
303
308
|
runId: string
|
|
304
309
|
/** Get the current workflow run */
|
|
@@ -309,4 +314,7 @@ export interface PikkuWorkflowWire {
|
|
|
309
314
|
|
|
310
315
|
/** Sleep for a duration */
|
|
311
316
|
sleep: WorkflowWireSleep
|
|
317
|
+
|
|
318
|
+
/** Suspend workflow until explicitly resumed */
|
|
319
|
+
suspend: WorkflowWireSuspend
|
|
312
320
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { pikkuState } from '../../../pikku-state.js'
|
|
2
2
|
import { addFunction } from '../../../function/function-runner.js'
|
|
3
|
+
import { PikkuMissingMetaError } from '../../../errors/errors.js'
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Add a workflow to the system
|
|
@@ -10,8 +11,8 @@ export const addWorkflow = (workflowName: string, workflowFunc: any) => {
|
|
|
10
11
|
const meta = pikkuState(null, 'workflows', 'meta')
|
|
11
12
|
const workflowMeta = meta[workflowName]
|
|
12
13
|
if (!workflowMeta) {
|
|
13
|
-
throw new
|
|
14
|
-
`
|
|
14
|
+
throw new PikkuMissingMetaError(
|
|
15
|
+
`Missing generated metadata for workflow '${workflowName}'`
|
|
15
16
|
)
|
|
16
17
|
}
|
|
17
18
|
|
|
@@ -23,5 +24,5 @@ export const addWorkflow = (workflowName: string, workflowFunc: any) => {
|
|
|
23
24
|
})
|
|
24
25
|
|
|
25
26
|
// Register the function with pikku
|
|
26
|
-
addFunction(workflowMeta.
|
|
27
|
+
addFunction(workflowMeta.pikkuFuncId, workflowFunc)
|
|
27
28
|
}
|
|
@@ -54,7 +54,7 @@ export interface GraphNodeDef<
|
|
|
54
54
|
* @example
|
|
55
55
|
* ```typescript
|
|
56
56
|
* // Import the typed graph from generated types
|
|
57
|
-
* import { pikkuWorkflowGraph
|
|
57
|
+
* import { pikkuWorkflowGraph } from './.pikku/workflow/pikku-workflow-types.gen.js'
|
|
58
58
|
*
|
|
59
59
|
* export const myGraph = pikkuWorkflowGraph({
|
|
60
60
|
* name: 'myWorkflow',
|
|
@@ -71,11 +71,6 @@ export interface GraphNodeDef<
|
|
|
71
71
|
* },
|
|
72
72
|
* },
|
|
73
73
|
* })
|
|
74
|
-
*
|
|
75
|
-
* wireWorkflow({
|
|
76
|
-
* wires: { http: { route: '/start', method: 'post' } },
|
|
77
|
-
* graph: myGraph,
|
|
78
|
-
* })
|
|
79
74
|
* ```
|
|
80
75
|
*/
|
|
81
76
|
/**
|
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
import { describe, test } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
|
|
4
|
+
import { InMemoryWorkflowService } from '../../../services/in-memory-workflow-service.js'
|
|
5
|
+
import {
|
|
6
|
+
continueGraph,
|
|
7
|
+
executeGraphStep,
|
|
8
|
+
runWorkflowGraph,
|
|
9
|
+
} from './graph-runner.js'
|
|
10
|
+
import type { WorkflowRuntimeMeta } from '../workflow.types.js'
|
|
11
|
+
import { pikkuState } from '../../../pikku-state.js'
|
|
12
|
+
import { RPCNotFoundError } from '../../rpc/rpc-runner.js'
|
|
13
|
+
|
|
14
|
+
describe('graph-runner bugs', () => {
|
|
15
|
+
test('continueGraph should NOT mark workflow completed while nodes are still running', async () => {
|
|
16
|
+
const ws = new InMemoryWorkflowService()
|
|
17
|
+
|
|
18
|
+
const meta: WorkflowRuntimeMeta = {
|
|
19
|
+
name: 'testPrematureCompletion',
|
|
20
|
+
pikkuFuncId: 'testPrematureCompletion',
|
|
21
|
+
source: 'graph',
|
|
22
|
+
entryNodeIds: ['a'],
|
|
23
|
+
graphHash: 'test-hash',
|
|
24
|
+
nodes: {
|
|
25
|
+
a: { nodeId: 'a', rpcName: 'doA', next: 'b' },
|
|
26
|
+
b: { nodeId: 'b', rpcName: 'doB' },
|
|
27
|
+
},
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const runId = await ws.createRun(
|
|
31
|
+
'testPrematureCompletion',
|
|
32
|
+
{},
|
|
33
|
+
false,
|
|
34
|
+
'test-hash',
|
|
35
|
+
{ type: 'test' }
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
const stepA = await ws.insertStepState(runId, 'a', 'doA', {})
|
|
39
|
+
await ws.setStepRunning(stepA.stepId)
|
|
40
|
+
await ws.setStepResult(stepA.stepId, { ok: true })
|
|
41
|
+
|
|
42
|
+
const stepB = await ws.insertStepState(runId, 'b', 'doB', {})
|
|
43
|
+
await ws.setStepRunning(stepB.stepId)
|
|
44
|
+
|
|
45
|
+
await continueGraph(ws, runId, 'testPrematureCompletion', meta)
|
|
46
|
+
|
|
47
|
+
const run = await ws.getRun(runId)
|
|
48
|
+
assert.notEqual(
|
|
49
|
+
run?.status,
|
|
50
|
+
'completed',
|
|
51
|
+
'workflow should NOT be completed while node b is still running'
|
|
52
|
+
)
|
|
53
|
+
assert.equal(run?.status, 'running')
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
test('runWorkflowGraph should throw and not create a run for unknown input refs', async () => {
|
|
57
|
+
const ws = new InMemoryWorkflowService()
|
|
58
|
+
|
|
59
|
+
const metaState = pikkuState(null, 'workflows', 'meta')
|
|
60
|
+
metaState['testOrphanedRun'] = {
|
|
61
|
+
name: 'testOrphanedRun',
|
|
62
|
+
pikkuFuncId: 'testOrphanedRun',
|
|
63
|
+
source: 'graph',
|
|
64
|
+
entryNodeIds: ['a'],
|
|
65
|
+
graphHash: 'orphan-hash',
|
|
66
|
+
nodes: {
|
|
67
|
+
a: {
|
|
68
|
+
nodeId: 'a',
|
|
69
|
+
rpcName: 'doA',
|
|
70
|
+
input: { dep: { $ref: 'someOtherNode', path: 'value' } },
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
await assert.rejects(() => runWorkflowGraph(ws, 'testOrphanedRun', {}), {
|
|
76
|
+
message: /references unknown node 'someOtherNode' in input/,
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
const runs: string[] = [...(ws as any).runs.keys()]
|
|
80
|
+
assert.equal(
|
|
81
|
+
runs.length,
|
|
82
|
+
0,
|
|
83
|
+
'no run should be created when entry nodes have unsatisfied dependencies'
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
delete metaState['testOrphanedRun']
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
test('runWorkflowGraph should throw and not create a run for unknown next targets', async () => {
|
|
90
|
+
const ws = new InMemoryWorkflowService()
|
|
91
|
+
|
|
92
|
+
const metaState = pikkuState(null, 'workflows', 'meta')
|
|
93
|
+
metaState['testUnknownNextTarget'] = {
|
|
94
|
+
name: 'testUnknownNextTarget',
|
|
95
|
+
pikkuFuncId: 'testUnknownNextTarget',
|
|
96
|
+
source: 'graph',
|
|
97
|
+
entryNodeIds: ['a'],
|
|
98
|
+
graphHash: 'unknown-next-hash',
|
|
99
|
+
nodes: {
|
|
100
|
+
a: { nodeId: 'a', rpcName: 'doA', next: 'missingNode' },
|
|
101
|
+
},
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
await assert.rejects(
|
|
105
|
+
() => runWorkflowGraph(ws, 'testUnknownNextTarget', {}),
|
|
106
|
+
{
|
|
107
|
+
message: /routes to unknown node 'missingNode'/,
|
|
108
|
+
}
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
const runs: string[] = [...(ws as any).runs.keys()]
|
|
112
|
+
assert.equal(
|
|
113
|
+
runs.length,
|
|
114
|
+
0,
|
|
115
|
+
'no run should be created for invalid next targets'
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
delete metaState['testUnknownNextTarget']
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
test('continueGraph should throw for ambiguous template step remapping', async () => {
|
|
122
|
+
const ws = new InMemoryWorkflowService()
|
|
123
|
+
|
|
124
|
+
const meta: WorkflowRuntimeMeta = {
|
|
125
|
+
name: 'testAmbiguousTemplateStepRemap',
|
|
126
|
+
pikkuFuncId: 'testAmbiguousTemplateStepRemap',
|
|
127
|
+
source: 'graph',
|
|
128
|
+
entryNodeIds: ['start'],
|
|
129
|
+
graphHash: 'ambiguous-step-remap-hash',
|
|
130
|
+
nodes: {
|
|
131
|
+
start: { nodeId: 'start', rpcName: 'doStart' },
|
|
132
|
+
'task-${id}': { nodeId: 'task-${id}', rpcName: 'doTaskById' },
|
|
133
|
+
'task-${name}': { nodeId: 'task-${name}', rpcName: 'doTaskByName' },
|
|
134
|
+
},
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const runId = await ws.createRun(
|
|
138
|
+
'testAmbiguousTemplateStepRemap',
|
|
139
|
+
{},
|
|
140
|
+
false,
|
|
141
|
+
'ambiguous-step-remap-hash',
|
|
142
|
+
{ type: 'test' }
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
const step = await ws.insertStepState(runId, 'task-123', 'doTask', {})
|
|
146
|
+
await ws.setStepRunning(step.stepId)
|
|
147
|
+
await ws.setStepResult(step.stepId, { ok: true })
|
|
148
|
+
|
|
149
|
+
await assert.rejects(
|
|
150
|
+
() => continueGraph(ws, runId, 'testAmbiguousTemplateStepRemap', meta),
|
|
151
|
+
{
|
|
152
|
+
message: /ambiguous template node match for 'task-123'/i,
|
|
153
|
+
}
|
|
154
|
+
)
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
test('continueGraph should throw for ambiguous template branch key remapping', async () => {
|
|
158
|
+
const ws = new InMemoryWorkflowService()
|
|
159
|
+
|
|
160
|
+
const meta: WorkflowRuntimeMeta = {
|
|
161
|
+
name: 'testAmbiguousTemplateBranchRemap',
|
|
162
|
+
pikkuFuncId: 'testAmbiguousTemplateBranchRemap',
|
|
163
|
+
source: 'graph',
|
|
164
|
+
entryNodeIds: ['start'],
|
|
165
|
+
graphHash: 'ambiguous-branch-remap-hash',
|
|
166
|
+
nodes: {
|
|
167
|
+
start: { nodeId: 'start', rpcName: 'doStart' },
|
|
168
|
+
'branch-${id}': { nodeId: 'branch-${id}', rpcName: 'doBranchById' },
|
|
169
|
+
'branch-${name}': {
|
|
170
|
+
nodeId: 'branch-${name}',
|
|
171
|
+
rpcName: 'doBranchByName',
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const runId = await ws.createRun(
|
|
177
|
+
'testAmbiguousTemplateBranchRemap',
|
|
178
|
+
{},
|
|
179
|
+
false,
|
|
180
|
+
'ambiguous-branch-remap-hash',
|
|
181
|
+
{ type: 'test' }
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
const step = await ws.insertStepState(runId, 'branch-1', 'doBranch', {})
|
|
185
|
+
await ws.setBranchTaken(step.stepId, 'next')
|
|
186
|
+
|
|
187
|
+
await assert.rejects(
|
|
188
|
+
() => continueGraph(ws, runId, 'testAmbiguousTemplateBranchRemap', meta),
|
|
189
|
+
{
|
|
190
|
+
message: /ambiguous template branch key match for 'branch-1'/i,
|
|
191
|
+
}
|
|
192
|
+
)
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
test('continueGraph should queue converging next node only once', async () => {
|
|
196
|
+
const ws = new InMemoryWorkflowService()
|
|
197
|
+
const queuedNodes: string[] = []
|
|
198
|
+
|
|
199
|
+
ws.setServices(
|
|
200
|
+
{
|
|
201
|
+
queueService: {
|
|
202
|
+
add: async (_queueName: string, data: any) => {
|
|
203
|
+
if (data?.stepName) {
|
|
204
|
+
queuedNodes.push(data.stepName)
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
} as any,
|
|
209
|
+
(() => ({})) as any,
|
|
210
|
+
{} as any
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
const meta: WorkflowRuntimeMeta = {
|
|
214
|
+
name: 'testConvergingNextNode',
|
|
215
|
+
pikkuFuncId: 'testConvergingNextNode',
|
|
216
|
+
source: 'graph',
|
|
217
|
+
entryNodeIds: ['a', 'b'],
|
|
218
|
+
graphHash: 'converging-hash',
|
|
219
|
+
nodes: {
|
|
220
|
+
a: { nodeId: 'a', rpcName: 'doA', next: 'c' },
|
|
221
|
+
b: { nodeId: 'b', rpcName: 'doB', next: 'c' },
|
|
222
|
+
c: { nodeId: 'c', rpcName: 'doC' },
|
|
223
|
+
},
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const runId = await ws.createRun(
|
|
227
|
+
'testConvergingNextNode',
|
|
228
|
+
{},
|
|
229
|
+
false,
|
|
230
|
+
'converging-hash',
|
|
231
|
+
{ type: 'test' }
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
const stepA = await ws.insertStepState(runId, 'a', 'doA', {})
|
|
235
|
+
await ws.setStepRunning(stepA.stepId)
|
|
236
|
+
await ws.setStepResult(stepA.stepId, { ok: true })
|
|
237
|
+
|
|
238
|
+
const stepB = await ws.insertStepState(runId, 'b', 'doB', {})
|
|
239
|
+
await ws.setStepRunning(stepB.stepId)
|
|
240
|
+
await ws.setStepResult(stepB.stepId, { ok: true })
|
|
241
|
+
|
|
242
|
+
await continueGraph(ws, runId, 'testConvergingNextNode', meta)
|
|
243
|
+
|
|
244
|
+
assert.deepEqual(queuedNodes, ['c'])
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
test('inline graph should execute converging next node only once', async () => {
|
|
248
|
+
const ws = new InMemoryWorkflowService()
|
|
249
|
+
let cCalls = 0
|
|
250
|
+
|
|
251
|
+
const mockRpcService = {
|
|
252
|
+
rpcWithWire: async (rpcName: string) => {
|
|
253
|
+
if (rpcName === 'doA' || rpcName === 'doB') {
|
|
254
|
+
return { ok: true }
|
|
255
|
+
}
|
|
256
|
+
if (rpcName === 'doC') {
|
|
257
|
+
cCalls += 1
|
|
258
|
+
return { ok: true }
|
|
259
|
+
}
|
|
260
|
+
return {}
|
|
261
|
+
},
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const metaState = pikkuState(null, 'workflows', 'meta')
|
|
265
|
+
metaState['testInlineConvergingSingleExecution'] = {
|
|
266
|
+
name: 'testInlineConvergingSingleExecution',
|
|
267
|
+
pikkuFuncId: 'testInlineConvergingSingleExecution',
|
|
268
|
+
source: 'graph',
|
|
269
|
+
entryNodeIds: ['a', 'b'],
|
|
270
|
+
graphHash: 'inline-converging-hash',
|
|
271
|
+
nodes: {
|
|
272
|
+
a: { nodeId: 'a', rpcName: 'doA', next: 'c' },
|
|
273
|
+
b: { nodeId: 'b', rpcName: 'doB', next: 'c' },
|
|
274
|
+
c: { nodeId: 'c', rpcName: 'doC' },
|
|
275
|
+
},
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
await runWorkflowGraph(
|
|
279
|
+
ws,
|
|
280
|
+
'testInlineConvergingSingleExecution',
|
|
281
|
+
{},
|
|
282
|
+
mockRpcService,
|
|
283
|
+
true
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
assert.equal(cCalls, 1)
|
|
287
|
+
|
|
288
|
+
delete metaState['testInlineConvergingSingleExecution']
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
test('inline graph node failure should mark workflow as failed', async () => {
|
|
292
|
+
const ws = new InMemoryWorkflowService()
|
|
293
|
+
|
|
294
|
+
const mockRpcService = {
|
|
295
|
+
rpcWithWire: async (rpcName: string, _data: any, _wire: any) => {
|
|
296
|
+
if (rpcName === 'doA') return { ok: true }
|
|
297
|
+
if (rpcName === 'doB') throw new Error('doB exploded')
|
|
298
|
+
return {}
|
|
299
|
+
},
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const metaState = pikkuState(null, 'workflows', 'meta')
|
|
303
|
+
metaState['testInlineFailure'] = {
|
|
304
|
+
name: 'testInlineFailure',
|
|
305
|
+
pikkuFuncId: 'testInlineFailure',
|
|
306
|
+
source: 'graph',
|
|
307
|
+
entryNodeIds: ['a'],
|
|
308
|
+
graphHash: 'inline-fail-hash',
|
|
309
|
+
nodes: {
|
|
310
|
+
a: { nodeId: 'a', rpcName: 'doA', next: 'b' },
|
|
311
|
+
b: { nodeId: 'b', rpcName: 'doB' },
|
|
312
|
+
},
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
let runId: string | undefined
|
|
316
|
+
try {
|
|
317
|
+
const result = await runWorkflowGraph(
|
|
318
|
+
ws,
|
|
319
|
+
'testInlineFailure',
|
|
320
|
+
{},
|
|
321
|
+
mockRpcService,
|
|
322
|
+
true
|
|
323
|
+
)
|
|
324
|
+
runId = result.runId
|
|
325
|
+
} catch (_) {
|
|
326
|
+
const runs = (ws as any).runs as Map<string, any>
|
|
327
|
+
for (const [id] of runs) {
|
|
328
|
+
runId = id
|
|
329
|
+
break
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
assert.ok(runId, 'should have created a run')
|
|
334
|
+
const run = await ws.getRun(runId!)
|
|
335
|
+
assert.equal(
|
|
336
|
+
run?.status,
|
|
337
|
+
'failed',
|
|
338
|
+
'workflow should be failed after inline node error, not left running'
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
delete metaState['testInlineFailure']
|
|
342
|
+
})
|
|
343
|
+
|
|
344
|
+
test('executeGraphStep should throw after queueing onError nodes', async () => {
|
|
345
|
+
const ws = new InMemoryWorkflowService()
|
|
346
|
+
|
|
347
|
+
ws.setServices(
|
|
348
|
+
{
|
|
349
|
+
queueService: {
|
|
350
|
+
add: async () => {},
|
|
351
|
+
},
|
|
352
|
+
} as any,
|
|
353
|
+
(() => ({})) as any,
|
|
354
|
+
{} as any
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
const metaState = pikkuState(null, 'workflows', 'meta')
|
|
358
|
+
metaState['testQueuedOnErrorThrow'] = {
|
|
359
|
+
name: 'testQueuedOnErrorThrow',
|
|
360
|
+
pikkuFuncId: 'testQueuedOnErrorThrow',
|
|
361
|
+
source: 'graph',
|
|
362
|
+
entryNodeIds: ['a'],
|
|
363
|
+
graphHash: 'queued-on-error-hash',
|
|
364
|
+
nodes: {
|
|
365
|
+
a: { nodeId: 'a', rpcName: 'doA', onError: 'onErr' },
|
|
366
|
+
onErr: { nodeId: 'onErr', rpcName: 'handleErr' },
|
|
367
|
+
},
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
const runId = await ws.createRun(
|
|
371
|
+
'testQueuedOnErrorThrow',
|
|
372
|
+
{},
|
|
373
|
+
false,
|
|
374
|
+
'queued-on-error-hash',
|
|
375
|
+
{ type: 'test' }
|
|
376
|
+
)
|
|
377
|
+
const step = await ws.insertStepState(runId, 'a', 'doA', {})
|
|
378
|
+
|
|
379
|
+
const rpcService = {
|
|
380
|
+
rpcWithWire: async () => {
|
|
381
|
+
throw new Error('boom')
|
|
382
|
+
},
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
await assert.rejects(
|
|
386
|
+
() =>
|
|
387
|
+
executeGraphStep(
|
|
388
|
+
ws,
|
|
389
|
+
rpcService,
|
|
390
|
+
runId,
|
|
391
|
+
step.stepId,
|
|
392
|
+
'a',
|
|
393
|
+
'doA',
|
|
394
|
+
{},
|
|
395
|
+
'testQueuedOnErrorThrow'
|
|
396
|
+
),
|
|
397
|
+
/boom/
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
const errorStep = await ws.getStepState(runId, 'onErr')
|
|
401
|
+
assert.notEqual(
|
|
402
|
+
errorStep.stepId,
|
|
403
|
+
'',
|
|
404
|
+
'onError node should be queued as a step'
|
|
405
|
+
)
|
|
406
|
+
|
|
407
|
+
delete metaState['testQueuedOnErrorThrow']
|
|
408
|
+
})
|
|
409
|
+
|
|
410
|
+
test('executeWorkflowStep should mark graph step failed and suspend run on RPCNotFoundError', async () => {
|
|
411
|
+
const ws = new InMemoryWorkflowService()
|
|
412
|
+
|
|
413
|
+
const metaState = pikkuState(null, 'workflows', 'meta')
|
|
414
|
+
metaState['testQueuedRpcMissing'] = {
|
|
415
|
+
name: 'testQueuedRpcMissing',
|
|
416
|
+
pikkuFuncId: 'testQueuedRpcMissing',
|
|
417
|
+
source: 'graph',
|
|
418
|
+
entryNodeIds: ['a'],
|
|
419
|
+
graphHash: 'queued-rpc-missing-hash',
|
|
420
|
+
nodes: {
|
|
421
|
+
a: { nodeId: 'a', rpcName: 'missingRpc' },
|
|
422
|
+
},
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const runId = await ws.createRun(
|
|
426
|
+
'testQueuedRpcMissing',
|
|
427
|
+
{},
|
|
428
|
+
false,
|
|
429
|
+
'queued-rpc-missing-hash',
|
|
430
|
+
{ type: 'test' }
|
|
431
|
+
)
|
|
432
|
+
await ws.insertStepState(runId, 'a', 'missingRpc', {})
|
|
433
|
+
|
|
434
|
+
const rpcService = {
|
|
435
|
+
rpcWithWire: async () => {
|
|
436
|
+
throw new RPCNotFoundError('missingRpc')
|
|
437
|
+
},
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
await ws.executeWorkflowStep(runId, 'a', 'missingRpc', {}, rpcService)
|
|
441
|
+
|
|
442
|
+
const step = await ws.getStepState(runId, 'a')
|
|
443
|
+
const run = await ws.getRun(runId)
|
|
444
|
+
|
|
445
|
+
assert.equal(step.status, 'failed')
|
|
446
|
+
assert.equal(step.error?.message, 'RPC function not found: missingRpc')
|
|
447
|
+
assert.equal(run?.status, 'suspended')
|
|
448
|
+
assert.equal(run?.error?.code, 'RPC_NOT_FOUND')
|
|
449
|
+
|
|
450
|
+
delete metaState['testQueuedRpcMissing']
|
|
451
|
+
})
|
|
452
|
+
|
|
453
|
+
test('inline graph missing RPC should mark step failed and suspend run', async () => {
|
|
454
|
+
const ws = new InMemoryWorkflowService()
|
|
455
|
+
|
|
456
|
+
const metaState = pikkuState(null, 'workflows', 'meta')
|
|
457
|
+
metaState['testInlineRpcMissing'] = {
|
|
458
|
+
name: 'testInlineRpcMissing',
|
|
459
|
+
pikkuFuncId: 'testInlineRpcMissing',
|
|
460
|
+
source: 'graph',
|
|
461
|
+
entryNodeIds: ['a'],
|
|
462
|
+
graphHash: 'inline-rpc-missing-hash',
|
|
463
|
+
nodes: {
|
|
464
|
+
a: { nodeId: 'a', rpcName: 'missingInlineRpc' },
|
|
465
|
+
},
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
const rpcService = {
|
|
469
|
+
rpcWithWire: async () => {
|
|
470
|
+
throw new RPCNotFoundError('missingInlineRpc')
|
|
471
|
+
},
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
const { runId } = await runWorkflowGraph(
|
|
475
|
+
ws,
|
|
476
|
+
'testInlineRpcMissing',
|
|
477
|
+
{},
|
|
478
|
+
rpcService,
|
|
479
|
+
true
|
|
480
|
+
)
|
|
481
|
+
|
|
482
|
+
const step = await ws.getStepState(runId, 'a')
|
|
483
|
+
const run = await ws.getRun(runId)
|
|
484
|
+
|
|
485
|
+
assert.equal(step.status, 'failed')
|
|
486
|
+
assert.equal(
|
|
487
|
+
step.error?.message,
|
|
488
|
+
'RPC function not found: missingInlineRpc'
|
|
489
|
+
)
|
|
490
|
+
assert.equal(run?.status, 'suspended')
|
|
491
|
+
assert.equal(run?.error?.code, 'RPC_NOT_FOUND')
|
|
492
|
+
|
|
493
|
+
delete metaState['testInlineRpcMissing']
|
|
494
|
+
})
|
|
495
|
+
})
|