@lowdefy/server-dev 0.0.0-experimental-20260720072521 → 0.0.0-experimental-20260720135014

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 (196) hide show
  1. package/.eslintrc.yaml +1 -0
  2. package/lib/build/app.js +1 -8
  3. package/lib/build/appMeta.js +1 -8
  4. package/lib/build/auth.js +1 -8
  5. package/lib/build/config.js +1 -8
  6. package/lib/build/i18n.js +1 -8
  7. package/lib/build/logger.js +1 -8
  8. package/lib/build/theme.js +1 -8
  9. package/lib/client/App.js +80 -0
  10. package/{client/Page.jsx → lib/client/Page.js} +5 -5
  11. package/{client/Reload.jsx → lib/client/Reload.js} +7 -5
  12. package/lib/client/auth/{Auth.jsx → Auth.js} +5 -12
  13. package/lib/client/auth/AuthConfigured.js +61 -0
  14. package/lib/client/auth/AuthNotConfigured.js +2 -22
  15. package/lib/client/setPageId.js +5 -6
  16. package/lib/client/utils/useMutateCache.js +1 -14
  17. package/lib/client/utils/usePageConfig.js +11 -31
  18. package/lib/server/apiWrapper.js +116 -0
  19. package/lib/server/auth/{getStrategies.js → getAuthOptions.js} +9 -14
  20. package/lib/server/auth/{getMockUser.js → getMockSession.js} +19 -10
  21. package/{src/routes/docs/checkpointsRevert.js → lib/server/auth/getServerSession.js} +13 -11
  22. package/lib/server/compileCss.js +39 -0
  23. package/lib/server/jitPageBuilder.js +11 -36
  24. package/lib/server/log/logRequest.js +3 -1
  25. package/manager/getContext.mjs +7 -3
  26. package/manager/processes/compileCss.mjs +54 -0
  27. package/manager/processes/initialBuild.mjs +2 -0
  28. package/manager/processes/installPlugins.mjs +11 -19
  29. package/manager/processes/lowdefyBuild.mjs +7 -29
  30. package/manager/processes/nextBuild.mjs +50 -0
  31. package/manager/processes/readDotEnv.mjs +1 -13
  32. package/manager/processes/shutdownServer.mjs +6 -6
  33. package/manager/processes/startServer.mjs +7 -8
  34. package/manager/processes/startWatchers.mjs +2 -2
  35. package/manager/run.mjs +0 -41
  36. package/manager/utils/createCustomPluginMessagesMap.mjs +1 -8
  37. package/manager/utils/createCustomPluginTypesMap.mjs +2 -3
  38. package/manager/utils/{getViteBin.mjs → getNextBin.mjs} +10 -7
  39. package/manager/utils/updatePageTailwindCss.mjs +1 -7
  40. package/manager/watchers/lowdefyBuildWatcher.mjs +1 -0
  41. package/manager/watchers/moduleBuildWatcher.mjs +1 -0
  42. package/manager/watchers/{serverArtifactWatcher.mjs → nextBuildWatcher.mjs} +22 -18
  43. package/next.config.js +25 -0
  44. package/package.json +47 -63
  45. package/package.original.json +55 -66
  46. package/{src/routes/devTools.js → pages/404.js} +2 -4
  47. package/{src/routes/docs/appMap.js → pages/[[...pageId]].js} +2 -6
  48. package/{client/App.jsx → pages/_app.js} +33 -21
  49. package/pages/_document.js +107 -0
  50. package/pages/api/agent/[...path].js +86 -0
  51. package/pages/api/auth/[...nextauth].js +48 -0
  52. package/pages/api/client-error.js +45 -0
  53. package/{src/routes/docs/buildStatus.js → pages/api/dev-tools.js} +4 -5
  54. package/{lib/docs/clientErrorStore.js → pages/api/endpoints/[...endpointId].js} +11 -15
  55. package/{src/lib/serveBuildJs.js → pages/api/icons/dynamic.js} +12 -8
  56. package/{src/routes/jsEnv.js → pages/api/js/[env].js} +20 -8
  57. package/pages/api/page/[...pageId].js +74 -0
  58. package/{src/routes → pages/api}/ping.js +2 -4
  59. package/pages/api/reload.js +53 -0
  60. package/pages/api/request/[...path].js +41 -0
  61. package/{src/routes → pages/api}/root.js +4 -4
  62. package/client/Inspector.jsx +0 -206
  63. package/client/Routing.jsx +0 -106
  64. package/client/feedback/FeedbackMount.jsx +0 -83
  65. package/client/feedback/FeedbackOverlay.jsx +0 -901
  66. package/client/feedback/captureTabScreenshot.js +0 -84
  67. package/client/feedback/copyToClipboard.js +0 -45
  68. package/client/feedback/drawAnnotationsSvg.js +0 -119
  69. package/client/feedback/elementInspect.js +0 -99
  70. package/client/feedback/feedbackStyles.js +0 -301
  71. package/client/feedback/pinResponsiveImages.js +0 -59
  72. package/client/feedback/sendFeedback.js +0 -39
  73. package/client/feedback/useFeedbackToggle.js +0 -70
  74. package/client/main.jsx +0 -42
  75. package/client/openInEditor/OpenInEditorListener.jsx +0 -261
  76. package/client/openInEditor/findBlockLocation.js +0 -51
  77. package/lib/client/auth/AuthConfigured.jsx +0 -155
  78. package/lib/docs/captureAnnotatedScreenshot.js +0 -88
  79. package/lib/docs/checkpointPaths.js +0 -91
  80. package/lib/docs/checkpointStore.js +0 -234
  81. package/lib/docs/checkpointToMocks.js +0 -65
  82. package/lib/docs/configCheckpoints.test.mjs +0 -156
  83. package/lib/docs/createConfigCheckpoint.js +0 -92
  84. package/lib/docs/createDocsMcpServer.js +0 -506
  85. package/lib/docs/createDocsMcpServer.test.mjs +0 -123
  86. package/lib/docs/devMockRegistry.js +0 -68
  87. package/lib/docs/docs.test.mjs +0 -448
  88. package/lib/docs/enrichFeedback.js +0 -71
  89. package/lib/docs/evalOperator.js +0 -39
  90. package/lib/docs/evalOperator.test.mjs +0 -112
  91. package/lib/docs/evalOperatorHeadless.js +0 -87
  92. package/lib/docs/evalOperatorHeadless.test.mjs +0 -72
  93. package/lib/docs/evalOperatorInTab.js +0 -48
  94. package/lib/docs/findConfig.js +0 -260
  95. package/lib/docs/formatFeedback.js +0 -121
  96. package/lib/docs/formatFeedback.test.mjs +0 -204
  97. package/lib/docs/getAppMap.js +0 -180
  98. package/lib/docs/getBrowser.js +0 -115
  99. package/lib/docs/getBuildStatus.js +0 -37
  100. package/lib/docs/getCoreDoc.js +0 -63
  101. package/lib/docs/getDocsManifest.js +0 -40
  102. package/lib/docs/getExamples.js +0 -58
  103. package/lib/docs/getOverview.js +0 -115
  104. package/lib/docs/getPageConfig.js +0 -53
  105. package/lib/docs/getPluginDoc.js +0 -55
  106. package/lib/docs/getSchema.js +0 -65
  107. package/lib/docs/inspectState.js +0 -41
  108. package/lib/docs/inspectState.test.mjs +0 -91
  109. package/lib/docs/inspectStateFromTab.js +0 -40
  110. package/lib/docs/inspectStateHeadless.js +0 -84
  111. package/lib/docs/inspectStateHeadless.test.mjs +0 -60
  112. package/lib/docs/isWriteRequestsAllowed.js +0 -50
  113. package/lib/docs/listConfigCheckpoints.js +0 -55
  114. package/lib/docs/listPlugins.js +0 -80
  115. package/lib/docs/listTypes.js +0 -105
  116. package/lib/docs/loadState.js +0 -139
  117. package/lib/docs/mapPageBuildErrors.js +0 -28
  118. package/lib/docs/normalizeTypeKind.js +0 -40
  119. package/lib/docs/readBuildArtifact.js +0 -35
  120. package/lib/docs/readPageArtifact.js +0 -26
  121. package/lib/docs/resolvePluginDir.js +0 -49
  122. package/lib/docs/revertConfigCheckpoint.js +0 -73
  123. package/lib/docs/runRequest.js +0 -141
  124. package/lib/docs/saveAnnotatedScreenshot.js +0 -43
  125. package/lib/docs/scaffoldPage.js +0 -75
  126. package/lib/docs/scaffoldPage.test.mjs +0 -97
  127. package/lib/docs/screenshotPage.js +0 -109
  128. package/lib/docs/screenshotPage.test.mjs +0 -59
  129. package/lib/docs/screenshotPageClip.test.mjs +0 -102
  130. package/lib/docs/searchDocs.js +0 -67
  131. package/lib/docs/setupTestFixtures.mjs +0 -335
  132. package/lib/docs/snapshotState.js +0 -59
  133. package/lib/docs/stateCheckpoints.test.mjs +0 -348
  134. package/lib/docs/tabAvailable.js +0 -28
  135. package/lib/docs/tabChannel.js +0 -119
  136. package/lib/docs/tabChannel.test.mjs +0 -130
  137. package/lib/server/auth/createSystemContext.js +0 -70
  138. package/lib/server/auth/getAuth.js +0 -46
  139. package/lib/server/auth/getHeadlessUser.js +0 -39
  140. package/lib/server/auth/headlessUser.js +0 -30
  141. package/lib/server/createLowdefyContext.js +0 -133
  142. package/lib/server/loadDynamicJsMap.js +0 -47
  143. package/manager/processes/lowdefyBuild.test.mjs +0 -102
  144. package/manager/utils/formatNoticeBox.mjs +0 -30
  145. package/manager/utils/writeBuildStatus.mjs +0 -39
  146. package/manager/utils/writeBuildStatus.test.mjs +0 -76
  147. package/postcss.config.cjs +0 -1
  148. package/src/app.js +0 -188
  149. package/src/html/renderDevPage.js +0 -86
  150. package/src/lib/getPathSegments.js +0 -25
  151. package/src/lib/safeScriptJson.js +0 -38
  152. package/src/middleware/apiContext.js +0 -32
  153. package/src/middleware/errorHandler.js +0 -55
  154. package/src/routes/agent.js +0 -64
  155. package/src/routes/auth.js +0 -43
  156. package/src/routes/clientError.js +0 -57
  157. package/src/routes/cron.js +0 -44
  158. package/src/routes/detached.js +0 -51
  159. package/src/routes/devInspect.js +0 -94
  160. package/src/routes/docs/checkpointsCreate.js +0 -28
  161. package/src/routes/docs/checkpointsList.js +0 -23
  162. package/src/routes/docs/content.js +0 -31
  163. package/src/routes/docs/evalOperator.js +0 -46
  164. package/src/routes/docs/examples.js +0 -33
  165. package/src/routes/docs/find.js +0 -30
  166. package/src/routes/docs/index.js +0 -23
  167. package/src/routes/docs/inspectState.js +0 -34
  168. package/src/routes/docs/loadState.js +0 -38
  169. package/src/routes/docs/mcp.js +0 -30
  170. package/src/routes/docs/pageConfig.js +0 -36
  171. package/src/routes/docs/pluginDoc.js +0 -33
  172. package/src/routes/docs/plugins.js +0 -23
  173. package/src/routes/docs/runRequest.js +0 -34
  174. package/src/routes/docs/schema.js +0 -37
  175. package/src/routes/docs/screenshot.js +0 -66
  176. package/src/routes/docs/search.js +0 -27
  177. package/src/routes/docs/snapshotState.js +0 -36
  178. package/src/routes/docs/stateCheckpointsList.js +0 -26
  179. package/src/routes/docs/types.js +0 -33
  180. package/src/routes/endpoints.js +0 -76
  181. package/src/routes/feedback.js +0 -110
  182. package/src/routes/feedback.test.mjs +0 -204
  183. package/src/routes/iconsDynamic.js +0 -25
  184. package/src/routes/jitPage.js +0 -99
  185. package/src/routes/reload.js +0 -81
  186. package/src/routes/request.js +0 -66
  187. package/src/routes/usage.js +0 -46
  188. package/src/routes/user.js +0 -27
  189. package/src/routes/websocket.js +0 -33
  190. package/src/websocket/devWebSocket.js +0 -78
  191. package/vite.config.js +0 -111
  192. /package/lib/client/{BuildErrorPage.jsx → BuildErrorPage.js} +0 -0
  193. /package/lib/client/{BuildingPage.jsx → BuildingPage.js} +0 -0
  194. /package/lib/client/{ErrorBar.jsx → ErrorBar.js} +0 -0
  195. /package/lib/client/{InstallingPluginsPage.jsx → InstallingPluginsPage.js} +0 -0
  196. /package/lib/client/{RestartingPage.jsx → RestartingPage.js} +0 -0
