@lowdefy/build 5.6.0 → 6.1.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 (102) hide show
  1. package/dist/build/buildAgents.js +61 -16
  2. package/dist/build/buildApi/buildApi.js +4 -1
  3. package/dist/build/buildApi/buildEndpoint.js +8 -2
  4. package/dist/build/buildApi/buildRoutine/countStepTypes.js +1 -1
  5. package/dist/build/buildApi/buildRoutine/setStepId.js +2 -0
  6. package/dist/build/buildApi/buildRoutine/validateStep.js +61 -0
  7. package/dist/build/buildApi/resolveEndpointSchedules.js +40 -0
  8. package/dist/build/buildApi/validateEndpoint.js +96 -1
  9. package/dist/build/buildApp.js +13 -20
  10. package/dist/build/buildAppMeta.js +138 -0
  11. package/dist/build/buildAuth/buildAgentAuth.js +14 -1
  12. package/dist/build/buildAuth/buildAuth.js +8 -3
  13. package/dist/build/buildAuth/buildAuthPlugins.js +6 -0
  14. package/dist/build/buildAuth/buildAuthStrategies.js +117 -0
  15. package/dist/build/buildAuth/buildWebsocketAuth.js +55 -0
  16. package/dist/build/buildAuth/getProtectedWebsockets.js +29 -0
  17. package/dist/build/buildAuth/getWebsocketRoles.js +39 -0
  18. package/dist/build/buildAuth/validateAuthConfig.js +15 -3
  19. package/dist/build/buildEnvironments.js +261 -0
  20. package/dist/build/buildImports/buildImportsDev.js +15 -0
  21. package/dist/build/buildImports/buildImportsProd.js +4 -1
  22. package/dist/build/buildJs/generateClientJsModule.js +27 -0
  23. package/dist/build/buildJs/writeJs.js +3 -5
  24. package/dist/build/buildLogger.js +22 -6
  25. package/dist/build/buildMcp.js +73 -0
  26. package/dist/build/buildModuleDefs.js +90 -48
  27. package/dist/build/buildModules.js +61 -14
  28. package/dist/build/buildNotifications.js +98 -0
  29. package/dist/build/buildPages/buildBlock/buildBlock.js +3 -1
  30. package/dist/build/buildPages/buildBlock/buildDynamicBlock.js +131 -0
  31. package/dist/build/buildPages/buildBlock/buildEvents.js +186 -21
  32. package/dist/build/buildPages/buildBlock/buildRequests.js +9 -0
  33. package/dist/build/buildPages/buildBlock/normalizeClassAndStyles.js +2 -11
  34. package/dist/build/buildPages/buildBlock/setBlockId.js +5 -2
  35. package/dist/build/buildPages/buildBlock/validateBlock.js +7 -0
  36. package/dist/build/buildPages/buildPage.js +27 -3
  37. package/dist/build/buildPages/buildSubscriptions.js +145 -0
  38. package/dist/build/buildPages/validateDynamicBlockRefs.js +30 -0
  39. package/dist/build/buildPages/validateStateReferences.js +4 -2
  40. package/dist/build/buildPages/validateWebsocketRefs.js +30 -0
  41. package/dist/build/buildRefs/buildRefs.js +21 -12
  42. package/dist/build/buildRefs/cloneWithMarkers.js +57 -0
  43. package/dist/build/buildRefs/deferredRegions.js +80 -0
  44. package/dist/build/buildRefs/deferredRegistry.js +292 -0
  45. package/dist/build/buildRefs/getModuleRefContent.js +21 -6
  46. package/dist/build/buildRefs/getUserJavascriptFunction.js +1 -1
  47. package/dist/build/buildRefs/parseRefContent.js +24 -0
  48. package/dist/build/buildRefs/{evaluateStaticOperators.js → precomputeRuntimeOperators.js} +7 -6
  49. package/dist/build/buildRefs/walker.js +471 -207
  50. package/dist/build/buildTypes.js +22 -1
  51. package/dist/build/buildWebsockets.js +99 -0
  52. package/dist/build/collectPageContent.js +7 -1
  53. package/dist/build/copyAgentFileSystems.js +2 -2
  54. package/dist/build/full/buildPages.js +16 -0
  55. package/dist/build/full/updateServerPackageJson.js +21 -0
  56. package/dist/build/jit/buildPageJit.js +46 -6
  57. package/dist/build/jit/collectSkeletonSourceFiles.js +14 -0
  58. package/dist/build/jit/pageContentKeys.js +1 -0
  59. package/dist/build/jit/shallowBuild.js +84 -3
  60. package/dist/build/jit/writePageJit.js +11 -8
  61. package/dist/build/registerModules.js +125 -24
  62. package/dist/build/validateCallAgentSteps.js +58 -0
  63. package/dist/build/validateConfig.js +6 -1
  64. package/dist/build/validateEnvironmentGuards.js +69 -0
  65. package/dist/build/validateRenderNotificationSteps.js +50 -0
  66. package/dist/build/writeApi.js +98 -1
  67. package/dist/build/writeMcp.js +21 -0
  68. package/dist/build/writeNotifications.js +30 -0
  69. package/dist/build/writePluginImports/importPluginModule.js +39 -0
  70. package/dist/build/writePluginImports/writeActionSchemaMap.js +6 -7
  71. package/dist/build/writePluginImports/writeAuthImports.js +4 -0
  72. package/dist/build/writePluginImports/writeAvailableTypes.js +99 -0
  73. package/dist/build/writePluginImports/writeBlockSchemaMap.js +10 -9
  74. package/dist/build/writePluginImports/writeConnectionSchemaMap.js +101 -0
  75. package/dist/build/writePluginImports/writeGlobalsCss.js +20 -10
  76. package/dist/build/writePluginImports/writeNotificationImports.js +31 -0
  77. package/dist/build/writePluginImports/writeOperatorSchemaMap.js +6 -7
  78. package/dist/build/writePluginImports/writePluginImports.js +18 -4
  79. package/dist/build/writePluginImports/writeWebsocketImports.js +22 -0
  80. package/dist/build/writeWebsockets.js +30 -0
  81. package/dist/createContext.js +6 -1
  82. package/dist/defaultPackages.js +7 -1
  83. package/dist/defaultTypesMap.js +688 -388
  84. package/dist/dynamic/buildDynamicBlocks.js +120 -0
  85. package/dist/index.js +81 -10
  86. package/dist/indexDev.js +4 -0
  87. package/dist/lowdefySchema.js +969 -6
  88. package/dist/scripts/generateDefaultTypes.js +5 -2
  89. package/dist/test-utils/expectTerminates.js +33 -0
  90. package/dist/test-utils/runBuild.js +15 -1
  91. package/dist/test-utils/runBuildForSnapshots.js +37 -4
  92. package/dist/test-utils/testContext.js +8 -2
  93. package/dist/utils/countOperators.js +5 -17
  94. package/dist/utils/createPluginTypesMap.js +21 -0
  95. package/dist/utils/getEnvironmentNames.js +26 -0
  96. package/dist/utils/logCollectedErrors.js +15 -9
  97. package/dist/utils/serializeBuildException.js +29 -0
  98. package/dist/utils/validateCronExpression.js +131 -0
  99. package/dist/utils/writeBuildArtifact.js +5 -2
  100. package/package.json +67 -60
  101. package/dist/build/writePluginImports/writeServerExternalPackages.js +0 -121
  102. /package/dist/build/{resolveModuleOperators.js → buildRefs/scopeMenuItemIds.js} +0 -0
