@aglyn/plugins-workflows 1.0.0-beta.143

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.
Files changed (75) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +52 -0
  3. package/package.json +53 -0
  4. package/src/index.d.ts +18 -0
  5. package/src/index.js +19 -0
  6. package/src/index.js.map +1 -0
  7. package/src/lib/components/automation-step-fields.component.d.ts +74 -0
  8. package/src/lib/components/automation-step-fields.component.js +1210 -0
  9. package/src/lib/components/automation-step-fields.component.js.map +1 -0
  10. package/src/lib/components/host-actions-card.component.d.ts +15 -0
  11. package/src/lib/components/host-actions-card.component.js +1229 -0
  12. package/src/lib/components/host-actions-card.component.js.map +1 -0
  13. package/src/lib/components/host-activity-card.component.d.ts +84 -0
  14. package/src/lib/components/host-activity-card.component.js +280 -0
  15. package/src/lib/components/host-activity-card.component.js.map +1 -0
  16. package/src/lib/components/host-run-history-card.component.d.ts +40 -0
  17. package/src/lib/components/host-run-history-card.component.js +284 -0
  18. package/src/lib/components/host-run-history-card.component.js.map +1 -0
  19. package/src/lib/components/host-webhooks-card.component.d.ts +15 -0
  20. package/src/lib/components/host-webhooks-card.component.js +421 -0
  21. package/src/lib/components/host-webhooks-card.component.js.map +1 -0
  22. package/src/lib/components/host-workflows-card.component.d.ts +18 -0
  23. package/src/lib/components/host-workflows-card.component.js +952 -0
  24. package/src/lib/components/host-workflows-card.component.js.map +1 -0
  25. package/src/lib/components/run-quota-line.component.d.ts +27 -0
  26. package/src/lib/components/run-quota-line.component.js +72 -0
  27. package/src/lib/components/run-quota-line.component.js.map +1 -0
  28. package/src/lib/components/use-automation-step-pickers.d.ts +27 -0
  29. package/src/lib/components/use-automation-step-pickers.js +205 -0
  30. package/src/lib/components/use-automation-step-pickers.js.map +1 -0
  31. package/src/lib/components/workflow-zones.d.ts +36 -0
  32. package/src/lib/components/workflow-zones.js +19 -0
  33. package/src/lib/components/workflow-zones.js.map +1 -0
  34. package/src/lib/components/workflows-console-page.d.ts +25 -0
  35. package/src/lib/components/workflows-console-page.js +112 -0
  36. package/src/lib/components/workflows-console-page.js.map +1 -0
  37. package/src/lib/components/workflows-console-sections.d.ts +34 -0
  38. package/src/lib/components/workflows-console-sections.js +50 -0
  39. package/src/lib/components/workflows-console-sections.js.map +1 -0
  40. package/src/lib/constants/bundle-common.d.ts +8 -0
  41. package/src/lib/constants/bundle-common.js +9 -0
  42. package/src/lib/constants/bundle-common.js.map +1 -0
  43. package/src/lib/declarations.server.d.ts +41 -0
  44. package/src/lib/declarations.server.js +54 -0
  45. package/src/lib/declarations.server.js.map +1 -0
  46. package/src/lib/engine/crm-action-steps.d.ts +129 -0
  47. package/src/lib/engine/crm-action-steps.js +432 -0
  48. package/src/lib/engine/crm-action-steps.js.map +1 -0
  49. package/src/lib/engine/flow-enrollments.d.ts +264 -0
  50. package/src/lib/engine/flow-enrollments.js +386 -0
  51. package/src/lib/engine/flow-enrollments.js.map +1 -0
  52. package/src/lib/engine/run-event-actions.d.ts +232 -0
  53. package/src/lib/engine/run-event-actions.js +1392 -0
  54. package/src/lib/engine/run-event-actions.js.map +1 -0
  55. package/src/lib/engine/run-event-automations.d.ts +28 -0
  56. package/src/lib/engine/run-event-automations.js +37 -0
  57. package/src/lib/engine/run-event-automations.js.map +1 -0
  58. package/src/lib/engine/run-event-workflows.d.ts +75 -0
  59. package/src/lib/engine/run-event-workflows.js +311 -0
  60. package/src/lib/engine/run-event-workflows.js.map +1 -0
  61. package/src/lib/engine/workflow-steps.d.ts +107 -0
  62. package/src/lib/engine/workflow-steps.js +124 -0
  63. package/src/lib/engine/workflow-steps.js.map +1 -0
  64. package/src/lib/plugin.d.ts +33 -0
  65. package/src/lib/plugin.js +94 -0
  66. package/src/lib/plugin.js.map +1 -0
  67. package/src/lib/server-automation-drafts.d.ts +90 -0
  68. package/src/lib/server-automation-drafts.js +429 -0
  69. package/src/lib/server-automation-drafts.js.map +1 -0
  70. package/src/lib/server-console.d.ts +27 -0
  71. package/src/lib/server-console.js +35 -0
  72. package/src/lib/server-console.js.map +1 -0
  73. package/src/lib/server.d.ts +29 -0
  74. package/src/lib/server.js +298 -0
  75. package/src/lib/server.js.map +1 -0
