@lowdefy/server-dev 5.6.0 → 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 (214) hide show
  1. package/{pages/_app.js → client/App.jsx} +21 -33
  2. package/client/DevStreamContext.js +30 -0
  3. package/client/Inspector.jsx +226 -0
  4. package/{lib/client/Page.js → client/Page.jsx} +4 -8
  5. package/client/Reload.jsx +85 -0
  6. package/client/Routing.jsx +117 -0
  7. package/client/feedback/FeedbackMount.jsx +83 -0
  8. package/client/feedback/FeedbackOverlay.jsx +901 -0
  9. package/client/feedback/captureTabScreenshot.js +84 -0
  10. package/client/feedback/copyToClipboard.js +45 -0
  11. package/client/feedback/drawAnnotationsSvg.js +119 -0
  12. package/client/feedback/elementInspect.js +99 -0
  13. package/client/feedback/feedbackStyles.js +301 -0
  14. package/client/feedback/pinResponsiveImages.js +59 -0
  15. package/client/feedback/sendFeedback.js +39 -0
  16. package/client/feedback/useFeedbackToggle.js +70 -0
  17. package/client/main.jsx +42 -0
  18. package/client/openInEditor/OpenInEditorListener.jsx +268 -0
  19. package/client/openInEditor/findBlockLocation.js +51 -0
  20. package/lib/build/app.js +8 -1
  21. package/lib/build/appMeta.js +8 -1
  22. package/lib/build/auth.js +8 -1
  23. package/lib/build/config.js +8 -1
  24. package/lib/build/i18n.js +8 -1
  25. package/lib/build/logger.js +8 -1
  26. package/lib/build/theme.js +8 -1
  27. package/lib/client/auth/{Auth.js → Auth.jsx} +11 -2
  28. package/lib/client/auth/{AuthConfigured.js → AuthConfigured.jsx} +23 -10
  29. package/lib/client/setPageId.js +6 -5
  30. package/lib/client/utils/useMutateCache.js +14 -1
  31. package/lib/client/utils/usePageConfig.js +45 -43
  32. package/lib/client/utils/usePageConfig.test.mjs +62 -0
  33. package/lib/docs/captureAnnotatedScreenshot.js +88 -0
  34. package/lib/docs/checkpointPaths.js +91 -0
  35. package/lib/docs/checkpointStore.js +240 -0
  36. package/lib/docs/checkpointToMocks.js +65 -0
  37. package/lib/docs/clientErrorStore.js +36 -0
  38. package/lib/docs/configCheckpoints.test.mjs +156 -0
  39. package/lib/docs/createConfigCheckpoint.js +92 -0
  40. package/lib/docs/createDocsMcpServer.js +531 -0
  41. package/lib/docs/createDocsMcpServer.test.mjs +141 -0
  42. package/lib/docs/devMockRegistry.js +68 -0
  43. package/lib/docs/docs.test.mjs +448 -0
  44. package/lib/docs/enrichFeedback.js +71 -0
  45. package/lib/docs/evalOperator.js +47 -0
  46. package/lib/docs/evalOperator.test.mjs +157 -0
  47. package/lib/docs/evalOperatorHeadless.js +87 -0
  48. package/lib/docs/evalOperatorHeadless.test.mjs +72 -0
  49. package/lib/docs/evalOperatorInTab.js +48 -0
  50. package/lib/docs/findConfig.js +260 -0
  51. package/lib/docs/formatFeedback.js +121 -0
  52. package/lib/docs/formatFeedback.test.mjs +204 -0
  53. package/lib/docs/getAppMap.js +180 -0
  54. package/lib/docs/getBrowser.js +127 -0
  55. package/lib/docs/getBrowser.test.mjs +122 -0
  56. package/lib/docs/getBuildStatus.js +37 -0
  57. package/lib/docs/getCoreDoc.js +63 -0
  58. package/lib/docs/getDocsManifest.js +40 -0
  59. package/lib/docs/getExamples.js +58 -0
  60. package/lib/docs/getOverview.js +115 -0
  61. package/lib/docs/getPageConfig.js +53 -0
  62. package/lib/docs/getPluginDoc.js +55 -0
  63. package/lib/docs/getSchema.js +65 -0
  64. package/lib/docs/inspectState.js +47 -0
  65. package/lib/docs/inspectState.test.mjs +140 -0
  66. package/lib/docs/inspectStateFromTab.js +40 -0
  67. package/lib/docs/inspectStateHeadless.js +84 -0
  68. package/lib/docs/inspectStateHeadless.test.mjs +60 -0
  69. package/lib/docs/isWriteRequestsAllowed.js +50 -0
  70. package/lib/docs/listConfigCheckpoints.js +55 -0
  71. package/lib/docs/listPlugins.js +80 -0
  72. package/lib/docs/listTypes.js +105 -0
  73. package/lib/docs/loadState.js +152 -0
  74. package/lib/docs/mapPageBuildErrors.js +28 -0
  75. package/lib/docs/normalizeTypeKind.js +40 -0
  76. package/{pages/api/endpoints/[...endpointId].js → lib/docs/readBuildArtifact.js} +15 -12
  77. package/lib/docs/readPageArtifact.js +26 -0
  78. package/lib/docs/resolvePluginDir.js +49 -0
  79. package/lib/docs/resolveSource.js +48 -0
  80. package/lib/docs/resolveSource.test.mjs +100 -0
  81. package/lib/docs/revertConfigCheckpoint.js +73 -0
  82. package/lib/docs/runRequest.js +141 -0
  83. package/lib/docs/saveAnnotatedScreenshot.js +43 -0
  84. package/lib/docs/scaffoldPage.js +75 -0
  85. package/lib/docs/scaffoldPage.test.mjs +97 -0
  86. package/lib/docs/screenshotPage.js +110 -0
  87. package/lib/docs/screenshotPage.test.mjs +59 -0
  88. package/lib/docs/screenshotPageClip.test.mjs +102 -0
  89. package/lib/docs/searchDocs.js +67 -0
  90. package/lib/docs/setupTestFixtures.mjs +335 -0
  91. package/lib/docs/snapshotState.js +59 -0
  92. package/lib/docs/stateCheckpoints.test.mjs +366 -0
  93. package/lib/docs/tabAvailable.js +28 -0
  94. package/lib/docs/tabChannel.js +119 -0
  95. package/lib/docs/tabChannel.test.mjs +130 -0
  96. package/lib/server/auth/{getAuthOptions.js → getAuthConfig.js} +7 -4
  97. package/lib/server/auth/getDevSession.js +70 -0
  98. package/lib/server/auth/getDevSession.test.mjs +138 -0
  99. package/lib/server/auth/getHeadlessUser.js +40 -0
  100. package/lib/server/auth/{getMockSession.js → getMockUser.js} +8 -21
  101. package/lib/server/auth/headlessUser.js +29 -0
  102. package/lib/server/auth/resolveHeadlessUser.js +38 -0
  103. package/lib/server/auth/resolveHeadlessUser.test.mjs +78 -0
  104. package/lib/server/auth/session.js +39 -0
  105. package/lib/server/auth/strategies.js +47 -0
  106. package/lib/server/createLowdefyContext.js +122 -0
  107. package/lib/server/getPageJitEnrichment.test.mjs +105 -0
  108. package/lib/server/jitPageBuilder.js +125 -12
  109. package/lib/server/log/createHandleError.test.mjs +126 -0
  110. package/manager/getContext.mjs +3 -7
  111. package/manager/processes/initialBuild.mjs +0 -2
  112. package/manager/processes/installPlugins.mjs +19 -11
  113. package/manager/processes/lowdefyBuild.mjs +29 -7
  114. package/manager/processes/lowdefyBuild.test.mjs +102 -0
  115. package/manager/processes/readDotEnv.mjs +13 -1
  116. package/manager/processes/shutdownServer.mjs +6 -6
  117. package/manager/processes/startProxy.mjs +160 -0
  118. package/manager/processes/startProxy.test.mjs +102 -0
  119. package/manager/processes/startServer.mjs +33 -16
  120. package/manager/processes/startWatchers.mjs +2 -2
  121. package/manager/processes/warnAuthUrlPortMismatch.mjs +47 -0
  122. package/manager/processes/warnAuthUrlPortMismatch.test.mjs +93 -0
  123. package/manager/run.mjs +50 -0
  124. package/manager/utils/createCustomPluginMessagesMap.mjs +8 -1
  125. package/manager/utils/createCustomPluginTypesMap.mjs +1 -0
  126. package/manager/utils/formatNoticeBox.mjs +30 -0
  127. package/manager/utils/{getNextBin.mjs → getViteBin.mjs} +7 -10
  128. package/manager/utils/updatePageTailwindCss.mjs +7 -1
  129. package/manager/utils/writeBuildStatus.mjs +39 -0
  130. package/manager/utils/writeBuildStatus.test.mjs +76 -0
  131. package/manager/watchers/lowdefyBuildWatcher.mjs +0 -1
  132. package/manager/watchers/moduleBuildWatcher.mjs +0 -1
  133. package/manager/watchers/{nextBuildWatcher.mjs → serverArtifactWatcher.mjs} +18 -20
  134. package/package.json +61 -47
  135. package/package.original.json +64 -50
  136. package/postcss.config.cjs +1 -0
  137. package/src/app.js +175 -0
  138. package/src/html/renderDevPage.js +86 -0
  139. package/src/lib/getPathSegments.js +25 -0
  140. package/src/lib/safeScriptJson.js +38 -0
  141. package/src/middleware/apiContext.js +32 -0
  142. package/src/middleware/errorHandler.js +48 -0
  143. package/src/middleware/errorHandler.test.mjs +235 -0
  144. package/src/routes/agent.js +64 -0
  145. package/src/routes/apiPage.js +37 -0
  146. package/src/routes/auth.js +49 -0
  147. package/src/routes/auth.test.mjs +84 -0
  148. package/src/routes/clientError.js +57 -0
  149. package/src/routes/cron.js +47 -0
  150. package/src/routes/cronForward.js +47 -0
  151. package/src/routes/detached.js +47 -0
  152. package/src/routes/devInspect.js +111 -0
  153. package/src/routes/devInspect.test.mjs +119 -0
  154. package/{pages/[[...pageId]].js → src/routes/devTools.js} +4 -2
  155. package/{pages/404.js → src/routes/docs/appMap.js} +6 -2
  156. package/{pages/api/dev-tools.js → src/routes/docs/buildStatus.js} +5 -4
  157. package/src/routes/docs/checkpointsCreate.js +28 -0
  158. package/src/routes/docs/checkpointsList.js +23 -0
  159. package/{pages/api/icons/dynamic.js → src/routes/docs/checkpointsRevert.js} +11 -12
  160. package/src/routes/docs/content.js +31 -0
  161. package/src/routes/docs/evalOperator.js +56 -0
  162. package/src/routes/docs/examples.js +33 -0
  163. package/src/routes/docs/find.js +30 -0
  164. package/src/routes/docs/index.js +23 -0
  165. package/src/routes/docs/inspectState.js +44 -0
  166. package/src/routes/docs/loadState.js +49 -0
  167. package/src/routes/docs/mcp.js +30 -0
  168. package/src/routes/docs/pageConfig.js +36 -0
  169. package/src/routes/docs/parseUserParam.js +52 -0
  170. package/src/routes/docs/parseUserParam.test.mjs +45 -0
  171. package/src/routes/docs/pluginDoc.js +33 -0
  172. package/src/routes/docs/plugins.js +23 -0
  173. package/src/routes/docs/runRequest.js +36 -0
  174. package/{lib/server/auth/getServerSession.js → src/routes/docs/schema.js} +17 -15
  175. package/src/routes/docs/screenshot.js +72 -0
  176. package/src/routes/docs/search.js +27 -0
  177. package/src/routes/docs/snapshotState.js +36 -0
  178. package/src/routes/docs/stateCheckpointsList.js +26 -0
  179. package/src/routes/docs/types.js +33 -0
  180. package/src/routes/endpoints.js +71 -0
  181. package/src/routes/feedback.js +110 -0
  182. package/src/routes/feedback.test.mjs +204 -0
  183. package/src/routes/jitPage.js +86 -0
  184. package/src/routes/mcp.js +34 -0
  185. package/{pages/api → src/routes}/ping.js +4 -2
  186. package/src/routes/reload.js +79 -0
  187. package/src/routes/request.js +74 -0
  188. package/src/routes/request.test.mjs +124 -0
  189. package/{pages/api → src/routes}/root.js +4 -4
  190. package/src/routes/usage.js +46 -0
  191. package/src/routes/websocket.js +33 -0
  192. package/src/websocket/devWebSocket.js +78 -0
  193. package/vite.config.js +111 -0
  194. package/.eslintrc.yaml +0 -1
  195. package/lib/client/App.js +0 -80
  196. package/lib/client/Reload.js +0 -60
  197. package/lib/server/apiWrapper.js +0 -109
  198. package/lib/server/compileCss.js +0 -39
  199. package/manager/processes/compileCss.mjs +0 -54
  200. package/manager/processes/nextBuild.mjs +0 -50
  201. package/next.config.js +0 -25
  202. package/pages/_document.js +0 -109
  203. package/pages/api/agent/[...path].js +0 -86
  204. package/pages/api/auth/[...nextauth].js +0 -48
  205. package/pages/api/client-error.js +0 -45
  206. package/pages/api/js/[env].js +0 -42
  207. package/pages/api/page/[...pageId].js +0 -74
  208. package/pages/api/reload.js +0 -53
  209. package/pages/api/request/[...path].js +0 -41
  210. /package/lib/client/{BuildErrorPage.js → BuildErrorPage.jsx} +0 -0
  211. /package/lib/client/{BuildingPage.js → BuildingPage.jsx} +0 -0
  212. /package/lib/client/{ErrorBar.js → ErrorBar.jsx} +0 -0
  213. /package/lib/client/{InstallingPluginsPage.js → InstallingPluginsPage.jsx} +0 -0
  214. /package/lib/client/{RestartingPage.js → RestartingPage.jsx} +0 -0
