@lowdefy/server-dev 4.7.0 → 4.7.1

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.
@@ -15,6 +15,7 @@
15
15
  */
16
16
 
17
17
  import React from 'react';
18
+ import { GenIcon } from 'react-icons/lib';
18
19
  import Client from '@lowdefy/client';
19
20
 
20
21
  import BuildErrorPage from './BuildErrorPage.js';
@@ -58,6 +59,17 @@ const Page = ({
58
59
  // Merge dynamic JS entries fetched after JIT build with the static jsMap
59
60
  const mergedJsMap = pageConfig._jsEntries ? { ...jsMap, ...pageConfig._jsEntries } : jsMap;
60
61
 
62
+ // Merge JIT-discovered icon data into the static icons object.
63
+ // createIcon.js looks up Icons[name] on every render from the captured reference,
64
+ // so mutating the original object makes new icons available immediately.
65
+ if (pageConfig._dynamicIcons) {
66
+ for (const [name, data] of Object.entries(pageConfig._dynamicIcons)) {
67
+ if (!types.icons[name]) {
68
+ types.icons[name] = GenIcon(data);
69
+ }
70
+ }
71
+ }
72
+
61
73
  return (
62
74
  <Client
63
75
  auth={auth}
@@ -32,6 +32,16 @@ async function fetchJsEntries(basePath) {
32
32
  }
33
33
  }
34
34
 
35
+ async function fetchDynamicIcons(basePath) {
36
+ try {
37
+ const res = await fetch(`${basePath}/api/icons/dynamic`);
38
+ if (!res.ok) return {};
39
+ return parseJsModule(await res.text());
40
+ } catch {
41
+ return {};
42
+ }
43
+ }
44
+
35
45
  async function fetchPageConfig(url) {
36
46
  const res = await fetch(url, {
37
47
  headers: { 'Content-Type': 'application/json' },
@@ -50,11 +60,16 @@ async function fetchPageConfig(url) {
50
60
  throw new Error(data.message || 'Request error');
51
61
  }
52
62
 
53
- // Fetch jsMap after page build completes (JIT build may have added new entries).
54
- // Extract basePath from the URL to construct the jsMap endpoint.
63
+ // Fetch jsMap and dynamic icons after page build completes
64
+ // (JIT build may have added new entries).
65
+ // Extract basePath from the URL to construct the endpoints.
55
66
  const basePath = url.replace(/\/api\/page\/.*$/, '');
56
- const jsEntries = await fetchJsEntries(basePath);
67
+ const [jsEntries, dynamicIcons] = await Promise.all([
68
+ fetchJsEntries(basePath),
69
+ fetchDynamicIcons(basePath),
70
+ ]);
57
71
  data._jsEntries = jsEntries;
72
+ data._dynamicIcons = dynamicIcons;
58
73
 
59
74
  return data;
60
75
  }
@@ -34,6 +34,12 @@ let cachedRegistry = null;
34
34
  let cachedBuildContext = null;
35
35
  let lastInvalidationMtime = null;
36
36
 
37
+ // Frozen snapshot of icon imports from the initial build (what's actually in the Next.js bundle).
38
+ // Module-level so it persists across context resets (skeleton rebuilds update iconImports.json
39
+ // with newly discovered icons, but those aren't in the bundle until the next nextBuild).
40
+ // Only resets when the server process restarts (which happens after every nextBuild).
41
+ let bundledIconImports = null;
42
+
37
43
  function readJsonFile(filePath) {
38
44
  try {
39
45
  const content = fs.readFileSync(filePath, 'utf8');
@@ -112,6 +118,19 @@ function getBuildContext(buildDirectory, configDirectory) {
112
118
  readJsonFile(path.join(buildDirectory, 'installedPluginPackages.json')) ?? [];
113
119
  cachedBuildContext.installedPluginPackages = new Set(installedPluginPackages);
114
120
 
121
+ // Use the frozen icon imports from the initial build for JIT detection.
122
+ // This represents what's actually in the Next.js bundle — not what shallowBuild
123
+ // discovers on subsequent rebuilds (those icons aren't bundled yet).
124
+ // bundledIconImports is module-level and only resets on server restart (after nextBuild).
125
+ if (!bundledIconImports) {
126
+ bundledIconImports = readJsonFile(path.join(buildDirectory, 'iconImports.json')) ?? [];
127
+ }
128
+ cachedBuildContext.iconImports = bundledIconImports;
129
+
130
+ // Accumulator for dynamically extracted icon SVG data written to plugins/iconsDynamic.js.
131
+ // Reset on skeleton rebuild (cachedBuildContext = null) — JIT re-discovers as needed.
132
+ cachedBuildContext.dynamicIconData = {};
133
+
115
134
  // Advance makeId past all skeleton IDs to prevent collisions with JIT builds
116
135
  const idCounter = readJsonFile(path.join(buildDirectory, 'idCounter.json'));
117
136
  if (idCounter != null) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lowdefy/server-dev",
3
- "version": "4.7.0",
3
+ "version": "4.7.1",
4
4
  "license": "Apache-2.0",
5
5
  "description": "",
6
6
  "homepage": "https://lowdefy.com",
@@ -36,34 +36,34 @@
36
36
  ".npmrc"
37
37
  ],
38
38
  "dependencies": {
39
- "@lowdefy/actions-core": "4.7.0",
40
- "@lowdefy/api": "4.7.0",
41
- "@lowdefy/block-utils": "4.7.0",
42
- "@lowdefy/blocks-aggrid": "4.7.0",
43
- "@lowdefy/blocks-antd": "4.7.0",
44
- "@lowdefy/blocks-basic": "4.7.0",
45
- "@lowdefy/blocks-color-selectors": "4.7.0",
46
- "@lowdefy/blocks-echarts": "4.7.0",
47
- "@lowdefy/blocks-loaders": "4.7.0",
48
- "@lowdefy/blocks-markdown": "4.7.0",
49
- "@lowdefy/blocks-qr": "4.7.0",
50
- "@lowdefy/build": "4.7.0",
51
- "@lowdefy/client": "4.7.0",
52
- "@lowdefy/engine": "4.7.0",
53
- "@lowdefy/errors": "4.7.0",
54
- "@lowdefy/helpers": "4.7.0",
55
- "@lowdefy/layout": "4.7.0",
56
- "@lowdefy/logger": "4.7.0",
57
- "@lowdefy/node-utils": "4.7.0",
58
- "@lowdefy/operators-change-case": "4.7.0",
59
- "@lowdefy/operators-diff": "4.7.0",
60
- "@lowdefy/operators-js": "4.7.0",
61
- "@lowdefy/operators-moment": "4.7.0",
62
- "@lowdefy/operators-mql": "4.7.0",
63
- "@lowdefy/operators-nunjucks": "4.7.0",
64
- "@lowdefy/operators-uuid": "4.7.0",
65
- "@lowdefy/operators-yaml": "4.7.0",
66
- "@lowdefy/plugin-next-auth": "4.7.0",
39
+ "@lowdefy/actions-core": "4.7.1",
40
+ "@lowdefy/api": "4.7.1",
41
+ "@lowdefy/block-utils": "4.7.1",
42
+ "@lowdefy/blocks-aggrid": "4.7.1",
43
+ "@lowdefy/blocks-antd": "4.7.1",
44
+ "@lowdefy/blocks-basic": "4.7.1",
45
+ "@lowdefy/blocks-color-selectors": "4.7.1",
46
+ "@lowdefy/blocks-echarts": "4.7.1",
47
+ "@lowdefy/blocks-loaders": "4.7.1",
48
+ "@lowdefy/blocks-markdown": "4.7.1",
49
+ "@lowdefy/blocks-qr": "4.7.1",
50
+ "@lowdefy/build": "4.7.1",
51
+ "@lowdefy/client": "4.7.1",
52
+ "@lowdefy/engine": "4.7.1",
53
+ "@lowdefy/errors": "4.7.1",
54
+ "@lowdefy/helpers": "4.7.1",
55
+ "@lowdefy/layout": "4.7.1",
56
+ "@lowdefy/logger": "4.7.1",
57
+ "@lowdefy/node-utils": "4.7.1",
58
+ "@lowdefy/operators-change-case": "4.7.1",
59
+ "@lowdefy/operators-diff": "4.7.1",
60
+ "@lowdefy/operators-js": "4.7.1",
61
+ "@lowdefy/operators-moment": "4.7.1",
62
+ "@lowdefy/operators-mql": "4.7.1",
63
+ "@lowdefy/operators-nunjucks": "4.7.1",
64
+ "@lowdefy/operators-uuid": "4.7.1",
65
+ "@lowdefy/operators-yaml": "4.7.1",
66
+ "@lowdefy/plugin-next-auth": "4.7.1",
67
67
  "chokidar": "3.5.3",
68
68
  "dotenv": "16.3.1",
69
69
  "next": "13.5.4",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lowdefy/server-dev",
3
- "version": "4.7.0",
3
+ "version": "4.7.1",
4
4
  "license": "Apache-2.0",
5
5
  "description": "",
6
6
  "homepage": "https://lowdefy.com",
@@ -44,34 +44,34 @@
44
44
  "prepublishOnly": "pnpm build"
45
45
  },
46
46
  "dependencies": {
47
- "@lowdefy/actions-core": "4.7.0",
48
- "@lowdefy/api": "4.7.0",
49
- "@lowdefy/block-utils": "4.7.0",
50
- "@lowdefy/blocks-aggrid": "4.7.0",
51
- "@lowdefy/blocks-antd": "4.7.0",
52
- "@lowdefy/blocks-basic": "4.7.0",
53
- "@lowdefy/blocks-color-selectors": "4.7.0",
54
- "@lowdefy/blocks-echarts": "4.7.0",
55
- "@lowdefy/blocks-loaders": "4.7.0",
56
- "@lowdefy/blocks-markdown": "4.7.0",
57
- "@lowdefy/blocks-qr": "4.7.0",
58
- "@lowdefy/build": "4.7.0",
59
- "@lowdefy/client": "4.7.0",
60
- "@lowdefy/engine": "4.7.0",
61
- "@lowdefy/errors": "4.7.0",
62
- "@lowdefy/helpers": "4.7.0",
63
- "@lowdefy/layout": "4.7.0",
64
- "@lowdefy/logger": "4.7.0",
65
- "@lowdefy/node-utils": "4.7.0",
66
- "@lowdefy/operators-change-case": "4.7.0",
67
- "@lowdefy/operators-diff": "4.7.0",
68
- "@lowdefy/operators-js": "4.7.0",
69
- "@lowdefy/operators-moment": "4.7.0",
70
- "@lowdefy/operators-mql": "4.7.0",
71
- "@lowdefy/operators-nunjucks": "4.7.0",
72
- "@lowdefy/operators-uuid": "4.7.0",
73
- "@lowdefy/operators-yaml": "4.7.0",
74
- "@lowdefy/plugin-next-auth": "4.7.0",
47
+ "@lowdefy/actions-core": "4.7.1",
48
+ "@lowdefy/api": "4.7.1",
49
+ "@lowdefy/block-utils": "4.7.1",
50
+ "@lowdefy/blocks-aggrid": "4.7.1",
51
+ "@lowdefy/blocks-antd": "4.7.1",
52
+ "@lowdefy/blocks-basic": "4.7.1",
53
+ "@lowdefy/blocks-color-selectors": "4.7.1",
54
+ "@lowdefy/blocks-echarts": "4.7.1",
55
+ "@lowdefy/blocks-loaders": "4.7.1",
56
+ "@lowdefy/blocks-markdown": "4.7.1",
57
+ "@lowdefy/blocks-qr": "4.7.1",
58
+ "@lowdefy/build": "4.7.1",
59
+ "@lowdefy/client": "4.7.1",
60
+ "@lowdefy/engine": "4.7.1",
61
+ "@lowdefy/errors": "4.7.1",
62
+ "@lowdefy/helpers": "4.7.1",
63
+ "@lowdefy/layout": "4.7.1",
64
+ "@lowdefy/logger": "4.7.1",
65
+ "@lowdefy/node-utils": "4.7.1",
66
+ "@lowdefy/operators-change-case": "4.7.1",
67
+ "@lowdefy/operators-diff": "4.7.1",
68
+ "@lowdefy/operators-js": "4.7.1",
69
+ "@lowdefy/operators-moment": "4.7.1",
70
+ "@lowdefy/operators-mql": "4.7.1",
71
+ "@lowdefy/operators-nunjucks": "4.7.1",
72
+ "@lowdefy/operators-uuid": "4.7.1",
73
+ "@lowdefy/operators-yaml": "4.7.1",
74
+ "@lowdefy/plugin-next-auth": "4.7.1",
75
75
  "chokidar": "3.5.3",
76
76
  "dotenv": "16.3.1",
77
77
  "next": "13.5.4",
@@ -0,0 +1,34 @@
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
+ */
16
+
17
+ import fs from 'fs';
18
+ import path from 'path';
19
+
20
+ async function handler(req, res) {
21
+ const filePath = path.join(process.cwd(), 'build', 'plugins', 'iconsDynamic.js');
22
+
23
+ try {
24
+ const content = fs.readFileSync(filePath, 'utf8');
25
+ res.setHeader('Content-Type', 'application/javascript');
26
+ res.status(200).send(content);
27
+ } catch {
28
+ // Return empty default export if file doesn't exist yet
29
+ res.setHeader('Content-Type', 'application/javascript');
30
+ res.status(200).send('export default {};');
31
+ }
32
+ }
33
+
34
+ export default handler;