@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.
Files changed (165) hide show
  1. package/dist/build/addDefaultPages/404.js +1 -1
  2. package/dist/build/addDefaultPages/addDefaultPages.js +10 -4
  3. package/dist/build/addKeys.js +85 -29
  4. package/dist/build/buildApi/buildApi.js +27 -8
  5. package/dist/build/buildApi/buildEndpoint.js +7 -1
  6. package/dist/build/buildApi/buildRoutine/buildControl.js +1 -1
  7. package/dist/build/buildApi/buildRoutine/buildRoutine.js +1 -1
  8. package/dist/build/buildApi/buildRoutine/buildStep.js +1 -1
  9. package/dist/build/buildApi/buildRoutine/controlTypes.js +34 -11
  10. package/dist/build/buildApi/buildRoutine/countControl.js +1 -1
  11. package/dist/build/buildApi/buildRoutine/countStepTypes.js +2 -2
  12. package/dist/build/buildApi/buildRoutine/setStepId.js +1 -1
  13. package/dist/build/buildApi/buildRoutine/validateStep.js +30 -9
  14. package/dist/build/buildApi/validateEndpoint.js +36 -7
  15. package/dist/build/buildApi/validateStepReferences.js +65 -0
  16. package/dist/build/buildApp.js +1 -1
  17. package/dist/build/buildAuth/buildApiAuth.js +7 -3
  18. package/dist/build/buildAuth/buildAuth.js +7 -4
  19. package/dist/build/buildAuth/buildAuthPlugins.js +42 -13
  20. package/dist/build/buildAuth/buildPageAuth.js +14 -3
  21. package/dist/build/buildAuth/getApiRoles.js +1 -1
  22. package/dist/build/buildAuth/getPageRoles.js +1 -1
  23. package/dist/build/buildAuth/getProtectedApi.js +1 -1
  24. package/dist/build/buildAuth/getProtectedPages.js +1 -1
  25. package/dist/build/buildAuth/validateAuthConfig.js +39 -5
  26. package/dist/build/buildAuth/validateMutualExclusivity.js +13 -5
  27. package/dist/build/buildConnections.js +23 -24
  28. package/dist/build/buildImports/buildIconImports.js +1 -1
  29. package/dist/build/buildImports/buildImports.js +1 -1
  30. package/dist/build/buildImports/buildImportsDev.js +1 -1
  31. package/dist/build/buildImports/buildImportsProd.js +1 -1
  32. package/dist/build/buildImports/buildStyleImports.js +1 -1
  33. package/dist/build/buildImports/defaultIconsDev.js +1 -1
  34. package/dist/build/buildImports/defaultIconsProd.js +1 -1
  35. package/dist/build/buildJs/generateJsFile.js +1 -1
  36. package/dist/build/buildJs/jsMapParser.js +1 -1
  37. package/dist/build/buildJs/writeJs.js +1 -1
  38. package/dist/build/buildLogger.js +41 -0
  39. package/dist/build/buildMenu.js +36 -12
  40. package/dist/build/buildPages/buildBlock/buildBlock.js +1 -1
  41. package/dist/build/buildPages/buildBlock/buildEvents.js +79 -9
  42. package/dist/build/buildPages/buildBlock/buildRequests.js +38 -8
  43. package/dist/build/buildPages/buildBlock/buildSubBlocks.js +6 -2
  44. package/dist/build/buildPages/buildBlock/countBlockOperators.js +1 -1
  45. package/dist/build/buildPages/buildBlock/countBlockTypes.js +2 -2
  46. package/dist/build/buildPages/buildBlock/moveSkeletonBlocksToArea.js +6 -2
  47. package/dist/build/buildPages/buildBlock/moveSubBlocksToArea.js +6 -2
  48. package/dist/build/buildPages/buildBlock/setBlockId.js +1 -1
  49. package/dist/build/buildPages/buildBlock/validateBlock.js +25 -7
  50. package/dist/build/buildPages/buildPage.js +35 -6
  51. package/dist/build/buildPages/validateLinkReferences.js +33 -0
  52. package/dist/build/buildPages/validatePayloadReferences.js +59 -0
  53. package/dist/build/buildPages/validateRequestReferences.js +33 -0
  54. package/dist/build/buildPages/validateServerStateReferences.js +41 -0
  55. package/dist/build/buildPages/validateStateReferences.js +79 -0
  56. package/dist/build/buildRefs/buildRefs.js +20 -3
  57. package/dist/build/buildRefs/createRefReviver.js +28 -0
  58. package/dist/build/buildRefs/evaluateBuildOperators.js +26 -7
  59. package/dist/build/buildRefs/evaluateStaticOperators.js +56 -0
  60. package/dist/build/buildRefs/getConfigFile.js +25 -6
  61. package/dist/build/buildRefs/getKey.js +1 -1
  62. package/dist/build/buildRefs/getRefContent.js +1 -1
  63. package/dist/build/buildRefs/getRefPath.js +1 -1
  64. package/dist/build/buildRefs/getRefsFromFile.js +9 -4
  65. package/dist/build/buildRefs/getUserJavascriptFunction.js +18 -4
  66. package/dist/build/buildRefs/makeRefDefinition.js +10 -5
  67. package/dist/build/buildRefs/parseNunjucks.js +1 -1
  68. package/dist/build/buildRefs/parseRefContent.js +100 -6
  69. package/dist/build/buildRefs/populateRefs.js +75 -13
  70. package/dist/build/buildRefs/recursiveBuild.js +66 -18
  71. package/dist/build/buildRefs/runRefResolver.js +11 -3
  72. package/dist/build/buildRefs/runTransformer.js +7 -3
  73. package/dist/build/buildTypes.js +22 -7
  74. package/dist/build/cleanBuildDirectory.js +1 -1
  75. package/dist/build/collectDynamicIdentifiers.js +35 -0
  76. package/dist/build/collectTypeNames.js +36 -0
  77. package/dist/build/copyPublicFolder.js +1 -1
  78. package/dist/build/{buildJs → full}/buildJs.js +3 -3
  79. package/dist/build/full/buildPages.js +87 -0
  80. package/dist/build/{buildPages → full}/buildTestPage.js +15 -3
  81. package/dist/build/{updateServerPackageJson.js → full/updateServerPackageJson.js} +1 -1
  82. package/dist/build/{writePages.js → full/writePages.js} +1 -1
  83. package/dist/build/{writeRequests.js → full/writeRequests.js} +11 -3
  84. package/dist/build/{writeTypes.js → full/writeTypes.js} +1 -1
  85. package/dist/build/jit/addInstalledTypes.js +51 -0
  86. package/dist/build/jit/buildJsShallow.js +41 -0
  87. package/dist/build/jit/buildPageJit.js +252 -0
  88. package/dist/build/jit/buildShallowPages.js +90 -0
  89. package/dist/build/jit/createPageRegistry.js +80 -0
  90. package/dist/build/jit/detectMissingPluginPackages.js +62 -0
  91. package/dist/build/jit/getRefPositions.js +38 -0
  92. package/dist/build/jit/isPageContentPath.js +24 -0
  93. package/dist/build/jit/pageContentKeys.js +26 -0
  94. package/dist/build/jit/shallowBuild.js +245 -0
  95. package/dist/build/jit/stripPageContent.js +23 -0
  96. package/dist/build/jit/updateServerPackageJsonJit.js +33 -0
  97. package/dist/build/jit/validatePageTypes.js +73 -0
  98. package/dist/build/jit/writePageJit.js +44 -0
  99. package/dist/build/jit/writePageRegistry.js +23 -0
  100. package/dist/build/jit/writeSourcelessPages.js +23 -0
  101. package/dist/build/testSchema.js +45 -7
  102. package/dist/build/validateConfig.js +2 -2
  103. package/dist/build/validateOperatorsDynamic.js +28 -0
  104. package/dist/build/writeApi.js +1 -1
  105. package/dist/build/writeApp.js +1 -1
  106. package/dist/build/writeAuth.js +1 -1
  107. package/dist/build/writeConfig.js +1 -1
  108. package/dist/build/writeConnections.js +1 -1
  109. package/dist/build/writeGlobal.js +1 -1
  110. package/dist/build/writeLogger.js +19 -0
  111. package/dist/build/writeMaps.js +1 -1
  112. package/dist/build/writeMenus.js +1 -1
  113. package/dist/build/writePluginImports/generateImportFile.js +1 -1
  114. package/dist/build/writePluginImports/writeActionImports.js +1 -1
  115. package/dist/build/writePluginImports/writeActionSchemaMap.js +42 -0
  116. package/dist/build/writePluginImports/writeAuthImports.js +1 -1
  117. package/dist/build/writePluginImports/writeBlockImports.js +1 -1
  118. package/dist/build/writePluginImports/writeBlockSchemaMap.js +42 -0
  119. package/dist/build/writePluginImports/writeConnectionImports.js +1 -1
  120. package/dist/build/writePluginImports/writeIconImports.js +1 -1
  121. package/dist/build/writePluginImports/writeOperatorImports.js +1 -1
  122. package/dist/build/writePluginImports/writeOperatorSchemaMap.js +49 -0
  123. package/dist/build/writePluginImports/writePluginImports.js +16 -1
  124. package/dist/build/writePluginImports/writeStyleImports.js +1 -1
  125. package/dist/createContext.js +16 -4
  126. package/dist/defaultTypesMap.js +479 -457
  127. package/dist/index.js +188 -127
  128. package/dist/indexDev.js +18 -0
  129. package/dist/lowdefySchema.js +589 -0
  130. package/dist/scripts/generateDefaultTypes.js +2 -1
  131. package/dist/scripts/run.js +1 -1
  132. package/dist/{test → test-utils}/buildRefs/testBuildRefsAsyncFunction.js +1 -1
  133. package/dist/{test → test-utils}/buildRefs/testBuildRefsErrorResolver.js +1 -1
  134. package/dist/{test → test-utils}/buildRefs/testBuildRefsNullResolver.js +1 -1
  135. package/dist/{test → test-utils}/buildRefs/testBuildRefsParsingResolver.js +1 -1
  136. package/dist/{test → test-utils}/buildRefs/testBuildRefsResolver.js +1 -1
  137. package/dist/{test → test-utils}/buildRefs/testBuildRefsTransform.js +1 -1
  138. package/dist/{test → test-utils}/buildRefs/testBuildRefsTransformIdentity.js +1 -1
  139. package/dist/test-utils/buildRefs/testJitPageResolver.js +24 -0
  140. package/dist/test-utils/createTestLogger.js +36 -0
  141. package/dist/test-utils/parseTestYaml.js +126 -0
  142. package/dist/test-utils/runBuild.js +228 -0
  143. package/dist/test-utils/runBuildForSnapshots.js +704 -0
  144. package/dist/{test → test-utils}/testContext.js +12 -2
  145. package/dist/utils/collectExceptions.js +34 -0
  146. package/dist/utils/countOperators.js +31 -12
  147. package/dist/utils/createBuildHandleError.js +38 -0
  148. package/dist/utils/createCheckDuplicateId.js +15 -9
  149. package/dist/utils/createCounter.js +16 -3
  150. package/dist/utils/createHandleWarning.js +41 -0
  151. package/dist/utils/createPluginTypesMap.js +1 -1
  152. package/dist/utils/extractOperatorKey.js +36 -0
  153. package/dist/utils/findConfigKey.js +37 -0
  154. package/dist/utils/findSimilarString.js +53 -0
  155. package/dist/utils/logCollectedErrors.js +30 -0
  156. package/dist/utils/makeId.js +13 -8
  157. package/dist/utils/preserveMetaProperties.js +27 -0
  158. package/dist/utils/readConfigFile.js +1 -1
  159. package/dist/utils/setNonEnumerableProperty.js +23 -0
  160. package/dist/utils/traverseConfig.js +43 -0
  161. package/dist/utils/tryBuildStep.js +46 -0
  162. package/dist/utils/writeBuildArtifact.js +1 -1
  163. package/package.json +46 -41
  164. package/dist/build/buildPages/buildPages.js +0 -31
  165. package/dist/utils/formatErrorMessage.js +0 -56
