@zenbujs/core 0.0.5 → 0.0.9

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 (72) hide show
  1. package/dist/{advice-config-QYB2qEd_.mjs → advice-config-DXSIo0sg.mjs} +40 -39
  2. package/dist/advice.d.mts +8 -8
  3. package/dist/advice.mjs +2 -2
  4. package/dist/{base-window-BbFRRhKP.mjs → base-window-BxBZ2md_.mjs} +51 -7
  5. package/dist/{transforms-CuTODvDx.d.mts → build-config-Dzg2frpk.d.mts} +98 -28
  6. package/dist/build-config-pWdmLnrk.mjs +53 -0
  7. package/dist/{build-electron-CNJ0dLND.mjs → build-electron-Dsbb1EMl.mjs} +308 -120
  8. package/dist/{build-source-C2puqEVr.mjs → build-source-d1J3shV8.mjs} +62 -27
  9. package/dist/cli/bin.mjs +7 -7
  10. package/dist/cli/build.d.mts +2 -2
  11. package/dist/cli/build.mjs +2 -3
  12. package/dist/cli/resolve-config.mjs +1 -1
  13. package/dist/{cli-C3R1LBMY.mjs → cli-kL6mPgBE.mjs} +2 -2
  14. package/dist/config.d.mts +3 -3
  15. package/dist/config.mjs +2 -3
  16. package/dist/{db-xjvahRFJ.mjs → db-Bc292RYo.mjs} +2 -2
  17. package/dist/db.d.mts +1 -1
  18. package/dist/dev-B2emj0HZ.mjs +301 -0
  19. package/dist/env-bootstrap.d.mts +1 -1
  20. package/dist/events.d.mts +19 -0
  21. package/dist/events.mjs +1 -0
  22. package/dist/host-version-BIrF8tX7.mjs +65 -0
  23. package/dist/index-CVF768Xs.d.mts +783 -0
  24. package/dist/index.d.mts +5 -6
  25. package/dist/index.mjs +2 -2
  26. package/dist/installing-preload.cjs +60 -0
  27. package/dist/launcher.mjs +2615 -122
  28. package/dist/{link-c0_aLWQ3.mjs → link-glX89NV5.mjs} +215 -89
  29. package/dist/{load-config-xMf2wxH8.mjs → load-config-C4Oe2qZO.mjs} +5 -1
  30. package/dist/loaders/zenbu.mjs +102 -0
  31. package/dist/node-loader.mjs +1 -1
  32. package/dist/{publish-source-Dill72NS.mjs → publish-source-Dq2c0iOw.mjs} +2 -2
  33. package/dist/react.d.mts +55 -6
  34. package/dist/react.mjs +116 -5
  35. package/dist/registry-CMp8FYgS.d.mts +47 -0
  36. package/dist/registry-generated.d.mts +26 -0
  37. package/dist/registry-generated.mjs +1 -0
  38. package/dist/registry.d.mts +2 -2
  39. package/dist/{reloader-DzEO8kJr.mjs → reloader-B22UiNA2.mjs} +2 -4
  40. package/dist/{renderer-host-Cau9JK0v.mjs → renderer-host-DD16MXhI.mjs} +152 -43
  41. package/dist/{rpc-JfGv-Wuw.mjs → rpc-C4_NQmpT.mjs} +5 -4
  42. package/dist/{runtime-pCeVzj--.d.mts → runtime-BQWntcOb.d.mts} +85 -48
  43. package/dist/runtime.d.mts +2 -2
  44. package/dist/runtime.mjs +139 -83
  45. package/dist/{schema-Dl85YjXW.d.mts → schema-CjrMVk36.d.mts} +3 -3
  46. package/dist/schema.d.mts +1 -1
  47. package/dist/schema.mjs +1 -1
  48. package/dist/{server-y3PPbh3l.mjs → server-CZLMF8Dj.mjs} +1 -3
  49. package/dist/services/default.d.mts +3 -3
  50. package/dist/services/default.mjs +14 -13
  51. package/dist/services/index.d.mts +2 -280
  52. package/dist/services/index.mjs +8 -7
  53. package/dist/setup-gate.d.mts +1 -1
  54. package/dist/setup-gate.mjs +123 -24
  55. package/dist/{transform-CmFYPmt8.mjs → transform-BzrwkEdf.mjs} +22 -916
  56. package/dist/updater-BtB_Ki1r.mjs +1011 -0
  57. package/dist/{vite-plugins-Do7liKi_.mjs → vite-plugins-tt6KAtyE.mjs} +26 -25
  58. package/dist/vite.d.mts +3 -3
  59. package/dist/vite.mjs +1 -1
  60. package/dist/{window-o2NGUsIb.mjs → window-YFKvAM0l.mjs} +30 -16
  61. package/package.json +17 -4
  62. package/dist/build-config-C3a-o3_B.mjs +0 -23
  63. package/dist/dev-Dazhu66l.mjs +0 -85
  64. package/dist/registry-eX6e2oql.d.mts +0 -61
  65. package/dist/transforms-htxfTwsY.mjs +0 -47
  66. /package/dist/{config-DXRCDUxG.mjs → config-BK78JDRI.mjs} +0 -0
  67. /package/dist/{env-bootstrap-DW2hVhSO.d.mts → env-bootstrap-rTs8KR3-.d.mts} +0 -0
  68. /package/dist/{index-M_lSNBrq.d.mts → index-DeDxePAa.d.mts} +0 -0
  69. /package/dist/{mirror-sync-PDzxhf1w.mjs → mirror-sync-pYU6f3-c.mjs} +0 -0
  70. /package/dist/{monorepo-3avKJwzJ.mjs → monorepo-Dct-kkbQ.mjs} +0 -0
  71. /package/dist/{node-_8xShqxr.mjs → node-BhfLKYCi.mjs} +0 -0
  72. /package/dist/{setup-gate-Dcy8gGPJ.d.mts → setup-gate-BQq0QgZH.d.mts} +0 -0
