@lowdefy/build 4.5.2 → 4.6.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/dist/build/addDefaultPages/404.js +1 -1
- package/dist/build/addDefaultPages/addDefaultPages.js +10 -4
- package/dist/build/addKeys.js +85 -29
- package/dist/build/buildApi/buildApi.js +27 -8
- package/dist/build/buildApi/buildEndpoint.js +7 -1
- package/dist/build/buildApi/buildRoutine/buildControl.js +1 -1
- package/dist/build/buildApi/buildRoutine/buildRoutine.js +1 -1
- package/dist/build/buildApi/buildRoutine/buildStep.js +1 -1
- package/dist/build/buildApi/buildRoutine/controlTypes.js +34 -11
- package/dist/build/buildApi/buildRoutine/countControl.js +1 -1
- package/dist/build/buildApi/buildRoutine/countStepTypes.js +2 -2
- package/dist/build/buildApi/buildRoutine/setStepId.js +1 -1
- package/dist/build/buildApi/buildRoutine/validateStep.js +30 -9
- package/dist/build/buildApi/validateEndpoint.js +36 -7
- package/dist/build/buildApi/validateStepReferences.js +65 -0
- package/dist/build/buildApp.js +1 -1
- package/dist/build/buildAuth/buildApiAuth.js +7 -3
- package/dist/build/buildAuth/buildAuth.js +7 -4
- package/dist/build/buildAuth/buildAuthPlugins.js +42 -13
- package/dist/build/buildAuth/buildPageAuth.js +14 -3
- package/dist/build/buildAuth/getApiRoles.js +1 -1
- package/dist/build/buildAuth/getPageRoles.js +1 -1
- package/dist/build/buildAuth/getProtectedApi.js +1 -1
- package/dist/build/buildAuth/getProtectedPages.js +1 -1
- package/dist/build/buildAuth/validateAuthConfig.js +39 -5
- package/dist/build/buildAuth/validateMutualExclusivity.js +13 -5
- package/dist/build/buildConnections.js +23 -24
- package/dist/build/buildImports/buildIconImports.js +1 -1
- package/dist/build/buildImports/buildImports.js +1 -1
- package/dist/build/buildImports/buildImportsDev.js +1 -1
- package/dist/build/buildImports/buildImportsProd.js +1 -1
- package/dist/build/buildImports/buildStyleImports.js +1 -1
- package/dist/build/buildImports/defaultIconsDev.js +1 -1
- package/dist/build/buildImports/defaultIconsProd.js +1 -1
- package/dist/build/buildJs/generateJsFile.js +1 -1
- package/dist/build/buildJs/jsMapParser.js +1 -1
- package/dist/build/buildJs/writeJs.js +1 -1
- package/dist/build/buildLogger.js +41 -0
- package/dist/build/buildMenu.js +36 -12
- package/dist/build/buildPages/buildBlock/buildBlock.js +1 -1
- package/dist/build/buildPages/buildBlock/buildEvents.js +79 -9
- package/dist/build/buildPages/buildBlock/buildRequests.js +38 -8
- package/dist/build/buildPages/buildBlock/buildSubBlocks.js +6 -2
- package/dist/build/buildPages/buildBlock/countBlockOperators.js +1 -1
- package/dist/build/buildPages/buildBlock/countBlockTypes.js +2 -2
- package/dist/build/buildPages/buildBlock/moveSkeletonBlocksToArea.js +6 -2
- package/dist/build/buildPages/buildBlock/moveSubBlocksToArea.js +6 -2
- package/dist/build/buildPages/buildBlock/setBlockId.js +1 -1
- package/dist/build/buildPages/buildBlock/validateBlock.js +25 -7
- package/dist/build/buildPages/buildPage.js +35 -6
- package/dist/build/buildPages/validateLinkReferences.js +33 -0
- package/dist/build/buildPages/validatePayloadReferences.js +59 -0
- package/dist/build/buildPages/validateRequestReferences.js +33 -0
- package/dist/build/buildPages/validateServerStateReferences.js +41 -0
- package/dist/build/buildPages/validateStateReferences.js +79 -0
- package/dist/build/buildRefs/buildRefs.js +20 -3
- package/dist/build/buildRefs/createRefReviver.js +28 -0
- package/dist/build/buildRefs/evaluateBuildOperators.js +26 -7
- package/dist/build/buildRefs/evaluateStaticOperators.js +56 -0
- package/dist/build/buildRefs/getConfigFile.js +25 -6
- package/dist/build/buildRefs/getKey.js +1 -1
- package/dist/build/buildRefs/getRefContent.js +1 -1
- package/dist/build/buildRefs/getRefPath.js +1 -1
- package/dist/build/buildRefs/getRefsFromFile.js +9 -4
- package/dist/build/buildRefs/getUserJavascriptFunction.js +18 -4
- package/dist/build/buildRefs/makeRefDefinition.js +10 -5
- package/dist/build/buildRefs/parseNunjucks.js +1 -1
- package/dist/build/buildRefs/parseRefContent.js +100 -6
- package/dist/build/buildRefs/populateRefs.js +75 -13
- package/dist/build/buildRefs/recursiveBuild.js +66 -18
- package/dist/build/buildRefs/runRefResolver.js +11 -3
- package/dist/build/buildRefs/runTransformer.js +7 -3
- package/dist/build/buildTypes.js +22 -7
- package/dist/build/cleanBuildDirectory.js +1 -1
- package/dist/build/collectDynamicIdentifiers.js +35 -0
- package/dist/build/collectTypeNames.js +36 -0
- package/dist/build/copyPublicFolder.js +1 -1
- package/dist/build/{buildJs → full}/buildJs.js +3 -3
- package/dist/build/full/buildPages.js +87 -0
- package/dist/build/{buildPages → full}/buildTestPage.js +15 -3
- package/dist/build/{updateServerPackageJson.js → full/updateServerPackageJson.js} +1 -1
- package/dist/build/{writePages.js → full/writePages.js} +1 -1
- package/dist/build/{writeRequests.js → full/writeRequests.js} +11 -3
- package/dist/build/{writeTypes.js → full/writeTypes.js} +1 -1
- package/dist/build/jit/addInstalledTypes.js +51 -0
- package/dist/build/jit/buildJsShallow.js +41 -0
- package/dist/build/jit/buildPageJit.js +252 -0
- package/dist/build/jit/buildShallowPages.js +90 -0
- package/dist/build/jit/createPageRegistry.js +80 -0
- package/dist/build/jit/detectMissingPluginPackages.js +62 -0
- package/dist/build/jit/getRefPositions.js +38 -0
- package/dist/build/jit/isPageContentPath.js +24 -0
- package/dist/build/jit/pageContentKeys.js +26 -0
- package/dist/build/jit/shallowBuild.js +245 -0
- package/dist/build/jit/stripPageContent.js +23 -0
- package/dist/build/jit/updateServerPackageJsonJit.js +33 -0
- package/dist/build/jit/validatePageTypes.js +73 -0
- package/dist/build/jit/writePageJit.js +44 -0
- package/dist/build/jit/writePageRegistry.js +23 -0
- package/dist/build/jit/writeSourcelessPages.js +23 -0
- package/dist/build/testSchema.js +45 -7
- package/dist/build/validateConfig.js +2 -2
- package/dist/build/validateOperatorsDynamic.js +28 -0
- package/dist/build/writeApi.js +1 -1
- package/dist/build/writeApp.js +1 -1
- package/dist/build/writeAuth.js +1 -1
- package/dist/build/writeConfig.js +1 -1
- package/dist/build/writeConnections.js +1 -1
- package/dist/build/writeGlobal.js +1 -1
- package/dist/build/writeLogger.js +19 -0
- package/dist/build/writeMaps.js +1 -1
- package/dist/build/writeMenus.js +1 -1
- package/dist/build/writePluginImports/generateImportFile.js +1 -1
- package/dist/build/writePluginImports/writeActionImports.js +1 -1
- package/dist/build/writePluginImports/writeActionSchemaMap.js +42 -0
- package/dist/build/writePluginImports/writeAuthImports.js +1 -1
- package/dist/build/writePluginImports/writeBlockImports.js +1 -1
- package/dist/build/writePluginImports/writeBlockSchemaMap.js +42 -0
- package/dist/build/writePluginImports/writeConnectionImports.js +1 -1
- package/dist/build/writePluginImports/writeIconImports.js +1 -1
- package/dist/build/writePluginImports/writeOperatorImports.js +1 -1
- package/dist/build/writePluginImports/writeOperatorSchemaMap.js +49 -0
- package/dist/build/writePluginImports/writePluginImports.js +16 -1
- package/dist/build/writePluginImports/writeStyleImports.js +1 -1
- package/dist/createContext.js +16 -4
- package/dist/defaultTypesMap.js +479 -457
- package/dist/index.js +188 -127
- package/dist/indexDev.js +18 -0
- package/dist/lowdefySchema.js +589 -0
- package/dist/scripts/generateDefaultTypes.js +2 -1
- package/dist/scripts/run.js +1 -1
- package/dist/{test → test-utils}/buildRefs/testBuildRefsAsyncFunction.js +1 -1
- package/dist/{test → test-utils}/buildRefs/testBuildRefsErrorResolver.js +1 -1
- package/dist/{test → test-utils}/buildRefs/testBuildRefsNullResolver.js +1 -1
- package/dist/{test → test-utils}/buildRefs/testBuildRefsParsingResolver.js +1 -1
- package/dist/{test → test-utils}/buildRefs/testBuildRefsResolver.js +1 -1
- package/dist/{test → test-utils}/buildRefs/testBuildRefsTransform.js +1 -1
- package/dist/{test → test-utils}/buildRefs/testBuildRefsTransformIdentity.js +1 -1
- package/dist/test-utils/buildRefs/testJitPageResolver.js +24 -0
- package/dist/test-utils/createTestLogger.js +36 -0
- package/dist/test-utils/parseTestYaml.js +126 -0
- package/dist/test-utils/runBuild.js +228 -0
- package/dist/test-utils/runBuildForSnapshots.js +704 -0
- package/dist/{test → test-utils}/testContext.js +12 -2
- package/dist/utils/collectExceptions.js +34 -0
- package/dist/utils/countOperators.js +31 -12
- package/dist/utils/createBuildHandleError.js +38 -0
- package/dist/utils/createCheckDuplicateId.js +15 -9
- package/dist/utils/createCounter.js +16 -3
- package/dist/utils/createHandleWarning.js +41 -0
- package/dist/utils/createPluginTypesMap.js +1 -1
- package/dist/utils/extractOperatorKey.js +36 -0
- package/dist/utils/findConfigKey.js +37 -0
- package/dist/utils/findSimilarString.js +53 -0
- package/dist/utils/logCollectedErrors.js +30 -0
- package/dist/utils/makeId.js +13 -8
- package/dist/utils/preserveMetaProperties.js +27 -0
- package/dist/utils/readConfigFile.js +1 -1
- package/dist/utils/setNonEnumerableProperty.js +23 -0
- package/dist/utils/traverseConfig.js +43 -0
- package/dist/utils/tryBuildStep.js +46 -0
- package/dist/utils/writeBuildArtifact.js +1 -1
- package/package.json +46 -41
- package/dist/build/buildPages/buildPages.js +0 -31
- package/dist/utils/formatErrorMessage.js +0 -56
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2020-
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -13,8 +13,9 @@
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import { type } from '@lowdefy/helpers';
|
|
16
|
+
import { ConfigError } from '@lowdefy/errors';
|
|
16
17
|
import page404 from './404.js';
|
|
17
|
-
function addDefaultPages({ components }) {
|
|
18
|
+
function addDefaultPages({ components, context }) {
|
|
18
19
|
// If not copied, the same object is mutated by build every time
|
|
19
20
|
// build runs for dev server. See #647
|
|
20
21
|
const defaultPages = [
|
|
@@ -24,11 +25,16 @@ function addDefaultPages({ components }) {
|
|
|
24
25
|
components.pages = [];
|
|
25
26
|
}
|
|
26
27
|
if (!type.isArray(components.pages)) {
|
|
27
|
-
throw new
|
|
28
|
+
throw new ConfigError('lowdefy.pages is not an array.', {
|
|
29
|
+
received: components.pages
|
|
30
|
+
});
|
|
28
31
|
}
|
|
29
32
|
const pageIds = components.pages.map((page, index)=>{
|
|
30
33
|
if (!type.isObject(page)) {
|
|
31
|
-
throw new
|
|
34
|
+
throw new ConfigError(`pages[${index}] is not an object.`, {
|
|
35
|
+
received: page,
|
|
36
|
+
configKey: page?.['~k']
|
|
37
|
+
});
|
|
32
38
|
}
|
|
33
39
|
return page.id;
|
|
34
40
|
});
|
package/dist/build/addKeys.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2020-
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -13,13 +13,37 @@
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import { type } from '@lowdefy/helpers';
|
|
16
|
+
import { ConfigError, VALID_CHECK_SLUGS } from '@lowdefy/errors';
|
|
17
|
+
import collectExceptions from '../utils/collectExceptions.js';
|
|
16
18
|
import makeId from '../utils/makeId.js';
|
|
17
|
-
|
|
19
|
+
import setNonEnumerableProperty from '../utils/setNonEnumerableProperty.js';
|
|
20
|
+
function recArray({ array, arrayKey, keyMap, parentKeyMapId, context }) {
|
|
21
|
+
let arrayKeyMapId;
|
|
22
|
+
if (array['~k']) {
|
|
23
|
+
arrayKeyMapId = array['~k'];
|
|
24
|
+
} else {
|
|
25
|
+
arrayKeyMapId = makeId.next();
|
|
26
|
+
const entry = {
|
|
27
|
+
key: arrayKey,
|
|
28
|
+
'~k_parent': parentKeyMapId
|
|
29
|
+
};
|
|
30
|
+
if (array['~r'] !== undefined) entry['~r'] = array['~r'];
|
|
31
|
+
if (array['~l'] !== undefined) entry['~l'] = array['~l'];
|
|
32
|
+
keyMap[arrayKeyMapId] = entry;
|
|
33
|
+
Object.defineProperty(array, '~k', {
|
|
34
|
+
value: arrayKeyMapId,
|
|
35
|
+
enumerable: false,
|
|
36
|
+
writable: true,
|
|
37
|
+
configurable: true
|
|
38
|
+
});
|
|
39
|
+
delete array['~r'];
|
|
40
|
+
delete array['~l'];
|
|
41
|
+
}
|
|
18
42
|
array.forEach((item, index)=>{
|
|
19
43
|
if (type.isObject(item)) {
|
|
20
|
-
let path = `${
|
|
44
|
+
let path = `${arrayKey}[${index}]`;
|
|
21
45
|
// TODO: Convert all artifacts to not modify id.
|
|
22
|
-
const id = item.blockId ?? item.menuId ?? item.menuItemId ?? item.requestId ?? item.connectionId ?? item.
|
|
46
|
+
const id = item.blockId ?? item.menuId ?? item.menuItemId ?? item.requestId ?? item.connectionId ?? item.id;
|
|
23
47
|
if (id) {
|
|
24
48
|
path = `${path.slice(0, -1)}:${id}]`;
|
|
25
49
|
}
|
|
@@ -30,61 +54,93 @@ function recArray({ array, nextKey, key, keyMap, keyMapId }) {
|
|
|
30
54
|
object: item,
|
|
31
55
|
key: path,
|
|
32
56
|
keyMap: keyMap,
|
|
33
|
-
parentKeyMapId:
|
|
57
|
+
parentKeyMapId: arrayKeyMapId,
|
|
58
|
+
context
|
|
34
59
|
});
|
|
35
60
|
}
|
|
36
61
|
if (type.isArray(item)) {
|
|
37
62
|
recArray({
|
|
38
63
|
array: item,
|
|
39
|
-
|
|
40
|
-
key,
|
|
64
|
+
arrayKey: `${arrayKey}[${index}]`,
|
|
41
65
|
keyMap,
|
|
42
|
-
|
|
66
|
+
parentKeyMapId: arrayKeyMapId,
|
|
67
|
+
context
|
|
43
68
|
});
|
|
44
69
|
}
|
|
45
70
|
});
|
|
46
71
|
}
|
|
47
|
-
function recAddKeys({ object, key, keyMap, parentKeyMapId }) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
'~
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
72
|
+
function recAddKeys({ object, key, keyMap, parentKeyMapId, context }) {
|
|
73
|
+
let keyMapId;
|
|
74
|
+
let storedKey = key;
|
|
75
|
+
// Skip objects that already have a ~k (already processed)
|
|
76
|
+
if (object['~k']) {
|
|
77
|
+
keyMapId = object['~k'];
|
|
78
|
+
// Use the stored key from keyMap for correct child paths
|
|
79
|
+
storedKey = keyMap[keyMapId]?.key ?? key;
|
|
80
|
+
} else {
|
|
81
|
+
keyMapId = makeId.next();
|
|
82
|
+
const entry = {
|
|
83
|
+
key,
|
|
84
|
+
'~k_parent': parentKeyMapId
|
|
85
|
+
};
|
|
86
|
+
if (object['~r'] !== undefined) entry['~r'] = object['~r'];
|
|
87
|
+
if (object['~l'] !== undefined) entry['~l'] = object['~l'];
|
|
88
|
+
// Add entry to keyMap BEFORE validation so errors can resolve location
|
|
89
|
+
keyMap[keyMapId] = entry;
|
|
90
|
+
// Handle ~ignoreBuildChecks property
|
|
91
|
+
if (object['~ignoreBuildChecks'] !== undefined) {
|
|
92
|
+
const checks = object['~ignoreBuildChecks'];
|
|
93
|
+
if (Array.isArray(checks)) {
|
|
94
|
+
const validSlugs = Object.keys(VALID_CHECK_SLUGS);
|
|
95
|
+
const invalid = checks.filter((slug)=>!validSlugs.includes(slug));
|
|
96
|
+
if (invalid.length > 0) {
|
|
97
|
+
collectExceptions(context, new ConfigError(`Invalid check slug(s): "${invalid.join('", "')}". Valid slugs: ${validSlugs.join(', ')}`, {
|
|
98
|
+
configKey: keyMapId
|
|
99
|
+
}));
|
|
100
|
+
}
|
|
101
|
+
} else if (checks !== true) {
|
|
102
|
+
collectExceptions(context, new ConfigError('~ignoreBuildChecks must be true or an array of check slugs.', {
|
|
103
|
+
received: checks,
|
|
104
|
+
configKey: keyMapId
|
|
105
|
+
}));
|
|
106
|
+
}
|
|
107
|
+
entry['~ignoreBuildChecks'] = checks;
|
|
108
|
+
}
|
|
109
|
+
setNonEnumerableProperty(object, '~k', keyMapId);
|
|
110
|
+
delete object['~r'];
|
|
111
|
+
delete object['~l'];
|
|
112
|
+
delete object['~ignoreBuildChecks'];
|
|
113
|
+
}
|
|
114
|
+
// Always recurse into children (they may be new objects without keys)
|
|
61
115
|
Object.keys(object).forEach((nextKey)=>{
|
|
62
116
|
if (type.isObject(object[nextKey])) {
|
|
63
117
|
recAddKeys({
|
|
64
118
|
object: object[nextKey],
|
|
65
|
-
key: `${
|
|
119
|
+
key: `${storedKey}.${nextKey}`,
|
|
66
120
|
keyMap: keyMap,
|
|
67
|
-
parentKeyMapId: keyMapId
|
|
121
|
+
parentKeyMapId: keyMapId,
|
|
122
|
+
context
|
|
68
123
|
});
|
|
69
124
|
}
|
|
70
125
|
if (type.isArray(object[nextKey])) {
|
|
71
126
|
recArray({
|
|
72
127
|
array: object[nextKey],
|
|
73
|
-
nextKey
|
|
74
|
-
key,
|
|
128
|
+
arrayKey: `${storedKey}.${nextKey}`,
|
|
75
129
|
keyMap,
|
|
76
|
-
keyMapId
|
|
130
|
+
parentKeyMapId: keyMapId,
|
|
131
|
+
context
|
|
77
132
|
});
|
|
78
133
|
}
|
|
79
134
|
});
|
|
80
135
|
}
|
|
81
136
|
function addKeys({ components, context }) {
|
|
82
|
-
const keyMapId = makeId(
|
|
137
|
+
const keyMapId = makeId.next();
|
|
83
138
|
recAddKeys({
|
|
84
139
|
object: components,
|
|
85
140
|
key: 'root',
|
|
86
141
|
keyMap: context.keyMap,
|
|
87
|
-
parentKeyMapId: keyMapId
|
|
142
|
+
parentKeyMapId: keyMapId,
|
|
143
|
+
context
|
|
88
144
|
});
|
|
89
145
|
}
|
|
90
146
|
export default addKeys;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2020-
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -13,22 +13,41 @@
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import { type } from '@lowdefy/helpers';
|
|
16
|
+
import { ConfigError, shouldSuppressBuildCheck } from '@lowdefy/errors';
|
|
16
17
|
import createCheckDuplicateId from '../../utils/createCheckDuplicateId.js';
|
|
17
18
|
import buildEndpoint from './buildEndpoint.js';
|
|
18
19
|
function buildApi({ components, context }) {
|
|
19
20
|
if (components.api && !type.isArray(components.api)) {
|
|
20
|
-
throw new
|
|
21
|
+
throw new ConfigError('Api is not an array.', {
|
|
22
|
+
received: components.api
|
|
23
|
+
});
|
|
21
24
|
}
|
|
22
25
|
const api = type.isArray(components.api) ? components.api : [];
|
|
23
26
|
const checkDuplicateEndpointId = createCheckDuplicateId({
|
|
24
27
|
message: 'Duplicate endpointId "{{ id }}".'
|
|
25
28
|
});
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
// Wrap each endpoint build to collect errors instead of stopping on first error
|
|
30
|
+
api.forEach((endpoint, index)=>{
|
|
31
|
+
try {
|
|
32
|
+
buildEndpoint({
|
|
33
|
+
endpoint,
|
|
34
|
+
index,
|
|
35
|
+
context,
|
|
36
|
+
checkDuplicateEndpointId
|
|
37
|
+
});
|
|
38
|
+
} catch (error) {
|
|
39
|
+
// Skip suppressed ConfigErrors (via ~ignoreBuildChecks)
|
|
40
|
+
if (error instanceof ConfigError && shouldSuppressBuildCheck(error, context.keyMap)) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
// Collect error object if context.errors exists, otherwise throw (for backward compat with tests)
|
|
44
|
+
if (context?.errors) {
|
|
45
|
+
context.errors.push(error);
|
|
46
|
+
} else {
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
});
|
|
32
51
|
return components;
|
|
33
52
|
}
|
|
34
53
|
export default buildApi;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* eslint-disable no-param-reassign */ /*
|
|
2
|
-
Copyright 2020-
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import buildRoutine from './buildRoutine/buildRoutine.js';
|
|
16
16
|
import validateEndpoint from './validateEndpoint.js';
|
|
17
|
+
import validateStepReferences from './validateStepReferences.js';
|
|
17
18
|
function buildEndpoint({ endpoint, index, context, checkDuplicateEndpointId }) {
|
|
18
19
|
validateEndpoint({
|
|
19
20
|
endpoint,
|
|
@@ -25,6 +26,11 @@ function buildEndpoint({ endpoint, index, context, checkDuplicateEndpointId }) {
|
|
|
25
26
|
endpointId: endpoint.endpointId,
|
|
26
27
|
typeCounters: context.typeCounters
|
|
27
28
|
});
|
|
29
|
+
// Validate that _step references point to defined step IDs
|
|
30
|
+
validateStepReferences({
|
|
31
|
+
endpoint,
|
|
32
|
+
context
|
|
33
|
+
});
|
|
28
34
|
endpoint.id = `endpoint:${endpoint.endpointId}`;
|
|
29
35
|
}
|
|
30
36
|
export default buildEndpoint;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2020-
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import { type } from '@lowdefy/helpers';
|
|
16
|
+
import { ConfigError } from '@lowdefy/errors';
|
|
16
17
|
import buildRoutine from './buildRoutine.js';
|
|
17
18
|
import countControl from './countControl.js';
|
|
18
19
|
import countOperators from '../../../utils/countOperators.js';
|
|
@@ -144,23 +145,35 @@ const controlTypes = {
|
|
|
144
145
|
function getAdditionalKeys(controlType, keys) {
|
|
145
146
|
return keys.filter((item)=>!controlTypes[controlType].required.includes(item));
|
|
146
147
|
}
|
|
147
|
-
function checkMissingRequiredControls({ controlType, keys },
|
|
148
|
+
function checkMissingRequiredControls({ controlType, keys, control }, endpointContext) {
|
|
149
|
+
const { endpointId } = endpointContext;
|
|
148
150
|
const missingControls = controlTypes[controlType].required.filter((item)=>!keys.includes(item));
|
|
149
151
|
if (missingControls.length > 0) {
|
|
150
|
-
throw new
|
|
152
|
+
throw new ConfigError(`Missing required control type(s) for endpoint ${endpointId}.`, {
|
|
153
|
+
received: missingControls,
|
|
154
|
+
configKey: control?.['~k']
|
|
155
|
+
});
|
|
151
156
|
}
|
|
152
157
|
}
|
|
153
|
-
function checkInvalidControls({ controlType, keys },
|
|
158
|
+
function checkInvalidControls({ controlType, keys, control }, endpointContext) {
|
|
159
|
+
const { endpointId } = endpointContext;
|
|
154
160
|
const additionalControls = getAdditionalKeys(controlType, keys);
|
|
155
161
|
const invalidControls = additionalControls.filter((item)=>!controlTypes[controlType].optional.includes(item));
|
|
156
162
|
if (invalidControls.length > 0) {
|
|
157
|
-
throw new
|
|
163
|
+
throw new ConfigError(`Invalid control type(s) for endpoint ${endpointId}.`, {
|
|
164
|
+
received: invalidControls,
|
|
165
|
+
configKey: control?.['~k']
|
|
166
|
+
});
|
|
158
167
|
}
|
|
159
168
|
}
|
|
160
169
|
function handleSwitch(control, endpointContext) {
|
|
170
|
+
const { endpointId } = endpointContext;
|
|
161
171
|
const switchArray = control[':switch'];
|
|
162
172
|
if (!type.isArray(control[':switch'])) {
|
|
163
|
-
throw new
|
|
173
|
+
throw new ConfigError(`Type given for :switch control is invalid at endpoint ${endpointId}.`, {
|
|
174
|
+
received: control[':switch'],
|
|
175
|
+
configKey: control['~k']
|
|
176
|
+
});
|
|
164
177
|
}
|
|
165
178
|
switchArray.forEach((caseObj)=>{
|
|
166
179
|
const input = {
|
|
@@ -168,7 +181,8 @@ function handleSwitch(control, endpointContext) {
|
|
|
168
181
|
keys: [
|
|
169
182
|
':switch',
|
|
170
183
|
...Object.keys(caseObj)
|
|
171
|
-
]
|
|
184
|
+
],
|
|
185
|
+
control: caseObj
|
|
172
186
|
};
|
|
173
187
|
checkMissingRequiredControls(input, endpointContext);
|
|
174
188
|
checkInvalidControls(input, endpointContext);
|
|
@@ -185,13 +199,20 @@ function handleSwitch(control, endpointContext) {
|
|
|
185
199
|
});
|
|
186
200
|
}
|
|
187
201
|
function validateControl(control, endpointContext) {
|
|
202
|
+
const { endpointId } = endpointContext;
|
|
188
203
|
const keys = Object.keys(control);
|
|
189
204
|
const intersection = keys.filter((item)=>Object.keys(controlTypes).includes(item));
|
|
190
205
|
if (intersection.length === 0) {
|
|
191
|
-
throw new
|
|
206
|
+
throw new ConfigError(`Invalid control type(s) for endpoint ${endpointId}.`, {
|
|
207
|
+
received: keys,
|
|
208
|
+
configKey: control['~k']
|
|
209
|
+
});
|
|
192
210
|
}
|
|
193
211
|
if (intersection.length > 1) {
|
|
194
|
-
throw new
|
|
212
|
+
throw new ConfigError(`More than one control type found for endpoint ${endpointId}.`, {
|
|
213
|
+
received: intersection,
|
|
214
|
+
configKey: control['~k']
|
|
215
|
+
});
|
|
195
216
|
}
|
|
196
217
|
const controlType = intersection[0];
|
|
197
218
|
if (controlType === ':switch') {
|
|
@@ -200,11 +221,13 @@ function validateControl(control, endpointContext) {
|
|
|
200
221
|
}
|
|
201
222
|
checkMissingRequiredControls({
|
|
202
223
|
controlType,
|
|
203
|
-
keys
|
|
224
|
+
keys,
|
|
225
|
+
control
|
|
204
226
|
}, endpointContext);
|
|
205
227
|
checkInvalidControls({
|
|
206
228
|
controlType,
|
|
207
|
-
keys
|
|
229
|
+
keys,
|
|
230
|
+
control
|
|
208
231
|
}, endpointContext);
|
|
209
232
|
return controlType;
|
|
210
233
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2020-
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -13,6 +13,6 @@
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ function countStepTypes(step, { typeCounters }) {
|
|
16
|
-
typeCounters.requests.increment(step.type);
|
|
16
|
+
typeCounters.requests.increment(step.type, step['~k']);
|
|
17
17
|
}
|
|
18
18
|
export default countStepTypes;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2020-
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -13,30 +13,51 @@
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import { type } from '@lowdefy/helpers';
|
|
16
|
+
import { ConfigError } from '@lowdefy/errors';
|
|
16
17
|
function validateStep(step, { endpointId }) {
|
|
18
|
+
const configKey = step['~k'];
|
|
17
19
|
if (Object.keys(step).length === 0) {
|
|
18
|
-
throw new
|
|
20
|
+
throw new ConfigError(`Step is not defined at endpoint "${endpointId}".`, {
|
|
21
|
+
configKey
|
|
22
|
+
});
|
|
19
23
|
}
|
|
20
24
|
if (type.isUndefined(step.id)) {
|
|
21
|
-
throw new
|
|
25
|
+
throw new ConfigError(`Step id missing at endpoint "${endpointId}".`, {
|
|
26
|
+
configKey
|
|
27
|
+
});
|
|
22
28
|
}
|
|
23
29
|
if (!type.isString(step.id)) {
|
|
24
|
-
throw new
|
|
30
|
+
throw new ConfigError(`Step id is not a string at endpoint "${endpointId}".`, {
|
|
31
|
+
received: step.id,
|
|
32
|
+
configKey
|
|
33
|
+
});
|
|
25
34
|
}
|
|
26
35
|
if (step.id.includes('.')) {
|
|
27
|
-
throw new
|
|
36
|
+
throw new ConfigError(`Step id "${step.id}" at endpoint "${endpointId}" should not include a period (".").`, {
|
|
37
|
+
configKey
|
|
38
|
+
});
|
|
28
39
|
}
|
|
29
40
|
if (type.isNone(step.type)) {
|
|
30
|
-
throw new
|
|
41
|
+
throw new ConfigError(`Step type is not defined at "${step.id}" on endpoint "${endpointId}".`, {
|
|
42
|
+
configKey
|
|
43
|
+
});
|
|
31
44
|
}
|
|
32
45
|
if (!type.isString(step.type)) {
|
|
33
|
-
throw new
|
|
46
|
+
throw new ConfigError(`Step type is not a string at "${step.id}" on endpoint "${endpointId}".`, {
|
|
47
|
+
received: step.type,
|
|
48
|
+
configKey
|
|
49
|
+
});
|
|
34
50
|
}
|
|
35
51
|
if (type.isUndefined(step.connectionId)) {
|
|
36
|
-
throw new
|
|
52
|
+
throw new ConfigError(`Step connectionId missing at endpoint "${endpointId}".`, {
|
|
53
|
+
configKey
|
|
54
|
+
});
|
|
37
55
|
}
|
|
38
56
|
if (!type.isString(step.connectionId)) {
|
|
39
|
-
throw new
|
|
57
|
+
throw new ConfigError(`Step connectionId is not a string at endpoint "${endpointId}".`, {
|
|
58
|
+
received: step.connectionId,
|
|
59
|
+
configKey
|
|
60
|
+
});
|
|
40
61
|
}
|
|
41
62
|
}
|
|
42
63
|
export default validateStep;
|
|
@@ -1,22 +1,51 @@
|
|
|
1
|
-
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/ import { type } from '@lowdefy/helpers';
|
|
16
|
+
import { ConfigError } from '@lowdefy/errors';
|
|
2
17
|
function validateEndpoint({ endpoint, index, checkDuplicateEndpointId }) {
|
|
18
|
+
const configKey = endpoint['~k'];
|
|
3
19
|
if (type.isUndefined(endpoint.id)) {
|
|
4
|
-
throw new
|
|
20
|
+
throw new ConfigError(`Endpoint id missing at endpoint ${index}.`, {
|
|
21
|
+
configKey
|
|
22
|
+
});
|
|
5
23
|
}
|
|
6
24
|
if (!type.isString(endpoint.id)) {
|
|
7
|
-
throw new
|
|
25
|
+
throw new ConfigError(`Endpoint id is not a string at endpoint ${index}.`, {
|
|
26
|
+
received: endpoint.id,
|
|
27
|
+
configKey
|
|
28
|
+
});
|
|
8
29
|
}
|
|
9
30
|
if (endpoint.id.includes('.')) {
|
|
10
|
-
throw new
|
|
31
|
+
throw new ConfigError(`Endpoint id "${endpoint.id}" should not include a period (".").`, {
|
|
32
|
+
configKey
|
|
33
|
+
});
|
|
11
34
|
}
|
|
12
35
|
if (type.isUndefined(endpoint.type)) {
|
|
13
|
-
throw new
|
|
36
|
+
throw new ConfigError(`Endpoint type is not defined at "${endpoint.id}".`, {
|
|
37
|
+
configKey
|
|
38
|
+
});
|
|
14
39
|
}
|
|
15
40
|
if (!type.isString(endpoint.type)) {
|
|
16
|
-
throw new
|
|
41
|
+
throw new ConfigError(`Endpoint type is not a string at "${endpoint.id}".`, {
|
|
42
|
+
received: endpoint.type,
|
|
43
|
+
configKey
|
|
44
|
+
});
|
|
17
45
|
}
|
|
18
46
|
checkDuplicateEndpointId({
|
|
19
|
-
id: endpoint.id
|
|
47
|
+
id: endpoint.id,
|
|
48
|
+
configKey
|
|
20
49
|
});
|
|
21
50
|
}
|
|
22
51
|
export default validateEndpoint;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/ import { ConfigWarning } from '@lowdefy/errors';
|
|
16
|
+
import { type } from '@lowdefy/helpers';
|
|
17
|
+
import extractOperatorKey from '../../utils/extractOperatorKey.js';
|
|
18
|
+
import traverseConfig from '../../utils/traverseConfig.js';
|
|
19
|
+
// Collect all step IDs from a routine (including nested control structures)
|
|
20
|
+
// Note: After buildRoutine, steps have requestId (original id) and id is modified
|
|
21
|
+
function collectStepIds(routine, stepIds) {
|
|
22
|
+
if (type.isArray(routine)) {
|
|
23
|
+
routine.forEach((item)=>collectStepIds(item, stepIds));
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (type.isObject(routine)) {
|
|
27
|
+
// Check if this is a step (has requestId after build, or id before build)
|
|
28
|
+
if (routine.requestId) {
|
|
29
|
+
stepIds.add(routine.requestId);
|
|
30
|
+
}
|
|
31
|
+
// Recurse into all values (handles control structures like :then, :else, :try, :catch)
|
|
32
|
+
Object.values(routine).forEach((value)=>collectStepIds(value, stepIds));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function validateStepReferences({ endpoint, context }) {
|
|
36
|
+
// Collect all step IDs defined in the routine
|
|
37
|
+
const stepIds = new Set();
|
|
38
|
+
collectStepIds(endpoint.routine, stepIds);
|
|
39
|
+
// Find _step references in the routine
|
|
40
|
+
const stepRefs = new Map(); // topLevelKey -> configKey (first occurrence)
|
|
41
|
+
traverseConfig({
|
|
42
|
+
config: endpoint.routine,
|
|
43
|
+
visitor: (obj)=>{
|
|
44
|
+
if (obj._step !== undefined) {
|
|
45
|
+
const stepId = extractOperatorKey({
|
|
46
|
+
operatorValue: obj._step
|
|
47
|
+
});
|
|
48
|
+
if (stepId && !stepRefs.has(stepId)) {
|
|
49
|
+
stepRefs.set(stepId, obj['~k']);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
// Warn for undefined step references
|
|
55
|
+
stepRefs.forEach((configKey, stepId)=>{
|
|
56
|
+
if (stepIds.has(stepId)) return;
|
|
57
|
+
const message = `_step references "${stepId}" in endpoint "${endpoint.endpointId}", ` + `but no step with id "${stepId}" exists in the routine. ` + `Step IDs are defined by the "id" property of each step. ` + `Check for typos or add a step with this id.`;
|
|
58
|
+
context.handleWarning(new ConfigWarning(message, {
|
|
59
|
+
configKey,
|
|
60
|
+
prodError: true,
|
|
61
|
+
checkSlug: 'step-refs'
|
|
62
|
+
}));
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
export default validateStepReferences;
|
package/dist/build/buildApp.js
CHANGED