@lowdefy/build 5.2.0 → 5.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build/buildAgents.js +249 -0
- package/dist/build/buildApi/buildRoutine/countStepTypes.js +1 -1
- package/dist/build/buildApi/buildRoutine/setStepId.js +6 -2
- package/dist/build/buildApi/buildRoutine/validateStep.js +18 -0
- package/dist/build/buildApp.js +18 -5
- package/dist/build/buildImports/buildImportsDev.js +5 -0
- package/dist/build/buildImports/buildImportsProd.js +1 -0
- package/dist/build/buildJs/writeJs.js +2 -2
- package/dist/build/buildMenu.js +5 -0
- package/dist/build/buildModuleDefs.js +52 -1
- package/dist/build/buildModules.js +1 -1
- package/dist/build/buildPages/validateCallApiRefs.js +9 -0
- package/dist/build/buildRefs/getUserJavascriptFunction.js +6 -9
- package/dist/build/buildRefs/runTransformer.js +3 -2
- package/dist/build/buildRefs/walker.js +22 -39
- package/dist/build/buildTypes.js +7 -0
- package/dist/build/codegenI18nLocales.js +53 -0
- package/dist/build/copyAgentFileSystems.js +45 -0
- package/dist/build/full/updateServerPackageJson.js +1 -0
- package/dist/build/jit/shallowBuild.js +31 -0
- package/dist/build/registerModules.js +11 -33
- package/dist/build/writeAgents.js +26 -0
- package/dist/build/writeAppMeta.js +19 -0
- package/dist/build/writeI18n.js +117 -0
- package/dist/build/writePluginImports/writeAgentImports.js +22 -0
- package/dist/build/writePluginImports/writePluginImports.js +10 -0
- package/dist/build/writePluginImports/writeServerExternalPackages.js +121 -0
- package/dist/createContext.js +8 -1
- package/dist/defaultMessagesMap.js +3 -0
- package/dist/defaultPackages.js +7 -0
- package/dist/defaultTypesMap.js +590 -377
- package/dist/index.js +30 -0
- package/dist/lowdefySchema.js +414 -0
- package/dist/scripts/generateDefaultMessages.js +37 -0
- package/dist/scripts/generateDefaultTypes.js +1 -0
- package/dist/test-utils/testContext.js +2 -0
- package/dist/utils/createPluginTypesMap.js +7 -0
- package/package.json +51 -44
|
@@ -330,11 +330,6 @@ function resolveModulePageId(arg, moduleEntry, context, configKey) {
|
|
|
330
330
|
configKey
|
|
331
331
|
});
|
|
332
332
|
}
|
|
333
|
-
if (!(moduleEntry.exports?.pages ?? []).some((p)=>p.id === arg)) {
|
|
334
|
-
throw new ConfigError(`Module "${moduleEntry.id}" does not export page "${arg}".`, {
|
|
335
|
-
configKey
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
333
|
return `${moduleEntry.id}/${arg}`;
|
|
339
334
|
}
|
|
340
335
|
if (type.isObject(arg) && type.isString(arg.id) && type.isString(arg.module)) {
|
|
@@ -345,12 +340,6 @@ function resolveModulePageId(arg, moduleEntry, context, configKey) {
|
|
|
345
340
|
configKey,
|
|
346
341
|
usage: `_module.pageId { id: "${arg.id}", module: "${arg.module}" }`
|
|
347
342
|
});
|
|
348
|
-
if (!(targetEntry.exports?.pages ?? []).some((p)=>p.id === arg.id)) {
|
|
349
|
-
const caller = moduleEntry ? `Module "${moduleEntry.id}"` : 'App config';
|
|
350
|
-
throw new ConfigError(`${caller} references page "${arg.id}" ` + `from "${arg.module}" (entry "${targetEntry.id}"), ` + `but that module does not export page "${arg.id}".`, {
|
|
351
|
-
configKey
|
|
352
|
-
});
|
|
353
|
-
}
|
|
354
343
|
return `${targetEntry.id}/${arg.id}`;
|
|
355
344
|
}
|
|
356
345
|
throw new ConfigError('_module.pageId requires a string or object { id, module }.', {
|
|
@@ -365,11 +354,6 @@ function resolveModuleConnectionId(arg, moduleEntry, context, configKey) {
|
|
|
365
354
|
configKey
|
|
366
355
|
});
|
|
367
356
|
}
|
|
368
|
-
if (!(moduleEntry.exports?.connections ?? []).some((c)=>c.id === arg)) {
|
|
369
|
-
throw new ConfigError(`Module "${moduleEntry.id}" does not export connection "${arg}".`, {
|
|
370
|
-
configKey
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
357
|
const remapping = moduleEntry.connections ?? {};
|
|
374
358
|
if (remapping[arg]) {
|
|
375
359
|
return remapping[arg];
|
|
@@ -384,12 +368,6 @@ function resolveModuleConnectionId(arg, moduleEntry, context, configKey) {
|
|
|
384
368
|
configKey,
|
|
385
369
|
usage: `_module.connectionId { id: "${arg.id}", module: "${arg.module}" }`
|
|
386
370
|
});
|
|
387
|
-
if (!(targetEntry.exports?.connections ?? []).some((c)=>c.id === arg.id)) {
|
|
388
|
-
const caller = moduleEntry ? `Module "${moduleEntry.id}"` : 'App config';
|
|
389
|
-
throw new ConfigError(`${caller} references connection "${arg.id}" ` + `from "${arg.module}" (entry "${targetEntry.id}"), ` + `but that module does not export connection "${arg.id}".`, {
|
|
390
|
-
configKey
|
|
391
|
-
});
|
|
392
|
-
}
|
|
393
371
|
const targetRemapping = targetEntry.connections ?? {};
|
|
394
372
|
if (targetRemapping[arg.id]) {
|
|
395
373
|
return targetRemapping[arg.id];
|
|
@@ -408,11 +386,6 @@ function resolveModuleEndpointId(arg, moduleEntry, context, configKey) {
|
|
|
408
386
|
configKey
|
|
409
387
|
});
|
|
410
388
|
}
|
|
411
|
-
if (!(moduleEntry.exports?.api ?? []).some((e)=>e.id === arg)) {
|
|
412
|
-
throw new ConfigError(`Module "${moduleEntry.id}" does not export endpoint "${arg}".`, {
|
|
413
|
-
configKey
|
|
414
|
-
});
|
|
415
|
-
}
|
|
416
389
|
return `${moduleEntry.id}/${arg}`;
|
|
417
390
|
}
|
|
418
391
|
if (type.isObject(arg) && type.isString(arg.id) && type.isString(arg.module)) {
|
|
@@ -423,12 +396,6 @@ function resolveModuleEndpointId(arg, moduleEntry, context, configKey) {
|
|
|
423
396
|
configKey,
|
|
424
397
|
usage: `_module.endpointId { id: "${arg.id}", module: "${arg.module}" }`
|
|
425
398
|
});
|
|
426
|
-
if (!(targetEntry.exports?.api ?? []).some((e)=>e.id === arg.id)) {
|
|
427
|
-
const caller = moduleEntry ? `Module "${moduleEntry.id}"` : 'App config';
|
|
428
|
-
throw new ConfigError(`${caller} references endpoint "${arg.id}" ` + `from "${arg.module}" (entry "${targetEntry.id}"), ` + `but that module does not export endpoint "${arg.id}".`, {
|
|
429
|
-
configKey
|
|
430
|
-
});
|
|
431
|
-
}
|
|
432
399
|
return `${targetEntry.id}/${arg.id}`;
|
|
433
400
|
}
|
|
434
401
|
throw new ConfigError('_module.endpointId requires a string or object { id, module }.', {
|
|
@@ -503,8 +470,16 @@ async function resolveRef(node, ctx) {
|
|
|
503
470
|
refDef.key = await resolve(cloneForResolve(refDef.key), ctx);
|
|
504
471
|
}
|
|
505
472
|
// 4. Module path resolution: resolve relative paths from the module root
|
|
506
|
-
if (ctx.moduleRoot
|
|
507
|
-
refDef.path
|
|
473
|
+
if (ctx.moduleRoot) {
|
|
474
|
+
if (type.isString(refDef.path) && !path.isAbsolute(refDef.path)) {
|
|
475
|
+
refDef.path = path.resolve(ctx.moduleRoot, refDef.path);
|
|
476
|
+
}
|
|
477
|
+
if (type.isString(refDef.resolver) && !path.isAbsolute(refDef.resolver)) {
|
|
478
|
+
refDef.resolver = path.resolve(ctx.moduleRoot, refDef.resolver);
|
|
479
|
+
}
|
|
480
|
+
if (type.isString(refDef.transformer) && !path.isAbsolute(refDef.transformer)) {
|
|
481
|
+
refDef.transformer = path.resolve(ctx.moduleRoot, refDef.transformer);
|
|
482
|
+
}
|
|
508
483
|
}
|
|
509
484
|
// 5. Update refMap with resolved path; store original for resolver refs
|
|
510
485
|
ctx.refMap[refDef.id].path = refDef.path;
|
|
@@ -512,9 +487,16 @@ async function resolveRef(node, ctx) {
|
|
|
512
487
|
ctx.refMap[refDef.id].original = refDef.original;
|
|
513
488
|
}
|
|
514
489
|
// 6. Path escape constraint: module refs cannot escape the package root
|
|
515
|
-
if (ctx.packageRoot
|
|
516
|
-
|
|
517
|
-
|
|
490
|
+
if (ctx.packageRoot) {
|
|
491
|
+
for (const field of [
|
|
492
|
+
'path',
|
|
493
|
+
'resolver',
|
|
494
|
+
'transformer'
|
|
495
|
+
]){
|
|
496
|
+
const value = refDef[field];
|
|
497
|
+
if (type.isString(value) && !value.startsWith(ctx.packageRoot + '/') && value !== ctx.packageRoot) {
|
|
498
|
+
throw new ConfigError(`Module ref ${field} "${value}" escapes the package root.`);
|
|
499
|
+
}
|
|
518
500
|
}
|
|
519
501
|
}
|
|
520
502
|
// 7. Circular detection
|
|
@@ -628,7 +610,8 @@ async function resolveRef(node, ctx) {
|
|
|
628
610
|
content = await runTransformer({
|
|
629
611
|
context: ctx.buildContext,
|
|
630
612
|
input: content,
|
|
631
|
-
refDef
|
|
613
|
+
refDef,
|
|
614
|
+
referencedFrom: ctx.currentFile
|
|
632
615
|
});
|
|
633
616
|
// 14. Extract key
|
|
634
617
|
content = getKey({
|
package/dist/build/buildTypes.js
CHANGED
|
@@ -65,6 +65,7 @@ function buildTypes({ components, context }) {
|
|
|
65
65
|
typeCounters.actions.increment('SetDarkMode');
|
|
66
66
|
components.types = {
|
|
67
67
|
actions: {},
|
|
68
|
+
agents: {},
|
|
68
69
|
auth: {
|
|
69
70
|
adapters: {},
|
|
70
71
|
callbacks: {},
|
|
@@ -86,6 +87,12 @@ function buildTypes({ components, context }) {
|
|
|
86
87
|
store: components.types.actions,
|
|
87
88
|
typeClass: 'Action'
|
|
88
89
|
});
|
|
90
|
+
buildTypeClass(context, {
|
|
91
|
+
counter: typeCounters.agents,
|
|
92
|
+
definitions: context.typesMap.agents,
|
|
93
|
+
store: components.types.agents,
|
|
94
|
+
typeClass: 'Agent'
|
|
95
|
+
});
|
|
89
96
|
buildTypeClass(context, {
|
|
90
97
|
counter: typeCounters.auth.adapters,
|
|
91
98
|
definitions: context.typesMap.auth.adapters,
|
|
@@ -0,0 +1,53 @@
|
|
|
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
|
+
*/ import { type } from '@lowdefy/helpers';
|
|
16
|
+
const HEADER = `// Generated by @lowdefy/build. Do not edit.\n`;
|
|
17
|
+
const SAFE_IDENTIFIER_REGEX = /^[A-Za-z0-9_-]+$/;
|
|
18
|
+
function isSafeIdentifier(value) {
|
|
19
|
+
return type.isString(value) && SAFE_IDENTIFIER_REGEX.test(value);
|
|
20
|
+
}
|
|
21
|
+
function buildAntdLoaders(locales) {
|
|
22
|
+
const entries = locales.filter((locale)=>isSafeIdentifier(locale.code) && isSafeIdentifier(locale.antd)).map((locale)=>` '${locale.code}': () => import('antd/locale/${locale.antd}.js').then((m) => m.default ?? m),`);
|
|
23
|
+
return `${HEADER}const loaders = {\n${entries.join('\n')}\n};\nexport default loaders;\n`;
|
|
24
|
+
}
|
|
25
|
+
function buildDayjsImports(locales) {
|
|
26
|
+
const validDayjsLocales = locales.filter((locale)=>isSafeIdentifier(locale.code) && isSafeIdentifier(locale.dayjs));
|
|
27
|
+
const ids = Array.from(new Set(validDayjsLocales.map((locale)=>locale.dayjs)));
|
|
28
|
+
const imports = ids.map((id)=>`import 'dayjs/locale/${id}.js';`).join('\n');
|
|
29
|
+
const localeMap = validDayjsLocales.map((locale)=>` '${locale.code}': '${locale.dayjs}',`).join('\n');
|
|
30
|
+
return `${HEADER}${imports}\nconst localeMap = {\n${localeMap}\n};\nexport default localeMap;\n`;
|
|
31
|
+
}
|
|
32
|
+
// antd X (@ant-design/x@2.7.x) only ships two locale packs: en_US and zh_CN.
|
|
33
|
+
// Other locales fall back to en_US for X-native strings (New chat, OK/Cancel,
|
|
34
|
+
// Stop loading, Like/Dislike, etc.). App authors override per-locale via
|
|
35
|
+
// config.i18n.messages.{locale}.agent.antdx.* keys handled outside this codegen.
|
|
36
|
+
const ANTD_X_SUPPORTED = new Set([
|
|
37
|
+
'en_US',
|
|
38
|
+
'zh_CN'
|
|
39
|
+
]);
|
|
40
|
+
function buildAntdXLoaders(locales) {
|
|
41
|
+
const entries = locales.filter((locale)=>isSafeIdentifier(locale.code) && isSafeIdentifier(locale.antd)).map((locale)=>{
|
|
42
|
+
const pack = ANTD_X_SUPPORTED.has(locale.antd) ? locale.antd : 'en_US';
|
|
43
|
+
return ` '${locale.code}': () => import('@ant-design/x/locale/${pack}.js').then((m) => m.default ?? m),`;
|
|
44
|
+
});
|
|
45
|
+
return `${HEADER}const loaders = {\n${entries.join('\n')}\n};\nexport default loaders;\n`;
|
|
46
|
+
}
|
|
47
|
+
async function codegenI18nLocales({ components, context }) {
|
|
48
|
+
const locales = components.config?.i18n?.locales ?? [];
|
|
49
|
+
await context.writeBuildArtifact('i18n/antdLocales.js', buildAntdLoaders(locales));
|
|
50
|
+
await context.writeBuildArtifact('i18n/antdXLocales.js', buildAntdXLoaders(locales));
|
|
51
|
+
await context.writeBuildArtifact('i18n/dayjsLocales.js', buildDayjsImports(locales));
|
|
52
|
+
}
|
|
53
|
+
export default codegenI18nLocales;
|
|
@@ -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
|
+
*/ import path from 'path';
|
|
16
|
+
import fs from 'fs';
|
|
17
|
+
import { copyFileOrDirectory } from '@lowdefy/node-utils';
|
|
18
|
+
async function copyAgentFileSystems({ components, context }) {
|
|
19
|
+
const basePaths = [];
|
|
20
|
+
const seen = new Set();
|
|
21
|
+
for (const agent of components.agents ?? []){
|
|
22
|
+
const basePath = agent.properties?.fileSystem?.basePath;
|
|
23
|
+
if (!basePath || typeof basePath !== 'string') continue;
|
|
24
|
+
if (seen.has(basePath)) continue;
|
|
25
|
+
seen.add(basePath);
|
|
26
|
+
basePaths.push(basePath);
|
|
27
|
+
}
|
|
28
|
+
// Manifest is consumed by next.config.js to populate outputFileTracingIncludes,
|
|
29
|
+
// so the Next.js tracer bundles these directories on Vercel and standalone builds.
|
|
30
|
+
await context.writeBuildArtifact('agentFileSystems.json', JSON.stringify(basePaths));
|
|
31
|
+
if (context.directories.config === context.directories.server) return;
|
|
32
|
+
for (const basePath of basePaths){
|
|
33
|
+
const source = path.resolve(context.directories.config, basePath);
|
|
34
|
+
if (!fs.existsSync(source)) continue;
|
|
35
|
+
const dest = path.resolve(context.directories.server, basePath);
|
|
36
|
+
try {
|
|
37
|
+
await copyFileOrDirectory(source, dest);
|
|
38
|
+
} catch (err) {
|
|
39
|
+
throw new Error(`Failed to copy fileSystem basePath "${basePath}" to server directory: ${err.message}`, {
|
|
40
|
+
cause: err
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export default copyAgentFileSystems;
|
|
@@ -25,6 +25,7 @@ async function updateServerPackageJson({ components, context }) {
|
|
|
25
25
|
});
|
|
26
26
|
}
|
|
27
27
|
getPackages(components.types.actions);
|
|
28
|
+
getPackages(components.types.agents);
|
|
28
29
|
getPackages(components.types.auth.adapters);
|
|
29
30
|
getPackages(components.types.auth.callbacks);
|
|
30
31
|
getPackages(components.types.auth.events);
|
|
@@ -23,6 +23,7 @@ import addKeys from '../addKeys.js';
|
|
|
23
23
|
import buildApp from '../buildApp.js';
|
|
24
24
|
import buildAuth from '../buildAuth/buildAuth.js';
|
|
25
25
|
import buildConnections from '../buildConnections.js';
|
|
26
|
+
import buildAgents from '../buildAgents.js';
|
|
26
27
|
import buildApi from '../buildApi/buildApi.js';
|
|
27
28
|
import buildLogger from '../buildLogger.js';
|
|
28
29
|
import buildImports from '../buildImports/buildImports.js';
|
|
@@ -32,17 +33,22 @@ import buildModules from '../buildModules.js';
|
|
|
32
33
|
import buildRefs from '../buildRefs/buildRefs.js';
|
|
33
34
|
import buildTypes from '../buildTypes.js';
|
|
34
35
|
import cleanBuildDirectory from '../cleanBuildDirectory.js';
|
|
36
|
+
import copyAgentFileSystems from '../copyAgentFileSystems.js';
|
|
35
37
|
import copyPublicFolder from '../copyPublicFolder.js';
|
|
36
38
|
import testSchema from '../testSchema.js';
|
|
37
39
|
import validateConfig from '../validateConfig.js';
|
|
38
40
|
import writeApp from '../writeApp.js';
|
|
41
|
+
import writeAppMeta from '../writeAppMeta.js';
|
|
39
42
|
import writeAuth from '../writeAuth.js';
|
|
40
43
|
import writeConfig from '../writeConfig.js';
|
|
41
44
|
import writeConnections from '../writeConnections.js';
|
|
45
|
+
import writeAgents from '../writeAgents.js';
|
|
42
46
|
import writeApi from '../writeApi.js';
|
|
43
47
|
import writeGlobal from '../writeGlobal.js';
|
|
44
48
|
import writeJs from '../buildJs/writeJs.js';
|
|
45
49
|
import writeLogger from '../writeLogger.js';
|
|
50
|
+
import codegenI18nLocales from '../codegenI18nLocales.js';
|
|
51
|
+
import writeI18n from '../writeI18n.js';
|
|
46
52
|
import writeTheme from '../writeTheme.js';
|
|
47
53
|
import writeMaps from '../writeMaps.js';
|
|
48
54
|
import updateServerPackageJson from '../full/updateServerPackageJson.js';
|
|
@@ -146,6 +152,10 @@ async function shallowBuild(options) {
|
|
|
146
152
|
components,
|
|
147
153
|
context
|
|
148
154
|
});
|
|
155
|
+
tryBuildStep(buildAgents, 'buildAgents', {
|
|
156
|
+
components,
|
|
157
|
+
context
|
|
158
|
+
});
|
|
149
159
|
const { pageRegistry, sourcelessPageArtifacts } = buildShallowPages({
|
|
150
160
|
components,
|
|
151
161
|
context
|
|
@@ -195,6 +205,10 @@ async function shallowBuild(options) {
|
|
|
195
205
|
components,
|
|
196
206
|
context
|
|
197
207
|
});
|
|
208
|
+
await writeAppMeta({
|
|
209
|
+
components,
|
|
210
|
+
context
|
|
211
|
+
});
|
|
198
212
|
await writeAuth({
|
|
199
213
|
components,
|
|
200
214
|
context
|
|
@@ -207,6 +221,10 @@ async function shallowBuild(options) {
|
|
|
207
221
|
components,
|
|
208
222
|
context
|
|
209
223
|
});
|
|
224
|
+
await writeAgents({
|
|
225
|
+
components,
|
|
226
|
+
context
|
|
227
|
+
});
|
|
210
228
|
await writeConfig({
|
|
211
229
|
components,
|
|
212
230
|
context
|
|
@@ -219,6 +237,14 @@ async function shallowBuild(options) {
|
|
|
219
237
|
components,
|
|
220
238
|
context
|
|
221
239
|
});
|
|
240
|
+
await writeI18n({
|
|
241
|
+
components,
|
|
242
|
+
context
|
|
243
|
+
});
|
|
244
|
+
await codegenI18nLocales({
|
|
245
|
+
components,
|
|
246
|
+
context
|
|
247
|
+
});
|
|
222
248
|
await writeLogger({
|
|
223
249
|
components,
|
|
224
250
|
context
|
|
@@ -242,6 +268,7 @@ async function shallowBuild(options) {
|
|
|
242
268
|
await context.writeBuildArtifact('jsMap.json', JSON.stringify(context.jsMap));
|
|
243
269
|
await context.writeBuildArtifact('idCounter.json', JSON.stringify(makeId.counter));
|
|
244
270
|
await context.writeBuildArtifact('customTypesMap.json', JSON.stringify(options.customTypesMap ?? {}));
|
|
271
|
+
await context.writeBuildArtifact('customMessagesMap.json', JSON.stringify(options.customMessagesMap ?? {}));
|
|
245
272
|
// Persist snapshot of installed packages for JIT missing-package detection.
|
|
246
273
|
// Written as a build artifact so JIT builds compare against the skeleton
|
|
247
274
|
// build state, not a potentially-updated package.json (race condition).
|
|
@@ -265,6 +292,10 @@ async function shallowBuild(options) {
|
|
|
265
292
|
components,
|
|
266
293
|
context
|
|
267
294
|
});
|
|
295
|
+
await copyAgentFileSystems({
|
|
296
|
+
components,
|
|
297
|
+
context
|
|
298
|
+
});
|
|
268
299
|
return {
|
|
269
300
|
components,
|
|
270
301
|
pageRegistry,
|
|
@@ -122,40 +122,19 @@ async function resolveLocalManifest({ entry, resolvedPaths, context }) {
|
|
|
122
122
|
throw new ConfigError(`Module "${entry.id}": each item in "dependencies" must have a string "id".`);
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
|
-
//
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
'menus',
|
|
131
|
-
'connections',
|
|
132
|
-
'api'
|
|
133
|
-
];
|
|
134
|
-
const exports = {};
|
|
135
|
-
for (const section of exportSections){
|
|
136
|
-
const items = rawExports[section] ?? [];
|
|
137
|
-
if (!type.isArray(items)) {
|
|
138
|
-
throw new ConfigError(`Module "${entry.id}": exports.${section} must be an array.`);
|
|
139
|
-
}
|
|
140
|
-
for (const item of items){
|
|
141
|
-
if (!type.isString(item.id)) {
|
|
142
|
-
throw new ConfigError(`Module "${entry.id}": each item in exports.${section} must have a string "id".`);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
exports[section] = items;
|
|
146
|
-
}
|
|
147
|
-
// Reject unknown keys in exports
|
|
148
|
-
for (const key of Object.keys(rawExports)){
|
|
149
|
-
if (!exportSections.includes(key)) {
|
|
150
|
-
throw new ConfigError(`Module "${entry.id}": unknown exports section "${key}". ` + `Valid sections: ${exportSections.join(', ')}.`);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
// Validate required vars without defaults (needs raw defs + consumer values only).
|
|
154
|
-
// Type validation moves to after Phase 2 because defaults are resolved lazily.
|
|
125
|
+
// Capture var definitions for the registered module entry.
|
|
126
|
+
// Required-var validation is deferred to Phase 2.5 (buildModuleDefs.js)
|
|
127
|
+
// because entry.vars may contain unresolved _refs at this point.
|
|
128
|
+
// Type validation runs at the end of Phase 3 against the lazily-populated
|
|
129
|
+
// resolvedVarCache.
|
|
155
130
|
const varDefs = manifest.vars ?? {};
|
|
156
|
-
validateRequiredVars(varDefs, entry.vars ?? {}, entry.id, entry.source);
|
|
157
131
|
// Validate plugin dependencies against app's declared plugins
|
|
158
132
|
const requiredPlugins = manifest.plugins ?? [];
|
|
133
|
+
for (const plugin of requiredPlugins){
|
|
134
|
+
if (!type.isString(plugin.version)) {
|
|
135
|
+
throw new ConfigError(`Module "${entry.id}": plugin "${plugin.name}" must declare a "version" ` + `(semver range) in module.lowdefy.yaml.`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
159
138
|
const appPlugins = (context.plugins ?? []).reduce((map, p)=>map.set(p.name, p.version), new Map());
|
|
160
139
|
for (const plugin of requiredPlugins){
|
|
161
140
|
if (context.defaultPackageNames.has(plugin.name)) {
|
|
@@ -184,7 +163,6 @@ async function resolveLocalManifest({ entry, resolvedPaths, context }) {
|
|
|
184
163
|
connections: entry.connections ?? {},
|
|
185
164
|
manifest,
|
|
186
165
|
dependencies,
|
|
187
|
-
exports,
|
|
188
166
|
moduleDependencies: entry.dependencies ?? {},
|
|
189
167
|
refDef
|
|
190
168
|
};
|
|
@@ -239,4 +217,4 @@ async function resolveFullManifest({ entryId, context }) {
|
|
|
239
217
|
validateVarTypes(varDefs, moduleEntry.resolvedVarCache, entryId, moduleEntry.source);
|
|
240
218
|
}
|
|
241
219
|
}
|
|
242
|
-
export { resolveLocalManifest, resolveFullManifest };
|
|
220
|
+
export { resolveLocalManifest, resolveFullManifest, validateRequiredVars };
|
|
@@ -0,0 +1,26 @@
|
|
|
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
|
+
*/ import { type, serializer } from '@lowdefy/helpers';
|
|
16
|
+
async function writeAgents({ components, context }) {
|
|
17
|
+
if (type.isNone(components.agents)) return;
|
|
18
|
+
if (!type.isArray(components.agents)) {
|
|
19
|
+
throw new Error(`Agents is not an array.`);
|
|
20
|
+
}
|
|
21
|
+
const writePromises = components.agents.map(async (agent)=>{
|
|
22
|
+
await context.writeBuildArtifact(`agents/${agent.agentId}.json`, serializer.serializeToString(agent));
|
|
23
|
+
});
|
|
24
|
+
return Promise.all(writePromises);
|
|
25
|
+
}
|
|
26
|
+
export default writeAgents;
|
|
@@ -0,0 +1,19 @@
|
|
|
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
|
+
*/ import { serializer } from '@lowdefy/helpers';
|
|
16
|
+
async function writeAppMeta({ components, context }) {
|
|
17
|
+
await context.writeBuildArtifact('appMeta.json', serializer.serializeToString(components.appMeta));
|
|
18
|
+
}
|
|
19
|
+
export default writeAppMeta;
|
|
@@ -0,0 +1,117 @@
|
|
|
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
|
+
*/ import { ConfigError, ConfigWarning } from '@lowdefy/errors';
|
|
16
|
+
import { mergeObjects, serializer, type } from '@lowdefy/helpers';
|
|
17
|
+
function collectPluginMessages({ messagesMap, declaredCodes }) {
|
|
18
|
+
const collected = {};
|
|
19
|
+
Object.values(messagesMap ?? {}).forEach((pluginCatalog)=>{
|
|
20
|
+
if (!type.isObject(pluginCatalog)) return;
|
|
21
|
+
Object.entries(pluginCatalog).forEach(([code, perLocale])=>{
|
|
22
|
+
if (!declaredCodes.has(code)) return;
|
|
23
|
+
if (!type.isObject(perLocale)) return;
|
|
24
|
+
collected[code] = mergeObjects([
|
|
25
|
+
collected[code] ?? {},
|
|
26
|
+
perLocale
|
|
27
|
+
]);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
return collected;
|
|
31
|
+
}
|
|
32
|
+
async function writeI18n({ components, context }) {
|
|
33
|
+
const i18n = components.config?.i18n;
|
|
34
|
+
if (type.isNone(i18n)) {
|
|
35
|
+
await context.writeBuildArtifact('i18n.json', serializer.serializeToString({}));
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (!type.isObject(i18n)) {
|
|
39
|
+
throw new ConfigError('App "config.i18n" should be an object.', {
|
|
40
|
+
configKey: i18n?.['~k']
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
if (type.isNone(i18n.defaultLocale) || !type.isString(i18n.defaultLocale)) {
|
|
44
|
+
throw new ConfigError('App "config.i18n" requires a string "defaultLocale".', {
|
|
45
|
+
configKey: i18n['~k']
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
if (!type.isArray(i18n.locales) || i18n.locales.length === 0) {
|
|
49
|
+
throw new ConfigError('App "config.i18n" requires a non-empty "locales" array.', {
|
|
50
|
+
configKey: i18n['~k']
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
const codes = new Set();
|
|
54
|
+
i18n.locales.forEach((locale)=>{
|
|
55
|
+
if (!type.isObject(locale) || !type.isString(locale.code)) {
|
|
56
|
+
throw new ConfigError('App "config.i18n.locales[]" requires a string "code".', {
|
|
57
|
+
configKey: locale?.['~k'] ?? i18n['~k']
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
if (codes.has(locale.code)) {
|
|
61
|
+
throw new ConfigError(`Duplicate locale code "${locale.code}" in "config.i18n.locales".`, {
|
|
62
|
+
configKey: locale['~k']
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
codes.add(locale.code);
|
|
66
|
+
});
|
|
67
|
+
if (!codes.has(i18n.defaultLocale)) {
|
|
68
|
+
throw new ConfigError(`App "config.i18n.defaultLocale" "${i18n.defaultLocale}" must be present in "locales".`, {
|
|
69
|
+
configKey: i18n['~k']
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
const messages = i18n.messages ?? {};
|
|
73
|
+
if (!type.isObject(messages)) {
|
|
74
|
+
throw new ConfigError('App "config.i18n.messages" should be an object.', {
|
|
75
|
+
configKey: i18n['~k']
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
Object.keys(messages).forEach((code)=>{
|
|
79
|
+
if (!codes.has(code)) {
|
|
80
|
+
context.handleWarning(new ConfigWarning(`App "config.i18n.messages.${code}" references a locale not declared in "locales".`, {
|
|
81
|
+
configKey: i18n['~k']
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
const pluginMessages = collectPluginMessages({
|
|
86
|
+
messagesMap: context.messagesMap,
|
|
87
|
+
declaredCodes: codes
|
|
88
|
+
});
|
|
89
|
+
const mergedMessages = {};
|
|
90
|
+
codes.forEach((code)=>{
|
|
91
|
+
const userPerLocale = messages[code];
|
|
92
|
+
const pluginPerLocale = pluginMessages[code];
|
|
93
|
+
const combined = mergeObjects([
|
|
94
|
+
pluginPerLocale ?? {},
|
|
95
|
+
userPerLocale ?? {}
|
|
96
|
+
]);
|
|
97
|
+
if (Object.keys(combined).length === 0) {
|
|
98
|
+
context.handleWarning(new ConfigWarning(`App "config.i18n" has no messages for locale "${code}". Falls back to "en-US".`, {
|
|
99
|
+
configKey: i18n['~k']
|
|
100
|
+
}));
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
mergedMessages[code] = combined;
|
|
104
|
+
});
|
|
105
|
+
const artifact = {
|
|
106
|
+
defaultLocale: i18n.defaultLocale,
|
|
107
|
+
locales: i18n.locales.map((locale)=>({
|
|
108
|
+
code: locale.code,
|
|
109
|
+
label: locale.label,
|
|
110
|
+
antd: locale.antd,
|
|
111
|
+
dayjs: locale.dayjs
|
|
112
|
+
})),
|
|
113
|
+
messages: mergedMessages
|
|
114
|
+
};
|
|
115
|
+
await context.writeBuildArtifact('i18n.json', serializer.serializeToString(artifact));
|
|
116
|
+
}
|
|
117
|
+
export default writeI18n;
|
|
@@ -0,0 +1,22 @@
|
|
|
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
|
+
*/ import generateImportFile from './generateImportFile.js';
|
|
16
|
+
async function writeAgentImports({ components, context }) {
|
|
17
|
+
await context.writeBuildArtifact('plugins/agents.js', generateImportFile({
|
|
18
|
+
imports: components.imports.agents,
|
|
19
|
+
importPath: 'agents'
|
|
20
|
+
}));
|
|
21
|
+
}
|
|
22
|
+
export default writeAgentImports;
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import writeActionImports from './writeActionImports.js';
|
|
16
16
|
import writeActionSchemaMap from './writeActionSchemaMap.js';
|
|
17
|
+
import writeAgentImports from './writeAgentImports.js';
|
|
17
18
|
import writeAuthImports from './writeAuthImports.js';
|
|
18
19
|
import writeBlockImports from './writeBlockImports.js';
|
|
19
20
|
import writeBlockSchemaMap from './writeBlockSchemaMap.js';
|
|
@@ -22,6 +23,7 @@ import writeIconImports from './writeIconImports.js';
|
|
|
22
23
|
import writeOperatorImports from './writeOperatorImports.js';
|
|
23
24
|
import writeOperatorSchemaMap from './writeOperatorSchemaMap.js';
|
|
24
25
|
import writeGlobalsCss from './writeGlobalsCss.js';
|
|
26
|
+
import writeServerExternalPackages from './writeServerExternalPackages.js';
|
|
25
27
|
async function writePluginImports({ components, context }) {
|
|
26
28
|
await writeActionImports({
|
|
27
29
|
components,
|
|
@@ -31,6 +33,10 @@ async function writePluginImports({ components, context }) {
|
|
|
31
33
|
components,
|
|
32
34
|
context
|
|
33
35
|
});
|
|
36
|
+
await writeAgentImports({
|
|
37
|
+
components,
|
|
38
|
+
context
|
|
39
|
+
});
|
|
34
40
|
await writeAuthImports({
|
|
35
41
|
components,
|
|
36
42
|
context
|
|
@@ -63,6 +69,10 @@ async function writePluginImports({ components, context }) {
|
|
|
63
69
|
components,
|
|
64
70
|
context
|
|
65
71
|
});
|
|
72
|
+
await writeServerExternalPackages({
|
|
73
|
+
components,
|
|
74
|
+
context
|
|
75
|
+
});
|
|
66
76
|
// Write block package names for Next.js transpilePackages (CSS imports).
|
|
67
77
|
const blockPackages = [
|
|
68
78
|
...new Set((components.imports.blocks ?? []).map((b)=>b.package))
|