@@ -0,0 +1,245 @@
1
+ /* eslint-disable no-console */ /*
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 { BuildError, LowdefyInternalError } from '@lowdefy/errors';
16
+ import createContext from '../../createContext.js';
17
+ import logCollectedErrors from '../../utils/logCollectedErrors.js';
18
+ import makeId from '../../utils/makeId.js';
19
+ import tryBuildStep from '../../utils/tryBuildStep.js';
20
+ import addDefaultPages from '../addDefaultPages/addDefaultPages.js';
21
+ import addKeys from '../addKeys.js';
22
+ import buildApp from '../buildApp.js';
23
+ import buildAuth from '../buildAuth/buildAuth.js';
24
+ import buildConnections from '../buildConnections.js';
25
+ import buildApi from '../buildApi/buildApi.js';
26
+ import buildLogger from '../buildLogger.js';
27
+ import buildImports from '../buildImports/buildImports.js';
28
+ import buildMenu from '../buildMenu.js';
29
+ import buildRefs from '../buildRefs/buildRefs.js';
30
+ import buildTypes from '../buildTypes.js';
31
+ import cleanBuildDirectory from '../cleanBuildDirectory.js';
32
+ import copyPublicFolder from '../copyPublicFolder.js';
33
+ import testSchema from '../testSchema.js';
34
+ import validateConfig from '../validateConfig.js';
35
+ import writeApp from '../writeApp.js';
36
+ import writeAuth from '../writeAuth.js';
37
+ import writeConfig from '../writeConfig.js';
38
+ import writeConnections from '../writeConnections.js';
39
+ import writeApi from '../writeApi.js';
40
+ import writeGlobal from '../writeGlobal.js';
41
+ import writeJs from '../buildJs/writeJs.js';
42
+ import writeLogger from '../writeLogger.js';
43
+ import writeMaps from '../writeMaps.js';
44
+ import updateServerPackageJson from '../full/updateServerPackageJson.js';
45
+ import writeMenus from '../writeMenus.js';
46
+ import writePageRegistry from './writePageRegistry.js';
47
+ import writePluginImports from '../writePluginImports/writePluginImports.js';
48
+ import addInstalledTypes from './addInstalledTypes.js';
49
+ import buildJsShallow from './buildJsShallow.js';
50
+ import buildShallowPages from './buildShallowPages.js';
51
+ import stripPageContent from './stripPageContent.js';
52
+ import writeSourcelessPages from './writeSourcelessPages.js';
53
+ async function shallowBuild(options) {
54
+ makeId.reset();
55
+ let context;
56
+ try {
57
+ context = createContext(options);
58
+ let components;
59
+ try {
60
+ components = await buildRefs({
61
+ context,
62
+ shallowOptions: true
63
+ });
64
+ } catch (err) {
65
+ if (err.isLowdefyError) {
66
+ context.handleError(err);
67
+ throw new BuildError('Build failed with 1 error(s). See above for details.');
68
+ }
69
+ throw err;
70
+ }
71
+ // addKeys + testSchema first for error location info
72
+ tryBuildStep(addKeys, 'addKeys', {
73
+ components,
74
+ context
75
+ });
76
+ stripPageContent({
77
+ components
78
+ });
79
+ tryBuildStep(testSchema, 'testSchema', {
80
+ components,
81
+ context
82
+ });
83
+ logCollectedErrors(context);
84
+ // Build skeleton steps (everything except page content)
85
+ tryBuildStep(buildApp, 'buildApp', {
86
+ components,
87
+ context
88
+ });
89
+ tryBuildStep(buildLogger, 'buildLogger', {
90
+ components,
91
+ context
92
+ });
93
+ tryBuildStep(validateConfig, 'validateConfig', {
94
+ components,
95
+ context
96
+ });
97
+ tryBuildStep(addDefaultPages, 'addDefaultPages', {
98
+ components,
99
+ context
100
+ });
101
+ tryBuildStep(addKeys, 'addKeys', {
102
+ components,
103
+ context
104
+ });
105
+ tryBuildStep(buildAuth, 'buildAuth', {
106
+ components,
107
+ context
108
+ });
109
+ tryBuildStep(buildConnections, 'buildConnections', {
110
+ components,
111
+ context
112
+ });
113
+ tryBuildStep(buildApi, 'buildApi', {
114
+ components,
115
+ context
116
+ });
117
+ const { pageRegistry, sourcelessPageArtifacts } = buildShallowPages({
118
+ components,
119
+ context
120
+ });
121
+ tryBuildStep(buildJsShallow, 'buildJsShallow', {
122
+ components,
123
+ context
124
+ });
125
+ tryBuildStep(buildMenu, 'buildMenu', {
126
+ components,
127
+ context
128
+ });
129
+ tryBuildStep(buildTypes, 'buildTypes', {
130
+ components,
131
+ context
132
+ });
133
+ // Update server package.json before addInstalledTypes so that addInstalledTypes
134
+ // sees the full set of dependencies on every run (not just after the first build).
135
+ // This prevents plugin import files from differing between the initial and
136
+ // subsequent builds, which would trigger unnecessary Next.js rebuilds.
137
+ await updateServerPackageJson({
138
+ components,
139
+ context
140
+ });
141
+ tryBuildStep(addInstalledTypes, 'addInstalledTypes', {
142
+ components,
143
+ context
144
+ });
145
+ tryBuildStep(buildImports, 'buildImports', {
146
+ components,
147
+ context
148
+ });
149
+ tryBuildStep(addKeys, 'addKeys', {
150
+ components,
151
+ context
152
+ });
153
+ logCollectedErrors(context);
154
+ // Write all build artifacts
155
+ await cleanBuildDirectory({
156
+ context
157
+ });
158
+ await writeSourcelessPages({
159
+ sourcelessPageArtifacts,
160
+ context
161
+ });
162
+ await writeApp({
163
+ components,
164
+ context
165
+ });
166
+ await writeAuth({
167
+ components,
168
+ context
169
+ });
170
+ await writeConnections({
171
+ components,
172
+ context
173
+ });
174
+ await writeApi({
175
+ components,
176
+ context
177
+ });
178
+ await writeConfig({
179
+ components,
180
+ context
181
+ });
182
+ await writeGlobal({
183
+ components,
184
+ context
185
+ });
186
+ await writeLogger({
187
+ components,
188
+ context
189
+ });
190
+ await writeMaps({
191
+ context
192
+ });
193
+ await context.writeBuildArtifact('connectionIds.json', JSON.stringify([
194
+ ...context.connectionIds
195
+ ]));
196
+ await writeMenus({
197
+ components,
198
+ context
199
+ });
200
+ await writeJs({
201
+ context
202
+ });
203
+ await context.writeBuildArtifact('jsMap.json', JSON.stringify(context.jsMap));
204
+ await context.writeBuildArtifact('customTypesMap.json', JSON.stringify(options.customTypesMap ?? {}));
205
+ // Persist snapshot of installed packages for JIT missing-package detection.
206
+ // Written as a build artifact so JIT builds compare against the skeleton
207
+ // build state, not a potentially-updated package.json (race condition).
208
+ await context.writeBuildArtifact('installedPluginPackages.json', JSON.stringify([
209
+ ...context.installedPackages ?? []
210
+ ]));
211
+ await writePluginImports({
212
+ components,
213
+ context
214
+ });
215
+ await writePageRegistry({
216
+ pageRegistry,
217
+ context
218
+ });
219
+ await copyPublicFolder({
220
+ components,
221
+ context
222
+ });
223
+ return {
224
+ components,
225
+ pageRegistry,
226
+ context
227
+ };
228
+ } catch (err) {
229
+ if (err instanceof BuildError) {
230
+ throw err;
231
+ }
232
+ // Unexpected internal error - preserve Lowdefy errors as-is, wrap plain errors
233
+ const lowdefyErr = err.isLowdefyError ? err : new LowdefyInternalError(err.message, {
234
+ cause: err
235
+ });
236
+ if (context) {
237
+ context.handleError(lowdefyErr);
238
+ } else {
239
+ const logger = options.logger ?? console;
240
+ logger.error(lowdefyErr);
241
+ }
242
+ throw new BuildError('Build failed due to internal error. See above for details.');
243
+ }
244
+ }
245
+ export default shallowBuild;
@@ -0,0 +1,23 @@
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 PAGE_CONTENT_KEYS from './pageContentKeys.js';
16
+ function stripPageContent({ components }) {
17
+ for (const page of components.pages ?? []){
18
+ for (const key of PAGE_CONTENT_KEYS){
19
+ delete page[key];
20
+ }
21
+ }
22
+ }
23
+ export default stripPageContent;
@@ -0,0 +1,33 @@
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 path from 'path';
16
+ import { readFile, writeFile } from '@lowdefy/node-utils';
17
+ async function updateServerPackageJsonJit({ directories, missingPackages }) {
18
+ const filePath = path.join(directories.server, 'package.json');
19
+ const packageJsonContent = await readFile(filePath);
20
+ const packageJson = JSON.parse(packageJsonContent);
21
+ const dependencies = packageJson.dependencies ?? {};
22
+ for (const [packageName, { version }] of missingPackages){
23
+ dependencies[packageName] = version;
24
+ }
25
+ // Sort dependencies alphabetically
26
+ packageJson.dependencies = {};
27
+ Object.keys(dependencies).sort().forEach((name)=>{
28
+ packageJson.dependencies[name] = dependencies[name];
29
+ });
30
+ const newPackageJsonContent = JSON.stringify(packageJson, null, 2).concat('\n');
31
+ await writeFile(filePath, newPackageJsonContent);
32
+ }
33
+ export default updateServerPackageJsonJit;
@@ -0,0 +1,73 @@
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 { ConfigError, ConfigWarning } from '@lowdefy/errors';
16
+ import findSimilarString from '../../utils/findSimilarString.js';
17
+ function validateTypeClass({ context, counter, definitions, typeClass, warnIfMissing = false }) {
18
+ const counts = counter.getCounts();
19
+ const definedTypes = Object.keys(definitions);
20
+ for (const typeName of Object.keys(counts)){
21
+ if (!definitions[typeName]) {
22
+ const configKey = counter.getLocation(typeName);
23
+ let message = `${typeClass} type "${typeName}" was used but is not defined.`;
24
+ const suggestion = findSimilarString({
25
+ input: typeName,
26
+ candidates: definedTypes
27
+ });
28
+ if (suggestion) {
29
+ message += ` Did you mean "${suggestion}"?`;
30
+ }
31
+ if (warnIfMissing) {
32
+ context.handleWarning(new ConfigWarning(message, {
33
+ configKey,
34
+ checkSlug: 'types'
35
+ }));
36
+ continue;
37
+ }
38
+ throw new ConfigError(message, {
39
+ configKey
40
+ });
41
+ }
42
+ }
43
+ }
44
+ function validatePageTypes({ context }) {
45
+ const { typeCounters, typesMap } = context;
46
+ validateTypeClass({
47
+ context,
48
+ counter: typeCounters.blocks,
49
+ definitions: typesMap.blocks,
50
+ typeClass: 'Block'
51
+ });
52
+ validateTypeClass({
53
+ context,
54
+ counter: typeCounters.actions,
55
+ definitions: typesMap.actions,
56
+ typeClass: 'Action'
57
+ });
58
+ validateTypeClass({
59
+ context,
60
+ counter: typeCounters.operators.client,
61
+ definitions: typesMap.operators.client,
62
+ typeClass: 'Operator',
63
+ warnIfMissing: true
64
+ });
65
+ validateTypeClass({
66
+ context,
67
+ counter: typeCounters.operators.server,
68
+ definitions: typesMap.operators.server,
69
+ typeClass: 'Operator',
70
+ warnIfMissing: true
71
+ });
72
+ }
73
+ export default validatePageTypes;
@@ -0,0 +1,44 @@
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 { serializer, type } from '@lowdefy/helpers';
16
+ import writeJs from '../buildJs/writeJs.js';
17
+ async function writePageJit({ page, context }) {
18
+ // Write page JSON
19
+ await context.writeBuildArtifact(`pages/${page.pageId}/${page.pageId}.json`, serializer.serializeToString(page ?? {}));
20
+ // Write page request JSONs
21
+ const requests = page.requests ?? [];
22
+ for (const request of requests){
23
+ await context.writeBuildArtifact(`pages/${page.pageId}/requests/${request.requestId}.json`, serializer.serializeToString(request ?? {}));
24
+ // Clean up request after writing (same as writeRequests)
25
+ delete request.properties;
26
+ delete request.type;
27
+ delete request.connectionId;
28
+ delete request.auth;
29
+ }
30
+ // Write updated keyMap and refMap (JIT build adds new entries)
31
+ if (!type.isObject(context.keyMap)) {
32
+ throw new Error('keyMap is not an object.');
33
+ }
34
+ if (!type.isObject(context.refMap)) {
35
+ throw new Error('refMap is not an object.');
36
+ }
37
+ await context.writeBuildArtifact('keyMap.json', serializer.serializeToString(context.keyMap));
38
+ await context.writeBuildArtifact('refMap.json', serializer.serializeToString(context.refMap));
39
+ // Write updated JS map files (JIT build extracts page-level _js functions)
40
+ await writeJs({
41
+ context
42
+ });
43
+ }
44
+ export default writePageJit;
@@ -0,0 +1,23 @@
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 { serializer } from '@lowdefy/helpers';
16
+ async function writePageRegistry({ pageRegistry, context }) {
17
+ const entries = {};
18
+ for (const [pageId, entry] of pageRegistry){
19
+ entries[pageId] = entry;
20
+ }
21
+ await context.writeBuildArtifact('pageRegistry.json', serializer.serializeToString(entries));
22
+ }
23
+ export default writePageRegistry;
@@ -0,0 +1,23 @@
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
+ */ async function writeSourcelessPages({ sourcelessPageArtifacts, context }) {
16
+ for (const artifact of sourcelessPageArtifacts){
17
+ await context.writeBuildArtifact(`pages/${artifact.pageId}/${artifact.pageId}.json`, artifact.pageJson);
18
+ for (const request of artifact.requests){
19
+ await context.writeBuildArtifact(`pages/${artifact.pageId}/requests/${request.requestId}.json`, request.requestJson);
20
+ }
21
+ }
22
+ }
23
+ export default writeSourcelessPages;
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright 2020-2024 Lowdefy, Inc
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 { validate } from '@lowdefy/ajv';
16
+ import { ConfigError, shouldSuppressBuildCheck } from '@lowdefy/errors';
17
+ import findConfigKey from '../utils/findConfigKey.js';
16
18
  import lowdefySchema from '../lowdefySchema.js';