@@ -5,9 +5,9 @@ import { fileURLToPath } from "node:url";
5
5
  //#region src/services/advice-config.ts
6
6
  var advice_config_exports = /* @__PURE__ */ __exportAll({
7
7
  getAdvice: () => getAdvice,
8
- getAllAdviceScopes: () => getAllAdviceScopes,
8
+ getAllAdviceTypes: () => getAllAdviceTypes,
9
9
  getAllContentScriptPaths: () => getAllContentScriptPaths,
10
- getAllScopes: () => getAllScopes,
10
+ getAllTypes: () => getAllTypes,
11
11
  getContentScripts: () => getContentScripts,
12
12
  registerAdvice: () => registerAdvice,
13
13
  registerContentScript: () => registerContentScript
@@ -53,64 +53,65 @@ const RESOLVED_PREFIX = "\0@advice-prelude/";
53
53
  const APP_RENDERER_RELOADER_ID = "app";
54
54
  const adviceEntries = /* @__PURE__ */ new Map();
55
55
  const contentScripts = /* @__PURE__ */ new Map();
56
- function invalidatePrelude(scope) {
56
+ function invalidatePrelude(type) {
57
57
  try {
58
58
  const reloader = runtime.getSlot("reloader")?.instance;
59
59
  if (!reloader) return;
60
60
  const coreEntry = reloader.get(APP_RENDERER_RELOADER_ID);
61
61
  if (!coreEntry?.viteServer) return;
62
62
  const graph = coreEntry.viteServer.moduleGraph;
63
- const invalidateScope = (s) => {
64
- const prefix = RESOLVED_PREFIX + s;
63
+ const invalidateMatching = (test) => {
65
64
  const ids = [];
66
65
  for (const id of graph.idToModuleMap.keys()) {
67
66
  if (typeof id !== "string") continue;
68
- if (id === prefix || id.startsWith(prefix + "?")) ids.push(id);
67
+ if (test(id)) ids.push(id);
69
68
  }
70
69
  for (const id of ids) {
71
70
  const mod = graph.getModuleById(id);
72
71
  if (mod) graph.invalidateModule(mod);
73
72
  }
74
73
  };
75
- if (scope === "*") for (const s of getAllScopes()) invalidateScope(s);
76
- 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
+ }
77
79
  } catch {}
78
80
  }
79
- function emitReload(scope) {
80
- invalidatePrelude(scope);
81
+ function emitReload(type) {
82
+ invalidatePrelude(type);
81
83
  try {
82
84
  const rpc = runtime.getSlot("rpc")?.instance;
83
85
  if (!rpc) return;
84
- if (scope === "*") for (const s of getAllScopes()) rpc.emit.advice.reload({ scope: s });
85
- else rpc.emit.advice.reload({ scope });
86
+ rpc.emit.advice.reload({ type });
86
87
  } catch {}
87
88
  }
88
- function registerAdvice(scope, entry, meta) {
89
+ function registerAdvice(type, entry, meta) {
89
90
  const resolvedEntry = {
90
91
  ...entry,
91
92
  modulePath: resolvePluginPath(entry.modulePath, meta)
92
93
  };
93
- const list = adviceEntries.get(scope) ?? [];
94
+ const list = adviceEntries.get(type) ?? [];
94
95
  list.push(resolvedEntry);
95
- adviceEntries.set(scope, list);
96
- emitReload(scope);
96
+ adviceEntries.set(type, list);
97
+ emitReload(type);
97
98
  return () => {
98
- const current = adviceEntries.get(scope);
99
+ const current = adviceEntries.get(type);
99
100
  if (!current) return;
100
101
  const idx = current.indexOf(resolvedEntry);
101
102
  if (idx >= 0) current.splice(idx, 1);
102
- if (current.length === 0) adviceEntries.delete(scope);
103
- emitReload(scope);
103
+ if (current.length === 0) adviceEntries.delete(type);
104
+ emitReload(type);
104
105
  };
105
106
  }
106
- function getAdvice(scope) {
107
- return adviceEntries.get(scope) ?? [];
107
+ function getAdvice(type) {
108
+ return adviceEntries.get(type) ?? [];
108
109
  }
109
- function getAllAdviceScopes() {
110
+ function getAllAdviceTypes() {
110
111
  return [...adviceEntries.keys()];
111
112
  }
112
113
  /**
113
- * Register a content script for the given scope. `modulePath` is normally
114
+ * Register a content script for the given view type. `modulePath` is normally
114
115
  * a path relative to the plugin root (the folder with `zenbu.plugin.json`);
115
116
  * pass `import.meta` so we can resolve it. Absolute paths are accepted as
116
117
  * an escape hatch.
@@ -119,35 +120,35 @@ function getAllAdviceScopes() {
119
120
  * registerContentScript("app", "src/content/clock.tsx", import.meta),
120
121
  * )
121
122
  */
122
- function registerContentScript(scope, modulePath, meta) {
123
+ function registerContentScript(type, modulePath, meta) {
123
124
  const entry = { path: resolvePluginPath(modulePath, meta) };
124
- const list = contentScripts.get(scope) ?? [];
125
+ const list = contentScripts.get(type) ?? [];
125
126
  list.push(entry);
126
- contentScripts.set(scope, list);
127
- emitReload(scope === "*" ? "*" : scope);
127
+ contentScripts.set(type, list);
128
+ emitReload(type === "*" ? "*" : type);
128
129
  return () => {
129
- const current = contentScripts.get(scope);
130
+ const current = contentScripts.get(type);
130
131
  if (!current) return;
131
132
  const idx = current.indexOf(entry);
132
133
  if (idx >= 0) current.splice(idx, 1);
133
- if (current.length === 0) contentScripts.delete(scope);
134
- emitReload(scope === "*" ? "*" : scope);
134
+ if (current.length === 0) contentScripts.delete(type);
135
+ emitReload(type === "*" ? "*" : type);
135
136
  };
136
137
  }
137
- function getContentScripts(scope) {
138
- const scoped = (contentScripts.get(scope) ?? []).map((e) => e.path);
139
- 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];
140
141
  }
141
142
  function getAllContentScriptPaths() {
142
143
  const paths = [];
143
144
  for (const list of contentScripts.values()) for (const entry of list) paths.push(entry.path);
144
145
  return paths;
145
146
  }
146
- function getAllScopes() {
147
- const scopes = /* @__PURE__ */ new Set();
148
- for (const k of adviceEntries.keys()) scopes.add(k);
149
- for (const k of contentScripts.keys()) if (k !== "*") scopes.add(k);
150
- 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];
151
152
  }
152
153
  //#endregion
153
- export { getAllScopes as a, registerContentScript as c, getAllContentScriptPaths as i, getAdvice as n, getContentScripts as o, getAllAdviceScopes as r, registerAdvice as s, advice_config_exports 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 getAllScopes, c as registerContentScript, i as getAllContentScriptPaths, n as getAdvice, o as getContentScripts, r as getAllAdviceScopes, s as registerAdvice } from "./advice-config-QYB2qEd_.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 };
@@ -1,9 +1,52 @@
1
1
  import { n as __exportAll } from "./chunk-DsiFFCwN.mjs";
2
- import { Service, runtime } from "./runtime.mjs";
2
+ import { Service, getAppEntrypoint, runtime } from "./runtime.mjs";
3
3
  import { t as createLogger } from "./log-6rzaCV0I.mjs";
4
- import { a as DbService } from "./renderer-host-Cau9JK0v.mjs";
4
+ import { a as DbService } from "./renderer-host-DD16MXhI.mjs";
5
+ import fs from "node:fs";
6
+ import path from "node:path";
5
7
  import { nanoid } from "nanoid";
6
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
7
50
  //#region src/services/base-window.ts
8
51
  var base_window_exports = /* @__PURE__ */ __exportAll({
9
52
  BaseWindowService: () => BaseWindowService,
@@ -11,9 +54,10 @@ var base_window_exports = /* @__PURE__ */ __exportAll({
11
54
  });
12
55
  const log = createLogger("base-window");
13
56
  const MAIN_WINDOW_ID = "main";
14
- var BaseWindowService = class extends Service {
15
- static key = "base-window";
16
- static deps = { db: DbService };
57
+ var BaseWindowService = class extends Service.create({
58
+ key: "base-window",
59
+ deps: { db: DbService }
60
+ }) {
17
61
  windows = /* @__PURE__ */ new Map();
18
62
  get bootWindows() {
19
63
  return globalThis.__zenbu_boot_windows__ ?? [];
@@ -46,7 +90,7 @@ var BaseWindowService = class extends Service {
46
90
  x: 14,
47
91
  y: 10
48
92
  },
49
- backgroundColor: "#F4F4F4"
93
+ backgroundColor: entrypointBgColor()
50
94
  });
51
95
  this.windows.set(windowId, win);
52
96
  win.on("closed", () => this.windows.delete(windowId));
@@ -96,4 +140,4 @@ var BaseWindowService = class extends Service {
96
140
  };
97
141
  runtime.register(BaseWindowService, import.meta);
98
142
  //#endregion
99
- export { MAIN_WINDOW_ID as n, base_window_exports as r, BaseWindowService as t };
143
+ export { entrypointBgColor as i, MAIN_WINDOW_ID as n, base_window_exports as r, BaseWindowService as t };
@@ -1,13 +1,48 @@
1
1
  //#region src/cli/lib/build-config.d.ts
2
- interface TransformInput {
3
- path: string;
4
- code: string;
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;
5
19
  }
6
- interface TransformOutput {
7
- code?: string;
8
- drop?: boolean;
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>;
9
45
  }
10
- type Transform = (file: TransformInput) => TransformOutput | null | undefined | void;
11
46
  interface MirrorConfig {
12
47
  target: string;
13
48
  branch?: string;
@@ -15,19 +50,63 @@ interface MirrorConfig {
15
50
  interface BundleConfig {
16
51
  extraResources?: string[];
17
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
+ };
18
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;
19
96
  source?: string;
20
97
  out?: string;
21
98
  include: string[];
22
99
  ignore?: string[];
23
- transforms?: Transform[];
100
+ plugins?: BuildPlugin[];
24
101
  mirror?: MirrorConfig;
25
102
  bundle?: BundleConfig;
103
+ packageManager?: PackageManagerSpec;
26
104
  }
27
105
  declare function defineBuildConfig(config: BuildConfig): BuildConfig;
28
106
  type ResolvedBuildConfig = Required<Omit<BuildConfig, "mirror" | "bundle">> & {
29
107
  mirror?: MirrorConfig;
30
108
  bundle?: BundleConfig;
109
+ packageManager: PackageManagerSpec;
31
110
  };
32
111
  declare function resolveBuildConfig(config: BuildConfig): ResolvedBuildConfig;
33
112
  /**
@@ -47,7 +126,7 @@ interface Plugin {
47
126
  preload?: string;
48
127
  events?: string;
49
128
  /**
50
- * Plugin-author-defined SVG icons keyed by view scope. Read by
129
+ * Plugin-author-defined SVG icons keyed by view type. Read by
51
130
  * `view-registry` to decorate registered views. Optional.
52
131
  */
53
132
  icons?: Record<string, string>;
@@ -119,27 +198,18 @@ interface ResolvedConfig {
119
198
  * between Electron `whenReady` and the renderer's first paint.
120
199
  */
121
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;
122
210
  plugins: ResolvedPlugin[];
123
211
  /** Resolved build config; defaults filled in even when user omits. */
124
212
  build: ResolvedBuildConfig;
125
213
  }
126
214
  //#endregion
127
- //#region src/cli/lib/transforms.d.ts
128
- /**
129
- * Marker-based feature-flag stripping. Removes lines between
130
- * // @zenbu:strip-if FLAG (strip when FLAG is truthy)
131
- * // @zenbu:strip-if !FLAG (strip when FLAG is falsy)
132
- * ...
133
- * // @zenbu:end
134
- *
135
- * Pure string/line ops — no AST, no compiler dep.
136
- */
137
- declare function stripIfDisabled(flags: Record<string, boolean>): Transform;
138
- /**
139
- * Drop files whose path matches the given pattern (relative path from the
140
- * source root, posix slashes). Also covered by `ignore` globs in the config;
141
- * use this when a regex is more convenient than a glob.
142
- */
143
- declare function dropFiles(pattern: RegExp | ((path: string) => boolean)): Transform;
144
- //#endregion
145
- export { resolveBuildConfig as _, Config as a, ResolvedBuildConfig as c, Transform as d, TransformInput as f, definePlugin as g, defineConfig as h, BundleConfig as i, ResolvedConfig as l, defineBuildConfig as m, stripIfDisabled as n, MirrorConfig as o, TransformOutput as p, BuildConfig as r, Plugin as s, dropFiles as t, ResolvedPlugin as u };
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 };