@zenbujs/core 0.0.4 → 0.0.8

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 (106) hide show
  1. package/dist/{advice-config-BLXjqjGN.mjs → advice-config-DXSIo0sg.mjs} +49 -38
  2. package/dist/advice.d.mts +8 -8
  3. package/dist/advice.mjs +2 -2
  4. package/dist/base-window-BxBZ2md_.mjs +143 -0
  5. package/dist/build-config-Dzg2frpk.d.mts +215 -0
  6. package/dist/build-config-pWdmLnrk.mjs +53 -0
  7. package/dist/{build-electron-C3Beey84.mjs → build-electron-Dsbb1EMl.mjs} +308 -120
  8. package/dist/{build-source-BvC4bPqH.mjs → build-source-d1J3shV8.mjs} +62 -27
  9. package/dist/chunk-DsiFFCwN.mjs +16 -0
  10. package/dist/cli/bin.mjs +7 -7
  11. package/dist/cli/build.d.mts +2 -2
  12. package/dist/cli/build.mjs +2 -3
  13. package/dist/cli/resolve-config.mjs +3 -2
  14. package/dist/{cli-F0B4dvSg.mjs → cli-kL6mPgBE.mjs} +4 -4
  15. package/dist/{config-BlRXeUXx.mjs → config-BK78JDRI.mjs} +1 -1
  16. package/dist/config.d.mts +3 -2
  17. package/dist/config.mjs +3 -3
  18. package/dist/{db-Cd5ETuPG.mjs → db-Bc292RYo.mjs} +2 -2
  19. package/dist/db.d.mts +1 -1
  20. package/dist/db.mjs +2 -2
  21. package/dist/dev-B2emj0HZ.mjs +301 -0
  22. package/dist/env-bootstrap.d.mts +1 -1
  23. package/dist/env-bootstrap.mjs +52 -1
  24. package/dist/events.d.mts +19 -0
  25. package/dist/events.mjs +1 -0
  26. package/dist/host-version-BIrF8tX7.mjs +65 -0
  27. package/dist/index-w5QyDjuf.d.mts +780 -0
  28. package/dist/index.d.mts +5 -6
  29. package/dist/index.mjs +5 -5
  30. package/dist/installing-preload.cjs +60 -0
  31. package/dist/launcher.mjs +2615 -122
  32. package/dist/{link-BJmsKgPa.mjs → link-glX89NV5.mjs} +215 -89
  33. package/dist/{load-config-BG2tPIfF.mjs → load-config-C4Oe2qZO.mjs} +22 -3
  34. package/dist/loaders/zenbu.d.mts +1 -0
  35. package/dist/loaders/zenbu.mjs +108 -86
  36. package/dist/{monorepo-DCruz9Jx.mjs → monorepo-Dct-kkbQ.mjs} +3 -0
  37. package/dist/node-loader.mjs +1 -1
  38. package/dist/{publish-source-34Hn9zb0.mjs → publish-source-Dq2c0iOw.mjs} +2 -2
  39. package/dist/react.d.mts +56 -7
  40. package/dist/react.mjs +118 -7
  41. package/dist/registry-CMp8FYgS.d.mts +47 -0
  42. package/dist/registry-generated.d.mts +26 -0
  43. package/dist/registry-generated.mjs +1 -0
  44. package/dist/registry.d.mts +2 -2
  45. package/dist/{reloader-DJoCB0bC.mjs → reloader-B22UiNA2.mjs} +7 -7
  46. package/dist/{renderer-host-ztaSIOGx.mjs → renderer-host-DD16MXhI.mjs} +178 -57
  47. package/dist/{rpc-CsgWnlZx.mjs → rpc-C4_NQmpT.mjs} +11 -8
  48. package/dist/rpc.d.mts +1 -1
  49. package/dist/rpc.mjs +1 -1
  50. package/dist/runtime-BQWntcOb.d.mts +218 -0
  51. package/dist/runtime.d.mts +2 -2
  52. package/dist/runtime.mjs +578 -2
  53. package/dist/{schema-DvT61x2_.d.mts → schema-CjrMVk36.d.mts} +3 -3
  54. package/dist/schema.d.mts +1 -1
  55. package/dist/schema.mjs +27 -1
  56. package/dist/{server-DB3Eki_G.mjs → server-CZLMF8Dj.mjs} +6 -6
  57. package/dist/services/default.d.mts +3 -3
  58. package/dist/services/default.mjs +14 -13
  59. package/dist/services/index.d.mts +2 -276
  60. package/dist/services/index.mjs +8 -7
  61. package/dist/setup-gate.d.mts +1 -1
  62. package/dist/setup-gate.mjs +341 -1
  63. package/dist/{transform-DJH3vN4b.mjs → transform-BzrwkEdf.mjs} +23 -917
  64. package/dist/{transport-BMSzG2-F.mjs → transport-F2hv_OEm.mjs} +1 -1
  65. package/dist/updater-DCkz9M1c.mjs +1008 -0
  66. package/dist/{vite-plugins-t4MlFcz3.mjs → vite-plugins-tt6KAtyE.mjs} +27 -26
  67. package/dist/vite.d.mts +3 -3
  68. package/dist/vite.mjs +1 -1
  69. package/dist/{window-DUvMTons.mjs → window-YFKvAM0l.mjs} +36 -19
  70. package/dist/{write-9dRFczGJ.mjs → write-DgIRjo23.mjs} +1 -1
  71. package/package.json +18 -5
  72. package/dist/advice-config-D6K_a7e9.mjs +0 -2
  73. package/dist/base-window-D8CpxMU3.mjs +0 -94
  74. package/dist/base-window-OXg2KSyP.mjs +0 -2
  75. package/dist/build-config-BwnnfrN-.mjs +0 -23
  76. package/dist/chunk-Dm34NbLt.mjs +0 -6
  77. package/dist/config-Ch1FreWU.mjs +0 -2
  78. package/dist/db-Bz_CDIWg.mjs +0 -2
  79. package/dist/dev-DLutFPyo.mjs +0 -85
  80. package/dist/env-bootstrap-rj7I-59x.mjs +0 -53
  81. package/dist/http-B36qtsm0.mjs +0 -2
  82. package/dist/load-config-CQG4297M.mjs +0 -2
  83. package/dist/registry-CioEYLI5.d.mts +0 -61
  84. package/dist/reloader-FeHKV2jd.mjs +0 -2
  85. package/dist/renderer-host-BQpS0ZM2.mjs +0 -2
  86. package/dist/rpc-D_s7-WZe.mjs +0 -2
  87. package/dist/runtime-C95iyVn6.mjs +0 -461
  88. package/dist/runtime-CsiDppGF.d.mts +0 -149
  89. package/dist/schema-dGK6qkfR.mjs +0 -28
  90. package/dist/server-CgzQOPSW.mjs +0 -2
  91. package/dist/setup-gate-D8XfYY52.mjs +0 -140
  92. package/dist/transforms-DVoy8dCu.mjs +0 -47
  93. package/dist/transforms-EVd5Fgyk.d.mts +0 -136
  94. package/dist/view-registry-2zePxTEg.mjs +0 -2
  95. package/dist/window-S3TlTXlK.mjs +0 -2
  96. /package/dist/{env-bootstrap-uCKbw2q8.d.mts → env-bootstrap-rTs8KR3-.d.mts} +0 -0
  97. /package/dist/{index-CE0iPntP.d.mts → index-C-ALz_SH.d.mts} +0 -0
  98. /package/dist/{index-CKKoxA9V.d.mts → index-ClXLQ1fw.d.mts} +0 -0
  99. /package/dist/{index-UK58xuoR.d.mts → index-DeDxePAa.d.mts} +0 -0
  100. /package/dist/{log-CyKv8hQg.mjs → log-6rzaCV0I.mjs} +0 -0
  101. /package/dist/{mirror-sync-EiWvdzTJ.mjs → mirror-sync-pYU6f3-c.mjs} +0 -0
  102. /package/dist/{node-CvZnTx53.mjs → node-BhfLKYCi.mjs} +0 -0
  103. /package/dist/{schema-CIg4GzHQ.mjs → schema-Ca7SxXgS.mjs} +0 -0
  104. /package/dist/{setup-gate-D62nX5lk.d.mts → setup-gate-BQq0QgZH.d.mts} +0 -0
  105. /package/dist/{src-pELM4_iH.mjs → src-Cven45mq.mjs} +0 -0
  106. /package/dist/{trace-DCB7qFzT.mjs → trace-BaVg0rnY.mjs} +0 -0