package/src/app.js DELETED
@@ -1,188 +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 { Hono } from 'hono';
18
- import { bodyLimit } from 'hono/body-limit';
19
- import { serveStatic } from '@hono/node-server/serve-static';
20
-
21
- import agentHandler from './routes/agent.js';
22
- import apiContext from './middleware/apiContext.js';
23
- import authJson from '../lib/build/auth.js';
24
- import authMiddleware from './routes/auth.js';
25
- import clientErrorHandler from './routes/clientError.js';
26
- import createErrorHandler from './middleware/errorHandler.js';
27
- import createLogger from '../lib/server/log/createLogger.js';
28
- import cronHandler from './routes/cron.js';
29
- import detachedHandler from './routes/detached.js';
30
- import devInspectHandler from './routes/devInspect.js';
31
- import devToolsHandler from './routes/devTools.js';
32
- import feedbackHandler from './routes/feedback.js';
33
- import docsAppMapHandler from './routes/docs/appMap.js';
34
- import docsBuildStatusHandler from './routes/docs/buildStatus.js';
35
- import docsCheckpointsCreateHandler from './routes/docs/checkpointsCreate.js';
36
- import docsCheckpointsListHandler from './routes/docs/checkpointsList.js';
37
- import docsCheckpointsRevertHandler from './routes/docs/checkpointsRevert.js';
38
- import docsContentHandler from './routes/docs/content.js';
39
- import docsEvalOperatorHandler from './routes/docs/evalOperator.js';
40
- import docsExamplesHandler from './routes/docs/examples.js';
41
- import docsFindHandler from './routes/docs/find.js';
42
- import docsIndexHandler from './routes/docs/index.js';
43
- import docsInspectStateHandler from './routes/docs/inspectState.js';
44
- import docsLoadStateHandler from './routes/docs/loadState.js';
45
- import docsMcpHandler from './routes/docs/mcp.js';
46
- import docsPageConfigHandler from './routes/docs/pageConfig.js';
47
- import docsRunRequestHandler from './routes/docs/runRequest.js';
48
- import docsSnapshotStateHandler from './routes/docs/snapshotState.js';
49
- import docsStateCheckpointsListHandler from './routes/docs/stateCheckpointsList.js';
50
- import docsPluginDocHandler from './routes/docs/pluginDoc.js';
51
- import docsPluginsHandler from './routes/docs/plugins.js';
52
- import docsSchemaHandler from './routes/docs/schema.js';
53
- import docsScreenshotHandler from './routes/docs/screenshot.js';
54
- import docsSearchHandler from './routes/docs/search.js';
55
- import docsTypesHandler from './routes/docs/types.js';
56
- import endpointsHandler from './routes/endpoints.js';
57
- import getAuth from '../lib/server/auth/getAuth.js';
58
- import getStrategies from '../lib/server/auth/getStrategies.js';
59
- import getMockUser from '../lib/server/auth/getMockUser.js';
60
- import iconsDynamicHandler from './routes/iconsDynamic.js';
61
- import jitPageHandler from './routes/jitPage.js';
62
- import jsEnvHandler from './routes/jsEnv.js';
63
- import lowdefyConfig from '../lib/build/config.js';
64
- import pingHandler from './routes/ping.js';
65
- import reloadHandler from './routes/reload.js';
66
- import renderDevPage from './html/renderDevPage.js';
67
- import requestHandler from './routes/request.js';
68
- import rootHandler from './routes/root.js';
69
- import usageHandler from './routes/usage.js';
70
- import userHandler from './routes/user.js';
71
- import websocketHandler from './routes/websocket.js';
72
-
73
- const basePath = lowdefyConfig.basePath ?? '';
74
-
75
- // Dev Hono app — mounted into Vite via @hono/vite-dev-server (Vite owns HTTP
76
- // and serves /client/* modules with HMR; everything else lands here).
77
- // No compression in dev (parity with the old next.config compress: false,
78
- // and SSE must stay unbuffered).
79
- function createApp() {
80
- const app = basePath ? new Hono().basePath(basePath) : new Hono();
81
- const logger = createLogger({ server: 'lowdefy-dev' });
82
-
83
- // No api context: SSE/health/static-js routes had no apiWrapper before.
84
- app.get('/api/reload', reloadHandler);
85
- app.get('/api/ping', pingHandler);
86
- app.get('/api/js/:env', jsEnvHandler);
87
- app.get('/api/icons/dynamic', iconsDynamicHandler);
88
- app.get('/api/dev-tools', devToolsHandler);
89
- // Annotation helper: the in-page overlay (Cmd/Ctrl+/) POSTs annotation
90
- // batches here and gets back the enriched agent-readable text, which the
91
- // overlay copies to the clipboard. No api context needed.
92
- // /lowdefy-feedback is a reserved page-path prefix in dev, like /lowdefy-docs.
93
- app.post('/lowdefy-feedback', feedbackHandler);
94
-
95
- const mockUser = getMockUser();
96
- if (authJson.configured === true && !mockUser) {
97
- // Construct the BetterAuth instance and strategy verifiers at startup so
98
- // config errors fail boot instead of the first request, and so the
99
- // process-memoized singletons capture the base logger rather than the
100
- // first request's rid-scoped child.
101
- getAuth({ logger });
102
- getStrategies({ logger });
103
- }
104
-
105
- // Docs and MCP endpoint for AI coding agents — always on in dev. Serves
106
- // schemas/examples/docs for every installed plugin (core and local) plus
107
- // the extracted core docs (@lowdefy/docs-content). Mounted outside /api/*
108
- // so it can't clash with user API endpoints; /lowdefy-docs is a reserved page
109
- // prefix in dev. The handlers need no auth protection or api context —
110
- // they read build artifacts and node_modules directly — but run-request
111
- // and eval-operator build a full Lowdefy context (createLowdefyContext),
112
- // which resolves the caller from the request headers via resolveAuthentication.
113
- app.all('/lowdefy-docs/mcp', docsMcpHandler);
114
- app.get('/lowdefy-docs', docsIndexHandler);
115
- app.get('/lowdefy-docs/build-status', docsBuildStatusHandler);
116
- app.get('/lowdefy-docs/page-config/:pageId', docsPageConfigHandler);
117
- app.get('/lowdefy-docs/find/:id', docsFindHandler);
118
- app.get('/lowdefy-docs/screenshot/:pageId', docsScreenshotHandler);
119
- app.get('/lowdefy-docs/inspect-state/:pageId', docsInspectStateHandler);
120
- app.post('/lowdefy-docs/eval-operator', docsEvalOperatorHandler);
121
- app.post('/lowdefy-docs/run-request', docsRunRequestHandler);
122
- app.get('/lowdefy-docs/app-map', docsAppMapHandler);
123
- app.get('/lowdefy-docs/checkpoints', docsCheckpointsListHandler);
124
- app.post('/lowdefy-docs/checkpoints', docsCheckpointsCreateHandler);
125
- app.post('/lowdefy-docs/checkpoints/revert', docsCheckpointsRevertHandler);
126
- app.get('/lowdefy-docs/state-checkpoints', docsStateCheckpointsListHandler);
127
- app.post('/lowdefy-docs/state-checkpoints/snapshot', docsSnapshotStateHandler);
128
- app.post('/lowdefy-docs/state-checkpoints/load', docsLoadStateHandler);
129
- // Live-tab inspection channel: dev tabs (client/Inspector.jsx) answer
130
- // targeted SSE events by posting results here; GET lists connected tabs
131
- // and serves checkpoint parts for the ?_checkpoint bootstrap.
132
- app.all('/api/dev-inspect', devInspectHandler);
133
- app.all('/api/dev-inspect/*', devInspectHandler);
134
- app.get('/lowdefy-docs/plugins', docsPluginsHandler);
135
- app.get('/lowdefy-docs/schema/:kind/:type', docsSchemaHandler);
136
- app.get('/lowdefy-docs/examples/:type', docsExamplesHandler);
137
- app.get('/lowdefy-docs/search', docsSearchHandler);
138
- app.get('/lowdefy-docs/plugin-doc/:package{.+}', docsPluginDocHandler);
139
- app.get('/lowdefy-docs/content/:slug{.+}', docsContentHandler);
140
- app.get('/lowdefy-docs/:kind', docsTypesHandler);
141
-
142
- app.use('/api/*', apiContext());
143
- // Unified dev get-session: createLowdefyContext resolves the mock or headless
144
- // caller into context.user on every path, so read it here rather than
145
- // re-deriving the precedence. context.user is only absent in the real-engine
146
- // case (the developer's own browser), which must fall through to BetterAuth.
147
- // Registered before the /api/auth/* mount so this exact path wins while every
148
- // other auth route still reaches the engine.
149
- app.get('/api/auth/get-session', async (c, next) => {
150
- const context = c.get('lowdefyContext');
151
- if (context.user) return c.json({ session: { id: 'dev' }, user: context.user });
152
- return next();
153
- });
154
- app.use('/api/auth/*', authMiddleware({ logger }));
155
- app.get('/api/root', rootHandler);
156
- app.get('/api/page/*', jitPageHandler);
157
- app.all('/api/request/*', requestHandler);
158
- // Endpoint payloads may carry base64 file content (emitFileContent + CallAPI);
159
- // cap bodies at 10 MiB to match the agent route.
160
- app.all('/api/endpoints/*', bodyLimit({ maxSize: 10 * 1024 * 1024 }), endpointsHandler);
161
- app.get('/api/cron/*', cronHandler);
162
- app.post('/api/detached/*', detachedHandler);
163
- app.all('/api/client-error', clientErrorHandler);
164
- app.all('/api/usage', usageHandler);
165
- app.all('/api/agent/*', bodyLimit({ maxSize: 10 * 1024 * 1024 }), agentHandler);
166
- app.get('/api/websocket', websocketHandler);
167
- app.get('/api/user', userHandler);
168
-
169
- // User public assets (icons, images). Vite serves /client modules itself.
170
- app.use(
171
- '/*',
172
- serveStatic({
173
- root: './public',
174
- rewriteRequestPath: basePath ? (path) => path.replace(basePath, '') : undefined,
175
- })
176
- );
177
-
178
- // Every page path renders the same shell — the client fetches config and
179
- // handles home/404 routing, exactly like the old dev pages router did.
180
- app.get('/', (c) => renderDevPage(c, { basePath }));
181
- app.get('/:rest{.+}', (c) => renderDevPage(c, { basePath }));
182
-
183
- app.onError(createErrorHandler({ basePath, logger }));
184
-
185
- return app;
186
- }
187
-
188
- export default createApp();
@@ -1,86 +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 'node:fs';
18
- import path from 'node:path';
19
-
20
- import safeScriptJson from '../lib/safeScriptJson.js';
21
-
22
- // Dev HTML shell — config-free: the client fetches root config and page
23
- // config over the API (SWR), exactly like the old dev pages did. Theme and
24
- // app config are read per request so a lowdefyBuild does not require a
25
- // server restart for the pre-hydration values to update.
26
- //
27
- // @hono/vite-dev-server injects /@vite/client into this response; the
28
- // react-refresh preamble must be inlined here for @vitejs/plugin-react.
29
- const layerOrderScript = `(function(){var s=document.createElement("style");s.id="__lf-layer-order";s.textContent="@layer theme, base, antd, components, utilities;";document.head.prepend(s);new MutationObserver(function(){if(document.head.firstChild!==s)document.head.prepend(s)}).observe(document.head,{childList:true})})();`;
30
-
31
- function readBuildJson(name) {
32
- try {
33
- return JSON.parse(fs.readFileSync(path.join(process.cwd(), 'build', `${name}.json`), 'utf8'));
34
- } catch {
35
- return {};
36
- }
37
- }
38
-
39
- function renderDevPage(c, { basePath = '' }) {
40
- const themeConfig = readBuildJson('theme');
41
- const appJson = readBuildJson('app');
42
-
43
- const VALID_COLOR_MODES = ['system', 'light', 'dark'];
44
- const configColorMode = VALID_COLOR_MODES.includes(themeConfig.darkMode)
45
- ? themeConfig.darkMode
46
- : 'system';
47
- const darkBg = themeConfig?.antd?.darkToken?.colorBgLayout ?? '#000';
48
- const lightBg = themeConfig?.antd?.lightToken?.colorBgLayout ?? '';
49
-
50
- const darkModeScript = `(function(){var c=${safeScriptJson(
51
- configColorMode
52
- )};var db=${safeScriptJson(darkBg)};var lb=${safeScriptJson(
53
- lightBg
54
- )};var d;if(c==="dark")d=true;else if(c==="light")d=false;else{try{var p=localStorage.getItem("lowdefy_darkMode");if(p==="dark")d=true;else if(p==="light")d=false;else d=window.matchMedia("(prefers-color-scheme:dark)").matches}catch(e){d=window.matchMedia("(prefers-color-scheme:dark)").matches}}var bg=d?db:lb;if(bg)document.documentElement.style.backgroundColor=bg})();`;
55
-
56
- const html = `<!DOCTYPE html>
57
- <html class="lowdefy">
58
- <head>
59
- <meta charset="utf-8" />
60
- <script>${layerOrderScript}</script>
61
- <script>${darkModeScript}</script>
62
- <link rel="manifest" href="${basePath}/manifest.webmanifest" />
63
- <link rel="icon" type="image/svg+xml" href="${basePath}/icon.svg" />
64
- <link rel="apple-touch-icon" href="${basePath}/apple-touch-icon.png" />
65
- <meta name="viewport" content="width=device-width, initial-scale=1" />
66
- <script type="module">
67
- import RefreshRuntime from '${basePath}/@react-refresh';
68
- RefreshRuntime.injectIntoGlobalHook(window);
69
- window.$RefreshReg$ = () => {};
70
- window.$RefreshSig$ = () => (type) => type;
71
- window.__vite_plugin_react_preamble_installed__ = true;
72
- </script>
73
- ${appJson.html?.appendHead ?? ''}
74
- </head>
75
- <body>
76
- <div id="root"></div>
77
- <script id="__LOWDEFY_CONFIG__" type="application/json">${safeScriptJson({ basePath })}</script>
78
- ${appJson.html?.appendBody ?? ''}
79
- <script type="module" src="${basePath}/client/main.jsx"></script>
80
- </body>
81
- </html>`;
82
-
83
- return c.html(html);
84
- }
85
-
86
- export default renderDevPage;
@@ -1,25 +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
- // Splits the rest of a catch-all route into decoded segments, independent of
18
- // any configured basePath. Mirrors the Next.js [...param] query arrays —
19
- // nested ids (slashes in pageId or endpointId) are real.
20
- function getPathSegments(c, prefix) {
21
- const rest = c.req.path.split(prefix)[1] ?? '';
22
- return rest.split('/').filter(Boolean).map(decodeURIComponent);
23
- }
24
-
25
- export default getPathSegments;
@@ -1,38 +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
- // Escape characters that could break out of the enclosing <script> tag or
18
- // terminate a JS string literal. Used to defuse the js/bad-code-sanitization
19
- // class of injection for values embedded into inline scripts and the
20
- // application/json config script.
21
- const SCRIPT_ESCAPES = {
22
- '<': '\\u003C',
23
- '>': '\\u003E',
24
- '\b': '\\b',
25
- '\f': '\\f',
26
- '\n': '\\n',
27
- '\r': '\\r',
28
- '\t': '\\t',
29
- '\0': '\\0',
30
- '\u2028': '\\u2028',
31
- '\u2029': '\\u2029',
32
- };
33
-
34
- function safeScriptJson(value) {
35
- return JSON.stringify(value).replace(/[<>\b\f\n\r\t\0\u2028\u2029]/g, (c) => SCRIPT_ESCAPES[c]);
36
- }
37
-
38
- export default safeScriptJson;
@@ -1,32 +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 createLowdefyContext from '../../lib/server/createLowdefyContext.js';
18
-
19
- // Replaces lib/server/apiWrapper.js. Errors thrown by handlers are routed by
20
- // Hono to the app-level error handler (src/middleware/errorHandler.js).
21
- function apiContext() {
22
- return async function apiContextMiddleware(c, next) {
23
- if (c.get('lowdefyContext')) {
24
- return next();
25
- }
26
- const context = await createLowdefyContext({ c });
27
- c.set('lowdefyContext', context);
28
- return next();
29
- };
30
- }
31
-
32
- export default apiContext;
@@ -1,55 +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 { serializer } from '@lowdefy/helpers';
18
-
19
- // Hono routes every handler error to the app-level error handler — upstream
20
- // middleware try/catch never sees them. API routes get the serialized error
21
- // JSON the old apiWrapper returned; page routes get a plain 500.
22
- function createErrorHandler({ basePath = '', logger }) {
23
- return async function errorHandler(error, c) {
24
- const path = basePath ? c.req.path.replace(basePath, '') : c.req.path;
25
- // Unauthenticated requests to protected endpoints are expected traffic -
26
- // one warning line and a 401, skipping the structured error log so
27
- // probing cannot flood it. Keys strictly on the error name; the 500 path
28
- // below is untouched.
29
- if (error.name === 'AuthenticationError') {
30
- logger.warn(`Unauthenticated request: ${c.req.method} ${c.req.path}`);
31
- if (path.startsWith('/api/')) {
32
- return c.json({ name: error.name, message: error.message }, 401);
33
- }
34
- return c.text('Unauthorized', 401);
35
- }
36
- const context = c.get('lowdefyContext');
37
- if (context) {
38
- await context.handleError(error);
39
- } else {
40
- logger.error(error);
41
- }
42
- if (path.startsWith('/api/')) {
43
- const serialized = serializer.serialize(error);
44
- if (serialized?.['~e']) {
45
- delete serialized['~e'].received;
46
- delete serialized['~e'].stack;
47
- delete serialized['~e'].configKey;
48
- }
49
- return c.json(serialized, 500);
50
- }
51
- return c.text('Internal Server Error', 500);
52
- };
53
- }
54
-
55
- export default createErrorHandler;
@@ -1,64 +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 { callAgent } from '@lowdefy/api';
18
- import { translate, type } from '@lowdefy/helpers';
19
-
20
- import getPathSegments from '../lib/getPathSegments.js';
21
-
22
- async function agentHandler(c) {
23
- const context = c.get('lowdefyContext');
24
- const t = (key, values) => translate({ key, values, i18n: context.i18n });
25
- if (c.req.method !== 'POST') {
26
- throw new Error(t('agent.runtime.methodNotAllowed'));
27
- }
28
- const segments = getPathSegments(c, '/api/agent/');
29
- if (segments.length < 2) {
30
- return c.json({ error: t('agent.runtime.invalidPath') }, 400);
31
- }
32
- const agentId = segments[segments.length - 1];
33
- const pageId = segments.slice(0, -1).join('/');
34
- context.logger.info({ event: 'call_agent', agentId, pageId });
35
- const { conversationId } = c.req.query();
36
- const { messages, urlQuery, sharedState } = await c.req.json();
37
- if (!Array.isArray(messages)) {
38
- return c.json({ error: t('agent.runtime.messagesMustBeArray') }, 400);
39
- }
40
- if (urlQuery != null && (typeof urlQuery !== 'object' || Array.isArray(urlQuery))) {
41
- return c.json({ error: t('agent.runtime.urlQueryMustBeObject') }, 400);
42
- }
43
- if (sharedState != null && !type.isObject(sharedState)) {
44
- return c.json({ error: t('agent.runtime.sharedStateMustBeObject') }, 400);
45
- }
46
- const { response: webResponse } = await callAgent(context, {
47
- agentId,
48
- pageId,
49
- messages,
50
- conversationId: conversationId ?? undefined,
51
- sharedState: sharedState ?? undefined,
52
- urlQuery: urlQuery ?? undefined,
53
- });
54
-
55
- // callAgent returns a Web Response — stream its body straight through.
56
- return c.body(webResponse.body, 200, {
57
- 'Content-Type': 'text/event-stream',
58
- 'Cache-Control': 'no-cache',
59
- Connection: 'keep-alive',
60
- 'Content-Encoding': 'none',
61
- });
62
- }
63
-
64
- export default agentHandler;
@@ -1,43 +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 authJson from '../../lib/build/auth.js';
18
- import getAuth from '../../lib/server/auth/getAuth.js';
19
- import getMockUser from '../../lib/server/auth/getMockUser.js';
20
-
21
- // Mounts BetterAuth's Web Standard handler on /api/auth/*. Hono routes HEAD
22
- // requests through GET handlers, so HEAD short-circuits before the handler -
23
- // corporate email link-checkers pre-fetch magic-link and verification URLs
24
- // with HEAD, and letting those reach the handler would consume the one-time
25
- // token before the user clicks.
26
- function authMiddleware({ logger }) {
27
- return async function auth(c) {
28
- if (authJson.configured !== true) {
29
- return c.json({ message: 'Auth not configured' }, 404);
30
- }
31
- if (getMockUser()) {
32
- // Mock user active - no auth engine runs; the get-session stub in
33
- // app.js is the only auth endpoint.
34
- return c.json({ message: 'Auth engine disabled while dev.mockUser is active' }, 404);
35
- }
36
- if (c.req.method === 'HEAD') {
37
- return c.body(null, 200);
38
- }
39
- return getAuth({ logger }).handler(c.req.raw);
40
- };
41
- }
42
-
43
- export default authMiddleware;
@@ -1,57 +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 { logClientError } from '@lowdefy/api';
18
-
19
- import clientErrorStore from '../../lib/docs/clientErrorStore.js';
20
-
21
- async function clientErrorHandler(c) {
22
- if (c.req.method !== 'POST') {
23
- throw new Error('Only POST requests are supported.');
24
- }
25
- const context = c.get('lowdefyContext');
26
-
27
- const origin = c.req.header('origin');
28
- if (!origin) {
29
- return c.json({ error: 'Forbidden' }, 403);
30
- }
31
- try {
32
- if (new URL(origin).host !== c.req.header('host')) {
33
- return c.json({ error: 'Forbidden' }, 403);
34
- }
35
- } catch {
36
- return c.json({ error: 'Forbidden' }, 403);
37
- }
38
-
39
- // Dev keeps `received` in the payload — it powers error tracing in dev tools.
40
- const body = await c.req.json();
41
- const { error, ...response } = await logClientError(context, body);
42
-
43
- // Feed the agent-facing feedback loop (GET /lowdefy-docs/build-status) with a
44
- // serializable summary — not the full error object, which may carry
45
- // non-serializable `received` values.
46
- clientErrorStore.push({
47
- timestamp: new Date().toISOString(),
48
- name: error?.name ?? 'Error',
49
- message: error?.message ?? null,
50
- source: response.source ?? null,
51
- config: response.config ?? null,
52
- });
53
-
54
- return c.json(response);
55
- }
56
-
57
- export default clientErrorHandler;
@@ -1,44 +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 { runScheduledEndpoint } from '@lowdefy/api';
18
-
19
- import getPathSegments from '../lib/getPathSegments.js';
20
-
21
- // Triggered by Vercel Cron in production: an HTTP GET to /api/cron/<endpointId>. Available in dev so
22
- // scheduled endpoints can be triggered locally with curl. Vercel auto-sends the value of the project
23
- // env var named exactly CRON_SECRET as `Authorization: Bearer <value>`, and the firing cron
24
- // expression in the `x-vercel-cron-schedule` header. Fails closed if CRON_SECRET is unset.
25
- async function cronHandler(c) {
26
- if (c.req.method !== 'GET') {
27
- throw new Error('Only GET requests are supported.');
28
- }
29
- const context = c.get('lowdefyContext');
30
-
31
- const secret = process.env.CRON_SECRET;
32
- if (!secret || c.req.header('authorization') !== `Bearer ${secret}`) {
33
- context.logger.warn({ event: 'cron_unauthorized' });
34
- return c.json({ error: 'Unauthorized' }, 401);
35
- }
36
-
37
- const endpointId = getPathSegments(c, '/api/cron/').join('/');
38
- const cron = c.req.header('x-vercel-cron-schedule');
39
- context.logger.info({ event: 'call_cron_endpoint', endpointId, cron });
40
- const response = await runScheduledEndpoint(context, { endpointId, cron });
41
- return c.json(response);
42
- }
43
-
44
- export default cronHandler;