@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.
- package/{pages/_app.js → client/App.jsx} +21 -33
- package/client/DevStreamContext.js +30 -0
- package/client/Inspector.jsx +226 -0
- package/{lib/client/Page.js → client/Page.jsx} +4 -8
- package/client/Reload.jsx +85 -0
- package/client/Routing.jsx +117 -0
- package/client/feedback/FeedbackMount.jsx +83 -0
- package/client/feedback/FeedbackOverlay.jsx +901 -0
- package/client/feedback/captureTabScreenshot.js +84 -0
- package/client/feedback/copyToClipboard.js +45 -0
- package/client/feedback/drawAnnotationsSvg.js +119 -0
- package/client/feedback/elementInspect.js +99 -0
- package/client/feedback/feedbackStyles.js +301 -0
- package/client/feedback/pinResponsiveImages.js +59 -0
- package/client/feedback/sendFeedback.js +39 -0
- package/client/feedback/useFeedbackToggle.js +70 -0
- package/client/main.jsx +42 -0
- package/client/openInEditor/OpenInEditorListener.jsx +268 -0
- package/client/openInEditor/findBlockLocation.js +51 -0
- package/lib/build/app.js +8 -1
- package/lib/build/appMeta.js +8 -1
- package/lib/build/auth.js +8 -1
- package/lib/build/config.js +8 -1
- package/lib/build/i18n.js +8 -1
- package/lib/build/logger.js +8 -1
- package/lib/build/theme.js +8 -1
- package/lib/client/auth/{Auth.js → Auth.jsx} +11 -2
- package/lib/client/auth/{AuthConfigured.js → AuthConfigured.jsx} +23 -10
- package/lib/client/setPageId.js +6 -5
- package/lib/client/utils/useMutateCache.js +14 -1
- package/lib/client/utils/usePageConfig.js +45 -43
- package/lib/client/utils/usePageConfig.test.mjs +62 -0
- package/lib/docs/captureAnnotatedScreenshot.js +88 -0
- package/lib/docs/checkpointPaths.js +91 -0
- package/lib/docs/checkpointStore.js +240 -0
- package/lib/docs/checkpointToMocks.js +65 -0
- package/lib/docs/clientErrorStore.js +36 -0
- package/lib/docs/configCheckpoints.test.mjs +156 -0
- package/lib/docs/createConfigCheckpoint.js +92 -0
- package/lib/docs/createDocsMcpServer.js +531 -0
- package/lib/docs/createDocsMcpServer.test.mjs +141 -0
- package/lib/docs/devMockRegistry.js +68 -0
- package/lib/docs/docs.test.mjs +448 -0
- package/lib/docs/enrichFeedback.js +71 -0
- package/lib/docs/evalOperator.js +47 -0
- package/lib/docs/evalOperator.test.mjs +157 -0
- package/lib/docs/evalOperatorHeadless.js +87 -0
- package/lib/docs/evalOperatorHeadless.test.mjs +72 -0
- package/lib/docs/evalOperatorInTab.js +48 -0
- package/lib/docs/findConfig.js +260 -0
- package/lib/docs/formatFeedback.js +121 -0
- package/lib/docs/formatFeedback.test.mjs +204 -0
- package/lib/docs/getAppMap.js +180 -0
- package/lib/docs/getBrowser.js +127 -0
- package/lib/docs/getBrowser.test.mjs +122 -0
- package/lib/docs/getBuildStatus.js +37 -0
- package/lib/docs/getCoreDoc.js +63 -0
- package/lib/docs/getDocsManifest.js +40 -0
- package/lib/docs/getExamples.js +58 -0
- package/lib/docs/getOverview.js +115 -0
- package/lib/docs/getPageConfig.js +53 -0
- package/lib/docs/getPluginDoc.js +55 -0
- package/lib/docs/getSchema.js +65 -0
- package/lib/docs/inspectState.js +47 -0
- package/lib/docs/inspectState.test.mjs +140 -0
- package/lib/docs/inspectStateFromTab.js +40 -0
- package/lib/docs/inspectStateHeadless.js +84 -0
- package/lib/docs/inspectStateHeadless.test.mjs +60 -0
- package/lib/docs/isWriteRequestsAllowed.js +50 -0
- package/lib/docs/listConfigCheckpoints.js +55 -0
- package/lib/docs/listPlugins.js +80 -0
- package/lib/docs/listTypes.js +105 -0
- package/lib/docs/loadState.js +152 -0
- package/lib/docs/mapPageBuildErrors.js +28 -0
- package/lib/docs/normalizeTypeKind.js +40 -0
- package/{pages/api/endpoints/[...endpointId].js → lib/docs/readBuildArtifact.js} +15 -12
- package/lib/docs/readPageArtifact.js +26 -0
- package/lib/docs/resolvePluginDir.js +49 -0
- package/lib/docs/resolveSource.js +48 -0
- package/lib/docs/resolveSource.test.mjs +100 -0
- package/lib/docs/revertConfigCheckpoint.js +73 -0
- package/lib/docs/runRequest.js +141 -0
- package/lib/docs/saveAnnotatedScreenshot.js +43 -0
- package/lib/docs/scaffoldPage.js +75 -0
- package/lib/docs/scaffoldPage.test.mjs +97 -0
- package/lib/docs/screenshotPage.js +110 -0
- package/lib/docs/screenshotPage.test.mjs +59 -0
- package/lib/docs/screenshotPageClip.test.mjs +102 -0
- package/lib/docs/searchDocs.js +67 -0
- package/lib/docs/setupTestFixtures.mjs +335 -0
- package/lib/docs/snapshotState.js +59 -0
- package/lib/docs/stateCheckpoints.test.mjs +366 -0
- package/lib/docs/tabAvailable.js +28 -0
- package/lib/docs/tabChannel.js +119 -0
- package/lib/docs/tabChannel.test.mjs +130 -0
- package/lib/server/auth/{getAuthOptions.js → getAuthConfig.js} +7 -4
- package/lib/server/auth/getDevSession.js +70 -0
- package/lib/server/auth/getDevSession.test.mjs +138 -0
- package/lib/server/auth/getHeadlessUser.js +40 -0
- package/lib/server/auth/{getMockSession.js → getMockUser.js} +8 -21
- package/lib/server/auth/headlessUser.js +29 -0
- package/lib/server/auth/resolveHeadlessUser.js +38 -0
- package/lib/server/auth/resolveHeadlessUser.test.mjs +78 -0
- package/lib/server/auth/session.js +39 -0
- package/lib/server/auth/strategies.js +47 -0
- package/lib/server/createLowdefyContext.js +122 -0
- package/lib/server/getPageJitEnrichment.test.mjs +105 -0
- package/lib/server/jitPageBuilder.js +125 -12
- package/lib/server/log/createHandleError.test.mjs +126 -0
- package/manager/getContext.mjs +3 -7
- package/manager/processes/initialBuild.mjs +0 -2
- package/manager/processes/installPlugins.mjs +19 -11
- package/manager/processes/lowdefyBuild.mjs +29 -7
- package/manager/processes/lowdefyBuild.test.mjs +102 -0
- package/manager/processes/readDotEnv.mjs +13 -1
- package/manager/processes/shutdownServer.mjs +6 -6
- package/manager/processes/startProxy.mjs +160 -0
- package/manager/processes/startProxy.test.mjs +102 -0
- package/manager/processes/startServer.mjs +33 -16
- package/manager/processes/startWatchers.mjs +2 -2
- package/manager/processes/warnAuthUrlPortMismatch.mjs +47 -0
- package/manager/processes/warnAuthUrlPortMismatch.test.mjs +93 -0
- package/manager/run.mjs +50 -0
- package/manager/utils/createCustomPluginMessagesMap.mjs +8 -1
- package/manager/utils/createCustomPluginTypesMap.mjs +1 -0
- package/manager/utils/formatNoticeBox.mjs +30 -0
- package/manager/utils/{getNextBin.mjs → getViteBin.mjs} +7 -10
- package/manager/utils/updatePageTailwindCss.mjs +7 -1
- package/manager/utils/writeBuildStatus.mjs +39 -0
- package/manager/utils/writeBuildStatus.test.mjs +76 -0
- package/manager/watchers/lowdefyBuildWatcher.mjs +0 -1
- package/manager/watchers/moduleBuildWatcher.mjs +0 -1
- package/manager/watchers/{nextBuildWatcher.mjs → serverArtifactWatcher.mjs} +18 -20
- package/package.json +61 -47
- package/package.original.json +64 -50
- package/postcss.config.cjs +1 -0
- package/src/app.js +175 -0
- package/src/html/renderDevPage.js +86 -0
- package/src/lib/getPathSegments.js +25 -0
- package/src/lib/safeScriptJson.js +38 -0
- package/src/middleware/apiContext.js +32 -0
- package/src/middleware/errorHandler.js +48 -0
- package/src/middleware/errorHandler.test.mjs +235 -0
- package/src/routes/agent.js +64 -0
- package/src/routes/apiPage.js +37 -0
- package/src/routes/auth.js +49 -0
- package/src/routes/auth.test.mjs +84 -0
- package/src/routes/clientError.js +57 -0
- package/src/routes/cron.js +47 -0
- package/src/routes/cronForward.js +47 -0
- package/src/routes/detached.js +47 -0
- package/src/routes/devInspect.js +111 -0
- package/src/routes/devInspect.test.mjs +119 -0
- package/{pages/[[...pageId]].js → src/routes/devTools.js} +4 -2
- package/{pages/404.js → src/routes/docs/appMap.js} +6 -2
- package/{pages/api/dev-tools.js → src/routes/docs/buildStatus.js} +5 -4
- package/src/routes/docs/checkpointsCreate.js +28 -0
- package/src/routes/docs/checkpointsList.js +23 -0
- package/{pages/api/icons/dynamic.js → src/routes/docs/checkpointsRevert.js} +11 -12
- package/src/routes/docs/content.js +31 -0
- package/src/routes/docs/evalOperator.js +56 -0
- package/src/routes/docs/examples.js +33 -0
- package/src/routes/docs/find.js +30 -0
- package/src/routes/docs/index.js +23 -0
- package/src/routes/docs/inspectState.js +44 -0
- package/src/routes/docs/loadState.js +49 -0
- package/src/routes/docs/mcp.js +30 -0
- package/src/routes/docs/pageConfig.js +36 -0
- package/src/routes/docs/parseUserParam.js +52 -0
- package/src/routes/docs/parseUserParam.test.mjs +45 -0
- package/src/routes/docs/pluginDoc.js +33 -0
- package/src/routes/docs/plugins.js +23 -0
- package/src/routes/docs/runRequest.js +36 -0
- package/{lib/server/auth/getServerSession.js → src/routes/docs/schema.js} +17 -15
- package/src/routes/docs/screenshot.js +72 -0
- package/src/routes/docs/search.js +27 -0
- package/src/routes/docs/snapshotState.js +36 -0
- package/src/routes/docs/stateCheckpointsList.js +26 -0
- package/src/routes/docs/types.js +33 -0
- package/src/routes/endpoints.js +71 -0
- package/src/routes/feedback.js +110 -0
- package/src/routes/feedback.test.mjs +204 -0
- package/src/routes/jitPage.js +86 -0
- package/src/routes/mcp.js +34 -0
- package/{pages/api → src/routes}/ping.js +4 -2
- package/src/routes/reload.js +79 -0
- package/src/routes/request.js +74 -0
- package/src/routes/request.test.mjs +124 -0
- package/{pages/api → src/routes}/root.js +4 -4
- package/src/routes/usage.js +46 -0
- package/src/routes/websocket.js +33 -0
- package/src/websocket/devWebSocket.js +78 -0
- package/vite.config.js +111 -0
- package/.eslintrc.yaml +0 -1
- package/lib/client/App.js +0 -80
- package/lib/client/Reload.js +0 -60
- package/lib/server/apiWrapper.js +0 -109
- package/lib/server/compileCss.js +0 -39
- package/manager/processes/compileCss.mjs +0 -54
- package/manager/processes/nextBuild.mjs +0 -50
- package/next.config.js +0 -25
- package/pages/_document.js +0 -109
- package/pages/api/agent/[...path].js +0 -86
- package/pages/api/auth/[...nextauth].js +0 -48
- package/pages/api/client-error.js +0 -45
- package/pages/api/js/[env].js +0 -42
- package/pages/api/page/[...pageId].js +0 -74
- package/pages/api/reload.js +0 -53
- package/pages/api/request/[...path].js +0 -41
- /package/lib/client/{BuildErrorPage.js → BuildErrorPage.jsx} +0 -0
- /package/lib/client/{BuildingPage.js → BuildingPage.jsx} +0 -0
- /package/lib/client/{ErrorBar.js → ErrorBar.jsx} +0 -0
- /package/lib/client/{InstallingPluginsPage.js → InstallingPluginsPage.jsx} +0 -0
- /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;
|
package/lib/client/Reload.js
DELETED
|
@@ -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;
|
package/lib/server/apiWrapper.js
DELETED
|
@@ -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;
|
package/lib/server/compileCss.js
DELETED
|
@@ -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;
|