@zenbujs/core 0.0.3 → 0.0.5

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 (89) hide show
  1. package/dist/{advice-config-CjgkEf2E.mjs → advice-config-QYB2qEd_.mjs} +32 -14
  2. package/dist/advice.mjs +1 -1
  3. package/dist/{base-window-BUt8pwbw.mjs → base-window-BbFRRhKP.mjs} +9 -4
  4. package/dist/{build-config-pbv0w4oN.mjs → build-config-C3a-o3_B.mjs} +8 -2
  5. package/dist/{build-electron-BzHa_hRi.mjs → build-electron-CNJ0dLND.mjs} +12 -6
  6. package/dist/{build-source-CnTfQBGK.mjs → build-source-C2puqEVr.mjs} +13 -8
  7. package/dist/chunk-DsiFFCwN.mjs +16 -0
  8. package/dist/cli/bin.mjs +12 -15
  9. package/dist/cli/build.d.mts +1 -52
  10. package/dist/cli/build.mjs +2 -47
  11. package/dist/cli/resolve-config.mjs +37 -0
  12. package/dist/{cli-BLbQQIVB.mjs → cli-C3R1LBMY.mjs} +5 -5
  13. package/dist/{config-CdVrW85P.mjs → config-DXRCDUxG.mjs} +1 -1
  14. package/dist/config.d.mts +3 -0
  15. package/dist/config.mjs +4 -0
  16. package/dist/{db-BXadETOb.mjs → db-xjvahRFJ.mjs} +47 -41
  17. package/dist/db.d.mts +1 -1
  18. package/dist/db.mjs +2 -2
  19. package/dist/env-bootstrap.d.mts +1 -1
  20. package/dist/env-bootstrap.mjs +52 -1
  21. package/dist/index-ClXLQ1fw.d.mts +1 -0
  22. package/dist/index.d.mts +5 -5
  23. package/dist/index.mjs +4 -4
  24. package/dist/{link-VOoGs-pY.mjs → link-c0_aLWQ3.mjs} +87 -120
  25. package/dist/load-config-xMf2wxH8.mjs +141 -0
  26. package/dist/loaders/zenbu.d.mts +17 -0
  27. package/dist/loaders/zenbu.mjs +144 -135
  28. package/dist/{monorepo-CQeQBIpa.mjs → monorepo-3avKJwzJ.mjs} +5 -2
  29. package/dist/node-loader.mjs +1 -1
  30. package/dist/{publish-source-BJdpDAFH.mjs → publish-source-Dill72NS.mjs} +12 -6
  31. package/dist/react.d.mts +3 -3
  32. package/dist/react.mjs +2 -2
  33. package/dist/{registry-Dh_e7HU1.d.mts → registry-eX6e2oql.d.mts} +1 -1
  34. package/dist/registry.d.mts +1 -1
  35. package/dist/{reloader-lLAJ3lqg.mjs → reloader-DzEO8kJr.mjs} +6 -4
  36. package/dist/{renderer-host-Bg8QdeeH.mjs → renderer-host-Cau9JK0v.mjs} +90 -212
  37. package/dist/{rpc-BwwQK6hD.mjs → rpc-JfGv-Wuw.mjs} +7 -5
  38. package/dist/rpc.d.mts +1 -1
  39. package/dist/rpc.mjs +1 -1
  40. package/dist/{runtime-CjqDr8Yf.d.mts → runtime-pCeVzj--.d.mts} +73 -1
  41. package/dist/runtime.d.mts +2 -2
  42. package/dist/runtime.mjs +522 -2
  43. package/dist/{schema-DMoSkwUx.d.mts → schema-Dl85YjXW.d.mts} +1 -1
  44. package/dist/schema.d.mts +1 -1
  45. package/dist/schema.mjs +27 -1
  46. package/dist/{server-BXwZEQ-n.mjs → server-y3PPbh3l.mjs} +5 -3
  47. package/dist/services/default.mjs +10 -10
  48. package/dist/services/index.d.mts +8 -4
  49. package/dist/services/index.mjs +6 -6
  50. package/dist/setup-gate.d.mts +1 -1
  51. package/dist/setup-gate.mjs +248 -1
  52. package/dist/{transform-DJH3vN4b.mjs → transform-CmFYPmt8.mjs} +1 -1
  53. package/dist/transforms-CuTODvDx.d.mts +145 -0
  54. package/dist/transforms-htxfTwsY.mjs +47 -0
  55. package/dist/{transport-BMSzG2-F.mjs → transport-F2hv_OEm.mjs} +1 -1
  56. package/dist/{vite-plugins-Bh3SCOw-.mjs → vite-plugins-Do7liKi_.mjs} +5 -19
  57. package/dist/vite.mjs +1 -1
  58. package/dist/{window-CmmpCVX6.mjs → window-o2NGUsIb.mjs} +10 -7
  59. package/dist/{write-9dRFczGJ.mjs → write-DgIRjo23.mjs} +1 -1
  60. package/package.json +11 -10
  61. package/dist/advice-config-Cy133IQP.mjs +0 -2
  62. package/dist/base-window-DEIAk618.mjs +0 -2
  63. package/dist/chunk-Dm34NbLt.mjs +0 -6
  64. package/dist/config-LK73dJmO.mjs +0 -2
  65. package/dist/db-ByKPbnP6.mjs +0 -2
  66. package/dist/env-bootstrap-rj7I-59x.mjs +0 -53
  67. package/dist/http-IBcLzbYu.mjs +0 -2
  68. package/dist/load-build-config-DozuRhAN.mjs +0 -40
  69. package/dist/reloader-BCkLjDhS.mjs +0 -2
  70. package/dist/renderer-host-DpvBPTHJ.mjs +0 -2
  71. package/dist/rpc-CqitnyR4.mjs +0 -2
  72. package/dist/runtime-DUFKDIe4.mjs +0 -409
  73. package/dist/schema-dGK6qkfR.mjs +0 -28
  74. package/dist/server-DjrZUbbu.mjs +0 -2
  75. package/dist/setup-gate-BcoqWu8S.mjs +0 -110
  76. package/dist/view-registry-BualWgAf.mjs +0 -2
  77. package/dist/window-CM2a9Kyc.mjs +0 -2
  78. package/dist/{index-FtE8MXJ_.d.mts → cli/resolve-config.d.mts} +0 -0
  79. package/dist/{dev-BU_llQh1.mjs → dev-Dazhu66l.mjs} +0 -0
  80. package/dist/{env-bootstrap-BtVME-CU.d.mts → env-bootstrap-DW2hVhSO.d.mts} +0 -0
  81. package/dist/{index-Bhlbyrn7.d.mts → index-C-ALz_SH.d.mts} +0 -0
  82. package/dist/{index-CPZ5d6Hl.d.mts → index-M_lSNBrq.d.mts} +0 -0
  83. package/dist/{log-CyKv8hQg.mjs → log-6rzaCV0I.mjs} +0 -0
  84. package/dist/{mirror-sync-BN59kMCG.mjs → mirror-sync-PDzxhf1w.mjs} +1 -1
  85. /package/dist/{node-D4M19_mV.mjs → node-_8xShqxr.mjs} +0 -0
  86. /package/dist/{schema-CIg4GzHQ.mjs → schema-Ca7SxXgS.mjs} +0 -0
  87. /package/dist/{setup-gate-BqOzm7zp.d.mts → setup-gate-Dcy8gGPJ.d.mts} +0 -0
  88. /package/dist/{src-pELM4_iH.mjs → src-Cven45mq.mjs} +0 -0
  89. /package/dist/{trace-DCB7qFzT.mjs → trace-BaVg0rnY.mjs} +0 -0
