@lowdefy/build 4.7.2 → 5.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 (57) hide show
  1. package/dist/build/addDefaultPages/404.js +8 -2
  2. package/dist/build/buildApi/buildRoutine/validateStep.js +7 -5
  3. package/dist/build/buildApi/validateEndpoint.js +6 -5
  4. package/dist/build/buildConnections.js +6 -0
  5. package/dist/build/buildImports/buildIconImports.js +5 -1
  6. package/dist/build/buildImports/buildImportsDev.js +1 -6
  7. package/dist/build/buildImports/buildImportsProd.js +1 -6
  8. package/dist/build/buildImports/validateIconImports.js +65 -0
  9. package/dist/build/buildJs/jsMapParser.js +5 -2
  10. package/dist/build/buildPages/buildBlock/buildBlock.js +12 -4
  11. package/dist/build/buildPages/buildBlock/buildEvents.js +34 -1
  12. package/dist/build/buildPages/buildBlock/buildRequests.js +7 -5
  13. package/dist/build/buildPages/buildBlock/buildSubBlocks.js +9 -9
  14. package/dist/build/buildPages/buildBlock/countBlockOperators.js +1 -1
  15. package/dist/build/buildPages/buildBlock/moveAreasToSlots.js +31 -0
  16. package/dist/build/buildPages/buildBlock/{moveSkeletonBlocksToArea.js → moveSkeletonBlocksToSlot.js} +8 -8
  17. package/dist/build/buildPages/buildBlock/{moveSubBlocksToArea.js → moveSubBlocksToSlot.js} +3 -3
  18. package/dist/build/buildPages/buildBlock/normalizeClassAndStyles.js +124 -0
  19. package/dist/build/buildPages/buildBlock/normalizeLayout.js +68 -0
  20. package/dist/build/buildPages/buildBlock/setBlockId.js +7 -1
  21. package/dist/build/buildPages/buildBlock/validateSlots.js +34 -0
  22. package/dist/build/buildPages/buildPage.js +23 -1
  23. package/dist/build/buildRefs/addLineNumbers.js +76 -0
  24. package/dist/build/{buildImports/buildStyleImports.js → buildRefs/getLineNumber.js} +4 -10
  25. package/dist/build/buildRefs/getRefContent.js +9 -1
  26. package/dist/build/buildRefs/parseRefContent.js +4 -66
  27. package/dist/build/buildTypes.js +4 -2
  28. package/dist/build/cleanBuildDirectory.js +3 -1
  29. package/dist/build/collectPageContent.js +57 -0
  30. package/dist/build/jit/buildPageJit.js +14 -3
  31. package/dist/build/jit/collectSkeletonSourceFiles.js +75 -0
  32. package/dist/build/jit/extractIconData.js +16 -1
  33. package/dist/build/jit/pageContentKeys.js +1 -0
  34. package/dist/build/jit/shallowBuild.js +34 -1
  35. package/dist/build/jit/stripPageContent.js +29 -0
  36. package/dist/build/jit/writePageJit.js +9 -1
  37. package/dist/build/testSchema.js +3 -0
  38. package/dist/build/writePluginImports/collectBlockSourceContent.js +65 -0
  39. package/dist/build/writePluginImports/writeActionSchemaMap.js +1 -1
  40. package/dist/build/writePluginImports/writeBlockSchemaMap.js +45 -7
  41. package/dist/build/writePluginImports/writeGlobalsCss.js +126 -0
  42. package/dist/build/writePluginImports/writeOperatorSchemaMap.js +1 -1
  43. package/dist/build/writePluginImports/writePluginImports.js +7 -2
  44. package/dist/build/writeTheme.js +28 -0
  45. package/dist/createContext.js +2 -0
  46. package/dist/defaultTypesMap.js +1693 -837
  47. package/dist/index.js +16 -0
  48. package/dist/lowdefySchema.js +100 -0
  49. package/dist/scripts/generateDefaultTypes.js +5 -10
  50. package/dist/test-utils/runBuild.js +3 -0
  51. package/dist/test-utils/runBuildForSnapshots.js +5 -2
  52. package/dist/test-utils/testContext.js +2 -1
  53. package/dist/utils/createHandleWarning.js +3 -0
  54. package/dist/utils/createPluginTypesMap.js +5 -9
  55. package/dist/utils/validateId.js +24 -0
  56. package/package.json +47 -47
  57. package/dist/build/writePluginImports/writeStyleImports.js +0 -34
