everything-dev 1.16.3 → 1.19.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 (83) hide show
  1. package/dist/cli/init.cjs +167 -87
  2. package/dist/cli/init.cjs.map +1 -1
  3. package/dist/cli/init.d.cts +14 -2
  4. package/dist/cli/init.d.cts.map +1 -1
  5. package/dist/cli/init.d.mts +14 -2
  6. package/dist/cli/init.d.mts.map +1 -1
  7. package/dist/cli/init.mjs +166 -88
  8. package/dist/cli/init.mjs.map +1 -1
  9. package/dist/cli/prompts.cjs +12 -14
  10. package/dist/cli/prompts.cjs.map +1 -1
  11. package/dist/cli/prompts.mjs +12 -14
  12. package/dist/cli/prompts.mjs.map +1 -1
  13. package/dist/cli/sync.cjs +3 -5
  14. package/dist/cli/sync.cjs.map +1 -1
  15. package/dist/cli/sync.mjs +3 -5
  16. package/dist/cli/sync.mjs.map +1 -1
  17. package/dist/cli/upgrade.cjs +214 -2
  18. package/dist/cli/upgrade.cjs.map +1 -1
  19. package/dist/cli/upgrade.mjs +214 -2
  20. package/dist/cli/upgrade.mjs.map +1 -1
  21. package/dist/config.cjs +125 -74
  22. package/dist/config.cjs.map +1 -1
  23. package/dist/config.d.cts +9 -2
  24. package/dist/config.d.cts.map +1 -1
  25. package/dist/config.d.mts +9 -2
  26. package/dist/config.d.mts.map +1 -1
  27. package/dist/config.mjs +126 -76
  28. package/dist/config.mjs.map +1 -1
  29. package/dist/contract.cjs +1 -4
  30. package/dist/contract.cjs.map +1 -1
  31. package/dist/contract.d.cts +40 -22
  32. package/dist/contract.d.cts.map +1 -1
  33. package/dist/contract.d.mts +40 -22
  34. package/dist/contract.d.mts.map +1 -1
  35. package/dist/contract.meta.cjs +5 -5
  36. package/dist/contract.meta.cjs.map +1 -1
  37. package/dist/contract.meta.d.cts +9 -9
  38. package/dist/contract.meta.d.mts +9 -9
  39. package/dist/contract.meta.mjs +5 -5
  40. package/dist/contract.meta.mjs.map +1 -1
  41. package/dist/contract.mjs +1 -4
  42. package/dist/contract.mjs.map +1 -1
  43. package/dist/index.cjs +2 -0
  44. package/dist/index.d.cts +3 -3
  45. package/dist/index.d.mts +3 -3
  46. package/dist/index.mjs +3 -3
  47. package/dist/merge.cjs +1 -0
  48. package/dist/merge.mjs +1 -1
  49. package/dist/plugin.cjs +70 -114
  50. package/dist/plugin.cjs.map +1 -1
  51. package/dist/plugin.d.cts +38 -17
  52. package/dist/plugin.d.cts.map +1 -1
  53. package/dist/plugin.d.mts +38 -17
  54. package/dist/plugin.d.mts.map +1 -1
  55. package/dist/plugin.mjs +71 -115
  56. package/dist/plugin.mjs.map +1 -1
  57. package/dist/sidebar.cjs +6 -14
  58. package/dist/sidebar.cjs.map +1 -1
  59. package/dist/sidebar.d.cts +3 -3
  60. package/dist/sidebar.d.cts.map +1 -1
  61. package/dist/sidebar.d.mts +3 -3
  62. package/dist/sidebar.d.mts.map +1 -1
  63. package/dist/sidebar.mjs +6 -14
  64. package/dist/sidebar.mjs.map +1 -1
  65. package/dist/types.cjs +10 -16
  66. package/dist/types.cjs.map +1 -1
  67. package/dist/types.d.cts +56 -12
  68. package/dist/types.d.cts.map +1 -1
  69. package/dist/types.d.mts +56 -12
  70. package/dist/types.d.mts.map +1 -1
  71. package/dist/types.mjs +10 -17
  72. package/dist/types.mjs.map +1 -1
  73. package/package.json +1 -1
  74. package/src/cli/init.ts +225 -131
  75. package/src/cli/prompts.ts +17 -22
  76. package/src/cli/sync.ts +5 -8
  77. package/src/cli/upgrade.ts +326 -2
  78. package/src/config.ts +250 -107
  79. package/src/contract.meta.ts +6 -8
  80. package/src/contract.ts +1 -4
  81. package/src/plugin.ts +120 -183
  82. package/src/sidebar.ts +9 -31
  83. package/src/types.ts +10 -15