package/dist/db.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { i as createSchema, n as blob, r as collection } from "./schema-CIg4GzHQ.mjs";
2
- import { i as dbStringify, r as dbParse, t as connectReplica } from "./transport-BMSzG2-F.mjs";
1
+ import { i as createSchema, n as blob, r as collection } from "./schema-Ca7SxXgS.mjs";
2
+ import { i as dbStringify, r as dbParse, t as connectReplica } from "./transport-F2hv_OEm.mjs";
3
3
  import { z as z$1 } from "zod";
4
4
  //#region src/db.ts
5
5
  /**
@@ -1,2 +1,2 @@
1
- import { t as bootstrapEnv } from "./env-bootstrap-BtVME-CU.mjs";
1
+ import { t as bootstrapEnv } from "./env-bootstrap-DW2hVhSO.mjs";
2
2
  export { bootstrapEnv };
@@ -1,2 +1,53 @@
1
- import { t as bootstrapEnv } from "./env-bootstrap-rj7I-59x.mjs";
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ //#region src/env-bootstrap.ts
5
+ const internalDir = path.join(os.homedir(), ".zenbu", ".internal");
6
+ const pathsJson = path.join(internalDir, "paths.json");
7
+ function userCacheRoot() {
8
+ if (process.platform === "darwin") return path.join(os.homedir(), "Library", "Caches");
9
+ if (process.platform === "win32") return process.env.LOCALAPPDATA ?? path.join(os.homedir(), "AppData", "Local");
10
+ return process.env.XDG_CACHE_HOME ?? path.join(os.homedir(), ".cache");
11
+ }
12
+ function computePaths() {
13
+ const cacheRoot = path.join(userCacheRoot(), "Zenbu");
14
+ const binDir = path.join(cacheRoot, "bin");
15
+ return {
16
+ cacheRoot,
17
+ binDir,
18
+ bunInstall: path.join(cacheRoot, "bun"),
19
+ bunPath: path.join(binDir, "bun"),
20
+ pnpmHome: path.join(cacheRoot, "pnpm"),
21
+ pnpmPath: path.join(binDir, "pnpm"),
22
+ gitPath: path.join(binDir, "git"),
23
+ writtenAt: Date.now()
24
+ };
25
+ }
26
+ function bootstrapEnv() {
27
+ const paths = computePaths();
28
+ try {
29
+ fs.mkdirSync(paths.binDir, { recursive: true });
30
+ } catch {}
31
+ const toolchainReady = fs.existsSync(paths.bunPath) && fs.existsSync(paths.pnpmPath);
32
+ if (toolchainReady) {
33
+ process.env.BUN_INSTALL ??= paths.bunInstall;
34
+ process.env.PNPM_HOME ??= paths.pnpmHome;
35
+ }
36
+ const pathParts = toolchainReady ? [paths.binDir, process.env.PATH ?? ""] : [process.env.PATH ?? ""];
37
+ const seen = /* @__PURE__ */ new Set();
38
+ process.env.PATH = pathParts.flatMap((part) => part.split(path.delimiter)).filter((part) => {
39
+ if (!part || seen.has(part)) return false;
40
+ seen.add(part);
41
+ return true;
42
+ }).join(path.delimiter);
43
+ try {
44
+ fs.mkdirSync(internalDir, { recursive: true });
45
+ fs.writeFileSync(pathsJson, JSON.stringify(paths, null, 2));
46
+ } catch {}
47
+ return {
48
+ paths,
49
+ needsToolchainDownload: !toolchainReady
50
+ };
51
+ }
52
+ //#endregion
2
53
  export { bootstrapEnv };
