@lowdefy/server-e2e 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 (42) hide show
  1. package/{pages/_app.js → client/App.jsx} +43 -28
  2. package/client/Page.jsx +110 -0
  3. package/client/main.jsx +39 -0
  4. package/lib/build/app.js +8 -1
  5. package/lib/build/appMeta.js +8 -1
  6. package/lib/build/auth.js +8 -1
  7. package/lib/build/config.js +8 -1
  8. package/lib/build/i18n.js +26 -0
  9. package/lib/build/logger.js +8 -1
  10. package/lib/build/theme.js +8 -1
  11. package/lib/client/auth/{Auth.js → Auth.jsx} +5 -1
  12. package/lib/server/auth/{getServerSession.js → session.js} +5 -3
  13. package/lib/server/log/createHandleError.test.mjs +126 -0
  14. package/lowdefy/createCustomPluginTypesMap.mjs +1 -0
  15. package/lowdefy/createCustomPluginTypesMap.test.mjs +2 -0
  16. package/package.json +49 -41
  17. package/package.original.json +52 -44
  18. package/postcss.config.cjs +1 -0
  19. package/src/app.js +78 -0
  20. package/src/html/getAssets.js +45 -0
  21. package/src/html/renderPage.js +79 -0
  22. package/src/html/template.js +95 -0
  23. package/src/index.js +40 -0
  24. package/src/lib/getPathSegments.js +25 -0
  25. package/src/lib/safeScriptJson.js +38 -0
  26. package/src/middleware/apiContext.js +81 -0
  27. package/src/middleware/errorHandler.js +39 -0
  28. package/src/routes/apiPage.js +37 -0
  29. package/{pages/api/client-error.js → src/routes/clientError.js} +14 -18
  30. package/{pages/api/endpoints/[...endpointId].js → src/routes/endpoints.js} +8 -7
  31. package/{pages/api/request/[...path].js → src/routes/request.js} +10 -10
  32. package/{pages/api/auth/session.js → src/routes/sessionMock.js} +4 -5
  33. package/{pages/api → src/routes}/usage.js +11 -8
  34. package/src/routes/websocket.js +46 -0
  35. package/vite.config.js +45 -0
  36. package/.eslintrc.yaml +0 -1
  37. package/lib/client/Page.js +0 -57
  38. package/lib/server/serverSidePropsWrapper.js +0 -64
  39. package/next.config.js +0 -20
  40. package/pages/404.js +0 -49
  41. package/pages/[[...pageId]].js +0 -85
  42. package/pages/_document.js +0 -108