@@ -0,0 +1,120 @@
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';
17
+ import buildBlock from '../build/buildPages/buildBlock/buildBlock.js';
18
+ import createCheckDuplicateId from '../utils/createCheckDuplicateId.js';
19
+ import createCounter from '../utils/createCounter.js';
20
+ // At build time, type counters feed types.json and import generation. At
21
+ // runtime the client bundle is fixed, so the same counter calls become
22
+ // membership checks against the bundled types instead.
23
+ function createMembershipCounter({ category, allowed, dynamicBlockId, pageId }) {
24
+ return {
25
+ increment: (typeName)=>{
26
+ if (!allowed.has(typeName)) {
27
+ throw new ConfigError(`Dynamic block "${dynamicBlockId}" on page "${pageId}" resolved content uses ${category} type "${typeName}" which is not included in the app's client bundle. Declare it in the Dynamic block's properties.types.`);
28
+ }
29
+ }
30
+ };
31
+ }
32
+ // types.json is fileCache-cached (same object per server lifetime), so the
33
+ // allowed-type sets are derived once per types object, not per Dynamic block.
34
+ const allowedSetsCache = new WeakMap();
35
+ function getAllowedSets(types) {
36
+ let sets = allowedSetsCache.get(types);
37
+ if (!sets) {
38
+ sets = {
39
+ actions: new Set(Object.keys(types.actions ?? {})),
40
+ blocks: new Set(Object.keys(types.blocks ?? {})),
41
+ operators: new Set(Object.keys(types.operators?.client ?? {}))
42
+ };
43
+ allowedSetsCache.set(types, sets);
44
+ }
45
+ return sets;
46
+ }
47
+ // Counter for categories dynamic content cannot reach (requests are forbidden,
48
+ // so request types and server operators never occur in a valid fragment).
49
+ const noopCounter = {
50
+ increment: ()=>{}
51
+ };
52
+ function buildDynamicBlocks({ blocks, pageId, dynamicBlockId, idPrefix, types, blockMetas }) {
53
+ if (!type.isArray(blocks)) {
54
+ throw new ConfigError(`Dynamic block "${dynamicBlockId}" on page "${pageId}" endpoint must return an object with a "blocks" array.`, {
55
+ received: blocks
56
+ });
57
+ }
58
+ const warnings = [];
59
+ const callApiActionRefs = [];
60
+ const requestActionRefs = [];
61
+ const allowed = getAllowedSets(types);
62
+ const pageContext = {
63
+ blockIdCounter: createCounter(),
64
+ // Namespace runtime ids under the resolving Dynamic block's built id —
65
+ // unique by construction, so they can never collide with static block ids.
66
+ blockIdPrefix: idPrefix,
67
+ callApiActionRefs,
68
+ checkDuplicateRequestId: createCheckDuplicateId({
69
+ message: 'Duplicate requestId "{{ id }}" on page "{{ pageId }}".'
70
+ }),
71
+ context: {
72
+ blockMetas,
73
+ handleWarning: (warning)=>{
74
+ warnings.push(warning);
75
+ }
76
+ },
77
+ // Pure sink — buildDynamicBlock pushes nested Dynamic refs here, but at
78
+ // runtime a bad endpointId surfaces through resolution, not ref checking.
79
+ dynamicBlockRefs: [],
80
+ forbidRequests: true,
81
+ linkActionRefs: [],
82
+ pageId,
83
+ requestActionRefs,
84
+ requests: [],
85
+ shortcutRefs: [],
86
+ typeCounters: {
87
+ actions: createMembershipCounter({
88
+ category: 'action',
89
+ allowed: allowed.actions,
90
+ dynamicBlockId,
91
+ pageId
92
+ }),
93
+ blocks: createMembershipCounter({
94
+ category: 'block',
95
+ allowed: allowed.blocks,
96
+ dynamicBlockId,
97
+ pageId
98
+ }),
99
+ operators: {
100
+ client: createMembershipCounter({
101
+ category: 'operator',
102
+ allowed: allowed.operators,
103
+ dynamicBlockId,
104
+ pageId
105
+ }),
106
+ server: noopCounter
107
+ },
108
+ requests: noopCounter
109
+ },
110
+ websocketActionRefs: []
111
+ };
112
+ blocks.forEach((block)=>buildBlock(block, pageContext));
113
+ return {
114
+ blocks,
115
+ callApiActionRefs,
116
+ requestActionRefs,
117
+ warnings
118
+ };
119
+ }
120
+ export default buildDynamicBlocks;
package/dist/index.js CHANGED
@@ -22,17 +22,22 @@ import addDefaultPages from './build/addDefaultPages/addDefaultPages.js';
22
22
  import addKeys from './build/addKeys.js';