@@ -40,6 +40,7 @@ import writeApi from '../writeApi.js';
40
40
  import writeGlobal from '../writeGlobal.js';
41
41
  import writeJs from '../buildJs/writeJs.js';
42
42
  import writeLogger from '../writeLogger.js';
43
+ import writeTheme from '../writeTheme.js';
43
44
  import writeMaps from '../writeMaps.js';
44
45
  import updateServerPackageJson from '../full/updateServerPackageJson.js';
45
46
  import writeMenus from '../writeMenus.js';
@@ -48,6 +49,9 @@ import writePluginImports from '../writePluginImports/writePluginImports.js';
48
49
  import addInstalledTypes from './addInstalledTypes.js';
49
50
  import buildJsShallow from './buildJsShallow.js';
50
51
  import buildShallowPages from './buildShallowPages.js';
52
+ import collectPageContent from '../collectPageContent.js';
53
+ import collectSkeletonSourceFiles from './collectSkeletonSourceFiles.js';
54
+ import stripPageContent from './stripPageContent.js';
51
55
  import writeSourcelessPages from './writeSourcelessPages.js';
52
56
  async function shallowBuild(options) {
53
57
  makeId.reset();
@@ -67,11 +71,33 @@ async function shallowBuild(options) {
67
71
  }
68
72
  throw err;
69
73
  }
74
+ // Stop early if buildRefs collected errors (e.g., YAML parse errors).
75
+ // Failed _ref resolutions leave null entries in arrays — logging now
76
+ // surfaces the real error before downstream code crashes on nulls.
77
+ logCollectedErrors(context);
78
+ // Collect skeleton source files while ~r markers still exist on objects.
79
+ const skeletonSourceFiles = collectSkeletonSourceFiles({
80
+ components,
81
+ context
82
+ });
70
83
  // addKeys + testSchema first for error location info
71
84
  tryBuildStep(addKeys, 'addKeys', {
72
85
  components,
73
86
  context
74
87
  });