@@ -0,0 +1,38 @@
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;
@@ -0,0 +1,81 @@
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 path from 'node:path';
18
+ import { createApiContext } from '@lowdefy/api';
19
+ import { v4 as uuid } from 'uuid';
20
+
21
+ import agents from '../../build/plugins/agents.js';
22
+ import appMeta from '../../lib/build/appMeta.js';
23
+ import config from '../../lib/build/config.js';
24
+ import connections from '../../build/plugins/connections.js';
25
+ import createHandleError from '../../lib/server/log/createHandleError.js';
26
+ import createLogger from '../../lib/server/log/createLogger.js';
27
+ import fileCache from '../../lib/server/fileCache.js';
28
+ import getE2eSecrets from '../../lib/server/getE2eSecrets.js';
29
+ import getSession from '../../lib/server/auth/session.js';
30
+ import i18nConfig from '../../lib/build/i18n.js';
31
+ import jsMap from '../../build/plugins/operators/serverJsMap.js';
32
+ import logRequest from '../../lib/server/log/logRequest.js';
33
+ import operators from '../../build/plugins/operators/server.js';
34
+ import websockets from '../../build/plugins/websockets.js';
35
+
36
+ const secrets = getE2eSecrets();
37
+
38
+ // Replaces lib/server/apiWrapper.js. Builds the request context consumed by
39
+ // @lowdefy/api functions. Errors thrown by handlers are routed by Hono to the
40
+ // app-level error handler (src/middleware/errorHandler.js), which reads this
41
+ // context back from the Hono context.
42
+ function apiContext() {
43
+ return async function apiContextMiddleware(c, next) {
44
+ // The page-route mount ('/*') also matches /api/* paths that already
45
+ // built a context — never build twice for one request.
46
+ if (c.get('lowdefyContext')) {
47
+ return next();
48
+ }
49
+ const rid = uuid();
50
+ const context = {
51
+ rid,
52
+ agents,
53
+ appMeta,
54
+ buildDirectory: path.join(process.cwd(), 'build'),
55
+ config,
56
+ configDirectory: process.env.LOWDEFY_DIRECTORY_CONFIG || process.cwd(),
57
+ connections,
58
+ fileCache,
59
+ headers: c.req.header(),
60
+ i18n: i18nConfig,
61
+ jsMap,
62
+ logger: createLogger({ rid }),
63
+ operators,
64
+ req: {
65
+ url: c.req.path,
66
+ method: c.req.method,
67
+ hostname: c.req.header('host'),
68
+ },
69
+ secrets,
70
+ websockets,
71
+ };
72
+ context.handleError = createHandleError({ context });
73
+ context.session = getSession(c);
74
+ createApiContext(context);
75
+ logRequest({ context });
76
+ c.set('lowdefyContext', context);
77
+ return next();
78
+ };
79
+ }
80
+
81
+ export default apiContext;
@@ -0,0 +1,39 @@
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 { redactErrorResponse } from '@lowdefy/api';
18
+
19
+ // Hono routes every handler error to the app-level error handler — upstream
20
+ // middleware try/catch never sees them (compose catches per dispatch level).
21
+ // API routes get the serialized error JSON the old apiWrapper returned;
22
+ // page routes get a plain 500.
23
+ function createErrorHandler({ basePath = '', logger }) {
24
+ return async function errorHandler(error, c) {
25
+ const context = c.get('lowdefyContext');
26
+ if (context) {
27
+ await context.handleError(error);
28
+ } else {
29
+ logger.error(error);
30
+ }
31
+ const path = basePath ? c.req.path.replace(basePath, '') : c.req.path;
32
+ if (path.startsWith('/api/')) {
33
+ return c.json(redactErrorResponse(context, error), 500);
34
+ }
35
+ return c.text('Internal Server Error', 500);
36
+ };
37
+ }
38
+
39
+ export default createErrorHandler;
@@ -0,0 +1,37 @@
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 { getPageConfig } from '@lowdefy/api';
18
+
19
+ import getPathSegments from '../lib/getPathSegments.js';
20
+
21
+ // Page config as JSON for client-side SPA navigation. The first page load is
22
+ // served embedded in the HTML; subsequent navigations fetch from here.
23
+ async function apiPageHandler(c) {
24
+ const context = c.get('lowdefyContext');
25
+ const pageId = getPathSegments(c, '/api/page/').join('/');
26
+ // The client forwards its current query string on the fetch so Dynamic block
27
+ // resolution sees the same urlQuery as an initial HTML load.
28
+ const pageConfig = await getPageConfig(context, { pageId, urlQuery: c.req.query() });
29
+ if (!pageConfig) {
30
+ context.logger.info({ event: 'api_page_not_found', pageId });
31
+ return c.json({ pageConfig: null }, 404);
32
+ }
33
+ context.logger.info({ event: 'api_page_view', pageId });
34
+ return c.json({ pageConfig });
35
+ }
36
+
37
+ export default apiPageHandler;
@@ -16,36 +16,32 @@
16
16
 
17
17
  import { logClientError } from '@lowdefy/api';
18
18
 