@@ -0,0 +1 @@
1
+ export { };
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
- import { t as bootstrapEnv } from "./env-bootstrap-BtVME-CU.mjs";
2
- import { t as setupGate } from "./setup-gate-BqOzm7zp.mjs";
3
- import { a as runtime, i as optional, n as Service, o as serviceWithDeps, r as ServiceRuntime, t as CleanupReason } from "./runtime-CjqDr8Yf.mjs";
4
- import { n as SchemaRoot, o as schema, t as CoreSchema } from "./schema-DMoSkwUx.mjs";
5
- import { i as CoreServiceRouter, n as CoreEvents, r as CorePreloads, t as CoreDbSections } from "./registry-Dh_e7HU1.mjs";
1
+ import { a as ServiceRuntime, d as optional, g as serviceWithDeps, h as runtime, i as Service, t as CleanupReason } from "./runtime-pCeVzj--.mjs";
2
+ import { t as bootstrapEnv } from "./env-bootstrap-DW2hVhSO.mjs";
3
+ import { t as setupGate } from "./setup-gate-Dcy8gGPJ.mjs";
4
+ import { n as SchemaRoot, o as schema, t as CoreSchema } from "./schema-Dl85YjXW.mjs";
5
+ import { i as CoreServiceRouter, n as CoreEvents, r as CorePreloads, t as CoreDbSections } from "./registry-eX6e2oql.mjs";
6
6
  export { CleanupReason, CoreDbSections, CoreEvents, CorePreloads, CoreSchema, SchemaRoot as CoreSchemaRoot, CoreServiceRouter, Service, ServiceRuntime, bootstrapEnv, schema as coreSchema, optional, runtime, serviceWithDeps, setupGate };
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { t as bootstrapEnv } from "./env-bootstrap-rj7I-59x.mjs";
2
- import { t as setupGate } from "./setup-gate-BcoqWu8S.mjs";
3
- import { a as serviceWithDeps, i as runtime, n as ServiceRuntime, r as optional, t as Service } from "./runtime-DUFKDIe4.mjs";
4
- import { t as schema } from "./schema-dGK6qkfR.mjs";
1
+ import { bootstrapEnv } from "./env-bootstrap.mjs";
2
+ import { setupGate } from "./setup-gate.mjs";
3
+ import { Service, ServiceRuntime, optional, runtime, serviceWithDeps } from "./runtime.mjs";
4
+ import { schema } from "./schema.mjs";
5
5
  export { Service, ServiceRuntime, bootstrapEnv, schema as coreSchema, optional, runtime, serviceWithDeps, setupGate };
@@ -1,11 +1,17 @@
1
+ import { t as loadConfig } from "./load-config-xMf2wxH8.mjs";
1
2
  import fs from "node:fs";
2
3
  import path from "node:path";
3
4
  //#region src/cli/commands/link.ts