@@ -1,7 +1,17 @@
1
- import { a as getPlugins, u as runtime } from "./runtime-C95iyVn6.mjs";
1
+ import { n as __exportAll } from "./chunk-DsiFFCwN.mjs";
2
+ import { getPlugins, runtime } from "./runtime.mjs";
2
3
  import path from "node:path";
3
4
  import { fileURLToPath } from "node:url";
4
5
  //#region src/services/advice-config.ts
6
+ var advice_config_exports = /* @__PURE__ */ __exportAll({
7
+ getAdvice: () => getAdvice,
8
+ getAllAdviceTypes: () => getAllAdviceTypes,
9
+ getAllContentScriptPaths: () => getAllContentScriptPaths,
10
+ getAllTypes: () => getAllTypes,
11
+ getContentScripts: () => getContentScripts,
12
+ registerAdvice: () => registerAdvice,
13
+ registerContentScript: () => registerContentScript
14
+ });
5
15
  /**
6
16
  * Find the plugin whose `dir` contains the file at `metaUrl`. The runtime
7
17
  * plugin registry (populated by the loader-emitted barrel) is the source
@@ -43,64 +53,65 @@ const RESOLVED_PREFIX = "\0@advice-prelude/";
43
53
  const APP_RENDERER_RELOADER_ID = "app";
44
54
  const adviceEntries = /* @__PURE__ */ new Map();
