@zenbujs/core 0.0.3 → 0.0.4

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 (84) hide show
  1. package/dist/{advice-config-CjgkEf2E.mjs → advice-config-BLXjqjGN.mjs} +21 -13
  2. package/dist/advice-config-D6K_a7e9.mjs +2 -0
  3. package/dist/advice.mjs +1 -1
  4. package/dist/{base-window-BUt8pwbw.mjs → base-window-D8CpxMU3.mjs} +2 -2
  5. package/dist/base-window-OXg2KSyP.mjs +2 -0
  6. package/dist/{build-config-pbv0w4oN.mjs → build-config-BwnnfrN-.mjs} +8 -2
  7. package/dist/{build-electron-BzHa_hRi.mjs → build-electron-C3Beey84.mjs} +12 -6
  8. package/dist/{build-source-CnTfQBGK.mjs → build-source-BvC4bPqH.mjs} +13 -8
  9. package/dist/cli/bin.mjs +12 -15
  10. package/dist/cli/build.d.mts +1 -52
  11. package/dist/cli/build.mjs +2 -47
  12. package/dist/cli/resolve-config.mjs +36 -0
  13. package/dist/{cli-BLbQQIVB.mjs → cli-F0B4dvSg.mjs} +3 -3
  14. package/dist/config-Ch1FreWU.mjs +2 -0
  15. package/dist/config.d.mts +2 -0
  16. package/dist/config.mjs +3 -0
  17. package/dist/db-Bz_CDIWg.mjs +2 -0
  18. package/dist/{db-BXadETOb.mjs → db-Cd5ETuPG.mjs} +47 -41
  19. package/dist/db.d.mts +1 -1
  20. package/dist/env-bootstrap.d.mts +1 -1
  21. package/dist/http-B36qtsm0.mjs +2 -0
  22. package/dist/index-CKKoxA9V.d.mts +1 -0
  23. package/dist/index.d.mts +5 -5
  24. package/dist/index.mjs +2 -2
  25. package/dist/{link-VOoGs-pY.mjs → link-BJmsKgPa.mjs} +87 -120
  26. package/dist/load-config-BG2tPIfF.mjs +126 -0
  27. package/dist/load-config-CQG4297M.mjs +2 -0
  28. package/dist/loaders/zenbu.d.mts +16 -0
  29. package/dist/loaders/zenbu.mjs +151 -62
  30. package/dist/{monorepo-CQeQBIpa.mjs → monorepo-DCruz9Jx.mjs} +2 -2
  31. package/dist/{publish-source-BJdpDAFH.mjs → publish-source-34Hn9zb0.mjs} +12 -6
  32. package/dist/react.d.mts +3 -3
  33. package/dist/{registry-Dh_e7HU1.d.mts → registry-CioEYLI5.d.mts} +1 -1
  34. package/dist/registry.d.mts +1 -1
  35. package/dist/{reloader-lLAJ3lqg.mjs → reloader-DJoCB0bC.mjs} +2 -2
  36. package/dist/reloader-FeHKV2jd.mjs +2 -0
  37. package/dist/renderer-host-BQpS0ZM2.mjs +2 -0
  38. package/dist/{renderer-host-Bg8QdeeH.mjs → renderer-host-ztaSIOGx.mjs} +71 -205
  39. package/dist/{rpc-BwwQK6hD.mjs → rpc-CsgWnlZx.mjs} +2 -2
  40. package/dist/rpc-D_s7-WZe.mjs +2 -0
  41. package/dist/rpc.d.mts +1 -1
  42. package/dist/{runtime-DUFKDIe4.mjs → runtime-C95iyVn6.mjs} +53 -1
  43. package/dist/{runtime-CjqDr8Yf.d.mts → runtime-CsiDppGF.d.mts} +41 -1
  44. package/dist/runtime.d.mts +2 -2
  45. package/dist/runtime.mjs +2 -2
  46. package/dist/{schema-DMoSkwUx.d.mts → schema-DvT61x2_.d.mts} +1 -1
  47. package/dist/schema.d.mts +1 -1
  48. package/dist/server-CgzQOPSW.mjs +2 -0
  49. package/dist/{server-BXwZEQ-n.mjs → server-DB3Eki_G.mjs} +1 -1
  50. package/dist/services/default.mjs +10 -10
  51. package/dist/services/index.d.mts +3 -3
  52. package/dist/services/index.mjs +6 -6
  53. package/dist/{setup-gate-BcoqWu8S.mjs → setup-gate-D8XfYY52.mjs} +35 -5
  54. package/dist/setup-gate.d.mts +1 -1
  55. package/dist/setup-gate.mjs +1 -1
  56. package/dist/transforms-DVoy8dCu.mjs +47 -0
  57. package/dist/transforms-EVd5Fgyk.d.mts +136 -0
  58. package/dist/view-registry-2zePxTEg.mjs +2 -0
  59. package/dist/{vite-plugins-Bh3SCOw-.mjs → vite-plugins-t4MlFcz3.mjs} +4 -18
  60. package/dist/vite.mjs +1 -1
  61. package/dist/{window-CmmpCVX6.mjs → window-DUvMTons.mjs} +3 -3
  62. package/dist/window-S3TlTXlK.mjs +2 -0
  63. package/package.json +9 -8
  64. package/dist/advice-config-Cy133IQP.mjs +0 -2
  65. package/dist/base-window-DEIAk618.mjs +0 -2
  66. package/dist/config-LK73dJmO.mjs +0 -2
  67. package/dist/db-ByKPbnP6.mjs +0 -2
  68. package/dist/http-IBcLzbYu.mjs +0 -2
  69. package/dist/load-build-config-DozuRhAN.mjs +0 -40
  70. package/dist/reloader-BCkLjDhS.mjs +0 -2
  71. package/dist/renderer-host-DpvBPTHJ.mjs +0 -2
  72. package/dist/rpc-CqitnyR4.mjs +0 -2
  73. package/dist/server-DjrZUbbu.mjs +0 -2
  74. package/dist/view-registry-BualWgAf.mjs +0 -2
  75. package/dist/window-CM2a9Kyc.mjs +0 -2
  76. package/dist/{index-FtE8MXJ_.d.mts → cli/resolve-config.d.mts} +0 -0
  77. package/dist/{config-CdVrW85P.mjs → config-BlRXeUXx.mjs} +0 -0
  78. package/dist/{dev-BU_llQh1.mjs → dev-DLutFPyo.mjs} +0 -0
  79. package/dist/{env-bootstrap-BtVME-CU.d.mts → env-bootstrap-uCKbw2q8.d.mts} +0 -0
  80. package/dist/{index-Bhlbyrn7.d.mts → index-CE0iPntP.d.mts} +0 -0
  81. package/dist/{index-CPZ5d6Hl.d.mts → index-UK58xuoR.d.mts} +0 -0
  82. package/dist/{mirror-sync-BN59kMCG.mjs → mirror-sync-EiWvdzTJ.mjs} +1 -1
  83. /package/dist/{node-D4M19_mV.mjs → node-CvZnTx53.mjs} +0 -0
  84. /package/dist/{setup-gate-BqOzm7zp.d.mts → setup-gate-D62nX5lk.d.mts} +0 -0
