@aglyn/plugins-workflows 1.0.0-beta.218 → 1.0.0-beta.220
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/README.md +33 -4
- package/package.json +13 -13
- package/src/index.d.ts +1 -0
- package/src/index.js.map +1 -1
- package/src/lib/components/host-actions-card.component.js +3 -2
- package/src/lib/components/host-actions-card.component.js.map +1 -1
- package/src/lib/components/host-run-history-card.component.d.ts +2 -2
- package/src/lib/components/host-run-history-card.component.js +3 -2
- package/src/lib/components/host-run-history-card.component.js.map +1 -1
- package/src/lib/components/host-webhooks-card.component.js +2 -1
- package/src/lib/components/host-webhooks-card.component.js.map +1 -1
- package/src/lib/components/host-workflows-card.component.js +4 -3
- package/src/lib/components/host-workflows-card.component.js.map +1 -1
- package/src/lib/components/use-automation-step-pickers.js +50 -42
- package/src/lib/components/use-automation-step-pickers.js.map +1 -1
- package/src/lib/components/use-org-automation-step-pickers.js +23 -11
- package/src/lib/components/use-org-automation-step-pickers.js.map +1 -1
- package/src/lib/components/workflow-zones.d.ts +49 -0
- package/src/lib/components/workflow-zones.js +3 -0
- package/src/lib/components/workflow-zones.js.map +1 -1
- package/src/lib/declarations.server.d.ts +6 -0
- package/src/lib/declarations.server.js +39 -0
- package/src/lib/declarations.server.js.map +1 -1
- package/src/lib/engine/crm-action-steps.d.ts +14 -1
- package/src/lib/engine/crm-action-steps.js +15 -0
- package/src/lib/engine/crm-action-steps.js.map +1 -1
- package/src/lib/engine/run-event-actions.d.ts +2 -1
- package/src/lib/engine/run-event-actions.js +66 -25
- package/src/lib/engine/run-event-actions.js.map +1 -1
- package/src/lib/engine/run-event-workflows.js +2 -1
- package/src/lib/engine/run-event-workflows.js.map +1 -1
- package/src/lib/engine/workflow-steps.d.ts +1 -1
- package/src/lib/engine/workflow-steps.js +1 -1
- package/src/lib/engine/workflow-steps.js.map +1 -1
- package/src/lib/model/automation-record.d.ts +47 -0
- package/src/lib/model/automation-record.js +79 -0
- package/src/lib/model/automation-record.js.map +1 -0
- package/src/lib/model/org-automations.js.map +1 -1
- package/src/lib/model/step-outcomes.d.ts +42 -0
- package/src/lib/model/step-outcomes.js +70 -0
- package/src/lib/model/step-outcomes.js.map +1 -0
- package/src/lib/model/webhooks.d.ts +36 -0
- package/src/lib/model/webhooks.js +24 -0
- package/src/lib/model/webhooks.js.map +1 -0
- package/src/lib/model/workflows-record-lists.d.ts +18 -0
- package/src/lib/model/workflows-record-lists.js +45 -0
- package/src/lib/model/workflows-record-lists.js.map +1 -0
- package/src/lib/model/workflows-record-routes.d.ts +22 -0
- package/src/lib/model/workflows-record-routes.js +73 -0
- package/src/lib/model/workflows-record-routes.js.map +1 -0
- package/src/lib/model/workflows-search-sources.d.ts +20 -0
- package/src/lib/model/workflows-search-sources.js +35 -0
- package/src/lib/model/workflows-search-sources.js.map +1 -0
- package/src/lib/model/workflows.d.ts +102 -0
- package/src/lib/model/workflows.js +167 -0
- package/src/lib/model/workflows.js.map +1 -0
- package/src/lib/plan-entitlements.d.ts +36 -0
- package/src/lib/plan-entitlements.js +44 -0
- package/src/lib/plan-entitlements.js.map +1 -0
- package/src/lib/plugin.js +37 -2
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/server/automation-record-index.d.ts +20 -0
- package/src/lib/server/automation-record-index.js +59 -0
- package/src/lib/server/automation-record-index.js.map +1 -0
- package/src/lib/server/workflow-dependents.d.ts +28 -0
- package/src/lib/server/workflow-dependents.js +61 -0
- package/src/lib/server/workflow-dependents.js.map +1 -0
- package/src/lib/server/workflow-variables.d.ts +20 -0
- package/src/lib/server/workflow-variables.js +75 -0
- package/src/lib/server/workflow-variables.js.map +1 -0
- package/src/lib/server.d.ts +1 -0
- package/src/lib/server.js +2 -1
- package/src/lib/server.js.map +1 -1
- package/src/lib/tenant-emails.d.ts +29 -0
- package/src/lib/tenant-emails.js +41 -0
- package/src/lib/tenant-emails.js.map +1 -0
- package/src/lib/testing/stand-in-dataset-list.d.ts +28 -0
- package/src/lib/testing/stand-in-dataset-list.js +55 -0
- package/src/lib/testing/stand-in-dataset-list.js.map +1 -0
- package/src/lib/testing/stand-in-overlay-list.d.ts +26 -0
- package/src/lib/testing/stand-in-overlay-list.js +53 -0
- package/src/lib/testing/stand-in-overlay-list.js.map +1 -0
- package/src/lib/usage-axes.d.ts +28 -0
- package/src/lib/usage-axes.js +72 -0
- package/src/lib/usage-axes.js.map +1 -0
|
@@ -0,0 +1,167 @@
|
|
|
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 { evaluateExpression, evaluateHostFunction } from "@aglyn/aglyn/app-utils/functions";
|
|
18
|
+
export const WORKFLOW_MAX_STEPS = 25;
|
|
19
|
+
/** Max nesting across workflow→function→workflow cross-calls (AGL-129). */ export const CROSS_MAX_DEPTH = 3;
|
|
20
|
+
/** How deep one custom event may chain into another automation's run. */ export const ACTION_MAX_EVENT_DEPTH = 3;
|
|
21
|
+
/** Variable values as a typed expression scope (mirrors resolveBindings). */ function variableScope(variables) {
|
|
22
|
+
const scope = {};
|
|
23
|
+
for (const [key, variable] of Object.entries(variables)){
|
|
24
|
+
var _variable_value, _variable_value1;
|
|
25
|
+
const value = variable.type === 'number' ? Number((_variable_value = variable.value) != null ? _variable_value : 0) : variable.type === 'boolean' ? variable.value === 'true' : (_variable_value1 = variable.value) != null ? _variable_value1 : '';
|
|
26
|
+
scope[key] = value;
|
|
27
|
+
// Under its NAME as well (AGL-3202). Callers key this map by name, by
|
|
28
|
+
// id, or by both; an expression only ever says the name, so a map keyed
|
|
29
|
+
// by id alone used to give it nothing to find.
|
|
30
|
+
if (variable.name && !Object.prototype.hasOwnProperty.call(scope, variable.name)) {
|
|
31
|
+
scope[variable.name] = value;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return scope;
|
|
35
|
+
}
|
|
36
|
+
export function runWorkflow(workflow, functions, variables = {}, /**
|
|
37
|
+
* Extra scope entries seeded ahead of the steps — event payloads (path,
|
|
38
|
+
* formName, field values) land here (AGL-128). Wins over variables.
|
|
39
|
+
*/ extraScope = {}, context = {}) {
|
|
40
|
+
var _workflow_steps, _context_depth, _Object_values_at;
|
|
41
|
+
var _workflow_returnValue;
|
|
42
|
+
const steps = (_workflow_steps = workflow.steps) != null ? _workflow_steps : [];
|
|
43
|
+
if (steps.length > WORKFLOW_MAX_STEPS) {
|
|
44
|
+
return {
|
|
45
|
+
ok: false,
|
|
46
|
+
error: `Workflows are capped at ${WORKFLOW_MAX_STEPS} steps`
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
const depth = (_context_depth = context.depth) != null ? _context_depth : 0;
|
|
50
|
+
if (depth > CROSS_MAX_DEPTH) {
|
|
51
|
+
return {
|
|
52
|
+
ok: false,
|
|
53
|
+
error: 'Workflow nesting is too deep'
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
// Function steps may call other workflows (AGL-129); every hop shares
|
|
57
|
+
// this depth guard so mutual recursion terminates.
|
|
58
|
+
const invokeWorkflow = (name, callScope)=>{
|
|
59
|
+
var _context_workflows;
|
|
60
|
+
const nested = (_context_workflows = context.workflows) == null ? void 0 : _context_workflows[name == null ? void 0 : name.trim()];
|
|
61
|
+
if (!nested) throw new Error(`Unknown workflow "${name}"`);
|
|
62
|
+
const run = runWorkflow(nested, functions, variables, callScope, _extends({}, context, {
|
|
63
|
+
depth: depth + 1
|
|
64
|
+
}));
|
|
65
|
+
if (run.ok === false) throw new Error(run.error);
|
|
66
|
+
return run.value;
|
|
67
|
+
};
|
|
68
|
+
// The site's variables, apart from the step results layered over them:
|
|
69
|
+
// they are what a function may read by name (AGL-3202), wherever it runs.
|
|
70
|
+
const siteVariables = variableScope(variables);
|
|
71
|
+
const scope = _extends({}, siteVariables, extraScope);
|
|
72
|
+
const results = {};
|
|
73
|
+
for (const [index, step] of steps.entries()){
|
|
74
|
+
var _functions_, _ref, _ref1;
|
|
75
|
+
var _step_functionId, _step_functionName, _step_resultName;
|
|
76
|
+
// Id-first resolution (AGL-261): maps are double-keyed by id and name.
|
|
77
|
+
const definition = (_functions_ = functions[(_ref = (_step_functionId = step.functionId) == null ? void 0 : _step_functionId.trim()) != null ? _ref : '']) != null ? _functions_ : functions[(_ref1 = (_step_functionName = step.functionName) == null ? void 0 : _step_functionName.trim()) != null ? _ref1 : ''];
|
|
78
|
+
if (!definition) {
|
|
79
|
+
return {
|
|
80
|
+
ok: false,
|
|
81
|
+
error: `Unknown function "${step.functionName || step.functionId}"`,
|
|
82
|
+
step: index + 1
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
const args = {};
|
|
86
|
+
try {
|
|
87
|
+
var _definition_parameters;
|
|
88
|
+
(_definition_parameters = definition.parameters) == null ? void 0 : _definition_parameters.forEach((parameter, parameterIndex)=>{
|
|
89
|
+
var _step_args;
|
|
90
|
+
const expression = (_step_args = step.args) == null ? void 0 : _step_args[parameterIndex];
|
|
91
|
+
if (expression != null && String(expression).trim() !== '') {
|
|
92
|
+
args[parameter.name] = evaluateExpression(String(expression), scope);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
} catch (error) {
|
|
96
|
+
return {
|
|
97
|
+
ok: false,
|
|
98
|
+
error: `Step ${index + 1}: ${error.message}`,
|
|
99
|
+
step: index + 1
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
const run = evaluateHostFunction(definition, args, _extends({}, context.workflows ? {
|
|
103
|
+
invokeWorkflow
|
|
104
|
+
} : {}, {
|
|
105
|
+
// A function that prices from `extra_site_price` on a page must not
|
|
106
|
+
// fail with "Unknown name" the day a workflow calls it.
|
|
107
|
+
globals: siteVariables
|
|
108
|
+
}));
|
|
109
|
+
// `=== false` (not `!run.ok`): the union fails to narrow under the
|
|
110
|
+
// stricter lib build tsconfig otherwise (same quirk as publish.ts).
|
|
111
|
+
if (run.ok === false) {
|
|
112
|
+
return {
|
|
113
|
+
ok: false,
|
|
114
|
+
error: `Step ${index + 1} (${definition.name}): ${run.error}`,
|
|
115
|
+
step: index + 1
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
const resultName = ((_step_resultName = step.resultName) == null ? void 0 : _step_resultName.trim()) || `step${index + 1}`;
|
|
119
|
+
scope[resultName] = run.value;
|
|
120
|
+
results[resultName] = run.value;
|
|
121
|
+
}
|
|
122
|
+
const returnName = (_workflow_returnValue = workflow.returnValue) == null ? void 0 : _workflow_returnValue.trim();
|
|
123
|
+
const value = returnName && returnName in scope ? scope[returnName] : (_Object_values_at = Object.values(results).at(-1)) != null ? _Object_values_at : '';
|
|
124
|
+
return {
|
|
125
|
+
ok: true,
|
|
126
|
+
value,
|
|
127
|
+
results
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Computed variables (AGL-129): a variable naming a workflow takes that
|
|
132
|
+
* workflow's result as its value at compose time — by id first, then by
|
|
133
|
+
* name; failures keep the stored fallback value. Each computed variable
|
|
134
|
+
* evaluates once, bounded by the shared depth guard.
|
|
135
|
+
*/ export function resolveComputedVariables(variables, functions, workflows) {
|
|
136
|
+
const resolved = {};
|
|
137
|
+
// Lookup maps are double-keyed by id and name (AGL-185), so the same doc
|
|
138
|
+
// can appear under two keys — evaluate each workflow once per doc.
|
|
139
|
+
const memo = new Map();
|
|
140
|
+
for (const [name, variable] of Object.entries(variables)){
|
|
141
|
+
var _ref;
|
|
142
|
+
const source = variable;
|
|
143
|
+
const workflowId = typeof source.workflowId === 'string' ? source.workflowId.trim() : '';
|
|
144
|
+
const workflowName = typeof source.workflowName === 'string' ? source.workflowName.trim() : '';
|
|
145
|
+
const workflow = (_ref = workflowId ? workflows[workflowId] : undefined) != null ? _ref : workflowName ? workflows[workflowName] : undefined;
|
|
146
|
+
if (!workflow) {
|
|
147
|
+
resolved[name] = variable;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
const cached = memo.get(variable);
|
|
151
|
+
if (cached) {
|
|
152
|
+
resolved[name] = cached;
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
const run = runWorkflow(workflow, functions, variables, {}, {
|
|
156
|
+
workflows
|
|
157
|
+
});
|
|
158
|
+
const next = run.ok === false ? variable : _extends({}, variable, {
|
|
159
|
+
value: String(run.value)
|
|
160
|
+
});
|
|
161
|
+
memo.set(variable, next);
|
|
162
|
+
resolved[name] = next;
|
|
163
|
+
}
|
|
164
|
+
return resolved;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
//# sourceMappingURL=workflows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/model/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 evaluateExpression,\n evaluateHostFunction,\n type HostFunction,\n} from '@aglyn/aglyn/app-utils/functions'\nimport type { HostEventType } from '@aglyn/aglyn/app-utils/host-events'\nimport type { HostVariable } from '@aglyn/aglyn/app-utils/variables'\n\n/**\n * Workflows (Workflow Builder, AGL-101): named pipelines of host-function\n * calls. Each step evaluates its argument expressions over host variables\n * and previous step results, runs the function through the safe evaluator,\n * and stores the result under its name for later steps. Pure and bounded —\n * no I/O, no loops. Site-event triggers arrive in v2.\n */\n\nexport interface HostWorkflowTrigger {\n event: HostEventType\n /**\n * Optional expression over the event payload (plus variables); the\n * workflow only runs when it evaluates truthy (e.g. `path == \"/pricing\"`).\n */\n filter?: string\n}\n\nexport interface HostWorkflowStep {\n /**\n * Host function to run — by doc id (AGL-261), rename-safe. Steps saved\n * before AGL-261 carry only `functionName`; executors resolve id first.\n */\n functionId?: string\n /** Legacy name reference, kept as the display hint; `functionId` wins. */\n functionName: string\n /**\n * One expression per function parameter, evaluated over variables and\n * previous step results (e.g. `price * qty`, `step1 + 10`).\n */\n args: string[]\n /** Scope name the step's result binds to; defaults to `step<N>`. */\n resultName?: string\n}\n\n/** `hosts/{hostId}/workflows/{id}` doc. */\nexport interface HostWorkflow {\n name: string\n steps: HostWorkflowStep[]\n /** Scope name whose final value the workflow returns. */\n returnValue?: string\n /** Event trigger (AGL-128); absent means manual/embedded use only. */\n trigger?: HostWorkflowTrigger | null\n}\n\nexport const WORKFLOW_MAX_STEPS = 25\n/** Max nesting across workflow→function→workflow cross-calls (AGL-129). */\nexport const CROSS_MAX_DEPTH = 3\n\n/** How deep one custom event may chain into another automation's run. */\nexport const ACTION_MAX_EVENT_DEPTH = 3\n\nexport type WorkflowRunResult =\n | {\n ok: true\n value: number | string | boolean\n results: Record<string, number | string | boolean>\n }\n | { ok: false; error: string; step?: number }\n\n/** Variable values as a typed expression scope (mirrors resolveBindings). */\nfunction variableScope(\n variables: Record<string, HostVariable>,\n): Record<string, number | string | boolean> {\n const scope: Record<string, number | string | boolean> = {}\n for (const [key, variable] of Object.entries(variables)) {\n const value =\n variable.type === 'number'\n ? Number(variable.value ?? 0)\n : variable.type === 'boolean'\n ? variable.value === 'true'\n : (variable.value ?? '')\n scope[key] = value\n // Under its NAME as well (AGL-3202). Callers key this map by name, by\n // id, or by both; an expression only ever says the name, so a map keyed\n // by id alone used to give it nothing to find.\n if (\n variable.name &&\n !Object.prototype.hasOwnProperty.call(scope, variable.name)\n ) {\n scope[variable.name] = value\n }\n }\n return scope\n}\n\nexport interface WorkflowRunContext {\n /** All host workflows by name, enabling function→workflow calls. */\n workflows?: Record<string, HostWorkflow>\n /** Cross-call nesting depth; internal — callers omit it. */\n depth?: number\n}\n\nexport function runWorkflow(\n workflow: HostWorkflow,\n functions: Record<string, HostFunction>,\n variables: Record<string, HostVariable> = {},\n /**\n * Extra scope entries seeded ahead of the steps — event payloads (path,\n * formName, field values) land here (AGL-128). Wins over variables.\n */\n extraScope: Record<string, number | string | boolean> = {},\n context: WorkflowRunContext = {},\n): WorkflowRunResult {\n const steps = workflow.steps ?? []\n if (steps.length > WORKFLOW_MAX_STEPS) {\n return { ok: false, error: `Workflows are capped at ${WORKFLOW_MAX_STEPS} steps` }\n }\n const depth = context.depth ?? 0\n if (depth > CROSS_MAX_DEPTH) {\n return { ok: false, error: 'Workflow nesting is too deep' }\n }\n // Function steps may call other workflows (AGL-129); every hop shares\n // this depth guard so mutual recursion terminates.\n const invokeWorkflow = (\n name: string,\n callScope: Record<string, number | string | boolean>,\n ): number | string | boolean => {\n const nested = context.workflows?.[name?.trim()]\n if (!nested) throw new Error(`Unknown workflow \"${name}\"`)\n const run = runWorkflow(nested, functions, variables, callScope, {\n ...context,\n depth: depth + 1,\n })\n if (run.ok === false) throw new Error(run.error)\n return run.value\n }\n // The site's variables, apart from the step results layered over them:\n // they are what a function may read by name (AGL-3202), wherever it runs.\n const siteVariables = variableScope(variables)\n const scope = { ...siteVariables, ...extraScope }\n const results: Record<string, number | string | boolean> = {}\n\n for (const [index, step] of steps.entries()) {\n // Id-first resolution (AGL-261): maps are double-keyed by id and name.\n const definition =\n functions[step.functionId?.trim() ?? ''] ??\n functions[step.functionName?.trim() ?? '']\n if (!definition) {\n return {\n ok: false,\n error: `Unknown function \"${step.functionName || step.functionId}\"`,\n step: index + 1,\n }\n }\n const args: Record<string, unknown> = {}\n try {\n definition.parameters?.forEach((parameter, parameterIndex) => {\n const expression = step.args?.[parameterIndex]\n if (expression != null && String(expression).trim() !== '') {\n args[parameter.name] = evaluateExpression(String(expression), scope)\n }\n })\n } catch (error) {\n return {\n ok: false,\n error: `Step ${index + 1}: ${(error as Error).message}`,\n step: index + 1,\n }\n }\n const run = evaluateHostFunction(definition, args, {\n ...(context.workflows ? { invokeWorkflow } : {}),\n // A function that prices from `extra_site_price` on a page must not\n // fail with \"Unknown name\" the day a workflow calls it.\n globals: siteVariables,\n })\n // `=== false` (not `!run.ok`): the union fails to narrow under the\n // stricter lib build tsconfig otherwise (same quirk as publish.ts).\n if (run.ok === false) {\n return {\n ok: false,\n error: `Step ${index + 1} (${definition.name}): ${run.error}`,\n step: index + 1,\n }\n }\n const resultName = step.resultName?.trim() || `step${index + 1}`\n scope[resultName] = run.value\n results[resultName] = run.value\n }\n\n const returnName = workflow.returnValue?.trim()\n const value =\n returnName && returnName in scope\n ? scope[returnName]\n : (Object.values(results).at(-1) ?? '')\n return { ok: true, value, results }\n}\n\n/**\n * The reference a computed site variable carries to the workflow that\n * computes it: the workflow's document id (AGL-261), and the name it had when\n * it was picked, which a variable computed before ids existed carries alone.\n * Written by the variables editor; read here.\n */\nexport interface WorkflowComputedVariable extends HostVariable {\n workflowId?: string\n workflowName?: string\n}\n\n/**\n * Computed variables (AGL-129): a variable naming a workflow takes that\n * workflow's result as its value at compose time — by id first, then by\n * name; failures keep the stored fallback value. Each computed variable\n * evaluates once, bounded by the shared depth guard.\n */\nexport function resolveComputedVariables(\n variables: Record<string, HostVariable>,\n functions: Record<string, HostFunction>,\n workflows: Record<string, HostWorkflow>,\n): Record<string, HostVariable> {\n const resolved: Record<string, HostVariable> = {}\n // Lookup maps are double-keyed by id and name (AGL-185), so the same doc\n // can appear under two keys — evaluate each workflow once per doc.\n const memo = new Map<HostVariable, HostVariable>()\n for (const [name, variable] of Object.entries(variables)) {\n const source = variable as WorkflowComputedVariable\n const workflowId =\n typeof source.workflowId === 'string' ? source.workflowId.trim() : ''\n const workflowName =\n typeof source.workflowName === 'string' ? source.workflowName.trim() : ''\n const workflow =\n (workflowId ? workflows[workflowId] : undefined) ??\n (workflowName ? workflows[workflowName] : undefined)\n if (!workflow) {\n resolved[name] = variable\n continue\n }\n const cached = memo.get(variable)\n if (cached) {\n resolved[name] = cached\n continue\n }\n const run = runWorkflow(workflow, functions, variables, {}, { workflows })\n const next =\n run.ok === false\n ? variable\n : { ...variable, value: String(run.value) }\n memo.set(variable, next)\n resolved[name] = next\n }\n return resolved\n}\n"],"names":["evaluateExpression","evaluateHostFunction","WORKFLOW_MAX_STEPS","CROSS_MAX_DEPTH","ACTION_MAX_EVENT_DEPTH","variableScope","variables","scope","key","variable","Object","entries","value","type","Number","name","prototype","hasOwnProperty","call","runWorkflow","workflow","functions","extraScope","context","steps","length","ok","error","depth","invokeWorkflow","callScope","nested","workflows","trim","Error","run","siteVariables","results","index","step","definition","functionId","functionName","args","parameters","forEach","parameter","parameterIndex","expression","String","message","globals","resultName","returnName","returnValue","values","at","resolveComputedVariables","resolved","memo","Map","workflowId","source","workflowName","undefined","cached","get","next","set"],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
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 { OrgPlan } from '@aglyn/aglyn/foundation/definitions/org-billing.types';
|
|
18
|
+
import type { PluginPlanEntitlementsDeclaration } from '@aglyn/aglyn/plugin-manager/plugin-plan-entitlements';
|
|
19
|
+
/**
|
|
20
|
+
* THE WORKFLOWS PLUGIN'S PLAN BAND (AGL-3080): the workflow runs each plan
|
|
21
|
+
* includes a month. Compiled into core's `PLAN_ENTITLEMENTS` by the manifest
|
|
22
|
+
* generator (`register.planEntitlements`).
|
|
23
|
+
*/
|
|
24
|
+
declare module '@aglyn/aglyn/plugin-manager/plugin-entitlement-keys' {
|
|
25
|
+
interface PluginEntitlementQuotas {
|
|
26
|
+
/** Event-triggered workflow runs per calendar month (AGL-165). */
|
|
27
|
+
workflowRunsPerMonth?: number;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The workflow runs each plan includes a month. Priced into the cost model at
|
|
32
|
+
* `perRun` beside the action-run band, since 2026-09-07.
|
|
33
|
+
*/
|
|
34
|
+
export declare const WORKFLOW_RUNS_PER_MONTH_BY_PLAN: Readonly<Record<OrgPlan, number>>;
|
|
35
|
+
/** The workflows plugin's plan figures, for the manifest generator. */
|
|
36
|
+
export declare function workflowsPlanEntitlements(): PluginPlanEntitlementsDeclaration;
|
|
@@ -0,0 +1,44 @@
|
|
|
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
|
+
*/ // Types only: the manifest generator loads this module on its own to compile
|
|
17
|
+
// the plan figures, so nothing here may reach a core module at runtime.
|
|
18
|
+
/**
|
|
19
|
+
* The workflow runs each plan includes a month. Priced into the cost model at
|
|
20
|
+
* `perRun` beside the action-run band, since 2026-09-07.
|
|
21
|
+
*/ export const WORKFLOW_RUNS_PER_MONTH_BY_PLAN = {
|
|
22
|
+
free: 0,
|
|
23
|
+
starter: 500,
|
|
24
|
+
pro: 5000,
|
|
25
|
+
business: 50000,
|
|
26
|
+
scale: 150000,
|
|
27
|
+
advanced: 500000,
|
|
28
|
+
agency: 2000000,
|
|
29
|
+
// Agency's band × 2, the rule every Enterprise fallback follows.
|
|
30
|
+
enterprise: 4000000
|
|
31
|
+
};
|
|
32
|
+
/** The workflows plugin's plan figures, for the manifest generator. */ export function workflowsPlanEntitlements() {
|
|
33
|
+
return {
|
|
34
|
+
quotas: [
|
|
35
|
+
{
|
|
36
|
+
key: 'workflowRunsPerMonth',
|
|
37
|
+
label: 'Workflow runs / mo',
|
|
38
|
+
byPlan: WORKFLOW_RUNS_PER_MONTH_BY_PLAN
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
//# sourceMappingURL=plan-entitlements.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/plugins/workflows/src/lib/plan-entitlements.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\n// Types only: the manifest generator loads this module on its own to compile\n// the plan figures, so nothing here may reach a core module at runtime.\nimport type { OrgPlan } from '@aglyn/aglyn/foundation/definitions/org-billing.types'\nimport type { PluginPlanEntitlementsDeclaration } from '@aglyn/aglyn/plugin-manager/plugin-plan-entitlements'\n\n/**\n * THE WORKFLOWS PLUGIN'S PLAN BAND (AGL-3080): the workflow runs each plan\n * includes a month. Compiled into core's `PLAN_ENTITLEMENTS` by the manifest\n * generator (`register.planEntitlements`).\n */\ndeclare module '@aglyn/aglyn/plugin-manager/plugin-entitlement-keys' {\n interface PluginEntitlementQuotas {\n /** Event-triggered workflow runs per calendar month (AGL-165). */\n workflowRunsPerMonth?: number\n }\n}\n\n/**\n * The workflow runs each plan includes a month. Priced into the cost model at\n * `perRun` beside the action-run band, since 2026-09-07.\n */\nexport const WORKFLOW_RUNS_PER_MONTH_BY_PLAN: Readonly<Record<OrgPlan, number>> = {\n free: 0,\n starter: 500,\n pro: 5000,\n business: 50000,\n scale: 150000,\n advanced: 500000,\n agency: 2000000,\n // Agency's band × 2, the rule every Enterprise fallback follows.\n enterprise: 4_000_000,\n}\n\n/** The workflows plugin's plan figures, for the manifest generator. */\nexport function workflowsPlanEntitlements(): PluginPlanEntitlementsDeclaration {\n return {\n quotas: [\n {\n key: 'workflowRunsPerMonth',\n label: 'Workflow runs / mo',\n byPlan: WORKFLOW_RUNS_PER_MONTH_BY_PLAN,\n },\n ],\n }\n}\n"],"names":["WORKFLOW_RUNS_PER_MONTH_BY_PLAN","free","starter","pro","business","scale","advanced","agency","enterprise","workflowsPlanEntitlements","quotas","key","label","byPlan"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,6EAA6E;AAC7E,wEAAwE;AAgBxE;;;CAGC,GACD,OAAO,MAAMA,kCAAqE;IAChFC,MAAM;IACNC,SAAS;IACTC,KAAK;IACLC,UAAU;IACVC,OAAO;IACPC,UAAU;IACVC,QAAQ;IACR,iEAAiE;IACjEC,YAAY;AACd,EAAC;AAED,qEAAqE,GACrE,OAAO,SAASC;IACd,OAAO;QACLC,QAAQ;YACN;gBACEC,KAAK;gBACLC,OAAO;gBACPC,QAAQb;YACV;SACD;IACH;AACF"}
|
package/src/lib/plugin.js
CHANGED
|
@@ -20,8 +20,11 @@ import { HostActivityCard } from "./components/host-activity-card.component.js";
|
|
|
20
20
|
import { StaffOrgAutomationsCard, StaffSiteAutomationsCard } from "./components/staff-automations-card.component.js";
|
|
21
21
|
import { WORKFLOWS_CONSOLE_SECTIONS, WORKFLOWS_ORG_CONSOLE_SECTIONS } from "./components/workflows-console-sections.js";
|
|
22
22
|
import { registerPluginZone } from "@aglyn/aglyn/plugin-manager/plugin-zones";
|
|
23
|
-
import { WORKFLOW_USAGE_ZONE } from "./components/workflow-zones.js";
|
|
23
|
+
import { AUTOMATION_EDITOR_ZONE, AUTOMATION_RUN_ZONE, HOST_AUTOMATIONS_ZONE, WORKFLOW_USAGE_ZONE } from "./components/workflow-zones.js";
|
|
24
24
|
import { BUNDLE_ID } from "./constants/bundle-common.js";
|
|
25
|
+
import { registerWorkflowsRecordLists } from "./model/workflows-record-lists.js";
|
|
26
|
+
import { registerWorkflowsRecordRoutes } from "./model/workflows-record-routes.js";
|
|
27
|
+
import { WORKFLOWS_SEARCH_SOURCES } from "./model/workflows-search-sources.js";
|
|
25
28
|
/** Code-split: the Automation console page only loads when opened. */ const WorkflowsConsolePage = lazy(()=>import("./components/workflows-console-page.js"));
|
|
26
29
|
/**
|
|
27
30
|
* Workflows feature plugin (AGL-395). Console-only — workflows, actions,
|
|
@@ -37,6 +40,8 @@ import { BUNDLE_ID } from "./constants/bundle-common.js";
|
|
|
37
40
|
* Remote Config release flag — and a section's name is not a reason to orphan
|
|
38
41
|
* them. Only what a reader sees carries the new name.
|
|
39
42
|
*/ export function registerWorkflowsConsole() {
|
|
43
|
+
registerWorkflowsRecordRoutes();
|
|
44
|
+
registerWorkflowsRecordLists();
|
|
40
45
|
registerPluginZone({
|
|
41
46
|
zone: WORKFLOW_USAGE_ZONE,
|
|
42
47
|
label: 'Where a workflow is used',
|
|
@@ -46,6 +51,35 @@ import { BUNDLE_ID } from "./constants/bundle-common.js";
|
|
|
46
51
|
{
|
|
47
52
|
pluginId: BUNDLE_ID
|
|
48
53
|
});
|
|
54
|
+
// The zones the Automation page draws in its own layouts (AGL-2919): one
|
|
55
|
+
// item in the Actions row, inside an open editor, on a failed run's row.
|
|
56
|
+
registerPluginZone({
|
|
57
|
+
zone: HOST_AUTOMATIONS_ZONE,
|
|
58
|
+
label: 'Automation page actions',
|
|
59
|
+
surface: 'console',
|
|
60
|
+
layout: 'bare',
|
|
61
|
+
description: 'On the Automation page, beside Add action and Recipes: another way to start an automation. `openAction` opens a listed action in the Actions editor; a widget here writes nothing through the page.'
|
|
62
|
+
}, {
|
|
63
|
+
pluginId: BUNDLE_ID
|
|
64
|
+
});
|
|
65
|
+
registerPluginZone({
|
|
66
|
+
zone: AUTOMATION_EDITOR_ZONE,
|
|
67
|
+
label: 'An automation’s editor',
|
|
68
|
+
surface: 'console',
|
|
69
|
+
layout: 'bare',
|
|
70
|
+
description: 'Inside the editor of one saved automation, an action or a workflow. A widget here reads the automation as it is stored and changes nothing in the editor.'
|
|
71
|
+
}, {
|
|
72
|
+
pluginId: BUNDLE_ID
|
|
73
|
+
});
|
|
74
|
+
registerPluginZone({
|
|
75
|
+
zone: AUTOMATION_RUN_ZONE,
|
|
76
|
+
label: 'A failed automation run',
|
|
77
|
+
surface: 'console',
|
|
78
|
+
layout: 'bare',
|
|
79
|
+
description: 'On each failed run in an automation’s run history. A widget here reads the run as it was recorded and changes nothing.'
|
|
80
|
+
}, {
|
|
81
|
+
pluginId: BUNDLE_ID
|
|
82
|
+
});
|
|
49
83
|
Aglyn.registerConsoleExtension({
|
|
50
84
|
// Host activity feed (AGL-419): rendered by the shell's
|
|
51
85
|
// 'hostActivity' widget slot (dashboard + editor view page).
|
|
@@ -74,13 +108,14 @@ import { BUNDLE_ID } from "./constants/bundle-common.js";
|
|
|
74
108
|
pluginId: BUNDLE_ID,
|
|
75
109
|
displayName: 'Automation',
|
|
76
110
|
featureFlag: 'workflows',
|
|
111
|
+
searchSources: WORKFLOWS_SEARCH_SOURCES,
|
|
77
112
|
navItems: [
|
|
78
113
|
{
|
|
79
114
|
label: 'Automation',
|
|
80
115
|
// Workflows, Actions and Webhooks are the tabs INSIDE this section, so
|
|
81
116
|
// the section is named for what they have in common. `/workflows` —
|
|
82
117
|
// the address before the section had its own name — is redirected here
|
|
83
|
-
// by
|
|
118
|
+
// by this plugin's `consoleRedirects`.
|
|
84
119
|
href: '/automation',
|
|
85
120
|
// Sections as ROUTES (AGL-2501): each is a real URL the shell
|
|
86
121
|
// resolves and gates, so the page mounts the one being read.
|
package/src/lib/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../libs/plugins/workflows/src/lib/plugin.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 * as Aglyn from '@aglyn/aglyn'\nimport { mdiSitemap } from '@aglyn/shared-data-mdi'\nimport { lazy } from 'react'\nimport { HostActivityCard } from './components/host-activity-card.component'\nimport {\n StaffOrgAutomationsCard,\n StaffSiteAutomationsCard,\n} from './components/staff-automations-card.component'\nimport {\n WORKFLOWS_CONSOLE_SECTIONS,\n WORKFLOWS_ORG_CONSOLE_SECTIONS,\n} from './components/workflows-console-sections'\nimport { registerPluginZone } from '@aglyn/aglyn/plugin-manager/plugin-zones'\nimport { WORKFLOW_USAGE_ZONE } from './components/workflow-zones'\nimport { BUNDLE_ID } from './constants/bundle-common'\n\n/** Code-split: the Automation console page only loads when opened. */\nconst WorkflowsConsolePage = lazy(\n () => import('./components/workflows-console-page'),\n)\n\n/**\n * Workflows feature plugin (AGL-395). Console-only — workflows, actions,\n * and webhooks run server-side (event pipelines, `/api/hooks`), not through\n * a canvas element, so there is no UI bundle. The console half declares the\n * Automation nav + page through the ConsoleExtension registry, gated by the\n * `workflows` entitlement (the Actions/Webhooks tabs run their own per-plan\n * checks off the passed `org`). Where a workflow is used is asked of the\n * platform's scan and drawn in a zone this plugin hosts.\n *\n * `pluginId`, `featureFlag` and `navTabId` all still read `workflows`: they\n * are stored — an org's enabled-plugin ids, the plan's entitlement flags, the\n * Remote Config release flag — and a section's name is not a reason to orphan\n * them. Only what a reader sees carries the new name.\n */\nexport function registerWorkflowsConsole(): void {\n registerPluginZone(\n {\n zone: WORKFLOW_USAGE_ZONE,\n label: 'Where a workflow is used',\n surface: 'console',\n description:\n 'On the Automation page, after a reader asks where a workflow is used. A widget here lays out the scan the page already ran; it is handed the site, the answer and a way to close, and it writes nothing.',\n },\n // Named, because a spec calls this registrar without the loader.\n { pluginId: BUNDLE_ID },\n )\n Aglyn.registerConsoleExtension({\n // Host activity feed (AGL-419): rendered by the shell's\n // 'hostActivity' widget slot (dashboard + editor view page).\n widgets: [\n {\n slot: 'hostActivity',\n widgetId: 'workflows-host-activity',\n title: 'Recent Activity',\n Component: HostActivityCard,\n },\n // The staff site and organization pages' automations (AGL-3379), read\n // only: staff see what runs on a site without joining it.\n {\n slot: Aglyn.CONSOLE_WIDGET_SLOTS.staffSite,\n widgetId: 'workflows-staff-site-automations',\n title: 'Automations',\n Component: StaffSiteAutomationsCard,\n },\n {\n slot: Aglyn.CONSOLE_WIDGET_SLOTS.adminOrgDetail,\n widgetId: 'workflows-staff-org-automations',\n title: 'Organization automations',\n Component: StaffOrgAutomationsCard,\n },\n ],\n pluginId: BUNDLE_ID,\n displayName: 'Automation',\n featureFlag: 'workflows',\n navItems: [\n {\n label: 'Automation',\n // Workflows, Actions and Webhooks are the tabs INSIDE this section, so\n // the section is named for what they have in common. `/workflows` —\n // the address before the section had its own name — is redirected here\n // by the console (see `Route.HOST_WORKFLOWS`).\n href: '/automation',\n // Sections as ROUTES (AGL-2501): each is a real URL the shell\n // resolves and gates, so the page mounts the one being read.\n sections: WORKFLOWS_CONSOLE_SECTIONS,\n // Reuse the existing release-flag nav-tab so staff-preview gating is\n // unchanged now that the tab comes from the plugin (AGL-395).\n navTabId: 'nav-tab-workflows',\n icon: { path: mdiSitemap.path },\n header: {\n title: 'Automation',\n icon: { path: mdiSitemap.path },\n docsTopic: 'workflows',\n },\n Component: WorkflowsConsolePage,\n },\n ],\n /*\n * The ORGANIZATION's Automation hub (AGL-3302), at `/[orgSlug]/automation`:\n * the org automations placed across the organization's sites, and every\n * site's own workflows, actions and webhooks side by side. The same page\n * component, mounted with no site; the site tab's release flag gates both\n * levels, so one flag rolls the surface out at once.\n */\n orgNavItems: [\n {\n label: 'Automation',\n href: '/automation',\n sections: WORKFLOWS_ORG_CONSOLE_SECTIONS,\n navTabId: 'nav-tab-workflows',\n icon: { path: mdiSitemap.path },\n header: {\n title: 'Automation',\n icon: { path: mdiSitemap.path },\n docsTopic: 'workflows',\n },\n Component: WorkflowsConsolePage,\n },\n ],\n })\n}\n\n// Activity feed consumed directly by the app (dashboard + screen view).\nexport { default as HostActivityCard } from './components/host-activity-card.component'\nexport type { HostActivityCardProps } from './components/host-activity-card.component'\n"],"names":["Aglyn","mdiSitemap","lazy","HostActivityCard","StaffOrgAutomationsCard","StaffSiteAutomationsCard","WORKFLOWS_CONSOLE_SECTIONS","WORKFLOWS_ORG_CONSOLE_SECTIONS","registerPluginZone","WORKFLOW_USAGE_ZONE","BUNDLE_ID","WorkflowsConsolePage","registerWorkflowsConsole","zone","label","surface","description","pluginId","registerConsoleExtension","widgets","slot","widgetId","title","Component","CONSOLE_WIDGET_SLOTS","staffSite","adminOrgDetail","displayName","featureFlag","navItems","href","sections","navTabId","icon","path","header","docsTopic","orgNavItems","default"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,YAAYA,WAAW,eAAc;AACrC,SAASC,UAAU,QAAQ,yBAAwB;AACnD,SAASC,IAAI,QAAQ,QAAO;AAC5B,SAASC,gBAAgB,QAAQ,+CAA2C;AAC5E,SACEC,uBAAuB,EACvBC,wBAAwB,QACnB,mDAA+C;AACtD,SACEC,0BAA0B,EAC1BC,8BAA8B,QACzB,6CAAyC;AAChD,SAASC,kBAAkB,QAAQ,2CAA0C;AAC7E,SAASC,mBAAmB,QAAQ,iCAA6B;AACjE,SAASC,SAAS,QAAQ,+BAA2B;AAErD,oEAAoE,GACpE,MAAMC,uBAAuBT,KAC3B,IAAM,MAAM,CAAC;AAGf;;;;;;;;;;;;;CAaC,GACD,OAAO,SAASU;IACdJ,mBACE;QACEK,MAAMJ;QACNK,OAAO;QACPC,SAAS;QACTC,aACE;IACJ,GACA,iEAAiE;IACjE;QAAEC,UAAUP;IAAU;IAExBV,MAAMkB,wBAAwB,CAAC;QAC7B,wDAAwD;QACxD,6DAA6D;QAC7DC,SAAS;YACP;gBACEC,MAAM;gBACNC,UAAU;gBACVC,OAAO;gBACPC,WAAWpB;YACb;YACA,sEAAsE;YACtE,0DAA0D;YAC1D;gBACEiB,MAAMpB,MAAMwB,oBAAoB,CAACC,SAAS;gBAC1CJ,UAAU;gBACVC,OAAO;gBACPC,WAAWlB;YACb;YACA;gBACEe,MAAMpB,MAAMwB,oBAAoB,CAACE,cAAc;gBAC/CL,UAAU;gBACVC,OAAO;gBACPC,WAAWnB;YACb;SACD;QACDa,UAAUP;QACViB,aAAa;QACbC,aAAa;QACbC,UAAU;YACR;gBACEf,OAAO;gBACP,uEAAuE;gBACvE,oEAAoE;gBACpE,uEAAuE;gBACvE,+CAA+C;gBAC/CgB,MAAM;gBACN,8DAA8D;gBAC9D,6DAA6D;gBAC7DC,UAAUzB;gBACV,qEAAqE;gBACrE,8DAA8D;gBAC9D0B,UAAU;gBACVC,MAAM;oBAAEC,MAAMjC,WAAWiC,IAAI;gBAAC;gBAC9BC,QAAQ;oBACNb,OAAO;oBACPW,MAAM;wBAAEC,MAAMjC,WAAWiC,IAAI;oBAAC;oBAC9BE,WAAW;gBACb;gBACAb,WAAWZ;YACb;SACD;QACD;;;;;;KAMC,GACD0B,aAAa;YACX;gBACEvB,OAAO;gBACPgB,MAAM;gBACNC,UAAUxB;gBACVyB,UAAU;gBACVC,MAAM;oBAAEC,MAAMjC,WAAWiC,IAAI;gBAAC;gBAC9BC,QAAQ;oBACNb,OAAO;oBACPW,MAAM;wBAAEC,MAAMjC,WAAWiC,IAAI;oBAAC;oBAC9BE,WAAW;gBACb;gBACAb,WAAWZ;YACb;SACD;IACH;AACF;AAEA,wEAAwE;AACxE,SAAS2B,WAAWnC,gBAAgB,QAAQ,+CAA2C"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/plugins/workflows/src/lib/plugin.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 * as Aglyn from '@aglyn/aglyn'\nimport { mdiSitemap } from '@aglyn/shared-data-mdi'\nimport { lazy } from 'react'\nimport { HostActivityCard } from './components/host-activity-card.component'\nimport {\n StaffOrgAutomationsCard,\n StaffSiteAutomationsCard,\n} from './components/staff-automations-card.component'\nimport {\n WORKFLOWS_CONSOLE_SECTIONS,\n WORKFLOWS_ORG_CONSOLE_SECTIONS,\n} from './components/workflows-console-sections'\nimport { registerPluginZone } from '@aglyn/aglyn/plugin-manager/plugin-zones'\nimport {\n AUTOMATION_EDITOR_ZONE,\n AUTOMATION_RUN_ZONE,\n HOST_AUTOMATIONS_ZONE,\n WORKFLOW_USAGE_ZONE,\n} from './components/workflow-zones'\nimport { BUNDLE_ID } from './constants/bundle-common'\nimport { registerWorkflowsRecordLists } from './model/workflows-record-lists'\nimport { registerWorkflowsRecordRoutes } from './model/workflows-record-routes'\nimport { WORKFLOWS_SEARCH_SOURCES } from './model/workflows-search-sources'\n\n/** Code-split: the Automation console page only loads when opened. */\nconst WorkflowsConsolePage = lazy(\n () => import('./components/workflows-console-page'),\n)\n\n/**\n * Workflows feature plugin (AGL-395). Console-only — workflows, actions,\n * and webhooks run server-side (event pipelines, `/api/hooks`), not through\n * a canvas element, so there is no UI bundle. The console half declares the\n * Automation nav + page through the ConsoleExtension registry, gated by the\n * `workflows` entitlement (the Actions/Webhooks tabs run their own per-plan\n * checks off the passed `org`). Where a workflow is used is asked of the\n * platform's scan and drawn in a zone this plugin hosts.\n *\n * `pluginId`, `featureFlag` and `navTabId` all still read `workflows`: they\n * are stored — an org's enabled-plugin ids, the plan's entitlement flags, the\n * Remote Config release flag — and a section's name is not a reason to orphan\n * them. Only what a reader sees carries the new name.\n */\nexport function registerWorkflowsConsole(): void {\n registerWorkflowsRecordRoutes()\n registerWorkflowsRecordLists()\n registerPluginZone(\n {\n zone: WORKFLOW_USAGE_ZONE,\n label: 'Where a workflow is used',\n surface: 'console',\n description:\n 'On the Automation page, after a reader asks where a workflow is used. A widget here lays out the scan the page already ran; it is handed the site, the answer and a way to close, and it writes nothing.',\n },\n // Named, because a spec calls this registrar without the loader.\n { pluginId: BUNDLE_ID },\n )\n // The zones the Automation page draws in its own layouts (AGL-2919): one\n // item in the Actions row, inside an open editor, on a failed run's row.\n registerPluginZone(\n {\n zone: HOST_AUTOMATIONS_ZONE,\n label: 'Automation page actions',\n surface: 'console',\n layout: 'bare',\n description:\n 'On the Automation page, beside Add action and Recipes: another way to start an automation. `openAction` opens a listed action in the Actions editor; a widget here writes nothing through the page.',\n },\n { pluginId: BUNDLE_ID },\n )\n registerPluginZone(\n {\n zone: AUTOMATION_EDITOR_ZONE,\n label: 'An automation’s editor',\n surface: 'console',\n layout: 'bare',\n description:\n 'Inside the editor of one saved automation, an action or a workflow. A widget here reads the automation as it is stored and changes nothing in the editor.',\n },\n { pluginId: BUNDLE_ID },\n )\n registerPluginZone(\n {\n zone: AUTOMATION_RUN_ZONE,\n label: 'A failed automation run',\n surface: 'console',\n layout: 'bare',\n description:\n 'On each failed run in an automation’s run history. A widget here reads the run as it was recorded and changes nothing.',\n },\n { pluginId: BUNDLE_ID },\n )\n Aglyn.registerConsoleExtension({\n // Host activity feed (AGL-419): rendered by the shell's\n // 'hostActivity' widget slot (dashboard + editor view page).\n widgets: [\n {\n slot: 'hostActivity',\n widgetId: 'workflows-host-activity',\n title: 'Recent Activity',\n Component: HostActivityCard,\n },\n // The staff site and organization pages' automations (AGL-3379), read\n // only: staff see what runs on a site without joining it.\n {\n slot: Aglyn.CONSOLE_WIDGET_SLOTS.staffSite,\n widgetId: 'workflows-staff-site-automations',\n title: 'Automations',\n Component: StaffSiteAutomationsCard,\n },\n {\n slot: Aglyn.CONSOLE_WIDGET_SLOTS.adminOrgDetail,\n widgetId: 'workflows-staff-org-automations',\n title: 'Organization automations',\n Component: StaffOrgAutomationsCard,\n },\n ],\n pluginId: BUNDLE_ID,\n displayName: 'Automation',\n featureFlag: 'workflows',\n searchSources: WORKFLOWS_SEARCH_SOURCES,\n navItems: [\n {\n label: 'Automation',\n // Workflows, Actions and Webhooks are the tabs INSIDE this section, so\n // the section is named for what they have in common. `/workflows` —\n // the address before the section had its own name — is redirected here\n // by this plugin's `consoleRedirects`.\n href: '/automation',\n // Sections as ROUTES (AGL-2501): each is a real URL the shell\n // resolves and gates, so the page mounts the one being read.\n sections: WORKFLOWS_CONSOLE_SECTIONS,\n // Reuse the existing release-flag nav-tab so staff-preview gating is\n // unchanged now that the tab comes from the plugin (AGL-395).\n navTabId: 'nav-tab-workflows',\n icon: { path: mdiSitemap.path },\n header: {\n title: 'Automation',\n icon: { path: mdiSitemap.path },\n docsTopic: 'workflows',\n },\n Component: WorkflowsConsolePage,\n },\n ],\n /*\n * The ORGANIZATION's Automation hub (AGL-3302), at `/[orgSlug]/automation`:\n * the org automations placed across the organization's sites, and every\n * site's own workflows, actions and webhooks side by side. The same page\n * component, mounted with no site; the site tab's release flag gates both\n * levels, so one flag rolls the surface out at once.\n */\n orgNavItems: [\n {\n label: 'Automation',\n href: '/automation',\n sections: WORKFLOWS_ORG_CONSOLE_SECTIONS,\n navTabId: 'nav-tab-workflows',\n icon: { path: mdiSitemap.path },\n header: {\n title: 'Automation',\n icon: { path: mdiSitemap.path },\n docsTopic: 'workflows',\n },\n Component: WorkflowsConsolePage,\n },\n ],\n })\n}\n\n// Activity feed consumed directly by the app (dashboard + screen view).\nexport { default as HostActivityCard } from './components/host-activity-card.component'\nexport type { HostActivityCardProps } from './components/host-activity-card.component'\n"],"names":["Aglyn","mdiSitemap","lazy","HostActivityCard","StaffOrgAutomationsCard","StaffSiteAutomationsCard","WORKFLOWS_CONSOLE_SECTIONS","WORKFLOWS_ORG_CONSOLE_SECTIONS","registerPluginZone","AUTOMATION_EDITOR_ZONE","AUTOMATION_RUN_ZONE","HOST_AUTOMATIONS_ZONE","WORKFLOW_USAGE_ZONE","BUNDLE_ID","registerWorkflowsRecordLists","registerWorkflowsRecordRoutes","WORKFLOWS_SEARCH_SOURCES","WorkflowsConsolePage","registerWorkflowsConsole","zone","label","surface","description","pluginId","layout","registerConsoleExtension","widgets","slot","widgetId","title","Component","CONSOLE_WIDGET_SLOTS","staffSite","adminOrgDetail","displayName","featureFlag","searchSources","navItems","href","sections","navTabId","icon","path","header","docsTopic","orgNavItems","default"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,YAAYA,WAAW,eAAc;AACrC,SAASC,UAAU,QAAQ,yBAAwB;AACnD,SAASC,IAAI,QAAQ,QAAO;AAC5B,SAASC,gBAAgB,QAAQ,+CAA2C;AAC5E,SACEC,uBAAuB,EACvBC,wBAAwB,QACnB,mDAA+C;AACtD,SACEC,0BAA0B,EAC1BC,8BAA8B,QACzB,6CAAyC;AAChD,SAASC,kBAAkB,QAAQ,2CAA0C;AAC7E,SACEC,sBAAsB,EACtBC,mBAAmB,EACnBC,qBAAqB,EACrBC,mBAAmB,QACd,iCAA6B;AACpC,SAASC,SAAS,QAAQ,+BAA2B;AACrD,SAASC,4BAA4B,QAAQ,oCAAgC;AAC7E,SAASC,6BAA6B,QAAQ,qCAAiC;AAC/E,SAASC,wBAAwB,QAAQ,sCAAkC;AAE3E,oEAAoE,GACpE,MAAMC,uBAAuBf,KAC3B,IAAM,MAAM,CAAC;AAGf;;;;;;;;;;;;;CAaC,GACD,OAAO,SAASgB;IACdH;IACAD;IACAN,mBACE;QACEW,MAAMP;QACNQ,OAAO;QACPC,SAAS;QACTC,aACE;IACJ,GACA,iEAAiE;IACjE;QAAEC,UAAUV;IAAU;IAExB,yEAAyE;IACzE,yEAAyE;IACzEL,mBACE;QACEW,MAAMR;QACNS,OAAO;QACPC,SAAS;QACTG,QAAQ;QACRF,aACE;IACJ,GACA;QAAEC,UAAUV;IAAU;IAExBL,mBACE;QACEW,MAAMV;QACNW,OAAO;QACPC,SAAS;QACTG,QAAQ;QACRF,aACE;IACJ,GACA;QAAEC,UAAUV;IAAU;IAExBL,mBACE;QACEW,MAAMT;QACNU,OAAO;QACPC,SAAS;QACTG,QAAQ;QACRF,aACE;IACJ,GACA;QAAEC,UAAUV;IAAU;IAExBb,MAAMyB,wBAAwB,CAAC;QAC7B,wDAAwD;QACxD,6DAA6D;QAC7DC,SAAS;YACP;gBACEC,MAAM;gBACNC,UAAU;gBACVC,OAAO;gBACPC,WAAW3B;YACb;YACA,sEAAsE;YACtE,0DAA0D;YAC1D;gBACEwB,MAAM3B,MAAM+B,oBAAoB,CAACC,SAAS;gBAC1CJ,UAAU;gBACVC,OAAO;gBACPC,WAAWzB;YACb;YACA;gBACEsB,MAAM3B,MAAM+B,oBAAoB,CAACE,cAAc;gBAC/CL,UAAU;gBACVC,OAAO;gBACPC,WAAW1B;YACb;SACD;QACDmB,UAAUV;QACVqB,aAAa;QACbC,aAAa;QACbC,eAAepB;QACfqB,UAAU;YACR;gBACEjB,OAAO;gBACP,uEAAuE;gBACvE,oEAAoE;gBACpE,uEAAuE;gBACvE,uCAAuC;gBACvCkB,MAAM;gBACN,8DAA8D;gBAC9D,6DAA6D;gBAC7DC,UAAUjC;gBACV,qEAAqE;gBACrE,8DAA8D;gBAC9DkC,UAAU;gBACVC,MAAM;oBAAEC,MAAMzC,WAAWyC,IAAI;gBAAC;gBAC9BC,QAAQ;oBACNd,OAAO;oBACPY,MAAM;wBAAEC,MAAMzC,WAAWyC,IAAI;oBAAC;oBAC9BE,WAAW;gBACb;gBACAd,WAAWb;YACb;SACD;QACD;;;;;;KAMC,GACD4B,aAAa;YACX;gBACEzB,OAAO;gBACPkB,MAAM;gBACNC,UAAUhC;gBACViC,UAAU;gBACVC,MAAM;oBAAEC,MAAMzC,WAAWyC,IAAI;gBAAC;gBAC9BC,QAAQ;oBACNd,OAAO;oBACPY,MAAM;wBAAEC,MAAMzC,WAAWyC,IAAI;oBAAC;oBAC9BE,WAAW;gBACb;gBACAd,WAAWb;YACb;SACD;IACH;AACF;AAEA,wEAAwE;AACxE,SAAS6B,WAAW3C,gBAAgB,QAAQ,+CAA2C"}
|
|
@@ -0,0 +1,20 @@
|
|
|
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 { PluginRecordIndex } from '@aglyn/aglyn/plugin-manager/plugin-record-index';
|
|
18
|
+
export declare const workflowRecordIndex: PluginRecordIndex;
|
|
19
|
+
export declare const webhookRecordIndex: PluginRecordIndex;
|
|
20
|
+
export declare const actionRecordIndex: PluginRecordIndex;
|
|
@@ -0,0 +1,59 @@
|
|
|
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
|
+
*/ import { firebaseAdmin } from "@aglyn/tenant-data-admin/server/firebase-admin";
|
|
17
|
+
import { AUTOMATION_COLLECTIONS, automationIndexedRecord } from "../model/automation-record.js";
|
|
18
|
+
/**
|
|
19
|
+
* The workflows plugin's record indexes (AGL-3080): a site's workflows,
|
|
20
|
+
* webhooks and actions, as another surface reads them — an AI job drafting an
|
|
21
|
+
* automation that names a workflow, the "Used by" scan asking which workflows
|
|
22
|
+
* call a function — without knowing where they are stored or what a deleted
|
|
23
|
+
* one looks like.
|
|
24
|
+
*
|
|
25
|
+
* All three are a SITE's (`hostId` required; an org-only scope answers
|
|
26
|
+
* nothing). Each record is `automationIndexedRecord`'s
|
|
27
|
+
* (`model/automation-record.ts`), which leaves out a deleted record and
|
|
28
|
+
* documents the facts each kind shares.
|
|
29
|
+
*/ function hostCollection(hostId, kind) {
|
|
30
|
+
return firebaseAdmin.app().firestore().collection('hosts').doc(hostId).collection(AUTOMATION_COLLECTIONS[kind]);
|
|
31
|
+
}
|
|
32
|
+
function indexOf(kind) {
|
|
33
|
+
return {
|
|
34
|
+
async list ({ hostId, limit }) {
|
|
35
|
+
if (!hostId || limit <= 0) return {
|
|
36
|
+
records: [],
|
|
37
|
+
truncated: false
|
|
38
|
+
};
|
|
39
|
+
// One more than asked, so `truncated` is a fact rather than a guess;
|
|
40
|
+
// deleted and unnamed records are filtered after the read.
|
|
41
|
+
const snapshot = await hostCollection(hostId, kind).limit(limit + 1).get();
|
|
42
|
+
const records = snapshot.docs.map((doc)=>automationIndexedRecord(kind, doc.id, doc.data())).filter((record)=>record !== null);
|
|
43
|
+
return {
|
|
44
|
+
records: records.slice(0, limit),
|
|
45
|
+
truncated: snapshot.size > limit
|
|
46
|
+
};
|
|
47
|
+
},
|
|
48
|
+
async get ({ hostId, id }) {
|
|
49
|
+
if (!hostId || !id) return null;
|
|
50
|
+
const snapshot = await hostCollection(hostId, kind).doc(id).get();
|
|
51
|
+
return snapshot.exists ? automationIndexedRecord(kind, snapshot.id, snapshot.data()) : null;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
export const workflowRecordIndex = indexOf('workflow');
|
|
56
|
+
export const webhookRecordIndex = indexOf('webhook');
|
|
57
|
+
export const actionRecordIndex = indexOf('action');
|
|
58
|
+
|
|
59
|
+
//# sourceMappingURL=automation-record-index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/server/automation-record-index.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 type {\n PluginIndexedRecord,\n PluginRecordIndex,\n} from '@aglyn/aglyn/plugin-manager/plugin-record-index'\nimport { firebaseAdmin } from '@aglyn/tenant-data-admin/server/firebase-admin'\nimport {\n AUTOMATION_COLLECTIONS,\n automationIndexedRecord,\n type AutomationRecordKind,\n} from '../model/automation-record'\n\n/**\n * The workflows plugin's record indexes (AGL-3080): a site's workflows,\n * webhooks and actions, as another surface reads them — an AI job drafting an\n * automation that names a workflow, the \"Used by\" scan asking which workflows\n * call a function — without knowing where they are stored or what a deleted\n * one looks like.\n *\n * All three are a SITE's (`hostId` required; an org-only scope answers\n * nothing). Each record is `automationIndexedRecord`'s\n * (`model/automation-record.ts`), which leaves out a deleted record and\n * documents the facts each kind shares.\n */\n\nfunction hostCollection(hostId: string, kind: AutomationRecordKind) {\n return firebaseAdmin\n .app()\n .firestore()\n .collection('hosts')\n .doc(hostId)\n .collection(AUTOMATION_COLLECTIONS[kind])\n}\n\nfunction indexOf(kind: AutomationRecordKind): PluginRecordIndex {\n return {\n async list({ hostId, limit }) {\n if (!hostId || limit <= 0) return { records: [], truncated: false }\n // One more than asked, so `truncated` is a fact rather than a guess;\n // deleted and unnamed records are filtered after the read.\n const snapshot = await hostCollection(hostId, kind).limit(limit + 1).get()\n const records = snapshot.docs\n .map((doc) => automationIndexedRecord(kind, doc.id, doc.data()))\n .filter((record): record is PluginIndexedRecord => record !== null)\n return { records: records.slice(0, limit), truncated: snapshot.size > limit }\n },\n async get({ hostId, id }) {\n if (!hostId || !id) return null\n const snapshot = await hostCollection(hostId, kind).doc(id).get()\n return snapshot.exists ? automationIndexedRecord(kind, snapshot.id, snapshot.data()) : null\n },\n }\n}\n\nexport const workflowRecordIndex = indexOf('workflow')\nexport const webhookRecordIndex = indexOf('webhook')\nexport const actionRecordIndex = indexOf('action')\n"],"names":["firebaseAdmin","AUTOMATION_COLLECTIONS","automationIndexedRecord","hostCollection","hostId","kind","app","firestore","collection","doc","indexOf","list","limit","records","truncated","snapshot","get","docs","map","id","data","filter","record","slice","size","exists","workflowRecordIndex","webhookRecordIndex","actionRecordIndex"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAMD,SAASA,aAAa,QAAQ,iDAAgD;AAC9E,SACEC,sBAAsB,EACtBC,uBAAuB,QAElB,gCAA4B;AAEnC;;;;;;;;;;;CAWC,GAED,SAASC,eAAeC,MAAc,EAAEC,IAA0B;IAChE,OAAOL,cACJM,GAAG,GACHC,SAAS,GACTC,UAAU,CAAC,SACXC,GAAG,CAACL,QACJI,UAAU,CAACP,sBAAsB,CAACI,KAAK;AAC5C;AAEA,SAASK,QAAQL,IAA0B;IACzC,OAAO;QACL,MAAMM,MAAK,EAAEP,MAAM,EAAEQ,KAAK,EAAE;YAC1B,IAAI,CAACR,UAAUQ,SAAS,GAAG,OAAO;gBAAEC,SAAS,EAAE;gBAAEC,WAAW;YAAM;YAClE,qEAAqE;YACrE,2DAA2D;YAC3D,MAAMC,WAAW,MAAMZ,eAAeC,QAAQC,MAAMO,KAAK,CAACA,QAAQ,GAAGI,GAAG;YACxE,MAAMH,UAAUE,SAASE,IAAI,CAC1BC,GAAG,CAAC,CAACT,MAAQP,wBAAwBG,MAAMI,IAAIU,EAAE,EAAEV,IAAIW,IAAI,KAC3DC,MAAM,CAAC,CAACC,SAA0CA,WAAW;YAChE,OAAO;gBAAET,SAASA,QAAQU,KAAK,CAAC,GAAGX;gBAAQE,WAAWC,SAASS,IAAI,GAAGZ;YAAM;QAC9E;QACA,MAAMI,KAAI,EAAEZ,MAAM,EAAEe,EAAE,EAAE;YACtB,IAAI,CAACf,UAAU,CAACe,IAAI,OAAO;YAC3B,MAAMJ,WAAW,MAAMZ,eAAeC,QAAQC,MAAMI,GAAG,CAACU,IAAIH,GAAG;YAC/D,OAAOD,SAASU,MAAM,GAAGvB,wBAAwBG,MAAMU,SAASI,EAAE,EAAEJ,SAASK,IAAI,MAAM;QACzF;IACF;AACF;AAEA,OAAO,MAAMM,sBAAsBhB,QAAQ,YAAW;AACtD,OAAO,MAAMiB,qBAAqBjB,QAAQ,WAAU;AACpD,OAAO,MAAMkB,oBAAoBlB,QAAQ,UAAS"}
|
|
@@ -0,0 +1,28 @@
|
|
|
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 { PluginDependentsAnswer, PluginDependentsRequest } from '@aglyn/aglyn/plugin-manager/plugin-dependents';
|
|
18
|
+
/**
|
|
19
|
+
* Which of a site's workflows call a function, for the "Used by" scan.
|
|
20
|
+
*
|
|
21
|
+
* A workflow step calls a site function by its document id, with the name it
|
|
22
|
+
* had when the step was written beside it as a display hint (AGL-261); a step
|
|
23
|
+
* written before ids existed carries the name alone. Either reference is a
|
|
24
|
+
* dependent: the id survives a rename of the function, the name does not.
|
|
25
|
+
*/
|
|
26
|
+
/** How many of a site's workflows one scan reads. */
|
|
27
|
+
export declare const FUNCTION_DEPENDENTS_WORKFLOWS_READ = 100;
|
|
28
|
+
export declare function findFunctionDependents(request: PluginDependentsRequest): Promise<PluginDependentsAnswer>;
|
|
@@ -0,0 +1,61 @@
|
|
|
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
|
+
*/ import { workflowRecordIndex } from "./automation-record-index.js";
|
|
17
|
+
/**
|
|
18
|
+
* Which of a site's workflows call a function, for the "Used by" scan.
|
|
19
|
+
*
|
|
20
|
+
* A workflow step calls a site function by its document id, with the name it
|
|
21
|
+
* had when the step was written beside it as a display hint (AGL-261); a step
|
|
22
|
+
* written before ids existed carries the name alone. Either reference is a
|
|
23
|
+
* dependent: the id survives a rename of the function, the name does not.
|
|
24
|
+
*/ /** How many of a site's workflows one scan reads. */ export const FUNCTION_DEPENDENTS_WORKFLOWS_READ = 100;
|
|
25
|
+
const text = (value)=>typeof value === 'string' ? value.trim() : '';
|
|
26
|
+
export async function findFunctionDependents(request) {
|
|
27
|
+
const id = request.id.trim();
|
|
28
|
+
const name = text(request.name);
|
|
29
|
+
const { records, truncated } = await workflowRecordIndex.list({
|
|
30
|
+
hostId: request.hostId,
|
|
31
|
+
limit: FUNCTION_DEPENDENTS_WORKFLOWS_READ
|
|
32
|
+
});
|
|
33
|
+
const dependents = [];
|
|
34
|
+
for (const record of records){
|
|
35
|
+
const steps = Array.isArray(record.facts['steps']) ? record.facts['steps'] : [];
|
|
36
|
+
const via = new Set();
|
|
37
|
+
for (const step of steps){
|
|
38
|
+
if (!step || typeof step !== 'object') continue;
|
|
39
|
+
const { functionId, functionName } = step;
|
|
40
|
+
if (id && text(functionId) === id) via.add('id');
|
|
41
|
+
if (name && text(functionName) === name) via.add('name');
|
|
42
|
+
}
|
|
43
|
+
if (via.size) {
|
|
44
|
+
dependents.push({
|
|
45
|
+
type: 'workflow',
|
|
46
|
+
id: record.id,
|
|
47
|
+
name: record.name,
|
|
48
|
+
via: [
|
|
49
|
+
'id',
|
|
50
|
+
'name'
|
|
51
|
+
].filter((one)=>via.has(one))
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
dependents,
|
|
57
|
+
truncated
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
//# sourceMappingURL=workflow-dependents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/server/workflow-dependents.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 type { BindingRefVia } from '@aglyn/aglyn/app-utils/binding-tokens'\nimport type {\n PluginDependent,\n PluginDependentsAnswer,\n PluginDependentsRequest,\n} from '@aglyn/aglyn/plugin-manager/plugin-dependents'\nimport { workflowRecordIndex } from './automation-record-index'\n\n/**\n * Which of a site's workflows call a function, for the \"Used by\" scan.\n *\n * A workflow step calls a site function by its document id, with the name it\n * had when the step was written beside it as a display hint (AGL-261); a step\n * written before ids existed carries the name alone. Either reference is a\n * dependent: the id survives a rename of the function, the name does not.\n */\n\n/** How many of a site's workflows one scan reads. */\nexport const FUNCTION_DEPENDENTS_WORKFLOWS_READ = 100\n\nconst text = (value: unknown): string => (typeof value === 'string' ? value.trim() : '')\n\nexport async function findFunctionDependents(\n request: PluginDependentsRequest,\n): Promise<PluginDependentsAnswer> {\n const id = request.id.trim()\n const name = text(request.name)\n const { records, truncated } = await workflowRecordIndex.list({\n hostId: request.hostId,\n limit: FUNCTION_DEPENDENTS_WORKFLOWS_READ,\n })\n const dependents: PluginDependent[] = []\n for (const record of records) {\n const steps = Array.isArray(record.facts['steps']) ? (record.facts['steps'] as unknown[]) : []\n const via = new Set<BindingRefVia>()\n for (const step of steps) {\n if (!step || typeof step !== 'object') continue\n const { functionId, functionName } = step as Record<string, unknown>\n if (id && text(functionId) === id) via.add('id')\n if (name && text(functionName) === name) via.add('name')\n }\n if (via.size) {\n dependents.push({\n type: 'workflow',\n id: record.id,\n name: record.name,\n via: (['id', 'name'] as const).filter((one) => via.has(one)),\n })\n }\n }\n return { dependents, truncated }\n}\n"],"names":["workflowRecordIndex","FUNCTION_DEPENDENTS_WORKFLOWS_READ","text","value","trim","findFunctionDependents","request","id","name","records","truncated","list","hostId","limit","dependents","record","steps","Array","isArray","facts","via","Set","step","functionId","functionName","add","size","push","type","filter","one","has"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAQD,SAASA,mBAAmB,QAAQ,+BAA2B;AAE/D;;;;;;;CAOC,GAED,mDAAmD,GACnD,OAAO,MAAMC,qCAAqC,IAAG;AAErD,MAAMC,OAAO,CAACC,QAA4B,OAAOA,UAAU,WAAWA,MAAMC,IAAI,KAAK;AAErF,OAAO,eAAeC,uBACpBC,OAAgC;IAEhC,MAAMC,KAAKD,QAAQC,EAAE,CAACH,IAAI;IAC1B,MAAMI,OAAON,KAAKI,QAAQE,IAAI;IAC9B,MAAM,EAAEC,OAAO,EAAEC,SAAS,EAAE,GAAG,MAAMV,oBAAoBW,IAAI,CAAC;QAC5DC,QAAQN,QAAQM,MAAM;QACtBC,OAAOZ;IACT;IACA,MAAMa,aAAgC,EAAE;IACxC,KAAK,MAAMC,UAAUN,QAAS;QAC5B,MAAMO,QAAQC,MAAMC,OAAO,CAACH,OAAOI,KAAK,CAAC,QAAQ,IAAKJ,OAAOI,KAAK,CAAC,QAAQ,GAAiB,EAAE;QAC9F,MAAMC,MAAM,IAAIC;QAChB,KAAK,MAAMC,QAAQN,MAAO;YACxB,IAAI,CAACM,QAAQ,OAAOA,SAAS,UAAU;YACvC,MAAM,EAAEC,UAAU,EAAEC,YAAY,EAAE,GAAGF;YACrC,IAAIf,MAAML,KAAKqB,gBAAgBhB,IAAIa,IAAIK,GAAG,CAAC;YAC3C,IAAIjB,QAAQN,KAAKsB,kBAAkBhB,MAAMY,IAAIK,GAAG,CAAC;QACnD;QACA,IAAIL,IAAIM,IAAI,EAAE;YACZZ,WAAWa,IAAI,CAAC;gBACdC,MAAM;gBACNrB,IAAIQ,OAAOR,EAAE;gBACbC,MAAMO,OAAOP,IAAI;gBACjBY,KAAK,AAAC;oBAAC;oBAAM;iBAAO,CAAWS,MAAM,CAAC,CAACC,MAAQV,IAAIW,GAAG,CAACD;YACzD;QACF;IACF;IACA,OAAO;QAAEhB;QAAYJ;IAAU;AACjC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
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 { VariableComputation } from '@aglyn/aglyn/plugin-manager/computed-variables';
|
|
18
|
+
/** How many of a site's workflows a page reads to compute its variables. */
|
|
19
|
+
export declare const COMPUTED_VARIABLE_WORKFLOWS_READ = 100;
|
|
20
|
+
export declare function prepareWorkflowVariables(hostId: string): Promise<VariableComputation>;
|