package/src/plugin.ts CHANGED
@@ -15,6 +15,7 @@ import {
15
15
  runBunInstall,
16
16
  runDockerComposeUp,
17
17
  runTypesGen,
18
+ scaffoldMinimalProject,
18
19
  writeInitSnapshot,
19
20
  } from "./cli/init";
20
21
  import { promptInitOptions } from "./cli/prompts";
@@ -58,7 +59,7 @@ import {
58
59
  } from "./service-descriptor";
59
60
  import { syncAndGenerateSharedUi } from "./shared";
60
61
  import { writePluginSidebarGen } from "./sidebar";
61
- import type { BosConfig, BosPluginRef, RuntimeConfig, SourceMode } from "./types";
62
+ import type { BosConfig, BosConfigInput, BosPluginRef, RuntimeConfig, SourceMode } from "./types";
62
63
  import { run } from "./utils/run";
63
64
  import { saveBosConfig } from "./utils/save-config";
64
65
  import { colors } from "./utils/theme";
@@ -236,8 +237,6 @@ async function generateCodeArtifacts(
236
237
  runtimeConfig?: RuntimeConfig;
237
238
  },
238
239
  ): Promise<GeneratedArtifacts | null> {
239
- writePluginSidebarGen(configDir, config);
240
-
241
240
  if (opts?.env) {
242
241
  writeResolvedConfig(configDir, config, opts.env, opts.extendsChain);
243
242
  }
@@ -245,6 +244,8 @@ async function generateCodeArtifacts(
245
244
  const runtimeConfig = opts?.runtimeConfig ?? (await loadConfig({ cwd: configDir }))?.runtime;
246
245
  if (!runtimeConfig) return null;
247
246
 
247
+ writePluginSidebarGen(configDir, runtimeConfig);
248
+
248
249
  const bridge = await syncApiContractBridge({
249
250
  configDir,
250
251
  runtimeConfig,
@@ -646,92 +647,32 @@ export default createPlugin({
646
647
  const version = manifest?.plugin.version ?? pkgJson.version;
647
648
 
648
649
  if (publishedUrl) {
649
- const pluginConfigPath = join(localPath, "bos.config.json");
650
- if (existsSync(pluginConfigPath)) {
651
- try {
652
- const pluginConfig = JSON.parse(readFileSync(pluginConfigPath, "utf-8")) as Record<
653
- string,
654
- unknown
655
- >;
656
- if (!pluginConfig.app) pluginConfig.app = {};
657
- const app = pluginConfig.app as Record<string, unknown>;
658
- if (!app.api) app.api = {};
659
- const api = app.api as Record<string, unknown>;
660
- api.production = publishedUrl;
661
- if (integrity) {
662
- api.integrity = integrity;
663
- } else {
664
- delete api.integrity;
665
- }
666
- writeFileSync(pluginConfigPath, `${JSON.stringify(pluginConfig, null, 2)}\n`);
667
- console.log(` ✅ Updated ${pluginConfigPath}: app.api.production`);
668
- } catch (err) {
669
- console.error(
670
- ` ❌ Failed to update plugin bos.config.json:`,
671
- err instanceof Error ? err.message : err,
672
- );
673
- }
674
- }
675
-
676
- const account = deps.bosConfig.account;
677
- const network = getNetworkIdForAccount(account);
678
-
679
- let pluginDomain: string | undefined;
680
- if (existsSync(pluginConfigPath)) {
681
- try {
682
- const pluginConfig = JSON.parse(readFileSync(pluginConfigPath, "utf-8"));
683
- if (typeof pluginConfig.domain === "string") {
684
- pluginDomain = pluginConfig.domain;
685
- }
686
- } catch {}
687
- }
688
- if (!pluginDomain) {
689
- pluginDomain = `${input.key}.${deps.bosConfig.domain ?? "everything.dev"}`;
690
- }
691
-
650
+ const rootConfigPath = join(deps.configDir, "bos.config.json");
692
651
  try {
693
- const registryEntries: Record<string, string> = {};
694
-
695
- if (existsSync(pluginConfigPath)) {
696
- try {
697
- const publishedPluginConfig = JSON.parse(readFileSync(pluginConfigPath, "utf-8"));
698
- delete publishedPluginConfig.development;
699
- registryEntries[`apps/${account}/${pluginDomain}/bos.config.json`] =
700
- JSON.stringify(publishedPluginConfig);
701
- } catch {}
652
+ const rootConfig = JSON.parse(readFileSync(rootConfigPath, "utf-8")) as Record<
653
+ string,
654
+ unknown
655
+ >;
656
+ if (!rootConfig.plugins || typeof rootConfig.plugins !== "object") {
657
+ rootConfig.plugins = {};
702
658
  }
703
-
704
- if (Object.keys(registryEntries).length > 0) {
705
- const payload = JSON.stringify(registryEntries);
706
- const argsBase64 = Buffer.from(payload).toString("base64");
707
- const privateKey = process.env.NEAR_PRIVATE_KEY || process.env.BOS_NEAR_PRIVATE_KEY;
708
-
709
- await Effect.runPromise(ensureNearCli);
710
- try {
711
- await Effect.runPromise(
712
- executeTransaction({
713
- account,
714
- contract: getRegistryNamespaceForNetwork(network),
715
- method: "__fastdata_kv",
716
- argsBase64,
717
- network,
718
- privateKey,
719
- gas: "50Tgas",
720
- deposit: "0NEAR",
721
- }),
722
- );
723
- } catch (registryError) {
724
- const txHash = extractTransactionHash(registryError);
725
- if (!txHash) {
726
- console.warn(
727
- `[publish] Plugin registry write failed: ${registryError instanceof Error ? registryError.message : registryError}`,
728
- );
729
- }
730
- }
659
+ const plugins = rootConfig.plugins as Record<string, unknown>;
660
+ if (!plugins[input.key] || typeof plugins[input.key] !== "object") {
661
+ plugins[input.key] = {};
731
662
  }
732
- } catch (registryError) {
733
- console.warn(
734
- `[publish] Plugin registry write skipped: ${registryError instanceof Error ? registryError.message : registryError}`,
663
+ const entry = plugins[input.key] as Record<string, unknown>;
664
+ entry.production = publishedUrl;
665
+ if (integrity) {
666
+ entry.integrity = integrity;
667
+ } else {
668
+ delete entry.integrity;
669
+ }
670
+ writeFileSync(rootConfigPath, `${JSON.stringify(rootConfig, null, 2)}\n`);
671
+ console.log(` ✅ Updated bos.config.json: plugins.${input.key}.production`);
672
+ } catch (err) {
673
+ console.error(
674
+ ` ❌ Failed to update bos.config.json:`,
675
+ err instanceof Error ? err.message : err,
735
676
  );
736
677
  }
737
678
 
@@ -1139,29 +1080,6 @@ export default createPlugin({
1139
1080
  [`apps/${account}/${gateway}/bos.config.json`]: JSON.stringify(publishConfig),
1140
1081
  };
1141
1082
 
1142
- for (const [pluginKey, pluginEntry] of Object.entries(publishConfig.plugins ?? {})) {
1143
- const pluginRef = getPluginRef(pluginEntry);
1144
- if (!pluginRef?.development?.startsWith("local:")) continue;
1145
-
1146
- const localPath = join(deps.configDir, pluginRef.development.slice("local:".length));
1147
- const pluginConfigPath = join(localPath, "bos.config.json");
1148
- if (!existsSync(pluginConfigPath)) continue;
1149
-
1150
- try {
1151
- const pluginConfig = JSON.parse(readFileSync(pluginConfigPath, "utf-8")) as Record<
1152
- string,
1153
- unknown
1154
- >;
1155
- const pluginDomain =
1156
- typeof pluginConfig.domain === "string"
1157
- ? pluginConfig.domain
1158
- : `${pluginKey}.${gateway}`;
1159
- delete pluginConfig.development;
1160
- registryEntries[`apps/${account}/${pluginDomain}/bos.config.json`] =
1161
- JSON.stringify(pluginConfig);
1162
- } catch {}
1163
- }
1164
-
1165
1083
  const payload = JSON.stringify(registryEntries);
1166
1084
  const argsBase64 = Buffer.from(payload).toString("base64");
1167
1085
  const privateKey =
@@ -1273,8 +1191,8 @@ export default createPlugin({
1273
1191
  init: builder.init.handler(async ({ input }) => {
1274
1192
  try {
1275
1193
  const timings: PhaseTiming[] = [];
1276
- let extendsAccount = input.extendsAccount;
1277
- let extendsGateway = input.extendsGateway;
1194
+ let extendsAccount = "";
1195
+ let extendsGateway = "";
1278
1196
  let directory = input.directory;
1279
1197
  let account = input.account;
1280
1198
  let domain = input.domain;
@@ -1282,10 +1200,13 @@ export default createPlugin({
1282
1200
  let plugins = input.plugins;
1283
1201
 
1284
1202
  if (input.extends) {
1285
- const match = input.extends.match(/^(?:bos:\/\/)?([^/]+)\/(.+)$/);
1203
+ const normalized = input.extends.startsWith("bos://")
1204
+ ? input.extends
1205
+ : `bos://${input.extends}`;
1206
+ const match = normalized.match(/^bos:\/\/([^/]+)\/(.+)$/);
1286
1207
  if (match) {
1287
- if (!extendsAccount) extendsAccount = match[1];
1288
- if (!extendsGateway) extendsGateway = match[2];
1208
+ extendsAccount = match[1];
1209
+ extendsGateway = match[2];
1289
1210
  }
1290
1211
  }
1291
1212
 
@@ -1296,7 +1217,7 @@ export default createPlugin({
1296
1217
  let parentConfig: BosConfig | null = null;
1297
1218
  try {
1298
1219
  parentConfig = await timePhase(timings, "parent config", () =>
1299
- fetchParentConfig(extendsAccount!, extendsGateway!),
1220
+ fetchParentConfig(extendsAccount, extendsGateway),
1300
1221
  );
1301
1222
  if (parentConfig?.plugins && typeof parentConfig.plugins === "object") {
1302
1223
  parentPluginKeys = Object.keys(parentConfig.plugins);
@@ -1305,9 +1226,7 @@ export default createPlugin({
1305
1226
 
1306
1227
  if (!input.noInteractive) {
1307
1228
  const prompted = await promptInitOptions({
1308
- extendsAccount,
1309
- extendsGateway,
1310
- extends: input.extends,
1229
+ extends: `bos://${extendsAccount}/${extendsGateway}`,
1311
1230
  directory,
1312
1231
  account,
1313
1232
  domain,
@@ -1327,25 +1246,25 @@ export default createPlugin({
1327
1246
  directory = directory || domain || extendsGateway;
1328
1247
  const targetDir = resolve(directory);
1329
1248
  plugins = plugins ?? [];
1249
+ const extendsRef = `bos://${extendsAccount}/${extendsGateway}`;
1330
1250
 
1331
1251
  if (!parentConfig) {
1332
1252
  try {
1333
1253
  parentConfig = await timePhase(timings, "parent config", () =>
1334
- fetchParentConfig(extendsAccount!, extendsGateway!),
1254
+ fetchParentConfig(extendsAccount, extendsGateway),
1335
1255
  );
1336
1256
  } catch {
1337
1257
  return {
1338
1258
  status: "error" as const,
1339
1259
  directory,
1340
- extendsAccount,
1341
- extendsGateway,
1260
+ extendsRef,
1342
1261
  account,
1343
1262
  domain,
1344
- extends: `bos://${extendsAccount}/${extendsGateway}`,
1263
+ extends: extendsRef,
1345
1264
  plugins: plugins ?? [],
1346
1265
  filesCopied: 0,
1347
1266
  timings,
1348
- error: `No config found at bos://${extendsAccount}/${extendsGateway} — are you sure this is the right parent?`,
1267
+ error: `No config found at ${extendsRef} — are you sure this is the right parent?`,
1349
1268
  };
1350
1269
  }
1351
1270
  }
@@ -1364,64 +1283,82 @@ export default createPlugin({
1364
1283
 
1365
1284
  parentConfig = resolvedParentConfig;
1366
1285
 
1286
+ const isMinimalScaffold = sourceDir === "";
1287
+
1367
1288
  try {
1368
- const patterns = await readTemplatekeep(sourceDir);
1369
- if (patterns.length === 0) {
1370
- return {
1371
- status: "error" as const,
1372
- directory,
1373
- extendsAccount,
1374
- extendsGateway,
1375
- account,
1376
- domain,
1377
- extends: `bos://${extendsAccount}/${extendsGateway}`,
1378
- plugins: plugins ?? [],
1379
- filesCopied: 0,
1380
- error: "No .templatekeep found in template source",
1381
- };
1382
- }
1289
+ const s = p.spinner();
1290
+ s.start("Setting up project");
1383
1291
 
1384
- const pluginRoutes: Record<string, string[]> = {};
1385
- if (parentConfig.plugins) {
1386
- for (const [key, entry] of Object.entries(parentConfig.plugins)) {
1387
- const entryRef = getPluginRef(entry);
1388
- if (entryRef?.routes && entryRef.routes.length > 0) {
1389
- pluginRoutes[key] = entryRef.routes;
1390
- }
1292
+ let filesCopied: number;
1293
+
1294
+ if (isMinimalScaffold) {
1295
+ filesCopied = await timePhase(timings, "scaffold project", () =>
1296
+ scaffoldMinimalProject(targetDir, parentConfig as unknown as BosConfigInput, {
1297
+ extendsAccount,
1298
+ extendsGateway,
1299
+ account: account || extendsAccount,
1300
+ domain,
1301
+ plugins,
1302
+ withHost,
1303
+ }),
1304
+ );
1305
+ } else {
1306
+ const patterns = await readTemplatekeep(sourceDir);
1307
+ if (patterns.length === 0) {
1308
+ return {
1309
+ status: "error" as const,
1310
+ directory,
1311
+ extendsRef,
1312
+ account,
1313
+ domain,
1314
+ extends: extendsRef,
1315
+ plugins: plugins ?? [],
1316
+ filesCopied: 0,
1317
+ error: "No .templatekeep found in template source",
1318
+ };
1391
1319
  }
1392
- }
1393
1320
 
1394
- const s = p.spinner();
1395
- s.start("Setting up project");
1321
+ const pluginRoutes: Record<string, string[]> = {};
1322
+ const parentRuntimePlugins = await buildRuntimePluginsForConfig(
1323
+ parentConfig as BosConfig,
1324
+ sourceDir,
1325
+ "production",
1326
+ );
1327
+ for (const [key, plugin] of Object.entries(parentRuntimePlugins ?? {})) {
1328
+ if (plugin.routes && plugin.routes.length > 0) {
1329
+ pluginRoutes[key] = plugin.routes;
1330
+ }
1331
+ }
1396
1332
 
1397
- const filesCopied = await timePhase(timings, "copy files", () =>
1398
- copyFilteredFiles(sourceDir, targetDir, patterns, {
1399
- withHost,
1400
- plugins,
1401
- pluginRoutes,
1402
- }),
1403
- );
1333
+ filesCopied = await timePhase(timings, "copy files", () =>
1334
+ copyFilteredFiles(sourceDir, targetDir, patterns, {
1335
+ withHost,
1336
+ plugins,
1337
+ pluginRoutes,
1338
+ }),
1339
+ );
1404
1340
 
1405
- await timePhase(timings, "personalize config", () =>
1406
- personalizeConfig(targetDir, {
1407
- extendsAccount,
1408
- extendsGateway,
1409
- account: account || extendsAccount,
1410
- domain: domain || extendsGateway,
1411
- plugins,
1412
- pluginRoutes,
1413
- workspaceOpts: { sourceDir },
1414
- withHost,
1415
- }),
1416
- );
1341
+ await timePhase(timings, "personalize config", () =>
1342
+ personalizeConfig(targetDir, {
1343
+ extendsAccount,
1344
+ extendsGateway,
1345
+ account: account || extendsAccount,
1346
+ domain: domain || extendsGateway,
1347
+ plugins,
1348
+ pluginRoutes,
1349
+ workspaceOpts: { sourceDir },
1350
+ withHost,
1351
+ }),
1352
+ );
1417
1353
 
1418
- await timePhase(timings, "write snapshot", () =>
1419
- writeInitSnapshot(targetDir, extendsAccount, extendsGateway, sourceDir, patterns, {
1420
- withHost,
1421
- plugins,
1422
- pluginRoutes,
1423
- }),
1424
- );
1354
+ await timePhase(timings, "write snapshot", () =>
1355
+ writeInitSnapshot(targetDir, extendsAccount, extendsGateway, sourceDir, patterns, {
1356
+ withHost,
1357
+ plugins,
1358
+ pluginRoutes,
1359
+ }),
1360
+ );
1361
+ }
1425
1362
 
1426
1363
  const initConfig = await timePhase(timings, "resolve config", () =>
1427
1364
  loadConfig({ cwd: targetDir }),
@@ -1475,11 +1412,10 @@ export default createPlugin({
1475
1412
  return {
1476
1413
  status: "initialized" as const,
1477
1414
  directory,
1478
- extendsAccount,
1479
- extendsGateway,
1415
+ extendsRef,
1480
1416
  account,
1481
1417
  domain,
1482
- extends: `bos://${extendsAccount}/${extendsGateway}`,
1418
+ extends: extendsRef,
1483
1419
  plugins,
1484
1420
  filesCopied,
1485
1421
  timings,
@@ -1488,17 +1424,18 @@ export default createPlugin({
1488
1424
  await cleanup();
1489
1425
  }
1490
1426
  } catch (error) {
1427
+ const extendsRef = input.extends
1428
+ ? input.extends.startsWith("bos://")
1429
+ ? input.extends
1430
+ : `bos://${input.extends}`
1431
+ : "bos://dev.everything.near/everything.dev";
1491
1432
  return {
1492
1433
  status: "error" as const,
1493
1434
  directory: input.directory ?? "",
1494
- extendsAccount: input.extendsAccount ?? "",
1495
- extendsGateway: input.extendsGateway ?? "",
1435
+ extendsRef,
1496
1436
  account: input.account,
1497
1437
  domain: input.domain,
1498
- extends:
1499
- input.extendsAccount && input.extendsGateway
1500
- ? `bos://${input.extendsAccount}/${input.extendsGateway}`
1501
- : "",
1438
+ extends: extendsRef,
1502
1439
  plugins: input.plugins ?? [],
1503
1440
  filesCopied: 0,
1504
1441
  timings: [],
package/src/sidebar.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
2
  import { dirname, join } from "node:path";
3
- import type { BosConfig, SidebarItem } from "./types";
3
+ import type { RuntimeConfig, SidebarItem } from "./types";
4
4
 
5
5
  const ICON_IMPORTS: Record<string, string> = {
6
6
  Home: "lucide-react",
@@ -51,11 +51,11 @@ function collectIconImports(items: SidebarItem[]): Map<string, Set<string>> {
51
51
  return moduleMap;
52
52
  }
53
53
 
54
- export function generatePluginSidebarContent(config: BosConfig, configDir?: string): string {
54
+ export function generatePluginSidebarContent(runtimeConfig: RuntimeConfig): string {
55
55
  const coreItems: SidebarItem[] = [{ icon: "Home", label: "home", to: "/", roleRequired: "anon" }];
56
56
 
57
- if (config.app.auth?.sidebar) {
58
- for (const item of config.app.auth.sidebar) {
57
+ if (runtimeConfig.auth?.sidebar) {
58
+ for (const item of runtimeConfig.auth.sidebar) {
59
59
  coreItems.push({
60
60
  ...item,
61
61
  to: item.to ?? "/auth",
@@ -65,31 +65,9 @@ export function generatePluginSidebarContent(config: BosConfig, configDir?: stri
65
65
  }
66
66
 
67
67
  const pluginItems: SidebarItem[] = [];
68
- if (config.plugins) {
69
- for (const [key, entry] of Object.entries(config.plugins)) {
70
- let sidebar: SidebarItem[] | undefined;
71
-
72
- if (typeof entry === "object" && entry.sidebar) {
73
- sidebar = entry.sidebar;
74
- } else if (
75
- typeof entry === "object" &&
76
- entry.development?.startsWith("local:") &&
77
- configDir
78
- ) {
79
- const localPath = join(configDir, entry.development.slice("local:".length).trim());
80
- const pluginConfigPath = join(localPath, "bos.config.json");
81
- if (existsSync(pluginConfigPath)) {
82
- try {
83
- const pluginConfig = JSON.parse(readFileSync(pluginConfigPath, "utf-8")) as {
84
- sidebar?: SidebarItem[];
85
- };
86
- if (pluginConfig.sidebar) {
87
- sidebar = pluginConfig.sidebar;
88
- }
89
- } catch {}
90
- }
91
- }
92
-
68
+ if (runtimeConfig.plugins) {
69
+ for (const [key, entry] of Object.entries(runtimeConfig.plugins)) {
70
+ const sidebar = entry.sidebar;
93
71
  if (!sidebar) continue;
94
72
  for (const item of sidebar) {
95
73
  pluginItems.push({
@@ -135,10 +113,10 @@ ${itemsCode}
135
113
  `;
136
114
  }
137
115
 
138
- export function writePluginSidebarGen(configDir: string, config: BosConfig): string {
116
+ export function writePluginSidebarGen(configDir: string, runtimeConfig: RuntimeConfig): string {
139
117
  const outputPath = join(configDir, "ui/src/lib/plugin-sidebar.gen.ts");
140
118
 
141
- const content = generatePluginSidebarContent(config, configDir);
119
+ const content = generatePluginSidebarContent(runtimeConfig);
142
120
 
143
121
  const outputDir = dirname(outputPath);
144
122
  if (!existsSync(outputDir)) {
package/src/types.ts CHANGED
@@ -46,8 +46,9 @@ export const SidebarItemSchema = z.object({
46
46
  });
47
47
  export type SidebarItem = z.infer<typeof SidebarItemSchema>;
48
48
 
49
- export const ApiPluginConfigSchema = z.object({
50
- name: z.string(),
49
+ export const ComposableAppEntrySchema = z.object({
50
+ extends: ExtendsSchema.optional(),
51
+ name: z.string().optional(),
51
52
  development: z.string().optional(),
52
53
  production: z.string().optional(),
53
54
  integrity: z.string().optional(),
@@ -55,7 +56,11 @@ export const ApiPluginConfigSchema = z.object({
55
56
  variables: z.record(z.string(), z.string()).optional(),
56
57
  secrets: z.array(z.string()).optional(),
57
58
  sidebar: z.array(SidebarItemSchema).optional(),
59
+ routes: z.array(z.string()).optional(),
58
60
  });
61
+ export type ComposableAppEntry = z.infer<typeof ComposableAppEntrySchema>;
62
+
63
+ export const ApiPluginConfigSchema = ComposableAppEntrySchema;
59
64
  export type ApiPluginConfig = z.infer<typeof ApiPluginConfigSchema>;
60
65
 
61
66
  export const PluginUiConfigSchema = z.object({
@@ -66,18 +71,8 @@ export const PluginUiConfigSchema = z.object({
66
71
  });
67
72
  export type PluginUiConfig = z.infer<typeof PluginUiConfigSchema>;
68
73
 
69
- export const BosPluginRefSchema = z.object({
70
- extends: ExtendsSchema.optional(),
71
- development: z.string().optional(),
72
- production: z.string().optional(),
73
- integrity: z.string().optional(),
74
- name: z.string().optional(),
74
+ export const BosPluginRefSchema = ComposableAppEntrySchema.extend({
75
75
  version: z.string().optional(),
76
- proxy: z.string().optional(),
77
- variables: z.record(z.string(), z.string()).optional(),
78
- secrets: z.array(z.string()).optional(),
79
- routes: z.array(z.string()).optional(),
80
- sidebar: z.array(SidebarItemSchema).optional(),
81
76
  app: z.record(z.string(), z.unknown()).optional(),
82
77
  shared: z.record(z.string(), z.record(z.string(), SharedConfigSchema)).optional(),
83
78
  plugins: z.record(z.string(), z.unknown()).optional(),
@@ -222,8 +217,8 @@ export const BosConfigSchema = z.object({
222
217
  app: z.object({
223
218
  host: HostConfigSchema,
224
219
  ui: UiConfigSchema,
225
- api: ApiPluginConfigSchema,
226
- auth: ApiPluginConfigSchema.optional(),
220
+ api: ComposableAppEntrySchema,
221
+ auth: ComposableAppEntrySchema.optional(),
227
222
  }),
228
223
  });
229
224
  export type BosConfig = z.infer<typeof BosConfigSchema>;