@@ -1,9 +1,9 @@
1
- import { i as runtime, t as Service } from "./runtime-DUFKDIe4.mjs";
1
+ import { a as getPlugins, r as getAppEntrypoint, t as Service, u as runtime } from "./runtime-C95iyVn6.mjs";
2
2
  import { o as getZodDefault } from "./schema-CIg4GzHQ.mjs";
3
3
  import { t as schema } from "./schema-dGK6qkfR.mjs";
4
4
  import { t as createLogger } from "./log-CyKv8hQg.mjs";
5
- import { t as ServerService } from "./server-BXwZEQ-n.mjs";
6
- import { n as DB_CONFIG_JSON, r as INTERNAL_DIR, t as ReloaderService } from "./reloader-lLAJ3lqg.mjs";
5
+ import { t as ServerService } from "./server-DB3Eki_G.mjs";
6
+ import { n as DB_CONFIG_JSON, r as INTERNAL_DIR, t as ReloaderService } from "./reloader-DJoCB0bC.mjs";
7
7
  import { a as createBlob, c as makeErrorAck, g as layer$1, h as writeJsonFile, i as cleanupStaleTmpFiles, l as paths, m as validateSession, n as makeRootCache, o as createCollection, p as sendAck, r as broadcastDbUpdate, s as makeAck, t as handleWrite, u as readCollectionItemRange, v as FileSystem } from "./write-9dRFczGJ.mjs";
8
8
  import { t as traceKyju } from "./trace-DCB7qFzT.mjs";
9
9
  import { a as createClient, i as dbStringify, n as createRouter, o as createEffectClient, r as dbParse, s as createReplica } from "./transport-BMSzG2-F.mjs";
