@lowdefy/build 5.5.1 → 6.0.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 (107) hide show
  1. package/dist/build/buildAgents.js +70 -17
  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 +37 -0
  8. package/dist/build/buildApi/validateEndpoint.js +96 -1
  9. package/dist/build/buildApp.js +13 -20
  10. package/dist/build/buildAppMeta.js +130 -0
  11. package/dist/build/buildAuth/buildAgentAuth.js +69 -0
  12. package/dist/build/buildAuth/buildAuth.js +14 -0
  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/getAgentRoles.js +39 -0
  17. package/dist/build/buildAuth/getProtectedAgents.js +29 -0
  18. package/dist/build/buildAuth/getProtectedWebsockets.js +29 -0
  19. package/dist/build/buildAuth/getWebsocketRoles.js +39 -0
  20. package/dist/build/buildAuth/rejectReservedEntityIds.js +52 -0
  21. package/dist/build/buildAuth/validateAuthConfig.js +15 -3
  22. package/dist/build/buildImports/buildImportsDev.js +15 -0
  23. package/dist/build/buildImports/buildImportsProd.js +4 -1
  24. package/dist/build/buildJs/generateClientJsModule.js +27 -0
  25. package/dist/build/buildJs/writeJs.js +3 -5
  26. package/dist/build/buildMcp.js +73 -0
  27. package/dist/build/buildModuleDefs.js +90 -48
  28. package/dist/build/buildModules.js +61 -14
  29. package/dist/build/buildNotifications.js +98 -0
  30. package/dist/build/buildPages/buildBlock/buildBlock.js +3 -1
  31. package/dist/build/buildPages/buildBlock/buildDynamicBlock.js +131 -0
  32. package/dist/build/buildPages/buildBlock/buildEvents.js +197 -22
  33. package/dist/build/buildPages/buildBlock/buildRequests.js +9 -0
  34. package/dist/build/buildPages/buildBlock/normalizeClassAndStyles.js +2 -11
  35. package/dist/build/buildPages/buildBlock/setBlockId.js +5 -2
  36. package/dist/build/buildPages/buildBlock/validateBlock.js +19 -1
  37. package/dist/build/buildPages/buildPage.js +27 -3
  38. package/dist/build/buildPages/buildSubscriptions.js +145 -0
  39. package/dist/build/buildPages/validateDynamicBlockRefs.js +30 -0
  40. package/dist/build/buildPages/validateStateReferences.js +4 -2
  41. package/dist/build/buildPages/validateWebsocketRefs.js +30 -0
  42. package/dist/build/buildRefs/buildRefs.js +21 -12
  43. package/dist/build/buildRefs/cloneWithMarkers.js +57 -0
  44. package/dist/build/buildRefs/deferredRegions.js +80 -0
  45. package/dist/build/buildRefs/deferredRegistry.js +292 -0
  46. package/dist/build/buildRefs/getKey.js +16 -5
  47. package/dist/build/buildRefs/getModuleRefContent.js +21 -6
  48. package/dist/build/buildRefs/getUserJavascriptFunction.js +1 -1
  49. package/dist/build/buildRefs/parseRefContent.js +24 -0
  50. package/dist/build/buildRefs/{evaluateStaticOperators.js → precomputeRuntimeOperators.js} +7 -6
  51. package/dist/build/buildRefs/walker.js +490 -209
  52. package/dist/build/buildTypes.js +22 -1
  53. package/dist/build/buildWebsockets.js +99 -0
  54. package/dist/build/collectPageContent.js +7 -1
  55. package/dist/build/copyAgentFileSystems.js +2 -2
  56. package/dist/build/fetchModules.js +18 -4
  57. package/dist/build/full/buildPages.js +16 -0
  58. package/dist/build/full/updateServerPackageJson.js +21 -0
  59. package/dist/build/jit/buildPageJit.js +46 -6
  60. package/dist/build/jit/collectSkeletonSourceFiles.js +14 -0
  61. package/dist/build/jit/pageContentKeys.js +1 -0
  62. package/dist/build/jit/shallowBuild.js +81 -1
  63. package/dist/build/jit/writePageJit.js +11 -8
  64. package/dist/build/registerModules.js +149 -42
  65. package/dist/build/validateCallAgentSteps.js +58 -0
  66. package/dist/build/validateConfig.js +4 -0
  67. package/dist/build/validateCronConfig.js +110 -0
  68. package/dist/build/validateRenderNotificationSteps.js +50 -0
  69. package/dist/build/writeApi.js +58 -1
  70. package/dist/build/writeI18n.js +8 -1
  71. package/dist/build/writeMcp.js +21 -0
  72. package/dist/build/writeNotifications.js +30 -0
  73. package/dist/build/writePluginImports/importPluginModule.js +39 -0
  74. package/dist/build/writePluginImports/writeActionSchemaMap.js +6 -7
  75. package/dist/build/writePluginImports/writeAuthImports.js +4 -0
  76. package/dist/build/writePluginImports/writeAvailableTypes.js +99 -0
  77. package/dist/build/writePluginImports/writeBlockSchemaMap.js +10 -9
  78. package/dist/build/writePluginImports/writeConnectionSchemaMap.js +101 -0
  79. package/dist/build/writePluginImports/writeGlobalsCss.js +20 -11
  80. package/dist/build/writePluginImports/writeNotificationImports.js +31 -0
  81. package/dist/build/writePluginImports/writeOperatorSchemaMap.js +6 -7
  82. package/dist/build/writePluginImports/writePluginImports.js +18 -4
  83. package/dist/build/writePluginImports/writeWebsocketImports.js +22 -0
  84. package/dist/build/writeWebsockets.js +30 -0
  85. package/dist/createContext.js +6 -1
  86. package/dist/defaultPackages.js +7 -1
  87. package/dist/defaultTypesMap.js +689 -386
  88. package/dist/dynamic/buildDynamicBlocks.js +120 -0
  89. package/dist/index.js +78 -8
  90. package/dist/indexDev.js +4 -0
  91. package/dist/lowdefySchema.js +861 -6
  92. package/dist/scripts/generateDefaultTypes.js +5 -2
  93. package/dist/test-utils/expectTerminates.js +33 -0
  94. package/dist/test-utils/runBuild.js +20 -1
  95. package/dist/test-utils/runBuildForSnapshots.js +34 -4
  96. package/dist/test-utils/testContext.js +8 -2
  97. package/dist/utils/countOperators.js +5 -17
  98. package/dist/utils/createPluginTypesMap.js +21 -0
  99. package/dist/utils/getCronEnvironmentNames.js +25 -0
  100. package/dist/utils/logCollectedErrors.js +44 -10
  101. package/dist/utils/serializeBuildException.js +29 -0
  102. package/dist/utils/validateCronExpression.js +131 -0
  103. package/dist/utils/validateId.js +11 -0
  104. package/dist/utils/writeBuildArtifact.js +5 -2
  105. package/package.json +66 -59
  106. package/dist/build/writePluginImports/writeServerExternalPackages.js +0 -121
  107. /package/dist/build/{resolveModuleOperators.js → buildRefs/scopeMenuItemIds.js} +0 -0