4
- function findManifest(from) {
5
+ const CONFIG_NAMES = [
6
+ "zenbu.config.ts",
7
+ "zenbu.config.mts",
8
+ "zenbu.config.js",
9
+ "zenbu.config.mjs"
10
+ ];
11
+ function findProjectDir(from) {
5
12
  let dir = path.resolve(from);
6
13
  while (true) {
7
- const candidate = path.join(dir, "zenbu.plugin.json");
8
- if (fs.existsSync(candidate)) return candidate;
14
+ for (const name of CONFIG_NAMES) if (fs.existsSync(path.join(dir, name))) return dir;
9
15
  const parent = path.dirname(dir);
10
16
  if (parent === dir) return null;
11
17
  dir = parent;
@@ -44,23 +50,12 @@ function readRegistryDirFromTsconfig(tsconfigPath) {
44
50
  }
45
51
  }
46
52
  /**
47
- * An app root is the nearest ancestor (or self) that contains BOTH a
48
- * `zenbu.plugin.json` and a `config.json` whose `plugins` is an array.
49
- * That signature distinguishes the app from a bare plugin manifest.
53
+ * An app root is the nearest ancestor (or self) that contains a
54
+ * `zenbu.config.ts` (or its .mts/.js/.mjs variants). That single file
55
+ * uniquely identifies a Zenbu project root.
50
56
  */
51
57
  function findAppRoot(from) {
52
- let dir = path.resolve(from);
53
- while (true) {
54
- const manifest = path.join(dir, "zenbu.plugin.json");
55
- const config = path.join(dir, "config.json");
56
- if (fs.existsSync(manifest) && fs.existsSync(config)) try {
57
- const parsed = JSON.parse(fs.readFileSync(config, "utf8"));
58
- if (Array.isArray(parsed?.plugins)) return dir;
59
- } catch {}
60
- const parent = path.dirname(dir);
61
- if (parent === dir) return null;
62
- dir = parent;
63
- }
58
+ return findProjectDir(from);
64
59
  }
65
60
  /**
66
61
  * Pick the directory `zen link` should write registry types into.
@@ -86,10 +81,10 @@ function resolveRegistryDir(opts) {
86
81
  if (appRoot) return path.join(appRoot, "types");
87
82
  console.error(`zen link: could not determine target types directory for ${opts.manifestPath}.`);
88
83
  console.error(` Try one of:`);
89
- console.error(` run from inside an app dir (with both zenbu.plugin.json and config.json),`);
90
- console.error(` add a "devAppPath" field to ${path.basename(opts.manifestPath)} pointing at the host app,`);
91
- console.error(` create a tsconfig.local.json with a "#registry/*" path mapping,`);
92
- console.error(` or pass --registry <dir>.`);
84
+ console.error(` - run from inside an app dir (with a zenbu.config.ts),`);
85
+ console.error(` - add a "devAppPath" field to ${path.basename(opts.manifestPath)} pointing at the host app,`);
86
+ console.error(` - create a tsconfig.local.json with a "#registry/*" path mapping,`);
87
+ console.error(` - or pass --registry <dir>.`);
93
88
  process.exit(1);
94
89
  }
95
90
  function expandGlob(baseDir, pattern) {
@@ -307,7 +302,6 @@ function readExistingRegistry(registryDir) {
307
302
  if (fs.existsSync(servicesPath)) {
308
303
  const content = fs.readFileSync(servicesPath, "utf8");
309
304
  const importRe = /import type \{ (\w+)(?:\s+as\s+(\w+))? \} from "([^"]+)"/g;
310
- const routerRe = /^\s+(?:"([^"]+)"|(\w+)):\s+ExtractRpcMethods<(\w+)>/gm;
311
305
  const importMap = /* @__PURE__ */ new Map();
312
306
  for (const m of content.matchAll(importRe)) {
313
307
  const className = m[1];
@@ -319,31 +313,6 @@ function readExistingRegistry(registryDir) {
319
313
  filePath: absPath
320
314
  });
321
315
  }
322
- for (const m of content.matchAll(routerRe)) {
323
- const key = m[1] ?? m[2];
324
- const alias = m[3];
325
- const imp = importMap.get(alias);
326
- if (!imp) continue;
327
- let pluginName = null;
328
- let dir = path.dirname(imp.filePath);
329
- while (dir !== path.dirname(dir)) {
330
- const candidate = path.join(dir, "zenbu.plugin.json");
331
- if (fs.existsSync(candidate)) {
332
- try {
333
- pluginName = JSON.parse(fs.readFileSync(candidate, "utf8")).name;
334
- } catch {}
335
- break;
336
- }
337
- dir = path.dirname(dir);
338
- }
339
- if (!pluginName) continue;
340
- if (!services.has(pluginName)) services.set(pluginName, []);
341
- services.get(pluginName).push({
342
- className: imp.className,
343
- key,
344
- filePath: imp.filePath
345
- });
346
- }
347
316
  }
348
317
  const dbPath = path.join(registryDir, "db-sections.ts");
349
318
  if (fs.existsSync(dbPath)) {
@@ -387,32 +356,6 @@ function readExistingRegistry(registryDir) {
387
356
  });
