everything-dev 1.16.2 → 1.17.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 (95) hide show
  1. package/dist/api-contract.cjs +16 -5
  2. package/dist/api-contract.cjs.map +1 -1
  3. package/dist/api-contract.mjs +16 -5
  4. package/dist/api-contract.mjs.map +1 -1
  5. package/dist/cli/init.cjs +50 -51
  6. package/dist/cli/init.cjs.map +1 -1
  7. package/dist/cli/init.d.cts.map +1 -1
  8. package/dist/cli/init.d.mts.map +1 -1
  9. package/dist/cli/init.mjs +50 -51
  10. package/dist/cli/init.mjs.map +1 -1
  11. package/dist/cli/sync.cjs +3 -5
  12. package/dist/cli/sync.cjs.map +1 -1
  13. package/dist/cli/sync.mjs +3 -5
  14. package/dist/cli/sync.mjs.map +1 -1
  15. package/dist/cli/timing.cjs +30 -0
  16. package/dist/cli/timing.cjs.map +1 -0
  17. package/dist/cli/timing.mjs +27 -0
  18. package/dist/cli/timing.mjs.map +1 -0
  19. package/dist/cli/upgrade.cjs +214 -48
  20. package/dist/cli/upgrade.cjs.map +1 -1
  21. package/dist/cli/upgrade.mjs +214 -48
  22. package/dist/cli/upgrade.mjs.map +1 -1
  23. package/dist/cli.cjs +9 -0
  24. package/dist/cli.cjs.map +1 -1
  25. package/dist/cli.mjs +9 -0
  26. package/dist/cli.mjs.map +1 -1
  27. package/dist/components/dev-view.cjs +1 -1
  28. package/dist/components/dev-view.mjs +1 -1
  29. package/dist/components/streaming-view.cjs +1 -1
  30. package/dist/components/streaming-view.mjs +1 -1
  31. package/dist/config.cjs +125 -74
  32. package/dist/config.cjs.map +1 -1
  33. package/dist/config.d.cts +9 -2
  34. package/dist/config.d.cts.map +1 -1
  35. package/dist/config.d.mts +9 -2
  36. package/dist/config.d.mts.map +1 -1
  37. package/dist/config.mjs +126 -76
  38. package/dist/config.mjs.map +1 -1
  39. package/dist/contract.cjs +7 -0
  40. package/dist/contract.cjs.map +1 -1
  41. package/dist/contract.d.cts +58 -13
  42. package/dist/contract.d.cts.map +1 -1
  43. package/dist/contract.d.mts +58 -13
  44. package/dist/contract.d.mts.map +1 -1
  45. package/dist/contract.mjs +7 -1
  46. package/dist/contract.mjs.map +1 -1
  47. package/dist/dev-session.cjs +5 -3
  48. package/dist/dev-session.cjs.map +1 -1
  49. package/dist/dev-session.mjs +3 -3
  50. package/dist/dev-session.mjs.map +1 -1
  51. package/dist/index.cjs +3 -0
  52. package/dist/index.d.cts +4 -4
  53. package/dist/index.d.mts +4 -4
  54. package/dist/index.mjs +4 -4
  55. package/dist/merge.cjs +1 -0
  56. package/dist/merge.mjs +1 -1
  57. package/dist/orchestrator.cjs +1 -1
  58. package/dist/orchestrator.mjs +1 -1
  59. package/dist/plugin.cjs +49 -37
  60. package/dist/plugin.cjs.map +1 -1
  61. package/dist/plugin.d.cts +44 -12
  62. package/dist/plugin.d.cts.map +1 -1
  63. package/dist/plugin.d.mts +44 -12
  64. package/dist/plugin.d.mts.map +1 -1
  65. package/dist/plugin.mjs +48 -36
  66. package/dist/plugin.mjs.map +1 -1
  67. package/dist/sidebar.cjs +6 -14
  68. package/dist/sidebar.cjs.map +1 -1
  69. package/dist/sidebar.d.cts +3 -3
  70. package/dist/sidebar.d.cts.map +1 -1
  71. package/dist/sidebar.d.mts +3 -3
  72. package/dist/sidebar.d.mts.map +1 -1
  73. package/dist/sidebar.mjs +6 -14
  74. package/dist/sidebar.mjs.map +1 -1
  75. package/dist/types.cjs +10 -16
  76. package/dist/types.cjs.map +1 -1
  77. package/dist/types.d.cts +56 -12
  78. package/dist/types.d.cts.map +1 -1
  79. package/dist/types.d.mts +56 -12
  80. package/dist/types.d.mts.map +1 -1
  81. package/dist/types.mjs +10 -17
  82. package/dist/types.mjs.map +1 -1
  83. package/package.json +1 -1
  84. package/src/api-contract.ts +21 -3
  85. package/src/cli/init.ts +95 -63
  86. package/src/cli/sync.ts +5 -8
  87. package/src/cli/timing.ts +36 -0
  88. package/src/cli/upgrade.ts +292 -56
  89. package/src/cli.ts +15 -0
  90. package/src/config.ts +250 -107
  91. package/src/contract.ts +8 -0
  92. package/src/dev-session.ts +1 -1
  93. package/src/plugin.ts +97 -54
  94. package/src/sidebar.ts +9 -31
  95. package/src/types.ts +10 -15
