@aglyn/plugins-workflows 1.0.0-beta.218 → 1.0.0-beta.219
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 +28 -4
- package/package.json +12 -12
- package/src/index.d.ts +1 -0
- package/src/index.js.map +1 -1
- package/src/lib/components/host-run-history-card.component.js +1 -1
- package/src/lib/components/host-run-history-card.component.js.map +1 -1
- package/src/lib/components/host-workflows-card.component.js +2 -1
- package/src/lib/components/host-workflows-card.component.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/run-event-actions.d.ts +2 -1
- package/src/lib/engine/run-event-actions.js +49 -15
- 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/org-automations.js.map +1 -1
- 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 +90 -0
- package/src/lib/model/workflows.js +166 -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 +5 -1
- 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 +90 -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/usage-axes.d.ts +28 -0
- package/src/lib/usage-axes.js +61 -0
- package/src/lib/usage-axes.js.map +1 -0
|
@@ -0,0 +1,90 @@
|
|
|
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 HostFunction } from '@aglyn/aglyn/app-utils/functions';
|
|
18
|
+
import type { HostEventType } from '@aglyn/aglyn/app-utils/host-events';
|
|
19
|
+
import type { HostVariable } from '@aglyn/aglyn/app-utils/variables';
|
|
20
|
+
/**
|
|
21
|
+
* Workflows (Workflow Builder, AGL-101): named pipelines of host-function
|
|
22
|
+
* calls. Each step evaluates its argument expressions over host variables
|
|
23
|
+
* and previous step results, runs the function through the safe evaluator,
|
|
24
|
+
* and stores the result under its name for later steps. Pure and bounded —
|
|
25
|
+
* no I/O, no loops. Site-event triggers arrive in v2.
|
|
26
|
+
*/
|
|
27
|
+
export interface HostWorkflowTrigger {
|
|
28
|
+
event: HostEventType;
|
|
29
|
+
/**
|
|
30
|
+
* Optional expression over the event payload (plus variables); the
|
|
31
|
+
* workflow only runs when it evaluates truthy (e.g. `path == "/pricing"`).
|
|
32
|
+
*/
|
|
33
|
+
filter?: string;
|
|
34
|
+
}
|
|
35
|
+
export interface HostWorkflowStep {
|
|
36
|
+
/**
|
|
37
|
+
* Host function to run — by doc id (AGL-261), rename-safe. Steps saved
|
|
38
|
+
* before AGL-261 carry only `functionName`; executors resolve id first.
|
|
39
|
+
*/
|
|
40
|
+
functionId?: string;
|
|
41
|
+
/** Legacy name reference, kept as the display hint; `functionId` wins. */
|
|
42
|
+
functionName: string;
|
|
43
|
+
/**
|
|
44
|
+
* One expression per function parameter, evaluated over variables and
|
|
45
|
+
* previous step results (e.g. `price * qty`, `step1 + 10`).
|
|
46
|
+
*/
|
|
47
|
+
args: string[];
|
|
48
|
+
/** Scope name the step's result binds to; defaults to `step<N>`. */
|
|
49
|
+
resultName?: string;
|
|
50
|
+
}
|
|
51
|
+
/** `hosts/{hostId}/workflows/{id}` doc. */
|
|
52
|
+
export interface HostWorkflow {
|
|
53
|
+
name: string;
|
|
54
|
+
steps: HostWorkflowStep[];
|
|
55
|
+
/** Scope name whose final value the workflow returns. */
|
|
56
|
+
returnValue?: string;
|
|
57
|
+
/** Event trigger (AGL-128); absent means manual/embedded use only. */
|
|
58
|
+
trigger?: HostWorkflowTrigger | null;
|
|
59
|
+
}
|
|
60
|
+
export declare const WORKFLOW_MAX_STEPS = 25;
|
|
61
|
+
/** Max nesting across workflow→function→workflow cross-calls (AGL-129). */
|
|
62
|
+
export declare const CROSS_MAX_DEPTH = 3;
|
|
63
|
+
export type WorkflowRunResult = {
|
|
64
|
+
ok: true;
|
|
65
|
+
value: number | string | boolean;
|
|
66
|
+
results: Record<string, number | string | boolean>;
|
|
67
|
+
} | {
|
|
68
|
+
ok: false;
|
|
69
|
+
error: string;
|
|
70
|
+
step?: number;
|
|
71
|
+
};
|
|
72
|
+
export interface WorkflowRunContext {
|
|
73
|
+
/** All host workflows by name, enabling function→workflow calls. */
|
|
74
|
+
workflows?: Record<string, HostWorkflow>;
|
|
75
|
+
/** Cross-call nesting depth; internal — callers omit it. */
|
|
76
|
+
depth?: number;
|
|
77
|
+
}
|
|
78
|
+
export declare function runWorkflow(workflow: HostWorkflow, functions: Record<string, HostFunction>, variables?: Record<string, HostVariable>,
|
|
79
|
+
/**
|
|
80
|
+
* Extra scope entries seeded ahead of the steps — event payloads (path,
|
|
81
|
+
* formName, field values) land here (AGL-128). Wins over variables.
|
|
82
|
+
*/
|
|
83
|
+
extraScope?: Record<string, number | string | boolean>, context?: WorkflowRunContext): WorkflowRunResult;
|
|
84
|
+
/**
|
|
85
|
+
* Computed variables (AGL-129): a variable with `workflowName` takes the
|
|
86
|
+
* named workflow's result as its value at compose time; failures keep the
|
|
87
|
+
* stored fallback value. Each computed variable evaluates once, bounded
|
|
88
|
+
* by the shared depth guard.
|
|
89
|
+
*/
|
|
90
|
+
export declare function resolveComputedVariables(variables: Record<string, HostVariable>, functions: Record<string, HostFunction>, workflows: Record<string, HostWorkflow>): Record<string, HostVariable>;
|
|
@@ -0,0 +1,166 @@
|
|
|
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
|
+
/** Variable values as a typed expression scope (mirrors resolveBindings). */ function variableScope(variables) {
|
|
21
|
+
const scope = {};
|
|
22
|
+
for (const [key, variable] of Object.entries(variables)){
|
|
23
|
+
var _variable_value, _variable_value1;
|
|
24
|
+
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 : '';
|
|
25
|
+
scope[key] = value;
|
|
26
|
+
// Under its NAME as well (AGL-3202). Callers key this map by name, by
|
|
27
|
+
// id, or by both; an expression only ever says the name, so a map keyed
|
|
28
|
+
// by id alone used to give it nothing to find.
|
|
29
|
+
if (variable.name && !Object.prototype.hasOwnProperty.call(scope, variable.name)) {
|
|
30
|
+
scope[variable.name] = value;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return scope;
|
|
34
|
+
}
|
|
35
|
+
export function runWorkflow(workflow, functions, variables = {}, /**
|
|
36
|
+
* Extra scope entries seeded ahead of the steps — event payloads (path,
|
|
37
|
+
* formName, field values) land here (AGL-128). Wins over variables.
|
|
38
|
+
*/ extraScope = {}, context = {}) {
|
|
39
|
+
var _workflow_steps, _context_depth, _Object_values_at;
|
|
40
|
+
var _workflow_returnValue;
|
|
41
|
+
const steps = (_workflow_steps = workflow.steps) != null ? _workflow_steps : [];
|
|
42
|
+
if (steps.length > WORKFLOW_MAX_STEPS) {
|
|
43
|
+
return {
|
|
44
|
+
ok: false,
|
|
45
|
+
error: `Workflows are capped at ${WORKFLOW_MAX_STEPS} steps`
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
const depth = (_context_depth = context.depth) != null ? _context_depth : 0;
|
|
49
|
+
if (depth > CROSS_MAX_DEPTH) {
|
|
50
|
+
return {
|
|
51
|
+
ok: false,
|
|
52
|
+
error: 'Workflow nesting is too deep'
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
// Function steps may call other workflows (AGL-129); every hop shares
|
|
56
|
+
// this depth guard so mutual recursion terminates.
|
|
57
|
+
const invokeWorkflow = (name, callScope)=>{
|
|
58
|
+
var _context_workflows;
|
|
59
|
+
const nested = (_context_workflows = context.workflows) == null ? void 0 : _context_workflows[name == null ? void 0 : name.trim()];
|
|
60
|
+
if (!nested) throw new Error(`Unknown workflow "${name}"`);
|
|
61
|
+
const run = runWorkflow(nested, functions, variables, callScope, _extends({}, context, {
|
|
62
|
+
depth: depth + 1
|
|
63
|
+
}));
|
|
64
|
+
if (run.ok === false) throw new Error(run.error);
|
|
65
|
+
return run.value;
|
|
66
|
+
};
|
|
67
|
+
// The site's variables, apart from the step results layered over them:
|
|
68
|
+
// they are what a function may read by name (AGL-3202), wherever it runs.
|
|
69
|
+
const siteVariables = variableScope(variables);
|
|
70
|
+
const scope = _extends({}, siteVariables, extraScope);
|
|
71
|
+
const results = {};
|
|
72
|
+
for (const [index, step] of steps.entries()){
|
|
73
|
+
var _functions_, _ref, _ref1;
|
|
74
|
+
var _step_functionId, _step_functionName, _step_resultName;
|
|
75
|
+
// Id-first resolution (AGL-261): maps are double-keyed by id and name.
|
|
76
|
+
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 : ''];
|
|
77
|
+
if (!definition) {
|
|
78
|
+
return {
|
|
79
|
+
ok: false,
|
|
80
|
+
error: `Unknown function "${step.functionName || step.functionId}"`,
|
|
81
|
+
step: index + 1
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
const args = {};
|
|
85
|
+
try {
|
|
86
|
+
var _definition_parameters;
|
|
87
|
+
(_definition_parameters = definition.parameters) == null ? void 0 : _definition_parameters.forEach((parameter, parameterIndex)=>{
|
|
88
|
+
var _step_args;
|
|
89
|
+
const expression = (_step_args = step.args) == null ? void 0 : _step_args[parameterIndex];
|
|
90
|
+
if (expression != null && String(expression).trim() !== '') {
|
|
91
|
+
args[parameter.name] = evaluateExpression(String(expression), scope);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
} catch (error) {
|
|
95
|
+
return {
|
|
96
|
+
ok: false,
|
|
97
|
+
error: `Step ${index + 1}: ${error.message}`,
|
|
98
|
+
step: index + 1
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
const run = evaluateHostFunction(definition, args, _extends({}, context.workflows ? {
|
|
102
|
+
invokeWorkflow
|
|
103
|
+
} : {}, {
|
|
104
|
+
// A function that prices from `extra_site_price` on a page must not
|
|
105
|
+
// fail with "Unknown name" the day a workflow calls it.
|
|
106
|
+
globals: siteVariables
|
|
107
|
+
}));
|
|
108
|
+
// `=== false` (not `!run.ok`): the union fails to narrow under the
|
|
109
|
+
// stricter lib build tsconfig otherwise (same quirk as publish.ts).
|
|
110
|
+
if (run.ok === false) {
|
|
111
|
+
return {
|
|
112
|
+
ok: false,
|
|
113
|
+
error: `Step ${index + 1} (${definition.name}): ${run.error}`,
|
|
114
|
+
step: index + 1
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
const resultName = ((_step_resultName = step.resultName) == null ? void 0 : _step_resultName.trim()) || `step${index + 1}`;
|
|
118
|
+
scope[resultName] = run.value;
|
|
119
|
+
results[resultName] = run.value;
|
|
120
|
+
}
|
|
121
|
+
const returnName = (_workflow_returnValue = workflow.returnValue) == null ? void 0 : _workflow_returnValue.trim();
|
|
122
|
+
const value = returnName && returnName in scope ? scope[returnName] : (_Object_values_at = Object.values(results).at(-1)) != null ? _Object_values_at : '';
|
|
123
|
+
return {
|
|
124
|
+
ok: true,
|
|
125
|
+
value,
|
|
126
|
+
results
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Computed variables (AGL-129): a variable with `workflowName` takes the
|
|
131
|
+
* named workflow's result as its value at compose time; failures keep the
|
|
132
|
+
* stored fallback value. Each computed variable evaluates once, bounded
|
|
133
|
+
* by the shared depth guard.
|
|
134
|
+
*/ export function resolveComputedVariables(variables, functions, workflows) {
|
|
135
|
+
const resolved = {};
|
|
136
|
+
// Lookup maps are double-keyed by id and name (AGL-185), so the same doc
|
|
137
|
+
// can appear under two keys — evaluate each workflow once per doc.
|
|
138
|
+
const memo = new Map();
|
|
139
|
+
for (const [name, variable] of Object.entries(variables)){
|
|
140
|
+
var _ref, _ref1;
|
|
141
|
+
var _variable_workflowId_trim, _variable_workflowId, _variable_workflowName;
|
|
142
|
+
const workflowId = (_ref = (_variable_workflowId = variable.workflowId) == null ? void 0 : (_variable_workflowId_trim = _variable_workflowId.trim) == null ? void 0 : _variable_workflowId_trim.call(_variable_workflowId)) != null ? _ref : '';
|
|
143
|
+
const workflowName = (_variable_workflowName = variable.workflowName) == null ? void 0 : _variable_workflowName.trim();
|
|
144
|
+
const workflow = (_ref1 = workflowId ? workflows[workflowId] : undefined) != null ? _ref1 : workflowName ? workflows[workflowName] : undefined;
|
|
145
|
+
if (!workflow) {
|
|
146
|
+
resolved[name] = variable;
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
const cached = memo.get(variable);
|
|
150
|
+
if (cached) {
|
|
151
|
+
resolved[name] = cached;
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
const run = runWorkflow(workflow, functions, variables, {}, {
|
|
155
|
+
workflows
|
|
156
|
+
});
|
|
157
|
+
const next = run.ok === false ? variable : _extends({}, variable, {
|
|
158
|
+
value: String(run.value)
|
|
159
|
+
});
|
|
160
|
+
memo.set(variable, next);
|
|
161
|
+
resolved[name] = next;
|
|
162
|
+
}
|
|
163
|
+
return resolved;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
//# 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\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 * Computed variables (AGL-129): a variable with `workflowName` takes the\n * named workflow's result as its value at compose time; failures keep the\n * stored fallback value. Each computed variable evaluates once, bounded\n * 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 workflowId = (variable as any).workflowId?.trim?.() ?? ''\n const workflowName = variable.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","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","workflowName","undefined","cached","get","next","set"],"mappings":";AAAA;;;;;;;;;;;;;;;CAeC,GAED,SACEA,kBAAkB,EAClBC,oBAAoB,QAEf,mCAAkC;AAgDzC,OAAO,MAAMC,qBAAqB,GAAE;AACpC,yEAAyE,GACzE,OAAO,MAAMC,kBAAkB,EAAC;AAUhC,2EAA2E,GAC3E,SAASC,cACPC,SAAuC;IAEvC,MAAMC,QAAmD,CAAC;IAC1D,KAAK,MAAM,CAACC,KAAKC,SAAS,IAAIC,OAAOC,OAAO,CAACL,WAAY;YAG1CG,iBAGJA;QALT,MAAMG,QACJH,SAASI,IAAI,KAAK,WACdC,QAAOL,kBAAAA,SAASG,KAAK,YAAdH,kBAAkB,KACzBA,SAASI,IAAI,KAAK,YAChBJ,SAASG,KAAK,KAAK,UAClBH,mBAAAA,SAASG,KAAK,YAAdH,mBAAkB;QAC3BF,KAAK,CAACC,IAAI,GAAGI;QACb,sEAAsE;QACtE,wEAAwE;QACxE,+CAA+C;QAC/C,IACEH,SAASM,IAAI,IACb,CAACL,OAAOM,SAAS,CAACC,cAAc,CAACC,IAAI,CAACX,OAAOE,SAASM,IAAI,GAC1D;YACAR,KAAK,CAACE,SAASM,IAAI,CAAC,GAAGH;QACzB;IACF;IACA,OAAOL;AACT;AASA,OAAO,SAASY,YACdC,QAAsB,EACtBC,SAAuC,EACvCf,YAA0C,CAAC,CAAC,EAC5C;;;GAGC,GACDgB,aAAwD,CAAC,CAAC,EAC1DC,UAA8B,CAAC,CAAC;QAElBH,iBAIAG,gBA4EPb;QAJYU;IA5EnB,MAAMI,SAAQJ,kBAAAA,SAASI,KAAK,YAAdJ,kBAAkB,EAAE;IAClC,IAAII,MAAMC,MAAM,GAAGtB,oBAAoB;QACrC,OAAO;YAAEuB,IAAI;YAAOC,OAAO,CAAC,wBAAwB,EAAExB,mBAAmB,MAAM,CAAC;QAAC;IACnF;IACA,MAAMyB,SAAQL,iBAAAA,QAAQK,KAAK,YAAbL,iBAAiB;IAC/B,IAAIK,QAAQxB,iBAAiB;QAC3B,OAAO;YAAEsB,IAAI;YAAOC,OAAO;QAA+B;IAC5D;IACA,sEAAsE;IACtE,mDAAmD;IACnD,MAAME,iBAAiB,CACrBd,MACAe;YAEeP;QAAf,MAAMQ,UAASR,qBAAAA,QAAQS,SAAS,qBAAjBT,kBAAmB,CAACR,wBAAAA,KAAMkB,IAAI,GAAG;QAChD,IAAI,CAACF,QAAQ,MAAM,IAAIG,MAAM,CAAC,kBAAkB,EAAEnB,KAAK,CAAC,CAAC;QACzD,MAAMoB,MAAMhB,YAAYY,QAAQV,WAAWf,WAAWwB,WAAW,aAC5DP;YACHK,OAAOA,QAAQ;;QAEjB,IAAIO,IAAIT,EAAE,KAAK,OAAO,MAAM,IAAIQ,MAAMC,IAAIR,KAAK;QAC/C,OAAOQ,IAAIvB,KAAK;IAClB;IACA,uEAAuE;IACvE,0EAA0E;IAC1E,MAAMwB,gBAAgB/B,cAAcC;IACpC,MAAMC,QAAQ,aAAK6B,eAAkBd;IACrC,MAAMe,UAAqD,CAAC;IAE5D,KAAK,MAAM,CAACC,OAAOC,KAAK,IAAIf,MAAMb,OAAO,GAAI;YAGzCU;YAAUkB,kBACAA,oBAsCOA;QAzCnB,uEAAuE;QACvE,MAAMC,cACJnB,cAAAA,SAAS,UAACkB,mBAAAA,KAAKE,UAAU,qBAAfF,iBAAiBN,IAAI,qBAAM,GAAG,YAAxCZ,cACAA,SAAS,WAACkB,qBAAAA,KAAKG,YAAY,qBAAjBH,mBAAmBN,IAAI,sBAAM,GAAG;QAC5C,IAAI,CAACO,YAAY;YACf,OAAO;gBACLd,IAAI;gBACJC,OAAO,CAAC,kBAAkB,EAAEY,KAAKG,YAAY,IAAIH,KAAKE,UAAU,CAAC,CAAC,CAAC;gBACnEF,MAAMD,QAAQ;YAChB;QACF;QACA,MAAMK,OAAgC,CAAC;QACvC,IAAI;gBACFH;aAAAA,yBAAAA,WAAWI,UAAU,qBAArBJ,uBAAuBK,OAAO,CAAC,CAACC,WAAWC;oBACtBR;gBAAnB,MAAMS,cAAaT,aAAAA,KAAKI,IAAI,qBAATJ,UAAW,CAACQ,eAAe;gBAC9C,IAAIC,cAAc,QAAQC,OAAOD,YAAYf,IAAI,OAAO,IAAI;oBAC1DU,IAAI,CAACG,UAAU/B,IAAI,CAAC,GAAGd,mBAAmBgD,OAAOD,aAAazC;gBAChE;YACF;QACF,EAAE,OAAOoB,OAAO;YACd,OAAO;gBACLD,IAAI;gBACJC,OAAO,CAAC,KAAK,EAAEW,QAAQ,EAAE,EAAE,EAAE,AAACX,MAAgBuB,OAAO,EAAE;gBACvDX,MAAMD,QAAQ;YAChB;QACF;QACA,MAAMH,MAAMjC,qBAAqBsC,YAAYG,MAAM,aAC7CpB,QAAQS,SAAS,GAAG;YAAEH;QAAe,IAAI,CAAC;YAC9C,oEAAoE;YACpE,wDAAwD;YACxDsB,SAASf;;QAEX,mEAAmE;QACnE,oEAAoE;QACpE,IAAID,IAAIT,EAAE,KAAK,OAAO;YACpB,OAAO;gBACLA,IAAI;gBACJC,OAAO,CAAC,KAAK,EAAEW,QAAQ,EAAE,EAAE,EAAEE,WAAWzB,IAAI,CAAC,GAAG,EAAEoB,IAAIR,KAAK,EAAE;gBAC7DY,MAAMD,QAAQ;YAChB;QACF;QACA,MAAMc,aAAab,EAAAA,mBAAAA,KAAKa,UAAU,qBAAfb,iBAAiBN,IAAI,OAAM,CAAC,IAAI,EAAEK,QAAQ,GAAG;QAChE/B,KAAK,CAAC6C,WAAW,GAAGjB,IAAIvB,KAAK;QAC7ByB,OAAO,CAACe,WAAW,GAAGjB,IAAIvB,KAAK;IACjC;IAEA,MAAMyC,cAAajC,wBAAAA,SAASkC,WAAW,qBAApBlC,sBAAsBa,IAAI;IAC7C,MAAMrB,QACJyC,cAAcA,cAAc9C,QACxBA,KAAK,CAAC8C,WAAW,IAChB3C,oBAAAA,OAAO6C,MAAM,CAAClB,SAASmB,EAAE,CAAC,CAAC,cAA3B9C,oBAAiC;IACxC,OAAO;QAAEgB,IAAI;QAAMd;QAAOyB;IAAQ;AACpC;AAEA;;;;;CAKC,GACD,OAAO,SAASoB,yBACdnD,SAAuC,EACvCe,SAAuC,EACvCW,SAAuC;IAEvC,MAAM0B,WAAyC,CAAC;IAChD,yEAAyE;IACzE,mEAAmE;IACnE,MAAMC,OAAO,IAAIC;IACjB,KAAK,MAAM,CAAC7C,MAAMN,SAAS,IAAIC,OAAOC,OAAO,CAACL,WAAY;kBAIrDuD;YAHgB,2BAAA,sBACEpD;QADrB,MAAMoD,sBAAa,uBAAA,AAACpD,SAAiBoD,UAAU,sBAA5B,4BAAA,qBAA8B5B,IAAI,qBAAlC,+BAAA,wCAA0C;QAC7D,MAAM6B,gBAAerD,yBAAAA,SAASqD,YAAY,qBAArBrD,uBAAuBwB,IAAI;QAChD,MAAMb,YACHyC,QAAAA,aAAa7B,SAAS,CAAC6B,WAAW,GAAGE,qBAArCF,QACAC,eAAe9B,SAAS,CAAC8B,aAAa,GAAGC;QAC5C,IAAI,CAAC3C,UAAU;YACbsC,QAAQ,CAAC3C,KAAK,GAAGN;YACjB;QACF;QACA,MAAMuD,SAASL,KAAKM,GAAG,CAACxD;QACxB,IAAIuD,QAAQ;YACVN,QAAQ,CAAC3C,KAAK,GAAGiD;YACjB;QACF;QACA,MAAM7B,MAAMhB,YAAYC,UAAUC,WAAWf,WAAW,CAAC,GAAG;YAAE0B;QAAU;QACxE,MAAMkC,OACJ/B,IAAIT,EAAE,KAAK,QACPjB,WACA,aAAKA;YAAUG,OAAOqC,OAAOd,IAAIvB,KAAK;;QAC5C+C,KAAKQ,GAAG,CAAC1D,UAAUyD;QACnBR,QAAQ,CAAC3C,KAAK,GAAGmD;IACnB;IACA,OAAOR;AACT"}
|
|
@@ -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
|
@@ -22,6 +22,8 @@ import { WORKFLOWS_CONSOLE_SECTIONS, WORKFLOWS_ORG_CONSOLE_SECTIONS } from "./co
|
|
|
22
22
|
import { registerPluginZone } from "@aglyn/aglyn/plugin-manager/plugin-zones";
|
|
23
23
|
import { WORKFLOW_USAGE_ZONE } from "./components/workflow-zones.js";
|
|
24
24
|
import { BUNDLE_ID } from "./constants/bundle-common.js";
|
|
25
|
+
import { registerWorkflowsRecordRoutes } from "./model/workflows-record-routes.js";
|
|
26
|
+
import { WORKFLOWS_SEARCH_SOURCES } from "./model/workflows-search-sources.js";
|
|
25
27
|
/** Code-split: the Automation console page only loads when opened. */ const WorkflowsConsolePage = lazy(()=>import("./components/workflows-console-page.js"));
|
|
26
28
|
/**
|
|
27
29
|
* Workflows feature plugin (AGL-395). Console-only — workflows, actions,
|
|
@@ -37,6 +39,7 @@ import { BUNDLE_ID } from "./constants/bundle-common.js";
|
|
|
37
39
|
* Remote Config release flag — and a section's name is not a reason to orphan
|
|
38
40
|
* them. Only what a reader sees carries the new name.
|
|
39
41
|
*/ export function registerWorkflowsConsole() {
|
|
42
|
+
registerWorkflowsRecordRoutes();
|
|
40
43
|
registerPluginZone({
|
|
41
44
|
zone: WORKFLOW_USAGE_ZONE,
|
|
42
45
|
label: 'Where a workflow is used',
|
|
@@ -74,13 +77,14 @@ import { BUNDLE_ID } from "./constants/bundle-common.js";
|
|
|
74
77
|
pluginId: BUNDLE_ID,
|
|
75
78
|
displayName: 'Automation',
|
|
76
79
|
featureFlag: 'workflows',
|
|
80
|
+
searchSources: WORKFLOWS_SEARCH_SOURCES,
|
|
77
81
|
navItems: [
|
|
78
82
|
{
|
|
79
83
|
label: 'Automation',
|
|
80
84
|
// Workflows, Actions and Webhooks are the tabs INSIDE this section, so
|
|
81
85
|
// the section is named for what they have in common. `/workflows` —
|
|
82
86
|
// the address before the section had its own name — is redirected here
|
|
83
|
-
// by
|
|
87
|
+
// by this plugin's `consoleRedirects` (see `Route.HOST_WORKFLOWS`).
|
|
84
88
|
href: '/automation',
|
|
85
89
|
// Sections as ROUTES (AGL-2501): each is a real URL the shell
|
|
86
90
|
// 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
|
|
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'\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 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 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` (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","registerWorkflowsRecordRoutes","WORKFLOWS_SEARCH_SOURCES","WorkflowsConsolePage","registerWorkflowsConsole","zone","label","surface","description","pluginId","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,SAASC,mBAAmB,QAAQ,iCAA6B;AACjE,SAASC,SAAS,QAAQ,+BAA2B;AACrD,SAASC,6BAA6B,QAAQ,qCAAiC;AAC/E,SAASC,wBAAwB,QAAQ,sCAAkC;AAE3E,oEAAoE,GACpE,MAAMC,uBAAuBX,KAC3B,IAAM,MAAM,CAAC;AAGf;;;;;;;;;;;;;CAaC,GACD,OAAO,SAASY;IACdH;IACAH,mBACE;QACEO,MAAMN;QACNO,OAAO;QACPC,SAAS;QACTC,aACE;IACJ,GACA,iEAAiE;IACjE;QAAEC,UAAUT;IAAU;IAExBV,MAAMoB,wBAAwB,CAAC;QAC7B,wDAAwD;QACxD,6DAA6D;QAC7DC,SAAS;YACP;gBACEC,MAAM;gBACNC,UAAU;gBACVC,OAAO;gBACPC,WAAWtB;YACb;YACA,sEAAsE;YACtE,0DAA0D;YAC1D;gBACEmB,MAAMtB,MAAM0B,oBAAoB,CAACC,SAAS;gBAC1CJ,UAAU;gBACVC,OAAO;gBACPC,WAAWpB;YACb;YACA;gBACEiB,MAAMtB,MAAM0B,oBAAoB,CAACE,cAAc;gBAC/CL,UAAU;gBACVC,OAAO;gBACPC,WAAWrB;YACb;SACD;QACDe,UAAUT;QACVmB,aAAa;QACbC,aAAa;QACbC,eAAenB;QACfoB,UAAU;YACR;gBACEhB,OAAO;gBACP,uEAAuE;gBACvE,oEAAoE;gBACpE,uEAAuE;gBACvE,oEAAoE;gBACpEiB,MAAM;gBACN,8DAA8D;gBAC9D,6DAA6D;gBAC7DC,UAAU5B;gBACV,qEAAqE;gBACrE,8DAA8D;gBAC9D6B,UAAU;gBACVC,MAAM;oBAAEC,MAAMpC,WAAWoC,IAAI;gBAAC;gBAC9BC,QAAQ;oBACNd,OAAO;oBACPY,MAAM;wBAAEC,MAAMpC,WAAWoC,IAAI;oBAAC;oBAC9BE,WAAW;gBACb;gBACAd,WAAWZ;YACb;SACD;QACD;;;;;;KAMC,GACD2B,aAAa;YACX;gBACExB,OAAO;gBACPiB,MAAM;gBACNC,UAAU3B;gBACV4B,UAAU;gBACVC,MAAM;oBAAEC,MAAMpC,WAAWoC,IAAI;gBAAC;gBAC9BC,QAAQ;oBACNd,OAAO;oBACPY,MAAM;wBAAEC,MAAMpC,WAAWoC,IAAI;oBAAC;oBAC9BE,WAAW;gBACb;gBACAd,WAAWZ;YACb;SACD;IACH;AACF;AAEA,wEAAwE;AACxE,SAAS4B,WAAWtC,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,90 @@
|
|
|
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
|
+
/** The stored kinds this module indexes, by their Firestore collection. */ const COLLECTION = {
|
|
18
|
+
workflow: 'workflows',
|
|
19
|
+
webhook: 'webhooks',
|
|
20
|
+
action: 'actions'
|
|
21
|
+
};
|
|
22
|
+
const str = (value)=>typeof value === 'string' ? value.trim() : '';
|
|
23
|
+
function recordOf(kind, id, data) {
|
|
24
|
+
var _data_trigger;
|
|
25
|
+
if (!data || data['deletedAt'] != null) return null;
|
|
26
|
+
const stored = str(data['name']);
|
|
27
|
+
if (kind === 'action') {
|
|
28
|
+
var _data_trigger1;
|
|
29
|
+
return {
|
|
30
|
+
id,
|
|
31
|
+
name: stored || id,
|
|
32
|
+
facts: {
|
|
33
|
+
trigger: (_data_trigger1 = data['trigger']) != null ? _data_trigger1 : null,
|
|
34
|
+
steps: Array.isArray(data['steps']) ? data['steps'] : [],
|
|
35
|
+
enabled: data['enabled'] !== false
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
if (!stored) return null;
|
|
40
|
+
if (kind === 'webhook') {
|
|
41
|
+
return {
|
|
42
|
+
id,
|
|
43
|
+
name: stored,
|
|
44
|
+
facts: {
|
|
45
|
+
direction: data['direction'],
|
|
46
|
+
enabled: data['enabled'] !== false
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
id,
|
|
52
|
+
name: stored,
|
|
53
|
+
facts: {
|
|
54
|
+
steps: Array.isArray(data['steps']) ? data['steps'] : [],
|
|
55
|
+
returnValue: str(data['returnValue']) || null,
|
|
56
|
+
trigger: (_data_trigger = data['trigger']) != null ? _data_trigger : null
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function hostCollection(hostId, kind) {
|
|
61
|
+
return firebaseAdmin.app().firestore().collection('hosts').doc(hostId).collection(COLLECTION[kind]);
|
|
62
|
+
}
|
|
63
|
+
function indexOf(kind) {
|
|
64
|
+
return {
|
|
65
|
+
async list ({ hostId, limit }) {
|
|
66
|
+
if (!hostId || limit <= 0) return {
|
|
67
|
+
records: [],
|
|
68
|
+
truncated: false
|
|
69
|
+
};
|
|
70
|
+
// One more than asked, so `truncated` is a fact rather than a guess;
|
|
71
|
+
// deleted and unnamed records are filtered after the read.
|
|
72
|
+
const snapshot = await hostCollection(hostId, kind).limit(limit + 1).get();
|
|
73
|
+
const records = snapshot.docs.map((doc)=>recordOf(kind, doc.id, doc.data())).filter((record)=>record !== null);
|
|
74
|
+
return {
|
|
75
|
+
records: records.slice(0, limit),
|
|
76
|
+
truncated: snapshot.size > limit
|
|
77
|
+
};
|
|
78
|
+
},
|
|
79
|
+
async get ({ hostId, id }) {
|
|
80
|
+
if (!hostId || !id) return null;
|
|
81
|
+
const snapshot = await hostCollection(hostId, kind).doc(id).get();
|
|
82
|
+
return snapshot.exists ? recordOf(kind, snapshot.id, snapshot.data()) : null;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
export const workflowRecordIndex = indexOf('workflow');
|
|
87
|
+
export const webhookRecordIndex = indexOf('webhook');
|
|
88
|
+
export const actionRecordIndex = indexOf('action');
|
|
89
|
+
|
|
90
|
+
//# 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'\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), and a deleted record is left out of every answer.\n *\n * A `workflow`'s `facts`:\n * `steps` (the stored step list: `functionId`, `functionName`, `args`,\n * `resultName` each), `returnValue` (a scope name, or `null`) and `trigger`\n * (`{ event, filter? }`, or `null` for a workflow run only by hand).\n * An unnamed workflow is left out.\n * A `webhook`'s `facts`:\n * `direction` (`outbound` | `inbound`) and `enabled` (a boolean). Never its\n * URL and never its secret. An unnamed webhook is left out.\n * An `action`'s `facts`:\n * `trigger`, `steps` and `enabled`, as stored. An action with no stored\n * name is named by its id — the name its run history already gives it.\n */\n\ntype Data = Record<string, unknown>\n\n/** The stored kinds this module indexes, by their Firestore collection. */\nconst COLLECTION = {\n workflow: 'workflows',\n webhook: 'webhooks',\n action: 'actions',\n} as const\n\ntype IndexedKind = keyof typeof COLLECTION\n\nconst str = (value: unknown): string => (typeof value === 'string' ? value.trim() : '')\n\nfunction recordOf(kind: IndexedKind, id: string, data: Data | undefined): PluginIndexedRecord | null {\n if (!data || data['deletedAt'] != null) return null\n const stored = str(data['name'])\n if (kind === 'action') {\n return {\n id,\n name: stored || id,\n facts: {\n trigger: data['trigger'] ?? null,\n steps: Array.isArray(data['steps']) ? data['steps'] : [],\n enabled: data['enabled'] !== false,\n },\n }\n }\n if (!stored) return null\n if (kind === 'webhook') {\n return {\n id,\n name: stored,\n facts: { direction: data['direction'], enabled: data['enabled'] !== false },\n }\n }\n return {\n id,\n name: stored,\n facts: {\n steps: Array.isArray(data['steps']) ? data['steps'] : [],\n returnValue: str(data['returnValue']) || null,\n trigger: data['trigger'] ?? null,\n },\n }\n}\n\nfunction hostCollection(hostId: string, kind: IndexedKind) {\n return firebaseAdmin\n .app()\n .firestore()\n .collection('hosts')\n .doc(hostId)\n .collection(COLLECTION[kind])\n}\n\nfunction indexOf(kind: IndexedKind): 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) => recordOf(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 ? recordOf(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","COLLECTION","workflow","webhook","action","str","value","trim","recordOf","kind","id","data","stored","name","facts","trigger","steps","Array","isArray","enabled","direction","returnValue","hostCollection","hostId","app","firestore","collection","doc","indexOf","list","limit","records","truncated","snapshot","get","docs","map","filter","record","slice","size","exists","workflowRecordIndex","webhookRecordIndex","actionRecordIndex"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAMD,SAASA,aAAa,QAAQ,iDAAgD;AA2B9E,yEAAyE,GACzE,MAAMC,aAAa;IACjBC,UAAU;IACVC,SAAS;IACTC,QAAQ;AACV;AAIA,MAAMC,MAAM,CAACC,QAA4B,OAAOA,UAAU,WAAWA,MAAMC,IAAI,KAAK;AAEpF,SAASC,SAASC,IAAiB,EAAEC,EAAU,EAAEC,IAAsB;QA4BxDA;IA3Bb,IAAI,CAACA,QAAQA,IAAI,CAAC,YAAY,IAAI,MAAM,OAAO;IAC/C,MAAMC,SAASP,IAAIM,IAAI,CAAC,OAAO;IAC/B,IAAIF,SAAS,UAAU;YAKRE;QAJb,OAAO;YACLD;YACAG,MAAMD,UAAUF;YAChBI,OAAO;gBACLC,OAAO,GAAEJ,iBAAAA,IAAI,CAAC,UAAU,YAAfA,iBAAmB;gBAC5BK,OAAOC,MAAMC,OAAO,CAACP,IAAI,CAAC,QAAQ,IAAIA,IAAI,CAAC,QAAQ,GAAG,EAAE;gBACxDQ,SAASR,IAAI,CAAC,UAAU,KAAK;YAC/B;QACF;IACF;IACA,IAAI,CAACC,QAAQ,OAAO;IACpB,IAAIH,SAAS,WAAW;QACtB,OAAO;YACLC;YACAG,MAAMD;YACNE,OAAO;gBAAEM,WAAWT,IAAI,CAAC,YAAY;gBAAEQ,SAASR,IAAI,CAAC,UAAU,KAAK;YAAM;QAC5E;IACF;IACA,OAAO;QACLD;QACAG,MAAMD;QACNE,OAAO;YACLE,OAAOC,MAAMC,OAAO,CAACP,IAAI,CAAC,QAAQ,IAAIA,IAAI,CAAC,QAAQ,GAAG,EAAE;YACxDU,aAAahB,IAAIM,IAAI,CAAC,cAAc,KAAK;YACzCI,OAAO,GAAEJ,gBAAAA,IAAI,CAAC,UAAU,YAAfA,gBAAmB;QAC9B;IACF;AACF;AAEA,SAASW,eAAeC,MAAc,EAAEd,IAAiB;IACvD,OAAOT,cACJwB,GAAG,GACHC,SAAS,GACTC,UAAU,CAAC,SACXC,GAAG,CAACJ,QACJG,UAAU,CAACzB,UAAU,CAACQ,KAAK;AAChC;AAEA,SAASmB,QAAQnB,IAAiB;IAChC,OAAO;QACL,MAAMoB,MAAK,EAAEN,MAAM,EAAEO,KAAK,EAAE;YAC1B,IAAI,CAACP,UAAUO,SAAS,GAAG,OAAO;gBAAEC,SAAS,EAAE;gBAAEC,WAAW;YAAM;YAClE,qEAAqE;YACrE,2DAA2D;YAC3D,MAAMC,WAAW,MAAMX,eAAeC,QAAQd,MAAMqB,KAAK,CAACA,QAAQ,GAAGI,GAAG;YACxE,MAAMH,UAAUE,SAASE,IAAI,CAC1BC,GAAG,CAAC,CAACT,MAAQnB,SAASC,MAAMkB,IAAIjB,EAAE,EAAEiB,IAAIhB,IAAI,KAC5C0B,MAAM,CAAC,CAACC,SAA0CA,WAAW;YAChE,OAAO;gBAAEP,SAASA,QAAQQ,KAAK,CAAC,GAAGT;gBAAQE,WAAWC,SAASO,IAAI,GAAGV;YAAM;QAC9E;QACA,MAAMI,KAAI,EAAEX,MAAM,EAAEb,EAAE,EAAE;YACtB,IAAI,CAACa,UAAU,CAACb,IAAI,OAAO;YAC3B,MAAMuB,WAAW,MAAMX,eAAeC,QAAQd,MAAMkB,GAAG,CAACjB,IAAIwB,GAAG;YAC/D,OAAOD,SAASQ,MAAM,GAAGjC,SAASC,MAAMwB,SAASvB,EAAE,EAAEuB,SAAStB,IAAI,MAAM;QAC1E;IACF;AACF;AAEA,OAAO,MAAM+B,sBAAsBd,QAAQ,YAAW;AACtD,OAAO,MAAMe,qBAAqBf,QAAQ,WAAU;AACpD,OAAO,MAAMgB,oBAAoBhB,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>;
|