19
- import apiWrapper from '../../lib/server/apiWrapper.js';
20
-
21
- async function handler({ context, req, res }) {
22
- if (req.method !== 'POST') {
19
+ async function clientErrorHandler(c) {
20
+ if (c.req.method !== 'POST') {
23
21
  throw new Error('Only POST requests are supported.');
24
22
  }
23
+ const context = c.get('lowdefyContext');
25
24
 
26
- const origin = req.headers.origin;
25
+ const origin = c.req.header('origin');
27
26
  if (!origin) {
28
- res.status(403).json({ error: 'Forbidden' });
29
- return;
27
+ return c.json({ error: 'Forbidden' }, 403);
30
28
  }
31
29
  try {
32
- if (new URL(origin).host !== req.headers.host) {
33
- res.status(403).json({ error: 'Forbidden' });
34
- return;
30
+ if (new URL(origin).host !== c.req.header('host')) {
31
+ return c.json({ error: 'Forbidden' }, 403);
35
32
  }
36
33
  } catch {
37
- res.status(403).json({ error: 'Forbidden' });
38
- return;
34
+ return c.json({ error: 'Forbidden' }, 403);
39
35
  }
40
36
 
37
+ const body = await c.req.json();
41
38
  // Strip received from payload — prod doesn't need it for schema validation
42
- if (req.body?.['~e']) {
43
- delete req.body['~e'].received;
39
+ if (body?.['~e']) {
40
+ delete body['~e'].received;
44
41
  }
45
- // eslint-disable-next-line no-unused-vars
46
- const { error, ...response } = await logClientError(context, req.body);
42
+ await logClientError(context, body);
47
43
 
48
- res.status(200).json({ success: true });
44
+ return c.json({ success: true });
49
45
  }
50
46
 
51
- export default apiWrapper(handler);
47
+ export default clientErrorHandler;
@@ -16,17 +16,18 @@
16
16
 
17
17
  import { callEndpoint } from '@lowdefy/api';
18
18
 
19
- import apiWrapper from '../../../lib/server/apiWrapper.js';
19
+ import getPathSegments from '../lib/getPathSegments.js';
20
20
 
21
- async function handler({ context, req, res }) {
22
- if (req.method !== 'POST') {
21
+ async function endpointsHandler(c) {
22
+ if (c.req.method !== 'POST') {
23
23
  throw new Error('Only POST requests are supported.');
24
24
  }
25
- const endpointId = req.query.endpointId.join('/');
26
- const { blockId, payload, pageId } = req.body;
25
+ const context = c.get('lowdefyContext');
26
+ const endpointId = getPathSegments(c, '/api/endpoints/').join('/');
27
+ const { blockId, payload, pageId } = await c.req.json();
27
28
  context.logger.info({ event: 'call_api_endpoint', blockId, endpointId, pageId });
28
29
  const response = await callEndpoint(context, { blockId, endpointId, pageId, payload });
29
- res.status(200).json(response);
30
+ return c.json(response);
30
31
  }
31
32
 
32
- export default apiWrapper(handler);
33
+ export default endpointsHandler;
@@ -16,23 +16,23 @@
16
16
 
17
17
  import { callRequest } from '@lowdefy/api';
18
18
 
19
- import apiWrapper from '../../../lib/server/apiWrapper.js';
19
+ import getPathSegments from '../lib/getPathSegments.js';
20
20
 
21
- async function handler({ context, req, res }) {
22
- if (req.method !== 'POST') {
21
+ async function requestHandler(c) {
22
+ if (c.req.method !== 'POST') {
23
23
  throw new Error('Only POST requests are supported.');
24
24
  }
25
- const segments = req.query.path;
26
- if (!Array.isArray(segments) || segments.length < 2) {
27
- res.status(400).json({ error: 'Invalid request path' });
28
- return;
25
+ const context = c.get('lowdefyContext');
26
+ const segments = getPathSegments(c, '/api/request/');
27
+ if (segments.length < 2) {
28
+ return c.json({ error: 'Invalid request path' }, 400);
29
29
  }
30
30
  const requestId = segments[segments.length - 1];
31
31
  const pageId = segments.slice(0, -1).join('/');
32
- const { actionId, blockId, payload } = req.body;
32
+ const { actionId, blockId, payload } = await c.req.json();
33
33
  context.logger.info({ event: 'call_request', pageId, requestId, blockId, actionId });
34
34
  const response = await callRequest(context, { blockId, pageId, payload, requestId });
35
- res.status(200).json(response);
35
+ return c.json(response);
36
36
  }
37
37
 
38
- export default apiWrapper(handler);
38
+ export default requestHandler;
@@ -14,10 +14,9 @@
14
14
  limitations under the License.
15
15
  */
16
16
 
17
- import apiWrapper from '../../../lib/server/apiWrapper.js';
18
-
19
- async function handler({ context, req, res }) {
20
- return res.status(200).json(context.session ?? {});
17
+ async function sessionMockHandler(c) {
18
+ const context = c.get('lowdefyContext');
19
+ return c.json(context.session ?? {});
21
20
  }
22
21
 
23
- export default apiWrapper(handler);
22
+ export default sessionMockHandler;
@@ -14,20 +14,23 @@
14
14
  limitations under the License.
15
15
  */
16
16
 
17
- import packageJson from '../../package.json';
18
- import apiWrapper from '../../lib/server/apiWrapper.js';
17
+ import fs from 'node:fs';
18
+ import path from 'node:path';
19
19
 
20
- async function handler({ context, req, res }) {
21
- if (req.method !== 'POST') {
20
+ const packageJson = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf8'));
21
+
22
+ async function usageHandler(c) {
23
+ if (c.req.method !== 'POST') {
22
24
  throw new Error('Only POST requests are supported.');
23
25
  }
24
- const { user, machine } = req.body;
25
- const host = req.headers.host;
26
+ const context = c.get('lowdefyContext');
27
+ const { user, machine } = await c.req.json();
28
+ const host = c.req.header('host');
26
29
  context.logger.info({ event: 'log_usage', user, machine });
27
30
 
28
31
  const timestamp = Date.now();
29
32
 
30
- return res.status(200).json({
33
+ return c.json({
31
34
  offline: false,
32
35
  data: {
33
36
  gitSha: context.appMeta.gitSha,
@@ -40,4 +43,4 @@ async function handler({ context, req, res }) {
40
43
  });
41
44
  }
42
45
 
43
- export default apiWrapper(handler);
46
+ export default usageHandler;
@@ -0,0 +1,46 @@
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 { upgradeWebSocket } from '@hono/node-server';
18
+ import { createChannelRegistry, createWebSocketConnection } from '@lowdefy/api';
19
+
20
+ // One registry per server process — channels and their running source
21
+ // resolvers are shared across all websocket connections on this instance.
22
+ const registry = createChannelRegistry();
23
+
24
+ const websocketHandler = upgradeWebSocket((c) => {
25
+ const context = c.get('lowdefyContext');
26
+ let connection;
27
+ return {
28
+ onOpen(event, ws) {
29
+ connection = createWebSocketConnection(context, {
30
+ registry,
31
+ send: (message) => ws.send(message),
32
+ });
33
+ },
34
+ onMessage(event) {
35
+ connection?.handleMessage(event.data);
36
+ },
37
+ onClose() {
38
+ connection?.close();
39
+ },
40
+ onError(event) {
41
+ context.logger.debug({ event: 'ws_error' }, String(event?.error ?? 'WebSocket error'));
42
+ },
43
+ };
44
+ });
45
+
46
+ export default websocketHandler;
package/vite.config.js ADDED
@@ -0,0 +1,45 @@
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
+
21
+ // basePath from the Lowdefy build — assets are served under it.
22
+ let basePath = '';
23
+ try {
24
+ const config = JSON.parse(fs.readFileSync('./build/config.json', 'utf8'));
25
+ basePath = config.basePath ?? '';
26
+ } catch (e) {
27
+ // No build yet (e.g. editor tooling) — default base.
28
+ }
29
+
30
+ export default defineConfig(({ mode }) => ({
31
+ base: `${basePath}/`,
32
+ plugins: [react()],
33
+ define: {
34
+ // Vite does not replace process.env.NODE_ENV inside dependencies —
35
+ // plugin and client code branch on it.
36
+ 'process.env.NODE_ENV': JSON.stringify(mode === 'production' ? 'production' : 'development'),
37
+ },
38
+ build: {
39
+ outDir: 'dist/client',
40
+ manifest: true,
41
+ rollupOptions: {
42
+ input: 'client/main.jsx',
43
+ },
44
+ },
45
+ }));
package/.eslintrc.yaml DELETED
@@ -1 +0,0 @@
1
- extends: 'plugin:@next/next/core-web-vitals'
@@ -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 React from 'react';
18
-
19
- import { useRouter } from 'next/router';
20
- import Client from '@lowdefy/client';
21
- import Head from 'next/head';
22
- import Link from 'next/link';
23
-
24
- import actions from '../../build/plugins/actions.js';
25
- import blockMetas from '../../build/plugins/blockMetas.json';
26
- import blocks from '../../build/plugins/blocks.js';
27
- import icons from '../../build/plugins/icons.js';
28
- import operators from '../../build/plugins/operators/client.js';
29
- import jsMap from '../../build/plugins/operators/clientJsMap.js';
30
-
31
- const Page = ({ auth, lowdefy, pageConfig, rootConfig }) => {
32
- const router = useRouter();
33
- return (
34
- <Client
35
- auth={auth}
36
- Components={{ Head, Link }}
37
- config={{
38
- pageConfig,
39
- rootConfig,
40
- }}
41
- jsMap={jsMap}
42
- lowdefy={lowdefy}
43
- router={router}
44
- types={{
45
- actions,
46
- blockMetas,
47
- blocks,
48
- icons,
49
- operators,
50
- }}
51
- stage="e2e"
52
- window={window}
53
- />
54
- );
55
- };
56
-
57
- export default Page;
@@ -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 path from 'path';
18
- import { createApiContext } from '@lowdefy/api';
19
- import { v4 as uuid } from 'uuid';
20
-
21
- import appMeta from '../build/appMeta.js';
22
- import config from '../build/config.js';
23
- import createLogger from './log/createLogger.js';
24
- import fileCache from './fileCache.js';
25
- import getServerSession from './auth/getServerSession.js';
26
- import createHandleError from './log/createHandleError.js';
27
- import logRequest from './log/logRequest.js';
28
-
29
- function serverSidePropsWrapper(handler) {
30
- return async function wrappedHandler(nextContext) {
31
- const context = {
32
- // Important to give absolute path so Next can trace build files
33
- rid: uuid(),
34
- appMeta,
35
- buildDirectory: path.join(process.cwd(), 'build'),
36
- configDirectory: process.env.LOWDEFY_DIRECTORY_CONFIG || process.cwd(),
37
- config,
38
- fileCache,
39
- handleError: async (err) => {
40
- console.error(err);
41
- },
42
- headers: nextContext?.req?.headers,
43
- logger: console,
44
- nextContext,
45
- req: nextContext?.req,
46
- res: nextContext?.res,
47
- };
48
- try {
49
- context.logger = createLogger({ rid: context.rid });
50
- context.handleError = createHandleError({ context });
51
- context.session = getServerSession(context);
52
- createApiContext(context);
53
- logRequest({ context });
54
- // Await here so that if handler throws it is caught.
55
- const response = await handler({ context, nextContext });
56
- return response;
57
- } catch (error) {
58
- await context.handleError(error);
59
- throw error;
60
- }
61
- };
62
- }
63
-
64
- export default serverSidePropsWrapper;
package/next.config.js DELETED
@@ -1,20 +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
- const nextConfig = {
6
- basePath: lowdefyConfig.basePath,
7
- reactStrictMode: true,
8
- transpilePackages: [
9
- '@lowdefy/client',
10
- '@ant-design/x',
11
- '@ant-design/x-markdown',
12
- ...blockPackages,
13
- ],
14
- serverExternalPackages,
15
- turbopack: {},
16
- poweredByHeader: false,
17
- output: process.env.LOWDEFY_BUILD_OUTPUT_STANDALONE === '1' ? 'standalone' : undefined,
18
- };
19
-
20
- module.exports = nextConfig;
package/pages/404.js DELETED
@@ -1,49 +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 path from 'path';
18
- import { createApiContext, getPageConfig, getRootConfig } from '@lowdefy/api';
19
-
20
- import appMeta from '../lib/build/appMeta.js';
21
- import config from '../lib/build/config.js';
22
- import fileCache from '../lib/server/fileCache.js';
23
- import Page from '../lib/client/Page.js';
24
-
25
- export async function getStaticProps() {
26
- // Important to give absolute path so Next can trace build files
27
- const context = {
28
- appMeta,
29
- buildDirectory: path.join(process.cwd(), 'build'),
30
- config,
31
- fileCache,
32
- logger: console, // TODO: pino or console or 🤷‍♂️?
33
- };
34
- createApiContext(context);
35
-
36
- const [rootConfig, pageConfig] = await Promise.all([
37
- getRootConfig(context),
38
- getPageConfig(context, { pageId: '404' }),
39
- ]);
40
-
41
- return {
42
- props: {
43
- pageConfig,
44
- rootConfig,
45
- },
46
- };
47
- }
48
-
49
- export default Page;