package/src/plugin.ts CHANGED
@@ -20,6 +20,7 @@ import {
20
20
  import { promptInitOptions } from "./cli/prompts";
21
21
  import { getStatus } from "./cli/status";
22
22
  import { syncTemplate } from "./cli/sync";
23
+ import { timePhase } from "./cli/timing";
23
24
  import { upgradeTemplate } from "./cli/upgrade";
24
25
  import {
25
26
  buildRuntimePluginsForConfig,
@@ -30,8 +31,12 @@ import {
30
31
  resolveLocalDevelopmentPath,
31
32
  writeResolvedConfig,
32
33
  } from "./config";
33
- import { type BosConfigResult, bosContract, type PluginListResult } from "./contract";
34
- import { devApp, startApp } from "./dev-session";
34
+ import {
35
+ type BosConfigResult,
36
+ bosContract,
37
+ type PhaseTiming,
38
+ type PluginListResult,
39
+ } from "./contract";
35
40
  import {
36
41
  buildRegistryConfigUrl,
37
42
  buildRegistryConfigUrlForNetwork,
@@ -58,6 +63,10 @@ import { run } from "./utils/run";
58
63
  import { saveBosConfig } from "./utils/save-config";
59
64
  import { colors } from "./utils/theme";
60
65
 
66
+ async function loadDevSession() {
67
+ return import("./dev-session");
68
+ }
69
+
61
70
  const buildCommands: Record<string, { cmd: string; args: string[] }> = {
62
71
  host: { cmd: "bun", args: ["run", "build"] },
63
72
  ui: { cmd: "bun", args: ["run", "build"] },
@@ -227,8 +236,6 @@ async function generateCodeArtifacts(
227
236
  runtimeConfig?: RuntimeConfig;
228
237
  },
229
238
  ): Promise<GeneratedArtifacts | null> {
230
- writePluginSidebarGen(configDir, config);
231
-
232
239
  if (opts?.env) {
233
240
  writeResolvedConfig(configDir, config, opts.env, opts.extendsChain);
234
241
  }
@@ -236,6 +243,8 @@ async function generateCodeArtifacts(
236
243
  const runtimeConfig = opts?.runtimeConfig ?? (await loadConfig({ cwd: configDir }))?.runtime;
237
244
  if (!runtimeConfig) return null;
238
245
 
246
+ writePluginSidebarGen(configDir, runtimeConfig);
247
+
239
248
  const bridge = await syncApiContractBridge({
240
249
  configDir,
241
250
  runtimeConfig,
@@ -644,18 +653,22 @@ export default createPlugin({
644
653
  string,
645
654
  unknown
646
655
  >;
647
- if (!pluginConfig.app) pluginConfig.app = {};
648
- const app = pluginConfig.app as Record<string, unknown>;
649
- if (!app.api) app.api = {};
650
- const api = app.api as Record<string, unknown>;
651
- api.production = publishedUrl;
656
+ if (!pluginConfig.plugins || typeof pluginConfig.plugins !== "object") {
657
+ pluginConfig.plugins = {};
658
+ }
659
+ const plugins = pluginConfig.plugins as Record<string, unknown>;
660
+ if (!plugins[input.key] || typeof plugins[input.key] !== "object") {
661
+ plugins[input.key] = {};
662
+ }
663
+ const entry = plugins[input.key] as Record<string, unknown>;
664
+ entry.production = publishedUrl;
652
665
  if (integrity) {
653
- api.integrity = integrity;
666
+ entry.integrity = integrity;
654
667
  } else {
655
- delete api.integrity;
668
+ delete entry.integrity;
656
669
  }
657
670
  writeFileSync(pluginConfigPath, `${JSON.stringify(pluginConfig, null, 2)}\n`);
658
- console.log(` ✅ Updated ${pluginConfigPath}: app.api.production`);
671
+ console.log(` ✅ Updated ${pluginConfigPath}: plugins.${input.key}.production`);
659
672
  } catch (err) {
660
673
  console.error(
661
674
  ` ❌ Failed to update plugin bos.config.json:`,
@@ -838,6 +851,7 @@ export default createPlugin({
838
851
  interactive: input.interactive,
839
852
  };
840
853
 
854
+ const { devApp } = await loadDevSession();
841
855
  devApp(orchestrator, services, runtimeConfig);
842
856
 
843
857
  return {
@@ -998,6 +1012,7 @@ export default createPlugin({
998
1012
  noLogs: true,
999
1013
  };
1000
1014
 
1015
+ const { startApp } = await loadDevSession();
1001
1016
  startApp(orchestrator, services, runtimeConfig);
1002
1017
  return {
1003
1018
  status: "running" as const,
@@ -1261,6 +1276,7 @@ export default createPlugin({
1261
1276
 
1262
1277
  init: builder.init.handler(async ({ input }) => {
1263
1278
  try {
1279
+ const timings: PhaseTiming[] = [];
1264
1280
  let extendsAccount = input.extendsAccount;
1265
1281
  let extendsGateway = input.extendsGateway;
1266
1282
  let directory = input.directory;
@@ -1283,7 +1299,9 @@ export default createPlugin({
1283
1299
  let parentPluginKeys: string[] = [];
1284
1300
  let parentConfig: BosConfig | null = null;
1285
1301
  try {
1286
- parentConfig = await fetchParentConfig(extendsAccount, extendsGateway);
1302
+ parentConfig = await timePhase(timings, "parent config", () =>
1303
+ fetchParentConfig(extendsAccount!, extendsGateway!),
1304
+ );
1287
1305
  if (parentConfig?.plugins && typeof parentConfig.plugins === "object") {
1288
1306
  parentPluginKeys = Object.keys(parentConfig.plugins);
1289
1307
  }
@@ -1316,7 +1334,9 @@ export default createPlugin({
1316
1334
 
1317
1335
  if (!parentConfig) {
1318
1336
  try {
1319
- parentConfig = await fetchParentConfig(extendsAccount, extendsGateway);
1337
+ parentConfig = await timePhase(timings, "parent config", () =>
1338
+ fetchParentConfig(extendsAccount!, extendsGateway!),
1339
+ );
1320
1340
  } catch {
1321
1341
  return {
1322
1342
  status: "error" as const,
@@ -1328,6 +1348,7 @@ export default createPlugin({
1328
1348
  extends: `bos://${extendsAccount}/${extendsGateway}`,
1329
1349
  plugins: plugins ?? [],
1330
1350
  filesCopied: 0,
1351
+ timings,
1331
1352
  error: `No config found at bos://${extendsAccount}/${extendsGateway} — are you sure this is the right parent?`,
1332
1353
  };
1333
1354
  }
@@ -1337,11 +1358,13 @@ export default createPlugin({
1337
1358
  sourceDir,
1338
1359
  parentConfig: resolvedParentConfig,
1339
1360
  cleanup,
1340
- } = await resolveSourceDir({
1341
- extendsAccount,
1342
- extendsGateway,
1343
- source: input.source,
1344
- });
1361
+ } = await timePhase(timings, "template source", () =>
1362
+ resolveSourceDir({
1363
+ extendsAccount,
1364
+ extendsGateway,
1365
+ source: input.source,
1366
+ }),
1367
+ );
1345
1368
 
1346
1369
  parentConfig = resolvedParentConfig;
1347
1370
 
@@ -1363,55 +1386,73 @@ export default createPlugin({
1363
1386
  }
1364
1387
 
1365
1388
  const pluginRoutes: Record<string, string[]> = {};
1366
- if (parentConfig.plugins) {
1367
- for (const [key, entry] of Object.entries(parentConfig.plugins)) {
1368
- const entryRef = getPluginRef(entry);
1369
- if (entryRef?.routes && entryRef.routes.length > 0) {
1370
- pluginRoutes[key] = entryRef.routes;
1371
- }
1389
+ const parentRuntimePlugins = await buildRuntimePluginsForConfig(
1390
+ parentConfig as BosConfig,
1391
+ sourceDir,
1392
+ "production",
1393
+ );
1394
+ for (const [key, plugin] of Object.entries(parentRuntimePlugins ?? {})) {
1395
+ if (plugin.routes && plugin.routes.length > 0) {
1396
+ pluginRoutes[key] = plugin.routes;
1372
1397
  }
1373
1398
  }
1374
1399
 
1375
1400
  const s = p.spinner();
1376
1401
  s.start("Setting up project");
1377
1402
 
1378
- const filesCopied = await copyFilteredFiles(sourceDir, targetDir, patterns, {
1379
- withHost,
1380
- plugins,
1381
- pluginRoutes,
1382
- });
1403
+ const filesCopied = await timePhase(timings, "copy files", () =>
1404
+ copyFilteredFiles(sourceDir, targetDir, patterns, {
1405
+ withHost,
1406
+ plugins,
1407
+ pluginRoutes,
1408
+ }),
1409
+ );
1383
1410
 
1384
- await personalizeConfig(targetDir, {
1385
- extendsAccount,
1386
- extendsGateway,
1387
- account: account || extendsAccount,
1388
- domain: domain || extendsGateway,
1389
- plugins,
1390
- pluginRoutes,
1391
- workspaceOpts: { sourceDir },
1392
- withHost,
1393
- });
1411
+ await timePhase(timings, "personalize config", () =>
1412
+ personalizeConfig(targetDir, {
1413
+ extendsAccount,
1414
+ extendsGateway,
1415
+ account: account || extendsAccount,
1416
+ domain: domain || extendsGateway,
1417
+ plugins,
1418
+ pluginRoutes,
1419
+ workspaceOpts: { sourceDir },
1420
+ withHost,
1421
+ }),
1422
+ );
1394
1423
 
1395
- await writeInitSnapshot(targetDir, extendsAccount, extendsGateway, sourceDir, patterns, {
1396
- withHost,
1397
- plugins,
1398
- pluginRoutes,
1399
- });
1424
+ await timePhase(timings, "write snapshot", () =>
1425
+ writeInitSnapshot(targetDir, extendsAccount, extendsGateway, sourceDir, patterns, {
1426
+ withHost,
1427
+ plugins,
1428
+ pluginRoutes,
1429
+ }),
1430
+ );
1400
1431
 
1401
- const initConfig = await loadConfig({ cwd: targetDir });
1432
+ const initConfig = await timePhase(timings, "resolve config", () =>
1433
+ loadConfig({ cwd: targetDir }),
1434
+ );
1402
1435
  if (initConfig?.runtime) {
1403
- writeGeneratedInfra(targetDir, initConfig.runtime);
1436
+ await timePhase(timings, "generate env/docker", async () => {
1437
+ writeGeneratedInfra(targetDir, initConfig.runtime);
1438
+ });
1404
1439
  }
1405
- ensureEnvFile(targetDir);
1440
+ await timePhase(timings, "create env file", async () => {
1441
+ ensureEnvFile(targetDir);
1442
+ });
1406
1443
 
1407
1444
  if (!input.noInstall) {
1408
- await runBunInstall(targetDir);
1409
- await runTypesGen(targetDir);
1410
- await generateDatabaseMigrations(targetDir);
1445
+ await timePhase(timings, "install dependencies", () => runBunInstall(targetDir));
1446
+ await timePhase(timings, "generate types", () => runTypesGen(targetDir));
1447
+ await timePhase(timings, "generate migrations", () =>
1448
+ generateDatabaseMigrations(targetDir),
1449
+ );
1411
1450
  }
1412
1451
 
1413
- if (initConfig?.config) {
1414
- await generateCodeArtifacts(targetDir, initConfig.config);
1452
+ if (input.noInstall && initConfig?.config) {
1453
+ await timePhase(timings, "generate code artifacts", () =>
1454
+ generateCodeArtifacts(targetDir, initConfig.config),
1455
+ );
1415
1456
  }
1416
1457
 
1417
1458
  s.stop("Project initialized");
@@ -1426,7 +1467,7 @@ export default createPlugin({
1426
1467
  const dockerSpinner = p.spinner();
1427
1468
  dockerSpinner.start("Starting Docker services");
1428
1469
  try {
1429
- await runDockerComposeUp(targetDir);
1470
+ await timePhase(timings, "docker compose up", () => runDockerComposeUp(targetDir));
1430
1471
  dockerSpinner.stop("Docker services ready");
1431
1472
  } catch (error) {
1432
1473
  dockerSpinner.stop("Docker services not started");
@@ -1447,6 +1488,7 @@ export default createPlugin({
1447
1488
  extends: `bos://${extendsAccount}/${extendsGateway}`,
1448
1489
  plugins,
1449
1490
  filesCopied,
1491
+ timings,
1450
1492
  };
1451
1493
  } finally {
1452
1494
  await cleanup();
@@ -1465,6 +1507,7 @@ export default createPlugin({
1465
1507
  : "",
1466
1508
  plugins: input.plugins ?? [],
1467
1509
  filesCopied: 0,
1510
+ timings: [],
1468
1511
  error: error instanceof Error ? error.message : "Unknown error",
1469
1512
  };
1470
1513
  }
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>;