@syntrologie/runtime-sdk 2.0.0 → 2.0.1-canary.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/CAPABILITIES.md +232 -138
- package/README.md +76 -57
- package/dist/RuntimeProvider.d.ts +6 -6
- package/dist/RuntimeProvider.js +2 -3
- package/dist/RuntimeProvider.js.map +1 -1
- package/dist/SmartCanvasApp.d.ts +8 -8
- package/dist/SmartCanvasApp.js +16 -18
- package/dist/SmartCanvasApp.js.map +1 -1
- package/dist/SmartCanvasElement.d.ts +5 -5
- package/dist/SmartCanvasElement.js +13 -13
- package/dist/SmartCanvasElement.js.map +1 -1
- package/dist/SmartCanvasPortal.d.ts +2 -2
- package/dist/SmartCanvasPortal.js +2 -2
- package/dist/actions/ActionEngine.d.ts +1 -1
- package/dist/actions/ActionEngine.js +24 -24
- package/dist/actions/ActionEngine.js.map +1 -1
- package/dist/actions/executors/index.d.ts +6 -6
- package/dist/actions/executors/index.js +22 -22
- package/dist/actions/executors/index.js.map +1 -1
- package/dist/actions/executors/tour.d.ts +1 -1
- package/dist/actions/executors/tour.js +19 -19
- package/dist/actions/executors/tour.js.map +1 -1
- package/dist/actions/index.d.ts +5 -5
- package/dist/actions/index.js +3 -3
- package/dist/actions/index.js.map +1 -1
- package/dist/actions/types.d.ts +37 -37
- package/dist/actions/validation.d.ts +1 -1
- package/dist/actions/validation.js +195 -196
- package/dist/actions/validation.js.map +1 -1
- package/dist/antiFlicker.js +1 -1
- package/dist/api.d.ts +10 -10
- package/dist/api.js +11 -11
- package/dist/api.js.map +1 -1
- package/dist/apps/AppContext.d.ts +2 -2
- package/dist/apps/AppContext.js +1 -1
- package/dist/apps/AppContext.js.map +1 -1
- package/dist/apps/AppLoader.d.ts +2 -2
- package/dist/apps/AppLoader.js +24 -24
- package/dist/apps/AppLoader.js.map +1 -1
- package/dist/apps/AppRegistry.d.ts +2 -2
- package/dist/apps/AppRegistry.js +28 -28
- package/dist/apps/AppRegistry.js.map +1 -1
- package/dist/apps/adaptive-chatbot/index.js +7 -0
- package/dist/apps/adaptive-chatbot/index.js.map +7 -0
- package/dist/apps/examples/gamification-app.example.d.ts +3 -3
- package/dist/apps/examples/gamification-app.example.js +94 -94
- package/dist/apps/examples/gamification-app.example.js.map +1 -1
- package/dist/apps/faq/index.js.map +3 -3
- package/dist/apps/gamification/index.js.map +3 -3
- package/dist/apps/index.d.ts +10 -10
- package/dist/apps/index.js +6 -6
- package/dist/apps/nav/index.js.map +3 -3
- package/dist/apps/types.d.ts +10 -10
- package/dist/blocks/data/ComparisonBlock.d.ts +1 -1
- package/dist/blocks/data/ComparisonBlock.js +40 -40
- package/dist/blocks/data/ComparisonBlock.js.map +1 -1
- package/dist/blocks/data/StatsBlock.d.ts +1 -1
- package/dist/blocks/data/StatsBlock.js +41 -41
- package/dist/blocks/data/StatsBlock.js.map +1 -1
- package/dist/blocks/data/index.d.ts +2 -2
- package/dist/blocks/data/index.js +2 -2
- package/dist/blocks/index.d.ts +5 -5
- package/dist/blocks/index.js +29 -29
- package/dist/blocks/index.js.map +1 -1
- package/dist/blocks/interactive/ChecklistBlock.d.ts +1 -1
- package/dist/blocks/interactive/ChecklistBlock.js +60 -60
- package/dist/blocks/interactive/ChecklistBlock.js.map +1 -1
- package/dist/blocks/interactive/RatingBlock.d.ts +1 -1
- package/dist/blocks/interactive/RatingBlock.js +75 -65
- package/dist/blocks/interactive/RatingBlock.js.map +1 -1
- package/dist/blocks/interactive/index.d.ts +2 -2
- package/dist/blocks/interactive/index.js +2 -2
- package/dist/blocks/notification/NotificationBlock.d.ts +2 -2
- package/dist/blocks/notification/NotificationBlock.js +67 -63
- package/dist/blocks/notification/NotificationBlock.js.map +1 -1
- package/dist/blocks/notification/index.d.ts +1 -1
- package/dist/blocks/notification/index.js +1 -1
- package/dist/bootstrap.d.ts +10 -10
- package/dist/bootstrap.js +54 -40
- package/dist/bootstrap.js.map +1 -1
- package/dist/components/ShadowCanvasOverlay.d.ts +6 -6
- package/dist/components/ShadowCanvasOverlay.js +117 -107
- package/dist/components/ShadowCanvasOverlay.js.map +1 -1
- package/dist/components/TileCard.d.ts +5 -5
- package/dist/components/TileCard.js +174 -143
- package/dist/components/TileCard.js.map +1 -1
- package/dist/components/TileWheel.d.ts +3 -3
- package/dist/components/TileWheel.js +7 -7
- package/dist/components/TileWheel.js.map +1 -1
- package/dist/configFetcher.d.ts +2 -2
- package/dist/configFetcher.js +10 -7
- package/dist/configFetcher.js.map +1 -1
- package/dist/context/ContextManager.d.ts +3 -3
- package/dist/context/ContextManager.js +15 -15
- package/dist/context/ContextManager.js.map +1 -1
- package/dist/context/index.d.ts +4 -4
- package/dist/context/index.js +3 -3
- package/dist/context/schema.d.ts +1 -1
- package/dist/context/schema.js +1 -1
- package/dist/decisions/engine.d.ts +5 -5
- package/dist/decisions/engine.js +13 -13
- package/dist/decisions/index.d.ts +6 -6
- package/dist/decisions/index.js +5 -5
- package/dist/decisions/schema.d.ts +1 -1
- package/dist/decisions/schema.js +20 -20
- package/dist/decisions/strategies/rules.d.ts +1 -1
- package/dist/decisions/strategies/rules.js +24 -24
- package/dist/decisions/strategies/rules.js.map +1 -1
- package/dist/decisions/strategies/score.d.ts +1 -1
- package/dist/decisions/strategies/score.js +3 -3
- package/dist/decisions/types.d.ts +19 -19
- package/dist/editorLoader.js +20 -20
- package/dist/editorLoader.js.map +1 -1
- package/dist/events/EventBus.d.ts +3 -3
- package/dist/events/EventBus.js +5 -7
- package/dist/events/EventBus.js.map +1 -1
- package/dist/events/index.d.ts +6 -6
- package/dist/events/index.js +5 -5
- package/dist/events/normalizers/canvas.d.ts +2 -2
- package/dist/events/normalizers/canvas.js +3 -3
- package/dist/events/normalizers/canvas.js.map +1 -1
- package/dist/events/normalizers/posthog.d.ts +1 -1
- package/dist/events/normalizers/posthog.js +34 -27
- package/dist/events/normalizers/posthog.js.map +1 -1
- package/dist/events/schema.d.ts +1 -1
- package/dist/events/schema.js +2 -2
- package/dist/events/types.d.ts +1 -1
- package/dist/events/types.js +27 -27
- package/dist/experiments/adapters/growthbook.d.ts +4 -4
- package/dist/experiments/adapters/growthbook.js +5 -5
- package/dist/experiments/adapters/growthbook.js.map +1 -1
- package/dist/experiments/index.d.ts +3 -3
- package/dist/experiments/index.js +1 -1
- package/dist/experiments/registry.d.ts +2 -2
- package/dist/experiments/registry.js +2 -2
- package/dist/experiments/types.d.ts +5 -1
- package/dist/fetchers/cdnFetcher.d.ts +1 -1
- package/dist/fetchers/cdnFetcher.js +4 -8
- package/dist/fetchers/cdnFetcher.js.map +1 -1
- package/dist/fetchers/experimentsFetcher.d.ts +2 -2
- package/dist/fetchers/experimentsFetcher.js +7 -7
- package/dist/fetchers/experimentsFetcher.js.map +1 -1
- package/dist/fetchers/index.d.ts +3 -3
- package/dist/fetchers/index.js +2 -2
- package/dist/fetchers/index.js.map +1 -1
- package/dist/fetchers/registry.d.ts +1 -1
- package/dist/fetchers/registry.js +4 -4
- package/dist/fetchers/types.d.ts +1 -1
- package/dist/hooks/useCanvasOverlays.d.ts +5 -5
- package/dist/hooks/useCanvasOverlays.js +15 -13
- package/dist/hooks/useCanvasOverlays.js.map +1 -1
- package/dist/hooks/useHostPatches.d.ts +2 -2
- package/dist/hooks/useHostPatches.js +8 -8
- package/dist/hooks/useHostPatches.js.map +1 -1
- package/dist/hooks/useShadowCanvasConfig.d.ts +3 -3
- package/dist/hooks/useShadowCanvasConfig.js +5 -2
- package/dist/hooks/useShadowCanvasConfig.js.map +1 -1
- package/dist/hostPatcher/core/patcher.d.ts +1 -1
- package/dist/hostPatcher/core/patcher.js +18 -9
- package/dist/hostPatcher/core/patcher.js.map +1 -1
- package/dist/hostPatcher/core/sanitizer.js +24 -3
- package/dist/hostPatcher/core/sanitizer.js.map +1 -1
- package/dist/hostPatcher/policy/defaultPolicy.js +15 -5
- package/dist/hostPatcher/policy/defaultPolicy.js.map +1 -1
- package/dist/hostPatcher/utils/anchors.js +4 -6
- package/dist/hostPatcher/utils/anchors.js.map +1 -1
- package/dist/index.d.ts +32 -32
- package/dist/index.js +29 -29
- package/dist/index.js.map +1 -1
- package/dist/metrics/index.d.ts +1 -1
- package/dist/metrics/index.js +1 -1
- package/dist/metrics/sessionMetrics.d.ts +1 -1
- package/dist/metrics/sessionMetrics.js +6 -6
- package/dist/overlays/fetcher.d.ts +2 -2
- package/dist/overlays/fetcher.js +4 -4
- package/dist/overlays/recipeRegistry.js +2 -2
- package/dist/overlays/recipeRegistry.js.map +1 -1
- package/dist/overlays/runtime/anchor/resolve.js +1 -1
- package/dist/overlays/runtime/anchor/resolve.js.map +1 -1
- package/dist/overlays/runtime/index.d.ts +7 -7
- package/dist/overlays/runtime/index.js +7 -7
- package/dist/overlays/runtime/overlay/highlight.js +39 -39
- package/dist/overlays/runtime/overlay/highlight.js.map +1 -1
- package/dist/overlays/runtime/overlay/modal.js +5 -5
- package/dist/overlays/runtime/overlay/modal.js.map +1 -1
- package/dist/overlays/runtime/overlay/root.js +1 -1
- package/dist/overlays/runtime/overlay/runner.js +70 -23
- package/dist/overlays/runtime/overlay/runner.js.map +1 -1
- package/dist/overlays/runtime/overlay/tooltip.d.ts +1 -1
- package/dist/overlays/runtime/overlay/tooltip.js +10 -10
- package/dist/overlays/runtime/overlay/tooltip.js.map +1 -1
- package/dist/overlays/runtime/utils/dom.js +4 -1
- package/dist/overlays/runtime/utils/dom.js.map +1 -1
- package/dist/overlays/schema.js +12 -8
- package/dist/overlays/schema.js.map +1 -1
- package/dist/react.d.ts +7 -7
- package/dist/react.js +4 -4
- package/dist/react.js.map +1 -1
- package/dist/render/RenderContext.d.ts +2 -2
- package/dist/render/RenderContext.js +5 -5
- package/dist/render/RenderContext.js.map +1 -1
- package/dist/render/index.d.ts +3 -3
- package/dist/render/index.js +1 -1
- package/dist/render/types.d.ts +4 -4
- package/dist/runtime.d.ts +12 -12
- package/dist/runtime.js +20 -20
- package/dist/runtime.js.map +1 -1
- package/dist/smart-canvas.esm.js +16 -16
- package/dist/smart-canvas.esm.js.map +4 -4
- package/dist/smart-canvas.js +644 -491
- package/dist/smart-canvas.js.map +4 -4
- package/dist/smart-canvas.min.js +15 -15
- package/dist/smart-canvas.min.js.map +4 -4
- package/dist/state/StateStore.d.ts +1 -1
- package/dist/state/StateStore.js +9 -9
- package/dist/state/StateStore.js.map +1 -1
- package/dist/state/helpers/cooldowns.d.ts +1 -1
- package/dist/state/helpers/cooldowns.js +1 -1
- package/dist/state/helpers/dismissals.d.ts +1 -1
- package/dist/state/helpers/dismissals.js +1 -1
- package/dist/state/helpers/frequency.d.ts +1 -1
- package/dist/state/helpers/frequency.js +1 -1
- package/dist/state/index.d.ts +4 -4
- package/dist/state/index.js +3 -3
- package/dist/state/schema.d.ts +1 -1
- package/dist/state/schema.js +1 -1
- package/dist/store/example.js +13 -13
- package/dist/store/example.js.map +1 -1
- package/dist/store/mini-effector.js +6 -8
- package/dist/store/mini-effector.js.map +1 -1
- package/dist/surfaces/Surfaces.d.ts +1 -1
- package/dist/surfaces/Surfaces.js +25 -25
- package/dist/surfaces/Surfaces.js.map +1 -1
- package/dist/surfaces/index.d.ts +4 -4
- package/dist/surfaces/index.js +3 -3
- package/dist/surfaces/positioning.d.ts +2 -2
- package/dist/surfaces/positioning.js +74 -77
- package/dist/surfaces/positioning.js.map +1 -1
- package/dist/surfaces/types.d.ts +9 -9
- package/dist/surfaces/types.js +7 -7
- package/dist/surfaces/types.js.map +1 -1
- package/dist/telemetry/adapters/noop.d.ts +12 -0
- package/dist/telemetry/adapters/noop.js +42 -0
- package/dist/telemetry/adapters/noop.js.map +1 -0
- package/dist/telemetry/adapters/posthog.d.ts +2 -2
- package/dist/telemetry/adapters/posthog.js +29 -16
- package/dist/telemetry/adapters/posthog.js.map +1 -1
- package/dist/telemetry/index.d.ts +4 -3
- package/dist/telemetry/index.js +3 -2
- package/dist/telemetry/index.js.map +1 -1
- package/dist/telemetry/registry.d.ts +2 -2
- package/dist/telemetry/registry.js +4 -2
- package/dist/telemetry/registry.js.map +1 -1
- package/dist/telemetry/types.d.ts +1 -1
- package/dist/theme/ThemeProvider.d.ts +2 -2
- package/dist/theme/ThemeProvider.js +21 -21
- package/dist/theme/ThemeProvider.js.map +1 -1
- package/dist/theme/defaultTheme.d.ts +2 -2
- package/dist/theme/defaultTheme.js +111 -111
- package/dist/theme/defaultTheme.js.map +1 -1
- package/dist/theme/extractHostTheme.d.ts +1 -1
- package/dist/theme/extractHostTheme.js +42 -44
- package/dist/theme/extractHostTheme.js.map +1 -1
- package/dist/theme/index.d.ts +5 -5
- package/dist/theme/index.js +3 -3
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/types.d.ts +2 -2
- package/dist/token.js +3 -6
- package/dist/token.js.map +1 -1
- package/dist/types-only.d.ts +1 -1
- package/dist/types.d.ts +43 -43
- package/dist/widgets/WidgetRegistry.d.ts +2 -2
- package/dist/widgets/WidgetRegistry.js +11 -11
- package/dist/widgets/WidgetRegistry.js.map +1 -1
- package/dist/widgets/index.d.ts +2 -2
- package/dist/widgets/index.js +1 -1
- package/dist/widgets/index.js.map +1 -1
- package/package.json +4 -2
- package/schema/canvas-config.schema.json +51 -7
- package/schema/runtime-context.schema.json +1 -5
|
@@ -3,41 +3,41 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Validates action steps before execution.
|
|
5
5
|
*/
|
|
6
|
-
import { hasExecutor } from
|
|
6
|
+
import { hasExecutor } from './executors';
|
|
7
7
|
/** Known action kinds */
|
|
8
8
|
const VALID_KINDS = [
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
9
|
+
'overlays:highlight',
|
|
10
|
+
'overlays:pulse',
|
|
11
|
+
'overlays:badge',
|
|
12
|
+
'overlays:tooltip',
|
|
13
|
+
'overlays:modal',
|
|
14
|
+
'content:insertHtml',
|
|
15
|
+
'content:setText',
|
|
16
|
+
'content:setAttr',
|
|
17
|
+
'content:addClass',
|
|
18
|
+
'content:removeClass',
|
|
19
|
+
'content:setStyle',
|
|
20
|
+
'core:mountWidget',
|
|
21
|
+
'core:wait',
|
|
22
|
+
'core:sequence',
|
|
23
|
+
'core:parallel',
|
|
24
|
+
'core:tour',
|
|
25
|
+
'navigation:scrollTo',
|
|
26
|
+
'navigation:navigate',
|
|
27
27
|
];
|
|
28
28
|
/** Dangerous attribute names that should not be set */
|
|
29
29
|
const DANGEROUS_ATTRS = new Set([
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
30
|
+
'onclick',
|
|
31
|
+
'onerror',
|
|
32
|
+
'onload',
|
|
33
|
+
'onmouseover',
|
|
34
|
+
'onfocus',
|
|
35
|
+
'onblur',
|
|
36
|
+
'onchange',
|
|
37
|
+
'onsubmit',
|
|
38
|
+
'onkeydown',
|
|
39
|
+
'onkeyup',
|
|
40
|
+
'onkeypress',
|
|
41
41
|
]);
|
|
42
42
|
/** Maximum HTML content length */
|
|
43
43
|
const MAX_HTML_LENGTH = 50000;
|
|
@@ -50,93 +50,93 @@ export function validateAction(action) {
|
|
|
50
50
|
const errors = [];
|
|
51
51
|
const warnings = [];
|
|
52
52
|
// Check action has a kind
|
|
53
|
-
if (!action || typeof action !==
|
|
53
|
+
if (!action || typeof action !== 'object') {
|
|
54
54
|
errors.push({
|
|
55
|
-
code:
|
|
56
|
-
message:
|
|
55
|
+
code: 'INVALID_ACTION',
|
|
56
|
+
message: 'Action must be an object',
|
|
57
57
|
});
|
|
58
58
|
return { valid: false, errors, warnings };
|
|
59
59
|
}
|
|
60
60
|
const kind = action.kind;
|
|
61
61
|
// Check kind is valid
|
|
62
|
-
if (!kind || typeof kind !==
|
|
62
|
+
if (!kind || typeof kind !== 'string') {
|
|
63
63
|
errors.push({
|
|
64
|
-
code:
|
|
64
|
+
code: 'MISSING_KIND',
|
|
65
65
|
message: "Action must have a 'kind' property",
|
|
66
66
|
});
|
|
67
67
|
return { valid: false, errors, warnings };
|
|
68
68
|
}
|
|
69
69
|
if (!VALID_KINDS.includes(kind)) {
|
|
70
70
|
errors.push({
|
|
71
|
-
code:
|
|
71
|
+
code: 'UNKNOWN_KIND',
|
|
72
72
|
message: `Unknown action kind: ${kind}`,
|
|
73
|
-
field:
|
|
73
|
+
field: 'kind',
|
|
74
74
|
});
|
|
75
75
|
return { valid: false, errors, warnings };
|
|
76
76
|
}
|
|
77
77
|
// Check executor exists
|
|
78
|
-
if (!hasExecutor(kind) && kind !==
|
|
78
|
+
if (!hasExecutor(kind) && kind !== 'core:mountWidget') {
|
|
79
79
|
errors.push({
|
|
80
|
-
code:
|
|
80
|
+
code: 'NO_EXECUTOR',
|
|
81
81
|
message: `No executor registered for action kind: ${kind}`,
|
|
82
|
-
field:
|
|
82
|
+
field: 'kind',
|
|
83
83
|
});
|
|
84
84
|
}
|
|
85
85
|
// Kind-specific validation
|
|
86
86
|
switch (kind) {
|
|
87
|
-
case
|
|
88
|
-
case
|
|
89
|
-
case
|
|
87
|
+
case 'overlays:highlight':
|
|
88
|
+
case 'overlays:pulse':
|
|
89
|
+
case 'navigation:scrollTo':
|
|
90
90
|
validateAnchorAction(action, errors, warnings);
|
|
91
91
|
break;
|
|
92
|
-
case
|
|
92
|
+
case 'overlays:badge':
|
|
93
93
|
validateAnchorAction(action, errors, warnings);
|
|
94
94
|
validateBadgeAction(action, errors, warnings);
|
|
95
95
|
break;
|
|
96
|
-
case
|
|
96
|
+
case 'overlays:tooltip':
|
|
97
97
|
validateAnchorAction(action, errors, warnings);
|
|
98
98
|
validateTooltipAction(action, errors, warnings);
|
|
99
99
|
break;
|
|
100
|
-
case
|
|
100
|
+
case 'overlays:modal':
|
|
101
101
|
validateModalAction(action, errors, warnings);
|
|
102
102
|
break;
|
|
103
|
-
case
|
|
103
|
+
case 'content:insertHtml':
|
|
104
104
|
validateAnchorAction(action, errors, warnings);
|
|
105
105
|
validateInsertHtmlAction(action, errors, warnings);
|
|
106
106
|
break;
|
|
107
|
-
case
|
|
107
|
+
case 'content:setText':
|
|
108
108
|
validateAnchorAction(action, errors, warnings);
|
|
109
109
|
validateSetTextAction(action, errors, warnings);
|
|
110
110
|
break;
|
|
111
|
-
case
|
|
111
|
+
case 'content:setAttr':
|
|
112
112
|
validateAnchorAction(action, errors, warnings);
|
|
113
113
|
validateSetAttrAction(action, errors, warnings);
|
|
114
114
|
break;
|
|
115
|
-
case
|
|
116
|
-
case
|
|
115
|
+
case 'content:addClass':
|
|
116
|
+
case 'content:removeClass':
|
|
117
117
|
validateAnchorAction(action, errors, warnings);
|
|
118
118
|
validateClassAction(action, errors, warnings);
|
|
119
119
|
break;
|
|
120
|
-
case
|
|
120
|
+
case 'content:setStyle':
|
|
121
121
|
validateAnchorAction(action, errors, warnings);
|
|
122
122
|
validateSetStyleAction(action, errors, warnings);
|
|
123
123
|
break;
|
|
124
|
-
case
|
|
124
|
+
case 'core:mountWidget':
|
|
125
125
|
validateMountWidgetAction(action, errors, warnings);
|
|
126
126
|
break;
|
|
127
|
-
case
|
|
127
|
+
case 'core:wait':
|
|
128
128
|
validateWaitAction(action, errors, warnings);
|
|
129
129
|
break;
|
|
130
|
-
case
|
|
130
|
+
case 'core:sequence':
|
|
131
131
|
validateSequenceAction(action, errors, warnings);
|
|
132
132
|
break;
|
|
133
|
-
case
|
|
133
|
+
case 'core:parallel':
|
|
134
134
|
validateParallelAction(action, errors, warnings);
|
|
135
135
|
break;
|
|
136
|
-
case
|
|
136
|
+
case 'core:tour':
|
|
137
137
|
validateTourAction(action, errors, warnings);
|
|
138
138
|
break;
|
|
139
|
-
case
|
|
139
|
+
case 'navigation:navigate':
|
|
140
140
|
validateNavigateAction(action, errors, warnings);
|
|
141
141
|
break;
|
|
142
142
|
}
|
|
@@ -147,148 +147,149 @@ export function validateAction(action) {
|
|
|
147
147
|
};
|
|
148
148
|
}
|
|
149
149
|
function validateAnchorAction(action, errors, warnings) {
|
|
150
|
-
if (!action.anchorId || typeof action.anchorId !==
|
|
150
|
+
if (!action.anchorId || typeof action.anchorId !== 'string') {
|
|
151
151
|
errors.push({
|
|
152
|
-
code:
|
|
152
|
+
code: 'MISSING_ANCHOR_ID',
|
|
153
153
|
message: "Action requires an 'anchorId' property",
|
|
154
|
-
field:
|
|
154
|
+
field: 'anchorId',
|
|
155
155
|
});
|
|
156
156
|
}
|
|
157
157
|
else if (action.anchorId.length > 200) {
|
|
158
158
|
warnings.push({
|
|
159
|
-
code:
|
|
160
|
-
message:
|
|
161
|
-
suggestion:
|
|
159
|
+
code: 'LONG_ANCHOR_ID',
|
|
160
|
+
message: 'Anchor ID is unusually long',
|
|
161
|
+
suggestion: 'Consider using a shorter, more descriptive ID',
|
|
162
162
|
});
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
165
|
function validateBadgeAction(action, errors, warnings) {
|
|
166
|
-
if (!action.content || typeof action.content !==
|
|
166
|
+
if (!action.content || typeof action.content !== 'string') {
|
|
167
167
|
errors.push({
|
|
168
|
-
code:
|
|
168
|
+
code: 'MISSING_CONTENT',
|
|
169
169
|
message: "Badge action requires 'content' property",
|
|
170
|
-
field:
|
|
170
|
+
field: 'content',
|
|
171
171
|
});
|
|
172
172
|
}
|
|
173
173
|
else if (action.content.length > 100) {
|
|
174
174
|
warnings.push({
|
|
175
|
-
code:
|
|
176
|
-
message:
|
|
177
|
-
suggestion:
|
|
175
|
+
code: 'LONG_BADGE_CONTENT',
|
|
176
|
+
message: 'Badge content is quite long',
|
|
177
|
+
suggestion: 'Keep badge content short (under 100 characters)',
|
|
178
178
|
});
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
|
-
function validateTooltipAction(action, errors,
|
|
182
|
-
if (!action.content || typeof action.content !==
|
|
181
|
+
function validateTooltipAction(action, errors, _warnings) {
|
|
182
|
+
if (!action.content || typeof action.content !== 'object') {
|
|
183
183
|
errors.push({
|
|
184
|
-
code:
|
|
184
|
+
code: 'MISSING_CONTENT',
|
|
185
185
|
message: "Tooltip action requires 'content' object",
|
|
186
|
-
field:
|
|
186
|
+
field: 'content',
|
|
187
187
|
});
|
|
188
188
|
return;
|
|
189
189
|
}
|
|
190
|
-
if (!action.content.body || typeof action.content.body !==
|
|
190
|
+
if (!action.content.body || typeof action.content.body !== 'string') {
|
|
191
191
|
errors.push({
|
|
192
|
-
code:
|
|
192
|
+
code: 'MISSING_BODY',
|
|
193
193
|
message: "Tooltip content requires 'body' property",
|
|
194
|
-
field:
|
|
194
|
+
field: 'content.body',
|
|
195
195
|
});
|
|
196
196
|
}
|
|
197
197
|
}
|
|
198
|
-
function validateInsertHtmlAction(action, errors,
|
|
199
|
-
if (!action.html || typeof action.html !==
|
|
198
|
+
function validateInsertHtmlAction(action, errors, _warnings) {
|
|
199
|
+
if (!action.html || typeof action.html !== 'string') {
|
|
200
200
|
errors.push({
|
|
201
|
-
code:
|
|
201
|
+
code: 'MISSING_HTML',
|
|
202
202
|
message: "insertHtml action requires 'html' property",
|
|
203
|
-
field:
|
|
203
|
+
field: 'html',
|
|
204
204
|
});
|
|
205
205
|
}
|
|
206
206
|
else if (action.html.length > MAX_HTML_LENGTH) {
|
|
207
207
|
errors.push({
|
|
208
|
-
code:
|
|
208
|
+
code: 'HTML_TOO_LONG',
|
|
209
209
|
message: `HTML content exceeds maximum length of ${MAX_HTML_LENGTH}`,
|
|
210
|
-
field:
|
|
210
|
+
field: 'html',
|
|
211
211
|
});
|
|
212
212
|
}
|
|
213
|
-
const validPositions = [
|
|
213
|
+
const validPositions = ['before', 'after', 'prepend', 'append', 'replace'];
|
|
214
214
|
if (!action.position || !validPositions.includes(action.position)) {
|
|
215
215
|
errors.push({
|
|
216
|
-
code:
|
|
217
|
-
message: `Position must be one of: ${validPositions.join(
|
|
218
|
-
field:
|
|
216
|
+
code: 'INVALID_POSITION',
|
|
217
|
+
message: `Position must be one of: ${validPositions.join(', ')}`,
|
|
218
|
+
field: 'position',
|
|
219
219
|
});
|
|
220
220
|
}
|
|
221
221
|
}
|
|
222
|
-
function validateSetTextAction(action, errors,
|
|
222
|
+
function validateSetTextAction(action, errors, _warnings) {
|
|
223
223
|
if (action.text === undefined || action.text === null) {
|
|
224
224
|
errors.push({
|
|
225
|
-
code:
|
|
225
|
+
code: 'MISSING_TEXT',
|
|
226
226
|
message: "setText action requires 'text' property",
|
|
227
|
-
field:
|
|
227
|
+
field: 'text',
|
|
228
228
|
});
|
|
229
229
|
}
|
|
230
230
|
}
|
|
231
|
-
function validateSetAttrAction(action, errors,
|
|
232
|
-
if (!action.attr || typeof action.attr !==
|
|
231
|
+
function validateSetAttrAction(action, errors, _warnings) {
|
|
232
|
+
if (!action.attr || typeof action.attr !== 'string') {
|
|
233
233
|
errors.push({
|
|
234
|
-
code:
|
|
234
|
+
code: 'MISSING_ATTR',
|
|
235
235
|
message: "setAttr action requires 'attr' property",
|
|
236
|
-
field:
|
|
236
|
+
field: 'attr',
|
|
237
237
|
});
|
|
238
238
|
}
|
|
239
|
-
else if (DANGEROUS_ATTRS.has(action.attr.toLowerCase()) ||
|
|
239
|
+
else if (DANGEROUS_ATTRS.has(action.attr.toLowerCase()) ||
|
|
240
|
+
action.attr.toLowerCase().startsWith('on')) {
|
|
240
241
|
errors.push({
|
|
241
|
-
code:
|
|
242
|
+
code: 'DANGEROUS_ATTR',
|
|
242
243
|
message: `Event handler attributes are not allowed: ${action.attr}`,
|
|
243
|
-
field:
|
|
244
|
+
field: 'attr',
|
|
244
245
|
});
|
|
245
246
|
}
|
|
246
247
|
if (action.value === undefined || action.value === null) {
|
|
247
248
|
errors.push({
|
|
248
|
-
code:
|
|
249
|
+
code: 'MISSING_VALUE',
|
|
249
250
|
message: "setAttr action requires 'value' property",
|
|
250
|
-
field:
|
|
251
|
+
field: 'value',
|
|
251
252
|
});
|
|
252
253
|
}
|
|
253
254
|
}
|
|
254
255
|
function validateClassAction(action, errors, warnings) {
|
|
255
|
-
if (!action.className || typeof action.className !==
|
|
256
|
+
if (!action.className || typeof action.className !== 'string') {
|
|
256
257
|
errors.push({
|
|
257
|
-
code:
|
|
258
|
+
code: 'MISSING_CLASS_NAME',
|
|
258
259
|
message: "Class action requires 'className' property",
|
|
259
|
-
field:
|
|
260
|
+
field: 'className',
|
|
260
261
|
});
|
|
261
262
|
}
|
|
262
263
|
else if (!/^[a-zA-Z_-][a-zA-Z0-9_-]*$/.test(action.className)) {
|
|
263
264
|
warnings.push({
|
|
264
|
-
code:
|
|
265
|
-
message:
|
|
266
|
-
suggestion:
|
|
265
|
+
code: 'INVALID_CLASS_NAME',
|
|
266
|
+
message: 'Class name contains unusual characters',
|
|
267
|
+
suggestion: 'Use alphanumeric characters, hyphens, and underscores',
|
|
267
268
|
});
|
|
268
269
|
}
|
|
269
270
|
}
|
|
270
|
-
function validateSetStyleAction(action, errors,
|
|
271
|
-
if (!action.styles || typeof action.styles !==
|
|
271
|
+
function validateSetStyleAction(action, errors, _warnings) {
|
|
272
|
+
if (!action.styles || typeof action.styles !== 'object') {
|
|
272
273
|
errors.push({
|
|
273
|
-
code:
|
|
274
|
+
code: 'MISSING_STYLES',
|
|
274
275
|
message: "setStyle action requires 'styles' object",
|
|
275
|
-
field:
|
|
276
|
+
field: 'styles',
|
|
276
277
|
});
|
|
277
278
|
}
|
|
278
279
|
else {
|
|
279
280
|
const styleCount = Object.keys(action.styles).length;
|
|
280
281
|
if (styleCount > MAX_STYLE_COUNT) {
|
|
281
282
|
errors.push({
|
|
282
|
-
code:
|
|
283
|
+
code: 'TOO_MANY_STYLES',
|
|
283
284
|
message: `Too many styles (${styleCount}). Maximum is ${MAX_STYLE_COUNT}`,
|
|
284
|
-
field:
|
|
285
|
+
field: 'styles',
|
|
285
286
|
});
|
|
286
287
|
}
|
|
287
288
|
// Check for potentially dangerous style values
|
|
288
289
|
for (const [prop, value] of Object.entries(action.styles)) {
|
|
289
|
-
if (typeof value ===
|
|
290
|
+
if (typeof value === 'string' && value.includes('expression(')) {
|
|
290
291
|
errors.push({
|
|
291
|
-
code:
|
|
292
|
+
code: 'DANGEROUS_STYLE',
|
|
292
293
|
message: `Style expressions are not allowed: ${prop}`,
|
|
293
294
|
field: `styles.${prop}`,
|
|
294
295
|
});
|
|
@@ -296,65 +297,65 @@ function validateSetStyleAction(action, errors, warnings) {
|
|
|
296
297
|
}
|
|
297
298
|
}
|
|
298
299
|
}
|
|
299
|
-
function validateMountWidgetAction(action, errors,
|
|
300
|
-
if (!action.slot || typeof action.slot !==
|
|
300
|
+
function validateMountWidgetAction(action, errors, _warnings) {
|
|
301
|
+
if (!action.slot || typeof action.slot !== 'string') {
|
|
301
302
|
errors.push({
|
|
302
|
-
code:
|
|
303
|
+
code: 'MISSING_SLOT',
|
|
303
304
|
message: "mountWidget action requires 'slot' property",
|
|
304
|
-
field:
|
|
305
|
+
field: 'slot',
|
|
305
306
|
});
|
|
306
307
|
}
|
|
307
|
-
if (!action.widget || typeof action.widget !==
|
|
308
|
+
if (!action.widget || typeof action.widget !== 'object') {
|
|
308
309
|
errors.push({
|
|
309
|
-
code:
|
|
310
|
+
code: 'MISSING_WIDGET',
|
|
310
311
|
message: "mountWidget action requires 'widget' object",
|
|
311
|
-
field:
|
|
312
|
+
field: 'widget',
|
|
312
313
|
});
|
|
313
314
|
}
|
|
314
|
-
else if (!action.widget.widgetId || typeof action.widget.widgetId !==
|
|
315
|
+
else if (!action.widget.widgetId || typeof action.widget.widgetId !== 'string') {
|
|
315
316
|
errors.push({
|
|
316
|
-
code:
|
|
317
|
+
code: 'MISSING_WIDGET_ID',
|
|
317
318
|
message: "Widget must have a 'widgetId' property",
|
|
318
|
-
field:
|
|
319
|
+
field: 'widget.widgetId',
|
|
319
320
|
});
|
|
320
321
|
}
|
|
321
322
|
}
|
|
322
|
-
function validateWaitAction(action, errors,
|
|
323
|
+
function validateWaitAction(action, errors, _warnings) {
|
|
323
324
|
if (action.durationMs === undefined && !action.event) {
|
|
324
325
|
errors.push({
|
|
325
|
-
code:
|
|
326
|
+
code: 'MISSING_WAIT_CONFIG',
|
|
326
327
|
message: "wait action requires either 'durationMs' or 'event' property",
|
|
327
328
|
});
|
|
328
329
|
}
|
|
329
330
|
if (action.durationMs !== undefined && action.durationMs < 0) {
|
|
330
331
|
errors.push({
|
|
331
|
-
code:
|
|
332
|
-
message:
|
|
333
|
-
field:
|
|
332
|
+
code: 'INVALID_DURATION',
|
|
333
|
+
message: 'durationMs must be a positive number',
|
|
334
|
+
field: 'durationMs',
|
|
334
335
|
});
|
|
335
336
|
}
|
|
336
|
-
if (action.event !== undefined && typeof action.event !==
|
|
337
|
+
if (action.event !== undefined && typeof action.event !== 'string') {
|
|
337
338
|
errors.push({
|
|
338
|
-
code:
|
|
339
|
-
message:
|
|
340
|
-
field:
|
|
339
|
+
code: 'INVALID_EVENT',
|
|
340
|
+
message: 'event must be a string',
|
|
341
|
+
field: 'event',
|
|
341
342
|
});
|
|
342
343
|
}
|
|
343
344
|
}
|
|
344
345
|
function validateSequenceAction(action, errors, warnings) {
|
|
345
346
|
if (!action.actions || !Array.isArray(action.actions)) {
|
|
346
347
|
errors.push({
|
|
347
|
-
code:
|
|
348
|
+
code: 'MISSING_ACTIONS',
|
|
348
349
|
message: "sequence action requires 'actions' array",
|
|
349
|
-
field:
|
|
350
|
+
field: 'actions',
|
|
350
351
|
});
|
|
351
352
|
return;
|
|
352
353
|
}
|
|
353
354
|
if (action.actions.length === 0) {
|
|
354
355
|
warnings.push({
|
|
355
|
-
code:
|
|
356
|
-
message:
|
|
357
|
-
suggestion:
|
|
356
|
+
code: 'EMPTY_SEQUENCE',
|
|
357
|
+
message: 'sequence has no actions',
|
|
358
|
+
suggestion: 'Add at least one action to the sequence',
|
|
358
359
|
});
|
|
359
360
|
}
|
|
360
361
|
// Recursively validate nested actions
|
|
@@ -363,7 +364,7 @@ function validateSequenceAction(action, errors, warnings) {
|
|
|
363
364
|
for (const error of result.errors) {
|
|
364
365
|
errors.push({
|
|
365
366
|
...error,
|
|
366
|
-
field: `actions[${i}]${error.field ? `.${error.field}` :
|
|
367
|
+
field: `actions[${i}]${error.field ? `.${error.field}` : ''}`,
|
|
367
368
|
});
|
|
368
369
|
}
|
|
369
370
|
for (const warning of result.warnings) {
|
|
@@ -374,24 +375,24 @@ function validateSequenceAction(action, errors, warnings) {
|
|
|
374
375
|
function validateParallelAction(action, errors, warnings) {
|
|
375
376
|
if (!action.actions || !Array.isArray(action.actions)) {
|
|
376
377
|
errors.push({
|
|
377
|
-
code:
|
|
378
|
+
code: 'MISSING_ACTIONS',
|
|
378
379
|
message: "parallel action requires 'actions' array",
|
|
379
|
-
field:
|
|
380
|
+
field: 'actions',
|
|
380
381
|
});
|
|
381
382
|
return;
|
|
382
383
|
}
|
|
383
384
|
if (action.actions.length === 0) {
|
|
384
385
|
warnings.push({
|
|
385
|
-
code:
|
|
386
|
-
message:
|
|
387
|
-
suggestion:
|
|
386
|
+
code: 'EMPTY_PARALLEL',
|
|
387
|
+
message: 'parallel has no actions',
|
|
388
|
+
suggestion: 'Add at least one action to the parallel group',
|
|
388
389
|
});
|
|
389
390
|
}
|
|
390
|
-
if (action.waitFor && ![
|
|
391
|
+
if (action.waitFor && !['all', 'any'].includes(action.waitFor)) {
|
|
391
392
|
errors.push({
|
|
392
|
-
code:
|
|
393
|
+
code: 'INVALID_WAIT_FOR',
|
|
393
394
|
message: "waitFor must be 'all' or 'any'",
|
|
394
|
-
field:
|
|
395
|
+
field: 'waitFor',
|
|
395
396
|
});
|
|
396
397
|
}
|
|
397
398
|
// Recursively validate nested actions
|
|
@@ -400,7 +401,7 @@ function validateParallelAction(action, errors, warnings) {
|
|
|
400
401
|
for (const error of result.errors) {
|
|
401
402
|
errors.push({
|
|
402
403
|
...error,
|
|
403
|
-
field: `actions[${i}]${error.field ? `.${error.field}` :
|
|
404
|
+
field: `actions[${i}]${error.field ? `.${error.field}` : ''}`,
|
|
404
405
|
});
|
|
405
406
|
}
|
|
406
407
|
for (const warning of result.warnings) {
|
|
@@ -409,76 +410,76 @@ function validateParallelAction(action, errors, warnings) {
|
|
|
409
410
|
}
|
|
410
411
|
}
|
|
411
412
|
function validateNavigateAction(action, errors, warnings) {
|
|
412
|
-
if (!action.url || typeof action.url !==
|
|
413
|
+
if (!action.url || typeof action.url !== 'string') {
|
|
413
414
|
errors.push({
|
|
414
|
-
code:
|
|
415
|
+
code: 'MISSING_URL',
|
|
415
416
|
message: "navigate action requires 'url' property",
|
|
416
|
-
field:
|
|
417
|
+
field: 'url',
|
|
417
418
|
});
|
|
418
419
|
}
|
|
419
420
|
else {
|
|
420
421
|
const url = action.url.trim().toLowerCase();
|
|
421
|
-
if (url.startsWith(
|
|
422
|
+
if (url.startsWith('javascript:')) {
|
|
422
423
|
errors.push({
|
|
423
|
-
code:
|
|
424
|
-
message:
|
|
425
|
-
field:
|
|
424
|
+
code: 'DANGEROUS_URL',
|
|
425
|
+
message: 'javascript: URLs are not allowed',
|
|
426
|
+
field: 'url',
|
|
426
427
|
});
|
|
427
428
|
}
|
|
428
429
|
// Warn about data: URLs
|
|
429
|
-
if (url.startsWith(
|
|
430
|
+
if (url.startsWith('data:')) {
|
|
430
431
|
warnings.push({
|
|
431
|
-
code:
|
|
432
|
-
message:
|
|
433
|
-
suggestion:
|
|
432
|
+
code: 'DATA_URL',
|
|
433
|
+
message: 'data: URLs may have limited support',
|
|
434
|
+
suggestion: 'Consider using a regular URL instead',
|
|
434
435
|
});
|
|
435
436
|
}
|
|
436
437
|
}
|
|
437
438
|
}
|
|
438
|
-
function validateModalAction(action, errors,
|
|
439
|
-
if (!action.content || typeof action.content !==
|
|
439
|
+
function validateModalAction(action, errors, _warnings) {
|
|
440
|
+
if (!action.content || typeof action.content !== 'object') {
|
|
440
441
|
errors.push({
|
|
441
|
-
code:
|
|
442
|
+
code: 'MISSING_CONTENT',
|
|
442
443
|
message: "Modal action requires 'content' object",
|
|
443
|
-
field:
|
|
444
|
+
field: 'content',
|
|
444
445
|
});
|
|
445
446
|
return;
|
|
446
447
|
}
|
|
447
|
-
if (!action.content.body || typeof action.content.body !==
|
|
448
|
+
if (!action.content.body || typeof action.content.body !== 'string') {
|
|
448
449
|
errors.push({
|
|
449
|
-
code:
|
|
450
|
+
code: 'MISSING_BODY',
|
|
450
451
|
message: "Modal content requires 'body' property",
|
|
451
|
-
field:
|
|
452
|
+
field: 'content.body',
|
|
452
453
|
});
|
|
453
454
|
}
|
|
454
|
-
if (action.size && ![
|
|
455
|
+
if (action.size && !['sm', 'md', 'lg'].includes(action.size)) {
|
|
455
456
|
errors.push({
|
|
456
|
-
code:
|
|
457
|
+
code: 'INVALID_SIZE',
|
|
457
458
|
message: "Modal size must be 'sm', 'md', or 'lg'",
|
|
458
|
-
field:
|
|
459
|
+
field: 'size',
|
|
459
460
|
});
|
|
460
461
|
}
|
|
461
462
|
if (action.ctaButtons) {
|
|
462
463
|
if (!Array.isArray(action.ctaButtons)) {
|
|
463
464
|
errors.push({
|
|
464
|
-
code:
|
|
465
|
-
message:
|
|
466
|
-
field:
|
|
465
|
+
code: 'INVALID_CTA_BUTTONS',
|
|
466
|
+
message: 'ctaButtons must be an array',
|
|
467
|
+
field: 'ctaButtons',
|
|
467
468
|
});
|
|
468
469
|
}
|
|
469
470
|
else {
|
|
470
471
|
for (let i = 0; i < action.ctaButtons.length; i++) {
|
|
471
472
|
const btn = action.ctaButtons[i];
|
|
472
|
-
if (!btn.label || typeof btn.label !==
|
|
473
|
+
if (!btn.label || typeof btn.label !== 'string') {
|
|
473
474
|
errors.push({
|
|
474
|
-
code:
|
|
475
|
+
code: 'MISSING_BUTTON_LABEL',
|
|
475
476
|
message: `CTA button at index ${i} requires 'label' property`,
|
|
476
477
|
field: `ctaButtons[${i}].label`,
|
|
477
478
|
});
|
|
478
479
|
}
|
|
479
|
-
if (!btn.actionId || typeof btn.actionId !==
|
|
480
|
+
if (!btn.actionId || typeof btn.actionId !== 'string') {
|
|
480
481
|
errors.push({
|
|
481
|
-
code:
|
|
482
|
+
code: 'MISSING_BUTTON_ACTION_ID',
|
|
482
483
|
message: `CTA button at index ${i} requires 'actionId' property`,
|
|
483
484
|
field: `ctaButtons[${i}].actionId`,
|
|
484
485
|
});
|
|
@@ -488,34 +489,34 @@ function validateModalAction(action, errors, warnings) {
|
|
|
488
489
|
}
|
|
489
490
|
}
|
|
490
491
|
function validateTourAction(action, errors, warnings) {
|
|
491
|
-
if (!action.tourId || typeof action.tourId !==
|
|
492
|
+
if (!action.tourId || typeof action.tourId !== 'string') {
|
|
492
493
|
errors.push({
|
|
493
|
-
code:
|
|
494
|
+
code: 'MISSING_TOUR_ID',
|
|
494
495
|
message: "Tour action requires 'tourId' property",
|
|
495
|
-
field:
|
|
496
|
+
field: 'tourId',
|
|
496
497
|
});
|
|
497
498
|
}
|
|
498
499
|
if (!action.steps || !Array.isArray(action.steps)) {
|
|
499
500
|
errors.push({
|
|
500
|
-
code:
|
|
501
|
+
code: 'MISSING_STEPS',
|
|
501
502
|
message: "Tour action requires 'steps' array",
|
|
502
|
-
field:
|
|
503
|
+
field: 'steps',
|
|
503
504
|
});
|
|
504
505
|
return;
|
|
505
506
|
}
|
|
506
507
|
if (action.steps.length === 0) {
|
|
507
508
|
errors.push({
|
|
508
|
-
code:
|
|
509
|
-
message:
|
|
510
|
-
field:
|
|
509
|
+
code: 'EMPTY_STEPS',
|
|
510
|
+
message: 'Tour must have at least one step',
|
|
511
|
+
field: 'steps',
|
|
511
512
|
});
|
|
512
513
|
}
|
|
513
514
|
const stepIds = new Set();
|
|
514
515
|
for (let i = 0; i < action.steps.length; i++) {
|
|
515
516
|
const step = action.steps[i];
|
|
516
|
-
if (!step.id || typeof step.id !==
|
|
517
|
+
if (!step.id || typeof step.id !== 'string') {
|
|
517
518
|
errors.push({
|
|
518
|
-
code:
|
|
519
|
+
code: 'MISSING_STEP_ID',
|
|
519
520
|
message: `Step at index ${i} requires 'id' property`,
|
|
520
521
|
field: `steps[${i}].id`,
|
|
521
522
|
});
|
|
@@ -523,7 +524,7 @@ function validateTourAction(action, errors, warnings) {
|
|
|
523
524
|
else {
|
|
524
525
|
if (stepIds.has(step.id)) {
|
|
525
526
|
errors.push({
|
|
526
|
-
code:
|
|
527
|
+
code: 'DUPLICATE_STEP_ID',
|
|
527
528
|
message: `Duplicate step ID: ${step.id}`,
|
|
528
529
|
field: `steps[${i}].id`,
|
|
529
530
|
});
|
|
@@ -532,7 +533,7 @@ function validateTourAction(action, errors, warnings) {
|
|
|
532
533
|
}
|
|
533
534
|
if (!step.action) {
|
|
534
535
|
errors.push({
|
|
535
|
-
code:
|
|
536
|
+
code: 'MISSING_STEP_ACTION',
|
|
536
537
|
message: `Step at index ${i} requires 'action' property`,
|
|
537
538
|
field: `steps[${i}].action`,
|
|
538
539
|
});
|
|
@@ -543,7 +544,7 @@ function validateTourAction(action, errors, warnings) {
|
|
|
543
544
|
for (const error of result.errors) {
|
|
544
545
|
errors.push({
|
|
545
546
|
...error,
|
|
546
|
-
field: `steps[${i}].action${error.field ? `.${error.field}` :
|
|
547
|
+
field: `steps[${i}].action${error.field ? `.${error.field}` : ''}`,
|
|
547
548
|
});
|
|
548
549
|
}
|
|
549
550
|
for (const warning of result.warnings) {
|
|
@@ -552,10 +553,10 @@ function validateTourAction(action, errors, warnings) {
|
|
|
552
553
|
}
|
|
553
554
|
// Validate onAction references
|
|
554
555
|
if (step.onAction) {
|
|
555
|
-
for (const [
|
|
556
|
-
if (targetStepId !==
|
|
556
|
+
for (const [_actionId, targetStepId] of Object.entries(step.onAction)) {
|
|
557
|
+
if (targetStepId !== 'end' && !action.steps.some((s) => s.id === targetStepId)) {
|
|
557
558
|
warnings.push({
|
|
558
|
-
code:
|
|
559
|
+
code: 'UNKNOWN_TARGET_STEP',
|
|
559
560
|
message: `Step "${step.id}" references unknown target step: ${targetStepId}`,
|
|
560
561
|
suggestion: `Make sure step "${targetStepId}" exists in the tour`,
|
|
561
562
|
});
|
|
@@ -572,8 +573,8 @@ export function validateActions(actions) {
|
|
|
572
573
|
const warnings = [];
|
|
573
574
|
if (!Array.isArray(actions)) {
|
|
574
575
|
errors.push({
|
|
575
|
-
code:
|
|
576
|
-
message:
|
|
576
|
+
code: 'INVALID_ACTIONS',
|
|
577
|
+
message: 'Actions must be an array',
|
|
577
578
|
});
|
|
578
579
|
return { valid: false, errors, warnings };
|
|
579
580
|
}
|
|
@@ -588,9 +589,7 @@ export function validateActions(actions) {
|
|
|
588
589
|
for (const warning of result.warnings) {
|
|
589
590
|
warnings.push({
|
|
590
591
|
...warning,
|
|
591
|
-
suggestion: warning.suggestion
|
|
592
|
-
? `Action ${i}: ${warning.suggestion}`
|
|
593
|
-
: undefined,
|
|
592
|
+
suggestion: warning.suggestion ? `Action ${i}: ${warning.suggestion}` : undefined,
|
|
594
593
|
});
|
|
595
594
|
}
|
|
596
595
|
}
|