@kubuild/core 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +122 -0
- package/dist/commands.d.ts +26 -2
- package/dist/commands.d.ts.map +1 -1
- package/dist/conditional-resolver.d.ts +45 -0
- package/dist/conditional-resolver.d.ts.map +1 -0
- package/dist/index.cjs +1314 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1288 -1
- package/dist/index.js.map +1 -1
- package/dist/interpolator.d.ts +50 -0
- package/dist/interpolator.d.ts.map +1 -0
- package/dist/pipeline-executor.d.ts +136 -0
- package/dist/pipeline-executor.d.ts.map +1 -0
- package/dist/state-store.d.ts +128 -0
- package/dist/state-store.d.ts.map +1 -0
- package/dist/validation-engine.d.ts +39 -0
- package/dist/validation-engine.d.ts.map +1 -0
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -20,6 +20,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
ActionCancellationError: () => ActionCancellationError,
|
|
24
|
+
ActionPipelineExecutor: () => ActionPipelineExecutor,
|
|
25
|
+
ActionTimeoutError: () => ActionTimeoutError,
|
|
23
26
|
CORE_BUILTIN_COMPONENTS: () => CORE_BUILTIN_COMPONENTS,
|
|
24
27
|
DEFAULT_DOCUMENT_SECURITY_LIMITS: () => DEFAULT_DOCUMENT_SECURITY_LIMITS,
|
|
25
28
|
DEFAULT_MAX_HISTORY: () => DEFAULT_MAX_HISTORY,
|
|
@@ -27,6 +30,8 @@ __export(index_exports, {
|
|
|
27
30
|
DocumentHistoryManager: () => DocumentHistoryManager,
|
|
28
31
|
HistoryEngine: () => HistoryEngine,
|
|
29
32
|
MigrationRegistry: () => MigrationRegistry,
|
|
33
|
+
RuntimeStateStore: () => RuntimeStateStore,
|
|
34
|
+
applyFieldTransform: () => applyFieldTransform,
|
|
30
35
|
areNodeIdsCompletelyDistinct: () => areNodeIdsCompletelyDistinct,
|
|
31
36
|
buildSampleVariablesFromCatalog: () => buildSampleVariablesFromCatalog,
|
|
32
37
|
calculateChecksum: () => calculateChecksum,
|
|
@@ -40,16 +45,26 @@ __export(index_exports, {
|
|
|
40
45
|
compareManifestsSemantically: () => compareManifestsSemantically,
|
|
41
46
|
containsProhibitedKeys: () => containsProhibitedKeys,
|
|
42
47
|
createBlankDocument: () => createBlankDocument,
|
|
48
|
+
createDefaultFormState: () => createDefaultFormState,
|
|
49
|
+
createRuntimeStore: () => createRuntimeStore,
|
|
43
50
|
createTemplateRecord: () => createTemplateRecord,
|
|
44
51
|
deepClone: () => deepClone,
|
|
45
52
|
defaultIdGenerator: () => defaultIdGenerator,
|
|
46
53
|
defaultMigrationRegistry: () => defaultMigrationRegistry,
|
|
47
54
|
defaultRenameAssetStrategy: () => defaultRenameAssetStrategy,
|
|
48
55
|
duplicateNode: () => duplicateNode,
|
|
56
|
+
evaluateActionCondition: () => evaluateActionCondition,
|
|
57
|
+
evaluateCondition: () => evaluateCondition,
|
|
58
|
+
evaluateConditionGroup: () => evaluateConditionGroup,
|
|
59
|
+
evaluateConditions: () => evaluateConditions,
|
|
60
|
+
evaluateOperator: () => evaluateOperator,
|
|
61
|
+
evaluateRule: () => evaluateRule,
|
|
62
|
+
executeActionPipeline: () => executeActionPipeline,
|
|
49
63
|
exportPackage: () => exportPackage,
|
|
50
64
|
exportStoraPackage: () => exportStoraPackage,
|
|
51
65
|
extractRequirementsFromTree: () => extractRequirementsFromTree,
|
|
52
66
|
extractTemplateRequirements: () => extractTemplateRequirements,
|
|
67
|
+
extractTemplateVariables: () => extractTemplateVariables,
|
|
53
68
|
findMissingComponentNodes: () => findMissingComponentNodes,
|
|
54
69
|
findNodeById: () => findNodeById,
|
|
55
70
|
findNodeLocation: () => findNodeLocation,
|
|
@@ -58,14 +73,21 @@ __export(index_exports, {
|
|
|
58
73
|
getNavigationTarget: () => getNavigationTarget,
|
|
59
74
|
getNodeAncestors: () => getNodeAncestors,
|
|
60
75
|
getParentNodeId: () => getParentNodeId,
|
|
76
|
+
hasTemplateExpressions: () => hasTemplateExpressions,
|
|
61
77
|
importPackage: () => importPackage,
|
|
62
78
|
importStoraPackage: () => importStoraPackage,
|
|
63
79
|
insertNode: () => insertNode,
|
|
64
80
|
inspectPackage: () => inspectPackage,
|
|
81
|
+
interpolateTemplateString: () => interpolateTemplateString,
|
|
82
|
+
interpolateValue: () => interpolateValue,
|
|
83
|
+
isConditionGroup: () => isConditionGroup,
|
|
65
84
|
isDangerousAssetFilename: () => isDangerousAssetFilename,
|
|
66
85
|
isDangerousPath: () => isDangerousPath,
|
|
67
86
|
isDescendantOf: () => isDescendantOf,
|
|
87
|
+
isEmptyValue: () => isEmptyValue,
|
|
88
|
+
isFormValid: () => isFormValid,
|
|
68
89
|
isSafeUrl: () => isSafeUrl,
|
|
90
|
+
isValueEmpty: () => isValueEmpty,
|
|
69
91
|
migrateDocument: () => migrateDocument,
|
|
70
92
|
moveNode: () => moveNode,
|
|
71
93
|
preflightPackage: () => preflightPackage,
|
|
@@ -75,16 +97,23 @@ __export(index_exports, {
|
|
|
75
97
|
removeNode: () => removeNode,
|
|
76
98
|
resolveBinding: () => resolveBinding,
|
|
77
99
|
resolveBindingValue: () => resolveBindingValue,
|
|
100
|
+
resolvePropertyPath: () => resolvePropertyPath,
|
|
78
101
|
sanitizeFilename: () => sanitizeFilename,
|
|
79
102
|
sanitizeHtml: () => sanitizeHtml,
|
|
80
103
|
sanitizeUrl: () => sanitizeUrl,
|
|
81
104
|
saveDraftAsTemplate: () => saveDraftAsTemplate,
|
|
82
105
|
sha256Sync: () => sha256Sync,
|
|
106
|
+
updateActions: () => updateActions,
|
|
83
107
|
updateAnimation: () => updateAnimation,
|
|
108
|
+
updateFormConfig: () => updateFormConfig,
|
|
84
109
|
updateProps: () => updateProps,
|
|
85
110
|
updateStyle: () => updateStyle,
|
|
86
111
|
validateDocument: () => validateDocument,
|
|
87
112
|
validateDocumentSecurity: () => validateDocumentSecurity,
|
|
113
|
+
validateFieldValue: () => validateFieldValue,
|
|
114
|
+
validateFieldValueAsync: () => validateFieldValueAsync,
|
|
115
|
+
validateForm: () => validateForm,
|
|
116
|
+
validateFormAsync: () => validateFormAsync,
|
|
88
117
|
validateTemplate: () => validateTemplate
|
|
89
118
|
});
|
|
90
119
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -1395,6 +1424,67 @@ function updateAnimation(document, params) {
|
|
|
1395
1424
|
}
|
|
1396
1425
|
};
|
|
1397
1426
|
}
|
|
1427
|
+
function updateActions(document, params) {
|
|
1428
|
+
const { nodeId, actions } = params;
|
|
1429
|
+
const newDoc = deepClone(document);
|
|
1430
|
+
const loc = findNodeLocation(newDoc.document, nodeId);
|
|
1431
|
+
if (!loc) {
|
|
1432
|
+
throw new Error(`Cannot update actions: Node with ID "${nodeId}" not found in document.`);
|
|
1433
|
+
}
|
|
1434
|
+
const targetNode = loc.node;
|
|
1435
|
+
const previousActions = targetNode.actions ? deepClone(targetNode.actions) : void 0;
|
|
1436
|
+
if (actions === null || Array.isArray(actions) && actions.length === 0) {
|
|
1437
|
+
delete targetNode.actions;
|
|
1438
|
+
} else {
|
|
1439
|
+
targetNode.actions = import_schema4.ActionPipelineSchema.array().parse(actions);
|
|
1440
|
+
}
|
|
1441
|
+
return {
|
|
1442
|
+
document: newDoc,
|
|
1443
|
+
event: {
|
|
1444
|
+
type: "ACTIONS_UPDATED",
|
|
1445
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1446
|
+
nodeId,
|
|
1447
|
+
parentId: loc.parent ? loc.parent.id : void 0,
|
|
1448
|
+
payload: {
|
|
1449
|
+
actions: targetNode.actions,
|
|
1450
|
+
previousActions
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
};
|
|
1454
|
+
}
|
|
1455
|
+
function updateFormConfig(document, params) {
|
|
1456
|
+
const { nodeId, formConfig, merge = true } = params;
|
|
1457
|
+
const newDoc = deepClone(document);
|
|
1458
|
+
const loc = findNodeLocation(newDoc.document, nodeId);
|
|
1459
|
+
if (!loc) {
|
|
1460
|
+
throw new Error(`Cannot update formConfig: Node with ID "${nodeId}" not found in document.`);
|
|
1461
|
+
}
|
|
1462
|
+
const targetNode = loc.node;
|
|
1463
|
+
const previousFormConfig = targetNode.formConfig ? deepClone(targetNode.formConfig) : void 0;
|
|
1464
|
+
if (formConfig === null) {
|
|
1465
|
+
delete targetNode.formConfig;
|
|
1466
|
+
} else {
|
|
1467
|
+
const currentFormConfig = targetNode.formConfig ? deepClone(targetNode.formConfig) : { formId: nodeId };
|
|
1468
|
+
const candidate = merge ? { ...currentFormConfig, ...deepClone(formConfig) } : deepClone(formConfig);
|
|
1469
|
+
if (!candidate.formId) {
|
|
1470
|
+
candidate.formId = nodeId;
|
|
1471
|
+
}
|
|
1472
|
+
targetNode.formConfig = import_schema4.FormConfigSchema.parse(candidate);
|
|
1473
|
+
}
|
|
1474
|
+
return {
|
|
1475
|
+
document: newDoc,
|
|
1476
|
+
event: {
|
|
1477
|
+
type: "FORM_CONFIG_UPDATED",
|
|
1478
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1479
|
+
nodeId,
|
|
1480
|
+
parentId: loc.parent ? loc.parent.id : void 0,
|
|
1481
|
+
payload: {
|
|
1482
|
+
formConfig: targetNode.formConfig,
|
|
1483
|
+
previousFormConfig
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
};
|
|
1487
|
+
}
|
|
1398
1488
|
|
|
1399
1489
|
// src/history.ts
|
|
1400
1490
|
var DEFAULT_MAX_HISTORY = 50;
|
|
@@ -3646,8 +3736,1206 @@ function areNodeIdsCompletelyDistinct(docA, docB) {
|
|
|
3646
3736
|
}
|
|
3647
3737
|
return true;
|
|
3648
3738
|
}
|
|
3739
|
+
|
|
3740
|
+
// src/interpolator.ts
|
|
3741
|
+
var FORBIDDEN_KEY_SEGMENTS3 = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
3742
|
+
var TEMPLATE_EXPRESSION_REGEX = /\{\{\s*([a-zA-Z0-9_$.,\-[\]\s]+?)\s*\}\}/g;
|
|
3743
|
+
var EXACT_TEMPLATE_REGEX = /^\{\{\s*([a-zA-Z0-9_$.,\-[\]\s]+?)\s*\}\}$/;
|
|
3744
|
+
function hasTemplateExpressions(text) {
|
|
3745
|
+
if (typeof text !== "string") return false;
|
|
3746
|
+
return /\{\{\s*[\s\S]+?\s*\}\}/.test(text);
|
|
3747
|
+
}
|
|
3748
|
+
function extractTemplateVariables(text) {
|
|
3749
|
+
if (!text || typeof text !== "string") return [];
|
|
3750
|
+
const matches = [];
|
|
3751
|
+
const regex = new RegExp(TEMPLATE_EXPRESSION_REGEX.source, "g");
|
|
3752
|
+
let match;
|
|
3753
|
+
while ((match = regex.exec(text)) !== null) {
|
|
3754
|
+
if (match[1]) {
|
|
3755
|
+
const trimmed = match[1].trim();
|
|
3756
|
+
if (trimmed && !matches.includes(trimmed)) {
|
|
3757
|
+
matches.push(trimmed);
|
|
3758
|
+
}
|
|
3759
|
+
}
|
|
3760
|
+
}
|
|
3761
|
+
return matches;
|
|
3762
|
+
}
|
|
3763
|
+
function resolvePropertyPath(source, path, fallback) {
|
|
3764
|
+
const defaultFallback = arguments.length < 3 ? "" : fallback;
|
|
3765
|
+
if (!path || typeof path !== "string" || source === null || source === void 0) {
|
|
3766
|
+
return defaultFallback;
|
|
3767
|
+
}
|
|
3768
|
+
const normalizedPath = path.replace(/\[(\d+)\]/g, ".$1");
|
|
3769
|
+
const segments = normalizedPath.split(".").map((s) => s.trim()).filter(Boolean);
|
|
3770
|
+
if (segments.length === 0) {
|
|
3771
|
+
return defaultFallback;
|
|
3772
|
+
}
|
|
3773
|
+
let current = source;
|
|
3774
|
+
for (const segment of segments) {
|
|
3775
|
+
if (FORBIDDEN_KEY_SEGMENTS3.has(segment)) {
|
|
3776
|
+
return defaultFallback;
|
|
3777
|
+
}
|
|
3778
|
+
if (current === null || current === void 0) {
|
|
3779
|
+
return defaultFallback;
|
|
3780
|
+
}
|
|
3781
|
+
if (typeof current !== "object") {
|
|
3782
|
+
return defaultFallback;
|
|
3783
|
+
}
|
|
3784
|
+
if (Array.isArray(current)) {
|
|
3785
|
+
const index = Number(segment);
|
|
3786
|
+
if (!Number.isInteger(index) || index < 0 || index >= current.length) {
|
|
3787
|
+
return defaultFallback;
|
|
3788
|
+
}
|
|
3789
|
+
current = current[index];
|
|
3790
|
+
} else if (Object.prototype.hasOwnProperty.call(current, segment)) {
|
|
3791
|
+
current = current[segment];
|
|
3792
|
+
} else {
|
|
3793
|
+
return defaultFallback;
|
|
3794
|
+
}
|
|
3795
|
+
}
|
|
3796
|
+
if (current === void 0 || typeof current === "function") {
|
|
3797
|
+
return defaultFallback;
|
|
3798
|
+
}
|
|
3799
|
+
return current;
|
|
3800
|
+
}
|
|
3801
|
+
function interpolateTemplateString(template, context, fallback = "") {
|
|
3802
|
+
if (!template || typeof template !== "string") return "";
|
|
3803
|
+
if (!hasTemplateExpressions(template)) return template;
|
|
3804
|
+
return template.replace(/\{\{\s*([a-zA-Z0-9_$.,\-[\]\s]+?)\s*\}\}/g, (_match, rawKey) => {
|
|
3805
|
+
const key = rawKey.trim();
|
|
3806
|
+
if (!key) return fallback;
|
|
3807
|
+
const resolved = resolvePropertyPath(context, key, fallback);
|
|
3808
|
+
if (resolved === void 0 || resolved === null) {
|
|
3809
|
+
return fallback;
|
|
3810
|
+
}
|
|
3811
|
+
if (typeof resolved === "object") {
|
|
3812
|
+
try {
|
|
3813
|
+
return JSON.stringify(resolved);
|
|
3814
|
+
} catch {
|
|
3815
|
+
return fallback;
|
|
3816
|
+
}
|
|
3817
|
+
}
|
|
3818
|
+
return String(resolved);
|
|
3819
|
+
});
|
|
3820
|
+
}
|
|
3821
|
+
function interpolateValue(value, context) {
|
|
3822
|
+
if (value === null || value === void 0) {
|
|
3823
|
+
return value;
|
|
3824
|
+
}
|
|
3825
|
+
if (typeof value === "string") {
|
|
3826
|
+
const trimmed = value.trim();
|
|
3827
|
+
const exactMatch = EXACT_TEMPLATE_REGEX.exec(trimmed);
|
|
3828
|
+
if (exactMatch && exactMatch[1]) {
|
|
3829
|
+
const key = exactMatch[1].trim();
|
|
3830
|
+
return resolvePropertyPath(context, key, "");
|
|
3831
|
+
}
|
|
3832
|
+
return interpolateTemplateString(value, context);
|
|
3833
|
+
}
|
|
3834
|
+
if (Array.isArray(value)) {
|
|
3835
|
+
return value.map((item) => interpolateValue(item, context));
|
|
3836
|
+
}
|
|
3837
|
+
if (typeof value === "object") {
|
|
3838
|
+
const result = {};
|
|
3839
|
+
for (const [k, v] of Object.entries(value)) {
|
|
3840
|
+
if (!FORBIDDEN_KEY_SEGMENTS3.has(k)) {
|
|
3841
|
+
result[k] = interpolateValue(v, context);
|
|
3842
|
+
}
|
|
3843
|
+
}
|
|
3844
|
+
return result;
|
|
3845
|
+
}
|
|
3846
|
+
return value;
|
|
3847
|
+
}
|
|
3848
|
+
|
|
3849
|
+
// src/validation-engine.ts
|
|
3850
|
+
function isEmptyValue(value) {
|
|
3851
|
+
if (value === void 0 || value === null) {
|
|
3852
|
+
return true;
|
|
3853
|
+
}
|
|
3854
|
+
if (typeof value === "string") {
|
|
3855
|
+
return value.trim().length === 0;
|
|
3856
|
+
}
|
|
3857
|
+
if (Array.isArray(value)) {
|
|
3858
|
+
return value.length === 0;
|
|
3859
|
+
}
|
|
3860
|
+
if (typeof value === "boolean") {
|
|
3861
|
+
return value === false;
|
|
3862
|
+
}
|
|
3863
|
+
return false;
|
|
3864
|
+
}
|
|
3865
|
+
var EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
3866
|
+
var URL_REGEX = /^(https?:\/\/)([\w.-]+)(:[0-9]+)?(\/.*)?$/i;
|
|
3867
|
+
function applyFieldTransform(value, transform) {
|
|
3868
|
+
if (value === void 0 || value === null || !transform) {
|
|
3869
|
+
return value;
|
|
3870
|
+
}
|
|
3871
|
+
if (typeof value === "string") {
|
|
3872
|
+
switch (transform) {
|
|
3873
|
+
case "trim":
|
|
3874
|
+
return value.trim();
|
|
3875
|
+
case "lowercase":
|
|
3876
|
+
return value.toLowerCase();
|
|
3877
|
+
case "uppercase":
|
|
3878
|
+
return value.toUpperCase();
|
|
3879
|
+
case "number": {
|
|
3880
|
+
const trimmed = value.trim();
|
|
3881
|
+
if (trimmed === "") return value;
|
|
3882
|
+
const num = Number(trimmed);
|
|
3883
|
+
return Number.isNaN(num) ? value : num;
|
|
3884
|
+
}
|
|
3885
|
+
default:
|
|
3886
|
+
return value;
|
|
3887
|
+
}
|
|
3888
|
+
}
|
|
3889
|
+
if (typeof value === "number" && transform === "number") {
|
|
3890
|
+
return value;
|
|
3891
|
+
}
|
|
3892
|
+
return value;
|
|
3893
|
+
}
|
|
3894
|
+
function evaluateRule(rule, value, allFormValues) {
|
|
3895
|
+
const isValueEmpty2 = isEmptyValue(value);
|
|
3896
|
+
if (rule.type !== "required" && isValueEmpty2) {
|
|
3897
|
+
return null;
|
|
3898
|
+
}
|
|
3899
|
+
switch (rule.type) {
|
|
3900
|
+
case "required": {
|
|
3901
|
+
if (isValueEmpty2) {
|
|
3902
|
+
return rule.message;
|
|
3903
|
+
}
|
|
3904
|
+
return null;
|
|
3905
|
+
}
|
|
3906
|
+
case "email": {
|
|
3907
|
+
if (typeof value !== "string" || !EMAIL_REGEX.test(value.trim())) {
|
|
3908
|
+
return rule.message;
|
|
3909
|
+
}
|
|
3910
|
+
return null;
|
|
3911
|
+
}
|
|
3912
|
+
case "url": {
|
|
3913
|
+
if (typeof value !== "string" || !URL_REGEX.test(value.trim())) {
|
|
3914
|
+
return rule.message;
|
|
3915
|
+
}
|
|
3916
|
+
return null;
|
|
3917
|
+
}
|
|
3918
|
+
case "min_length": {
|
|
3919
|
+
const min = Number(rule.value);
|
|
3920
|
+
if (Number.isFinite(min)) {
|
|
3921
|
+
if (typeof value === "string" && value.length < min) {
|
|
3922
|
+
return rule.message;
|
|
3923
|
+
}
|
|
3924
|
+
if (Array.isArray(value) && value.length < min) {
|
|
3925
|
+
return rule.message;
|
|
3926
|
+
}
|
|
3927
|
+
}
|
|
3928
|
+
return null;
|
|
3929
|
+
}
|
|
3930
|
+
case "max_length": {
|
|
3931
|
+
const max = Number(rule.value);
|
|
3932
|
+
if (Number.isFinite(max)) {
|
|
3933
|
+
if (typeof value === "string" && value.length > max) {
|
|
3934
|
+
return rule.message;
|
|
3935
|
+
}
|
|
3936
|
+
if (Array.isArray(value) && value.length > max) {
|
|
3937
|
+
return rule.message;
|
|
3938
|
+
}
|
|
3939
|
+
}
|
|
3940
|
+
return null;
|
|
3941
|
+
}
|
|
3942
|
+
case "numeric_min": {
|
|
3943
|
+
const min = Number(rule.value);
|
|
3944
|
+
const num = Number(value);
|
|
3945
|
+
if (Number.isNaN(num) || !Number.isFinite(num) || num < min) {
|
|
3946
|
+
return rule.message;
|
|
3947
|
+
}
|
|
3948
|
+
return null;
|
|
3949
|
+
}
|
|
3950
|
+
case "numeric_max": {
|
|
3951
|
+
const max = Number(rule.value);
|
|
3952
|
+
const num = Number(value);
|
|
3953
|
+
if (Number.isNaN(num) || !Number.isFinite(num) || num > max) {
|
|
3954
|
+
return rule.message;
|
|
3955
|
+
}
|
|
3956
|
+
return null;
|
|
3957
|
+
}
|
|
3958
|
+
case "pattern":
|
|
3959
|
+
case "custom_regex": {
|
|
3960
|
+
try {
|
|
3961
|
+
const patternStr = String(rule.value || "");
|
|
3962
|
+
const regex = new RegExp(patternStr);
|
|
3963
|
+
if (!regex.test(String(value ?? ""))) {
|
|
3964
|
+
return rule.message;
|
|
3965
|
+
}
|
|
3966
|
+
} catch {
|
|
3967
|
+
return rule.message;
|
|
3968
|
+
}
|
|
3969
|
+
return null;
|
|
3970
|
+
}
|
|
3971
|
+
case "match_field": {
|
|
3972
|
+
const targetFieldName = String(rule.value || "");
|
|
3973
|
+
const targetValue = allFormValues?.[targetFieldName];
|
|
3974
|
+
if (value !== targetValue) {
|
|
3975
|
+
return rule.message;
|
|
3976
|
+
}
|
|
3977
|
+
return null;
|
|
3978
|
+
}
|
|
3979
|
+
default:
|
|
3980
|
+
return null;
|
|
3981
|
+
}
|
|
3982
|
+
}
|
|
3983
|
+
function validateFieldValue(value, rules, allFormValues) {
|
|
3984
|
+
if (!rules || !Array.isArray(rules) || rules.length === 0) {
|
|
3985
|
+
return null;
|
|
3986
|
+
}
|
|
3987
|
+
for (const rule of rules) {
|
|
3988
|
+
const error = evaluateRule(rule, value, allFormValues);
|
|
3989
|
+
if (error) {
|
|
3990
|
+
return error;
|
|
3991
|
+
}
|
|
3992
|
+
}
|
|
3993
|
+
return null;
|
|
3994
|
+
}
|
|
3995
|
+
async function validateFieldValueAsync(value, rules, allFormValues) {
|
|
3996
|
+
return validateFieldValue(value, rules, allFormValues);
|
|
3997
|
+
}
|
|
3998
|
+
function validateForm(values, fieldConfigs) {
|
|
3999
|
+
const errors = {};
|
|
4000
|
+
if (!fieldConfigs) {
|
|
4001
|
+
return errors;
|
|
4002
|
+
}
|
|
4003
|
+
if (Array.isArray(fieldConfigs)) {
|
|
4004
|
+
for (const field of fieldConfigs) {
|
|
4005
|
+
if (!field?.name) continue;
|
|
4006
|
+
let value = values?.[field.name];
|
|
4007
|
+
if (field.transform) {
|
|
4008
|
+
value = applyFieldTransform(value, field.transform);
|
|
4009
|
+
}
|
|
4010
|
+
const rules = [...field.rules || []];
|
|
4011
|
+
if (field.required && !rules.some((r) => r.type === "required")) {
|
|
4012
|
+
rules.unshift({
|
|
4013
|
+
type: "required",
|
|
4014
|
+
message: `${field.label || field.name} is required`
|
|
4015
|
+
});
|
|
4016
|
+
}
|
|
4017
|
+
const error = validateFieldValue(value, rules, values);
|
|
4018
|
+
if (error) {
|
|
4019
|
+
errors[field.name] = error;
|
|
4020
|
+
}
|
|
4021
|
+
}
|
|
4022
|
+
} else if (typeof fieldConfigs === "object") {
|
|
4023
|
+
for (const [fieldName, config] of Object.entries(fieldConfigs)) {
|
|
4024
|
+
let value = values?.[fieldName];
|
|
4025
|
+
let rules = [];
|
|
4026
|
+
if (Array.isArray(config)) {
|
|
4027
|
+
rules = config;
|
|
4028
|
+
} else if (config && typeof config === "object") {
|
|
4029
|
+
if (config.transform) {
|
|
4030
|
+
value = applyFieldTransform(value, config.transform);
|
|
4031
|
+
}
|
|
4032
|
+
rules = [...config.rules || []];
|
|
4033
|
+
if (config.required && !rules.some((r) => r.type === "required")) {
|
|
4034
|
+
rules.unshift({
|
|
4035
|
+
type: "required",
|
|
4036
|
+
message: `${config.label || fieldName} is required`
|
|
4037
|
+
});
|
|
4038
|
+
}
|
|
4039
|
+
}
|
|
4040
|
+
const error = validateFieldValue(value, rules, values);
|
|
4041
|
+
if (error) {
|
|
4042
|
+
errors[fieldName] = error;
|
|
4043
|
+
}
|
|
4044
|
+
}
|
|
4045
|
+
}
|
|
4046
|
+
return errors;
|
|
4047
|
+
}
|
|
4048
|
+
async function validateFormAsync(values, fieldConfigs) {
|
|
4049
|
+
return validateForm(values, fieldConfigs);
|
|
4050
|
+
}
|
|
4051
|
+
function isFormValid(errors) {
|
|
4052
|
+
return Object.keys(errors).length === 0;
|
|
4053
|
+
}
|
|
4054
|
+
|
|
4055
|
+
// src/conditional-resolver.ts
|
|
4056
|
+
function isConditionGroup(item) {
|
|
4057
|
+
return typeof item === "object" && item !== null && "combinator" in item && "conditions" in item;
|
|
4058
|
+
}
|
|
4059
|
+
function isValueEmpty(value) {
|
|
4060
|
+
if (value === void 0 || value === null) {
|
|
4061
|
+
return true;
|
|
4062
|
+
}
|
|
4063
|
+
if (typeof value === "string") {
|
|
4064
|
+
return value.trim().length === 0;
|
|
4065
|
+
}
|
|
4066
|
+
if (Array.isArray(value)) {
|
|
4067
|
+
return value.length === 0;
|
|
4068
|
+
}
|
|
4069
|
+
if (typeof value === "object") {
|
|
4070
|
+
return Object.keys(value).length === 0;
|
|
4071
|
+
}
|
|
4072
|
+
return false;
|
|
4073
|
+
}
|
|
4074
|
+
function evaluateOperator(operator, actual, expected, options) {
|
|
4075
|
+
let act = actual;
|
|
4076
|
+
let exp = expected;
|
|
4077
|
+
if (options?.trimStrings) {
|
|
4078
|
+
if (typeof act === "string") act = act.trim();
|
|
4079
|
+
if (typeof exp === "string") exp = exp.trim();
|
|
4080
|
+
}
|
|
4081
|
+
if (options?.caseInsensitive) {
|
|
4082
|
+
if (typeof act === "string") act = act.toLowerCase();
|
|
4083
|
+
if (typeof exp === "string") exp = exp.toLowerCase();
|
|
4084
|
+
}
|
|
4085
|
+
switch (operator) {
|
|
4086
|
+
case "equals": {
|
|
4087
|
+
if (act === exp) return true;
|
|
4088
|
+
if (typeof act === "number" && typeof exp === "string" && exp.trim() !== "") {
|
|
4089
|
+
const numExp = Number(exp);
|
|
4090
|
+
return !Number.isNaN(numExp) && act === numExp;
|
|
4091
|
+
}
|
|
4092
|
+
if (typeof act === "string" && typeof exp === "number" && act.trim() !== "") {
|
|
4093
|
+
const numAct = Number(act);
|
|
4094
|
+
return !Number.isNaN(numAct) && numAct === exp;
|
|
4095
|
+
}
|
|
4096
|
+
if (typeof act === "boolean" && typeof exp === "string") {
|
|
4097
|
+
return act === (exp.toLowerCase() === "true");
|
|
4098
|
+
}
|
|
4099
|
+
if (typeof act === "string" && typeof exp === "boolean") {
|
|
4100
|
+
return act.toLowerCase() === "true" === exp;
|
|
4101
|
+
}
|
|
4102
|
+
return false;
|
|
4103
|
+
}
|
|
4104
|
+
case "not_equals":
|
|
4105
|
+
return !evaluateOperator("equals", actual, expected, options);
|
|
4106
|
+
case "is_truthy":
|
|
4107
|
+
if (Array.isArray(act)) {
|
|
4108
|
+
return act.length > 0;
|
|
4109
|
+
}
|
|
4110
|
+
if (act && typeof act === "object") {
|
|
4111
|
+
return Object.keys(act).length > 0;
|
|
4112
|
+
}
|
|
4113
|
+
return Boolean(act);
|
|
4114
|
+
case "is_falsy":
|
|
4115
|
+
return !evaluateOperator("is_truthy", actual, void 0, options);
|
|
4116
|
+
case "is_empty":
|
|
4117
|
+
return isValueEmpty(actual);
|
|
4118
|
+
case "is_not_empty":
|
|
4119
|
+
return !isValueEmpty(actual);
|
|
4120
|
+
case "contains": {
|
|
4121
|
+
if (typeof act === "string") {
|
|
4122
|
+
const needle = options?.caseInsensitive && typeof exp === "string" ? exp : String(exp ?? "");
|
|
4123
|
+
return act.includes(needle);
|
|
4124
|
+
}
|
|
4125
|
+
if (Array.isArray(act)) {
|
|
4126
|
+
if (options?.caseInsensitive && typeof exp === "string") {
|
|
4127
|
+
return act.some((item) => typeof item === "string" && item.toLowerCase() === exp);
|
|
4128
|
+
}
|
|
4129
|
+
return act.includes(exp);
|
|
4130
|
+
}
|
|
4131
|
+
if (act && typeof act === "object") {
|
|
4132
|
+
return exp !== void 0 && String(exp) in act;
|
|
4133
|
+
}
|
|
4134
|
+
return false;
|
|
4135
|
+
}
|
|
4136
|
+
case "not_contains":
|
|
4137
|
+
return !evaluateOperator("contains", actual, expected, options);
|
|
4138
|
+
case "starts_with": {
|
|
4139
|
+
if (typeof act !== "string") return false;
|
|
4140
|
+
const prefix = options?.caseInsensitive && typeof exp === "string" ? exp : String(exp ?? "");
|
|
4141
|
+
return act.startsWith(prefix);
|
|
4142
|
+
}
|
|
4143
|
+
case "ends_with": {
|
|
4144
|
+
if (typeof act !== "string") return false;
|
|
4145
|
+
const suffix = options?.caseInsensitive && typeof exp === "string" ? exp : String(exp ?? "");
|
|
4146
|
+
return act.endsWith(suffix);
|
|
4147
|
+
}
|
|
4148
|
+
case "gt": {
|
|
4149
|
+
const actNum = Number(act);
|
|
4150
|
+
const expNum = Number(exp);
|
|
4151
|
+
return !Number.isNaN(actNum) && !Number.isNaN(expNum) && actNum > expNum;
|
|
4152
|
+
}
|
|
4153
|
+
case "gte": {
|
|
4154
|
+
const actNum = Number(act);
|
|
4155
|
+
const expNum = Number(exp);
|
|
4156
|
+
return !Number.isNaN(actNum) && !Number.isNaN(expNum) && actNum >= expNum;
|
|
4157
|
+
}
|
|
4158
|
+
case "lt": {
|
|
4159
|
+
const actNum = Number(act);
|
|
4160
|
+
const expNum = Number(exp);
|
|
4161
|
+
return !Number.isNaN(actNum) && !Number.isNaN(expNum) && actNum < expNum;
|
|
4162
|
+
}
|
|
4163
|
+
case "lte": {
|
|
4164
|
+
const actNum = Number(act);
|
|
4165
|
+
const expNum = Number(exp);
|
|
4166
|
+
return !Number.isNaN(actNum) && !Number.isNaN(expNum) && actNum <= expNum;
|
|
4167
|
+
}
|
|
4168
|
+
case "in": {
|
|
4169
|
+
if (Array.isArray(exp)) {
|
|
4170
|
+
if (options?.caseInsensitive && typeof act === "string") {
|
|
4171
|
+
return exp.some((item) => typeof item === "string" && item.toLowerCase() === act);
|
|
4172
|
+
}
|
|
4173
|
+
return exp.includes(act);
|
|
4174
|
+
}
|
|
4175
|
+
if (typeof exp === "string") {
|
|
4176
|
+
return exp.includes(String(act ?? ""));
|
|
4177
|
+
}
|
|
4178
|
+
return false;
|
|
4179
|
+
}
|
|
4180
|
+
case "not_in":
|
|
4181
|
+
return !evaluateOperator("in", actual, expected, options);
|
|
4182
|
+
case "regex": {
|
|
4183
|
+
try {
|
|
4184
|
+
const patternStr = String(exp ?? "");
|
|
4185
|
+
const flags = options?.caseInsensitive ? "i" : "";
|
|
4186
|
+
const regex = new RegExp(patternStr, flags);
|
|
4187
|
+
return regex.test(String(act ?? ""));
|
|
4188
|
+
} catch {
|
|
4189
|
+
return false;
|
|
4190
|
+
}
|
|
4191
|
+
}
|
|
4192
|
+
default:
|
|
4193
|
+
return true;
|
|
4194
|
+
}
|
|
4195
|
+
}
|
|
4196
|
+
function evaluateCondition(condition, context, options) {
|
|
4197
|
+
if (!condition) return true;
|
|
4198
|
+
const rawField = condition.field;
|
|
4199
|
+
if (!rawField || typeof rawField !== "string") return true;
|
|
4200
|
+
const fieldPath = rawField.replace(/^\{\{\s*/, "").replace(/\s*\}\}$/, "").trim();
|
|
4201
|
+
const actualValue = resolvePropertyPath(context, fieldPath, void 0);
|
|
4202
|
+
return evaluateOperator(condition.operator, actualValue, condition.value, options);
|
|
4203
|
+
}
|
|
4204
|
+
function evaluateConditionGroup(group, context, options) {
|
|
4205
|
+
if (!group || !Array.isArray(group.conditions) || group.conditions.length === 0) {
|
|
4206
|
+
return true;
|
|
4207
|
+
}
|
|
4208
|
+
const combinator = group.combinator === "or" ? "or" : "and";
|
|
4209
|
+
if (combinator === "and") {
|
|
4210
|
+
return group.conditions.every((item) => {
|
|
4211
|
+
if (isConditionGroup(item)) {
|
|
4212
|
+
return evaluateConditionGroup(item, context, options);
|
|
4213
|
+
}
|
|
4214
|
+
return evaluateCondition(item, context, options);
|
|
4215
|
+
});
|
|
4216
|
+
}
|
|
4217
|
+
return group.conditions.some((item) => {
|
|
4218
|
+
if (isConditionGroup(item)) {
|
|
4219
|
+
return evaluateConditionGroup(item, context, options);
|
|
4220
|
+
}
|
|
4221
|
+
return evaluateCondition(item, context, options);
|
|
4222
|
+
});
|
|
4223
|
+
}
|
|
4224
|
+
function evaluateConditions(conditions, context, combinator = "and", options) {
|
|
4225
|
+
return evaluateConditionGroup({ combinator, conditions }, context, options);
|
|
4226
|
+
}
|
|
4227
|
+
|
|
4228
|
+
// src/pipeline-executor.ts
|
|
4229
|
+
var ActionTimeoutError = class extends Error {
|
|
4230
|
+
stepId;
|
|
4231
|
+
timeoutMs;
|
|
4232
|
+
constructor(message, timeoutMs, stepId) {
|
|
4233
|
+
super(message);
|
|
4234
|
+
this.name = "ActionTimeoutError";
|
|
4235
|
+
this.timeoutMs = timeoutMs;
|
|
4236
|
+
this.stepId = stepId;
|
|
4237
|
+
}
|
|
4238
|
+
};
|
|
4239
|
+
var ActionCancellationError = class extends Error {
|
|
4240
|
+
stepId;
|
|
4241
|
+
constructor(message = "Action execution cancelled", stepId) {
|
|
4242
|
+
super(message);
|
|
4243
|
+
this.name = "ActionCancellationError";
|
|
4244
|
+
this.stepId = stepId;
|
|
4245
|
+
}
|
|
4246
|
+
};
|
|
4247
|
+
function evaluateActionCondition(condition, context) {
|
|
4248
|
+
return evaluateCondition(condition, context);
|
|
4249
|
+
}
|
|
4250
|
+
function normalizeAbortError(reason, stepId) {
|
|
4251
|
+
if (reason instanceof ActionTimeoutError) {
|
|
4252
|
+
return reason;
|
|
4253
|
+
}
|
|
4254
|
+
if (reason instanceof ActionCancellationError) {
|
|
4255
|
+
return reason;
|
|
4256
|
+
}
|
|
4257
|
+
const msg = reason instanceof Error ? reason.message : "Action execution cancelled";
|
|
4258
|
+
return new ActionCancellationError(msg, stepId);
|
|
4259
|
+
}
|
|
4260
|
+
function createTimeoutAbortSignal(parentSignal, timeoutMs, timeoutMessage, stepId) {
|
|
4261
|
+
const controller = new AbortController();
|
|
4262
|
+
let timerId;
|
|
4263
|
+
const onParentAbort = () => {
|
|
4264
|
+
controller.abort(normalizeAbortError(parentSignal?.reason, stepId));
|
|
4265
|
+
};
|
|
4266
|
+
if (parentSignal) {
|
|
4267
|
+
if (parentSignal.aborted) {
|
|
4268
|
+
onParentAbort();
|
|
4269
|
+
} else {
|
|
4270
|
+
parentSignal.addEventListener("abort", onParentAbort, { once: true });
|
|
4271
|
+
}
|
|
4272
|
+
}
|
|
4273
|
+
if (timeoutMs !== void 0 && timeoutMs > 0) {
|
|
4274
|
+
timerId = setTimeout(() => {
|
|
4275
|
+
controller.abort(
|
|
4276
|
+
new ActionTimeoutError(
|
|
4277
|
+
timeoutMessage || `Action execution timed out after ${timeoutMs}ms`,
|
|
4278
|
+
timeoutMs,
|
|
4279
|
+
stepId
|
|
4280
|
+
)
|
|
4281
|
+
);
|
|
4282
|
+
}, timeoutMs);
|
|
4283
|
+
}
|
|
4284
|
+
const cleanup = () => {
|
|
4285
|
+
if (timerId !== void 0) {
|
|
4286
|
+
clearTimeout(timerId);
|
|
4287
|
+
}
|
|
4288
|
+
if (parentSignal) {
|
|
4289
|
+
parentSignal.removeEventListener("abort", onParentAbort);
|
|
4290
|
+
}
|
|
4291
|
+
};
|
|
4292
|
+
return { signal: controller.signal, cleanup };
|
|
4293
|
+
}
|
|
4294
|
+
var ActionPipelineExecutor = class {
|
|
4295
|
+
handlers = /* @__PURE__ */ new Map();
|
|
4296
|
+
defaultTimeout;
|
|
4297
|
+
throwOnError;
|
|
4298
|
+
constructor(options) {
|
|
4299
|
+
this.defaultTimeout = options?.defaultTimeout;
|
|
4300
|
+
this.throwOnError = options?.throwOnError ?? false;
|
|
4301
|
+
this.registerBuiltInHandlers();
|
|
4302
|
+
if (options?.handlers) {
|
|
4303
|
+
for (const [type, handler] of Object.entries(options.handlers)) {
|
|
4304
|
+
this.registerHandler(type, handler);
|
|
4305
|
+
}
|
|
4306
|
+
}
|
|
4307
|
+
}
|
|
4308
|
+
/**
|
|
4309
|
+
* Registers default built-in handlers for core step types like `set_state` and `reset_form`.
|
|
4310
|
+
*/
|
|
4311
|
+
registerBuiltInHandlers() {
|
|
4312
|
+
this.registerHandler("set_state", (step, context) => {
|
|
4313
|
+
const key = String(step.payload?.key || "");
|
|
4314
|
+
const value = step.payload?.value;
|
|
4315
|
+
const scope = String(step.payload?.scope || "runtime");
|
|
4316
|
+
if (!key) return;
|
|
4317
|
+
if (!context.state) context.state = {};
|
|
4318
|
+
if (!context.variables) context.variables = {};
|
|
4319
|
+
if (scope === "runtime" || scope === "document") {
|
|
4320
|
+
context.state[key] = value;
|
|
4321
|
+
context.variables[key] = value;
|
|
4322
|
+
} else {
|
|
4323
|
+
context.state[key] = value;
|
|
4324
|
+
}
|
|
4325
|
+
return { key, value, scope };
|
|
4326
|
+
});
|
|
4327
|
+
this.registerHandler("reset_form", (_step, context) => {
|
|
4328
|
+
if (context.form && typeof context.form === "object") {
|
|
4329
|
+
for (const k of Object.keys(context.form)) {
|
|
4330
|
+
context.form[k] = "";
|
|
4331
|
+
}
|
|
4332
|
+
}
|
|
4333
|
+
return { reset: true };
|
|
4334
|
+
});
|
|
4335
|
+
}
|
|
4336
|
+
/**
|
|
4337
|
+
* Registers a handler for a step type.
|
|
4338
|
+
*/
|
|
4339
|
+
registerHandler(type, handler) {
|
|
4340
|
+
this.handlers.set(type, handler);
|
|
4341
|
+
return this;
|
|
4342
|
+
}
|
|
4343
|
+
/**
|
|
4344
|
+
* Unregisters a handler for a step type.
|
|
4345
|
+
*/
|
|
4346
|
+
unregisterHandler(type) {
|
|
4347
|
+
this.handlers.delete(type);
|
|
4348
|
+
return this;
|
|
4349
|
+
}
|
|
4350
|
+
/**
|
|
4351
|
+
* Checks if a handler exists for a step type.
|
|
4352
|
+
*/
|
|
4353
|
+
hasHandler(type) {
|
|
4354
|
+
return this.handlers.has(type);
|
|
4355
|
+
}
|
|
4356
|
+
/**
|
|
4357
|
+
* Gets the registered handler for a step type.
|
|
4358
|
+
*/
|
|
4359
|
+
getHandler(type) {
|
|
4360
|
+
return this.handlers.get(type);
|
|
4361
|
+
}
|
|
4362
|
+
/**
|
|
4363
|
+
* Executes a full ActionPipeline sequentially with support for timeouts, cancellation,
|
|
4364
|
+
* condition evaluation, and branching.
|
|
4365
|
+
*/
|
|
4366
|
+
async execute(pipeline, options) {
|
|
4367
|
+
const startTime = Date.now();
|
|
4368
|
+
const context = options?.context ?? {};
|
|
4369
|
+
if (!context.variables) context.variables = {};
|
|
4370
|
+
if (!context.state) context.state = {};
|
|
4371
|
+
if (!context.form) context.form = {};
|
|
4372
|
+
if (!context.stepResults) context.stepResults = {};
|
|
4373
|
+
const timeoutMs = options?.timeout ?? this.defaultTimeout;
|
|
4374
|
+
const { signal, cleanup } = createTimeoutAbortSignal(
|
|
4375
|
+
options?.signal,
|
|
4376
|
+
timeoutMs,
|
|
4377
|
+
`Pipeline "${pipeline.id}" timed out after ${timeoutMs}ms`
|
|
4378
|
+
);
|
|
4379
|
+
let pipelineStatus = "completed";
|
|
4380
|
+
let pipelineError = void 0;
|
|
4381
|
+
const allStepResults = [];
|
|
4382
|
+
try {
|
|
4383
|
+
if (pipeline.enabled === false) {
|
|
4384
|
+
return {
|
|
4385
|
+
pipelineId: pipeline.id,
|
|
4386
|
+
success: true,
|
|
4387
|
+
status: "completed",
|
|
4388
|
+
stepResults: [],
|
|
4389
|
+
context,
|
|
4390
|
+
durationMs: Date.now() - startTime
|
|
4391
|
+
};
|
|
4392
|
+
}
|
|
4393
|
+
const { success, results, error } = await this.executeSteps(
|
|
4394
|
+
pipeline.steps,
|
|
4395
|
+
context,
|
|
4396
|
+
signal,
|
|
4397
|
+
options
|
|
4398
|
+
);
|
|
4399
|
+
allStepResults.push(...results);
|
|
4400
|
+
if (!success) {
|
|
4401
|
+
pipelineStatus = signal.aborted ? "cancelled" : "failed";
|
|
4402
|
+
pipelineError = error;
|
|
4403
|
+
}
|
|
4404
|
+
} catch (err) {
|
|
4405
|
+
pipelineStatus = signal.aborted ? "cancelled" : "failed";
|
|
4406
|
+
pipelineError = err;
|
|
4407
|
+
} finally {
|
|
4408
|
+
cleanup();
|
|
4409
|
+
}
|
|
4410
|
+
const isSuccess = pipelineStatus === "completed";
|
|
4411
|
+
const result = {
|
|
4412
|
+
pipelineId: pipeline.id,
|
|
4413
|
+
success: isSuccess,
|
|
4414
|
+
status: pipelineStatus,
|
|
4415
|
+
stepResults: allStepResults,
|
|
4416
|
+
context,
|
|
4417
|
+
error: pipelineError,
|
|
4418
|
+
durationMs: Date.now() - startTime
|
|
4419
|
+
};
|
|
4420
|
+
const shouldThrow = options?.throwOnError ?? this.throwOnError;
|
|
4421
|
+
if (!isSuccess && shouldThrow) {
|
|
4422
|
+
throw pipelineError || new Error(`Action pipeline "${pipeline.id}" failed`);
|
|
4423
|
+
}
|
|
4424
|
+
return result;
|
|
4425
|
+
}
|
|
4426
|
+
/**
|
|
4427
|
+
* Executes an ordered list of ActionSteps sequentially.
|
|
4428
|
+
*/
|
|
4429
|
+
async executeSteps(steps, context, parentSignal, options) {
|
|
4430
|
+
const results = [];
|
|
4431
|
+
for (const step of steps) {
|
|
4432
|
+
if (parentSignal.aborted) {
|
|
4433
|
+
const cancelError = normalizeAbortError(parentSignal.reason, step.id);
|
|
4434
|
+
const cancelledResult = {
|
|
4435
|
+
stepId: step.id,
|
|
4436
|
+
stepType: step.type,
|
|
4437
|
+
status: "cancelled",
|
|
4438
|
+
error: cancelError,
|
|
4439
|
+
durationMs: 0
|
|
4440
|
+
};
|
|
4441
|
+
results.push(cancelledResult);
|
|
4442
|
+
context.stepResults[step.id] = cancelledResult;
|
|
4443
|
+
return { success: false, results, error: cancelError };
|
|
4444
|
+
}
|
|
4445
|
+
const stepResult = await this.executeSingleStep(step, context, parentSignal, options);
|
|
4446
|
+
results.push(stepResult);
|
|
4447
|
+
context.stepResults[step.id] = stepResult;
|
|
4448
|
+
if (stepResult.status === "error" || stepResult.status === "cancelled") {
|
|
4449
|
+
if (!step.continueOnError) {
|
|
4450
|
+
return { success: false, results, error: stepResult.error };
|
|
4451
|
+
}
|
|
4452
|
+
}
|
|
4453
|
+
}
|
|
4454
|
+
return { success: true, results };
|
|
4455
|
+
}
|
|
4456
|
+
/**
|
|
4457
|
+
* Executes a single ActionStep with condition checking, payload interpolation, timeout,
|
|
4458
|
+
* handler execution, response context passing, and branch execution.
|
|
4459
|
+
*/
|
|
4460
|
+
async executeSingleStep(step, context, parentSignal, options) {
|
|
4461
|
+
const stepStartTime = Date.now();
|
|
4462
|
+
if (step.condition && !evaluateActionCondition(step.condition, context)) {
|
|
4463
|
+
const skippedResult = {
|
|
4464
|
+
stepId: step.id,
|
|
4465
|
+
stepType: step.type,
|
|
4466
|
+
status: "skipped",
|
|
4467
|
+
durationMs: Date.now() - stepStartTime
|
|
4468
|
+
};
|
|
4469
|
+
options?.onStepComplete?.(step, skippedResult, context);
|
|
4470
|
+
return skippedResult;
|
|
4471
|
+
}
|
|
4472
|
+
options?.onStepStart?.(step, context);
|
|
4473
|
+
const stepTimeout = step.timeout;
|
|
4474
|
+
const { signal: stepSignal, cleanup: cleanupStepSignal } = createTimeoutAbortSignal(
|
|
4475
|
+
parentSignal,
|
|
4476
|
+
stepTimeout,
|
|
4477
|
+
`Step "${step.id}" timed out after ${stepTimeout}ms`,
|
|
4478
|
+
step.id
|
|
4479
|
+
);
|
|
4480
|
+
const rawPayload = step.payload || {};
|
|
4481
|
+
const interpolatedPayload = interpolateValue(rawPayload, context) || {};
|
|
4482
|
+
const resolvedStep = {
|
|
4483
|
+
...step,
|
|
4484
|
+
payload: interpolatedPayload
|
|
4485
|
+
};
|
|
4486
|
+
const customHandler = options?.handlers?.[step.type];
|
|
4487
|
+
const handler = customHandler || this.getHandler(step.type);
|
|
4488
|
+
let stepOutput;
|
|
4489
|
+
let stepError;
|
|
4490
|
+
let stepStatus = "success";
|
|
4491
|
+
const subResults = [];
|
|
4492
|
+
try {
|
|
4493
|
+
if (!handler) {
|
|
4494
|
+
throw new Error(`No handler registered for action step type: "${step.type}"`);
|
|
4495
|
+
}
|
|
4496
|
+
if (stepSignal.aborted) {
|
|
4497
|
+
throw normalizeAbortError(stepSignal.reason, step.id);
|
|
4498
|
+
}
|
|
4499
|
+
stepOutput = await handler(resolvedStep, context, stepSignal);
|
|
4500
|
+
if (stepOutput !== void 0) {
|
|
4501
|
+
context.response = stepOutput;
|
|
4502
|
+
}
|
|
4503
|
+
delete context.lastError;
|
|
4504
|
+
if (interpolatedPayload.responseMapping && typeof interpolatedPayload.responseMapping === "object") {
|
|
4505
|
+
const mapping = interpolatedPayload.responseMapping;
|
|
4506
|
+
for (const [targetVar, sourcePath] of Object.entries(mapping)) {
|
|
4507
|
+
const evalContext = {
|
|
4508
|
+
...context,
|
|
4509
|
+
response: stepOutput !== void 0 ? stepOutput : context.response
|
|
4510
|
+
};
|
|
4511
|
+
const cleanPath = String(sourcePath).replace(/^\{\{\s*/, "").replace(/\s*\}\}$/, "").trim();
|
|
4512
|
+
const mappedVal = resolvePropertyPath(evalContext, cleanPath, void 0);
|
|
4513
|
+
if (mappedVal !== void 0) {
|
|
4514
|
+
if (!context.variables) context.variables = {};
|
|
4515
|
+
context.variables[targetVar] = mappedVal;
|
|
4516
|
+
}
|
|
4517
|
+
}
|
|
4518
|
+
}
|
|
4519
|
+
if (step.onSuccess && Array.isArray(step.onSuccess) && step.onSuccess.length > 0) {
|
|
4520
|
+
const successBranch = await this.executeSteps(
|
|
4521
|
+
step.onSuccess,
|
|
4522
|
+
context,
|
|
4523
|
+
stepSignal,
|
|
4524
|
+
options
|
|
4525
|
+
);
|
|
4526
|
+
subResults.push(...successBranch.results);
|
|
4527
|
+
if (!successBranch.success) {
|
|
4528
|
+
stepStatus = "error";
|
|
4529
|
+
stepError = successBranch.error;
|
|
4530
|
+
}
|
|
4531
|
+
}
|
|
4532
|
+
} catch (err) {
|
|
4533
|
+
stepError = err;
|
|
4534
|
+
stepStatus = stepSignal.aborted ? "cancelled" : "error";
|
|
4535
|
+
context.lastError = err;
|
|
4536
|
+
context.error = err;
|
|
4537
|
+
if (step.onError && Array.isArray(step.onError) && step.onError.length > 0) {
|
|
4538
|
+
try {
|
|
4539
|
+
const errorBranch = await this.executeSteps(
|
|
4540
|
+
step.onError,
|
|
4541
|
+
context,
|
|
4542
|
+
parentSignal,
|
|
4543
|
+
// Use parent signal so error branch can run even if step timed out
|
|
4544
|
+
options
|
|
4545
|
+
);
|
|
4546
|
+
subResults.push(...errorBranch.results);
|
|
4547
|
+
} catch (onErrorErr) {
|
|
4548
|
+
}
|
|
4549
|
+
}
|
|
4550
|
+
} finally {
|
|
4551
|
+
cleanupStepSignal();
|
|
4552
|
+
}
|
|
4553
|
+
const result = {
|
|
4554
|
+
stepId: step.id,
|
|
4555
|
+
stepType: step.type,
|
|
4556
|
+
status: stepStatus,
|
|
4557
|
+
data: stepOutput,
|
|
4558
|
+
error: stepError,
|
|
4559
|
+
durationMs: Date.now() - stepStartTime,
|
|
4560
|
+
...subResults.length > 0 ? { subResults } : {}
|
|
4561
|
+
};
|
|
4562
|
+
options?.onStepComplete?.(step, result, context);
|
|
4563
|
+
return result;
|
|
4564
|
+
}
|
|
4565
|
+
};
|
|
4566
|
+
async function executeActionPipeline(pipeline, options) {
|
|
4567
|
+
const executor = new ActionPipelineExecutor();
|
|
4568
|
+
return executor.execute(pipeline, options);
|
|
4569
|
+
}
|
|
4570
|
+
|
|
4571
|
+
// src/state-store.ts
|
|
4572
|
+
var FORBIDDEN_KEY_SEGMENTS4 = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
4573
|
+
function createDefaultFormState(initialValues) {
|
|
4574
|
+
const init = initialValues ? { ...initialValues } : {};
|
|
4575
|
+
return {
|
|
4576
|
+
values: { ...init },
|
|
4577
|
+
errors: {},
|
|
4578
|
+
touched: {},
|
|
4579
|
+
isSubmitting: false,
|
|
4580
|
+
isValid: true,
|
|
4581
|
+
dirty: false,
|
|
4582
|
+
initialValues: { ...init }
|
|
4583
|
+
};
|
|
4584
|
+
}
|
|
4585
|
+
function cloneState(obj) {
|
|
4586
|
+
if (obj === null || typeof obj !== "object") {
|
|
4587
|
+
return obj;
|
|
4588
|
+
}
|
|
4589
|
+
if (Array.isArray(obj)) {
|
|
4590
|
+
return obj.map((item) => cloneState(item));
|
|
4591
|
+
}
|
|
4592
|
+
const copy = {};
|
|
4593
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
4594
|
+
if (!FORBIDDEN_KEY_SEGMENTS4.has(k)) {
|
|
4595
|
+
copy[k] = cloneState(v);
|
|
4596
|
+
}
|
|
4597
|
+
}
|
|
4598
|
+
return copy;
|
|
4599
|
+
}
|
|
4600
|
+
function setNestedPath(target, path, value) {
|
|
4601
|
+
if (!path || typeof path !== "string" || !target || typeof target !== "object") {
|
|
4602
|
+
return false;
|
|
4603
|
+
}
|
|
4604
|
+
const normalized = path.replace(/\[(\d+)\]/g, ".$1");
|
|
4605
|
+
const segments = normalized.split(".").map((s) => s.trim()).filter(Boolean);
|
|
4606
|
+
if (segments.length === 0) return false;
|
|
4607
|
+
let current = target;
|
|
4608
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
4609
|
+
const seg = segments[i];
|
|
4610
|
+
if (FORBIDDEN_KEY_SEGMENTS4.has(seg)) return false;
|
|
4611
|
+
if (current[seg] === void 0 || current[seg] === null || typeof current[seg] !== "object") {
|
|
4612
|
+
current[seg] = {};
|
|
4613
|
+
}
|
|
4614
|
+
current = current[seg];
|
|
4615
|
+
}
|
|
4616
|
+
const lastSeg = segments[segments.length - 1];
|
|
4617
|
+
if (FORBIDDEN_KEY_SEGMENTS4.has(lastSeg)) return false;
|
|
4618
|
+
current[lastSeg] = value;
|
|
4619
|
+
return true;
|
|
4620
|
+
}
|
|
4621
|
+
function deleteNestedPath(target, path) {
|
|
4622
|
+
if (!path || typeof path !== "string" || !target || typeof target !== "object") {
|
|
4623
|
+
return false;
|
|
4624
|
+
}
|
|
4625
|
+
const normalized = path.replace(/\[(\d+)\]/g, ".$1");
|
|
4626
|
+
const segments = normalized.split(".").map((s) => s.trim()).filter(Boolean);
|
|
4627
|
+
if (segments.length === 0) return false;
|
|
4628
|
+
let current = target;
|
|
4629
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
4630
|
+
const seg = segments[i];
|
|
4631
|
+
if (FORBIDDEN_KEY_SEGMENTS4.has(seg) || !(seg in current) || typeof current[seg] !== "object") {
|
|
4632
|
+
return false;
|
|
4633
|
+
}
|
|
4634
|
+
current = current[seg];
|
|
4635
|
+
}
|
|
4636
|
+
const lastSeg = segments[segments.length - 1];
|
|
4637
|
+
if (FORBIDDEN_KEY_SEGMENTS4.has(lastSeg) || !(lastSeg in current)) {
|
|
4638
|
+
return false;
|
|
4639
|
+
}
|
|
4640
|
+
delete current[lastSeg];
|
|
4641
|
+
return true;
|
|
4642
|
+
}
|
|
4643
|
+
var RuntimeStateStore = class _RuntimeStateStore {
|
|
4644
|
+
state;
|
|
4645
|
+
listeners = /* @__PURE__ */ new Set();
|
|
4646
|
+
pathListeners = /* @__PURE__ */ new Map();
|
|
4647
|
+
formListeners = /* @__PURE__ */ new Map();
|
|
4648
|
+
isBatching = false;
|
|
4649
|
+
batchOldState;
|
|
4650
|
+
isNotifying = false;
|
|
4651
|
+
constructor(initialState) {
|
|
4652
|
+
this.state = {
|
|
4653
|
+
variables: initialState?.variables ? { ...initialState.variables } : {},
|
|
4654
|
+
forms: initialState?.forms ? cloneState(initialState.forms) : {},
|
|
4655
|
+
state: initialState?.state ? { ...initialState.state } : {},
|
|
4656
|
+
...initialState
|
|
4657
|
+
};
|
|
4658
|
+
}
|
|
4659
|
+
/**
|
|
4660
|
+
* Retrieves a value at a specified path or the entire state snapshot.
|
|
4661
|
+
*/
|
|
4662
|
+
get(path, fallback) {
|
|
4663
|
+
if (!path || path.trim() === "") {
|
|
4664
|
+
return this.getSnapshot();
|
|
4665
|
+
}
|
|
4666
|
+
const cleanPath = path.replace(/^\{\{\s*/, "").replace(/\s*\}\}$/, "").trim();
|
|
4667
|
+
const resolved = resolvePropertyPath(this.state, cleanPath, fallback);
|
|
4668
|
+
return resolved;
|
|
4669
|
+
}
|
|
4670
|
+
/**
|
|
4671
|
+
* Gets an immutable snapshot of the current state.
|
|
4672
|
+
*/
|
|
4673
|
+
getSnapshot() {
|
|
4674
|
+
return cloneState(this.state);
|
|
4675
|
+
}
|
|
4676
|
+
/**
|
|
4677
|
+
* Sets a value at a dotted path and notifies subscribers.
|
|
4678
|
+
*/
|
|
4679
|
+
set(path, value) {
|
|
4680
|
+
if (!path) return this;
|
|
4681
|
+
const oldState = this.isBatching ? void 0 : cloneState(this.state);
|
|
4682
|
+
const cleanPath = path.replace(/^\{\{\s*/, "").replace(/\s*\}\}$/, "").trim();
|
|
4683
|
+
const success = setNestedPath(this.state, cleanPath, value);
|
|
4684
|
+
if (!success) return this;
|
|
4685
|
+
if (!this.isBatching && oldState) {
|
|
4686
|
+
this.notifyChanges(oldState, this.state);
|
|
4687
|
+
}
|
|
4688
|
+
return this;
|
|
4689
|
+
}
|
|
4690
|
+
/**
|
|
4691
|
+
* Performs multiple updates atomically, triggering subscriber notifications once.
|
|
4692
|
+
*/
|
|
4693
|
+
setBatch(updates) {
|
|
4694
|
+
if (!updates || typeof updates !== "object") return this;
|
|
4695
|
+
const oldState = this.batchOldState || cloneState(this.state);
|
|
4696
|
+
this.isBatching = true;
|
|
4697
|
+
this.batchOldState = oldState;
|
|
4698
|
+
try {
|
|
4699
|
+
for (const [path, value] of Object.entries(updates)) {
|
|
4700
|
+
this.set(path, value);
|
|
4701
|
+
}
|
|
4702
|
+
} finally {
|
|
4703
|
+
this.isBatching = false;
|
|
4704
|
+
this.batchOldState = void 0;
|
|
4705
|
+
this.notifyChanges(oldState, this.state);
|
|
4706
|
+
}
|
|
4707
|
+
return this;
|
|
4708
|
+
}
|
|
4709
|
+
/**
|
|
4710
|
+
* Deletes a property at the specified path.
|
|
4711
|
+
*/
|
|
4712
|
+
delete(path) {
|
|
4713
|
+
if (!path) return false;
|
|
4714
|
+
const oldState = this.isBatching ? void 0 : cloneState(this.state);
|
|
4715
|
+
const cleanPath = path.replace(/^\{\{\s*/, "").replace(/\s*\}\}$/, "").trim();
|
|
4716
|
+
const deleted = deleteNestedPath(this.state, cleanPath);
|
|
4717
|
+
if (deleted && !this.isBatching && oldState) {
|
|
4718
|
+
this.notifyChanges(oldState, this.state);
|
|
4719
|
+
}
|
|
4720
|
+
return deleted;
|
|
4721
|
+
}
|
|
4722
|
+
/**
|
|
4723
|
+
* Resets the store state to an initial or clean state.
|
|
4724
|
+
*/
|
|
4725
|
+
reset(initialState) {
|
|
4726
|
+
const oldState = cloneState(this.state);
|
|
4727
|
+
this.state = {
|
|
4728
|
+
variables: initialState?.variables ? { ...initialState.variables } : {},
|
|
4729
|
+
forms: initialState?.forms ? cloneState(initialState.forms) : {},
|
|
4730
|
+
state: initialState?.state ? { ...initialState.state } : {},
|
|
4731
|
+
...initialState
|
|
4732
|
+
};
|
|
4733
|
+
this.notifyChanges(oldState, this.state);
|
|
4734
|
+
return this;
|
|
4735
|
+
}
|
|
4736
|
+
/**
|
|
4737
|
+
* Subscribes a listener to any state changes.
|
|
4738
|
+
*/
|
|
4739
|
+
subscribe(listener) {
|
|
4740
|
+
this.listeners.add(listener);
|
|
4741
|
+
return () => {
|
|
4742
|
+
this.listeners.delete(listener);
|
|
4743
|
+
};
|
|
4744
|
+
}
|
|
4745
|
+
/**
|
|
4746
|
+
* Subscribes a listener to changes on a top-level key.
|
|
4747
|
+
*/
|
|
4748
|
+
subscribeKey(key, listener) {
|
|
4749
|
+
return this.subscribePath(key, listener);
|
|
4750
|
+
}
|
|
4751
|
+
/**
|
|
4752
|
+
* Subscribes a listener to changes at a specific dotted path.
|
|
4753
|
+
*/
|
|
4754
|
+
subscribePath(path, listener) {
|
|
4755
|
+
const cleanPath = path.replace(/^\{\{\s*/, "").replace(/\s*\}\}$/, "").trim();
|
|
4756
|
+
if (!this.pathListeners.has(cleanPath)) {
|
|
4757
|
+
this.pathListeners.set(cleanPath, /* @__PURE__ */ new Set());
|
|
4758
|
+
}
|
|
4759
|
+
const set = this.pathListeners.get(cleanPath);
|
|
4760
|
+
set.add(listener);
|
|
4761
|
+
return () => {
|
|
4762
|
+
set.delete(listener);
|
|
4763
|
+
if (set.size === 0) {
|
|
4764
|
+
this.pathListeners.delete(cleanPath);
|
|
4765
|
+
}
|
|
4766
|
+
};
|
|
4767
|
+
}
|
|
4768
|
+
/**
|
|
4769
|
+
* Subscribes a listener to changes of a specific form state.
|
|
4770
|
+
*/
|
|
4771
|
+
subscribeForm(formId, listener) {
|
|
4772
|
+
if (!this.formListeners.has(formId)) {
|
|
4773
|
+
this.formListeners.set(formId, /* @__PURE__ */ new Set());
|
|
4774
|
+
}
|
|
4775
|
+
const set = this.formListeners.get(formId);
|
|
4776
|
+
set.add(listener);
|
|
4777
|
+
return () => {
|
|
4778
|
+
set.delete(listener);
|
|
4779
|
+
if (set.size === 0) {
|
|
4780
|
+
this.formListeners.delete(formId);
|
|
4781
|
+
}
|
|
4782
|
+
};
|
|
4783
|
+
}
|
|
4784
|
+
/**
|
|
4785
|
+
* Notifies all relevant listeners when state changes.
|
|
4786
|
+
*/
|
|
4787
|
+
notifyChanges(oldState, newState) {
|
|
4788
|
+
if (this.isNotifying) return;
|
|
4789
|
+
this.isNotifying = true;
|
|
4790
|
+
try {
|
|
4791
|
+
const readOnlyNew = Object.freeze(cloneState(newState));
|
|
4792
|
+
const readOnlyOld = Object.freeze(cloneState(oldState));
|
|
4793
|
+
for (const listener of this.listeners) {
|
|
4794
|
+
try {
|
|
4795
|
+
listener(readOnlyNew, readOnlyOld);
|
|
4796
|
+
} catch {
|
|
4797
|
+
}
|
|
4798
|
+
}
|
|
4799
|
+
for (const [path, listeners] of this.pathListeners.entries()) {
|
|
4800
|
+
const oldVal = resolvePropertyPath(oldState, path, void 0);
|
|
4801
|
+
const newVal = resolvePropertyPath(newState, path, void 0);
|
|
4802
|
+
if (oldVal !== newVal) {
|
|
4803
|
+
for (const listener of listeners) {
|
|
4804
|
+
try {
|
|
4805
|
+
listener(newVal, oldVal);
|
|
4806
|
+
} catch {
|
|
4807
|
+
}
|
|
4808
|
+
}
|
|
4809
|
+
}
|
|
4810
|
+
}
|
|
4811
|
+
for (const [formId, listeners] of this.formListeners.entries()) {
|
|
4812
|
+
const oldForm = oldState.forms?.[formId];
|
|
4813
|
+
const newForm = newState.forms?.[formId];
|
|
4814
|
+
if (oldForm !== newForm) {
|
|
4815
|
+
for (const listener of listeners) {
|
|
4816
|
+
try {
|
|
4817
|
+
listener(newForm || createDefaultFormState(), oldForm);
|
|
4818
|
+
} catch {
|
|
4819
|
+
}
|
|
4820
|
+
}
|
|
4821
|
+
}
|
|
4822
|
+
}
|
|
4823
|
+
} finally {
|
|
4824
|
+
this.isNotifying = false;
|
|
4825
|
+
}
|
|
4826
|
+
}
|
|
4827
|
+
// ==========================================
|
|
4828
|
+
// Form State Management Helpers
|
|
4829
|
+
// ==========================================
|
|
4830
|
+
/**
|
|
4831
|
+
* Retrieves the FormState for a formId, initializing default form state if not present.
|
|
4832
|
+
*/
|
|
4833
|
+
getForm(formId) {
|
|
4834
|
+
if (!this.state.forms[formId]) {
|
|
4835
|
+
this.state.forms[formId] = createDefaultFormState();
|
|
4836
|
+
}
|
|
4837
|
+
return this.state.forms[formId];
|
|
4838
|
+
}
|
|
4839
|
+
/**
|
|
4840
|
+
* Updates a single field value in a form and marks dirty if changed from initial.
|
|
4841
|
+
*/
|
|
4842
|
+
setFormFieldValue(formId, fieldName, value) {
|
|
4843
|
+
const form = this.getForm(formId);
|
|
4844
|
+
const oldValues = { ...form.values };
|
|
4845
|
+
form.values[fieldName] = value;
|
|
4846
|
+
const initialVal = form.initialValues?.[fieldName];
|
|
4847
|
+
form.dirty = Object.keys(form.values).some((k) => form.values[k] !== form.initialValues?.[k]);
|
|
4848
|
+
this.set(`forms.${formId}.values.${fieldName}`, value);
|
|
4849
|
+
return this;
|
|
4850
|
+
}
|
|
4851
|
+
/**
|
|
4852
|
+
* Sets or clears an error for a form field.
|
|
4853
|
+
*/
|
|
4854
|
+
setFormFieldError(formId, fieldName, error) {
|
|
4855
|
+
const form = this.getForm(formId);
|
|
4856
|
+
if (error) {
|
|
4857
|
+
form.errors[fieldName] = error;
|
|
4858
|
+
} else {
|
|
4859
|
+
delete form.errors[fieldName];
|
|
4860
|
+
}
|
|
4861
|
+
form.isValid = Object.keys(form.errors).length === 0;
|
|
4862
|
+
this.set(`forms.${formId}.errors`, { ...form.errors });
|
|
4863
|
+
this.set(`forms.${formId}.isValid`, form.isValid);
|
|
4864
|
+
return this;
|
|
4865
|
+
}
|
|
4866
|
+
/**
|
|
4867
|
+
* Marks a form field as touched (or untouched).
|
|
4868
|
+
*/
|
|
4869
|
+
setFormFieldTouched(formId, fieldName, touched = true) {
|
|
4870
|
+
const form = this.getForm(formId);
|
|
4871
|
+
form.touched[fieldName] = touched;
|
|
4872
|
+
this.set(`forms.${formId}.touched.${fieldName}`, touched);
|
|
4873
|
+
return this;
|
|
4874
|
+
}
|
|
4875
|
+
/**
|
|
4876
|
+
* Updates multiple form errors simultaneously.
|
|
4877
|
+
*/
|
|
4878
|
+
setFormErrors(formId, errors) {
|
|
4879
|
+
const form = this.getForm(formId);
|
|
4880
|
+
form.errors = { ...errors };
|
|
4881
|
+
form.isValid = Object.keys(errors).length === 0;
|
|
4882
|
+
this.set(`forms.${formId}.errors`, form.errors);
|
|
4883
|
+
this.set(`forms.${formId}.isValid`, form.isValid);
|
|
4884
|
+
return this;
|
|
4885
|
+
}
|
|
4886
|
+
/**
|
|
4887
|
+
* Sets multiple form field values simultaneously.
|
|
4888
|
+
*/
|
|
4889
|
+
setFormValues(formId, values, replace = false) {
|
|
4890
|
+
const form = this.getForm(formId);
|
|
4891
|
+
form.values = replace ? { ...values } : { ...form.values, ...values };
|
|
4892
|
+
form.dirty = Object.keys(form.values).some((k) => form.values[k] !== form.initialValues?.[k]);
|
|
4893
|
+
this.set(`forms.${formId}.values`, { ...form.values });
|
|
4894
|
+
this.set(`forms.${formId}.dirty`, form.dirty);
|
|
4895
|
+
return this;
|
|
4896
|
+
}
|
|
4897
|
+
/**
|
|
4898
|
+
* Sets the submitting status of a form.
|
|
4899
|
+
*/
|
|
4900
|
+
setFormSubmitting(formId, isSubmitting) {
|
|
4901
|
+
const form = this.getForm(formId);
|
|
4902
|
+
form.isSubmitting = isSubmitting;
|
|
4903
|
+
this.set(`forms.${formId}.isSubmitting`, isSubmitting);
|
|
4904
|
+
return this;
|
|
4905
|
+
}
|
|
4906
|
+
/**
|
|
4907
|
+
* Resets a form's values, errors, touched, and submitting state to defaults or specified values.
|
|
4908
|
+
*/
|
|
4909
|
+
resetForm(formId, initialValues) {
|
|
4910
|
+
const newFormState = createDefaultFormState(
|
|
4911
|
+
initialValues || this.state.forms[formId]?.initialValues
|
|
4912
|
+
);
|
|
4913
|
+
this.set(`forms.${formId}`, newFormState);
|
|
4914
|
+
return this;
|
|
4915
|
+
}
|
|
4916
|
+
// ==========================================
|
|
4917
|
+
// Scoping & Isolation
|
|
4918
|
+
// ==========================================
|
|
4919
|
+
/**
|
|
4920
|
+
* Creates an isolated child scope store for a page or component container.
|
|
4921
|
+
*/
|
|
4922
|
+
createScope(scopeId, initialValues) {
|
|
4923
|
+
const scopedState = {
|
|
4924
|
+
variables: { ...initialValues || {} },
|
|
4925
|
+
forms: {},
|
|
4926
|
+
state: {}
|
|
4927
|
+
};
|
|
4928
|
+
return new _RuntimeStateStore(scopedState);
|
|
4929
|
+
}
|
|
4930
|
+
};
|
|
4931
|
+
function createRuntimeStore(initialState) {
|
|
4932
|
+
return new RuntimeStateStore(initialState);
|
|
4933
|
+
}
|
|
3649
4934
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3650
4935
|
0 && (module.exports = {
|
|
4936
|
+
ActionCancellationError,
|
|
4937
|
+
ActionPipelineExecutor,
|
|
4938
|
+
ActionTimeoutError,
|
|
3651
4939
|
CORE_BUILTIN_COMPONENTS,
|
|
3652
4940
|
DEFAULT_DOCUMENT_SECURITY_LIMITS,
|
|
3653
4941
|
DEFAULT_MAX_HISTORY,
|
|
@@ -3655,6 +4943,8 @@ function areNodeIdsCompletelyDistinct(docA, docB) {
|
|
|
3655
4943
|
DocumentHistoryManager,
|
|
3656
4944
|
HistoryEngine,
|
|
3657
4945
|
MigrationRegistry,
|
|
4946
|
+
RuntimeStateStore,
|
|
4947
|
+
applyFieldTransform,
|
|
3658
4948
|
areNodeIdsCompletelyDistinct,
|
|
3659
4949
|
buildSampleVariablesFromCatalog,
|
|
3660
4950
|
calculateChecksum,
|
|
@@ -3668,16 +4958,26 @@ function areNodeIdsCompletelyDistinct(docA, docB) {
|
|
|
3668
4958
|
compareManifestsSemantically,
|
|
3669
4959
|
containsProhibitedKeys,
|
|
3670
4960
|
createBlankDocument,
|
|
4961
|
+
createDefaultFormState,
|
|
4962
|
+
createRuntimeStore,
|
|
3671
4963
|
createTemplateRecord,
|
|
3672
4964
|
deepClone,
|
|
3673
4965
|
defaultIdGenerator,
|
|
3674
4966
|
defaultMigrationRegistry,
|
|
3675
4967
|
defaultRenameAssetStrategy,
|
|
3676
4968
|
duplicateNode,
|
|
4969
|
+
evaluateActionCondition,
|
|
4970
|
+
evaluateCondition,
|
|
4971
|
+
evaluateConditionGroup,
|
|
4972
|
+
evaluateConditions,
|
|
4973
|
+
evaluateOperator,
|
|
4974
|
+
evaluateRule,
|
|
4975
|
+
executeActionPipeline,
|
|
3677
4976
|
exportPackage,
|
|
3678
4977
|
exportStoraPackage,
|
|
3679
4978
|
extractRequirementsFromTree,
|
|
3680
4979
|
extractTemplateRequirements,
|
|
4980
|
+
extractTemplateVariables,
|
|
3681
4981
|
findMissingComponentNodes,
|
|
3682
4982
|
findNodeById,
|
|
3683
4983
|
findNodeLocation,
|
|
@@ -3686,14 +4986,21 @@ function areNodeIdsCompletelyDistinct(docA, docB) {
|
|
|
3686
4986
|
getNavigationTarget,
|
|
3687
4987
|
getNodeAncestors,
|
|
3688
4988
|
getParentNodeId,
|
|
4989
|
+
hasTemplateExpressions,
|
|
3689
4990
|
importPackage,
|
|
3690
4991
|
importStoraPackage,
|
|
3691
4992
|
insertNode,
|
|
3692
4993
|
inspectPackage,
|
|
4994
|
+
interpolateTemplateString,
|
|
4995
|
+
interpolateValue,
|
|
4996
|
+
isConditionGroup,
|
|
3693
4997
|
isDangerousAssetFilename,
|
|
3694
4998
|
isDangerousPath,
|
|
3695
4999
|
isDescendantOf,
|
|
5000
|
+
isEmptyValue,
|
|
5001
|
+
isFormValid,
|
|
3696
5002
|
isSafeUrl,
|
|
5003
|
+
isValueEmpty,
|
|
3697
5004
|
migrateDocument,
|
|
3698
5005
|
moveNode,
|
|
3699
5006
|
preflightPackage,
|
|
@@ -3703,16 +5010,23 @@ function areNodeIdsCompletelyDistinct(docA, docB) {
|
|
|
3703
5010
|
removeNode,
|
|
3704
5011
|
resolveBinding,
|
|
3705
5012
|
resolveBindingValue,
|
|
5013
|
+
resolvePropertyPath,
|
|
3706
5014
|
sanitizeFilename,
|
|
3707
5015
|
sanitizeHtml,
|
|
3708
5016
|
sanitizeUrl,
|
|
3709
5017
|
saveDraftAsTemplate,
|
|
3710
5018
|
sha256Sync,
|
|
5019
|
+
updateActions,
|
|
3711
5020
|
updateAnimation,
|
|
5021
|
+
updateFormConfig,
|
|
3712
5022
|
updateProps,
|
|
3713
5023
|
updateStyle,
|
|
3714
5024
|
validateDocument,
|
|
3715
5025
|
validateDocumentSecurity,
|
|
5026
|
+
validateFieldValue,
|
|
5027
|
+
validateFieldValueAsync,
|
|
5028
|
+
validateForm,
|
|
5029
|
+
validateFormAsync,
|
|
3716
5030
|
validateTemplate
|
|
3717
5031
|
});
|
|
3718
5032
|
//# sourceMappingURL=index.cjs.map
|