45
55
  const contentScripts = /* @__PURE__ */ new Map();
46
- function invalidatePrelude(scope) {
56
+ function invalidatePrelude(type) {
47
57
  try {
48
58
  const reloader = runtime.getSlot("reloader")?.instance;
49
59
  if (!reloader) return;
50
60
  const coreEntry = reloader.get(APP_RENDERER_RELOADER_ID);
51
61
  if (!coreEntry?.viteServer) return;
52
62
  const graph = coreEntry.viteServer.moduleGraph;
53
- const invalidateScope = (s) => {
54
- const prefix = RESOLVED_PREFIX + s;
63
+ const invalidateMatching = (test) => {
55
64
  const ids = [];
56
65
  for (const id of graph.idToModuleMap.keys()) {
57
66
  if (typeof id !== "string") continue;
58
- if (id === prefix || id.startsWith(prefix + "?")) ids.push(id);
67
+ if (test(id)) ids.push(id);
59
68
  }
60
69
  for (const id of ids) {
61
70
  const mod = graph.getModuleById(id);
62
71
  if (mod) graph.invalidateModule(mod);
63
72
  }
64
73
  };
65
- if (scope === "*") for (const s of getAllScopes()) invalidateScope(s);
66
- else invalidateScope(scope);
74
+ if (type === "*") invalidateMatching((id) => id.startsWith(RESOLVED_PREFIX));
75
+ else {
76
+ const prefix = RESOLVED_PREFIX + type;
77
+ invalidateMatching((id) => id === prefix || id.startsWith(prefix + "?"));
78
+ }
67
79
  } catch {}
68
80
  }
69
- function emitReload(scope) {
70
- invalidatePrelude(scope);
81
+ function emitReload(type) {
82
+ invalidatePrelude(type);
71
83
  try {
72
84
  const rpc = runtime.getSlot("rpc")?.instance;
73
85
  if (!rpc) return;
74
- if (scope === "*") for (const s of getAllScopes()) rpc.emit.advice.reload({ scope: s });
75
- else rpc.emit.advice.reload({ scope });
86
+ rpc.emit.advice.reload({ type });
76
87
  } catch {}
77
88
  }
78
- function registerAdvice(scope, entry, meta) {
89
+ function registerAdvice(type, entry, meta) {
79
90
  const resolvedEntry = {
80
91
  ...entry,
81
92
  modulePath: resolvePluginPath(entry.modulePath, meta)
82
93
  };
83
- const list = adviceEntries.get(scope) ?? [];
94
+ const list = adviceEntries.get(type) ?? [];
84
95
  list.push(resolvedEntry);
85
- adviceEntries.set(scope, list);
86
- emitReload(scope);
96
+ adviceEntries.set(type, list);
97
+ emitReload(type);
87
98
  return () => {
88
- const current = adviceEntries.get(scope);
99
+ const current = adviceEntries.get(type);
89
100
  if (!current) return;
90
101
  const idx = current.indexOf(resolvedEntry);
91
102
  if (idx >= 0) current.splice(idx, 1);
92
- if (current.length === 0) adviceEntries.delete(scope);
93
- emitReload(scope);
103
+ if (current.length === 0) adviceEntries.delete(type);
104
+ emitReload(type);
94
105
  };
95
106
  }
96
- function getAdvice(scope) {
97
- return adviceEntries.get(scope) ?? [];
107
+ function getAdvice(type) {
108
+ return adviceEntries.get(type) ?? [];
98
109
  }
99
- function getAllAdviceScopes() {
110
+ function getAllAdviceTypes() {
100
111
  return [...adviceEntries.keys()];
101
112
  }
102
113
  /**
103
- * Register a content script for the given scope. `modulePath` is normally
114
+ * Register a content script for the given view type. `modulePath` is normally
104
115
  * a path relative to the plugin root (the folder with `zenbu.plugin.json`);
105
116
  * pass `import.meta` so we can resolve it. Absolute paths are accepted as
106
117
  * an escape hatch.
@@ -109,35 +120,35 @@ function getAllAdviceScopes() {
109
120
  * registerContentScript("app", "src/content/clock.tsx", import.meta),
110
121
  * )
111
122
  */
112
- function registerContentScript(scope, modulePath, meta) {
123
+ function registerContentScript(type, modulePath, meta) {
113
124
  const entry = { path: resolvePluginPath(modulePath, meta) };
114
- const list = contentScripts.get(scope) ?? [];
125
+ const list = contentScripts.get(type) ?? [];
115
126
  list.push(entry);
116
- contentScripts.set(scope, list);
117
- emitReload(scope === "*" ? "*" : scope);
127
+ contentScripts.set(type, list);
128
+ emitReload(type === "*" ? "*" : type);
118
129
  return () => {
119
- const current = contentScripts.get(scope);
130
+ const current = contentScripts.get(type);
120
131
  if (!current) return;
121
132
  const idx = current.indexOf(entry);
122
133
  if (idx >= 0) current.splice(idx, 1);
123
- if (current.length === 0) contentScripts.delete(scope);
124
- emitReload(scope === "*" ? "*" : scope);
134
+ if (current.length === 0) contentScripts.delete(type);
135
+ emitReload(type === "*" ? "*" : type);
125
136
  };
126
137
  }
127
- function getContentScripts(scope) {
128
- const scoped = (contentScripts.get(scope) ?? []).map((e) => e.path);
129
- return [...scope !== "*" ? (contentScripts.get("*") ?? []).map((e) => e.path) : [], ...scoped];
138
+ function getContentScripts(type) {
139
+ const scoped = (contentScripts.get(type) ?? []).map((e) => e.path);
140
+ return [...type !== "*" ? (contentScripts.get("*") ?? []).map((e) => e.path) : [], ...scoped];
130
141
  }
131
142
  function getAllContentScriptPaths() {
132
143
  const paths = [];
133
144
  for (const list of contentScripts.values()) for (const entry of list) paths.push(entry.path);
134
145
  return paths;
135
146
  }
136
- function getAllScopes() {
137
- const scopes = /* @__PURE__ */ new Set();
138
- for (const k of adviceEntries.keys()) scopes.add(k);
139
- for (const k of contentScripts.keys()) if (k !== "*") scopes.add(k);
140
- return [...scopes];
147
+ function getAllTypes() {
148
+ const types = /* @__PURE__ */ new Set();
149
+ for (const k of adviceEntries.keys()) types.add(k);
150
+ for (const k of contentScripts.keys()) if (k !== "*") types.add(k);
151
+ return [...types];
141
152
  }
142
153
  //#endregion
143
- export { getContentScripts as a, getAllScopes as i, getAllAdviceScopes as n, registerAdvice as o, getAllContentScriptPaths as r, registerContentScript as s, getAdvice as t };
154
+ export { getAllTypes as a, registerContentScript as c, getAllContentScriptPaths as i, getAdvice as n, getContentScripts as o, getAllAdviceTypes as r, registerAdvice as s, advice_config_exports as t };
package/dist/advice.d.mts CHANGED
@@ -15,11 +15,11 @@ interface ViewAdviceEntry {
15
15
  type AdviceSpec = Omit<ViewAdviceEntry, "modulePath"> & {
16
16
  modulePath: string;
17
17
  };
18
- declare function registerAdvice(scope: string, entry: AdviceSpec, meta?: ImportMeta): () => void;
19
- declare function getAdvice(scope: string): ViewAdviceEntry[];
20
- declare function getAllAdviceScopes(): string[];
18
+ declare function registerAdvice(type: string, entry: AdviceSpec, meta?: ImportMeta): () => void;
19
+ declare function getAdvice(type: string): ViewAdviceEntry[];
20
+ declare function getAllAdviceTypes(): string[];
21
21
  /**
22
- * Register a content script for the given scope. `modulePath` is normally
22
+ * Register a content script for the given view type. `modulePath` is normally
23
23
  * a path relative to the plugin root (the folder with `zenbu.plugin.json`);
24
24
  * pass `import.meta` so we can resolve it. Absolute paths are accepted as
25
25
  * an escape hatch.
@@ -28,9 +28,9 @@ declare function getAllAdviceScopes(): string[];
28
28
  * registerContentScript("app", "src/content/clock.tsx", import.meta),
29
29
  * )
30
30
  */
31
- declare function registerContentScript(scope: string, modulePath: string, meta?: ImportMeta): () => void;
32
- declare function getContentScripts(scope: string): string[];
31
+ declare function registerContentScript(type: string, modulePath: string, meta?: ImportMeta): () => void;
32
+ declare function getContentScripts(type: string): string[];
33
33
  declare function getAllContentScriptPaths(): string[];
34
- declare function getAllScopes(): string[];
34
+ declare function getAllTypes(): string[];
35
35
  //#endregion
36
- export { type AdviceSpec, type ViewAdviceEntry, getAdvice, getAllAdviceScopes, getAllContentScriptPaths, getAllScopes, getContentScripts, registerAdvice, registerContentScript };
36
+ export { type AdviceSpec, type ViewAdviceEntry, getAdvice, getAllAdviceTypes, getAllContentScriptPaths, getAllTypes, getContentScripts, registerAdvice, registerContentScript };
package/dist/advice.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { a as getContentScripts, i as getAllScopes, n as getAllAdviceScopes, o as registerAdvice, r as getAllContentScriptPaths, s as registerContentScript, t as getAdvice } from "./advice-config-BLXjqjGN.mjs";
2
- export { getAdvice, getAllAdviceScopes, getAllContentScriptPaths, getAllScopes, getContentScripts, registerAdvice, registerContentScript };
1
+ import { a as getAllTypes, c as registerContentScript, i as getAllContentScriptPaths, n as getAdvice, o as getContentScripts, r as getAllAdviceTypes, s as registerAdvice } from "./advice-config-DXSIo0sg.mjs";
2
+ export { getAdvice, getAllAdviceTypes, getAllContentScriptPaths, getAllTypes, getContentScripts, registerAdvice, registerContentScript };
@@ -0,0 +1,143 @@
1
+ import { n as __exportAll } from "./chunk-DsiFFCwN.mjs";
2
+ import { Service, getAppEntrypoint, runtime } from "./runtime.mjs";
3
+ import { t as createLogger } from "./log-6rzaCV0I.mjs";
4
+ import { a as DbService } from "./renderer-host-DD16MXhI.mjs";
5
+ import fs from "node:fs";
6
+ import path from "node:path";
7
+ import { nanoid } from "nanoid";
8
+ import { BaseWindow } from "electron";
9
+ //#region src/shared/zenbu-bg.ts
10
+ const META_RE = /<meta\s+name=["']zenbu-bg["']\s+content=["']([^"']+)["']/i;
11
+ /**
12
+ * Read the `<meta name="zenbu-bg" content="#xxx">` value from an HTML
13
+ * file. Returns the configured value, or `fallback` when the file is
14
+ * missing, unreadable, or has no `zenbu-bg` meta tag.
15
+ *
16
+ * This convention exists because Electron paints a `BaseWindow`'s
17
+ * `backgroundColor` for the brief window between the window appearing
18
+ * on screen and the `WebContentsView`'s first frame reaching the
19
+ * compositor — and similarly the view itself flashes its
20
+ * `setBackgroundColor` before any HTML renders. Reading the meta from
21
+ * the same HTML the renderer will paint keeps both colors in sync with
22
+ * whatever theme the renderer is committing to (`#111` for a dark app,
23
+ * `#F4F4F4` for a light one), so the user never sees a single white
24
+ * frame on window open.
25
+ */
26
+ function readZenbuBgColor(htmlPath, fallback = "#F4F4F4") {
27
+ try {
28
+ const match = fs.readFileSync(htmlPath, "utf8").match(META_RE);
29
+ if (match?.[1]) return match[1];
30
+ } catch {}
31
+ return fallback;
32
+ }
33
+ /**
34
+ * Resolve the renderer entrypoint's `zenbu-bg` color via the global
35
+ * plugin registry. Convenience wrapper: services creating windows
36
+ * post-boot don't need to plumb the entrypoint path through —
37
+ * `getAppEntrypoint()` returns whatever was published by the loader's
38
+ * registry-setup module at import time.
39
+ *
40
+ * Returns `fallback` if the registry hasn't been populated yet (i.e.
41
+ * pre-loader code paths) or if the entrypoint dir has no `index.html`
42
+ * with a `zenbu-bg` meta tag.
43
+ */
44
+ function entrypointBgColor(fallback = "#F4F4F4") {
45
+ const entrypoint = getAppEntrypoint();
46
+ if (!entrypoint) return fallback;
47
+ return readZenbuBgColor(path.join(entrypoint, "index.html"), fallback);
48
+ }
49
+ //#endregion
50
+ //#region src/services/base-window.ts
51
+ var base_window_exports = /* @__PURE__ */ __exportAll({
52
+ BaseWindowService: () => BaseWindowService,
53
+ MAIN_WINDOW_ID: () => MAIN_WINDOW_ID
54
+ });
55
+ const log = createLogger("base-window");
56
+ const MAIN_WINDOW_ID = "main";
57
+ var BaseWindowService = class extends Service.create({
58
+ key: "base-window",
59
+ deps: { db: DbService }
60
+ }) {
61
+ windows = /* @__PURE__ */ new Map();
62
+ get bootWindows() {
63
+ return globalThis.__zenbu_boot_windows__ ?? [];
64
+ }
65
+ set bootWindows(v) {
66
+ globalThis.__zenbu_boot_windows__ = v;
67
+ }
68
+ getZenWidth() {
69
+ const flag = process.argv.find((a) => a.startsWith("--zen-width="));
70
+ if (!flag) return void 0;
71
+ const n = parseInt(flag.slice(12), 10);
72
+ return isNaN(n) ? void 0 : n;
73
+ }
74
+ getWindowId(win) {
75
+ for (const [id, w] of this.windows) if (w === win) return id;
76
+ }
77
+ createWindow(opts) {
78
+ const windowId = opts?.windowId ?? nanoid();
79
+ const zenWidth = this.getZenWidth();
80
+ const win = new BaseWindow({
81
+ width: opts?.width ?? zenWidth ?? 1100,
82
+ height: opts?.height ?? 750,
83
+ ...opts?.x != null && opts?.y != null ? {
84
+ x: opts.x,
85
+ y: opts.y
86
+ } : {},
87
+ show: opts?.show ?? true,
88
+ titleBarStyle: "hidden",
89
+ trafficLightPosition: {
90
+ x: 14,
91
+ y: 10
92
+ },
93
+ backgroundColor: entrypointBgColor()
94
+ });
95
+ this.windows.set(windowId, win);
96
+ win.on("closed", () => this.windows.delete(windowId));
97
+ return {
98
+ win,
99
+ windowId
100
+ };
101
+ }
102
+ evaluate() {
103
+ if (this.windows.size === 0) if (this.bootWindows.length > 0) {
104
+ for (const boot of this.bootWindows) {
105
+ this.windows.set(boot.windowId, boot.win);
106
+ boot.win.on("closed", () => this.windows.delete(boot.windowId));
107
+ }
108
+ this.bootWindows = [];
109
+ } else {
110
+ const prefs = this.ctx.db.client.readRoot().plugin.core.windowPrefs;
111
+ this.createWindow({
112
+ windowId: MAIN_WINDOW_ID,
113
+ ...prefs[MAIN_WINDOW_ID]?.lastKnownBounds
114
+ });
115
+ }
116
+ this.setup("window-cleanup", () => {
117
+ return () => {
118
+ const snapshot = [...this.windows.entries()].map(([windowId, win]) => ({
119
+ windowId,
120
+ bounds: win.getBounds()
121
+ }));
122
+ this.ctx.db.client.update((root) => {
123
+ const next = { ...root.plugin.core.windowPrefs };
124
+ for (const { windowId, bounds } of snapshot) next[windowId] = {
125
+ ...next[windowId],
126
+ lastKnownBounds: bounds
127
+ };
128
+ root.plugin.core.windowPrefs = next;
129
+ });
130
+ for (const win of this.windows.values()) {
131
+ win.__zenbu_on_close = null;
132
+ win.__zenbu_on_closed = null;
133
+ win.close();
134
+ }
135
+ this.windows.clear();
136
+ };
137
+ });
138
+ log.verbose(`ready (${this.windows.size} windows)`);
139
+ }
140
+ };
141
+ runtime.register(BaseWindowService, import.meta);
142
+ //#endregion
143
+ export { entrypointBgColor as i, MAIN_WINDOW_ID as n, base_window_exports as r, BaseWindowService as t };
@@ -0,0 +1,215 @@
1
+ //#region src/cli/lib/build-config.d.ts
2
+ interface BuildContext {
3
+ /** Absolute path to the source root (`build.source` resolved). */
4
+ sourceDir: string;
5
+ /** Absolute path to the staging output dir (`build.out` resolved). */
6
+ outDir: string;
7
+ /** Git HEAD of the source repo at build time, or `"uncommitted"`. */
8
+ sourceSha: string;
9
+ /** Absolute path to the `zenbu.config.ts` driving this build. */
10
+ configPath: string;
11
+ }
12
+ interface EmitContext extends BuildContext {
13
+ /**
14
+ * Write an additional file into `outDir`. Relative paths only — anything
15
+ * absolute or escaping `outDir` (via `..`) throws. Emitted files
16
+ * participate in the build's `.sha` content hash.
17
+ */
18
+ emit(relPath: string, contents: string | Uint8Array): void;
19
+ }
20
+ interface BuildPlugin {
21
+ name: string;
22
+ /**
23
+ * Called once per text file after `include`/`ignore` filtering, before
24
+ * the file is written to `outDir`. Plugins run in declaration order;
25
+ * each plugin's return value (if any) feeds the next.
26
+ *
27
+ * Return:
28
+ * - a string → use it as the new contents
29
+ * - `null` → drop the file (short-circuits remaining plugins)
30
+ * - `void` → leave contents unchanged
31
+ *
32
+ * Binary files (anything outside the small text-extension allow-list)
33
+ * are not visible to `transform` — they're copied byte-for-byte.
34
+ */
35
+ transform?(file: {
36
+ path: string;
37
+ contents: string;
38
+ }, ctx: BuildContext): string | null | void | Promise<string | null | void>;
39
+ /**
40
+ * Called once after every source file is written. Use `ctx.emit(...)` to
41
+ * write additional files (build manifests, generated artifacts, etc.)
42
+ * into `outDir`. Plugins run in declaration order.
43
+ */
44
+ done?(ctx: EmitContext): void | Promise<void>;
45
+ }
46
+ interface MirrorConfig {
47
+ target: string;
48
+ branch?: string;
49
+ }
50
+ interface BundleConfig {
51
+ extraResources?: string[];
52
+ }
53
+ /**
54
+ * Which package manager the produced .app should bundle and use to install
55
+ * the cloned source's dependencies on first launch.
56
+ *
57
+ * Exactly one PM per .app. The `version` is honored verbatim across all four
58
+ * variants: it drives the download URL at build time and is recorded in
59
+ * `app-config.json` so the launcher knows which CI-mode codepath to take.
60
+ *
61
+ * `bun` is not special at the API layer — but internally the runtime bun and
62
+ * the PM bun are collapsed into a single binary at the user's chosen
63
+ * version (so picking bun yields one binary in the bundle, not two).
64
+ */
65
+ type PackageManagerSpec = {
66
+ type: "pnpm";
67
+ version: string;
68
+ } | {
69
+ type: "npm";
70
+ version: string;
71
+ } | {
72
+ type: "yarn";
73
+ version: string;
74
+ } | {
75
+ type: "bun";
76
+ version: string;
77
+ };
78
+ interface BuildConfig {
79
+ /**
80
+ * The .app's "host version" — the developer's product version for the
81
+ * Electron+core+toolchain bundle as a whole. Required, semver-shaped
82
+ * (e.g. `"0.0.6"`).
83
+ *
84
+ * This is NOT derived from `package.json#version` (which lives in the
85
+ * source tree and gets overwritten by `git pull`) or from
86
+ * `@zenbujs/core`'s installed version (a transitive dep, not the
87
+ * developer's product). Bump it whenever you ship a new .app build.
88
+ *
89
+ * `zen build:electron` writes this verbatim into `<bundle>/host.json`.
90
+ * The launcher and `UpdaterService` read that file to drive
91
+ * compatibility checks against each commit's `package.json#zenbu.host`
92
+ * range — the predicate is
93
+ * `semver.satisfies(hostVersion, commitPackageJson.zenbu.host)`.
94
+ */
95
+ hostVersion: string;
96
+ source?: string;
97
+ out?: string;
98
+ include: string[];
99
+ ignore?: string[];
100
+ plugins?: BuildPlugin[];
101
+ mirror?: MirrorConfig;
102
+ bundle?: BundleConfig;
103
+ packageManager?: PackageManagerSpec;
104
+ }
105
+ declare function defineBuildConfig(config: BuildConfig): BuildConfig;
106
+ type ResolvedBuildConfig = Required<Omit<BuildConfig, "mirror" | "bundle">> & {
107
+ mirror?: MirrorConfig;
108
+ bundle?: BundleConfig;
109
+ packageManager: PackageManagerSpec;
110
+ };
111
+ declare function resolveBuildConfig(config: BuildConfig): ResolvedBuildConfig;
112
+ /**
113
+ * A Zenbu plugin's main-process surface. Plugins are pure main-process: they
114
+ * register services + side-effect modules (schema, preload, events). UI is
115
+ * handled exclusively at the outer config level via `uiEntrypoint` — there
116
+ * is exactly one HTML entrypoint per app.
117
+ *
118
+ * `services` is an array of glob patterns (relative to the plugin file's
119
+ * directory). `schema` / `preload` / `events` are optional file paths.
120
+ */
121
+ interface Plugin {
122
+ name: string;
123
+ services: string[];
124
+ schema?: string;
125
+ migrations?: string;
126
+ preload?: string;
127
+ events?: string;
128
+ /**
129
+ * Plugin-author-defined SVG icons keyed by view type. Read by
130
+ * `view-registry` to decorate registered views. Optional.
131
+ */
132
+ icons?: Record<string, string>;
133
+ }
134
+ declare function definePlugin(plugin: Plugin): Plugin;
135
+ /**
136
+ * A plugin manifest after path resolution. Every relative path has been made
137
+ * absolute against `dir` (the directory the manifest came from). Glob-form
138
+ * service entries stay as patterns (still anchored to `dir`).
139
+ *
140
+ * The runtime stores these in `runtime.getPlugins()`; consumers like
141
+ * `services/db.ts`, `services/advice-config.ts`, `vite-plugins.ts` read from
142
+ * there instead of walking the filesystem looking for `zenbu.plugin.json`.
143
+ */
144
+ interface ResolvedPlugin {
145
+ name: string;
146
+ /** Absolute directory the plugin was loaded from. */
147
+ dir: string;
148
+ /** Glob patterns for service files. Anchored to `dir`. */
149
+ services: string[];
150
+ /** Absolute path to `schema.ts` (or undefined). */
151
+ schemaPath?: string;
152
+ /** Absolute path to migrations dir/file (or undefined). */
153
+ migrationsPath?: string;
154
+ /** Absolute path to `preload.ts` (or undefined). */
155
+ preloadPath?: string;
156
+ /** Absolute path to `events.ts` (or undefined). */
157
+ eventsPath?: string;
158
+ /** Plugin-author-defined SVG icons. */
159
+ icons?: Record<string, string>;
160
+ }
161
+ /**
162
+ * The whole-app `zenbu.config.ts` shape. Authored by user code; imported
163
+ * (and re-imported on every change) by the loader and CLI.
164
+ *
165
+ * - `db`: directory the kyju database lives in (relative to the config file).
166
+ * - `uiEntrypoint`: path to the boot-window's HTML file. Exactly one — there
167
+ * is no per-plugin UI (today's per-plugin `uiEntrypoint` was effectively a
168
+ * bug that the new shape disallows at the type level).
169
+ * - `plugins`: flat list. Each entry is either an inline `definePlugin({...})`
170
+ * or a path to a `zenbu.plugin.ts` whose default export is a plugin. The
171
+ * "host plugin" is just `plugins[0]` by convention; nothing structurally
172
+ * distinguishes it.
173
+ * - `build`: shipped as `defineBuildConfig({...})`. Drives `zen build:source`
174
+ * and `zen build:electron`.
175
+ */
176
+ interface Config {
177
+ db: string;
178
+ uiEntrypoint: string;
179
+ plugins: Array<Plugin | string>;
180
+ build?: BuildConfig;
181
+ }
182
+ declare function defineConfig(config: Config): Config;
183
+ interface ResolvedConfig {
184
+ /** Absolute path to the `zenbu.config.ts` this came from. */
185
+ configPath: string;
186
+ /** Directory containing `zenbu.config.ts`. */
187
+ projectDir: string;
188
+ /** Absolute path to the database directory. */
189
+ dbPath: string;
190
+ /**
191
+ * Absolute path to the renderer's entrypoint directory. Vite's `root`
192
+ * resolves here; `index.html` inside it is served through Vite.
193
+ */
194
+ uiEntrypointPath: string;
195
+ /**
196
+ * Absolute path to `splash.html` inside the entrypoint directory. Loaded
197
+ * raw (no Vite) into a transient BrowserView during the brief window
198
+ * between Electron `whenReady` and the renderer's first paint.
199
+ */
200
+ splashPath: string;
201
+ /**
202
+ * Absolute path to `installing.html` inside the entrypoint directory, if
203
+ * the user provided one. Optional. Production launcher loads this raw
204
+ * during clone + first install (before the user's source even exists in
205
+ * the apps-dir). Receives IPC progress events via the framework's
206
+ * built-in `installing-preload.cjs`. Not used in dev mode — `pnpm dev`
207
+ * doesn't clone or install.
208
+ */
209
+ installingPath?: string;
210
+ plugins: ResolvedPlugin[];
211
+ /** Resolved build config; defaults filled in even when user omits. */
212
+ build: ResolvedBuildConfig;
213
+ }
214
+ //#endregion
215
+ export { Config as a, PackageManagerSpec as c, ResolvedConfig as d, ResolvedPlugin as f, resolveBuildConfig as g, definePlugin as h, BundleConfig as i, Plugin as l, defineConfig as m, BuildContext as n, EmitContext as o, defineBuildConfig as p, BuildPlugin as r, MirrorConfig as s, BuildConfig as t, ResolvedBuildConfig as u };
@@ -0,0 +1,53 @@
1
+ //#region src/cli/lib/build-config.ts
2
+ /**
3
+ * Soft default when the user omits `build.packageManager` entirely. Existing
4
+ * apps scaffolded before this field existed pick this up. The version
5
+ * tracks whatever pnpm we'd otherwise have hardcoded in the toolchain.
6
+ */
7
+ const DEFAULT_PACKAGE_MANAGER = {
8
+ type: "pnpm",
9
+ version: "10.33.0"
10
+ };
11
+ function defineBuildConfig(config) {
12
+ return config;
13
+ }
14
+ const SEMVER_RE = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
15
+ function validateHostVersion(value) {
16
+ if (typeof value !== "string" || value.trim().length === 0) throw new Error("zenbu build.hostVersion: required `string` (e.g. \"0.0.6\"). Set it on `defineBuildConfig({ hostVersion: \"...\" })`.");
17
+ const trimmed = value.trim();
18
+ if (!SEMVER_RE.test(trimmed)) throw new Error(`zenbu build.hostVersion: "${value}" is not a valid semver string (expected MAJOR.MINOR.PATCH with optional prerelease / build metadata).`);
19
+ return trimmed;
20
+ }
21
+ function validatePackageManager(spec) {
22
+ const allowed = [
23
+ "pnpm",
24
+ "npm",
25
+ "yarn",
26
+ "bun"
27
+ ];
28
+ if (!allowed.includes(spec.type)) throw new Error(`zenbu build.packageManager: unknown type "${spec.type}". Expected one of: ${allowed.join(", ")}.`);
29
+ if (typeof spec.version !== "string" || spec.version.trim().length === 0) throw new Error(`zenbu build.packageManager.${spec.type}: \`version\` is required and must be a non-empty string.`);
30
+ return spec;
31
+ }
32
+ function resolveBuildConfig(config) {
33
+ const packageManager = validatePackageManager(config.packageManager ?? DEFAULT_PACKAGE_MANAGER);
34
+ return {
35
+ hostVersion: validateHostVersion(config.hostVersion),
36
+ source: config.source ?? ".",
37
+ out: config.out ?? ".zenbu/build/source",
38
+ include: config.include,
39
+ ignore: config.ignore ?? [],
40
+ plugins: config.plugins ?? [],
41
+ mirror: config.mirror,
42
+ bundle: config.bundle,
43
+ packageManager
44
+ };
45
+ }
46
+ function definePlugin(plugin) {
47
+ return plugin;
48
+ }
49
+ function defineConfig(config) {
50
+ return config;
51
+ }
52
+ //#endregion
53
+ export { resolveBuildConfig as i, defineConfig as n, definePlugin as r, defineBuildConfig as t };