388
357
  }
389
358
  }
390
- const eventsRegistryPath = path.join(registryDir, "events.ts");
391
- if (fs.existsSync(eventsRegistryPath)) {
392
- const content = fs.readFileSync(eventsRegistryPath, "utf8");
393
- for (const m of content.matchAll(/import type \{ Events as (\w+) \} from "([^"]+)"/g)) {
394
- m[1];
395
- const relPath = m[2];
396
- const eventsPath = path.resolve(registryDir, relPath) + ".ts";
397
- let pluginName = null;
398
- let dir = path.dirname(eventsPath);
399
- while (dir !== path.dirname(dir)) {
400
- const candidate = path.join(dir, "zenbu.plugin.json");
401
- if (fs.existsSync(candidate)) {
402
- try {
403
- pluginName = JSON.parse(fs.readFileSync(candidate, "utf8")).name;
404
- } catch {}
405
- break;
406
- }
407
- dir = path.dirname(dir);
408
- }
409
- if (!pluginName) continue;
410
- events.set(pluginName, {
411
- name: pluginName,
412
- eventsPath
413
- });
414
- }
415
- }
416
359
  return {
417
360
  services,
418
361
  schemas,
@@ -438,10 +381,48 @@ function parseLinkArgs(argv) {
438
381
  registryOverride
439
382
  };
440
383
  }