@@ -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
+ */
16
+
17
+ import { setPendingWebSocketContext } from '../websocket/devWebSocket.js';
18
+
19
+ // In dev, Vite owns the HTTP server, so websocket upgrades can't flow through
20
+ // @hono/node-server. The Vite plugin (see vite.config.js) fetches this route
21
+ // with the upgrade request's headers to run the full middleware chain (auth
22
+ // session, apiContext), and this handler hands the built context back to the
23
+ // upgrade handler through a pending-context exchange keyed by request id.
24
+ function websocketHandler(c) {
25
+ const rid = c.req.header('x-lowdefy-websocket-rid');
26
+ if (!rid) {
27
+ return c.json({ message: 'WebSocket upgrade required.' }, 400);
28
+ }
29
+ setPendingWebSocketContext(rid, c.get('lowdefyContext'));
30
+ return c.json({ ok: true });
31
+ }
32
+
33
+ export default websocketHandler;
@@ -0,0 +1,78 @@
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 { randomUUID } from 'node:crypto';
18
+ import { createChannelRegistry, createWebSocketConnection } from '@lowdefy/api';
19
+
20
+ import app from '../app.js';
21
+
22
+ // One registry per dev server process, shared by all websocket connections.
23
+ const registry = createChannelRegistry();
24
+
25
+ // Contexts built by the /api/websocket route (full middleware chain) are
26
+ // handed to the upgrade handler through this exchange, keyed by request id.
27
+ const pendingContexts = new Map();
28
+
29
+ function setPendingWebSocketContext(rid, context) {
30
+ pendingContexts.set(rid, context);
31
+ }
32
+
33
+ function takePendingWebSocketContext(rid) {
34
+ const context = pendingContexts.get(rid);
35
+ pendingContexts.delete(rid);
36
+ return context;
37
+ }
38
+
39
+ // Called by the Vite plugin on an HTTP upgrade for /api/websocket. Runs the
40
+ // dev Hono app for the upgrade request (auth session + apiContext), then
41
+ // completes the websocket handshake and wires the connection to the registry.
42
+ async function handleWebSocketUpgrade({ request, socket, head, wss }) {
43
+ const rid = randomUUID();
44
+ const headers = new Headers();
45
+ Object.entries(request.headers).forEach(([key, value]) => {
46
+ if (value) {
47
+ headers.set(key, Array.isArray(value) ? value[0] : value);
48
+ }
49
+ });
50
+ headers.set('x-lowdefy-websocket-rid', rid);
51
+
52
+ const url = `http://${request.headers.host ?? 'localhost'}${request.url}`;
53
+ const response = await app.fetch(new Request(url, { headers }));
54
+ const context = takePendingWebSocketContext(rid);
55
+
56
+ if (!context || response.status !== 200) {
57
+ socket.end('HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n');
58
+ return;
59
+ }
60
+
61
+ wss.handleUpgrade(request, socket, head, (ws) => {
62
+ const connection = createWebSocketConnection(context, {
63
+ registry,
64
+ send: (message) => ws.send(message),
65
+ });
66
+ ws.on('message', (data) => {
67
+ connection.handleMessage(data.toString());
68
+ });
69
+ ws.on('close', () => {
70
+ connection.close();
71
+ });
72
+ ws.on('error', (error) => {
73
+ context.logger.debug({ event: 'ws_error' }, String(error?.message ?? error));
74
+ });
75
+ });
76
+ }
77
+
78
+ export { handleWebSocketUpgrade, setPendingWebSocketContext };
package/vite.config.js ADDED
@@ -0,0 +1,111 @@
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 'node:fs';
18
+ import { defineConfig } from 'vite';
19
+ import react from '@vitejs/plugin-react';
20
+ import devServer from '@hono/vite-dev-server';
21
+ import { WebSocketServer } from 'ws';
22
+
23
+ // basePath from the Lowdefy build — assets and routes are served under it.
24
+ let basePath = '';
25
+ try {
26
+ const config = JSON.parse(fs.readFileSync('./build/config.json', 'utf8'));
27
+ basePath = config.basePath ?? '';
28
+ } catch (e) {
29
+ // No build yet — default base.
30
+ }
31
+
32
+ // Vite owns the HTTP server in dev, so /api/websocket upgrades are handled
33
+ // here instead of @hono/node-server. The upgrade handler module is loaded
34
+ // through Vite's SSR graph so it shares the Hono app and @lowdefy/api module
35
+ // instances with the dev server routes. Vite's own HMR websocket uses a
36
+ // different path and is untouched.
37
+ function lowdefyWebSocket() {
38
+ return {
39
+ name: 'lowdefy-websocket',
40
+ configureServer(server) {
41
+ const wss = new WebSocketServer({ noServer: true, maxPayload: 256 * 1024 });
42
+ server.httpServer?.on('upgrade', async (request, socket, head) => {
43
+ const { pathname } = new URL(request.url ?? '/', 'http://localhost');
44
+ if (pathname !== `${basePath}/api/websocket`) {
45
+ return;
46
+ }
47
+ try {
48
+ const { handleWebSocketUpgrade } = await server.ssrLoadModule(
49
+ './src/websocket/devWebSocket.js'
50
+ );
51
+ await handleWebSocketUpgrade({ request, socket, head, wss });
52
+ } catch (error) {
53
+ console.error(error);
54
+ socket.destroy();
55
+ }
56
+ });
57
+ },
58
+ };
59
+ }
60
+
61
+ export default defineConfig(({ mode }) => ({
62
+ base: `${basePath}/`,
63
+ plugins: [
64
+ react(),
65
+ lowdefyWebSocket(),
66
+ devServer({
67
+ entry: './src/app.js',
68
+ // Vite serves these itself; everything else routes to the Hono app.
69
+ exclude: [
70
+ /^\/client\/.+/,
71
+ /^\/lib\/.+/,
72
+ /^\/build\/.+/,
73
+ /^\/@.+$/,
74
+ /^\/node_modules\/.*/,
75
+ /\?t=\d+$/,
76
+ /^\/favicon\.ico$/,
77
+ ],
78
+ }),
79
+ ],
80
+ define: {
81
+ // Vite does not replace process.env.NODE_ENV inside dependencies —
82
+ // plugin and client code branch on it.
83
+ 'process.env.NODE_ENV': JSON.stringify(mode === 'production' ? 'production' : 'development'),
84
+ },
85
+ optimizeDeps: {
86
+ // There is no index.html in the root (the Hono app renders HTML), so the
87
+ // dependency scanner has nothing to crawl and would discover client deps
88
+ // lazily at first request — ending in a mid-session "optimized
89
+ // dependencies changed" full reload. The client entry reaches every
90
+ // plugin import statically (main.jsx → App → Routing → build/plugins/*),
91
+ // so a startup crawl discovers the full set. Linked workspace plugins are
92
+ // intentionally not pre-bundled (Vite default) so local plugin edits stay
93
+ // live.
94
+ entries: ['client/main.jsx'],
95
+ },
96
+ resolve: {
97
+ // linked plugin packages (pnpm link: / workspace) must share one React.
98
+ dedupe: ['react', 'react-dom'],
99
+ },
100
+ server: {
101
+ watch: {
102
+ // Tailwind scan inputs are rewritten by JIT page builds, and Vite
103
+ // full-reloads the browser on any watched .html change — killing
104
+ // in-flight requests on every first page visit. CSS recompilation does
105
+ // not need these events: globals.css imports build/tailwind-candidates.css,
106
+ // which the JIT builder touches whenever tailwind content changes (the
107
+ // sole recompile trigger — see writeGlobalsCss in @lowdefy/build).
108
+ ignored: ['**/lowdefy-build/tailwind/**'],
109
+ },
110
+ },
111
+ }));
package/.eslintrc.yaml DELETED
@@ -1 +0,0 @@
1
- extends: 'plugin:@next/next/core-web-vitals'
package/lib/client/App.js DELETED
@@ -1,80 +0,0 @@
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 React, { Suspense } from 'react';
18
-
19
- import { useRouter } from 'next/router';
20
-
21
- import Head from 'next/head';
22
- import Link from 'next/link';
23
-
24
- import BuildingPage from './BuildingPage.js';
25
- import Reload from './Reload.js';
26
- import Page from './Page.js';
27
- import setPageId from './setPageId.js';
28
- import { getReloadVersion } from './utils/useMutateCache.js';
29
- import useRootConfig from './utils/useRootConfig.js';
30
-
31
- import actions from '../../build/plugins/actions.js';
32
- import blockMetas from '../../build/plugins/blockMetas.json';
33
- import blocks from '../../build/plugins/blocks.js';
34
- import icons from '../../build/plugins/icons.js';
35
- import operators from '../../build/plugins/operators/client.js';
36
- import staticJsMap from '../../build/plugins/operators/clientJsMap.js';
37
-
38
- const App = ({ auth, lowdefy }) => {
39
- const router = useRouter();
40
- const { data: rootConfig } = useRootConfig(router.basePath);
41
-
42
- if (rootConfig?.theme) {
43
- lowdefy.theme = rootConfig.theme;
44
- }
45
-
46
- const { redirect, pageId } = setPageId(router, rootConfig);
47
- if (redirect) {
48
- router.push(`/${pageId}`);
49
- return '';
50
- }
51
- return (
52
- <Reload basePath={router.basePath} lowdefy={lowdefy}>
53
- {(resetContext) => (
54
- <Suspense key={`${pageId}_${getReloadVersion()}`} fallback={<BuildingPage />}>
55
- <Page
56
- auth={auth}
57
- Components={{ Head, Link }}
58
- config={{
59
- rootConfig,
60
- }}
61
- jsMap={staticJsMap}
62
- lowdefy={lowdefy}
63
- pageId={pageId}
64
- resetContext={resetContext}
65
- router={router}
66
- types={{
67
- actions,
68
- blockMetas,
69
- blocks,
70
- icons,
71
- operators,
72
- }}
73
- />
74
- </Suspense>
75
- )}
76
- </Reload>
77
- );
78
- };
79
-
80
- export default App;
@@ -1,60 +0,0 @@
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 React, { useEffect, useState } from 'react';
18
-
19
- import useMutateCache from './utils/useMutateCache.js';
20
- import waitForRestartedServer from './utils/waitForRestartedServer.js';
21
-
22
- const Reload = ({ children, basePath, lowdefy }) => {
23
- const [reset, setReset] = useState(false);
24
- const [restarting, setRestarting] = useState(false);
25
- const mutateCache = useMutateCache(basePath);
26
- useEffect(() => {
27
- const sse = new EventSource(`${basePath}/api/reload`);
28
-
29
- sse.addEventListener('reload', () => {
30
- // add a update delay to prevent rerender before server is shut down for rebuild, ideally we don't want to do this.
31
- // TODO: We need to pass a flag when a rebuild will happen so that client does not trigger render.
32
- setTimeout(async () => {
33
- await mutateCache();
34
- if (lowdefy._internal?.initialised) {
35
- lowdefy._internal.initialised = false;
36
- }
37
- // Refresh JIT CSS link to pick up newly compiled Tailwind classes
38
- const cssLink = document.getElementById('tailwind-jit-css');
39
- if (cssLink) {
40
- cssLink.href = `${basePath}/tailwind-jit.css?v=${Date.now()}`;
41
- }
42
- setReset(true);
43
- console.log('Reloaded config.');
44
- }, 600);
45
- });
46
-
47
- sse.onerror = () => {
48
- setRestarting(true);
49
- console.log('Rebuilding Lowdefy App.');
50
- sse.close();
51
- waitForRestartedServer(basePath);
52
- };
53
- return () => {
54
- sse.close();
55
- };
56
- }, []);
57
- return <>{children({ reset, setReset, restarting })}</>;
58
- };
59
-
60
- export default Reload;
@@ -1,109 +0,0 @@
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
- import fs from 'fs';
17
- import path from 'path';
18
- import { createApiContext, redactErrorResponse } from '@lowdefy/api';
19
- import { getSecretsFromEnv } from '@lowdefy/node-utils';
20
- import { v4 as uuid } from 'uuid';
21
-
22
- import agents from '../../build/plugins/agents.js';
23
- import appMeta from '../build/appMeta.js';
24
- import config from '../build/config.js';
25
- import i18nConfig from '../build/i18n.js';
26
- import connections from '../../build/plugins/connections.js';
27
- import createLogger from './log/createLogger.js';
28
- import fileCache from './fileCache.js';
29
- import getServerSession from './auth/getServerSession.js';
30
- import createHandleError from './log/createHandleError.js';
31
- import logRequest from './log/logRequest.js';
32
- import operators from '../../build/plugins/operators/server.js';
33
- import staticJsMap from '../../build/plugins/operators/serverJsMap.js';
34
- import getAuthOptions from './auth/getAuthOptions.js';
35
-
36
- const secrets = getSecretsFromEnv();
37
-
38
- // Dynamic JS map loading for JIT-built pages
39
- let cachedJsMapMtime = null;
40
- let cachedJsMap = staticJsMap;
41
-
42
- function loadDynamicJsMap(buildDirectory) {
43
- const jsMapPath = path.join(buildDirectory, 'plugins', 'operators', 'serverJsMap.js');
44
- try {
45
- const stat = fs.statSync(jsMapPath);
46
- if (cachedJsMapMtime && stat.mtimeMs === cachedJsMapMtime) {
47
- return cachedJsMap;
48
- }
49
- cachedJsMapMtime = stat.mtimeMs;
50
- // For server-side, we can read and eval the JS file
51
- const content = fs.readFileSync(jsMapPath, 'utf8');
52
- const fn = new Function('exports', content.replace('export default', 'exports.default ='));
53
- const exports = {};
54
- fn(exports);
55
- cachedJsMap = { ...staticJsMap, ...(exports.default ?? {}) };
56
- return cachedJsMap;
57
- } catch {
58
- return cachedJsMap;
59
- }
60
- }
61
-
62
- function apiWrapper(handler) {
63
- return async function wrappedHandler(req, res) {
64
- const buildDirectory = path.join(process.cwd(), 'build');
65
- const jsMap = loadDynamicJsMap(buildDirectory);
66
-
67
- const context = {
68
- // Important to give absolute path so Next can trace build files
69
- rid: uuid(),
70
- agents,
71
- appMeta,
72
- buildDirectory,
73
- configDirectory: process.env.LOWDEFY_DIRECTORY_CONFIG || process.cwd(),
74
- config,
75
- connections,
76
- fileCache,
77
- headers: req?.headers,
78
- i18n: i18nConfig,
79
- jsMap,
80
- handleError: async (err) => {
81
- console.error(err);
82
- },
83
- logger: console,
84
- operators,
85
- req,
86
- res,
87
- secrets,
88
- };
89
- try {
90
- context.logger = createLogger();
91
- context.handleError = createHandleError({ context });
92
- context.authOptions = getAuthOptions(context);
93
- if (!req.url.startsWith('/api/auth')) {
94
- context.session = await getServerSession(context);
95
- }
96
- createApiContext(context);
97
- logRequest({ context });
98
- // Await here so that if handler throws it is caught.
99
- const response = await handler({ context, req, res });
100
- // TODO: Log response time?
101
- return response;
102
- } catch (error) {
103
- await context.handleError(error);
104
- res.status(500).json(redactErrorResponse(context, error));
105
- }
106
- };
107
- }
108
-
109
- export default apiWrapper;
@@ -1,39 +0,0 @@
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
- import postcss from 'postcss';
20
- import tailwindcssPlugin from '@tailwindcss/postcss';
21
-
22
- async function compileCss(buildDirectory) {
23
- const serverDirectory = path.resolve(buildDirectory, '..');
24
- const inputPath = path.join(buildDirectory, 'globals.css');
25
- const outputPath = path.join(serverDirectory, 'public/tailwind-jit.css');
26
- if (!fs.existsSync(inputPath)) return;
27
- const css = fs.readFileSync(inputPath, 'utf8');
28
- const result = await postcss([tailwindcssPlugin()]).process(css, {
29
- from: inputPath,
30
- to: outputPath,
31
- });
32
- // The Tailwind PostCSS plugin consumes the @layer order declaration from
33
- // globals.css during compilation. Re-inject it as the first line so the
34
- // browser establishes the correct cascade priority (antd > base/preflight).
35
- const layerOrder = '@layer theme, base, antd, components, utilities;\n';
36
- fs.writeFileSync(outputPath, layerOrder + result.css);
37
- }
38
-
39
- export default compileCss;
@@ -1,54 +0,0 @@
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
- import postcss from 'postcss';
20
- import tailwindcssPlugin from '@tailwindcss/postcss';
21
-
22
- function formatDuration(ms) {
23
- if (ms < 1000) return `${ms}ms`;
24
- return `${(ms / 1000).toFixed(2)}s`;
25
- }
26
-
27
- function compileCss({ directories, logger }) {
28
- return async () => {
29
- const inputPath = path.join(directories.build, 'globals.css');
30
- const outputPath = path.join(directories.server, 'public/tailwind-jit.css');
31
- if (!fs.existsSync(inputPath)) return;
32
-
33
- logger.info({ spin: 'start' }, 'Compiling CSS...');
34
- const startTime = Date.now();
35
-
36
- const css = fs.readFileSync(inputPath, 'utf8');
37
- const result = await postcss([tailwindcssPlugin()]).process(css, {
38
- from: inputPath,
39
- to: outputPath,
40
- });
41
- // The Tailwind PostCSS plugin consumes the @layer order declaration from
42
- // globals.css during compilation. Re-inject it as the first line so the
43
- // browser establishes the correct cascade priority (antd > base/preflight).
44
- const layerOrder = '@layer theme, base, antd, components, utilities;\n';
45
- fs.writeFileSync(outputPath, layerOrder + result.css);
46
-
47
- logger.info(
48
- { spin: 'succeed' },
49
- `Compiled CSS in ${formatDuration(Date.now() - startTime)}.`
50
- );
51
- };
52
- }
53
-
54
- export default compileCss;
@@ -1,50 +0,0 @@
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 { BuildError } from '@lowdefy/errors';
18
- import { spawnProcess } from '@lowdefy/node-utils';
19
-
20
- function formatDuration(ms) {
21
- if (ms < 1000) return `${ms}ms`;
22
- return `${(ms / 1000).toFixed(2)}s`;
23
- }
24
-
25
- function nextBuild({ bin, logger }) {
26
- return async () => {
27
- logger.info({ spin: 'start' }, 'Building app...');
28
- const startTime = Date.now();
29
- const errorLines = [];
30
- try {
31
- await spawnProcess({
32
- command: 'node',
33
- args: ['--max-old-space-size=4096', bin.next, 'build'],
34
- stdOutLineHandler: (line) => logger.debug(line),
35
- stdErrLineHandler: (line) => {
36
- logger.debug(line);
37
- errorLines.push(line);
38
- },
39
- });
40
- } catch (err) {
41
- if (errorLines.length > 0) {
42
- errorLines.forEach((line) => logger.error(line));
43
- }
44
- throw new BuildError('Next.js build failed. See above for details.');
45
- }
46
- logger.info({ spin: 'succeed' }, `Built app in ${formatDuration(Date.now() - startTime)}.`);
47
- };
48
- }
49
-
50
- export default nextBuild;
package/next.config.js DELETED
@@ -1,25 +0,0 @@
1
- const lowdefyConfig = require('./build/config.json');
2
- const blockPackages = require('./build/blockPackages.json');
3
- const serverExternalPackages = require('./build/serverExternalPackages.json');
4
-
5
- // Transpile @lowdefy/client plus all block plugin packages that may
6
- // contain CSS imports (e.g., AG Grid themes, loaders, markdown).
7
- // Built dynamically so custom user plugins are included automatically.
8
- const transpilePackages = [
9
- '@lowdefy/client',
10
- '@ant-design/x',
11
- '@ant-design/x-markdown',
12
- ...blockPackages,
13
- ];
14
-
15
- const nextConfig = {
16
- basePath: lowdefyConfig.basePath,
17
- // reactStrictMode: true,
18
- turbopack: {},
19
- transpilePackages,
20
- serverExternalPackages,
21
- compress: false,
22
- poweredByHeader: false,
23
- };
24
-
25
- module.exports = nextConfig;