@@ -0,0 +1,30 @@
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, serializer } from '@lowdefy/helpers';
16
+ async function writeNotification({ notification, context }) {
17
+ await context.writeBuildArtifact(`notifications/${notification.notificationId}.json`, serializer.serializeToString(notification ?? {}));
18
+ }
19
+ async function writeNotifications({ components, context }) {
20
+ if (type.isNone(components.notifications)) return;
21
+ if (!type.isArray(components.notifications)) {
22
+ throw new Error(`Notifications is not an array.`);
23
+ }
24
+ const writePromises = components.notifications.map((notification)=>writeNotification({
25
+ notification,
26
+ context
27
+ }));
28
+ return Promise.all(writePromises);
29
+ }
30
+ export default writeNotifications;
@@ -0,0 +1,39 @@
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 { createRequire } from 'node:module';
16
+ import path from 'node:path';
17
+ // Import a plugin module (e.g. `${pkg}/schemas`, `${pkg}/connections`) for
18
+ // schema collection. Default packages resolve from the build package itself;
19
+ // custom plugins only exist in the server's node_modules, so fall back to
20
+ // resolving from the server directory. Returns undefined when unresolvable —
21
+ // callers degrade gracefully.
22
+ async function importPluginModule({ context, specifier }) {
23
+ try {
24
+ return await import(/* webpackIgnore: true */ /* @vite-ignore */ specifier);
25
+ } catch {
26
+ // Not resolvable from the build package — try the server's node_modules.
27
+ }
28
+ const serverDir = context.directories?.server;
29
+ if (!serverDir) {
30
+ return undefined;
31
+ }
32
+ try {
33
+ const require = createRequire(path.join(serverDir, 'package.json'));
34
+ return await import(/* webpackIgnore: true */ /* @vite-ignore */ require.resolve(specifier));
35
+ } catch {
36
+ return undefined;
37
+ }
38
+ }
39
+ export default importPluginModule;
@@ -12,7 +12,8 @@
12
12
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
13
  See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