441
- function linkOne(manifestPath, existing) {
442
- const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
384
+ /**
385
+ * Variant for path-based plugin sources (a `zenbu.plugin.ts` whose default
386
+ * export is a `definePlugin({...})`). Resolved upstream by `loadConfig` so
387
+ * we just consume the resolved record here.
388
+ */
389
+ function linkResolvedPlugin(plugin, existing) {
390
+ console.log(`Linking types "${plugin.name}" from ${plugin.dir}`);
391
+ const serviceGlobs = plugin.services.map((abs) => path.relative(plugin.dir, abs).split(path.sep).join("/"));
392
+ const serviceEntries = discoverServices(plugin.dir, serviceGlobs);
393
+ console.log(` Found ${serviceEntries.length} service(s)`);
394
+ const schemaEntry = plugin.schemaPath ? {
395
+ name: plugin.name,
396
+ schemaPath: plugin.schemaPath
397
+ } : null;
398
+ if (schemaEntry) console.log(` Schema: ${schemaEntry.schemaPath}`);
399
+ const preloadEntry = plugin.preloadPath ? {
400
+ name: plugin.name,
401
+ preloadPath: plugin.preloadPath
402
+ } : null;
403
+ if (preloadEntry) console.log(` Preload: ${preloadEntry.preloadPath}`);
404
+ const eventsEntry = plugin.eventsPath ? {
405
+ name: plugin.name,
406
+ eventsPath: plugin.eventsPath
407
+ } : null;
408
+ if (eventsEntry) console.log(` Events: ${eventsEntry.eventsPath}`);
409
+ existing.services.set(plugin.name, serviceEntries);
410
+ if (schemaEntry) existing.schemas.set(plugin.name, schemaEntry);
411
+ if (preloadEntry) existing.preloads.set(plugin.name, preloadEntry);
412
+ else existing.preloads.delete(plugin.name);
413
+ if (eventsEntry) existing.events.set(plugin.name, eventsEntry);
414
+ else existing.events.delete(plugin.name);
415
+ }
416
+ /**
417
+ * Variant for the framework-internal `--types-config <path>` flow where the
418
+ * input is a small JSON file (e.g. `packages/core/zenbu-types.config.json`).
419
+ * Used by `pnpm link:types` inside core to bake its own services/registry
420
+ * types without going through a `zenbu.config.ts`.
421
+ */
422
+ function linkTypesConfig(jsonPath, existing) {
423
+ const manifest = JSON.parse(fs.readFileSync(jsonPath, "utf8"));
443
424
  const pluginName = manifest.name;
444
- const baseDir = path.dirname(manifestPath);
425
+ const baseDir = path.dirname(jsonPath);
445
426
  console.log(`Linking types "${pluginName}" from ${baseDir}`);
446
427
  const serviceEntries = discoverServices(baseDir, manifest.services ?? []);
447
428
  console.log(` Found ${serviceEntries.length} service(s)`);
@@ -491,11 +472,10 @@ function linkOne(manifestPath, existing) {
491
472
  * `"extends": "./tsconfig.local.json"`. The generated file then carries
492
473
  * `paths` + `include`, which TS merges into the IDE's resolved program.
493
474
  */
494
- function writePluginTsconfigLocal(pluginManifestPath, registryDir) {
495
- const pluginDir = path.dirname(pluginManifestPath);
475
+ function writePluginTsconfigLocal(pluginDir, registryDir) {
496
476
  const ownTsconfig = path.join(pluginDir, "tsconfig.json");
497
477
  if (!fs.existsSync(ownTsconfig)) return;
498
- if (fs.existsSync(path.join(pluginDir, "config.json"))) return;
478
+ for (const name of CONFIG_NAMES) if (fs.existsSync(path.join(pluginDir, name))) return;
499
479
  const target = path.join(pluginDir, "tsconfig.local.json");
500
480
  let registryRel = path.relative(pluginDir, registryDir);
501
481
  if (!registryRel.startsWith(".")) registryRel = "./" + registryRel;
@@ -512,55 +492,44 @@ function writePluginTsconfigLocal(pluginManifestPath, registryDir) {
512
492
  fs.writeFileSync(target, next);
513
493
  console.log(` Wrote ${target}`);
514
494
  }
515
- /**
516
- * When the manifest being linked is the host app's own manifest (sitting
517
- * next to its `config.json`), expand the work list to also include every
518
- * plugin path declared in `config.json#plugins`. For any other manifest
519
- * (a plugin sitting inside or outside the app), only that single manifest
520
- * is returned — the caller decides not to touch sibling plugins.
521
- */
522
- function expandAppManifests(manifestPath) {
523
- const manifestDir = path.dirname(manifestPath);
524
- const appRoot = findAppRoot(manifestDir);
525
- if (appRoot !== manifestDir) return [manifestPath];
526
- const configPath = path.join(appRoot, "config.json");
527
- let pluginEntries = [];
528
- try {
529
- const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
530
- if (Array.isArray(config?.plugins)) pluginEntries = config.plugins;
531
- } catch {}
532
- const all = [manifestPath];
533
- for (const entry of pluginEntries) {
534
- const resolved = path.isAbsolute(entry) ? entry : path.resolve(appRoot, entry);
535
- if (path.resolve(resolved) === path.resolve(manifestPath)) continue;
536
- if (!fs.existsSync(resolved)) {
537
- console.warn(` ⚠ skipping ${entry} (not found at ${resolved})`);
538
- continue;
539
- }
540
- all.push(resolved);
541
- }
542
- return all;
543
- }
544
495
  async function runLink(argv) {
545
496
  const { manifestArg, typesConfigArg, registryOverride } = parseLinkArgs(argv);
546
- const typeConfigPath = typesConfigArg ? path.resolve(typesConfigArg) : null;
547
- const manifestPath = typeConfigPath ? null : manifestArg ? path.resolve(manifestArg) : findManifest(process.cwd());
548
- if (!typeConfigPath && !manifestPath) {
549
- console.error("zen link: could not find zenbu.plugin.json in current directory or any parent.");
497
+ if (typesConfigArg) {
498
+ const typeConfigPath = path.resolve(typesConfigArg);
499
+ const registryDir = resolveRegistryDir({
500
+ manifestPath: typeConfigPath,
501
+ manifest: JSON.parse(fs.readFileSync(typeConfigPath, "utf8")),
502
+ registryOverride
503
+ });
504
+ console.log(`Registry: ${registryDir}`);
505
+ fs.mkdirSync(registryDir, { recursive: true });
506
+ const existing = readExistingRegistry(registryDir);
507
+ linkTypesConfig(typeConfigPath, existing);
508
+ writeRegistryFiles(registryDir, existing);
509
+ console.log("Done.");
510
+ return;
511
+ }
512
+ const projectDir = manifestArg ? path.resolve(manifestArg) : findProjectDir(process.cwd());
513
+ if (!projectDir) {
514
+ console.error("zen link: could not find zenbu.config.ts in current directory or any parent.");
550
515
  console.error(" For internal framework types, pass --types-config <path>.");
551
516
  process.exit(1);
552
517
  }
553
- const rootConfigPath = typeConfigPath ?? manifestPath;
518
+ const { resolved } = await loadConfig(projectDir);
554
519
  const registryDir = resolveRegistryDir({
555
- manifestPath: rootConfigPath,
556
- manifest: JSON.parse(fs.readFileSync(rootConfigPath, "utf8")),
520
+ manifestPath: resolved.configPath,
521
+ manifest: {},
557
522
  registryOverride
558
523
  });
559
524
  console.log(`Registry: ${registryDir}`);
560
- const manifestPaths = typeConfigPath ? [typeConfigPath] : expandAppManifests(manifestPath);
561
525
  fs.mkdirSync(registryDir, { recursive: true });
562
526
  const existing = readExistingRegistry(registryDir);
563
- for (const mp of manifestPaths) linkOne(mp, existing);
527
+ for (const plugin of resolved.plugins) linkResolvedPlugin(plugin, existing);
528
+ writeRegistryFiles(registryDir, existing);
529
+ for (const plugin of resolved.plugins) writePluginTsconfigLocal(plugin.dir, registryDir);
530
+ console.log("Done.");
531
+ }
532
+ function writeRegistryFiles(registryDir, existing) {
564
533
  const writes = [
565
534
  ["services.ts", generateServicesFile(registryDir, existing.services)],
566
535
  ["db-sections.ts", generateDbSectionsFile(registryDir, existing.schemas)],
@@ -573,8 +542,6 @@ async function runLink(argv) {
573
542
  fs.writeFileSync(target, body);
574
543
  console.log(` Wrote ${target}`);
575
544
  }
576
- for (const mp of manifestPaths) writePluginTsconfigLocal(mp, registryDir);
577
- console.log("Done.");
578
545
  }
579
546
  //#endregion
580
547
  export { runLink };
@@ -0,0 +1,141 @@
1
+ import { n as __exportAll } from "./chunk-DsiFFCwN.mjs";
2
+ import { i as resolveBuildConfig } from "./build-config-C3a-o3_B.mjs";
3
+ import { createRequire } from "node:module";
4
+ import fs from "node:fs";
5
+ import path from "node:path";
6
+ import { pathToFileURL } from "node:url";
7
+ //#region src/cli/lib/load-config.ts
8
+ var load_config_exports = /* @__PURE__ */ __exportAll({
9
+ findConfigPath: () => findConfigPath,
10
+ loadConfig: () => loadConfig
11
+ });
12
+ const localRequire = createRequire(import.meta.url);
13
+ const CONFIG_NAMES = [
14
+ "zenbu.config.ts",
15
+ "zenbu.config.mts",
16
+ "zenbu.config.js",
17
+ "zenbu.config.mjs"
18
+ ];
19
+ const PLUGIN_FILE_RE = /\.(?:ts|mts|js|mjs|cjs)$/;
20
+ function findConfigPath(projectDir) {
21
+ for (const name of CONFIG_NAMES) {
22
+ const candidate = path.join(projectDir, name);
23
+ if (fs.existsSync(candidate)) return candidate;
24
+ }
25
+ throw new Error(`No zenbu config found at ${projectDir}. Expected one of: ${CONFIG_NAMES.join(", ")}`);
26
+ }
27
+ let tsxRegistered = null;
28
+ function ensureTsxRegistered() {
29
+ if (tsxRegistered) return tsxRegistered;
30
+ tsxRegistered = (async () => {
31
+ try {
32
+ const tsxApi = localRequire("tsx/esm/api");
33
+ if (typeof tsxApi.register === "function") tsxApi.register();
34
+ } catch {}
35
+ })();
36
+ return tsxRegistered;
37
+ }
38
+ /**
39
+ * Dynamically import a TS module with a cache-busting query string. Each call
40
+ * forces tsx + Node's ESM loader to re-evaluate the file. Used to rebuild
41
+ * the resolved config + plugin set every time the loader is invoked, so a
42
+ * change to the source TS triggers a fresh `default` export.
43
+ *
44
+ * The returned object is whatever the module's default export is. Older
45
+ * defineConfig-style files that exported the object directly (no `default`)
46
+ * also work via the `mod.default ?? mod` fallback.
47
+ */
48
+ async function importFresh(absPath) {
49
+ await ensureTsxRegistered();
50
+ const mod = await import(pathToFileURL(absPath).href + "?t=" + Date.now());
51
+ return mod.default ?? mod;
52
+ }
53
+ function assertPluginShape(p, source) {
54
+ if (!p || typeof p !== "object") throw new Error(`${source} did not export a Plugin object.`);
55
+ const obj = p;
56
+ if (typeof obj.name !== "string" || obj.name.length === 0) throw new Error(`${source}: plugin missing required string \`name\`.`);
57
+ if (!Array.isArray(obj.services)) throw new Error(`${source}: plugin \`services\` must be an array of glob strings.`);
58
+ }
59
+ function resolvePluginPaths(plugin, dir) {
60
+ const abs = (rel) => path.isAbsolute(rel) ? rel : path.resolve(dir, rel);
61
+ return {
62
+ name: plugin.name,
63
+ dir,
64
+ services: plugin.services.map((s) => path.isAbsolute(s) ? s : path.resolve(dir, s)),
65
+ schemaPath: plugin.schema ? abs(plugin.schema) : void 0,
66
+ migrationsPath: plugin.migrations ? abs(plugin.migrations) : void 0,
67
+ preloadPath: plugin.preload ? abs(plugin.preload) : void 0,
68
+ eventsPath: plugin.events ? abs(plugin.events) : void 0,
69
+ icons: plugin.icons
70
+ };
71
+ }
72
+ async function resolvePluginEntry(entry, configDir) {
73
+ if (typeof entry === "string") {
74
+ const absPath = path.isAbsolute(entry) ? entry : path.resolve(configDir, entry);
75
+ if (!PLUGIN_FILE_RE.test(absPath)) throw new Error(`Plugin entry "${entry}" must point at a .ts/.js file (got ${path.basename(absPath)}). JSON plugin manifests are not supported in the new config; convert to \`zenbu.plugin.ts\`.`);
76
+ if (!fs.existsSync(absPath)) throw new Error(`Plugin entry "${entry}" does not exist at ${absPath}.`);
77
+ const plugin = await importFresh(absPath);
78
+ assertPluginShape(plugin, absPath);
79
+ return {
80
+ resolved: resolvePluginPaths(plugin, path.dirname(absPath)),
81
+ sourceFile: absPath
82
+ };
83
+ }
84
+ assertPluginShape(entry, "(inline plugin)");
85
+ return {
86
+ resolved: resolvePluginPaths(entry, configDir),
87
+ sourceFile: null
88
+ };
89
+ }
90
+ /**
91
+ * Read `<projectDir>/zenbu.config.ts`, resolve all plugin entries (inline +
92
+ * path), make every relative path absolute, and fill in `build` defaults.
93
+ *
94
+ * Used both by the loader (to generate the plugin barrel; cache-busted on
95
+ * every invocation) and by CLI commands (`build:source`, `build:electron`,
96
+ * `link`, `db generate`, `publish:source`).
97
+ */
98
+ async function loadConfig(projectDir) {
99
+ const configPath = findConfigPath(projectDir);
100
+ const config = await importFresh(configPath);
101
+ if (!config || typeof config !== "object") throw new Error(`${configPath} default export is not a Config object.`);
102
+ if (typeof config.db !== "string" || config.db.length === 0) throw new Error(`${configPath}: missing required \`db\` field (path to the database directory).`);
103
+ if (typeof config.uiEntrypoint !== "string" || config.uiEntrypoint.length === 0) throw new Error(`${configPath}: missing required \`uiEntrypoint\` field (directory holding index.html + splash.html).`);
104
+ if (!Array.isArray(config.plugins)) throw new Error(`${configPath}: \`plugins\` must be an array.`);
105
+ const configDir = path.dirname(configPath);
106
+ const dbPath = path.isAbsolute(config.db) ? config.db : path.resolve(configDir, config.db);
107
+ const uiEntrypointPath = path.isAbsolute(config.uiEntrypoint) ? config.uiEntrypoint : path.resolve(configDir, config.uiEntrypoint);
108
+ if (!(() => {
109
+ try {
110
+ return fs.statSync(uiEntrypointPath);
111
+ } catch {
112
+ return null;
113
+ }
114
+ })()?.isDirectory()) throw new Error(`${configPath}: uiEntrypoint must point at a directory; got ${config.uiEntrypoint}.`);
115
+ const splashPath = path.join(uiEntrypointPath, "splash.html");
116
+ if (!fs.existsSync(splashPath)) throw new Error(`${configPath}: uiEntrypoint directory ${config.uiEntrypoint} is missing required \`splash.html\`. The splash file is shown raw (no Vite) during the brief window between Electron startup and the app's first paint.`);
117
+ const plugins = [];
118
+ const pluginSourceFiles = [];
119
+ for (const entry of config.plugins) {
120
+ const { resolved, sourceFile } = await resolvePluginEntry(entry, configDir);
121
+ plugins.push(resolved);
122
+ if (sourceFile) pluginSourceFiles.push(sourceFile);
123
+ }
124
+ return {
125
+ resolved: {
126
+ configPath,
127
+ projectDir: configDir,
128
+ dbPath,
129
+ uiEntrypointPath,
130
+ splashPath,
131
+ plugins,
132
+ build: resolveBuildConfig(config.build ?? {
133
+ source: ".",
134
+ include: ["**/*"]
135
+ })
136
+ },
137
+ pluginSourceFiles
138
+ };
139
+ }
140
+ //#endregion
141
+ export { load_config_exports as n, loadConfig as t };
@@ -14,8 +14,25 @@ type TracePort = {
14
14
  };
15
15
  type InitializeData = {
16
16
  tracePort?: TracePort;
17
+ payload?: RegistryPayload;
18
+ pluginSourceFiles?: string[];
17
19
  };
18
20
  declare function initialize(data?: InitializeData): void;
21
+ interface ResolvedPluginRecord {
22
+ name: string;
23
+ dir: string;
24
+ services: string[];
25
+ schemaPath?: string;
26
+ migrationsPath?: string;
27
+ preloadPath?: string;
28
+ eventsPath?: string;
29
+ icons?: Record<string, string>;
30
+ }
31
+ interface RegistryPayload {
32
+ plugins: ResolvedPluginRecord[];
33
+ appEntrypoint: string;
34
+ splashPath: string;
35
+ }
19
36
  declare function resolve(specifier: string, context: LoaderContext, nextResolve: NextResolve): unknown;
20
37
  declare function load(url: string, context: LoaderContext, nextLoad: NextLoad): unknown;
21
38
  //#endregion