88
+ context.tailwindContentMap = new Map();
89
+ for (const page of components.pages ?? []){
90
+ const content = collectPageContent([
91
+ page
92
+ ]);
93
+ if (content) {
94
+ context.tailwindContentMap.set(page.id, content);
95
+ }
96
+ }
97
+ stripPageContent({
98
+ components,
99
+ context
100
+ });
75
101
  tryBuildStep(testSchema, 'testSchema', {
76
102
  components,
77
103
  context
@@ -179,6 +205,10 @@ async function shallowBuild(options) {
179
205
  components,
180
206
  context
181
207
  });
208
+ await writeTheme({
209
+ components,
210
+ context
211
+ });
182
212
  await writeLogger({
183
213
  components,
184
214
  context
@@ -188,7 +218,10 @@ async function shallowBuild(options) {
188
218
  });
189
219
  await context.writeBuildArtifact('connectionIds.json', JSON.stringify([
190
220
  ...context.connectionIds
191
- ]));
221
+ ].sort()));
222
+ await context.writeBuildArtifact('skeletonSourceFiles.json', JSON.stringify([
223
+ ...skeletonSourceFiles
224
+ ].sort()));
192
225
  await writeMenus({
193
226
  components,
194
227
  context
@@ -0,0 +1,29 @@
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 PAGE_CONTENT_KEYS from './pageContentKeys.js';
17
+ function stripPageContent({ components, context }) {
18
+ for (const page of components.pages ?? []){
19
+ // Only strip pages that have a source ref (will be JIT-rebuilt).
20
+ // Inline pages (no ~r) must keep their content for buildShallowPages.
21
+ const keyMapEntry = context.keyMap[page['~k']];
22
+ const refId = keyMapEntry?.['~r'] ?? null;
23
+ if (type.isNone(refId)) continue;
24
+ for (const key of PAGE_CONTENT_KEYS){
25
+ delete page[key];
26
+ }
27
+ }
28
+ }
29
+ export default stripPageContent;
@@ -12,7 +12,10 @@
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
- */ import { serializer, type } from '@lowdefy/helpers';
15
+ */ import path from 'path';
16
+ import { serializer, type } from '@lowdefy/helpers';
17
+ import { writeFile } from '@lowdefy/node-utils';
18
+ import collectPageContent from '../collectPageContent.js';
16
19
  import writeJs from '../buildJs/writeJs.js';
17
20
  async function writePageJit({ page, context }) {
18
21
  // Write page JSON
@@ -40,5 +43,10 @@ async function writePageJit({ page, context }) {
40
43
  await writeJs({
41
44
  context
42
45
  });
46
+ // Write per-page content file for Tailwind to scan class and property strings
47
+ const pageContent = collectPageContent([
48
+ page
49
+ ]);
50
+ await writeFile(path.join(context.directories.server, 'lowdefy-build', 'tailwind', `${page.pageId}.html`), '<!-- Generated by Lowdefy build -->\n' + (pageContent ?? ''));
43
51
  }
44
52
  export default writePageJit;
@@ -48,9 +48,12 @@ function testSchema({ components, context }) {
48
48
  components,
49
49
  instancePath
50
50
  });
51
+ const propertyName = instancePath[instancePath.length - 1];
51
52
  let message = error.message;
52
53
  if (error.params?.additionalProperty) {
53
54
  message = `${message} - "${error.params.additionalProperty}"`;
55
+ } else if (propertyName) {
56
+ message = `"${propertyName}" ${message}`;
54
57
  }
55
58
  const configError = new ConfigError(message, {
56
59
  configKey,
@@ -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 fs from 'fs';
16
+ import path from 'path';
17
+ import { createRequire } from 'node:module';
18
+ // Extract all string literals from JS source that could be Tailwind class candidates.
19
+ // We read the raw JS text — no AST parsing needed. Tailwind's scanner does the same:
20
+ // it treats every word-like token as a potential class candidate.
21
+ function readJsFiles(distDir) {
22
+ const content = [];
23
+ function walk(dir) {
24
+ for (const entry of fs.readdirSync(dir, {
25
+ withFileTypes: true
26
+ })){
27
+ const fullPath = path.join(dir, entry.name);
28
+ if (entry.isDirectory()) {
29
+ walk(fullPath);
30
+ } else if (/\.(js|jsx|ts|tsx|mjs)$/.test(entry.name)) {
31
+ content.push(fs.readFileSync(fullPath, 'utf8'));
32
+ }
33
+ }
34
+ }
35
+ if (fs.existsSync(distDir)) {
36
+ walk(distDir);
37
+ }
38
+ return content.join('\n');
39
+ }
40
+ function collectBlockSourceContent({ components, serverDirectory }) {
41
+ // Resolve packages from the server directory, not from @lowdefy/build's own location.
42
+ // In production, @lowdefy/build is installed inside .lowdefy/server/node_modules/.
43
+ // With pnpm, import.meta.url resolves to the .pnpm store where only @lowdefy/build's
44
+ // own declared deps are visible. Block packages are deps of the server, not of
45
+ // @lowdefy/build, so require.resolve from import.meta.url silently fails.
46
+ // Rooting at the server's package.json ensures block packages are always reachable.
47
+ const requireFromServer = createRequire(path.join(serverDirectory, 'package.json'));
48
+ const packages = [
49
+ ...new Set((components.imports?.blocks ?? []).map((b)=>b.package))
50
+ ];
51
+ const allContent = [];
52
+ for (const packageName of packages){
53
+ try {
54
+ // Resolve the package entry to find its real location on disk.
55
+ // This follows pnpm symlinks, yarn PnP, npm hoisting — any install strategy.
56
+ const entryPath = requireFromServer.resolve(`${packageName}/blocks`);
57
+ const distDir = path.dirname(entryPath);
58
+ allContent.push(readJsFiles(distDir));
59
+ } catch {
60
+ // Package not resolvable from server context (e.g., custom plugin not installed) — skip.
61
+ }
62
+ }
63
+ return allContent.join('\n');
64
+ }
65
+ export default collectBlockSourceContent;
@@ -25,7 +25,7 @@
25
25
  for (const [packageName, actions] of Object.entries(actionsByPackage)){
26
26
  let packageSchemas;
27
27
  try {
28
- packageSchemas = await import(`${packageName}/schemas`);
28
+ packageSchemas = await import(/* webpackIgnore: true */ `${packageName}/schemas`);
29
29
  } catch {
30
30
  // Package not resolvable from build context (custom plugins) — skip
31
31
  }
@@ -12,8 +12,10 @@
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 writeBlockSchemaMap({ components, context }) {
15
+ */ import { buildBlockSchema } from '@lowdefy/block-utils';
16
+ async function writeBlockSchemaMap({ components, context }) {
16
17
  const schemas = {};
18
+ const allMetas = {};
17
19
  const typesMapSchemas = context.typesMap.schemas?.blocks ?? {};
18
20
  const blocksByPackage = {};
19
21
  for (const block of components.imports.blocks){
@@ -23,20 +25,56 @@
23
25
  blocksByPackage[block.package].push(block);
24
26
  }
25
27
  for (const [packageName, blocks] of Object.entries(blocksByPackage)){
26
- let packageSchemas;
28
+ let packageMetas;
27
29
  try {
28
- packageSchemas = await import(`${packageName}/schemas`);
30
+ packageMetas = await import(/* webpackIgnore: true */ `${packageName}/metas`);
29
31
  } catch {
30
- // Package not resolvable from build context (custom plugins) — skip
32
+ try {
33
+ packageMetas = await import(/* webpackIgnore: true */ `${packageName}/schemas`);
34
+ } catch {
35
+ // Package not resolvable from build context (custom plugins) — skip
36
+ }
31
37
  }
32
38
  for (const block of blocks){
39
+ const meta = packageMetas?.[block.originalTypeName];
33
40
  if (typesMapSchemas[block.typeName]) {
34
41
  schemas[block.typeName] = typesMapSchemas[block.typeName];
35
- } else if (packageSchemas?.[block.originalTypeName]) {
36
- schemas[block.typeName] = packageSchemas[block.originalTypeName];
42
+ } else if (meta) {
43
+ schemas[block.typeName] = buildBlockSchema(meta);
44
+ }
45
+ if (meta) {
46
+ allMetas[block.typeName] = meta;
37
47
  }
38
48
  }
39
49
  }
40
- return context.writeBuildArtifact('plugins/blockSchemas.json', JSON.stringify(schemas));
50
+ const blockMetas = {};
51
+ const typesMapBlockMetas = context.typesMap.blockMetas ?? {};
52
+ for (const block of components.imports.blocks){
53
+ const typesMapMeta = typesMapBlockMetas[block.typeName];
54
+ const meta = allMetas[block.typeName];
55
+ if (typesMapMeta) {
56
+ blockMetas[block.typeName] = {
57
+ category: typesMapMeta.category,
58
+ ...typesMapMeta.valueType != null && {
59
+ valueType: typesMapMeta.valueType
60
+ },
61
+ ...typesMapMeta.initValue !== undefined && {
62
+ initValue: typesMapMeta.initValue
63
+ }
64
+ };
65
+ } else if (meta) {
66
+ blockMetas[block.typeName] = {
67
+ category: meta.category,
68
+ ...meta.valueType != null && {
69
+ valueType: meta.valueType
70
+ },
71
+ ...meta.initValue !== undefined && {
72
+ initValue: meta.initValue
73
+ }
74
+ };
75
+ }
76
+ }
77
+ await context.writeBuildArtifact('plugins/blockSchemas.json', JSON.stringify(schemas));
78
+ await context.writeBuildArtifact('plugins/blockMetas.json', JSON.stringify(blockMetas));
41
79
  }
42
80
  export default writeBlockSchemaMap;
@@ -0,0 +1,126 @@
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 fs from 'fs';
16
+ import path from 'path';
17
+ import { ConfigError } from '@lowdefy/errors';
18
+ import { mergeObjects } from '@lowdefy/helpers';
19
+ import { writeFile } from '@lowdefy/node-utils';
20
+ import collectBlockSourceContent from './collectBlockSourceContent.js';
21
+ const BRIDGE_DEFAULTS = {
22
+ color: {
23
+ primary: 'var(--ant-color-primary)',
24
+ 'primary-hover': 'var(--ant-color-primary-hover)',
25
+ 'primary-active': 'var(--ant-color-primary-active)',
26
+ 'primary-bg': 'var(--ant-color-primary-bg)',
27
+ success: 'var(--ant-color-success)',
28
+ warning: 'var(--ant-color-warning)',
29
+ error: 'var(--ant-color-error)',
30
+ info: 'var(--ant-color-info)',
31
+ 'text-primary': 'var(--ant-color-text)',
32
+ 'text-secondary': 'var(--ant-color-text-secondary)',
33
+ 'bg-container': 'var(--ant-color-bg-container)',
34
+ 'bg-layout': 'var(--ant-color-bg-layout)',
35
+ border: 'var(--ant-color-border)'
36
+ },
37
+ radius: {
38
+ DEFAULT: 'var(--ant-border-radius)',
39
+ sm: 'var(--ant-border-radius-sm)',
40
+ lg: 'var(--ant-border-radius-lg)'
41
+ },
42
+ 'font-size': {
43
+ DEFAULT: 'var(--ant-font-size)',
44
+ sm: 'var(--ant-font-size-sm)',
45
+ lg: 'var(--ant-font-size-lg)'
46
+ },
47
+ 'font-family': {
48
+ sans: 'var(--ant-font-family)'
49
+ }
50
+ };
51
+ function objectToThemeVars(obj, prefix) {
52
+ const lines = [];
53
+ for (const [key, value] of Object.entries(obj)){
54
+ const varName = prefix ? `${prefix}-${key}` : `--${key}`;
55
+ if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
56
+ lines.push(...objectToThemeVars(value, varName));
57
+ } else {
58
+ lines.push(` ${varName}: ${value};`);
59
+ }
60
+ }
61
+ return lines;
62
+ }
63
+ function buildThemeVars(tailwindConfig) {
64
+ const merged = mergeObjects([
65
+ {},
66
+ BRIDGE_DEFAULTS,
67
+ tailwindConfig ?? {}
68
+ ]);
69
+ return objectToThemeVars(merged).join('\n');
70
+ }
71
+ async function writeGlobalsCss({ components, context }) {
72
+ if (fs.existsSync(path.join(context.directories.config, 'public/styles.less'))) {
73
+ throw new ConfigError('public/styles.less is deprecated. Migrate to: (1) "theme" key in lowdefy.yaml for token overrides (recommended), (2) public/styles.css for custom CSS.');
74
+ }
75
+ const tailwindConfig = components.theme?.tailwind;
76
+ const themeVars = buildThemeVars(tailwindConfig);
77
+ const userStylesAbsolute = path.join(context.directories.config, 'public/styles.css');
78
+ const importUserStyles = fs.existsSync(userStylesAbsolute);
79
+ let userStylesImport = '';
80
+ if (importUserStyles) {
81
+ const relPath = path.relative(context.directories.build, userStylesAbsolute).split(path.sep).join('/');
82
+ userStylesImport = `/* User custom styles */\n@import "${relPath}" layer(components);\n\n`;
83
+ }
84
+ const css = `/* Generated by Lowdefy build */
85
+
86
+ /* Layer order — locks cascade priority before Tailwind declares its own layers */
87
+ @layer theme, base, antd, components, utilities;
88
+
89
+ @import "tailwindcss";
90
+ @import "@lowdefy/layout/grid.css";
91
+
92
+ ${userStylesImport}/* Content sources for Tailwind JIT — block JS content collected at build time */
93
+ @source "../lowdefy-build/tailwind/*.html";
94
+
95
+ /* Imported CSS file — when this changes, PostCSS re-runs and Tailwind re-scans @source */
96
+ @import "./tailwind-candidates.css";
97
+
98
+ /* Antd-to-Tailwind theme bridge — extends default Tailwind theme with antd design tokens */
99
+ @theme inline {
100
+ ${themeVars}
101
+ }
102
+ `;
103
+ await context.writeBuildArtifact('globals.css', css);
104
+ // Standalone layer order declaration — imported FIRST in _app.js so that
105
+ // Next.js/Turbopack generates a critical CSS chunk that loads before any
106
+ // JavaScript (including antd's CSS-in-JS). This guarantees the cascade
107
+ // layer priority is locked (antd > base/preflight) before antd injects
108
+ // @layer antd {} at runtime. Without this, antd wins the race and becomes
109
+ // the lowest-priority layer.
110
+ await context.writeBuildArtifact('layer-order.css', '/* Generated by Lowdefy build */\n@layer theme, base, antd, components, utilities;\n');
111
+ await context.writeBuildArtifact('tailwind-candidates.css', '/* Generated by Lowdefy build — rewritten on page changes to trigger CSS recompilation */\n');
112
+ for (const [pageId, content] of context.tailwindContentMap ?? []){
113
+ await writeFile(path.join(context.directories.server, 'lowdefy-build', 'tailwind', `${pageId}.html`), '<!-- Generated by Lowdefy build -->\n' + content);
114
+ }
115
+ // Collect Tailwind class candidates from block plugin JS source files.
116
+ // Resolves from the server directory so block packages are reachable regardless
117
+ // of package manager (pnpm strict isolation, yarn PnP, npm hoisting).
118
+ const blockContent = collectBlockSourceContent({
119
+ components,
120
+ serverDirectory: context.directories.server
121
+ });
122
+ if (blockContent) {
123
+ await writeFile(path.join(context.directories.server, 'lowdefy-build', 'tailwind', '_blocks.html'), '<!-- Block plugin JS content collected at build time -->\n' + blockContent);
124
+ }
125
+ }
126
+ export default writeGlobalsCss;
@@ -32,7 +32,7 @@
32
32
  for (const [packageName, operators] of Object.entries(operatorsByPackage)){
33
33
  let packageSchemas;
34
34
  try {
35
- packageSchemas = await import(`${packageName}/schemas`);
35
+ packageSchemas = await import(/* webpackIgnore: true */ `${packageName}/schemas`);
36
36
  } catch {
37
37
  // Package not resolvable from build context (custom plugins) — skip
38
38
  }
@@ -21,7 +21,7 @@ import writeConnectionImports from './writeConnectionImports.js';
21
21
  import writeIconImports from './writeIconImports.js';
22
22
  import writeOperatorImports from './writeOperatorImports.js';
23
23
  import writeOperatorSchemaMap from './writeOperatorSchemaMap.js';
24
- import writeStyleImports from './writeStyleImports.js';
24
+ import writeGlobalsCss from './writeGlobalsCss.js';
25
25
  async function writePluginImports({ components, context }) {
26
26
  await writeActionImports({
27
27
  components,
@@ -59,9 +59,14 @@ async function writePluginImports({ components, context }) {
59
59
  components,
60
60
  context
61
61
  });
62
- await writeStyleImports({
62
+ await writeGlobalsCss({
63
63
  components,
64
64
  context
65
65
  });
66
+ // Write block package names for Next.js transpilePackages (CSS imports).
67
+ const blockPackages = [
68
+ ...new Set((components.imports.blocks ?? []).map((b)=>b.package))
69
+ ];
70
+ await context.writeBuildArtifact('blockPackages.json', JSON.stringify(blockPackages));
66
71
  }
67
72
  export default writePluginImports;
@@ -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, serializer } from '@lowdefy/helpers';
16
+ async function writeTheme({ components, context }) {
17
+ if (type.isNone(components.theme)) {
18
+ components.theme = {};
19
+ }
20
+ if (!type.isObject(components.theme)) {
21
+ throw new Error('Theme is not an object.');
22
+ }
23
+ if (type.isNone(components.theme.darkMode)) {
24
+ components.theme.darkMode = 'system';
25
+ }
26
+ await context.writeBuildArtifact('theme.json', serializer.serializeToString(components.theme));
27
+ }
28
+ export default writeTheme;
@@ -25,6 +25,7 @@ function createContext({ customTypesMap, directories, logger, refResolver, stage
25
25
  directories,
26
26
  errors: [],
27
27
  jsMap: {},
28
+ warnings: [],
28
29
  keyMap: {},
29
30
  logger,
30
31
  readConfigFile: createReadConfigFile({
@@ -60,6 +61,7 @@ function createContext({ customTypesMap, directories, logger, refResolver, stage
60
61
  directories
61
62
  })
62
63
  };
64
+ context.blockMetas = context.typesMap.blockMetas ?? {};
63
65
  context.handleError = createBuildHandleError({
64
66
  context
65
67
  });