@@ -995,88 +995,47 @@ async function resolveManifestModulePath(baseDir, specifier) {
995
995
  async function importFreshModule(modulePath) {
996
996
  return import(pathToFileURL(modulePath).href);
997
997
  }
998
- async function resolveConfigPath$1() {
999
- if (process.env.ZENBU_CONFIG_PATH) return process.env.ZENBU_CONFIG_PATH;
1000
- const jsonc = path.join(os.homedir(), ".zenbu", "config.jsonc");
1001
- try {
1002
- await fsp.access(jsonc);
1003
- return jsonc;
1004
- } catch {
1005
- return path.join(os.homedir(), ".zenbu", "config.json");
1006
- }
998
+ function resolveConfigPath() {
999
+ const fromEnv = process.env.ZENBU_CONFIG_PATH;
1000
+ if (!fromEnv) throw new Error("ZENBU_CONFIG_PATH is not set; setup-gate populates this before services boot.");
1001
+ return fromEnv;
1007
1002
  }
1008
- async function loadAppConfig(configPath) {
1009
- let raw;
1010
- try {
1011
- raw = parseJsonc$2(await fsp.readFile(configPath, "utf8"));
1012
- } catch (err) {
1013
- throw new Error(`Failed to read Zenbu config at ${configPath}: ${err instanceof Error ? err.message : String(err)}`);
1014
- }
1015
- if (!raw || typeof raw !== "object") throw new Error(`Zenbu config at ${configPath} is not a JSON object`);
1016
- const obj = raw;
1017
- const plugins = Array.isArray(obj.plugins) ? obj.plugins.filter((p) => typeof p === "string") : [];
1018
- return {
1019
- db: typeof obj.db === "string" ? obj.db : "",
1020
- plugins
1021
- };
1022
- }
1023
- function parseJsonc$2(str) {
1024
- let result = "";
1025
- let i = 0;
1026
- while (i < str.length) if (str[i] === "\"") {
1027
- let j = i + 1;
1028
- while (j < str.length) if (str[j] === "\\") j += 2;
1029
- else if (str[j] === "\"") {
1030
- j++;
1031
- break;
1032
- } else j++;
1033
- result += str.slice(i, j);
1034
- i = j;
1035
- } else if (str[i] === "/" && str[i + 1] === "/") {
1036
- i += 2;
1037
- while (i < str.length && str[i] !== "\n") i++;
1038
- } else if (str[i] === "/" && str[i + 1] === "*") {
1039
- i += 2;
1040
- while (i < str.length && !(str[i] === "*" && str[i + 1] === "/")) i++;
1041
- i += 2;
1042
- } else {
1043
- result += str[i];
1044
- i++;
1045
- }
1046
- return JSON.parse(result.replace(/,\s*([\]}])/g, "$1"));
1003
+ /**
1004
+ * Load just the `db` field from the user's `zenbu.config.ts`. Used to feed
1005
+ * `resolveDbPath` (which expects a relative-or-absolute string). The full
1006
+ * plugin set comes from `runtime.getPlugins()` instead — populated by the
1007
+ * loader-emitted barrel before any service evaluates.
1008
+ */
1009
+ async function loadAppDbField(configPath) {
1010
+ const { loadConfig } = await import("./load-config-CQG4297M.mjs");
1011
+ const { resolved } = await loadConfig(path.dirname(configPath));
1012
+ return resolved.dbPath;
1047
1013
  }
1048
- async function discoverSections(configPath) {
1049
- const resolvedConfigPath = configPath ?? await resolveConfigPath$1();
1050
- let config = { plugins: [] };
1051
- try {
1052
- config = parseJsonc$2(await fsp.readFile(resolvedConfigPath, "utf8"));
1053
- } catch (error) {
1054
- log$2.error(`failed to read plugin config at ${resolvedConfigPath}: ${error instanceof Error ? error.message : String(error)}`);
1055
- return [];
1056
- }
1014
+ async function discoverSections() {
1015
+ const plugins = getPlugins();
1057
1016
  const perPluginTimings = [];
1058
- const tasks = config.plugins.map(async (manifestPath) => {
1017
+ const tasks = plugins.map(async (plugin) => {
1059
1018
  const pluginStart = Date.now();
1060
- let manifestMs = 0;
1061
1019
  let resolveSchemaMs = 0;
1062
1020
  let importSchemaMs = 0;
1063
1021
  let resolveMigrationsMs = 0;
1064
1022
  let importMigrationsMs = 0;
1065
- let pluginName = path.basename(path.dirname(manifestPath));
1023
+ const finish = (result) => {
1024
+ perPluginTimings.push({
1025
+ name: plugin.name,
1026
+ resolveSchemaMs,
1027
+ importSchemaMs,
1028
+ resolveMigrationsMs,
1029
+ importMigrationsMs,
1030
+ totalMs: Date.now() - pluginStart
1031
+ });
1032
+ return result;
1033
+ };
1034
+ if (!plugin.schemaPath) return finish(null);
1066
1035
  try {
1067
- const t0 = Date.now();
1068
- const raw = await fsp.readFile(manifestPath, "utf8");
1069
- manifestMs = Date.now() - t0;
1070
- const manifest = JSON.parse(raw);
1071
- pluginName = manifest.name ?? pluginName;
1072
- if (!manifest.name || !manifest.schema) {
1073
- log$2.error(`skipping manifest without name/schema: ${manifestPath}`);
1074
- return null;
1075
- }
1076
- const baseDir = path.dirname(path.resolve(manifestPath));
1077
1036
  const schemaChain = (async () => {
1078
1037
  const s0 = Date.now();
1079
- const schemaPath = await resolveManifestModulePath(baseDir, manifest.schema);
1038
+ const schemaPath = await resolveManifestModulePath(plugin.dir, plugin.schemaPath);
1080
1039
  resolveSchemaMs = Date.now() - s0;
1081
1040
  const s1 = Date.now();
1082
1041
  const schemaModule = await importFreshModule(schemaPath);
@@ -1086,10 +1045,10 @@ async function discoverSections(configPath) {
1086
1045
  schemaModule
1087
1046
  };
1088
1047
  })();
1089
- const migrationsChain = manifest.migrations ? (async () => {
1048
+ const migrationsChain = plugin.migrationsPath ? (async () => {
1090
1049
  try {
1091
1050
  const m0 = Date.now();
1092
- const migrationsPath = await resolveManifestModulePath(baseDir, manifest.migrations);
1051
+ const migrationsPath = await resolveManifestModulePath(plugin.dir, plugin.migrationsPath);
1093
1052
  resolveMigrationsMs = Date.now() - m0;
1094
1053
  const m1 = Date.now();
1095
1054
  const stat = await fsp.stat(migrationsPath);
@@ -1105,7 +1064,7 @@ async function discoverSections(configPath) {
1105
1064
  failed: false
1106
1065
  };
1107
1066
  } catch (error) {
1108
- log$2.error(`failed to load migrations from ${manifestPath}: ${error instanceof Error ? error.message : String(error)}`);
1067
+ log$2.error(`failed to load migrations for plugin "${plugin.name}": ${error instanceof Error ? error.message : String(error)}`);
1109
1068
  return {
1110
1069
  migrations: [],
1111
1070
  failed: true
@@ -1116,40 +1075,26 @@ async function discoverSections(configPath) {
1116
1075
  failed: false
1117
1076
  });
1118
1077
  const [schemaResult, migrationsResult] = await Promise.all([schemaChain, migrationsChain]);
1119
- if (migrationsResult.failed) return null;
1078
+ if (migrationsResult.failed) return finish(null);
1120
1079
  const schema = schemaResult.schemaModule.schema ?? schemaResult.schemaModule.default;
1121
1080
  if (!schema?.shape) {
1122
1081
  log$2.error(`schema module did not export a valid schema: ${schemaResult.schemaPath}`);
1123
- return null;
1082
+ return finish(null);
1124
1083
  }
1125
- return {
1126
- name: manifest.name,
1084
+ return finish({
1085
+ name: plugin.name,
1127
1086
  schema,
1128
1087
  migrations: migrationsResult.migrations
1129
- };
1130
- } catch (error) {
1131
- log$2.error(`failed to load section from ${manifestPath}: ${error instanceof Error ? error.message : String(error)}`);
1132
- return null;
1133
- } finally {
1134
- perPluginTimings.push({
1135
- name: pluginName,
1136
- manifestMs,
1137
- resolveSchemaMs,
1138
- importSchemaMs,
1139
- resolveMigrationsMs,
1140
- importMigrationsMs,
1141
- totalMs: Date.now() - pluginStart
1142
1088
  });
1089
+ } catch (error) {
1090
+ log$2.error(`failed to load section for plugin "${plugin.name}": ${error instanceof Error ? error.message : String(error)}`);
1091
+ return finish(null);
1143
1092
  }
1144
1093
  });
1145
- const sections = (await Promise.all(tasks)).filter((s) => s !== null);
1094
+ const sections = (await Promise.all(tasks)).filter((sec) => sec !== null);
1146
1095
  const sorted = [...perPluginTimings].sort((a, b) => b.totalMs - a.totalMs);
1147
- const sum = (k) => perPluginTimings.reduce((acc, p) => acc + p[k], 0);
1148
1096
  log$2.verbose("per-plugin breakdown (ms, parallel):");
1149
- log$2.verbose(` ${"plugin".padEnd(28)} ${"total".padStart(6)} ${"man".padStart(5)} ${"resS".padStart(5)} ${"impS".padStart(6)} ${"resM".padStart(5)} ${"impM".padStart(6)}`);
1150
- for (const p of sorted) log$2.verbose(` ${p.name.padEnd(28)} ${String(p.totalMs).padStart(6)} ${String(p.manifestMs).padStart(5)} ${String(p.resolveSchemaMs).padStart(5)} ${String(p.importSchemaMs).padStart(6)} ${String(p.resolveMigrationsMs).padStart(5)} ${String(p.importMigrationsMs).padStart(6)}`);
1151
- log$2.verbose(` ${"SUM(cpu)".padEnd(28)} ${String(sum("totalMs")).padStart(6)} ${String(sum("manifestMs")).padStart(5)} ${String(sum("resolveSchemaMs")).padStart(5)} ${String(sum("importSchemaMs")).padStart(6)} ${String(sum("resolveMigrationsMs")).padStart(5)} ${String(sum("importMigrationsMs")).padStart(6)}`);
1152
- log$2.verbose(` (wall time: look at db.discover-sections span — should be ~max(totalMs) not SUM)`);
1097
+ for (const ptm of sorted) log$2.verbose(` ${ptm.name.padEnd(28)} total=${String(ptm.totalMs).padStart(6)} resS=${String(ptm.resolveSchemaMs).padStart(5)} impS=${String(ptm.importSchemaMs).padStart(6)} resM=${String(ptm.resolveMigrationsMs).padStart(5)} impM=${String(ptm.importMigrationsMs).padStart(6)}`);
1153
1098
  return sections;
1154
1099
  }
1155
1100
  var DbService = class extends Service {
@@ -1201,14 +1146,14 @@ var DbService = class extends Service {
1201
1146
  }
1202
1147
  }
1203
1148
  async evaluate() {
1204
- const configPath = await resolveConfigPath$1();
1149
+ const configPath = resolveConfigPath();
1205
1150
  const configDir = path.dirname(configPath);
1206
- const appConfig = await loadAppConfig(configPath);
1151
+ const configDbAbs = await loadAppDbField(configPath);
1207
1152
  const [coreSec, pluginSections, resolved] = await Promise.all([
1208
1153
  this.trace("build-core-section", () => buildCoreSection()),
1209
- this.trace("discover-sections", () => discoverSections(configPath)),
1154
+ this.trace("discover-sections", () => discoverSections()),
1210
1155
  resolveDbPath(process.argv, {
1211
- configDb: appConfig.db,
1156
+ configDb: configDbAbs,
1212
1157
  configDir,
1213
1158
  configPath
1214
1159
  })
@@ -1340,7 +1285,7 @@ var ViewRegistryService = class extends Service {
1340
1285
  return this.views.get(scope);
1341
1286
  }
1342
1287
  evaluate() {
1343
- this.loadManifestIcons().catch((err) => {});
1288
+ this.loadManifestIcons();
1344
1289
  this.syncToDb();
1345
1290
  this.setup("view-registry-cleanup", () => {
1346
1291
  return async () => {
@@ -1350,23 +1295,12 @@ var ViewRegistryService = class extends Service {
1350
1295
  };
1351
1296
  });
1352
1297
  }
1353
- async loadManifestIcons() {
1298
+ loadManifestIcons() {
1354
1299
  this.manifestIcons.clear();
1355
- try {
1356
- const configPath = await resolveConfigPath();
1357
- let raw;
1358
- try {
1359
- raw = await fsp.readFile(configPath, "utf8");
1360
- } catch {
1361
- return;
1362
- }
1363
- const config = parseJsonc$1(raw);
1364
- for (const manifestPath of config.plugins ?? []) try {
1365
- const manifestRaw = await fsp.readFile(manifestPath, "utf8");
1366
- const icons = JSON.parse(manifestRaw).icons ?? {};
1367
- for (const [scope, svg] of Object.entries(icons)) this.manifestIcons.set(scope, svg);
1368
- } catch {}
1369
- } catch {}
1300
+ for (const plugin of getPlugins()) {
1301
+ if (!plugin.icons) continue;
1302
+ for (const [scope, svg] of Object.entries(plugin.icons)) this.manifestIcons.set(scope, svg);
1303
+ }
1370
1304
  }
1371
1305
  async syncToDb() {
1372
1306
  const client = this.ctx.db.effectClient;
@@ -1382,41 +1316,6 @@ var ViewRegistryService = class extends Service {
1382
1316
  })).catch((err) => {});
1383
1317
  }
1384
1318
  };
1385
- async function resolveConfigPath() {
1386
- if (process.env.ZENBU_CONFIG_PATH) return process.env.ZENBU_CONFIG_PATH;
1387
- const jsonc = path.join(os.homedir(), ".zenbu", "config.jsonc");
1388
- try {
1389
- await fsp.access(jsonc);
1390
- return jsonc;
1391
- } catch {
1392
- return path.join(os.homedir(), ".zenbu", "config.json");
1393
- }
1394
- }
1395
- function parseJsonc$1(str) {
1396
- let result = "";
1397
- let i = 0;
1398
- while (i < str.length) if (str[i] === "\"") {
1399
- let j = i + 1;
1400
- while (j < str.length) if (str[j] === "\\") j += 2;
1401
- else if (str[j] === "\"") {
1402
- j++;
1403
- break;
1404
- } else j++;
1405
- result += str.slice(i, j);
1406
- i = j;
1407
- } else if (str[i] === "/" && str[i + 1] === "/") {
1408
- i += 2;
1409
- while (i < str.length && str[i] !== "\n") i++;
1410
- } else if (str[i] === "/" && str[i + 1] === "*") {
1411
- i += 2;
1412
- while (i < str.length && !(str[i] === "*" && str[i + 1] === "/")) i++;
1413
- i += 2;
1414
- } else {
1415
- result += str[i];
1416
- i++;
1417
- }
1418
- return JSON.parse(result.replace(/,\s*([\]}])/g, "$1"));
1419
- }
1420
1319
  runtime.register(ViewRegistryService, import.meta);
1421
1320
  //#endregion
1422
1321
  //#region src/services/renderer-host.ts
@@ -1429,59 +1328,26 @@ async function pathExists(filePath) {
1429
1328
  return false;
1430
1329
  }
1431
1330
  }
1432
- function parseJsonc(str) {
1433
- let result = "";
1434
- let i = 0;
1435
- while (i < str.length) if (str[i] === "\"") {
1436
- let j = i + 1;
1437
- while (j < str.length) if (str[j] === "\\") j += 2;
1438
- else if (str[j] === "\"") {
1439
- j++;
1440
- break;
1441
- } else j++;
1442
- result += str.slice(i, j);
1443
- i = j;
1444
- } else if (str[i] === "/" && str[i + 1] === "/") {
1445
- i += 2;
1446
- while (i < str.length && str[i] !== "\n") i++;
1447
- } else if (str[i] === "/" && str[i + 1] === "*") {
1448
- i += 2;
1449
- while (i < str.length && !(str[i] === "*" && str[i + 1] === "/")) i++;
1450
- i += 2;
1451
- } else {
1452
- result += str[i];
1453
- i++;
1454
- }
1455
- return JSON.parse(result.replace(/,\s*([\]}])/g, "$1"));
1456
- }
1331
+ /**
1332
+ * The app's renderer root is the directory containing the boot-window HTML
1333
+ * file (`uiEntrypoint` in `zenbu.config.ts`). Vite's `root` resolves to that
1334
+ * directory, and `index.html` is served from there.
1335
+ *
1336
+ * `vite.config.ts` is picked up from the project root if present (sibling
1337
+ * of `zenbu.config.ts`).
1338
+ */
1457
1339
  async function resolveRendererRoot() {
1340
+ const entrypoint = getAppEntrypoint();
1341
+ if (!entrypoint) throw new Error("[renderer-host] no `uiEntrypoint` registered. Set `uiEntrypoint` in zenbu.config.ts before starting the app.");
1342
+ const rendererRoot = path.dirname(entrypoint);
1343
+ if (!await pathExists(rendererRoot)) throw new Error(`[renderer-host] uiEntrypoint references ${entrypoint} but ${rendererRoot} does not exist.`);
1458
1344
  const configPath = process.env.ZENBU_CONFIG_PATH;
1459
- if (!configPath) throw new Error("ZENBU_CONFIG_PATH is required to resolve the app renderer");
1460
- const config = parseJsonc(await fsp.readFile(configPath, "utf8"));
1461
- const configDir = path.dirname(configPath);
1462
- for (const manifestRel of config.plugins ?? []) {
1463
- const resolvedManifest = path.isAbsolute(manifestRel) ? manifestRel : path.resolve(configDir, manifestRel);
1464
- try {
1465
- const manifest = JSON.parse(await fsp.readFile(resolvedManifest, "utf8"));
1466
- if (!manifest.uiEntrypoint) continue;
1467
- const projectDir = path.dirname(resolvedManifest);
1468
- const rendererDir = path.resolve(projectDir, manifest.uiEntrypoint);
1469
- const viteConfig = path.join(projectDir, "vite.config.ts");
1470
- const configFile = await pathExists(viteConfig) ? viteConfig : false;
1471
- if (!await pathExists(rendererDir)) continue;
1472
- return {
1473
- rendererRoot: rendererDir,
1474
- configFile
1475
- };
1476
- } catch {}
1477
- }
1478
- const rendererDir = path.resolve(configDir, "src", "renderer");
1479
- const viteConfig = path.join(configDir, "vite.config.ts");
1480
- if (await pathExists(rendererDir)) return {
1481
- rendererRoot: rendererDir,
1345
+ const projectDir = configPath ? path.dirname(configPath) : rendererRoot;
1346
+ const viteConfig = path.join(projectDir, "vite.config.ts");
1347
+ return {
1348
+ rendererRoot,
1482
1349
  configFile: await pathExists(viteConfig) ? viteConfig : false
1483
1350
  };
1484
- throw new Error(`No renderer entrypoint found. Add uiEntrypoint to the app plugin manifest or create ${rendererDir}.`);
1485
1351
  }
1486
1352
  var RendererHostService = class extends Service {
1487
1353
  static key = "renderer-host";
@@ -1,6 +1,6 @@
1
- import { i as runtime, t as Service } from "./runtime-DUFKDIe4.mjs";
1
+ import { t as Service, u as runtime } from "./runtime-C95iyVn6.mjs";
2
2
  import { t as createLogger } from "./log-CyKv8hQg.mjs";
3
- import { o as HttpService } from "./renderer-host-Bg8QdeeH.mjs";
3
+ import { o as HttpService } from "./renderer-host-ztaSIOGx.mjs";
4
4
  import { n as createRpcRouter, r as createServer } from "./src-pELM4_iH.mjs";
5
5
  //#region src/services/rpc.ts
6
6
  const log = createLogger("rpc");
@@ -0,0 +1,2 @@
1
+ import "./rpc-CsgWnlZx.mjs";
2
+ export {};
package/dist/rpc.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { n as EventProxy, r as RouterProxy, t as connectRpc } from "./index-Bhlbyrn7.mjs";
1
+ import { n as EventProxy, r as RouterProxy, t as connectRpc } from "./index-CE0iPntP.mjs";
2
2
  export { type EventProxy, type RouterProxy, connectRpc };
@@ -376,6 +376,9 @@ var ServiceRuntime = class {
376
376
  }
377
377
  };
378
378
  /**
379
+ * fixme: i don't think these commments make sense
380
+ */
381
+ /**
379
382
  * Devtools-only handles, attached to the global so they aren't part of the
380
383
  * public `ServiceRuntime` autocomplete surface. Same shape React DevTools
381
384
  * uses (`__REACT_DEVTOOLS_GLOBAL_HOOK__`): user code reading
@@ -405,5 +408,54 @@ const runtime = (() => {
405
408
  installDevHook(fresh);
406
409
  return fresh;
407
410
  })();
411
+ function getPluginRegistry() {
412
+ const slot = globalThis;
413
+ if (!slot.__zenbu_plugin_registry__) slot.__zenbu_plugin_registry__ = {
414
+ plugins: /* @__PURE__ */ new Map(),
415
+ appEntrypoint: null
416
+ };
417
+ return slot.__zenbu_plugin_registry__;
418
+ }
419
+ /**
420
+ * Register a plugin's resolved manifest. Idempotent — replaces any existing
421
+ * entry for the same `name`. Called by the loader-emitted barrel; user code
422
+ * normally does not call this directly.
423
+ */
424
+ function registerPlugin(record) {
425
+ getPluginRegistry().plugins.set(record.name, record);
426
+ }
427
+ /**
428
+ * Drop a plugin from the registry. Used when the loader regenerates the
429
+ * barrel and needs to clear stale entries.
430
+ */
431
+ function unregisterPlugin(name) {
432
+ getPluginRegistry().plugins.delete(name);
433
+ }
434
+ /**
435
+ * Replace the entire plugin set in one shot. The loader uses this on every
436
+ * barrel regeneration so removed plugins disappear cleanly.
437
+ */
438
+ function replacePlugins(records) {
439
+ const reg = getPluginRegistry();
440
+ reg.plugins.clear();
441
+ for (const record of records) reg.plugins.set(record.name, record);
442
+ }
443
+ function getPlugins() {
444
+ return [...getPluginRegistry().plugins.values()];
445
+ }
446
+ function getPlugin(name) {
447
+ return getPluginRegistry().plugins.get(name);
448
+ }
449
+ /**
450
+ * Set the boot-window HTML path. Called once by the loader-emitted barrel.
451
+ * Consumers (`view-registry`, `vite-plugins`) ask for it via
452
+ * `getAppEntrypoint()`.
453
+ */
454
+ function registerAppEntrypoint(htmlPath) {
455
+ getPluginRegistry().appEntrypoint = htmlPath;
456
+ }
457
+ function getAppEntrypoint() {
458
+ return getPluginRegistry().appEntrypoint;
459
+ }
408
460
  //#endregion
409
- export { serviceWithDeps as a, runtime as i, ServiceRuntime as n, optional as r, Service as t };
461
+ export { getPlugins as a, registerPlugin as c, serviceWithDeps as d, unregisterPlugin as f, getPlugin as i, replacePlugins as l, ServiceRuntime as n, optional as o, getAppEntrypoint as r, registerAppEntrypoint as s, Service as t, runtime as u };
@@ -105,5 +105,45 @@ declare class ServiceRuntime {
105
105
  private topologicalLevels;
106
106
  }
107
107
  declare const runtime: ServiceRuntime;
108
+ /**
109
+ * A plugin manifest after the loader has resolved every relative path to
110
+ * absolute. Mirrors `ResolvedPlugin` in `cli/lib/build-config.ts` but is
111
+ * declared inline here to avoid runtime.ts importing CLI code.
112
+ */
113
+ interface PluginRecord {
114
+ name: string;
115
+ dir: string;
116
+ services: string[];
117
+ schemaPath?: string;
118
+ migrationsPath?: string;
119
+ preloadPath?: string;
120
+ eventsPath?: string;
121
+ icons?: Record<string, string>;
122
+ }
123
+ /**
124
+ * Register a plugin's resolved manifest. Idempotent — replaces any existing
125
+ * entry for the same `name`. Called by the loader-emitted barrel; user code
126
+ * normally does not call this directly.
127
+ */
128
+ declare function registerPlugin(record: PluginRecord): void;
129
+ /**
130
+ * Drop a plugin from the registry. Used when the loader regenerates the
131
+ * barrel and needs to clear stale entries.
132
+ */
133
+ declare function unregisterPlugin(name: string): void;
134
+ /**
135
+ * Replace the entire plugin set in one shot. The loader uses this on every
136
+ * barrel regeneration so removed plugins disappear cleanly.
137
+ */
138
+ declare function replacePlugins(records: PluginRecord[]): void;
139
+ declare function getPlugins(): PluginRecord[];
140
+ declare function getPlugin(name: string): PluginRecord | undefined;
141
+ /**
142
+ * Set the boot-window HTML path. Called once by the loader-emitted barrel.
143
+ * Consumers (`view-registry`, `vite-plugins`) ask for it via
144
+ * `getAppEntrypoint()`.
145
+ */
146
+ declare function registerAppEntrypoint(htmlPath: string): void;
147
+ declare function getAppEntrypoint(): string | null;
108
148
  //#endregion
109
- export { runtime as a, optional as i, Service as n, serviceWithDeps as o, ServiceRuntime as r, CleanupReason as t };
149
+ export { getAppEntrypoint as a, optional as c, replacePlugins as d, runtime as f, ServiceRuntime as i, registerAppEntrypoint as l, unregisterPlugin as m, PluginRecord as n, getPlugin as o, serviceWithDeps as p, Service as r, getPlugins as s, CleanupReason as t, registerPlugin as u };
@@ -1,2 +1,2 @@
1
- import { a as runtime, i as optional, n as Service, o as serviceWithDeps, r as ServiceRuntime, t as CleanupReason } from "./runtime-CjqDr8Yf.mjs";
2
- export { CleanupReason, Service, ServiceRuntime, optional, runtime, serviceWithDeps };
1
+ import { a as getAppEntrypoint, c as optional, d as replacePlugins, f as runtime, i as ServiceRuntime, l as registerAppEntrypoint, m as unregisterPlugin, n as PluginRecord, o as getPlugin, p as serviceWithDeps, r as Service, s as getPlugins, t as CleanupReason, u as registerPlugin } from "./runtime-CsiDppGF.mjs";
2
+ export { CleanupReason, PluginRecord, Service, ServiceRuntime, getAppEntrypoint, getPlugin, getPlugins, optional, registerAppEntrypoint, registerPlugin, replacePlugins, runtime, serviceWithDeps, unregisterPlugin };
package/dist/runtime.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { a as serviceWithDeps, i as runtime, n as ServiceRuntime, r as optional, t as Service } from "./runtime-DUFKDIe4.mjs";
2
- export { Service, ServiceRuntime, optional, runtime, serviceWithDeps };
1
+ import { a as getPlugins, c as registerPlugin, d as serviceWithDeps, f as unregisterPlugin, i as getPlugin, l as replacePlugins, n as ServiceRuntime, o as optional, r as getAppEntrypoint, s as registerAppEntrypoint, t as Service, u as runtime } from "./runtime-C95iyVn6.mjs";
2
+ export { Service, ServiceRuntime, getAppEntrypoint, getPlugin, getPlugins, optional, registerAppEntrypoint, registerPlugin, replacePlugins, runtime, serviceWithDeps, unregisterPlugin };
@@ -1,4 +1,4 @@
1
- import { m as Field, v as Schema } from "./index-CPZ5d6Hl.mjs";
1
+ import { m as Field, v as Schema } from "./index-UK58xuoR.mjs";
2
2
  import zod from "zod";
3
3
 
4
4
  //#region src/schema.d.ts
package/dist/schema.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as WindowPrefs, i as WindowBounds, n as SchemaRoot, o as schema, r as ViewRegistryEntry, t as CoreSchema } from "./schema-DMoSkwUx.mjs";
1
+ import { a as WindowPrefs, i as WindowBounds, n as SchemaRoot, o as schema, r as ViewRegistryEntry, t as CoreSchema } from "./schema-DvT61x2_.mjs";
2
2
  export { CoreSchema, SchemaRoot, ViewRegistryEntry, WindowBounds, WindowPrefs, schema };
@@ -0,0 +1,2 @@
1
+ import "./server-DB3Eki_G.mjs";
2
+ export {};
@@ -1,4 +1,4 @@
1
- import { i as runtime, t as Service } from "./runtime-DUFKDIe4.mjs";
1
+ import { t as Service, u as runtime } from "./runtime-C95iyVn6.mjs";
2
2
  import { t as createLogger } from "./log-CyKv8hQg.mjs";
3
3
  import http from "node:http";
4
4
  import { randomBytes, timingSafeEqual } from "node:crypto";
@@ -7,16 +7,16 @@
7
7
  * chance to bootstrap env vars and `process.chdir(projectRoot)`.
8
8
  */
9
9
  async function defaultServices() {
10
- await import("../server-DjrZUbbu.mjs");
11
- await import("../reloader-BCkLjDhS.mjs");
12
- await import("../renderer-host-DpvBPTHJ.mjs");
13
- await import("../http-IBcLzbYu.mjs");
14
- await import("../db-ByKPbnP6.mjs");
15
- await import("../base-window-DEIAk618.mjs");
16
- await import("../rpc-CqitnyR4.mjs");
17
- await import("../view-registry-BualWgAf.mjs");
18
- await import("../window-CM2a9Kyc.mjs");
19
- await import("../advice-config-Cy133IQP.mjs");
10
+ await import("../server-CgzQOPSW.mjs");
11
+ await import("../reloader-FeHKV2jd.mjs");
12
+ await import("../renderer-host-BQpS0ZM2.mjs");
13
+ await import("../http-B36qtsm0.mjs");
14
+ await import("../db-Bz_CDIWg.mjs");
15
+ await import("../base-window-OXg2KSyP.mjs");
16
+ await import("../rpc-D_s7-WZe.mjs");
17
+ await import("../view-registry-2zePxTEg.mjs");
18
+ await import("../window-S3TlTXlK.mjs");
19
+ await import("../advice-config-D6K_a7e9.mjs");
20
20
  }
21
21
  //#endregion
22
22
  export { defaultServices };
@@ -1,6 +1,6 @@
1
- import { c as EffectFieldNode, d as KyjuError, l as FieldNode, r as createRouter, t as Db } from "../index-CPZ5d6Hl.mjs";
2
- import { n as Service, t as CleanupReason } from "../runtime-CjqDr8Yf.mjs";
3
- import { o as ResolvedDbRoot, s as ResolvedEvents } from "../registry-Dh_e7HU1.mjs";
1
+ import { c as EffectFieldNode, d as KyjuError, l as FieldNode, r as createRouter, t as Db } from "../index-UK58xuoR.mjs";
2
+ import { r as Service, t as CleanupReason } from "../runtime-CsiDppGF.mjs";
3
+ import { o as ResolvedDbRoot, s as ResolvedEvents } from "../registry-CioEYLI5.mjs";
4
4
  import http from "node:http";
5
5
  import { WebSocket, WebSocketServer } from "ws";
6
6
  import { ViteDevServer } from "vite";
@@ -1,7 +1,7 @@
1
- import { t as ServerService } from "../server-BXwZEQ-n.mjs";
2
- import { t as ReloaderService } from "../reloader-lLAJ3lqg.mjs";
3
- import { n as ViewRegistryService, o as HttpService, r as DbService, t as RendererHostService } from "../renderer-host-Bg8QdeeH.mjs";
4
- import { n as MAIN_WINDOW_ID, t as BaseWindowService } from "../base-window-BUt8pwbw.mjs";
5
- import { t as RpcService } from "../rpc-BwwQK6hD.mjs";
6
- import { t as WindowService } from "../window-CmmpCVX6.mjs";
1
+ import { t as ServerService } from "../server-DB3Eki_G.mjs";
2
+ import { t as ReloaderService } from "../reloader-DJoCB0bC.mjs";
3
+ import { n as ViewRegistryService, o as HttpService, r as DbService, t as RendererHostService } from "../renderer-host-ztaSIOGx.mjs";
4
+ import { n as MAIN_WINDOW_ID, t as BaseWindowService } from "../base-window-D8CpxMU3.mjs";
5
+ import { t as RpcService } from "../rpc-CsgWnlZx.mjs";
6
+ import { t as WindowService } from "../window-DUvMTons.mjs";
7
7
  export { BaseWindowService, DbService, HttpService, MAIN_WINDOW_ID, ReloaderService, RendererHostService, RpcService, ServerService, ViewRegistryService, WindowService };