@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
@@ -1,102 +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 { jest } from '@jest/globals';
18
-
19
- // Covers the clip/scroll success path, which screenshotPage.test.mjs cannot
20
- // (it deliberately fails chromium.launch to test the "no browser" error
21
- // path). Mocking the whole ./getBrowser.js module — not just
22
- // playwright-core — means lib/build/config.js (which getBrowser.js reads at
23
- // import time) is never touched, so no fixture chdir is needed here.
24
- const mockScreenshot = jest.fn(async () => Buffer.from('fake-png'));
25
- const mockWaitForTimeout = jest.fn(async () => {});
26
- const mockEvaluate = jest.fn(async () => {});
27
- const mockPage = {
28
- screenshot: mockScreenshot,
29
- waitForTimeout: mockWaitForTimeout,
30
- evaluate: mockEvaluate,
31
- };
32
- const mockContext = { close: jest.fn(async () => {}) };
33
- const mockOpenPage = jest.fn(async () => ({
34
- context: mockContext,
35
- page: mockPage,
36
- url: 'http://localhost:3001/home',
37
- }));
38
- const mockGetBrowser = jest.fn(async () => ({}));
39
-
40
- jest.unstable_mockModule('./getBrowser.js', () => ({
41
- getBrowser: mockGetBrowser,
42
- openPage: mockOpenPage,
43
- buildPageUrl: jest.fn(() => 'http://localhost:3001/home'),
44
- }));
45
-
46
- const { default: screenshotPage } = await import('./screenshotPage.js');
47
-
48
- test('screenshotPage with a valid clip scrolls to scrollX/scrollY and converts clip to document coordinates', async () => {
49
- const result = await screenshotPage({
50
- origin: 'http://localhost:3001',
51
- pageId: 'home',
52
- clip: { x: 220, y: 480, width: 96, height: 40 },
53
- scrollX: 10,
54
- scrollY: 340,
55
- });
56
-
57
- expect(result.error).toBeUndefined();
58
- expect(mockEvaluate).toHaveBeenCalledWith(expect.any(Function), { x: 10, y: 340 });
59
- expect(mockScreenshot).toHaveBeenCalledWith({
60
- type: 'png',
61
- clip: { x: 230, y: 820, width: 96, height: 40 },
62
- });
63
- });
64
-
65
- test('screenshotPage without a clip takes a normal fullPage/viewport screenshot and never scrolls', async () => {
66
- const result = await screenshotPage({
67
- origin: 'http://localhost:3001',
68
- pageId: 'home',
69
- fullPage: true,
70
- });
71
-
72
- expect(result.error).toBeUndefined();
73
- expect(mockEvaluate).not.toHaveBeenCalled();
74
- expect(mockScreenshot).toHaveBeenCalledWith({ type: 'png', fullPage: true });
75
- });
76
-
77
- test('screenshotPage ignores a clip with non-positive dimensions and falls back to a viewport screenshot', async () => {
78
- const result = await screenshotPage({
79
- origin: 'http://localhost:3001',
80
- pageId: 'home',
81
- clip: { x: 0, y: 0, width: 0, height: 40 },
82
- });
83
-
84
- expect(result.error).toBeUndefined();
85
- expect(mockEvaluate).not.toHaveBeenCalled();
86
- expect(mockScreenshot).toHaveBeenCalledWith({ type: 'png', fullPage: false });
87
- });
88
-
89
- test('screenshotPage clip takes priority over fullPage when both are provided', async () => {
90
- const result = await screenshotPage({
91
- origin: 'http://localhost:3001',
92
- pageId: 'home',
93
- fullPage: true,
94
- clip: { x: 1, y: 2, width: 3, height: 4 },
95
- });
96
-
97
- expect(result.error).toBeUndefined();
98
- expect(mockScreenshot).toHaveBeenCalledWith({
99
- type: 'png',
100
- clip: { x: 1, y: 2, width: 3, height: 4 },
101
- });
102
- });
@@ -1,67 +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
- import { type } from '@lowdefy/helpers';
20
-
21
- import getDocsManifest from './getDocsManifest.js';
22
-
23
- const MAX_RESULTS = 20;
24
- const SNIPPET_RADIUS = 120;
25
-
26
- let contentCache = null;
27
-
28
- function getContents({ manifest }) {
29
- if (contentCache !== null) {
30
- return contentCache;
31
- }
32
- contentCache = manifest.docs.map((doc) => ({
33
- doc,
34
- content: fs.readFileSync(path.join(manifest.contentDir, doc.path), 'utf8'),
35
- }));
36
- return contentCache;
37
- }
38
-
39
- function searchDocs({ query }) {
40
- if (!type.isString(query) || query.trim() === '') {
41
- throw new Error('searchDocs requires a "query" string.');
42
- }
43
- const manifest = getDocsManifest();
44
- if (type.isNone(manifest)) {
45
- return [];
46
- }
47
- const lowerQuery = query.trim().toLowerCase();
48
- const titleMatches = [];
49
- const contentMatches = [];
50
- for (const { doc, content } of getContents({ manifest })) {
51
- if (doc.title.toLowerCase().includes(lowerQuery) || doc.slug.includes(lowerQuery)) {
52
- titleMatches.push({ ...doc, snippet: content.slice(0, SNIPPET_RADIUS * 2) });
53
- continue;
54
- }
55
- const index = content.toLowerCase().indexOf(lowerQuery);
56
- if (index !== -1) {
57
- const start = Math.max(0, index - SNIPPET_RADIUS);
58
- contentMatches.push({
59
- ...doc,
60
- snippet: content.slice(start, index + lowerQuery.length + SNIPPET_RADIUS),
61
- });
62
- }
63
- }
64
- return [...titleMatches, ...contentMatches].slice(0, MAX_RESULTS);
65
- }
66
-
67
- export default searchDocs;
@@ -1,335 +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 os from 'os';
19
- import path from 'path';
20
-
21
- // Writes a throwaway server directory (build artifacts + a fake installed
22
- // plugin in node_modules) for the docs service tests. Generated because a
23
- // committed node_modules fixture would be gitignored.
24
- function setupTestFixtures() {
25
- const fixtureDir = fs.mkdtempSync(path.join(os.tmpdir(), 'lowdefy-docs-test-'));
26
- const write = (relativePath, data) => {
27
- const filePath = path.join(fixtureDir, relativePath);
28
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
29
- fs.writeFileSync(filePath, typeof data === 'string' ? data : JSON.stringify(data));
30
- };
31
-
32
- write('package.json', { name: 'test-fixture-server', version: '1.0.0', type: 'module' });
33
-
34
- // lib/build/config.js reads this at import time (screenshotPage → basePath).
35
- write('build/config.json', {});
36
-
37
- write('build/plugins/availableTypes.json', {
38
- actions: {
39
- SetState: { package: '@lowdefy/actions-core', originalTypeName: 'SetState', version: '5.0.0' },
40
- },
41
- agents: {},
42
- auth: { adapters: {}, callbacks: {}, events: {}, providers: {} },
43
- blocks: {
44
- Button: { package: '@lowdefy/blocks-antd', originalTypeName: 'Button', version: '5.0.0' },
45
- TestBlock: { package: 'test-plugin', originalTypeName: 'TestBlock', version: '1.0.0' },
46
- },
47
- connections: {
48
- AxiosHttp: {
49
- package: '@lowdefy/connection-axios-http',
50
- originalTypeName: 'AxiosHttp',
51
- version: '5.0.0',
52
- },
53
- },
54
- notifications: {},
55
- operators: {
56
- client: {
57
- _get: { package: '@lowdefy/operators-js', originalTypeName: '_get', version: '5.0.0' },
58
- },
59
- server: {
60
- _get: { package: '@lowdefy/operators-js', originalTypeName: '_get', version: '5.0.0' },
61
- _secret: { package: '@lowdefy/operators-js', originalTypeName: '_secret', version: '5.0.0' },
62
- },
63
- },
64
- requests: {
65
- AxiosHttp: {
66
- package: '@lowdefy/connection-axios-http',
67
- originalTypeName: 'AxiosHttp',
68
- version: '5.0.0',
69
- },
70
- },
71
- websockets: {},
72
- });
73
-
74
- write('build/types.json', {
75
- actions: {},
76
- agents: {},
77
- auth: { adapters: {}, callbacks: {}, events: {}, providers: {} },
78
- blocks: {
79
- Button: {
80
- package: '@lowdefy/blocks-antd',
81
- originalTypeName: 'Button',
82
- version: '5.0.0',
83
- count: 3,
84
- },
85
- },
86
- connections: {},
87
- notifications: {},
88
- operators: {
89
- client: {
90
- _get: {
91
- package: '@lowdefy/operators-js',
92
- originalTypeName: '_get',
93
- version: '5.0.0',
94
- count: 1,
95
- },
96
- },
97
- server: {},
98
- },
99
- requests: {},
100
- websockets: {},
101
- });
102
-
103
- write('build/plugins/blockSchemas.json', {
104
- Button: { type: 'object', properties: { title: { type: 'string' } } },
105
- TestBlock: { type: 'object', properties: {} },
106
- });
107
- write('build/plugins/blockMetas.json', {
108
- Button: { category: 'display' },
109
- TestBlock: { category: 'input', valueType: 'string' },
110
- });
111
- write('build/plugins/actionSchemas.json', { SetState: { type: 'object' } });
112
- write('build/plugins/operatorSchemas.json', { _get: { params: { type: 'object' } } });
113
- write('build/plugins/connectionSchemas.json', {
114
- AxiosHttp: { schema: { type: 'object' }, requests: ['AxiosHttp'] },
115
- });
116
- write('build/plugins/requestSchemas.json', {
117
- AxiosHttp: { schema: { type: 'object' }, meta: { checkRead: false, checkWrite: false } },
118
- ReadOnlyRequest: { schema: { type: 'object' }, meta: { checkRead: true, checkWrite: false } },
119
- WriteRequest: { schema: { type: 'object' }, meta: { checkRead: true, checkWrite: true } },
120
- // No "meta" at all — some custom plugins don't declare it; treated as unknown.
121
- UnknownMetaRequest: { schema: { type: 'object' } },
122
- });
123
- write('build/customTypesMap.json', {
124
- blocks: { TestBlock: { package: 'test-plugin', originalTypeName: 'TestBlock', version: '1.0.0' } },
125
- });
126
- write('build/installedPluginPackages.json', [
127
- '@lowdefy/blocks-antd',
128
- '@lowdefy/actions-core',
129
- '@lowdefy/operators-js',
130
- '@lowdefy/connection-axios-http',
131
- 'test-plugin',
132
- ]);
133
-
134
- write('node_modules/test-plugin/package.json', { name: 'test-plugin', version: '1.0.0' });
135
- write('node_modules/test-plugin/README.md', '# test-plugin\n\nA local test plugin.\n');
136
- write(
137
- 'node_modules/test-plugin/dist/blocks/TestBlock/gallery.yaml',
138
- '- id: example\n type: TestBlock\n properties:\n title: Hello\n'
139
- );
140
-
141
- // Feedback-loop fixtures — build status, and a JIT-built page's registry,
142
- // keyMap and refMap entries (see packages/build/src/build/addKeys.js for
143
- // the key path format: `[index:id]` / `[index:id:Type]`).
144
- write('build/buildStatus.json', {
145
- status: 'ok',
146
- timestamp: '2026-01-01T00:00:00.000Z',
147
- errors: [],
148
- warnings: [],
149
- });
150
-
151
- write('build/pageRegistry.json', {
152
- home: { pageId: 'home', auth: null, refId: 'ref-home', refPath: 'pages/home.yaml' },
153
- other: { pageId: 'other', auth: null, refId: 'ref-other', refPath: 'pages/other.yaml' },
154
- legal: { pageId: 'legal', auth: null, refId: 'ref-legal', refPath: 'pages/legal.yaml' },
155
- unbuilt: { pageId: 'unbuilt', auth: null, refId: 'ref-unbuilt', refPath: 'pages/unbuilt.yaml' },
156
- });
157
-
158
- // Mirrors the real dev keyMap shape: the skeleton build keys the whole
159
- // config (`root.pages[N:id]` page stubs only), while each JIT page build
160
- // runs addKeys on the page object itself — so page CONTENT keys are
161
- // `root.blocks[...]` with no page segment, one `root`-keyed subtree per
162
- // built page, distinguishable only via the ~k_parent chain. Tree roots
163
- // reference a parent id that is never written to keyMap.
164
- write('build/keyMap.json', {
165
- 'key-root': { key: 'root', '~k_parent': 'key-root-parent' },
166
- 'key-pages': { key: 'root.pages', '~k_parent': 'key-root', '~r': 'ref-home' },
167
- 'key-home-stub': {
168
- key: 'root.pages[0:home]',
169
- '~k_parent': 'key-pages',
170
- '~r': 'ref-home',
171
- '~l': 1,
172
- },
173
- 'key-other-stub': {
174
- key: 'root.pages[1:other]',
175
- '~k_parent': 'key-pages',
176
- '~r': 'ref-other',
177
- '~l': 1,
178
- },
179
- // JIT subtree for page "home".
180
- 'key-home': { key: 'root', '~k_parent': 'key-home-jit-parent', '~r': 'ref-home', '~l': 1 },
181
- 'key-button': {
182
- key: 'root.blocks[2:my_button:Button]',
183
- '~k_parent': 'key-home',
184
- '~r': 'ref-home',
185
- '~l': 5,
186
- },
187
- // List item block — config ids inside lists carry the `$` placeholder;
188
- // runtime block ids have array indices applied (`my_list.0.item_title`).
189
- 'key-list-item': {
190
- key: 'root.blocks[3:my_list:List].blocks[0:my_list.$.item_title:Title]',
191
- '~k_parent': 'key-home',
192
- '~r': 'ref-home',
193
- '~l': 9,
194
- },
195
- // JIT subtree for page "other" — holds a block id that also exists on
196
- // home, with an IDENTICAL key shape. findConfig must scope pageId scans
197
- // via the ~k_parent chain, not the key path.
198
- 'key-other': { key: 'root', '~k_parent': 'key-other-jit-parent', '~r': 'ref-other', '~l': 1 },
199
- 'key-other-button': {
200
- key: 'root.blocks[0:my_button:Button]',
201
- '~k_parent': 'key-other',
202
- '~r': 'ref-other',
203
- '~l': 4,
204
- },
205
- // Skeleton-built page (like the default 404) — content is keyed inside
206
- // the global config tree with the page segment inline, and chains to the
207
- // shared config root rather than a page-specific one.
208
- 'key-legal': {
209
- key: 'root.pages[2:legal]',
210
- '~k_parent': 'key-pages',
211
- '~r': 'ref-legal',
212
- '~l': 1,
213
- },
214
- 'key-legal-button': {
215
- key: 'root.pages[2:legal].blocks[0:legal_button:Button]',
216
- '~k_parent': 'key-legal',
217
- '~r': 'ref-legal',
218
- '~l': 3,
219
- },
220
- });
221
-
222
- write('build/refMap.json', {
223
- 'ref-home': { parent: null, path: 'pages/home.yaml' },
224
- 'ref-other': { parent: null, path: 'pages/other.yaml' },
225
- 'ref-legal': { parent: null, path: 'pages/legal.yaml' },
226
- });
227
-
228
- write('build/pages/home.json', {
229
- pageId: 'home',
230
- blocks: [
231
- { id: 'my_button', type: 'Button', '~k': 'key-button' },
232
- {
233
- id: 'card',
234
- type: 'Card',
235
- slots: { content: { blocks: [{ id: 'nested_button', type: 'Button' }] } },
236
- },
237
- ],
238
- requests: [
239
- { id: 'request:home:req-read', requestId: 'req-read', payload: {} },
240
- { id: 'request:home:req-write', requestId: 'req-write', payload: {} },
241
- { id: 'request:home:req-unknown', requestId: 'req-unknown', payload: {} },
242
- ],
243
- });
244
-
245
- write('build/pages/other.json', {
246
- pageId: 'other',
247
- blocks: [{ id: 'my_button', type: 'Button', '~k': 'key-other-button' }],
248
- requests: [],
249
- });
250
-
251
- write('build/pages/legal.json', {
252
- pageId: 'legal',
253
- blocks: [{ id: 'legal_button', type: 'Button', '~k': 'key-legal-button' }],
254
- requests: [],
255
- });
256
-
257
- // Per-request artifacts (packages/build/src/build/full/writeRequests.js
258
- // strips type/connectionId/properties/auth off the page's `requests` array
259
- // after writing these, so a request's type is only readable here).
260
- write('build/pages/home/requests/req-read.json', {
261
- id: 'request:home:req-read',
262
- requestId: 'req-read',
263
- pageId: 'home',
264
- connectionId: 'axios',
265
- type: 'ReadOnlyRequest',
266
- payload: {},
267
- properties: {},
268
- });
269
- write('build/pages/home/requests/req-write.json', {
270
- id: 'request:home:req-write',
271
- requestId: 'req-write',
272
- pageId: 'home',
273
- connectionId: 'axios',
274
- type: 'WriteRequest',
275
- payload: {},
276
- properties: {},
277
- });
278
- write('build/pages/home/requests/req-unknown.json', {
279
- id: 'request:home:req-unknown',
280
- requestId: 'req-unknown',
281
- pageId: 'home',
282
- connectionId: 'axios',
283
- type: 'UnknownMetaRequest',
284
- payload: {},
285
- properties: {},
286
- });
287
-
288
- write('build/connectionIds.json', ['axios']);
289
- write('build/connections/axios.json', {
290
- id: 'connection:axios',
291
- connectionId: 'axios',
292
- type: 'AxiosHttp',
293
- properties: {},
294
- });
295
-
296
- write('build/menus.json', [
297
- {
298
- id: 'menu:default',
299
- menuId: 'default',
300
- links: [
301
- {
302
- id: 'menuitem:default:home',
303
- menuItemId: 'home',
304
- type: 'MenuLink',
305
- pageId: 'home',
306
- properties: { title: 'Home' },
307
- },
308
- ],
309
- },
310
- ]);
311
-
312
- write('build/api/resolve_greeting.json', {
313
- id: 'endpoint:resolve_greeting',
314
- type: 'InternalApi',
315
- routine: [],
316
- });
317
-
318
- write('build/agents/assistant.json', {
319
- id: 'agent:assistant',
320
- agentId: 'assistant',
321
- type: 'OpenAiAgent',
322
- connectionId: 'axios',
323
- });
324
-
325
- write('build/websocketIds.json', []);
326
-
327
- // No cli.agentTools.allowWriteRequests — tests toggle this file directly
328
- // (isWriteRequestsAllowed reads it fresh, no caching) to exercise the
329
- // opt-in gate.
330
- write('lowdefy.yaml', 'lowdefy: 5.0.0\n');
331
-
332
- return fixtureDir;
333
- }
334
-
335
- export default setupTestFixtures;
@@ -1,59 +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 { type } from '@lowdefy/helpers';
18
-
19
- import { buildPageUrl } from './getBrowser.js';
20
- import inspectState from './inspectState.js';
21
- import { writeCheckpoint } from './checkpointStore.js';
22
-
23
- // Snapshots the running app (page state + recorded request/api responses)
24
- // into a checkpoint folder under .lowdefy — see checkpointStore.js for the
25
- // on-disk layout. Reuses inspectState.js's tab-first/headless-fallback
26
- // snapshot rather than driving a browser directly, so a snapshot always
27
- // reflects whatever a developer is actually looking at when one is
28
- // available.
29
- async function snapshotState({ origin, pageId, name, notes, source, overwrite }) {
30
- if (type.isNone(pageId) || !type.isString(pageId)) {
31
- return {
32
- error: `snapshotState requires a "pageId" string. Received ${JSON.stringify(pageId)}.`,
33
- };
34
- }
35
- if (type.isNone(name) || !type.isString(name)) {
36
- return { error: `snapshotState requires a "name" string. Received ${JSON.stringify(name)}.` };
37
- }
38
-
39
- const snapshot = await inspectState({ origin, pageId, source });
40
- if (snapshot?.error) {
41
- return { error: snapshot.error };
42
- }
43
-
44
- const url = `${buildPageUrl({ origin, pageId })}${snapshot.urlQuery ?? ''}`;
45
-
46
- try {
47
- const { dir, parts } = writeCheckpoint({
48
- name,
49
- snapshot: { ...snapshot, url },
50
- notes,
51
- overwrite,
52
- });
53
- return { name, dir, parts, source: snapshot.source };
54
- } catch (error) {
55
- return { error: error.message };
56
- }
57
- }
58
-
59
- export default snapshotState;