23
23
  import buildAgents from './build/buildAgents.js';
24
24
  import buildApp from './build/buildApp.js';
25
+ import buildAppMeta from './build/buildAppMeta.js';
25
26
  import buildAuth from './build/buildAuth/buildAuth.js';
26
27
  import buildConnections from './build/buildConnections.js';
27
28
  import buildApi from './build/buildApi/buildApi.js';
28
29
  import buildImports from './build/buildImports/buildImports.js';
29
30
  import buildJs from './build/full/buildJs.js';
30
31
  import buildLogger from './build/buildLogger.js';
32
+ import buildMcp from './build/buildMcp.js';
31
33
  import buildMenu from './build/buildMenu.js';
32
34
  import buildModuleDefs from './build/buildModuleDefs.js';
33
35
  import buildModules from './build/buildModules.js';
36
+ import buildNotifications from './build/buildNotifications.js';
37
+ import precomputeRuntimeOperators from './build/buildRefs/precomputeRuntimeOperators.js';
34
38
  import buildPages from './build/full/buildPages.js';
35
39
  import buildRefs from './build/buildRefs/buildRefs.js';
40
+ import buildWebsockets from './build/buildWebsockets.js';
36
41
  import collectPageContent from './build/collectPageContent.js';
37
42
  import buildTypes from './build/buildTypes.js';