@@ -0,0 +1,311 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
2
+ /**
3
+ * @license
4
+ * Copyright 2026 Aglyn LLC
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */ import { ACTION_MAX_EVENT_DEPTH, checkEntitlement, evaluateExpression, FLOW_TIMED_OUT_FIELD, resolveOrgEntitlements, runWorkflow } from "@aglyn/aglyn/server";
18
+ import { firebaseAdmin, getOrgForHost } from "@aglyn/tenant-data-admin";
19
+ import { FieldValue } from "firebase-admin/firestore";
20
+ import { deferFlowEnrollment, endFlowEnrollment } from "./flow-enrollments.js";
21
+ import { automationRunEnv, executeWorkflow, FLOW_CLAIM_RETRY_MS, stopFlowEnrollment } from "./run-event-actions.js";
22
+ import { workflowHasActionSteps } from "./workflow-steps.js";
23
+ /** Bounded fan-out per event: at most this many triggered workflows run. */ const MAX_TRIGGERED_WORKFLOWS = 10;
24
+ /**
25
+ * One workflow run's row in the site's activity feed, which is the run
26
+ * history the Workflows tab reads.
27
+ *
28
+ * The one place a workflow's run is written, whichever door started it.
29
+ */ async function recordWorkflowRun(hostRef, row) {
30
+ await hostRef.collection('activity').add(_extends({
31
+ actorId: null,
32
+ actorEmail: null
33
+ }, row, {
34
+ createdAt: FieldValue.serverTimestamp()
35
+ })).catch(()=>undefined);
36
+ }
37
+ /**
38
+ * The history row for a run of a workflow with Actions steps, in the Actions
39
+ * run's phrasing (AGL-2171) — what each step did, joined — so the run table
40
+ * shows every step's outcome whichever engine the step came from. `status`
41
+ * and `durationMs` ride along as they do on every workflow run, for the
42
+ * dashboard feed that renders them.
43
+ */ export function workflowRunRow(execution, input) {
44
+ const failed = execution.errors.length > 0;
45
+ const action = failed ? `Workflow ran on ${input.event} with errors: ${execution.errors.join('; ')}`.slice(0, 300) : execution.ending === 'waiting' ? `Workflow is waiting, on ${input.event}` : `Workflow ran on ${input.event}`;
46
+ return {
47
+ action,
48
+ result: failed ? 'failed' : 'succeeded',
49
+ trigger: input.event,
50
+ summary: (execution.outcomes.length ? execution.outcomes.join(' · ') : 'Ran').slice(0, 300),
51
+ status: failed ? 'error' : 'ok',
52
+ durationMs: input.durationMs,
53
+ target: {
54
+ type: 'workflow',
55
+ id: input.workflowId,
56
+ name: input.workflowName
57
+ }
58
+ };
59
+ }
60
+ /**
61
+ * Event-triggered workflow runner (AGL-128): loads workflows whose
62
+ * `trigger.event` matches, evaluates optional trigger filters over the
63
+ * event payload, runs each, and logs runs to the host activity feed.
64
+ * Fire-and-forget from the tenant's event sites (form submit, pageview
65
+ * collector, membership APIs) — it never throws, and a failure must not
66
+ * break the request that emitted the event.
67
+ *
68
+ * A workflow of function calls runs through the pure `runWorkflow`
69
+ * evaluator exactly as it always has. A workflow with Actions steps runs
70
+ * through `executeWorkflow`, which performs them with the Actions executors;
71
+ * the site alerts its steps raise are what this resolves.
72
+ *
73
+ * ONE RUN, METERED ONCE: either kind counts one run on the workflow meter,
74
+ * `workflowRunsPerMonth`, however many steps it has and whatever they are.
75
+ * Its Actions steps take the Actions tier gates step by step, and none of
76
+ * them counts an action run.
77
+ *
78
+ * `depth` is the chain guard actions run under (`ACTION_MAX_EVENT_DEPTH`):
79
+ * an event a workflow's own step raised — a stage it set — is heard one
80
+ * level deeper, so a workflow that sets the stage it listens for stops.
81
+ */ export async function runEventWorkflows(hostId, event, payload = {}, depth = 0) {
82
+ const alerts = [];
83
+ if (depth > ACTION_MAX_EVENT_DEPTH) return alerts;
84
+ try {
85
+ const firestore = firebaseAdmin.app().firestore();
86
+ const hostRef = firestore.collection('hosts').doc(hostId);
87
+ const triggered = await hostRef.collection('workflows').where('trigger.event', '==', event).limit(MAX_TRIGGERED_WORKFLOWS).get();
88
+ const workflows = triggered.docs.filter((doc)=>!doc.get('deletedAt'));
89
+ if (!workflows.length) return alerts;
90
+ // Full workflow map for nested function→workflow calls (AGL-129).
91
+ const allWorkflowDocs = await hostRef.collection('workflows').limit(100).get();
92
+ // Double-keyed by doc id AND name (AGL-261): id references are
93
+ // rename-safe; legacy name references keep resolving.
94
+ // Each carries its id, so a workflow a step names by its legacy name
95
+ // still runs as the automation it is (see `WorkflowContext`).
96
+ const workflowMap = {};
97
+ for (const doc of allWorkflowDocs.docs){
98
+ const data = doc.data();
99
+ if (data.deletedAt) continue;
100
+ const withId = _extends({}, data, {
101
+ $id: doc.id
102
+ });
103
+ workflowMap[doc.id] = withId;
104
+ if (data == null ? void 0 : data.name) workflowMap[data.name] = withId;
105
+ }
106
+ // Monthly run cap by the owning org's plan (AGL-165) — dark-launch
107
+ // rule: workspaces without a plan are uncapped, like every other gate.
108
+ const monthKey = new Date().toISOString().slice(0, 7);
109
+ const runCounterRef = hostRef.collection('counters').doc('workflowRuns');
110
+ // Run caps ride the owning org's doc (AGL-238) — read through
111
+ // `getOrgForHost` below. The host document itself is not consulted: the
112
+ // cap, the counter and the workflow definitions all live elsewhere, so a
113
+ // read of it here would be billed on every host event and used for
114
+ // nothing.
115
+ const owner = await getOrgForHost(hostId);
116
+ {
117
+ var _counterSnapshot_get;
118
+ const org = owner == null ? void 0 : owner.org;
119
+ // Plan-less orgs resolve as free (AGL-247) — the cap always runs.
120
+ const limit = resolveOrgEntitlements(org).workflowRunsPerMonth;
121
+ const counterSnapshot = await runCounterRef.get();
122
+ const used = Number((_counterSnapshot_get = counterSnapshot.get(monthKey)) != null ? _counterSnapshot_get : 0);
123
+ if (used + workflows.length > limit) return alerts;
124
+ }
125
+ const [functionDocs, variableDocs] = await Promise.all([
126
+ hostRef.collection('functions').limit(100).get(),
127
+ hostRef.collection('variables').limit(100).get()
128
+ ]);
129
+ const functions = {};
130
+ for (const doc of functionDocs.docs){
131
+ const definition = doc.data();
132
+ if (definition.deletedAt) continue;
133
+ functions[doc.id] = definition;
134
+ if (definition.name) functions[definition.name] = definition;
135
+ }
136
+ const variables = {};
137
+ for (const doc of variableDocs.docs){
138
+ const variable = doc.data();
139
+ if (!variable.deletedAt && variable.name) {
140
+ variables[variable.name] = variable;
141
+ }
142
+ }
143
+ let executed = 0;
144
+ for (const doc of workflows){
145
+ var _workflow_name;
146
+ var _workflow_trigger_filter, _workflow_trigger;
147
+ const workflow = doc.data();
148
+ const filter = (_workflow_trigger = workflow.trigger) == null ? void 0 : (_workflow_trigger_filter = _workflow_trigger.filter) == null ? void 0 : _workflow_trigger_filter.trim();
149
+ if (filter) {
150
+ try {
151
+ const scope = _extends({
152
+ event
153
+ }, payload);
154
+ if (!evaluateExpression(filter, scope)) continue;
155
+ } catch (unused) {
156
+ continue; // A broken filter never fires.
157
+ }
158
+ }
159
+ const startedAt = Date.now();
160
+ if (workflowHasActionSteps(workflow)) {
161
+ var _workflow_name1, _workflow_name2;
162
+ /*
163
+ * A WORKFLOW WITH ACTIONS STEPS is performed, not evaluated. The
164
+ * maps above are this run's working set, so the executor reads them
165
+ * rather than a second copy; the plan gates come off the org
166
+ * document the cap already read.
167
+ */ const context = {
168
+ functions,
169
+ variables,
170
+ workflows: workflowMap
171
+ };
172
+ const env = automationRunEnv({
173
+ hostId,
174
+ hostRef,
175
+ owner,
176
+ depth,
177
+ alerts,
178
+ loadWorkflowContext: async ()=>context
179
+ });
180
+ const execution = await executeWorkflow(env, {
181
+ kind: 'workflow',
182
+ id: doc.id,
183
+ name: (_workflow_name1 = workflow.name) != null ? _workflow_name1 : ''
184
+ }, workflow, event, payload);
185
+ executed += 1;
186
+ await recordWorkflowRun(hostRef, workflowRunRow(execution, {
187
+ event,
188
+ workflowId: doc.id,
189
+ workflowName: (_workflow_name2 = workflow.name) != null ? _workflow_name2 : '',
190
+ durationMs: Date.now() - startedAt
191
+ }));
192
+ continue;
193
+ }
194
+ const run = runWorkflow(workflow, functions, variables, _extends({
195
+ event
196
+ }, payload), {
197
+ workflows: workflowMap
198
+ });
199
+ const durationMs = Date.now() - startedAt;
200
+ executed += 1;
201
+ // `=== false` (not `!run.ok`): the union fails to narrow under the
202
+ // stricter build tsconfig otherwise (same quirk as runWorkflow).
203
+ const action = run.ok === false ? `Workflow failed on ${event}: ${run.error}`.slice(0, 300) : `Workflow ran on ${event}`;
204
+ /*
205
+ * The run-history shape, not just `status` + `durationMs` (AGL-2222).
206
+ *
207
+ * `actionRunResult()` recognises a run by `result`, falling back to the
208
+ * prose prefix `Action ran on`. This writer's prose begins
209
+ * `Workflow ran on`, so every workflow execution was filtered out of the
210
+ * very table AGL-2171 built — the Runs dialog on the Workflows tab read
211
+ * "No runs yet" however many times a workflow had run. The `durationMs`
212
+ * caption in that table could never render either, because the only rows
213
+ * carrying a duration were the ones being dropped.
214
+ *
215
+ * `status` stays: the dashboard activity feed renders it, and removing
216
+ * it would trade one silent gap for another.
217
+ */ await recordWorkflowRun(hostRef, {
218
+ action,
219
+ result: run.ok === false ? 'failed' : 'succeeded',
220
+ trigger: event,
221
+ summary: run.ok === false ? String(run.error).slice(0, 300) : 'Ran',
222
+ status: run.ok === false ? 'error' : 'ok',
223
+ durationMs,
224
+ target: {
225
+ type: 'workflow',
226
+ id: doc.id,
227
+ name: (_workflow_name = workflow.name) != null ? _workflow_name : ''
228
+ }
229
+ });
230
+ }
231
+ // Filtered-out workflows do not bill — only executed runs count.
232
+ if (executed > 0) {
233
+ await runCounterRef.set({
234
+ [monthKey]: FieldValue.increment(executed)
235
+ }, {
236
+ merge: true
237
+ }).catch(()=>undefined);
238
+ }
239
+ } catch (error) {
240
+ console.error('runEventWorkflows failed', hostId, event, error);
241
+ }
242
+ return alerts;
243
+ }
244
+ /**
245
+ * Continues a WORKFLOW's enrollment from where its wait ended — the
246
+ * workflow twin of the action resume, and asked the same questions.
247
+ *
248
+ * - The kill switch is the workflow document: deleted, and the people inside
249
+ * it stop, exactly as they do when an action is deleted or switched off.
250
+ * - The plan is re-asked: a wait is an Actions step, so a workspace whose
251
+ * plan has lost the actions builder stops the flow rather than finishing
252
+ * it on a plan that no longer carries it.
253
+ * - The snapshot runs, not the workflow's current steps, and the results the
254
+ * function calls bound before the wait ride in its payload.
255
+ * - Counted on the workflow meter, never refused by it: the person is already
256
+ * inside, and the gate belongs at enrollment.
257
+ */ export async function resumeWorkflowEnrollment(enrollment, ref, options) {
258
+ var _enrollment_payload, _workflow_name, _workflow_name1;
259
+ const { nowMs } = options;
260
+ const hostId = enrollment.hostId;
261
+ const hostRef = firebaseAdmin.app().firestore().collection('hosts').doc(hostId);
262
+ const doc = await hostRef.collection('workflows').doc(enrollment.actionId).get().catch(()=>null);
263
+ if (!(doc == null ? void 0 : doc.exists) || doc.get('deletedAt')) {
264
+ return await stopFlowEnrollment(enrollment, ref, 'the workflow was deleted');
265
+ }
266
+ const workflow = doc.data();
267
+ const owner = await getOrgForHost(hostId).catch(()=>null);
268
+ if (!checkEntitlement(owner == null ? void 0 : owner.org, 'actions')) {
269
+ return await stopFlowEnrollment(enrollment, ref, 'this site’s plan no longer includes automations');
270
+ }
271
+ const env = automationRunEnv({
272
+ hostId,
273
+ hostRef,
274
+ owner,
275
+ depth: 0
276
+ });
277
+ const payload = _extends({}, (_enrollment_payload = enrollment.payload) != null ? _enrollment_payload : {}, options.timedOut ? {
278
+ [FLOW_TIMED_OUT_FIELD]: true
279
+ } : {});
280
+ const startedAt = Date.now();
281
+ const execution = await executeWorkflow(env, {
282
+ kind: 'workflow',
283
+ id: doc.id,
284
+ name: (_workflow_name = workflow.name) != null ? _workflow_name : ''
285
+ }, workflow, enrollment.event, payload, {
286
+ startIndex: enrollment.nextStepIndex,
287
+ steps: enrollment.steps,
288
+ enrollmentRef: ref
289
+ });
290
+ if (execution.ending === 'deferred') {
291
+ await deferFlowEnrollment(ref, nowMs + FLOW_CLAIM_RETRY_MS, nowMs);
292
+ return execution.ending;
293
+ }
294
+ if (execution.ending !== 'waiting') await endFlowEnrollment(ref);
295
+ await recordWorkflowRun(hostRef, workflowRunRow(execution, {
296
+ event: enrollment.event,
297
+ workflowId: doc.id,
298
+ workflowName: (_workflow_name1 = workflow.name) != null ? _workflow_name1 : '',
299
+ durationMs: Date.now() - startedAt
300
+ }));
301
+ const monthKey = new Date(nowMs).toISOString().slice(0, 7);
302
+ await hostRef.collection('counters').doc('workflowRuns').set({
303
+ [monthKey]: FieldValue.increment(1)
304
+ }, {
305
+ merge: true
306
+ }).catch(()=>undefined);
307
+ return execution.ending;
308
+ }
309
+ export default runEventWorkflows;
310
+
311
+ //# sourceMappingURL=run-event-workflows.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/engine/run-event-workflows.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ACTION_MAX_EVENT_DEPTH,\n checkEntitlement,\n evaluateExpression,\n FLOW_TIMED_OUT_FIELD,\n type HostActionAlert,\n type HostEventType,\n type HostFunction,\n type HostVariable,\n type HostWorkflow,\n resolveOrgEntitlements,\n runWorkflow,\n} from '@aglyn/aglyn/server'\nimport { firebaseAdmin, getOrgForHost } from '@aglyn/tenant-data-admin'\nimport type { HostEventPayload } from '@aglyn/tenant-runtime/host-event-listeners'\nimport { FieldValue } from 'firebase-admin/firestore'\nimport {\n deferFlowEnrollment,\n endFlowEnrollment,\n type FlowEnrollment,\n} from './flow-enrollments'\nimport {\n automationRunEnv,\n executeWorkflow,\n FLOW_CLAIM_RETRY_MS,\n stopFlowEnrollment,\n type WorkflowContext,\n type WorkflowExecution,\n} from './run-event-actions'\nimport {\n type AutomationWorkflow,\n workflowHasActionSteps,\n} from './workflow-steps'\n\n/** Bounded fan-out per event: at most this many triggered workflows run. */\nconst MAX_TRIGGERED_WORKFLOWS = 10\n\n/**\n * One workflow run's row in the site's activity feed, which is the run\n * history the Workflows tab reads.\n *\n * The one place a workflow's run is written, whichever door started it.\n */\nasync function recordWorkflowRun(\n hostRef: FirebaseFirestore.DocumentReference,\n row: Record<string, unknown>,\n): Promise<void> {\n await hostRef\n .collection('activity')\n .add({\n actorId: null,\n actorEmail: null,\n ...row,\n createdAt: FieldValue.serverTimestamp(),\n })\n .catch(() => undefined)\n}\n\n/**\n * The history row for a run of a workflow with Actions steps, in the Actions\n * run's phrasing (AGL-2171) — what each step did, joined — so the run table\n * shows every step's outcome whichever engine the step came from. `status`\n * and `durationMs` ride along as they do on every workflow run, for the\n * dashboard feed that renders them.\n */\nexport function workflowRunRow(\n execution: Pick<WorkflowExecution, 'ending' | 'errors' | 'outcomes'>,\n input: {\n event: string\n workflowId: string\n workflowName: string\n durationMs: number\n },\n): Record<string, unknown> {\n const failed = execution.errors.length > 0\n const action = failed\n ? `Workflow ran on ${input.event} with errors: ${execution.errors.join('; ')}`.slice(\n 0,\n 300,\n )\n : execution.ending === 'waiting'\n ? `Workflow is waiting, on ${input.event}`\n : `Workflow ran on ${input.event}`\n return {\n action,\n result: failed ? 'failed' : 'succeeded',\n trigger: input.event,\n summary: (execution.outcomes.length\n ? execution.outcomes.join(' · ')\n : 'Ran'\n ).slice(0, 300),\n status: failed ? 'error' : 'ok',\n durationMs: input.durationMs,\n target: {\n type: 'workflow',\n id: input.workflowId,\n name: input.workflowName,\n },\n }\n}\n\n/**\n * Event-triggered workflow runner (AGL-128): loads workflows whose\n * `trigger.event` matches, evaluates optional trigger filters over the\n * event payload, runs each, and logs runs to the host activity feed.\n * Fire-and-forget from the tenant's event sites (form submit, pageview\n * collector, membership APIs) — it never throws, and a failure must not\n * break the request that emitted the event.\n *\n * A workflow of function calls runs through the pure `runWorkflow`\n * evaluator exactly as it always has. A workflow with Actions steps runs\n * through `executeWorkflow`, which performs them with the Actions executors;\n * the site alerts its steps raise are what this resolves.\n *\n * ONE RUN, METERED ONCE: either kind counts one run on the workflow meter,\n * `workflowRunsPerMonth`, however many steps it has and whatever they are.\n * Its Actions steps take the Actions tier gates step by step, and none of\n * them counts an action run.\n *\n * `depth` is the chain guard actions run under (`ACTION_MAX_EVENT_DEPTH`):\n * an event a workflow's own step raised — a stage it set — is heard one\n * level deeper, so a workflow that sets the stage it listens for stops.\n */\nexport async function runEventWorkflows(\n hostId: string,\n event: HostEventType,\n payload: HostEventPayload = {},\n depth = 0,\n): Promise<HostActionAlert[]> {\n const alerts: HostActionAlert[] = []\n if (depth > ACTION_MAX_EVENT_DEPTH) return alerts\n try {\n const firestore = firebaseAdmin.app().firestore()\n const hostRef = firestore.collection('hosts').doc(hostId)\n const triggered = await hostRef\n .collection('workflows')\n .where('trigger.event', '==', event)\n .limit(MAX_TRIGGERED_WORKFLOWS)\n .get()\n const workflows = triggered.docs.filter((doc) => !doc.get('deletedAt'))\n if (!workflows.length) return alerts\n // Full workflow map for nested function→workflow calls (AGL-129).\n const allWorkflowDocs = await hostRef\n .collection('workflows')\n .limit(100)\n .get()\n // Double-keyed by doc id AND name (AGL-261): id references are\n // rename-safe; legacy name references keep resolving.\n // Each carries its id, so a workflow a step names by its legacy name\n // still runs as the automation it is (see `WorkflowContext`).\n const workflowMap: WorkflowContext['workflows'] = {}\n for (const doc of allWorkflowDocs.docs) {\n const data = doc.data() as any\n if (data.deletedAt) continue\n const withId = { ...data, $id: doc.id }\n workflowMap[doc.id] = withId\n if (data?.name) workflowMap[data.name] = withId\n }\n\n // Monthly run cap by the owning org's plan (AGL-165) — dark-launch\n // rule: workspaces without a plan are uncapped, like every other gate.\n const monthKey = new Date().toISOString().slice(0, 7)\n const runCounterRef = hostRef.collection('counters').doc('workflowRuns')\n // Run caps ride the owning org's doc (AGL-238) — read through\n // `getOrgForHost` below. The host document itself is not consulted: the\n // cap, the counter and the workflow definitions all live elsewhere, so a\n // read of it here would be billed on every host event and used for\n // nothing.\n const owner = await getOrgForHost(hostId)\n {\n const org = owner?.org\n // Plan-less orgs resolve as free (AGL-247) — the cap always runs.\n const limit = resolveOrgEntitlements(\n org as any,\n ).workflowRunsPerMonth\n const counterSnapshot = await runCounterRef.get()\n const used = Number(counterSnapshot.get(monthKey) ?? 0)\n if (used + workflows.length > limit) return alerts\n }\n\n const [functionDocs, variableDocs] = await Promise.all([\n hostRef.collection('functions').limit(100).get(),\n hostRef.collection('variables').limit(100).get(),\n ])\n const functions: Record<string, HostFunction> = {}\n for (const doc of functionDocs.docs) {\n const definition = doc.data() as any\n if (definition.deletedAt) continue\n functions[doc.id] = definition\n if (definition.name) functions[definition.name] = definition\n }\n const variables: Record<string, HostVariable> = {}\n for (const doc of variableDocs.docs) {\n const variable = doc.data() as any\n if (!variable.deletedAt && variable.name) {\n variables[variable.name] = variable\n }\n }\n\n let executed = 0\n for (const doc of workflows) {\n const workflow = doc.data() as AutomationWorkflow\n const filter = workflow.trigger?.filter?.trim()\n if (filter) {\n try {\n const scope: HostEventPayload = { event, ...payload }\n if (!evaluateExpression(filter, scope)) continue\n } catch {\n continue // A broken filter never fires.\n }\n }\n const startedAt = Date.now()\n if (workflowHasActionSteps(workflow)) {\n /*\n * A WORKFLOW WITH ACTIONS STEPS is performed, not evaluated. The\n * maps above are this run's working set, so the executor reads them\n * rather than a second copy; the plan gates come off the org\n * document the cap already read.\n */\n const context: WorkflowContext = {\n functions,\n variables,\n workflows: workflowMap,\n }\n const env = automationRunEnv({\n hostId,\n hostRef,\n owner,\n depth,\n alerts,\n loadWorkflowContext: async () => context,\n })\n const execution = await executeWorkflow(\n env,\n { kind: 'workflow', id: doc.id, name: workflow.name ?? '' },\n workflow,\n event,\n payload,\n )\n executed += 1\n await recordWorkflowRun(\n hostRef,\n workflowRunRow(execution, {\n event,\n workflowId: doc.id,\n workflowName: workflow.name ?? '',\n durationMs: Date.now() - startedAt,\n }),\n )\n continue\n }\n const run = runWorkflow(\n workflow as HostWorkflow,\n functions,\n variables,\n { event, ...payload },\n { workflows: workflowMap },\n )\n const durationMs = Date.now() - startedAt\n executed += 1\n // `=== false` (not `!run.ok`): the union fails to narrow under the\n // stricter build tsconfig otherwise (same quirk as runWorkflow).\n const action =\n run.ok === false\n ? `Workflow failed on ${event}: ${run.error}`.slice(0, 300)\n : `Workflow ran on ${event}`\n /*\n * The run-history shape, not just `status` + `durationMs` (AGL-2222).\n *\n * `actionRunResult()` recognises a run by `result`, falling back to the\n * prose prefix `Action ran on`. This writer's prose begins\n * `Workflow ran on`, so every workflow execution was filtered out of the\n * very table AGL-2171 built — the Runs dialog on the Workflows tab read\n * \"No runs yet\" however many times a workflow had run. The `durationMs`\n * caption in that table could never render either, because the only rows\n * carrying a duration were the ones being dropped.\n *\n * `status` stays: the dashboard activity feed renders it, and removing\n * it would trade one silent gap for another.\n */\n await recordWorkflowRun(hostRef, {\n action,\n result: run.ok === false ? 'failed' : 'succeeded',\n trigger: event,\n summary: run.ok === false ? String(run.error).slice(0, 300) : 'Ran',\n status: run.ok === false ? 'error' : 'ok',\n durationMs,\n target: { type: 'workflow', id: doc.id, name: workflow.name ?? '' },\n })\n }\n // Filtered-out workflows do not bill — only executed runs count.\n if (executed > 0) {\n await runCounterRef\n .set(\n { [monthKey]: FieldValue.increment(executed) },\n { merge: true },\n )\n .catch(() => undefined)\n }\n } catch (error) {\n console.error('runEventWorkflows failed', hostId, event, error)\n }\n return alerts\n}\n\n/**\n * Continues a WORKFLOW's enrollment from where its wait ended — the\n * workflow twin of the action resume, and asked the same questions.\n *\n * - The kill switch is the workflow document: deleted, and the people inside\n * it stop, exactly as they do when an action is deleted or switched off.\n * - The plan is re-asked: a wait is an Actions step, so a workspace whose\n * plan has lost the actions builder stops the flow rather than finishing\n * it on a plan that no longer carries it.\n * - The snapshot runs, not the workflow's current steps, and the results the\n * function calls bound before the wait ride in its payload.\n * - Counted on the workflow meter, never refused by it: the person is already\n * inside, and the gate belongs at enrollment.\n */\nexport async function resumeWorkflowEnrollment(\n enrollment: FlowEnrollment,\n ref: FirebaseFirestore.DocumentReference,\n options: { timedOut?: boolean; nowMs: number },\n): Promise<'ran' | 'waiting' | 'exited' | 'deferred' | 'stopped'> {\n const { nowMs } = options\n const hostId = enrollment.hostId\n const hostRef = firebaseAdmin.app().firestore().collection('hosts').doc(hostId)\n const doc = await hostRef\n .collection('workflows')\n .doc(enrollment.actionId)\n .get()\n .catch(() => null)\n if (!doc?.exists || doc.get('deletedAt')) {\n return await stopFlowEnrollment(\n enrollment,\n ref,\n 'the workflow was deleted',\n )\n }\n const workflow = doc.data() as AutomationWorkflow\n const owner = await getOrgForHost(hostId).catch(() => null)\n if (!checkEntitlement(owner?.org as any, 'actions')) {\n return await stopFlowEnrollment(\n enrollment,\n ref,\n 'this site’s plan no longer includes automations',\n )\n }\n const env = automationRunEnv({ hostId, hostRef, owner, depth: 0 })\n const payload: HostEventPayload = {\n ...((enrollment.payload ?? {}) as HostEventPayload),\n // The timeout BRANCH, as on an action's resume: the step after a\n // `waitForEvent` reads it to tell the clock from the event.\n ...(options.timedOut ? { [FLOW_TIMED_OUT_FIELD]: true } : {}),\n }\n const startedAt = Date.now()\n const execution = await executeWorkflow(\n env,\n { kind: 'workflow', id: doc.id, name: workflow.name ?? '' },\n workflow,\n enrollment.event,\n payload,\n {\n startIndex: enrollment.nextStepIndex,\n steps: enrollment.steps,\n enrollmentRef: ref,\n },\n )\n if (execution.ending === 'deferred') {\n await deferFlowEnrollment(ref, nowMs + FLOW_CLAIM_RETRY_MS, nowMs)\n return execution.ending\n }\n if (execution.ending !== 'waiting') await endFlowEnrollment(ref)\n await recordWorkflowRun(\n hostRef,\n workflowRunRow(execution, {\n event: enrollment.event,\n workflowId: doc.id,\n workflowName: workflow.name ?? '',\n durationMs: Date.now() - startedAt,\n }),\n )\n const monthKey = new Date(nowMs).toISOString().slice(0, 7)\n await hostRef\n .collection('counters')\n .doc('workflowRuns')\n .set({ [monthKey]: FieldValue.increment(1) }, { merge: true })\n .catch(() => undefined)\n return execution.ending\n}\n\nexport default runEventWorkflows\n"],"names":["ACTION_MAX_EVENT_DEPTH","checkEntitlement","evaluateExpression","FLOW_TIMED_OUT_FIELD","resolveOrgEntitlements","runWorkflow","firebaseAdmin","getOrgForHost","FieldValue","deferFlowEnrollment","endFlowEnrollment","automationRunEnv","executeWorkflow","FLOW_CLAIM_RETRY_MS","stopFlowEnrollment","workflowHasActionSteps","MAX_TRIGGERED_WORKFLOWS","recordWorkflowRun","hostRef","row","collection","add","actorId","actorEmail","createdAt","serverTimestamp","catch","undefined","workflowRunRow","execution","input","failed","errors","length","action","event","join","slice","ending","result","trigger","summary","outcomes","status","durationMs","target","type","id","workflowId","name","workflowName","runEventWorkflows","hostId","payload","depth","alerts","firestore","app","doc","triggered","where","limit","get","workflows","docs","filter","allWorkflowDocs","workflowMap","data","deletedAt","withId","$id","monthKey","Date","toISOString","runCounterRef","owner","counterSnapshot","org","workflowRunsPerMonth","used","Number","functionDocs","variableDocs","Promise","all","functions","definition","variables","variable","executed","workflow","trim","scope","startedAt","now","context","env","loadWorkflowContext","kind","run","ok","error","String","set","increment","merge","console","resumeWorkflowEnrollment","enrollment","ref","options","nowMs","actionId","exists","timedOut","startIndex","nextStepIndex","steps","enrollmentRef"],"mappings":"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"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import { type HostActionStep, type HostActionStepType } from '@aglyn/aglyn/app-utils/actions';
18
+ import { type HostWorkflow, type HostWorkflowStep } from '@aglyn/aglyn/app-utils/workflows';
19
+ /**
20
+ * ONE STEP MODEL FOR BOTH ENGINES.
21
+ *
22
+ * A workflow step is one of two things:
23
+ *
24
+ * - a FUNCTION CALL — `{ functionId, functionName, args, resultName }`, the
25
+ * shape every workflow has stored since the builder shipped, and still the
26
+ * default. It evaluates its argument expressions and binds the result for
27
+ * the steps after it;
28
+ * - an ACTIONS STEP — `{ type, …fields, when? }`, exactly as the Actions
29
+ * editor stores it: write a dataset record, send an email, update a CRM
30
+ * contact, post a webhook, wait. It runs through the Actions executors,
31
+ * with their validation, their tier gates and their run-history phrases.
32
+ *
33
+ * The two are told apart by `type`. An Actions step always carries one of the
34
+ * Actions step types and a function call never has one, so a stored workflow
35
+ * is read as it was written and nothing is migrated. A step whose `type` the
36
+ * Actions vocabulary does not know is read as a function call, which is how
37
+ * every workflow read it before — it fails as a call to no function.
38
+ *
39
+ * Pure and client-safe: the console's editor and the server's engine read the
40
+ * same definitions from here.
41
+ */
42
+ /** A workflow step that runs one of the Actions steps, stored in the Actions shape. */
43
+ export type WorkflowActionStep = HostActionStep;
44
+ /** Any step a stored workflow holds. */
45
+ export type WorkflowStep = HostWorkflowStep | WorkflowActionStep;
46
+ /** A stored workflow, read with the unified step model. */
47
+ export interface AutomationWorkflow extends Omit<HostWorkflow, 'steps'> {
48
+ steps: WorkflowStep[];
49
+ }
50
+ /** Whether a stored step is an Actions step rather than a function call. */
51
+ export declare function isWorkflowActionStep(step: unknown): step is WorkflowActionStep;
52
+ /** Whether a stored step is a function call. */
53
+ export declare function isWorkflowFunctionStep(step: unknown): step is HostWorkflowStep;
54
+ /** Whether any step of a workflow is an Actions step. */
55
+ export declare function workflowHasActionSteps(workflow: {
56
+ steps?: readonly unknown[] | null;
57
+ } | null | undefined): boolean;
58
+ /**
59
+ * The Actions steps a workflow may hold: every step the SERVER runs.
60
+ *
61
+ * The executor's own rule, stated once. It runs every step that is not a
62
+ * client step, and `siteAlert`, whose alert it hands back to the request that
63
+ * raised the event. What is left out is what only a visitor's browser can do —
64
+ * class toggles, drawers, menus, overlays, scrolling, custom HTML and
65
+ * JavaScript, analytics events, redirects — and a workflow runs on a server
66
+ * event, where there is no page to do it on.
67
+ */
68
+ export declare const WORKFLOW_ACTION_STEP_TYPES: readonly HostActionStepType[];
69
+ /** Whether a workflow may run an Actions step of this type. */
70
+ export declare function isWorkflowActionStepType(type: unknown): boolean;
71
+ /** How a step type reads in a sentence: its picker label, or its raw type. */
72
+ export declare function workflowStepTypeLabel(type: string): string;
73
+ /**
74
+ * Why a workflow cannot hold this Actions step, or null when it can.
75
+ *
76
+ * Shared by the editor, which refuses to save the step, and by the engine,
77
+ * which refuses to run one a writer stored anyway — an import, the API, an
78
+ * older client.
79
+ */
80
+ export declare function workflowActionStepRefusal(step: WorkflowActionStep): string | null;
81
+ /**
82
+ * A workflow's steps checked the way the editors check them; null when they
83
+ * pass, or the first problem, numbered by the step's place in the workflow.
84
+ *
85
+ * An Actions step is held to the Actions editor's own validator,
86
+ * `validateHostAction`, one step at a time — the rules are that validator's,
87
+ * never a second copy of them. The list is capped at `WORKFLOW_MAX_STEPS`,
88
+ * the workflow's own ceiling rather than the ten an action is capped at.
89
+ *
90
+ * A FUNCTION CALL is not checked, deliberately. A workflow has always been
91
+ * savable with a blank step — it is how the builder opens, and how an author
92
+ * leaves a pipeline half-built and comes back to it — and a call naming no
93
+ * function fails at run time with the evaluator's own words. Checking it here
94
+ * would refuse a save that has been allowed since the builder shipped.
95
+ */
96
+ export declare function validateWorkflowSteps(steps: readonly unknown[] | null | undefined): string | null;
97
+ /**
98
+ * The function calls of a workflow, as a workflow of their own, for the pure
99
+ * evaluator — the console's test run, and anything else that evaluates a
100
+ * workflow without performing it.
101
+ *
102
+ * Each call keeps the result name it would have had in place: an unnamed step
103
+ * binds `step<N>` by its position, and the position is the one it holds among
104
+ * ALL the steps, so a call after an Actions step keeps the name the steps
105
+ * after it refer to.
106
+ */
107
+ export declare function workflowFunctionCalls(workflow: AutomationWorkflow | HostWorkflow): HostWorkflow;
@@ -0,0 +1,124 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
2
+ /**
3
+ * @license
4
+ * Copyright 2026 Aglyn LLC
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */ import { HOST_ACTION_STEP_LABELS, isClientActionStep, validateHostAction } from "@aglyn/aglyn/app-utils/actions";
18
+ import { WORKFLOW_MAX_STEPS } from "@aglyn/aglyn/app-utils/workflows";
19
+ /** Whether a stored step is an Actions step rather than a function call. */ export function isWorkflowActionStep(step) {
20
+ const type = step == null ? void 0 : step.type;
21
+ return typeof type === 'string' && Object.prototype.hasOwnProperty.call(HOST_ACTION_STEP_LABELS, type);
22
+ }
23
+ /** Whether a stored step is a function call. */ export function isWorkflowFunctionStep(step) {
24
+ return Boolean(step) && typeof step === 'object' && !isWorkflowActionStep(step);
25
+ }
26
+ /** Whether any step of a workflow is an Actions step. */ export function workflowHasActionSteps(workflow) {
27
+ var _ref;
28
+ return ((_ref = workflow == null ? void 0 : workflow.steps) != null ? _ref : []).some(isWorkflowActionStep);
29
+ }
30
+ /**
31
+ * The Actions steps a workflow may hold: every step the SERVER runs.
32
+ *
33
+ * The executor's own rule, stated once. It runs every step that is not a
34
+ * client step, and `siteAlert`, whose alert it hands back to the request that
35
+ * raised the event. What is left out is what only a visitor's browser can do —
36
+ * class toggles, drawers, menus, overlays, scrolling, custom HTML and
37
+ * JavaScript, analytics events, redirects — and a workflow runs on a server
38
+ * event, where there is no page to do it on.
39
+ */ export const WORKFLOW_ACTION_STEP_TYPES = Object.keys(HOST_ACTION_STEP_LABELS).filter((type)=>type === 'siteAlert' || !isClientActionStep({
40
+ type
41
+ }));
42
+ const WORKFLOW_ACTION_STEP_TYPE_SET = new Set(WORKFLOW_ACTION_STEP_TYPES);
43
+ /** Whether a workflow may run an Actions step of this type. */ export function isWorkflowActionStepType(type) {
44
+ return typeof type === 'string' && WORKFLOW_ACTION_STEP_TYPE_SET.has(type);
45
+ }
46
+ /** How a step type reads in a sentence: its picker label, or its raw type. */ export function workflowStepTypeLabel(type) {
47
+ var _HOST_ACTION_STEP_LABELS_type;
48
+ return (_HOST_ACTION_STEP_LABELS_type = HOST_ACTION_STEP_LABELS[type]) != null ? _HOST_ACTION_STEP_LABELS_type : type;
49
+ }
50
+ /**
51
+ * Why a workflow cannot hold this Actions step, or null when it can.
52
+ *
53
+ * Shared by the editor, which refuses to save the step, and by the engine,
54
+ * which refuses to run one a writer stored anyway — an import, the API, an
55
+ * older client.
56
+ */ export function workflowActionStepRefusal(step) {
57
+ if (isWorkflowActionStepType(step.type)) return null;
58
+ if (HOST_ACTION_STEP_LABELS[step.type]) {
59
+ return `“${workflowStepTypeLabel(step.type)}” runs in the visitor’s browser, ` + 'so a workflow cannot run it — build it as an interaction in Actions';
60
+ }
61
+ return `“${String(step.type)}” is not a step a workflow can run`;
62
+ }
63
+ /**
64
+ * A workflow's steps checked the way the editors check them; null when they
65
+ * pass, or the first problem, numbered by the step's place in the workflow.
66
+ *
67
+ * An Actions step is held to the Actions editor's own validator,
68
+ * `validateHostAction`, one step at a time — the rules are that validator's,
69
+ * never a second copy of them. The list is capped at `WORKFLOW_MAX_STEPS`,
70
+ * the workflow's own ceiling rather than the ten an action is capped at.
71
+ *
72
+ * A FUNCTION CALL is not checked, deliberately. A workflow has always been
73
+ * savable with a blank step — it is how the builder opens, and how an author
74
+ * leaves a pipeline half-built and comes back to it — and a call naming no
75
+ * function fails at run time with the evaluator's own words. Checking it here
76
+ * would refuse a save that has been allowed since the builder shipped.
77
+ */ export function validateWorkflowSteps(steps) {
78
+ const list = Array.isArray(steps) ? steps : [];
79
+ if (list.length > WORKFLOW_MAX_STEPS) {
80
+ return `Workflows are capped at ${WORKFLOW_MAX_STEPS} steps`;
81
+ }
82
+ for (const [index, step] of list.entries()){
83
+ const label = `Step ${index + 1}`;
84
+ if (!isWorkflowActionStep(step)) continue;
85
+ const refusal = workflowActionStepRefusal(step);
86
+ if (refusal) return `${label}: ${refusal}`;
87
+ const problem = validateHostAction({
88
+ name: 'workflow step',
89
+ trigger: {
90
+ event: 'formSubmission'
91
+ },
92
+ steps: [
93
+ step
94
+ ]
95
+ });
96
+ if (problem) return problem.replace(/^Step 1\b/, label);
97
+ }
98
+ return null;
99
+ }
100
+ /**
101
+ * The function calls of a workflow, as a workflow of their own, for the pure
102
+ * evaluator — the console's test run, and anything else that evaluates a
103
+ * workflow without performing it.
104
+ *
105
+ * Each call keeps the result name it would have had in place: an unnamed step
106
+ * binds `step<N>` by its position, and the position is the one it holds among
107
+ * ALL the steps, so a call after an Actions step keeps the name the steps
108
+ * after it refer to.
109
+ */ export function workflowFunctionCalls(workflow) {
110
+ var _workflow_steps;
111
+ const steps = [];
112
+ ((_workflow_steps = workflow.steps) != null ? _workflow_steps : []).forEach((step, index)=>{
113
+ var _step_resultName;
114
+ if (!isWorkflowFunctionStep(step)) return;
115
+ steps.push(_extends({}, step, {
116
+ resultName: ((_step_resultName = step.resultName) == null ? void 0 : _step_resultName.trim()) || `step${index + 1}`
117
+ }));
118
+ });
119
+ return _extends({}, workflow, {
120
+ steps
121
+ });
122
+ }
123
+
124
+ //# sourceMappingURL=workflow-steps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/engine/workflow-steps.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n HOST_ACTION_STEP_LABELS,\n type HostActionStep,\n type HostActionStepType,\n isClientActionStep,\n validateHostAction,\n} from '@aglyn/aglyn/app-utils/actions'\nimport {\n type HostWorkflow,\n type HostWorkflowStep,\n WORKFLOW_MAX_STEPS,\n} from '@aglyn/aglyn/app-utils/workflows'\n\n/**\n * ONE STEP MODEL FOR BOTH ENGINES.\n *\n * A workflow step is one of two things:\n *\n * - a FUNCTION CALL — `{ functionId, functionName, args, resultName }`, the\n * shape every workflow has stored since the builder shipped, and still the\n * default. It evaluates its argument expressions and binds the result for\n * the steps after it;\n * - an ACTIONS STEP — `{ type, …fields, when? }`, exactly as the Actions\n * editor stores it: write a dataset record, send an email, update a CRM\n * contact, post a webhook, wait. It runs through the Actions executors,\n * with their validation, their tier gates and their run-history phrases.\n *\n * The two are told apart by `type`. An Actions step always carries one of the\n * Actions step types and a function call never has one, so a stored workflow\n * is read as it was written and nothing is migrated. A step whose `type` the\n * Actions vocabulary does not know is read as a function call, which is how\n * every workflow read it before — it fails as a call to no function.\n *\n * Pure and client-safe: the console's editor and the server's engine read the\n * same definitions from here.\n */\n\n/** A workflow step that runs one of the Actions steps, stored in the Actions shape. */\nexport type WorkflowActionStep = HostActionStep\n\n/** Any step a stored workflow holds. */\nexport type WorkflowStep = HostWorkflowStep | WorkflowActionStep\n\n/** A stored workflow, read with the unified step model. */\nexport interface AutomationWorkflow extends Omit<HostWorkflow, 'steps'> {\n steps: WorkflowStep[]\n}\n\n/** Whether a stored step is an Actions step rather than a function call. */\nexport function isWorkflowActionStep(step: unknown): step is WorkflowActionStep {\n const type = (step as { type?: unknown } | null | undefined)?.type\n return (\n typeof type === 'string' &&\n Object.prototype.hasOwnProperty.call(HOST_ACTION_STEP_LABELS, type)\n )\n}\n\n/** Whether a stored step is a function call. */\nexport function isWorkflowFunctionStep(step: unknown): step is HostWorkflowStep {\n return Boolean(step) && typeof step === 'object' && !isWorkflowActionStep(step)\n}\n\n/** Whether any step of a workflow is an Actions step. */\nexport function workflowHasActionSteps(\n workflow: { steps?: readonly unknown[] | null } | null | undefined,\n): boolean {\n return (workflow?.steps ?? []).some(isWorkflowActionStep)\n}\n\n/**\n * The Actions steps a workflow may hold: every step the SERVER runs.\n *\n * The executor's own rule, stated once. It runs every step that is not a\n * client step, and `siteAlert`, whose alert it hands back to the request that\n * raised the event. What is left out is what only a visitor's browser can do —\n * class toggles, drawers, menus, overlays, scrolling, custom HTML and\n * JavaScript, analytics events, redirects — and a workflow runs on a server\n * event, where there is no page to do it on.\n */\nexport const WORKFLOW_ACTION_STEP_TYPES: readonly HostActionStepType[] = (\n Object.keys(HOST_ACTION_STEP_LABELS) as HostActionStepType[]\n).filter(\n (type) =>\n type === 'siteAlert' || !isClientActionStep({ type } as HostActionStep),\n)\n\nconst WORKFLOW_ACTION_STEP_TYPE_SET: ReadonlySet<string> = new Set(\n WORKFLOW_ACTION_STEP_TYPES,\n)\n\n/** Whether a workflow may run an Actions step of this type. */\nexport function isWorkflowActionStepType(type: unknown): boolean {\n return typeof type === 'string' && WORKFLOW_ACTION_STEP_TYPE_SET.has(type)\n}\n\n/** How a step type reads in a sentence: its picker label, or its raw type. */\nexport function workflowStepTypeLabel(type: string): string {\n return HOST_ACTION_STEP_LABELS[type as HostActionStepType] ?? type\n}\n\n/**\n * Why a workflow cannot hold this Actions step, or null when it can.\n *\n * Shared by the editor, which refuses to save the step, and by the engine,\n * which refuses to run one a writer stored anyway — an import, the API, an\n * older client.\n */\nexport function workflowActionStepRefusal(step: WorkflowActionStep): string | null {\n if (isWorkflowActionStepType(step.type)) return null\n if (HOST_ACTION_STEP_LABELS[step.type as HostActionStepType]) {\n return (\n `“${workflowStepTypeLabel(step.type)}” runs in the visitor’s browser, ` +\n 'so a workflow cannot run it — build it as an interaction in Actions'\n )\n }\n return `“${String(step.type)}” is not a step a workflow can run`\n}\n\n/**\n * A workflow's steps checked the way the editors check them; null when they\n * pass, or the first problem, numbered by the step's place in the workflow.\n *\n * An Actions step is held to the Actions editor's own validator,\n * `validateHostAction`, one step at a time — the rules are that validator's,\n * never a second copy of them. The list is capped at `WORKFLOW_MAX_STEPS`,\n * the workflow's own ceiling rather than the ten an action is capped at.\n *\n * A FUNCTION CALL is not checked, deliberately. A workflow has always been\n * savable with a blank step — it is how the builder opens, and how an author\n * leaves a pipeline half-built and comes back to it — and a call naming no\n * function fails at run time with the evaluator's own words. Checking it here\n * would refuse a save that has been allowed since the builder shipped.\n */\nexport function validateWorkflowSteps(\n steps: readonly unknown[] | null | undefined,\n): string | null {\n const list = Array.isArray(steps) ? steps : []\n if (list.length > WORKFLOW_MAX_STEPS) {\n return `Workflows are capped at ${WORKFLOW_MAX_STEPS} steps`\n }\n for (const [index, step] of list.entries()) {\n const label = `Step ${index + 1}`\n if (!isWorkflowActionStep(step)) continue\n const refusal = workflowActionStepRefusal(step)\n if (refusal) return `${label}: ${refusal}`\n const problem = validateHostAction({\n name: 'workflow step',\n trigger: { event: 'formSubmission' },\n steps: [step],\n })\n if (problem) return problem.replace(/^Step 1\\b/, label)\n }\n return null\n}\n\n/**\n * The function calls of a workflow, as a workflow of their own, for the pure\n * evaluator — the console's test run, and anything else that evaluates a\n * workflow without performing it.\n *\n * Each call keeps the result name it would have had in place: an unnamed step\n * binds `step<N>` by its position, and the position is the one it holds among\n * ALL the steps, so a call after an Actions step keeps the name the steps\n * after it refer to.\n */\nexport function workflowFunctionCalls(\n workflow: AutomationWorkflow | HostWorkflow,\n): HostWorkflow {\n const steps: HostWorkflowStep[] = []\n ;(workflow.steps ?? []).forEach((step, index) => {\n if (!isWorkflowFunctionStep(step)) return\n steps.push({\n ...step,\n resultName: step.resultName?.trim() || `step${index + 1}`,\n })\n })\n return { ...workflow, steps } as HostWorkflow\n}\n"],"names":["HOST_ACTION_STEP_LABELS","isClientActionStep","validateHostAction","WORKFLOW_MAX_STEPS","isWorkflowActionStep","step","type","Object","prototype","hasOwnProperty","call","isWorkflowFunctionStep","Boolean","workflowHasActionSteps","workflow","steps","some","WORKFLOW_ACTION_STEP_TYPES","keys","filter","WORKFLOW_ACTION_STEP_TYPE_SET","Set","isWorkflowActionStepType","has","workflowStepTypeLabel","workflowActionStepRefusal","String","validateWorkflowSteps","list","Array","isArray","length","index","entries","label","refusal","problem","name","trigger","event","replace","workflowFunctionCalls","forEach","push","resultName","trim"],"mappings":"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"}