- */ async function writeActionSchemaMap({ components, context }) {
15
+ */ import importPluginModule from './importPluginModule.js';
16
+ async function writeActionSchemaMap({ components, context }) {
16
17
  const schemas = {};
17
18
  const typesMapSchemas = context.typesMap.schemas?.actions ?? {};
18
19
  const actionsByPackage = {};
@@ -23,12 +24,10 @@
23
24
  actionsByPackage[action.package].push(action);
24
25
  }
25
26
  for (const [packageName, actions] of Object.entries(actionsByPackage)){
26
- let packageSchemas;
27
- try {
28
- packageSchemas = await import(/* webpackIgnore: true */ `${packageName}/schemas`);
29
- } catch {
30
- // Package not resolvable from build context (custom plugins) — skip
31
- }
27
+ const packageSchemas = await importPluginModule({
28
+ context,
29
+ specifier: `${packageName}/schemas`
30
+ });
32
31
  for (const action of actions){
33
32
  if (typesMapSchemas[action.typeName]) {
34
33
  schemas[action.typeName] = typesMapSchemas[action.typeName];
@@ -30,5 +30,9 @@ async function writeAuthImports({ components, context }) {
30
30
  imports: components.imports.auth.providers,
31
31
  importPath: 'auth/providers'
32
32
  }));
33
+ await context.writeBuildArtifact('plugins/auth/strategies.js', generateImportFile({
34
+ imports: components.imports.auth.strategies,
35
+ importPath: 'auth/strategies'
36
+ }));
33
37
  }
34
38
  export default writeAuthImports;
@@ -0,0 +1,99 @@
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
+ */ function filterInstalled({ store, installedPackages }) {
16
+ const filtered = {};
17
+ for (const [typeName, definition] of Object.entries(store ?? {})){
18
+ if (installedPackages.has(definition.package)) {
19
+ filtered[typeName] = definition;
20
+ }
21
+ }
22
+ return filtered;
23
+ }
24
+ // Discovery artifact for the dev server docs routes: every type available
25
+ // from installed plugin packages, independent of whether the app config uses
26
+ // it. types.json only describes types counted in config (plus dev-installed
27
+ // blocks/actions/operators), so docs tooling needs this full map to list what
28
+ // a developer could use. Dev-only — context.installedPackages is set by the
29
+ // dev shallow build (addInstalledTypes); production builds skip it.
30
+ async function writeAvailableTypes({ context }) {
31
+ const { typesMap, installedPackages } = context;
32
+ if (!installedPackages) {
33
+ return;
34
+ }
35
+ const availableTypes = {
36
+ actions: filterInstalled({
37
+ store: typesMap.actions,
38
+ installedPackages
39
+ }),
40
+ agents: filterInstalled({
41
+ store: typesMap.agents,
42
+ installedPackages
43
+ }),
44
+ auth: {
45
+ adapters: filterInstalled({
46
+ store: typesMap.auth.adapters,
47
+ installedPackages
48
+ }),
49
+ callbacks: filterInstalled({
50
+ store: typesMap.auth.callbacks,
51
+ installedPackages
52
+ }),
53
+ events: filterInstalled({
54
+ store: typesMap.auth.events,
55
+ installedPackages
56
+ }),
57
+ providers: filterInstalled({
58
+ store: typesMap.auth.providers,
59
+ installedPackages
60
+ }),
61
+ strategies: filterInstalled({
62
+ store: typesMap.auth.strategies,
63
+ installedPackages
64
+ })
65
+ },
66
+ blocks: filterInstalled({
67
+ store: typesMap.blocks,
68
+ installedPackages
69
+ }),
70
+ connections: filterInstalled({
71
+ store: typesMap.connections,
72
+ installedPackages
73
+ }),
74
+ notifications: filterInstalled({
75
+ store: typesMap.notifications,
76
+ installedPackages
77
+ }),
78
+ operators: {
79
+ client: filterInstalled({
80
+ store: typesMap.operators.client,
81
+ installedPackages
82
+ }),
83
+ server: filterInstalled({
84
+ store: typesMap.operators.server,
85
+ installedPackages
86
+ })
87
+ },
88
+ requests: filterInstalled({
89
+ store: typesMap.requests,
90
+ installedPackages
91
+ }),
92
+ websockets: filterInstalled({
93
+ store: typesMap.websockets,
94
+ installedPackages
95
+ })
96
+ };
97
+ await context.writeBuildArtifact('plugins/availableTypes.json', JSON.stringify(availableTypes));
98
+ }
99
+ export default writeAvailableTypes;
@@ -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 { buildBlockSchema } from '@lowdefy/block-utils';
16
+ import importPluginModule from './importPluginModule.js';
16
17
  async function writeBlockSchemaMap({ components, context }) {
17
18
  const schemas = {};
18
19
  const allMetas = {};
@@ -25,15 +26,15 @@ async function writeBlockSchemaMap({ components, context }) {
25
26
  blocksByPackage[block.package].push(block);
26
27
  }
27
28
  for (const [packageName, blocks] of Object.entries(blocksByPackage)){
28
- let packageMetas;
29
- try {
30
- packageMetas = await import(/* webpackIgnore: true */ `${packageName}/metas`);
31
- } catch {
32
- try {
33
- packageMetas = await import(/* webpackIgnore: true */ `${packageName}/schemas`);
34
- } catch {
35
- // Package not resolvable from build context (custom plugins) — skip
36
- }
29
+ let packageMetas = await importPluginModule({
30
+ context,
31
+ specifier: `${packageName}/metas`
32
+ });
33
+ if (!packageMetas) {
34
+ packageMetas = await importPluginModule({
35
+ context,
36
+ specifier: `${packageName}/schemas`
37
+ });
37
38
  }
38
39
  for (const block of blocks){
39
40
  const meta = packageMetas?.[block.originalTypeName];
@@ -0,0 +1,101 @@
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 importPluginModule from './importPluginModule.js';
16
+ // Connection and request schemas live as statics on the connection classes
17
+ // (Connection.schema, Connection.requests[Request].schema), not behind a
18
+ // package /schemas export. Collect them here, in the build process, so the
19
+ // dev server can serve schemas for every installed connection package without
20
+ // importing heavy connection dependencies (database drivers etc.) at runtime.
21
+ // Dev-only — context.installedPackages is set by the dev shallow build
22
+ // (addInstalledTypes); production builds skip it.
23
+ async function writeConnectionSchemaMap({ context }) {
24
+ const { installedPackages } = context;
25
+ if (!installedPackages) {
26
+ return;
27
+ }
28
+ const connectionSchemas = {};
29
+ const requestSchemas = {};
30
+ const typesMapConnectionSchemas = context.typesMap.schemas?.connections ?? {};
31
+ const typesMapRequestSchemas = context.typesMap.schemas?.requests ?? {};
32
+ const connectionsByPackage = {};
33
+ for (const [typeName, definition] of Object.entries(context.typesMap.connections ?? {})){
34
+ if (!installedPackages.has(definition.package)) {
35
+ continue;
36
+ }
37
+ if (!connectionsByPackage[definition.package]) {
38
+ connectionsByPackage[definition.package] = [];
39
+ }
40
+ connectionsByPackage[definition.package].push({
41
+ typeName,
42
+ ...definition
43
+ });
44
+ }
45
+ const requestsByPackage = {};
46
+ for (const [typeName, definition] of Object.entries(context.typesMap.requests ?? {})){
47
+ if (!installedPackages.has(definition.package)) {
48
+ continue;
49
+ }
50
+ if (!requestsByPackage[definition.package]) {
51
+ requestsByPackage[definition.package] = [];
52
+ }
53
+ requestsByPackage[definition.package].push({
54
+ typeName,
55
+ ...definition
56
+ });
57
+ }
58
+ const packageNames = new Set([
59
+ ...Object.keys(connectionsByPackage),
60
+ ...Object.keys(requestsByPackage)
61
+ ]);
62
+ for (const packageName of packageNames){
63
+ const packageConnections = await importPluginModule({
64
+ context,
65
+ specifier: `${packageName}/connections`
66
+ });
67
+ const requestFnsByOriginalName = {};
68
+ for (const connection of Object.values(packageConnections ?? {})){
69
+ for (const [requestName, requestFn] of Object.entries(connection?.requests ?? {})){
70
+ requestFnsByOriginalName[requestName] = requestFn;
71
+ }
72
+ }
73
+ for (const connection of connectionsByPackage[packageName] ?? []){
74
+ const originalTypeName = connection.originalTypeName ?? connection.typeName;
75
+ const implementation = packageConnections?.[originalTypeName];
76
+ const typePrefix = connection.typeName.slice(0, connection.typeName.length - originalTypeName.length);
77
+ if (typesMapConnectionSchemas[connection.typeName]) {
78
+ connectionSchemas[connection.typeName] = typesMapConnectionSchemas[connection.typeName];
79
+ } else if (implementation?.schema) {
80
+ connectionSchemas[connection.typeName] = {
81
+ schema: implementation.schema,
82
+ requests: Object.keys(implementation.requests ?? {}).map((requestName)=>`${typePrefix}${requestName}`)
83
+ };
84
+ }
85
+ }
86
+ for (const request of requestsByPackage[packageName] ?? []){
87
+ const requestFn = requestFnsByOriginalName[request.originalTypeName ?? request.typeName];
88
+ if (typesMapRequestSchemas[request.typeName]) {
89
+ requestSchemas[request.typeName] = typesMapRequestSchemas[request.typeName];
90
+ } else if (requestFn?.schema) {
91
+ requestSchemas[request.typeName] = {
92
+ schema: requestFn.schema,
93
+ meta: requestFn.meta ?? {}
94
+ };
95
+ }
96
+ }
97
+ }
98
+ await context.writeBuildArtifact('plugins/connectionSchemas.json', JSON.stringify(connectionSchemas));
99
+ await context.writeBuildArtifact('plugins/requestSchemas.json', JSON.stringify(requestSchemas));
100
+ }
101
+ export default writeConnectionSchemaMap;
@@ -62,7 +62,6 @@ function objectToThemeVars(obj, prefix) {
62
62
  }
63
63
  function buildThemeVars(tailwindConfig) {
64
64
  const merged = mergeObjects([
65
- {},
66
65
  BRIDGE_DEFAULTS,
67
66
  tailwindConfig ?? {}
68
67
  ]);
@@ -81,20 +80,31 @@ async function writeGlobalsCss({ components, context }) {
81
80
  const relPath = path.relative(context.directories.build, userStylesAbsolute).split(path.sep).join('/');
82
81
  userStylesImport = `/* User custom styles */\n@import "${relPath}" layer(components);\n\n`;
83
82
  }
83
+ // All @import statements must precede @source and every other statement —
84
+ // the CSS spec only allows @charset and empty @layer before @import, and
85
+ // Vite's CSS pipeline enforces this (it warns and may drop late imports).
84
86
  const css = `/* Generated by Lowdefy build */
85
87
 
86
88
  /* Layer order — locks cascade priority before Tailwind declares its own layers */
87
89
  @layer theme, base, antd, components, utilities;
88
90
 
89
- @import "tailwindcss";
91
+ /* source(none) disables Tailwind's automatic source detection — without it the
92
+ oxide scanner walks the entire server directory tree (node_modules and all,
93
+ ~50s cold) on the first CSS compile. The explicit @source globs below are
94
+ the only scan inputs Lowdefy needs. */
95
+ @import "tailwindcss" source(none);
90
96
  @import "@lowdefy/layout/grid.css";
91
97
 
98
+ /* Imported CSS file — when this changes, PostCSS re-runs and Tailwind re-scans @source.
99
+ This import is the ONLY recompile trigger in dev: the @source .html files below are
100
+ deliberately excluded from Vite's watcher (server.watch.ignored in the dev server's
101
+ vite.config.js) because watched .html changes force full browser reloads. The JIT
102
+ page builder touches this file whenever tailwind content changes. */
103
+ @import "./tailwind-candidates.css";
104
+
92
105
  ${userStylesImport}/* Content sources for Tailwind JIT — block JS content collected at build time */
93
106
  @source "../lowdefy-build/tailwind/*.html";
94
107
 
95
- /* Imported CSS file — when this changes, PostCSS re-runs and Tailwind re-scans @source */
96
- @import "./tailwind-candidates.css";
97
-
98
108
  /* Themed scrollbars — opts out of the browser default that clashes on dark surfaces,
99
109
  especially on Windows/Linux where scrollbars are always visible and native-chrome.
100
110
  Colors use antd CSS custom properties so they auto-swap with dark/light mode. */
@@ -130,12 +140,11 @@ ${themeVars}
130
140
  }
131
141
  `;
132
142
  await context.writeBuildArtifact('globals.css', css);
133
- // Standalone layer order declaration — imported FIRST in _app.js so that
134
- // Next.js/Turbopack generates a critical CSS chunk that loads before any
135
- // JavaScript (including antd's CSS-in-JS). This guarantees the cascade
136
- // layer priority is locked (antd > base/preflight) before antd injects
137
- // @layer antd {} at runtime. Without this, antd wins the race and becomes
138
- // the lowest-priority layer.
143
+ // Standalone layer order declaration — imported FIRST in the client entry
144
+ // (client/main.jsx) so the cascade layer priority is locked
145
+ // (antd > base/preflight) before antd's CSS-in-JS injects @layer antd {}
146
+ // at runtime. Without this, antd wins the race and becomes the
147
+ // lowest-priority layer.
139
148
  await context.writeBuildArtifact('layer-order.css', '/* Generated by Lowdefy build */\n@layer theme, base, antd, components, utilities;\n');
140
149
  await context.writeBuildArtifact('tailwind-candidates.css', '/* Generated by Lowdefy build — rewritten on page changes to trigger CSS recompilation */\n');
141
150
  for (const [pageId, content] of context.tailwindContentMap ?? []){
@@ -0,0 +1,31 @@
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 generateImportFile from './generateImportFile.js';
16
+ async function writeNotificationImports({ components, context }) {
17
+ const registry = generateImportFile({
18
+ imports: components.imports.notifications,
19
+ importPath: 'notifications'
20
+ });
21
+ // The servers statically import renderEmail and interpolateProperties from this
22
+ // file, so both named exports must always exist. Apps with notifications get
23
+ // the real implementations; apps without notifications never install
24
+ // @lowdefy/email-templates, so the exports are undefined placeholders.
25
+ const helperExports = (components.notifications ?? []).length > 0 ? `export { renderEmail, interpolateProperties } from '@lowdefy/email-templates';` : `export const renderEmail = undefined;
26
+ export const interpolateProperties = undefined;`;
27
+ await context.writeBuildArtifact('plugins/notifications.js', `${registry}
28
+ ${helperExports}
29
+ `);
30
+ }
31
+ export default writeNotificationImports;
@@ -12,7 +12,8 @@
12
12
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
13
  See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
- */ async function writeOperatorSchemaMap({ components, context }) {
15
+ */ import importPluginModule from './importPluginModule.js';
16
+ async function writeOperatorSchemaMap({ components, context }) {
16
17
  const schemas = {};
17
18
  const typesMapSchemas = context.typesMap.schemas?.operators ?? {};
18
19
  const allOperators = new Map();
@@ -30,12 +31,10 @@
30
31
  operatorsByPackage[op.package].push(op);
31
32
  }
32
33
  for (const [packageName, operators] of Object.entries(operatorsByPackage)){
33
- let packageSchemas;
34
- try {
35
- packageSchemas = await import(/* webpackIgnore: true */ `${packageName}/schemas`);
36
- } catch {
37
- // Package not resolvable from build context (custom plugins) — skip
38
- }
34
+ const packageSchemas = await importPluginModule({
35
+ context,
36
+ specifier: `${packageName}/schemas`
37
+ });
39
38
  for (const op of operators){
40
39
  if (typesMapSchemas[op.typeName]) {
41
40
  schemas[op.typeName] = typesMapSchemas[op.typeName];
@@ -16,14 +16,17 @@
16
16
  import writeActionSchemaMap from './writeActionSchemaMap.js';
17
17
  import writeAgentImports from './writeAgentImports.js';
18
18
  import writeAuthImports from './writeAuthImports.js';
19
+ import writeAvailableTypes from './writeAvailableTypes.js';
19
20
  import writeBlockImports from './writeBlockImports.js';
20
21
  import writeBlockSchemaMap from './writeBlockSchemaMap.js';
21
22
  import writeConnectionImports from './writeConnectionImports.js';
23
+ import writeConnectionSchemaMap from './writeConnectionSchemaMap.js';
22
24
  import writeIconImports from './writeIconImports.js';
25
+ import writeNotificationImports from './writeNotificationImports.js';
23
26
  import writeOperatorImports from './writeOperatorImports.js';
24
27
  import writeOperatorSchemaMap from './writeOperatorSchemaMap.js';
28
+ import writeWebsocketImports from './writeWebsocketImports.js';
25
29
  import writeGlobalsCss from './writeGlobalsCss.js';
26
- import writeServerExternalPackages from './writeServerExternalPackages.js';
27
30
  async function writePluginImports({ components, context }) {
28
31
  await writeActionImports({
29
32
  components,
@@ -53,10 +56,17 @@ async function writePluginImports({ components, context }) {
53
56
  components,
54
57
  context
55
58
  });
59
+ await writeConnectionSchemaMap({
60
+ context
61
+ });
56
62
  await writeIconImports({
57
63
  components,
58
64
  context
59
65
  });
66
+ await writeNotificationImports({
67
+ components,
68
+ context
69
+ });
60
70
  await writeOperatorImports({
61
71
  components,
62
72
  context
@@ -65,15 +75,19 @@ async function writePluginImports({ components, context }) {
65
75
  components,
66
76
  context
67
77
  });
68
- await writeGlobalsCss({
78
+ await writeWebsocketImports({
69
79
  components,
70
80
  context
71
81
  });
72
- await writeServerExternalPackages({
82
+ await writeAvailableTypes({
83
+ context
84
+ });
85
+ await writeGlobalsCss({
73
86
  components,
74
87
  context
75
88
  });
76
- // Write block package names for Next.js transpilePackages (CSS imports).
89
+ // Write block package names — available as a vite.config.js escape hatch
90
+ // (optimizeDeps/noExternal lists) for packages that don't resolve cleanly.
77
91
  const blockPackages = [
78
92
  ...new Set((components.imports.blocks ?? []).map((b)=>b.package))
79
93
  ];
@@ -0,0 +1,22 @@
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 generateImportFile from './generateImportFile.js';
16
+ async function writeWebsocketImports({ components, context }) {
17
+ await context.writeBuildArtifact('plugins/websockets.js', generateImportFile({
18
+ imports: components.imports.websockets,
19
+ importPath: 'websockets'
20
+ }));
21
+ }
22
+ export default writeWebsocketImports;
@@ -0,0 +1,30 @@
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, serializer } from '@lowdefy/helpers';
16
+ async function writeWebsocket({ websocket, context }) {
17
+ await context.writeBuildArtifact(`websockets/${websocket.websocketId}.json`, serializer.serializeToString(websocket ?? {}));
18
+ }
19
+ async function writeWebsockets({ components, context }) {
20
+ if (type.isNone(components.websockets)) return;
21
+ if (!type.isArray(components.websockets)) {
22
+ throw new Error(`Websockets is not an array.`);
23
+ }
24
+ const writePromises = components.websockets.map((websocket)=>writeWebsocket({
25
+ websocket,
26
+ context
27
+ }));
28
+ return Promise.all(writePromises);
29
+ }
30
+ export default writeWebsockets;
@@ -26,6 +26,8 @@ function createContext({ customMessagesMap, customTypesMap, directories, logger,
26
26
  defaultPackageNames: new Set(defaultPackages),
27
27
  agentIds: new Set(),
28
28
  connectionIds: new Set(),
29
+ notificationIds: new Set(),
30
+ websocketIds: new Set(),
29
31
  directories,
30
32
  errors: [],
31
33
  jsMap: {},
@@ -49,11 +51,14 @@ function createContext({ customMessagesMap, customTypesMap, directories, logger,
49
51
  adapters: createCounter(),
50
52
  callbacks: createCounter(),
51
53
  events: createCounter(),
52
- providers: createCounter()
54
+ providers: createCounter(),
55
+ strategies: createCounter()
53
56
  },
54
57
  blocks: createCounter(),
55
58
  connections: createCounter(),
59
+ notifications: createCounter(),
56
60
  requests: createCounter(),
61
+ websockets: createCounter(),
57
62
  controls: createCounter(),
58
63
  operators: {
59
64
  client: createCounter('client'),
@@ -21,6 +21,7 @@
21
21
  '@lowdefy/blocks-basic',
22
22
  '@lowdefy/blocks-diff',
23
23
  '@lowdefy/blocks-echarts',
24
+ '@lowdefy/blocks-files',
24
25
  '@lowdefy/blocks-google-maps',
25
26
  '@lowdefy/blocks-loaders',
26
27
  '@lowdefy/blocks-markdown',
@@ -40,7 +41,9 @@
40
41
  '@lowdefy/connection-mongodb',
41
42
  '@lowdefy/connection-redis',
42
43
  '@lowdefy/connection-sendgrid',
44
+ '@lowdefy/connection-smtp',
43
45
  '@lowdefy/connection-stripe',
46
+ '@lowdefy/email-templates',
44
47
  '@lowdefy/operators-change-case',
45
48
  '@lowdefy/operators-diff',
46
49
  '@lowdefy/operators-js',
@@ -52,7 +55,10 @@
52
55
  '@lowdefy/operators-yaml',
53
56
  '@lowdefy/plugin-auth0',
54
57
  '@lowdefy/plugin-aws',
58
+ '@lowdefy/plugin-azure',
55
59
  '@lowdefy/plugin-csv',
56
- '@lowdefy/plugin-next-auth'
60
+ '@lowdefy/plugin-gcp',
61
+ '@lowdefy/plugin-next-auth',
62
+ '@lowdefy/websockets-core'
57
63
  ];
58
64
  export default defaultPackages;