17
- import formatErrorMessage from '../utils/formatErrorMessage.js';
18
19
  function testSchema({ components, context }) {
19
20
  const { valid, errors } = validate({
20
21
  schema: lowdefySchema,
@@ -22,11 +23,48 @@ function testSchema({ components, context }) {
22
23
  returnErrors: true
23
24
  });
24
25
  if (!valid) {
25
- context.logger.warn('Schema not valid.');
26
- errors.map((error)=>context.logger.warn(formatErrorMessage({
27
- error,
28
- components
29
- })));
26
+ // Filter out anyOf/oneOf cascade errors - these are always accompanied by
27
+ // more specific validation errors and just add noise
28
+ let filteredErrors = errors.filter((error)=>error.keyword !== 'anyOf' && error.keyword !== 'oneOf');
29
+ // Hierarchical deduplication: if an error exists at a child path,
30
+ // filter out errors at parent paths (prefer more specific errors)
31
+ filteredErrors = filteredErrors.filter((error)=>{
32
+ const hasChildError = filteredErrors.some((other)=>other !== error && other.instancePath.startsWith(error.instancePath + '/'));
33
+ return !hasChildError;
34
+ });
35
+ // Same-path deduplication: only show first error per unique path
36
+ // (multiple errors at same path are usually cascade errors from schema branches)
37
+ const seenPaths = new Set();
38
+ filteredErrors = filteredErrors.filter((error)=>{
39
+ if (seenPaths.has(error.instancePath)) {
40
+ return false;
41
+ }
42
+ seenPaths.add(error.instancePath);
43
+ return true;
44
+ });
45
+ filteredErrors.forEach((error)=>{
46
+ const instancePath = error.instancePath.split('/').slice(1).filter(Boolean);
47
+ const configKey = findConfigKey({
48
+ components,
49
+ instancePath
50
+ });
51
+ let message = error.message;
52
+ if (error.params?.additionalProperty) {
53
+ message = `${message} - "${error.params.additionalProperty}"`;
54
+ }
55
+ const configError = new ConfigError(message, {
56
+ configKey,
57
+ checkSlug: 'schema'
58
+ });
59
+ if (!shouldSuppressBuildCheck(configError, context.keyMap)) {
60
+ if (!context.errors) {
61
+ // If no error collection array, throw immediately (fallback for tests)
62
+ throw configError;
63
+ }
64
+ // Collect error object - logging happens at checkpoints in index.js
65
+ context.errors.push(configError);
66
+ }
67
+ });
30
68
  }
31
69
  }
32
70
  export default testSchema;
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable no-param-reassign */ /*
2
- Copyright 2020-2024 Lowdefy, Inc
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.
@@ -22,7 +22,7 @@ function validateConfig({ components }) {
22
22
  }
23
23
  if (type.isString(components.config.basePath)) {
24
24
  if (components.config.basePath[0] !== '/') {
25
- throw Error('Base path must start with "/".');
25
+ throw new Error('Base path must start with "/".');
26
26
  }
27
27
  }
28
28
  return components;
@@ -0,0 +1,28 @@
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
+ function validateOperatorsDynamic({ operators }) {
17
+ const missingDynamic = [];
18
+ Object.entries(operators).forEach(([operatorName, operatorFn])=>{
19
+ if (!type.isFunction(operatorFn)) return;
20
+ if (!type.isBoolean(operatorFn.dynamic)) {
21
+ missingDynamic.push(operatorName);
22
+ }
23
+ });
24
+ if (missingDynamic.length > 0) {
25
+ throw new Error(`Operator validation failed: The following operators are missing the 'dynamic' property: ${missingDynamic.join(', ')}. ` + `All operators must have a 'dynamic' boolean property (true for runtime-only, false for build-time safe).`);
26
+ }
27
+ }
28
+ export default validateOperatorsDynamic;
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright 2020-2024 Lowdefy, Inc
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.
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright 2020-2024 Lowdefy, Inc
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.
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright 2020-2024 Lowdefy, Inc
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.
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright 2020-2024 Lowdefy, Inc
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.
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright 2020-2024 Lowdefy, Inc
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.
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright 2020-2024 Lowdefy, Inc
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.
@@ -0,0 +1,19 @@
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 { serializer } from '@lowdefy/helpers';
16
+ async function writeLogger({ components, context }) {
17
+ await context.writeBuildArtifact('logger.json', serializer.serializeToString(components.logger ?? {}));
18
+ }
19
+ export default writeLogger;
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright 2020-2024 Lowdefy, Inc
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.
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright 2020-2024 Lowdefy, Inc
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.