@xyne/workflow-sdk 3.2.36 → 3.2.38
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/dist/agents/agent-step.d.ts +2 -2
- package/dist/agents/host-agent-step.d.ts +1 -1
- package/dist/builder/index.d.ts +2 -2
- package/dist/builder/index.d.ts.map +1 -1
- package/dist/builder/index.js +1 -1
- package/dist/builder/index.js.map +1 -1
- package/dist/client/events-client.d.ts +57 -0
- package/dist/client/events-client.d.ts.map +1 -0
- package/dist/client/events-client.js +107 -0
- package/dist/client/events-client.js.map +1 -0
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/sse.d.ts +30 -0
- package/dist/client/sse.d.ts.map +1 -0
- package/dist/client/sse.js +76 -0
- package/dist/client/sse.js.map +1 -0
- package/dist/client/types.d.ts +31 -6
- package/dist/client/types.d.ts.map +1 -1
- package/dist/client/url.d.ts +11 -0
- package/dist/client/url.d.ts.map +1 -0
- package/dist/client/url.js +28 -0
- package/dist/client/url.js.map +1 -0
- package/dist/client/workflow-client.d.ts +1 -1
- package/dist/client/workflow-client.d.ts.map +1 -1
- package/dist/client/workflow-client.js +32 -20
- package/dist/client/workflow-client.js.map +1 -1
- package/dist/common/citation-ref.d.ts +4 -4
- package/dist/common/credentials.d.ts +107 -0
- package/dist/common/credentials.d.ts.map +1 -1
- package/dist/common/credentials.js +67 -0
- package/dist/common/credentials.js.map +1 -1
- package/dist/common/index.d.ts +2 -2
- package/dist/common/index.d.ts.map +1 -1
- package/dist/common/index.js +2 -2
- package/dist/common/index.js.map +1 -1
- package/dist/connectors/builtin/builtin-connector.d.ts +32 -0
- package/dist/connectors/builtin/builtin-connector.d.ts.map +1 -0
- package/dist/connectors/builtin/builtin-connector.js +62 -0
- package/dist/connectors/builtin/builtin-connector.js.map +1 -0
- package/dist/connectors/builtin/credentials.d.ts +18 -0
- package/dist/connectors/builtin/credentials.d.ts.map +1 -0
- package/dist/connectors/builtin/credentials.js +50 -0
- package/dist/connectors/builtin/credentials.js.map +1 -0
- package/dist/connectors/builtin/steps/code.step.d.ts +99 -0
- package/dist/connectors/builtin/steps/code.step.d.ts.map +1 -0
- package/dist/connectors/builtin/steps/code.step.js +152 -0
- package/dist/connectors/builtin/steps/code.step.js.map +1 -0
- package/dist/connectors/builtin/steps/conditional.step.d.ts +182 -0
- package/dist/connectors/builtin/steps/conditional.step.d.ts.map +1 -0
- package/dist/connectors/builtin/steps/conditional.step.js +82 -0
- package/dist/connectors/builtin/steps/conditional.step.js.map +1 -0
- package/dist/connectors/builtin/steps/dedup.step.d.ts +65 -0
- package/dist/connectors/builtin/steps/dedup.step.d.ts.map +1 -0
- package/dist/connectors/builtin/steps/dedup.step.js +61 -0
- package/dist/connectors/builtin/steps/dedup.step.js.map +1 -0
- package/dist/connectors/builtin/steps/http-request.step.d.ts +1027 -0
- package/dist/connectors/builtin/steps/http-request.step.d.ts.map +1 -0
- package/dist/connectors/builtin/steps/http-request.step.js +497 -0
- package/dist/connectors/builtin/steps/http-request.step.js.map +1 -0
- package/dist/connectors/builtin/steps/loop.step.d.ts +100 -0
- package/dist/connectors/builtin/steps/loop.step.d.ts.map +1 -0
- package/dist/connectors/builtin/steps/loop.step.js +73 -0
- package/dist/connectors/builtin/steps/loop.step.js.map +1 -0
- package/dist/connectors/builtin/steps/map.step.d.ts +148 -0
- package/dist/connectors/builtin/steps/map.step.d.ts.map +1 -0
- package/dist/connectors/builtin/steps/map.step.js +111 -0
- package/dist/connectors/builtin/steps/map.step.js.map +1 -0
- package/dist/connectors/builtin/steps/parallel.step.d.ts +246 -0
- package/dist/connectors/builtin/steps/parallel.step.d.ts.map +1 -0
- package/dist/connectors/builtin/steps/parallel.step.js +175 -0
- package/dist/connectors/builtin/steps/parallel.step.js.map +1 -0
- package/dist/connectors/builtin/steps/ssrf-guard.d.ts +9 -0
- package/dist/connectors/builtin/steps/ssrf-guard.d.ts.map +1 -0
- package/dist/connectors/builtin/steps/ssrf-guard.js +115 -0
- package/dist/connectors/builtin/steps/ssrf-guard.js.map +1 -0
- package/dist/connectors/builtin/steps/switch.step.d.ts +235 -0
- package/dist/connectors/builtin/steps/switch.step.d.ts.map +1 -0
- package/dist/connectors/builtin/steps/switch.step.js +101 -0
- package/dist/connectors/builtin/steps/switch.step.js.map +1 -0
- package/dist/connectors/builtin/steps/wait.step.d.ts +1072 -0
- package/dist/connectors/builtin/steps/wait.step.d.ts.map +1 -0
- package/dist/connectors/builtin/steps/wait.step.js +254 -0
- package/dist/connectors/builtin/steps/wait.step.js.map +1 -0
- package/dist/connectors/builtin/triggers/default-cron-trigger.d.ts +44 -0
- package/dist/connectors/builtin/triggers/default-cron-trigger.d.ts.map +1 -0
- package/dist/connectors/builtin/triggers/default-cron-trigger.js +31 -0
- package/dist/connectors/builtin/triggers/default-cron-trigger.js.map +1 -0
- package/dist/connectors/builtin/triggers/default-event-trigger.d.ts +32 -0
- package/dist/connectors/builtin/triggers/default-event-trigger.d.ts.map +1 -0
- package/dist/connectors/builtin/triggers/default-event-trigger.js +21 -0
- package/dist/connectors/builtin/triggers/default-event-trigger.js.map +1 -0
- package/dist/connectors/builtin/triggers/default-manual-trigger.d.ts +45 -0
- package/dist/connectors/builtin/triggers/default-manual-trigger.d.ts.map +1 -0
- package/dist/connectors/builtin/triggers/default-manual-trigger.js +51 -0
- package/dist/connectors/builtin/triggers/default-manual-trigger.js.map +1 -0
- package/dist/connectors/builtin/triggers/default-webhook-v2-trigger.d.ts +31 -0
- package/dist/connectors/builtin/triggers/default-webhook-v2-trigger.d.ts.map +1 -0
- package/dist/connectors/builtin/triggers/default-webhook-v2-trigger.js +40 -0
- package/dist/connectors/builtin/triggers/default-webhook-v2-trigger.js.map +1 -0
- package/dist/connectors/core/base-connector.d.ts +45 -0
- package/dist/connectors/core/base-connector.d.ts.map +1 -0
- package/dist/connectors/core/base-connector.js +3 -0
- package/dist/connectors/core/base-connector.js.map +1 -0
- package/dist/connectors/core/connector-registry.d.ts +130 -0
- package/dist/connectors/core/connector-registry.d.ts.map +1 -0
- package/dist/connectors/core/connector-registry.js +357 -0
- package/dist/connectors/core/connector-registry.js.map +1 -0
- package/dist/connectors/core/credentials.d.ts +104 -0
- package/dist/connectors/core/credentials.d.ts.map +1 -0
- package/dist/connectors/core/credentials.js +67 -0
- package/dist/connectors/core/credentials.js.map +1 -0
- package/dist/connectors/core/index.d.ts +7 -0
- package/dist/connectors/core/index.d.ts.map +1 -0
- package/dist/connectors/core/index.js +5 -0
- package/dist/connectors/core/index.js.map +1 -0
- package/dist/engine/available-context.d.ts +3 -4
- package/dist/engine/available-context.d.ts.map +1 -1
- package/dist/engine/available-context.js +17 -13
- package/dist/engine/available-context.js.map +1 -1
- package/dist/engine/config-validator.d.ts +13 -5
- package/dist/engine/config-validator.d.ts.map +1 -1
- package/dist/engine/config-validator.js +89 -11
- package/dist/engine/config-validator.js.map +1 -1
- package/dist/engine/credential-resolver.d.ts +42 -0
- package/dist/engine/credential-resolver.d.ts.map +1 -0
- package/dist/engine/credential-resolver.js +63 -0
- package/dist/engine/credential-resolver.js.map +1 -0
- package/dist/engine/workflow-executor.d.ts +15 -9
- package/dist/engine/workflow-executor.d.ts.map +1 -1
- package/dist/engine/workflow-executor.js +31 -40
- package/dist/engine/workflow-executor.js.map +1 -1
- package/dist/events/in-memory-adapter.d.ts +15 -0
- package/dist/events/in-memory-adapter.d.ts.map +1 -0
- package/dist/events/in-memory-adapter.js +50 -0
- package/dist/events/in-memory-adapter.js.map +1 -0
- package/dist/events/types.d.ts +154 -0
- package/dist/events/types.d.ts.map +1 -0
- package/dist/events/types.js +34 -0
- package/dist/events/types.js.map +1 -0
- package/dist/index.d.ts +50 -31
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +39 -16
- package/dist/index.js.map +1 -1
- package/dist/ingest/body.d.ts +18 -0
- package/dist/ingest/body.d.ts.map +1 -0
- package/dist/ingest/body.js +47 -0
- package/dist/ingest/body.js.map +1 -0
- package/dist/ingest/filter.d.ts +11 -0
- package/dist/ingest/filter.d.ts.map +1 -0
- package/dist/ingest/filter.js +23 -0
- package/dist/ingest/filter.js.map +1 -0
- package/dist/ingest/headers.d.ts +3 -0
- package/dist/ingest/headers.d.ts.map +1 -0
- package/dist/ingest/headers.js +11 -0
- package/dist/ingest/headers.js.map +1 -0
- package/dist/ingest/types.d.ts +50 -0
- package/dist/ingest/types.d.ts.map +1 -0
- package/dist/ingest/types.js +9 -0
- package/dist/ingest/types.js.map +1 -0
- package/dist/persistence/in-memory-adapter.d.ts +4 -8
- package/dist/persistence/in-memory-adapter.d.ts.map +1 -1
- package/dist/persistence/in-memory-adapter.js +8 -25
- package/dist/persistence/in-memory-adapter.js.map +1 -1
- package/dist/persistence/types.d.ts +5 -19
- package/dist/persistence/types.d.ts.map +1 -1
- package/dist/router/types.d.ts +31 -3
- package/dist/router/types.d.ts.map +1 -1
- package/dist/router/workflow-router.d.ts +4 -3
- package/dist/router/workflow-router.d.ts.map +1 -1
- package/dist/router/workflow-router.js +258 -63
- package/dist/router/workflow-router.js.map +1 -1
- package/dist/runtime/types.d.ts +36 -56
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/workflow-runtime.d.ts +70 -46
- package/dist/runtime/workflow-runtime.d.ts.map +1 -1
- package/dist/runtime/workflow-runtime.js +217 -141
- package/dist/runtime/workflow-runtime.js.map +1 -1
- package/dist/steps/base-step.d.ts +23 -0
- package/dist/steps/base-step.d.ts.map +1 -1
- package/dist/steps/base-step.js +22 -0
- package/dist/steps/base-step.js.map +1 -1
- package/dist/steps/step-descriptor.d.ts +52 -0
- package/dist/steps/step-descriptor.d.ts.map +1 -0
- package/dist/steps/step-descriptor.js +32 -0
- package/dist/steps/step-descriptor.js.map +1 -0
- package/dist/testing/authz-conformance.d.ts.map +1 -1
- package/dist/testing/authz-conformance.js +6 -7
- package/dist/testing/authz-conformance.js.map +1 -1
- package/dist/testing/index.d.ts +1 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +1 -0
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/mock-step-context.d.ts +1 -0
- package/dist/testing/mock-step-context.d.ts.map +1 -1
- package/dist/testing/mock-step-context.js +1 -0
- package/dist/testing/mock-step-context.js.map +1 -1
- package/dist/testing/test-connector.d.ts +40 -0
- package/dist/testing/test-connector.d.ts.map +1 -0
- package/dist/testing/test-connector.js +39 -0
- package/dist/testing/test-connector.js.map +1 -0
- package/dist/triggers/api-trigger.d.ts +15 -0
- package/dist/triggers/api-trigger.d.ts.map +1 -0
- package/dist/triggers/api-trigger.js +14 -0
- package/dist/triggers/api-trigger.js.map +1 -0
- package/dist/triggers/base-trigger.d.ts +29 -0
- package/dist/triggers/base-trigger.d.ts.map +1 -1
- package/dist/triggers/base-trigger.js +16 -0
- package/dist/triggers/base-trigger.js.map +1 -1
- package/dist/triggers/trigger-descriptor.d.ts +42 -0
- package/dist/triggers/trigger-descriptor.d.ts.map +1 -0
- package/dist/triggers/trigger-descriptor.js +29 -0
- package/dist/triggers/trigger-descriptor.js.map +1 -0
- package/dist/triggers/webhook-trigger.d.ts +31 -38
- package/dist/triggers/webhook-trigger.d.ts.map +1 -1
- package/dist/triggers/webhook-trigger.js +19 -6
- package/dist/triggers/webhook-trigger.js.map +1 -1
- package/dist/types/known-types.d.ts +0 -1
- package/dist/types/known-types.d.ts.map +1 -1
- package/dist/types/known-types.js +0 -1
- package/dist/types/known-types.js.map +1 -1
- package/dist/types/validation.d.ts +3 -1
- package/dist/types/validation.d.ts.map +1 -1
- package/dist/types/validation.js +2 -0
- package/dist/types/validation.js.map +1 -1
- package/dist/types/workflow-config.d.ts +23 -0
- package/dist/types/workflow-config.d.ts.map +1 -1
- package/dist/types/workflow-config.js +8 -0
- package/dist/types/workflow-config.js.map +1 -1
- package/dist/util/credential-slot-schema.d.ts +20 -0
- package/dist/util/credential-slot-schema.d.ts.map +1 -0
- package/dist/util/credential-slot-schema.js +30 -0
- package/dist/util/credential-slot-schema.js.map +1 -0
- package/dist/util/event-channel.d.ts +25 -0
- package/dist/util/event-channel.d.ts.map +1 -0
- package/dist/util/event-channel.js +61 -0
- package/dist/util/event-channel.js.map +1 -0
- package/package.json +1 -1
- package/dist/common/expression-eval.d.ts +0 -35
- package/dist/common/expression-eval.d.ts.map +0 -1
- package/dist/common/expression-eval.js +0 -214
- package/dist/common/expression-eval.js.map +0 -1
- package/dist/common/principal.d.ts +0 -45
- package/dist/common/principal.d.ts.map +0 -1
- package/dist/common/principal.js +0 -9
- package/dist/common/principal.js.map +0 -1
- package/dist/steps/builtin/transform.step.d.ts +0 -247
- package/dist/steps/builtin/transform.step.d.ts.map +0 -1
- package/dist/steps/builtin/transform.step.js +0 -135
- package/dist/steps/builtin/transform.step.js.map +0 -1
- package/dist/types/attachment.d.ts +0 -23
- package/dist/types/attachment.d.ts.map +0 -1
- package/dist/types/attachment.js +0 -2
- package/dist/types/attachment.js.map +0 -1
- package/dist/types/resume-payload.d.ts +0 -34
- package/dist/types/resume-payload.d.ts.map +0 -1
- package/dist/types/resume-payload.js +0 -12
- package/dist/types/resume-payload.js.map +0 -1
- package/dist/util/executable-check.d.ts +0 -42
- package/dist/util/executable-check.d.ts.map +0 -1
- package/dist/util/executable-check.js +0 -115
- package/dist/util/executable-check.js.map +0 -1
|
@@ -11,16 +11,25 @@
|
|
|
11
11
|
* - Resume paused executions
|
|
12
12
|
* - Process queued jobs (the worker loop body)
|
|
13
13
|
*/
|
|
14
|
+
import { executionTopic, workflowTopic } from '../events/types.js';
|
|
14
15
|
import { projectVariables } from '../types/workflow-variable.js';
|
|
15
16
|
import { ConfigValidator } from '../engine/config-validator.js';
|
|
16
17
|
import { validateTriggerPayload } from '../common/validate-payload.js';
|
|
17
18
|
import { AccessDeniedError, ResourceNotFoundError } from '../authz/default.js';
|
|
18
19
|
import { EventTrigger } from '../triggers/event-trigger.js';
|
|
19
20
|
import { WebhookTrigger } from '../triggers/webhook-trigger.js';
|
|
21
|
+
import { ApiTrigger } from '../triggers/api-trigger.js';
|
|
22
|
+
import { CredentialResolver } from '../engine/credential-resolver.js';
|
|
23
|
+
import { headerValue } from '../ingest/headers.js';
|
|
24
|
+
import { parseInboundBody } from '../ingest/body.js';
|
|
25
|
+
import { matchesTriggerFilter } from '../ingest/filter.js';
|
|
20
26
|
import { CronTrigger } from '../triggers/cron-trigger.js';
|
|
21
27
|
import { PauseStep } from '../engine/pause-step.js';
|
|
22
28
|
import { leafStepId } from '../engine/node-path.js';
|
|
23
29
|
// ─── Helpers ───
|
|
30
|
+
function messageOf(err) {
|
|
31
|
+
return err instanceof Error ? err.message : String(err);
|
|
32
|
+
}
|
|
24
33
|
const noopLogger = {
|
|
25
34
|
info: () => { },
|
|
26
35
|
warn: () => { },
|
|
@@ -31,6 +40,13 @@ function generateSecret() {
|
|
|
31
40
|
crypto.getRandomValues(bytes);
|
|
32
41
|
return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');
|
|
33
42
|
}
|
|
43
|
+
/** The trigger's author-supplied input schema, when it has one. */
|
|
44
|
+
function inputSchemaOf(config) {
|
|
45
|
+
const inputSchema = (config.trigger.config ?? {})['inputSchema'];
|
|
46
|
+
return inputSchema && typeof inputSchema === 'object' && !Array.isArray(inputSchema)
|
|
47
|
+
? inputSchema
|
|
48
|
+
: undefined;
|
|
49
|
+
}
|
|
34
50
|
function parseWorkflowConfig(raw) {
|
|
35
51
|
return JSON.parse(raw ?? '{}');
|
|
36
52
|
}
|
|
@@ -68,12 +84,12 @@ export class WorkflowRuntime {
|
|
|
68
84
|
queue;
|
|
69
85
|
scheduler;
|
|
70
86
|
services;
|
|
71
|
-
|
|
72
|
-
triggers;
|
|
87
|
+
connectors;
|
|
73
88
|
executor;
|
|
89
|
+
credentialResolver;
|
|
74
90
|
log;
|
|
75
91
|
baseUrl;
|
|
76
|
-
/**
|
|
92
|
+
/** Pub/sub transport for live execution events. Exposed for the router's SSE stream. */
|
|
77
93
|
eventBus;
|
|
78
94
|
/** Storage adapter for file attachments. Exposed for the router. */
|
|
79
95
|
storage;
|
|
@@ -94,9 +110,9 @@ export class WorkflowRuntime {
|
|
|
94
110
|
this.queue = opts.queue;
|
|
95
111
|
this.scheduler = opts.scheduler;
|
|
96
112
|
this.services = opts.services;
|
|
97
|
-
this.
|
|
98
|
-
this.triggers = opts.triggers;
|
|
113
|
+
this.connectors = opts.connectors;
|
|
99
114
|
this.executor = opts.executor;
|
|
115
|
+
this.credentialResolver = new CredentialResolver(opts.persistence);
|
|
100
116
|
this.log = opts.logger ?? noopLogger;
|
|
101
117
|
this.eventBus = opts.eventBus;
|
|
102
118
|
this.storage = opts.storage;
|
|
@@ -107,6 +123,43 @@ export class WorkflowRuntime {
|
|
|
107
123
|
this.defaultCronTimezone = config.defaultCronTimezone ?? 'Asia/Kolkata';
|
|
108
124
|
this.aiBuilder = config.aiBuilder;
|
|
109
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* Publish to the bus. Fire-and-forget for the same reason the executor's
|
|
128
|
+
* `emitEvent` is: the bus may cross a network, and a mutation must not fail
|
|
129
|
+
* because the thing it was announcing itself to is unreachable. A lost
|
|
130
|
+
* notification costs a stale view until the next read; a failed write costs
|
|
131
|
+
* the user their work.
|
|
132
|
+
*/
|
|
133
|
+
publish(topic, event) {
|
|
134
|
+
const bus = this.eventBus;
|
|
135
|
+
if (!bus)
|
|
136
|
+
return;
|
|
137
|
+
void bus.publish(topic, event).catch((err) => {
|
|
138
|
+
this.log.warn(`event bus publish failed (${event.event} on ${topic}): ${String(err)}`);
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
publishEvent(executionId, event) {
|
|
142
|
+
this.publish(executionTopic(executionId), event);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Announce that a workflow definition changed.
|
|
146
|
+
*
|
|
147
|
+
* Emitted from the runtime rather than the router on purpose: every writer goes
|
|
148
|
+
* through here — the builder, an agent's tool call, a host calling the runtime
|
|
149
|
+
* directly — so no caller can change a workflow without saying so. Put this in
|
|
150
|
+
* the HTTP layer instead and the first non-HTTP writer silently stops notifying.
|
|
151
|
+
*/
|
|
152
|
+
publishWorkflowChange(workflowId, change, origin) {
|
|
153
|
+
this.publish(workflowTopic(workflowId), {
|
|
154
|
+
event: 'workflow_changed',
|
|
155
|
+
data: {
|
|
156
|
+
workflowId,
|
|
157
|
+
change,
|
|
158
|
+
...(origin === undefined ? {} : { origin }),
|
|
159
|
+
at: new Date().toISOString(),
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
}
|
|
110
163
|
// ─── Authorization primitives ───
|
|
111
164
|
//
|
|
112
165
|
// Every caller-facing operation goes through exactly one of these. There is no
|
|
@@ -209,21 +262,27 @@ export class WorkflowRuntime {
|
|
|
209
262
|
* can render inline in the workflow builder.
|
|
210
263
|
*/
|
|
211
264
|
validateConfig(config) {
|
|
212
|
-
const validator = new ConfigValidator(this.
|
|
265
|
+
const validator = new ConfigValidator(this.connectors);
|
|
213
266
|
return validator.validate(config);
|
|
214
267
|
}
|
|
215
268
|
// ─── Workflow Lifecycle ───
|
|
216
269
|
/**
|
|
217
270
|
* Activate a workflow's trigger.
|
|
218
271
|
*
|
|
219
|
-
* -
|
|
272
|
+
* - Every trigger: its credential slots must resolve to accepted credentials
|
|
220
273
|
* - CronTrigger: registers with the scheduler
|
|
221
|
-
*
|
|
274
|
+
*
|
|
275
|
+
* Only then is the workflow marked ACTIVE. Webhook ingest and event dispatch
|
|
276
|
+
* both key off that status, so it is what actually turns a workflow on.
|
|
222
277
|
*/
|
|
223
|
-
async activateWorkflow(ctx, workflowId) {
|
|
278
|
+
async activateWorkflow(ctx, workflowId, opts) {
|
|
224
279
|
// Guard up front, before any external side-effects (webhook/scheduler).
|
|
225
280
|
const { record } = await this.authorizedWorkflow(ctx, workflowId, 'workflow:activate');
|
|
226
|
-
|
|
281
|
+
await this.activateInternal(record);
|
|
282
|
+
await this.persistence.updateWorkflow(workflowId, { status: 'ACTIVE' });
|
|
283
|
+
// After the side-effects, never before: an activation that failed is not a
|
|
284
|
+
// change worth telling anyone about.
|
|
285
|
+
this.publishWorkflowChange(workflowId, 'activated', opts?.origin);
|
|
227
286
|
}
|
|
228
287
|
/**
|
|
229
288
|
* The activation work, already authorized. Used by the guarded
|
|
@@ -233,20 +292,16 @@ export class WorkflowRuntime {
|
|
|
233
292
|
async activateInternal(workflow) {
|
|
234
293
|
const workflowId = workflow.id;
|
|
235
294
|
const config = parseWorkflowConfig(workflow.config);
|
|
236
|
-
if (!this.
|
|
295
|
+
if (!this.connectors.hasTrigger(config.trigger.type)) {
|
|
237
296
|
throw new Error(`Trigger type "${config.trigger.type}" is not registered`);
|
|
238
297
|
}
|
|
239
|
-
const trigger = this.
|
|
298
|
+
const trigger = this.connectors.getTrigger(config.trigger.type);
|
|
299
|
+
// A missing, revoked or wrong-type credential fails here, naming the slot,
|
|
300
|
+
// rather than on the first event.
|
|
301
|
+
if (trigger.credentialSlots?.length) {
|
|
302
|
+
await this.credentialResolver.resolve(workflow.attributes, trigger, config.trigger.config);
|
|
303
|
+
}
|
|
240
304
|
if (trigger instanceof WebhookTrigger) {
|
|
241
|
-
const secret = generateSecret();
|
|
242
|
-
const path = `/webhooks/${workflowId}/${secret}`;
|
|
243
|
-
await this.persistence.storeWebhookPath(workflowId, path, secret);
|
|
244
|
-
if (trigger.onActivate) {
|
|
245
|
-
await trigger.onActivate(config.trigger.config, {
|
|
246
|
-
webhookUrl: this.baseUrl + path,
|
|
247
|
-
credentials: {},
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
305
|
this.log.info(`activated webhook trigger for workflow ${workflowId}`);
|
|
251
306
|
}
|
|
252
307
|
else if (trigger instanceof CronTrigger) {
|
|
@@ -259,30 +314,27 @@ export class WorkflowRuntime {
|
|
|
259
314
|
/**
|
|
260
315
|
* Deactivate a workflow's trigger.
|
|
261
316
|
*/
|
|
262
|
-
async deactivateWorkflow(ctx, workflowId) {
|
|
317
|
+
async deactivateWorkflow(ctx, workflowId, opts) {
|
|
263
318
|
const workflow = await this.persistence.getWorkflow(workflowId);
|
|
264
319
|
if (!workflow) {
|
|
265
320
|
throw new Error(`Workflow ${workflowId} not found`);
|
|
266
321
|
}
|
|
267
322
|
await this.require(ctx, 'workflow:activate', this.workflowRef(workflow));
|
|
268
323
|
const config = parseWorkflowConfig(workflow.config);
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
credentials: {},
|
|
277
|
-
});
|
|
278
|
-
}
|
|
279
|
-
await this.persistence.removeWebhookPath(workflowId);
|
|
280
|
-
this.log.info(`deactivated webhook trigger for workflow ${workflowId}`);
|
|
281
|
-
}
|
|
282
|
-
else if (trigger instanceof CronTrigger) {
|
|
324
|
+
// Falls through rather than returning early on an unregistered trigger type:
|
|
325
|
+
// the call still succeeded, and every successful call must leave by the same
|
|
326
|
+
// door so that none of them can quietly skip the notification below.
|
|
327
|
+
const trigger = this.connectors.hasTrigger(config.trigger.type)
|
|
328
|
+
? this.connectors.getTrigger(config.trigger.type)
|
|
329
|
+
: null;
|
|
330
|
+
if (trigger instanceof CronTrigger) {
|
|
283
331
|
await this.scheduler.unschedule(workflowId);
|
|
284
332
|
this.log.info(`deactivated cron trigger for workflow ${workflowId}`);
|
|
285
333
|
}
|
|
334
|
+
// Webhook, event and manual triggers need no teardown: webhook ingest and
|
|
335
|
+
// event dispatch only reach ACTIVE workflows, so the status below stops them.
|
|
336
|
+
await this.persistence.updateWorkflow(workflowId, { status: 'DISABLED' });
|
|
337
|
+
this.publishWorkflowChange(workflowId, 'deactivated', opts?.origin);
|
|
286
338
|
}
|
|
287
339
|
// ─── Workflow callback secret ───
|
|
288
340
|
/**
|
|
@@ -333,9 +385,9 @@ export class WorkflowRuntime {
|
|
|
333
385
|
const executionIds = [];
|
|
334
386
|
for (const workflow of workflows) {
|
|
335
387
|
const config = parseWorkflowConfig(workflow.config);
|
|
336
|
-
if (!this.
|
|
388
|
+
if (!this.connectors.hasTrigger(config.trigger.type))
|
|
337
389
|
continue;
|
|
338
|
-
const trigger = this.
|
|
390
|
+
const trigger = this.connectors.getTrigger(config.trigger.type);
|
|
339
391
|
if (!(trigger instanceof EventTrigger))
|
|
340
392
|
continue;
|
|
341
393
|
// Hydrate lightweight payload → full context
|
|
@@ -353,6 +405,10 @@ export class WorkflowRuntime {
|
|
|
353
405
|
if (!trigger.matchFilters(config.trigger.config, payload)) {
|
|
354
406
|
continue;
|
|
355
407
|
}
|
|
408
|
+
// And the author's filter, before a run exists.
|
|
409
|
+
if (!matchesTriggerFilter(config.trigger.filter, payload, config.variables)) {
|
|
410
|
+
continue;
|
|
411
|
+
}
|
|
356
412
|
const execId = await this.createAndEnqueue(workflow, {
|
|
357
413
|
type: event.type,
|
|
358
414
|
...payload,
|
|
@@ -362,43 +418,80 @@ export class WorkflowRuntime {
|
|
|
362
418
|
return executionIds;
|
|
363
419
|
}
|
|
364
420
|
/**
|
|
365
|
-
*
|
|
421
|
+
* Ingest a request to a workflow's webhook URL, `<baseUrl>/webhooks/<workflowId>`.
|
|
422
|
+
*
|
|
423
|
+
* The order is fixed, and the trigger's own code runs only after the sender is
|
|
424
|
+
* authenticated:
|
|
425
|
+
*
|
|
426
|
+
* 1. The workflow exists, is ACTIVE and uses a webhook trigger — else 404, the
|
|
427
|
+
* same answer for each so workflow ids cannot be probed.
|
|
428
|
+
* 2. The trigger's credentials resolve — else 401, before any connector code runs.
|
|
429
|
+
* 3. The trigger's own `verify` accepts the request — else 401.
|
|
430
|
+
* 4. The body is parsed from the raw bytes — else 400.
|
|
431
|
+
* 5. The trigger turns the request into events and a reply.
|
|
432
|
+
* 6. Each event must pass the workflow's trigger filter, or it is dropped.
|
|
433
|
+
* 7. Survivors are enqueued before the reply is returned.
|
|
366
434
|
*
|
|
367
|
-
*
|
|
368
|
-
* `handleRequest()`, and enqueues an execution.
|
|
435
|
+
* Reasons for a rejection go to the log; responses stay generic.
|
|
369
436
|
*/
|
|
370
|
-
async handleWebhook(
|
|
371
|
-
const
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
}
|
|
437
|
+
async handleWebhook(workflowId, request) {
|
|
438
|
+
const notFound = {
|
|
439
|
+
reply: { status: 404, body: { error: 'Webhook not found' } },
|
|
440
|
+
executionIds: [],
|
|
441
|
+
};
|
|
442
|
+
const unauthorized = {
|
|
443
|
+
reply: { status: 401, body: { error: 'Unauthorized' } },
|
|
444
|
+
executionIds: [],
|
|
445
|
+
};
|
|
446
|
+
const workflow = await this.persistence.getWorkflow(workflowId);
|
|
447
|
+
if (!workflow || workflow.status !== 'ACTIVE')
|
|
448
|
+
return notFound;
|
|
449
|
+
const config = parseWorkflowConfig(workflow.config);
|
|
450
|
+
const trigger = this.connectors.findTrigger(config.trigger.type)?.trigger;
|
|
451
|
+
if (!(trigger instanceof WebhookTrigger))
|
|
452
|
+
return notFound;
|
|
453
|
+
const attributes = workflow.attributes;
|
|
454
|
+
const triggerConfig = config.trigger.config;
|
|
455
|
+
let ctx;
|
|
456
|
+
try {
|
|
457
|
+
const credentials = await this.credentialResolver.resolve(attributes, trigger, triggerConfig);
|
|
458
|
+
ctx = { credentials, attributes, baseUrl: this.baseUrl };
|
|
377
459
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
httpResponse: { status: 404, body: { error: 'Workflow not active' } },
|
|
383
|
-
};
|
|
460
|
+
catch (err) {
|
|
461
|
+
// Fail closed: verification never runs without the credentials it needs.
|
|
462
|
+
this.log.warn(`webhook ${workflowId}: rejected, ${messageOf(err)}`);
|
|
463
|
+
return unauthorized;
|
|
384
464
|
}
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
return {
|
|
389
|
-
executionId: '',
|
|
390
|
-
httpResponse: {
|
|
391
|
-
status: 400,
|
|
392
|
-
body: { error: 'Workflow does not use a webhook trigger' },
|
|
393
|
-
},
|
|
394
|
-
};
|
|
465
|
+
let verified = false;
|
|
466
|
+
try {
|
|
467
|
+
verified = await trigger.verify(request, triggerConfig, ctx);
|
|
395
468
|
}
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
469
|
+
catch (err) {
|
|
470
|
+
this.log.warn(`webhook ${workflowId}: verification threw: ${messageOf(err)}`);
|
|
471
|
+
}
|
|
472
|
+
if (!verified) {
|
|
473
|
+
this.log.warn(`webhook ${workflowId}: rejected by ${trigger.type} verification`);
|
|
474
|
+
return unauthorized;
|
|
475
|
+
}
|
|
476
|
+
let body;
|
|
477
|
+
try {
|
|
478
|
+
body = parseInboundBody(request.rawBody, headerValue(request.headers, 'content-type'));
|
|
479
|
+
}
|
|
480
|
+
catch (err) {
|
|
481
|
+
this.log.warn(`webhook ${workflowId}: rejected, ${messageOf(err)}`);
|
|
482
|
+
return { reply: { status: 400, body: { error: 'Malformed request body' } }, executionIds: [] };
|
|
483
|
+
}
|
|
484
|
+
const translation = await trigger.handleRequest({ ...request, body }, triggerConfig, ctx);
|
|
485
|
+
const executionIds = [];
|
|
486
|
+
for (const event of translation.events) {
|
|
487
|
+
if (!matchesTriggerFilter(config.trigger.filter, event.payload, config.variables))
|
|
488
|
+
continue;
|
|
489
|
+
executionIds.push(await this.createAndEnqueue(workflow, { type: event.type, ...event.payload }, { publicTrigger: true }));
|
|
490
|
+
}
|
|
491
|
+
return {
|
|
492
|
+
reply: translation.reply ?? { status: 200, body: { ok: true } },
|
|
493
|
+
executionIds,
|
|
494
|
+
};
|
|
402
495
|
}
|
|
403
496
|
/**
|
|
404
497
|
* Handle an incoming wait-callback at `POST /wait/callback/<secret>/<executionId>`.
|
|
@@ -478,91 +571,67 @@ export class WorkflowRuntime {
|
|
|
478
571
|
return this.createAndEnqueue(workflow, triggerPayload);
|
|
479
572
|
}
|
|
480
573
|
/**
|
|
481
|
-
*
|
|
574
|
+
* Start a workflow from the API trigger route.
|
|
575
|
+
*
|
|
576
|
+
* No caller reaches the SDK here: the route has no session, and the SDK does
|
|
577
|
+
* not authorize whoever calls it. A host that exposes the route guards it
|
|
578
|
+
* itself, for example with an API key. The workflow must use an API trigger,
|
|
579
|
+
* and the payload must satisfy its input schema.
|
|
482
580
|
*
|
|
483
|
-
*
|
|
484
|
-
* the route publicly. The workflow itself must opt in by using WEBHOOK_V2,
|
|
485
|
-
* and the execution is marked as public so privileged steps can enforce their
|
|
486
|
-
* own public-trigger restrictions.
|
|
581
|
+
* Runs are marked as public triggers, so privileged steps refuse them.
|
|
487
582
|
*/
|
|
488
|
-
async
|
|
489
|
-
const workflow = await this.
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
const
|
|
494
|
-
if (config.trigger.type !== 'WEBHOOK_V2') {
|
|
495
|
-
throw new Error(`Workflow ${workflowId} does not use a WEBHOOK_V2 trigger`);
|
|
496
|
-
}
|
|
497
|
-
const triggerCfg = (config.trigger.config ?? {});
|
|
498
|
-
const inputSchema = triggerCfg['inputSchema'];
|
|
499
|
-
const webhookV2InputSchema = inputSchema && Array.isArray(inputSchema['required'])
|
|
583
|
+
async triggerViaApi(workflowId, payload) {
|
|
584
|
+
const { workflow, config } = await this.apiTriggerWorkflow(workflowId);
|
|
585
|
+
const inputSchema = inputSchemaOf(config);
|
|
586
|
+
// Uploaded documents are optional on this route even when the schema lists
|
|
587
|
+
// them as required.
|
|
588
|
+
const apiInputSchema = inputSchema && Array.isArray(inputSchema['required'])
|
|
500
589
|
? {
|
|
501
590
|
...inputSchema,
|
|
502
591
|
required: inputSchema['required'].filter((field) => field !== 'documents'),
|
|
503
592
|
}
|
|
504
593
|
: inputSchema;
|
|
505
|
-
const errors = validateTriggerPayload(
|
|
594
|
+
const errors = validateTriggerPayload(apiInputSchema, payload);
|
|
506
595
|
if (errors.length > 0) {
|
|
507
596
|
throw new Error(`Invalid trigger payload: ${errors.map((e) => e.message).join('; ')}`);
|
|
508
597
|
}
|
|
509
|
-
return this.createAndEnqueue(workflow, {
|
|
510
|
-
type: config.trigger.type,
|
|
511
|
-
...payload,
|
|
512
|
-
}, { publicTrigger: true });
|
|
598
|
+
return this.createAndEnqueue(workflow, { type: config.trigger.type, ...payload }, { publicTrigger: true });
|
|
513
599
|
}
|
|
514
600
|
/**
|
|
515
|
-
*
|
|
516
|
-
*
|
|
601
|
+
* What the API trigger route needs before it builds a payload: the trigger's
|
|
602
|
+
* input schema, and the workflow's scope for storing uploaded files. Checked
|
|
603
|
+
* the same way as {@link triggerViaApi}.
|
|
517
604
|
*/
|
|
518
|
-
async
|
|
519
|
-
const workflow = await this.
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
const config = parseWorkflowConfig(workflow.config);
|
|
525
|
-
const triggerCfg = (config.trigger.config ?? {});
|
|
526
|
-
const inputSchema = triggerCfg['inputSchema'];
|
|
527
|
-
return inputSchema && typeof inputSchema === 'object' && !Array.isArray(inputSchema)
|
|
528
|
-
? inputSchema
|
|
529
|
-
: undefined;
|
|
605
|
+
async getApiTriggerTarget(workflowId) {
|
|
606
|
+
const { workflow, config } = await this.apiTriggerWorkflow(workflowId);
|
|
607
|
+
return {
|
|
608
|
+
inputSchema: inputSchemaOf(config),
|
|
609
|
+
storageScope: workflow.attributes,
|
|
610
|
+
};
|
|
530
611
|
}
|
|
531
|
-
/**
|
|
532
|
-
|
|
533
|
-
*
|
|
534
|
-
* Unlike getWorkflowTriggerInputSchema(), this does not authorize a caller;
|
|
535
|
-
* it only verifies the workflow exists and opted into the expected public
|
|
536
|
-
* trigger type.
|
|
537
|
-
*/
|
|
538
|
-
async getWorkflowTriggerInputSchemaPublic(workflowId, expectedTriggerType) {
|
|
612
|
+
/** The workflow exists and uses an API trigger. */
|
|
613
|
+
async apiTriggerWorkflow(workflowId) {
|
|
539
614
|
const workflow = await this.persistence.getWorkflow(workflowId);
|
|
540
|
-
if (!workflow)
|
|
541
|
-
throw new
|
|
542
|
-
}
|
|
615
|
+
if (!workflow)
|
|
616
|
+
throw new ResourceNotFoundError('Workflow', workflowId);
|
|
543
617
|
const config = parseWorkflowConfig(workflow.config);
|
|
544
|
-
|
|
545
|
-
|
|
618
|
+
const trigger = this.connectors.findTrigger(config.trigger.type)?.trigger;
|
|
619
|
+
if (!(trigger instanceof ApiTrigger)) {
|
|
620
|
+
throw new Error(`Workflow ${workflowId} does not use an API trigger`);
|
|
546
621
|
}
|
|
547
|
-
|
|
548
|
-
const inputSchema = triggerCfg['inputSchema'];
|
|
549
|
-
return inputSchema && typeof inputSchema === 'object' && !Array.isArray(inputSchema)
|
|
550
|
-
? inputSchema
|
|
551
|
-
: undefined;
|
|
622
|
+
return { workflow, config };
|
|
552
623
|
}
|
|
553
624
|
/**
|
|
554
|
-
* Return the
|
|
625
|
+
* Return the configured trigger input schema for routes that need to translate
|
|
626
|
+
* transport-level payloads before calling `triggerManual()`.
|
|
555
627
|
*/
|
|
556
|
-
async
|
|
628
|
+
async getWorkflowTriggerInputSchema(ctx, workflowId) {
|
|
557
629
|
const workflow = await this.persistence.getWorkflow(workflowId);
|
|
558
630
|
if (!workflow) {
|
|
559
631
|
throw new Error(`Workflow ${workflowId} not found`);
|
|
560
632
|
}
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
throw new Error(`Workflow ${workflowId} does not use a ${expectedTriggerType} trigger`);
|
|
564
|
-
}
|
|
565
|
-
return workflow.attributes;
|
|
633
|
+
await this.require(ctx, 'workflow:run', this.workflowRef(workflow));
|
|
634
|
+
return inputSchemaOf(parseWorkflowConfig(workflow.config));
|
|
566
635
|
}
|
|
567
636
|
/**
|
|
568
637
|
* Resume a paused execution. Guards `execution:approve`, then does the work.
|
|
@@ -591,7 +660,7 @@ export class WorkflowRuntime {
|
|
|
591
660
|
const isAbort = input?.abort === true || input?.data?.action === 'abort';
|
|
592
661
|
if (isAbort) {
|
|
593
662
|
await this.persistence.updateExecutionStatus(executionId, 'CANCELLED');
|
|
594
|
-
this.
|
|
663
|
+
this.publishEvent(executionId, { event: 'execution_cancelled', data: {} });
|
|
595
664
|
this.log.info(`execution ${executionId} aborted by user`);
|
|
596
665
|
return;
|
|
597
666
|
}
|
|
@@ -696,7 +765,7 @@ export class WorkflowRuntime {
|
|
|
696
765
|
* Validates the config, persists it, and optionally activates the trigger.
|
|
697
766
|
* Returns the created WorkflowRecord.
|
|
698
767
|
*/
|
|
699
|
-
async createWorkflow(ctx, input) {
|
|
768
|
+
async createWorkflow(ctx, input, opts) {
|
|
700
769
|
// Create is an action on the *container*: the folder is the thing that
|
|
701
770
|
// exists, so this same decision is what the UI projects onto its "New
|
|
702
771
|
// workflow" button. Also proves the folder exists — no separate lookup.
|
|
@@ -720,11 +789,17 @@ export class WorkflowRuntime {
|
|
|
720
789
|
// Internal post-create activation — already authorized by the create above.
|
|
721
790
|
await this.activateInternal(record);
|
|
722
791
|
}
|
|
723
|
-
catch {
|
|
724
|
-
// Non-fatal — workflow is created
|
|
792
|
+
catch (err) {
|
|
793
|
+
// Non-fatal — the workflow is created, and its trigger can be activated
|
|
794
|
+
// once whatever failed is fixed.
|
|
795
|
+
this.log.warn(`created workflow ${id} but could not activate its trigger: ${messageOf(err)}`);
|
|
725
796
|
}
|
|
726
797
|
}
|
|
727
798
|
this.log.info(`created workflow ${id} (${input.name})`);
|
|
799
|
+
// One event, not also an `activated` one from the self-activation above: a
|
|
800
|
+
// subscriber re-reads and sees the settled state either way, and two frames
|
|
801
|
+
// for one call would just cost it a second read.
|
|
802
|
+
this.publishWorkflowChange(id, 'created', opts?.origin);
|
|
728
803
|
return record;
|
|
729
804
|
}
|
|
730
805
|
/**
|
|
@@ -733,7 +808,7 @@ export class WorkflowRuntime {
|
|
|
733
808
|
* Accepts partial updates: config, metadata, or both.
|
|
734
809
|
* If config changes, validates it and updates the trigger type.
|
|
735
810
|
*/
|
|
736
|
-
async updateWorkflow(ctx, workflowId, input) {
|
|
811
|
+
async updateWorkflow(ctx, workflowId, input, opts) {
|
|
737
812
|
const { record: existing } = await this.authorizedWorkflow(ctx, workflowId, 'workflow:update');
|
|
738
813
|
const update = {};
|
|
739
814
|
if (input.summary !== undefined)
|
|
@@ -767,6 +842,7 @@ export class WorkflowRuntime {
|
|
|
767
842
|
if (!updated)
|
|
768
843
|
throw new Error('Failed to read updated workflow');
|
|
769
844
|
this.log.info(`updated workflow ${workflowId}`);
|
|
845
|
+
this.publishWorkflowChange(workflowId, 'updated', opts?.origin);
|
|
770
846
|
return updated;
|
|
771
847
|
}
|
|
772
848
|
// ─── Folders ───
|
|
@@ -814,13 +890,13 @@ export class WorkflowRuntime {
|
|
|
814
890
|
return created;
|
|
815
891
|
}
|
|
816
892
|
/** Reorganize folders and workflows in one batch (drag-and-drop). */
|
|
817
|
-
async moveBatch(ctx, input) {
|
|
893
|
+
async moveBatch(ctx, input, opts) {
|
|
818
894
|
// Each item is authorized individually by the op it delegates to, which
|
|
819
895
|
// guards both ends of the move: `*:update` on the thing moved and
|
|
820
896
|
// `*:create` on the destination container.
|
|
821
897
|
await Promise.all([
|
|
822
898
|
...input.folders.map((f) => this.updateFolder(ctx, f.id, { parentId: f.parentId })),
|
|
823
|
-
...input.workflows.map((w) => this.updateWorkflow(ctx, w.id, { folderId: w.folderId })),
|
|
899
|
+
...input.workflows.map((w) => this.updateWorkflow(ctx, w.id, { folderId: w.folderId }, opts)),
|
|
824
900
|
]);
|
|
825
901
|
}
|
|
826
902
|
async updateFolder(ctx, id, input) {
|
|
@@ -1036,7 +1112,7 @@ export class WorkflowRuntime {
|
|
|
1036
1112
|
throw new Error(`Execution ${executionId} is already terminal (status: ${exec.status})`);
|
|
1037
1113
|
}
|
|
1038
1114
|
await this.persistence.updateExecutionStatus(executionId, 'CANCELLED');
|
|
1039
|
-
this.
|
|
1115
|
+
this.publishEvent(executionId, { event: 'execution_cancelled', data: {} });
|
|
1040
1116
|
this.log.info(`execution ${executionId} cancelled`);
|
|
1041
1117
|
}
|
|
1042
1118
|
/** List the credentials visible to `ctx` as safe, paginated summaries. */
|
|
@@ -1157,9 +1233,9 @@ export class WorkflowRuntime {
|
|
|
1157
1233
|
if (!workflow || workflow.status !== 'ACTIVE')
|
|
1158
1234
|
return null;
|
|
1159
1235
|
const config = parseWorkflowConfig(workflow.config);
|
|
1160
|
-
if (!this.
|
|
1236
|
+
if (!this.connectors.hasTrigger(config.trigger.type))
|
|
1161
1237
|
return null;
|
|
1162
|
-
const trigger = this.
|
|
1238
|
+
const trigger = this.connectors.getTrigger(config.trigger.type);
|
|
1163
1239
|
if (!(trigger instanceof CronTrigger))
|
|
1164
1240
|
return null;
|
|
1165
1241
|
const metadata = JSON.parse(workflow.metadata ?? '{}');
|