38
43
  import cleanBuildDirectory from './build/cleanBuildDirectory.js';
@@ -40,7 +45,9 @@ import copyAgentFileSystems from './build/copyAgentFileSystems.js';
40
45
  import copyPublicFolder from './build/copyPublicFolder.js';
41
46
  import testSchema from './build/testSchema.js';
42
47
  import updateServerPackageJson from './build/full/updateServerPackageJson.js';
48
+ import validateCallAgentSteps from './build/validateCallAgentSteps.js';
43
49
  import validateConfig from './build/validateConfig.js';
50
+ import validateRenderNotificationSteps from './build/validateRenderNotificationSteps.js';
44
51
  import writeAgents from './build/writeAgents.js';
45
52
  import writeApp from './build/writeApp.js';
46
53
  import writeAppMeta from './build/writeAppMeta.js';
@@ -49,6 +56,8 @@ import writeConfig from './build/writeConfig.js';
49
56
  import writeConnections from './build/writeConnections.js';
50
57
  import writeApi from './build/writeApi.js';
51
58
  import writeGlobal from './build/writeGlobal.js';
59
+ import writeMcp from './build/writeMcp.js';
60
+ import writeWebsockets from './build/writeWebsockets.js';
52
61
  import codegenI18nLocales from './build/codegenI18nLocales.js';
53
62
  import writeI18n from './build/writeI18n.js';
54
63
  import writeTheme from './build/writeTheme.js';
@@ -56,6 +65,7 @@ import writeJs from './build/buildJs/writeJs.js';
56
65
  import writeLogger from './build/writeLogger.js';
57
66
  import writeMaps from './build/writeMaps.js';
58
67
  import writeMenus from './build/writeMenus.js';
68
+ import writeNotifications from './build/writeNotifications.js';
59
69
  import writePages from './build/full/writePages.js';
60
70
  import writePluginImports from './build/writePluginImports/writePluginImports.js';
61
71
  import writeRequests from './build/full/writeRequests.js';
@@ -66,6 +76,15 @@ async function build(options) {
66
76
  let context;
67
77
  try {
68
78
  context = createContext(options);
79
+ // Phase 0: Resolve root app metadata into context.appMeta before any
80
+ // operator evaluation. _app / _build.app read this, and buildModuleDefs
81
+ // (next) evaluates operators on root config, consumer vars, and connections.
82
+ await buildAppMeta({
83
+ context
84
+ });
85
+ // Surface bad root metadata (unsupported operators, failed _build.*) now,
86
+ // before module operators evaluate against it — avoids cascade errors.
87
+ logCollectedErrors(context);
69
88
  // Phase 1: Build module definitions
70
89
  // Parses lowdefy.yaml, resolves module refs, populates context.modules
71
90
  await buildModuleDefs({
@@ -92,6 +111,18 @@ async function build(options) {
92
111
  components,
93
112
  context
94
113
  });
114
+ // Phase 3.5: Pre-compute static runtime operators (_sum, _if, _string, etc.)
115
+ // whose arguments are fully static. This single fold covers components after
116
+ // module manifests are merged (replacing the old per-region folds in buildRefs,
117
+ // buildModuleDefs, and registerModules). Must run before addKeys so that ~k
118
+ // markers are added to the already-folded tree.
119
+ // context.rootRefDef is the lowdefy.yaml refDef stashed by buildRefs (Phase 2)
120
+ // so we can resolve error source file paths without allocating a new makeId entry.
121
+ components = precomputeRuntimeOperators({
122
+ context,
123
+ input: components,
124
+ refDef: context.rootRefDef
125
+ });
95
126
  // Build steps - collect all errors before stopping
96
127
  // addKeys runs first so testSchema has ~k markers for error location info
97
128
  tryBuildStep(addKeys, 'addKeys', {
@@ -110,11 +141,15 @@ async function build(options) {
110
141
  components,
111
142
  context
112
143
  });
113
- tryBuildStep(buildLogger, 'buildLogger', {
144
+ // appMeta is computed in Phase 0; attach it here (where buildApp used to
145
+ // create it) so the following addKeys pass keys it identically.
146
+ components.appMeta = context.appMeta;
147
+ // validateConfig resolves the current environment, which buildLogger reads for Sentry.
148
+ tryBuildStep(validateConfig, 'validateConfig', {
114
149
  components,
115
150
  context
116
151
  });
117
- tryBuildStep(validateConfig, 'validateConfig', {
152
+ tryBuildStep(buildLogger, 'buildLogger', {
118
153
  components,
119
154
  context
120
155
  });
@@ -143,32 +178,39 @@ async function build(options) {
143
178
  components,
144
179
  context
145
180
  });
146
- tryBuildStep(buildPages, 'buildPages', {
181
+ tryBuildStep(buildMcp, 'buildMcp', {
147
182
  components,
148
183
  context
149
184
  });
150
- tryBuildStep(buildMenu, 'buildMenu', {
185
+ tryBuildStep(buildWebsockets, 'buildWebsockets', {
151
186
  components,
152
187
  context
153
188
  });
154
- tryBuildStep(buildJs, 'buildJs', {
189
+ tryBuildStep(buildNotifications, 'buildNotifications', {
155
190
  components,
156
191
  context
157
192
  });
158
- tryBuildStep(buildTypes, 'buildTypes', {
193
+ // Cross-config step validations — need buildApi (stepIds) and the
194
+ // buildAgents/buildNotifications id sets
195
+ tryBuildStep(validateCallAgentSteps, 'validateCallAgentSteps', {
159
196
  components,
160
197
  context
161
198
  });
162
- tryBuildStep(buildImports, 'buildImports', {
199
+ tryBuildStep(validateRenderNotificationSteps, 'validateRenderNotificationSteps', {
163
200
  components,
164
201
  context
165
202
  });
166
- // Final addKeys pass to ensure all objects (including those created by build steps) have ~k
167
- tryBuildStep(addKeys, 'addKeys', {
203
+ tryBuildStep(buildPages, 'buildPages', {
168
204
  components,
169
205
  context
170
206
  });
171
- // Collect page content strings for Tailwind to scan
207
+ tryBuildStep(buildMenu, 'buildMenu', {
208
+ components,
209
+ context
210
+ });
211
+ // Collect page content strings for Tailwind to scan. Must run before
212
+ // buildJs — jsMapParser replaces _js source with hashes, and class
213
+ // candidates used only inside _js source would otherwise never be scanned.
172
214
  context.tailwindContentMap = new Map();
173
215
  for (const page of components.pages ?? []){
174
216
  const content = collectPageContent([
@@ -178,6 +220,23 @@ async function build(options) {
178
220
  context.tailwindContentMap.set(page.pageId, content);
179
221
  }
180
222
  }
223
+ tryBuildStep(buildJs, 'buildJs', {
224
+ components,
225
+ context
226
+ });
227
+ tryBuildStep(buildTypes, 'buildTypes', {
228
+ components,
229
+ context
230
+ });
231
+ tryBuildStep(buildImports, 'buildImports', {
232
+ components,
233
+ context
234
+ });
235
+ // Final addKeys pass to ensure all objects (including those created by build steps) have ~k
236
+ tryBuildStep(addKeys, 'addKeys', {
237
+ components,
238
+ context
239
+ });
181
240
  // Check if there are any collected errors before writing
182
241
  logCollectedErrors(context);
183
242
  // Write steps - only if no errors
@@ -208,6 +267,18 @@ async function build(options) {
208
267
  components,
209
268
  context
210
269
  });
270
+ await writeMcp({
271
+ components,
272
+ context
273
+ });
274
+ await writeWebsockets({
275
+ components,
276
+ context
277
+ });
278
+ await writeNotifications({
279
+ components,
280
+ context
281
+ });
211
282
  await writeRequests({
212
283
  components,
213
284
  context
package/dist/indexDev.js CHANGED
@@ -14,8 +14,12 @@
14
14
  limitations under the License.
15
15
  */ export { default as buildModuleDefs } from './build/buildModuleDefs.js';
16
16
  export { default as buildModules } from './build/buildModules.js';
17
+ export { default as generateClientJsModule } from './build/buildJs/generateClientJsModule.js';
18
+ export { default as iconPackages } from './build/buildImports/iconPackages.js';
17
19
  export { default as shallowBuild } from './build/jit/shallowBuild.js';
18
20
  export { default as buildPageJit } from './build/jit/buildPageJit.js';
19
21
  export { default as createPageRegistry } from './build/jit/createPageRegistry.js';
20
22
  export { default as createContext } from './createContext.js';
21
23
  export { default as makeId } from './utils/makeId.js';
24
+ export { default as serializeBuildException } from './utils/serializeBuildException.js';
25
+ export { hydrateDeferredRecords } from './build/buildRefs/deferredRegistry.js';