@zenbujs/core 0.0.1

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 (94) hide show
  1. package/LICENSE +11 -0
  2. package/dist/advice-config-CjgkEf2E.mjs +135 -0
  3. package/dist/advice-config-Cy133IQP.mjs +2 -0
  4. package/dist/advice-runtime.d.mts +35 -0
  5. package/dist/advice-runtime.mjs +131 -0
  6. package/dist/advice.d.mts +36 -0
  7. package/dist/advice.mjs +2 -0
  8. package/dist/base-window-BUt8pwbw.mjs +94 -0
  9. package/dist/base-window-DEIAk618.mjs +2 -0
  10. package/dist/build-config-pbv0w4oN.mjs +17 -0
  11. package/dist/build-electron-B4Gd0Gi4.mjs +516 -0
  12. package/dist/build-source-_q1n1zTV.mjs +162 -0
  13. package/dist/chunk-Dm34NbLt.mjs +6 -0
  14. package/dist/cli/bin.d.mts +1 -0
  15. package/dist/cli/bin.mjs +88 -0
  16. package/dist/cli/build.d.mts +53 -0
  17. package/dist/cli/build.mjs +48 -0
  18. package/dist/cli-BLbQQIVB.mjs +8054 -0
  19. package/dist/config-CdVrW85P.mjs +59 -0
  20. package/dist/config-LK73dJmO.mjs +2 -0
  21. package/dist/db-ByKPbnP6.mjs +2 -0
  22. package/dist/db-DhuAJrye.mjs +531 -0
  23. package/dist/db.d.mts +16 -0
  24. package/dist/db.mjs +16 -0
  25. package/dist/dev-BuqklM0k.mjs +85 -0
  26. package/dist/env-bootstrap-BtVME-CU.d.mts +16 -0
  27. package/dist/env-bootstrap-rj7I-59x.mjs +53 -0
  28. package/dist/env-bootstrap.d.mts +2 -0
  29. package/dist/env-bootstrap.mjs +2 -0
  30. package/dist/http-IBcLzbYu.mjs +2 -0
  31. package/dist/index-Bhlbyrn7.d.mts +63 -0
  32. package/dist/index-CPZ5d6Hl.d.mts +442 -0
  33. package/dist/index-FtE8MXJ_.d.mts +1 -0
  34. package/dist/index.d.mts +6 -0
  35. package/dist/index.mjs +5 -0
  36. package/dist/launcher.mjs +173 -0
  37. package/dist/link-6roQ7Cn6.mjs +580 -0
  38. package/dist/loaders/zenbu.d.mts +22 -0
  39. package/dist/loaders/zenbu.mjs +267 -0
  40. package/dist/log-CyKv8hQg.mjs +20 -0
  41. package/dist/mirror-sync-CodOnwkD.mjs +332 -0
  42. package/dist/monorepo-CmGPHsVm.mjs +119 -0
  43. package/dist/node-D4M19_mV.mjs +5 -0
  44. package/dist/node-loader.d.mts +17 -0
  45. package/dist/node-loader.mjs +33 -0
  46. package/dist/pause-DvAUNmKn.mjs +52 -0
  47. package/dist/publish-source-BVgB62Zj.mjs +131 -0
  48. package/dist/react.d.mts +76 -0
  49. package/dist/react.mjs +291 -0
  50. package/dist/registry-Dh_e7HU1.d.mts +61 -0
  51. package/dist/registry.d.mts +2 -0
  52. package/dist/registry.mjs +1 -0
  53. package/dist/reloader-BCkLjDhS.mjs +2 -0
  54. package/dist/reloader-lLAJ3lqg.mjs +164 -0
  55. package/dist/renderer-host-Bg8QdeeH.mjs +1508 -0
  56. package/dist/renderer-host-DpvBPTHJ.mjs +2 -0
  57. package/dist/rpc-BwwQK6hD.mjs +71 -0
  58. package/dist/rpc-CqitnyR4.mjs +2 -0
  59. package/dist/rpc.d.mts +2 -0
  60. package/dist/rpc.mjs +2 -0
  61. package/dist/runtime-CjqDr8Yf.d.mts +109 -0
  62. package/dist/runtime-DUFKDIe4.mjs +409 -0
  63. package/dist/runtime.d.mts +2 -0
  64. package/dist/runtime.mjs +2 -0
  65. package/dist/schema-CIg4GzHQ.mjs +100 -0
  66. package/dist/schema-DMoSkwUx.d.mts +62 -0
  67. package/dist/schema-dGK6qkfR.mjs +28 -0
  68. package/dist/schema.d.mts +2 -0
  69. package/dist/schema.mjs +2 -0
  70. package/dist/server-BXwZEQ-n.mjs +66 -0
  71. package/dist/server-DjrZUbbu.mjs +2 -0
  72. package/dist/services/default.d.mts +11 -0
  73. package/dist/services/default.mjs +22 -0
  74. package/dist/services/index.d.mts +276 -0
  75. package/dist/services/index.mjs +7 -0
  76. package/dist/setup-gate-BeD6WS6d.mjs +110 -0
  77. package/dist/setup-gate-BqOzm7zp.d.mts +4 -0
  78. package/dist/setup-gate.d.mts +2 -0
  79. package/dist/setup-gate.mjs +2 -0
  80. package/dist/src-pELM4_iH.mjs +376 -0
  81. package/dist/trace-DCB7qFzT.mjs +10 -0
  82. package/dist/transform-DJH3vN4b.mjs +84041 -0
  83. package/dist/transport-BMSzG2-F.mjs +1045 -0
  84. package/dist/view-registry-BualWgAf.mjs +2 -0
  85. package/dist/vite-plugins-Bh3SCOw-.mjs +331 -0
  86. package/dist/vite.d.mts +68 -0
  87. package/dist/vite.mjs +2 -0
  88. package/dist/window-CM2a9Kyc.mjs +2 -0
  89. package/dist/window-CmmpCVX6.mjs +156 -0
  90. package/dist/write-9dRFczGJ.mjs +1248 -0
  91. package/migrations/0000_migration.ts +34 -0
  92. package/migrations/meta/0000_snapshot.json +18 -0
  93. package/migrations/meta/_journal.json +10 -0
  94. package/package.json +124 -0
@@ -0,0 +1,2 @@
1
+ import "./renderer-host-Bg8QdeeH.mjs";
2
+ export {};
@@ -0,0 +1,331 @@
1
+ import { n as require_lib, t as zenbuAdviceTransform$1 } from "./transform-DJH3vN4b.mjs";
2
+ import { a as getContentScripts, i as getAllScopes, r as getAllContentScriptPaths, t as getAdvice } from "./advice-config-CjgkEf2E.mjs";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import fsp from "node:fs/promises";
6
+ //#region ../advice/src/vite.ts
7
+ var import_lib = require_lib();
8
+ const defaultInclude = /\.[jt]sx?$/;
9
+ const defaultExclude = /node_modules/;
10
+ function zenbuAdvicePlugin(options = {}) {
11
+ let resolvedRoot;
12
+ return {
13
+ name: "zenbu-advice",
14
+ enforce: "pre",
15
+ configResolved(config) {
16
+ resolvedRoot = options.root ?? config.root;
17
+ },
18
+ transform(code, id) {
19
+ const include = options.include ?? defaultInclude;
20
+ const exclude = options.exclude ?? defaultExclude;
21
+ if (!include.test(id)) return null;
22
+ if (exclude.test(id)) return null;
23
+ if (code.includes("applyAdviceChain") || code.includes("__zenbu_def")) return null;
24
+ const parserPlugins = /\.tsx?$/.test(id) ? ["typescript"] : [];
25
+ if (/\.(?:jsx|tsx)$/.test(id)) parserPlugins.push("jsx");
26
+ const result = (0, import_lib.transformSync)(code, {
27
+ filename: id,
28
+ plugins: [[zenbuAdviceTransform$1, { root: resolvedRoot }]],
29
+ parserOpts: { plugins: parserPlugins },
30
+ sourceMaps: true,
31
+ configFile: false,
32
+ babelrc: false
33
+ });
34
+ if (!result?.code) return null;
35
+ return {
36
+ code: result.code,
37
+ map: result.map
38
+ };
39
+ }
40
+ };
41
+ }
42
+ //#endregion
43
+ //#region src/vite-plugins.ts
44
+ /**
45
+ * Renderer-side Vite plugins that wire advice + content scripts into every
46
+ * Zenbu view. The framework auto-injects these from `ReloaderService`; users
47
+ * should not need to import them in their own `vite.config.ts`.
48
+ */
49
+ const PRELUDE_PREFIX = "/@advice-prelude/";
50
+ const RESOLVED_PREFIX = "\0@advice-prelude/";
51
+ const HERE = path.dirname(fileURLToPath(import.meta.url));
52
+ const ADVICE_RUNTIME_ENTRY = path.resolve(HERE, "advice-runtime.mjs");
53
+ /**
54
+ * The package directory of `@zenbujs/core` itself. We expose it on the dev
55
+ * server's `server.fs.allow` so requests for files inside core (the bundled
56
+ * advice runtime, vite plugin, etc.) aren't blocked by Vite's workspace
57
+ * restriction when the host happens to live in a different workspace.
58
+ */
59
+ const CORE_PACKAGE_ROOT = path.resolve(HERE, "..");
60
+ /**
61
+ * Vite plugin that enforces the framework's "single React, single core"
62
+ * invariant for every renderer iframe.
63
+ *
64
+ * Mechanism: `resolve.dedupe`. Vite's dedupe re-roots resolution for the
65
+ * listed packages at the project's root `node_modules`, so a plugin's
66
+ * `import "react"` in `plugins/<name>/src/...` doesn't walk up into its own
67
+ * `node_modules/react` (where a peer-dep / dev-dep install would otherwise
68
+ * land). All importers — host renderer source, plugin content scripts,
69
+ * advice modules — collapse onto the host's single React instance.
70
+ *
71
+ * `@zenbujs/core` is also deduped, but in practice the symlinks created by
72
+ * `pnpm link:` already collapse it: the host's
73
+ * `node_modules/@zenbujs/core` and each plugin's
74
+ * `node_modules/@zenbujs/core` resolve to the same real path on disk.
75
+ * Adding it to `dedupe` is a belt-and-suspenders guarantee for non-pnpm
76
+ * installs.
77
+ *
78
+ * Why dedupe and not absolute-path rewriting: the host's
79
+ * `node_modules/<package>` is *inside* Vite's workspace, so files served
80
+ * from there go through Vite's normal `/node_modules/.vite/deps/` pipeline.
81
+ * Rewriting to a path outside the workspace forces `/@fs/...` URLs that
82
+ * trip the workspace fs guard even with `fs.strict: false`.
83
+ *
84
+ * `fs.allow: [CORE_PACKAGE_ROOT]` is still added because the framework
85
+ * itself ships a few files (e.g. `@zenbu/advice/runtime` re-exported from
86
+ * core's dist) that the prelude pulls in directly via `/@fs/...`.
87
+ */
88
+ function zenbuFrameworkResolve() {
89
+ return {
90
+ name: "zenbu-framework-resolve",
91
+ enforce: "pre",
92
+ config() {
93
+ return {
94
+ resolve: { dedupe: [
95
+ "react",
96
+ "react-dom",
97
+ "@zenbujs/core"
98
+ ] },
99
+ server: { fs: { allow: [CORE_PACKAGE_ROOT] } }
100
+ };
101
+ },
102
+ /**
103
+ * Vite's built-in tsconfig watcher (`reloadOnTsconfigChange` in
104
+ * `plugins/esbuild.ts`) only triggers a cache-clear + full reload when
105
+ * the changed path ends in exactly `/tsconfig.json` — non-canonical
106
+ * names like `tsconfig.local.json` are silently ignored even though the
107
+ * underlying chokidar watcher does fire on them. We use that pattern
108
+ * (a committed `tsconfig.json` that extends a generated, gitignored
109
+ * `tsconfig.local.json`) so plugin sources can `#registry/*`-import
110
+ * the host's typed registry without a host-specific path leaking into
111
+ * a committed file.
112
+ *
113
+ * Without this hook, every `zen link` run would silently leave esbuild
114
+ * with a stale "extends target missing" cache and plugin sources would
115
+ * fail to load until the dev process is killed by hand. This watches
116
+ * the plugin directories declared in the host's `config.json` and
117
+ * proactively calls `server.restart()` on add/change/unlink of any
118
+ * `tsconfig.local.json`.
119
+ */
120
+ async configureServer(server) {
121
+ const configPath = process.env.ZENBU_CONFIG_PATH;
122
+ if (!configPath) return;
123
+ const configDir = path.dirname(configPath);
124
+ let tsconfigPaths = [];
125
+ try {
126
+ const raw = await fsp.readFile(configPath, "utf8");
127
+ const config = JSON.parse(raw);
128
+ if (Array.isArray(config.plugins)) for (const entry of config.plugins) {
129
+ if (typeof entry !== "string") continue;
130
+ const manifestAbs = path.isAbsolute(entry) ? entry : path.resolve(configDir, entry);
131
+ tsconfigPaths.push(path.join(path.dirname(manifestAbs), "tsconfig.local.json"));
132
+ }
133
+ } catch {
134
+ return;
135
+ }
136
+ if (tsconfigPaths.length === 0) return;
137
+ server.watcher.add(tsconfigPaths);
138
+ let restarting = false;
139
+ const handle = (file) => {
140
+ if (!file.endsWith("tsconfig.local.json")) return;
141
+ if (restarting) return;
142
+ restarting = true;
143
+ server.config.logger.info(`[zenbu] ${file} changed — restarting Vite to refresh tsconfig (vite's built-in watcher only fires on /tsconfig.json)`, {
144
+ timestamp: true,
145
+ clear: false
146
+ });
147
+ server.restart().catch((err) => {
148
+ server.config.logger.error(`[zenbu] vite restart failed: ${err instanceof Error ? err.message : String(err)}`);
149
+ }).finally(() => {
150
+ restarting = false;
151
+ });
152
+ };
153
+ server.watcher.on("add", handle);
154
+ server.watcher.on("change", handle);
155
+ server.watcher.on("unlink", handle);
156
+ }
157
+ };
158
+ }
159
+ function getScopeFromPath(urlPath) {
160
+ const m = urlPath.match(/^\/views\/([^/]+)\//);
161
+ return m ? m[1] : null;
162
+ }
163
+ /**
164
+ * Resolve the view scope for a request. The kernel passes `?scope=<name>`
165
+ * in the iframe URL when opening a view (see `WindowService.openView`); we
166
+ * also support `/views/<scope>/...` paths for plugins that register their
167
+ * own multi-page Vite layouts.
168
+ */
169
+ function resolveScope(urlPath, originalUrl) {
170
+ const fromPath = getScopeFromPath(urlPath);
171
+ if (fromPath) return fromPath;
172
+ if (!originalUrl) return null;
173
+ const queryIdx = originalUrl.indexOf("?");
174
+ if (queryIdx < 0) return null;
175
+ return new URLSearchParams(originalUrl.slice(queryIdx + 1)).get("scope");
176
+ }
177
+ function parsePreludeId(id) {
178
+ const rest = id.slice(17);
179
+ const queryIdx = rest.indexOf("?");
180
+ if (queryIdx < 0) return { scope: rest };
181
+ return { scope: rest.slice(0, queryIdx) };
182
+ }
183
+ function generateAdvicePreludeCode(entries) {
184
+ if (entries.length === 0) return "";
185
+ const imports = ["import { replace, advise } from \"@zenbu/advice/runtime\""];
186
+ const calls = [];
187
+ entries.forEach((entry, i) => {
188
+ const alias = `__r${i}`;
189
+ imports.push(`import { ${entry.exportName} as ${alias} } from ${JSON.stringify(entry.modulePath)}`);
190
+ if (entry.type === "replace") calls.push(`replace(${JSON.stringify(entry.moduleId)}, ${JSON.stringify(entry.name)}, ${alias})`);
191
+ else calls.push(`advise(${JSON.stringify(entry.moduleId)}, ${JSON.stringify(entry.name)}, ${JSON.stringify(entry.type)}, ${alias})`);
192
+ });
193
+ return imports.join("\n") + "\n" + calls.join("\n") + "\n";
194
+ }
195
+ /**
196
+ * Resolves `@zenbu/advice/runtime` to the bundled core runtime so plugins'
197
+ * advice + content scripts can `import { replace, advise } from "@zenbu/advice/runtime"`
198
+ * without depending on the package directly.
199
+ */
200
+ function resolveAdviceRuntime() {
201
+ return {
202
+ name: "zenbu-resolve-advice-runtime",
203
+ enforce: "pre",
204
+ resolveId(source) {
205
+ if (source === "@zenbu/advice/runtime") return ADVICE_RUNTIME_ENTRY;
206
+ return null;
207
+ }
208
+ };
209
+ }
210
+ /**
211
+ * Per-iframe prelude that registers all advice + content scripts for the
212
+ * iframe's scope. The prelude is loaded via a `<script type="module">` tag
213
+ * injected into the iframe's HTML; loading it before the app's own entry
214
+ * lets advice register before the modules it patches evaluate.
215
+ */
216
+ function advicePreludePlugin() {
217
+ return {
218
+ name: "zenbu-advice-prelude",
219
+ enforce: "pre",
220
+ resolveId(source) {
221
+ if (source.startsWith(PRELUDE_PREFIX)) return RESOLVED_PREFIX + source.slice(17);
222
+ return null;
223
+ },
224
+ load(id) {
225
+ if (!id.startsWith(RESOLVED_PREFIX)) return null;
226
+ const { scope } = parsePreludeId(id);
227
+ let code = generateAdvicePreludeCode(getAdvice(scope));
228
+ for (const scriptPath of getContentScripts(scope)) code += `import ${JSON.stringify(scriptPath)}\n`;
229
+ return code || "// no advice or content scripts\n";
230
+ },
231
+ handleHotUpdate({ file, server }) {
232
+ let matched = false;
233
+ for (const scope of getAllScopes()) {
234
+ for (const entry of getAdvice(scope)) if (file === entry.modulePath) {
235
+ matched = true;
236
+ break;
237
+ }
238
+ if (matched) break;
239
+ }
240
+ if (!matched) matched = getAllContentScriptPaths().includes(file);
241
+ if (matched) {
242
+ server.ws.send({ type: "full-reload" });
243
+ return [];
244
+ }
245
+ },
246
+ configureServer(server) {
247
+ server.middlewares.use(async (req, res, next) => {
248
+ const url = req.url ?? "";
249
+ if (!url.startsWith(PRELUDE_PREFIX)) return next();
250
+ try {
251
+ const result = await server.transformRequest(url);
252
+ if (result) {
253
+ res.statusCode = 200;
254
+ res.setHeader("Content-Type", "application/javascript");
255
+ res.setHeader("Cache-Control", "no-cache");
256
+ res.end(result.code);
257
+ return;
258
+ }
259
+ } catch (e) {
260
+ console.error("[advice-prelude] transform error:", e);
261
+ }
262
+ next();
263
+ });
264
+ },
265
+ transformIndexHtml(html, ctx) {
266
+ const scope = resolveScope(ctx.path ?? "", ctx.originalUrl);
267
+ if (!scope) return html;
268
+ const hasAdvice = getAdvice(scope).length > 0;
269
+ const hasScripts = getContentScripts(scope).length > 0;
270
+ if (!hasAdvice && !hasScripts) return html;
271
+ return [{
272
+ tag: "script",
273
+ attrs: {
274
+ type: "module",
275
+ src: `${PRELUDE_PREFIX}${scope}`
276
+ },
277
+ injectTo: "head"
278
+ }];
279
+ }
280
+ };
281
+ }
282
+ /**
283
+ * Wraps `@zenbu/advice/vite`'s babel transform so the include filter is
284
+ * scoped to the renderer's resolved root. This keeps advice moduleIds
285
+ * canonical (each renderer transforms its own files; cross-package imports
286
+ * stay owned by whichever renderer originally loaded them).
287
+ */
288
+ function zenbuAdviceTransform() {
289
+ let inner = null;
290
+ return {
291
+ name: "zenbu-advice-scoped",
292
+ enforce: "pre",
293
+ configResolved(config) {
294
+ const escaped = config.root.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
295
+ inner = zenbuAdvicePlugin({
296
+ root: config.root,
297
+ include: new RegExp(`^${escaped}.*\\.[jt]sx?$`)
298
+ });
299
+ const hook = inner?.configResolved;
300
+ if (typeof hook === "function") hook.call(this, config);
301
+ },
302
+ transform(code, id) {
303
+ const hook = inner?.transform;
304
+ if (typeof hook !== "function") return null;
305
+ return hook.call(this, code, id);
306
+ }
307
+ };
308
+ }
309
+ /**
310
+ * Returns the framework Vite plugins in the canonical order. Auto-injected
311
+ * by `ReloaderService` for every renderer; exported for advanced users who
312
+ * want to compose them into a custom Vite stack.
313
+ *
314
+ * Order matters:
315
+ * 1. `zenbuFrameworkResolve` — `enforce: "pre"`, runs first so it gets
316
+ * `react` / `@zenbujs/core/*` *before* Vite's default resolver walks
317
+ * up and finds plugin-local copies.
318
+ * 2. `advicePreludePlugin` — generates the per-iframe prelude module.
319
+ * 3. `resolveAdviceRuntime` — points `@zenbu/advice/runtime` at core.
320
+ * 4. `zenbuAdviceTransform` — babel transform wrapping top-level fns.
321
+ */
322
+ function zenbuVitePlugins() {
323
+ return [
324
+ zenbuFrameworkResolve(),
325
+ advicePreludePlugin(),
326
+ resolveAdviceRuntime(),
327
+ zenbuAdviceTransform()
328
+ ];
329
+ }
330
+ //#endregion
331
+ export { zenbuVitePlugins as a, zenbuFrameworkResolve as i, resolveAdviceRuntime as n, zenbuAdviceTransform as r, advicePreludePlugin as t };
@@ -0,0 +1,68 @@
1
+ import { Plugin } from "vite";
2
+
3
+ //#region src/vite-plugins.d.ts
4
+ /**
5
+ * Vite plugin that enforces the framework's "single React, single core"
6
+ * invariant for every renderer iframe.
7
+ *
8
+ * Mechanism: `resolve.dedupe`. Vite's dedupe re-roots resolution for the
9
+ * listed packages at the project's root `node_modules`, so a plugin's
10
+ * `import "react"` in `plugins/<name>/src/...` doesn't walk up into its own
11
+ * `node_modules/react` (where a peer-dep / dev-dep install would otherwise
12
+ * land). All importers — host renderer source, plugin content scripts,
13
+ * advice modules — collapse onto the host's single React instance.
14
+ *
15
+ * `@zenbujs/core` is also deduped, but in practice the symlinks created by
16
+ * `pnpm link:` already collapse it: the host's
17
+ * `node_modules/@zenbujs/core` and each plugin's
18
+ * `node_modules/@zenbujs/core` resolve to the same real path on disk.
19
+ * Adding it to `dedupe` is a belt-and-suspenders guarantee for non-pnpm
20
+ * installs.
21
+ *
22
+ * Why dedupe and not absolute-path rewriting: the host's
23
+ * `node_modules/<package>` is *inside* Vite's workspace, so files served
24
+ * from there go through Vite's normal `/node_modules/.vite/deps/` pipeline.
25
+ * Rewriting to a path outside the workspace forces `/@fs/...` URLs that
26
+ * trip the workspace fs guard even with `fs.strict: false`.
27
+ *
28
+ * `fs.allow: [CORE_PACKAGE_ROOT]` is still added because the framework
29
+ * itself ships a few files (e.g. `@zenbu/advice/runtime` re-exported from
30
+ * core's dist) that the prelude pulls in directly via `/@fs/...`.
31
+ */
32
+ declare function zenbuFrameworkResolve(): Plugin;
33
+ /**
34
+ * Resolves `@zenbu/advice/runtime` to the bundled core runtime so plugins'
35
+ * advice + content scripts can `import { replace, advise } from "@zenbu/advice/runtime"`
36
+ * without depending on the package directly.
37
+ */
38
+ declare function resolveAdviceRuntime(): Plugin;
39
+ /**
40
+ * Per-iframe prelude that registers all advice + content scripts for the
41
+ * iframe's scope. The prelude is loaded via a `<script type="module">` tag
42
+ * injected into the iframe's HTML; loading it before the app's own entry
43
+ * lets advice register before the modules it patches evaluate.
44
+ */
45
+ declare function advicePreludePlugin(): Plugin;
46
+ /**
47
+ * Wraps `@zenbu/advice/vite`'s babel transform so the include filter is
48
+ * scoped to the renderer's resolved root. This keeps advice moduleIds
49
+ * canonical (each renderer transforms its own files; cross-package imports
50
+ * stay owned by whichever renderer originally loaded them).
51
+ */
52
+ declare function zenbuAdviceTransform(): Plugin;
53
+ /**
54
+ * Returns the framework Vite plugins in the canonical order. Auto-injected
55
+ * by `ReloaderService` for every renderer; exported for advanced users who
56
+ * want to compose them into a custom Vite stack.
57
+ *
58
+ * Order matters:
59
+ * 1. `zenbuFrameworkResolve` — `enforce: "pre"`, runs first so it gets
60
+ * `react` / `@zenbujs/core/*` *before* Vite's default resolver walks
61
+ * up and finds plugin-local copies.
62
+ * 2. `advicePreludePlugin` — generates the per-iframe prelude module.
63
+ * 3. `resolveAdviceRuntime` — points `@zenbu/advice/runtime` at core.
64
+ * 4. `zenbuAdviceTransform` — babel transform wrapping top-level fns.
65
+ */
66
+ declare function zenbuVitePlugins(): Plugin[];
67
+ //#endregion
68
+ export { advicePreludePlugin, resolveAdviceRuntime, zenbuAdviceTransform, zenbuFrameworkResolve, zenbuVitePlugins };
package/dist/vite.mjs ADDED
@@ -0,0 +1,2 @@
1
+ import { a as zenbuVitePlugins, i as zenbuFrameworkResolve, n as resolveAdviceRuntime, r as zenbuAdviceTransform, t as advicePreludePlugin } from "./vite-plugins-Bh3SCOw-.mjs";
2
+ export { advicePreludePlugin, resolveAdviceRuntime, zenbuAdviceTransform, zenbuFrameworkResolve, zenbuVitePlugins };
@@ -0,0 +1,2 @@
1
+ import "./window-CmmpCVX6.mjs";
2
+ export {};
@@ -0,0 +1,156 @@
1
+ import { a as serviceWithDeps, i as runtime } from "./runtime-DUFKDIe4.mjs";
2
+ import { t as createLogger } from "./log-CyKv8hQg.mjs";
3
+ import { n as ViewRegistryService, o as HttpService, t as RendererHostService } from "./renderer-host-Bg8QdeeH.mjs";
4
+ import { t as BaseWindowService } from "./base-window-BUt8pwbw.mjs";
5
+ import { URLSearchParams } from "node:url";
6
+ import { WebContentsView, clipboard, dialog, shell } from "electron";
7
+ import electronContextMenu from "electron-context-menu";
8
+ //#region src/services/window.ts
9
+ const log = createLogger("window");
10
+ function queryString(query) {
11
+ if (!query) return "";
12
+ const params = new URLSearchParams();
13
+ for (const [key, value] of Object.entries(query)) {
14
+ if (value === void 0 || value === null) continue;
15
+ params.set(key, String(value));
16
+ }
17
+ const encoded = params.toString();
18
+ return encoded ? `?${encoded}` : "";
19
+ }
20
+ var WindowService = class extends serviceWithDeps({
21
+ baseWindow: BaseWindowService,
22
+ viewRegistry: ViewRegistryService,
23
+ http: HttpService,
24
+ rendererHost: RendererHostService
25
+ }) {
26
+ static key = "window";
27
+ mounted = /* @__PURE__ */ new Map();
28
+ evaluate() {
29
+ this.setup("window-view-cleanup", () => {
30
+ return () => {
31
+ for (const mounted of this.mounted.values()) {
32
+ const win = this.ctx.baseWindow.windows.get(mounted.windowId);
33
+ try {
34
+ win?.contentView.removeChildView(mounted.view);
35
+ } catch {}
36
+ try {
37
+ mounted.disposeContextMenu();
38
+ } catch {}
39
+ mounted.view.webContents.close();
40
+ }
41
+ this.mounted.clear();
42
+ };
43
+ });
44
+ }
45
+ async openView(args) {
46
+ const entry = this.ctx.viewRegistry.get(args.scope);
47
+ if (!entry) throw new Error(`No registered view for scope "${args.scope}"`);
48
+ const windowId = args.windowId ?? "main";
49
+ let win = this.ctx.baseWindow.windows.get(windowId);
50
+ if (!win) win = this.ctx.baseWindow.createWindow({ windowId }).win;
51
+ const existing = this.mounted.get(windowId);
52
+ if (existing) {
53
+ try {
54
+ win.contentView.removeChildView(existing.view);
55
+ } catch {}
56
+ try {
57
+ existing.disposeContextMenu();
58
+ } catch {}
59
+ existing.view.webContents.close();
60
+ this.mounted.delete(windowId);
61
+ }
62
+ const view = new WebContentsView({ webPreferences: {
63
+ nodeIntegration: false,
64
+ contextIsolation: true,
65
+ sandbox: true
66
+ } });
67
+ view.setBackgroundColor("#F4F4F4");
68
+ win.contentView.addChildView(view);
69
+ const disposeContextMenu = electronContextMenu({
70
+ window: view,
71
+ showInspectElement: true,
72
+ showSearchWithGoogle: false,
73
+ showSelectAll: true
74
+ });
75
+ const handleInput = (_event, input) => {
76
+ if ((input.key === "I" || input.key === "i") && (process.platform === "darwin" && input.alt && input.meta || process.platform !== "darwin" && input.shift && input.control) || input.key === "F12") if (view.webContents.isDevToolsOpened()) view.webContents.closeDevTools();
77
+ else view.webContents.openDevTools({ mode: "detach" });
78
+ };
79
+ view.webContents.on("before-input-event", handleInput);
80
+ const layout = () => {
81
+ const { width, height } = win.getContentBounds();
82
+ view.setBounds({
83
+ x: 0,
84
+ y: 0,
85
+ width,
86
+ height
87
+ });
88
+ };
89
+ layout();
90
+ win.on("resize", layout);
91
+ view.webContents.once("destroyed", () => {
92
+ win.off("resize", layout);
93
+ try {
94
+ disposeContextMenu();
95
+ } catch {}
96
+ });
97
+ const url = `${entry.url.replace(/\/$/, "")}/index.html${queryString({
98
+ ...args.query,
99
+ wsPort: this.ctx.http.port,
100
+ wsToken: this.ctx.http.authToken,
101
+ windowId,
102
+ scope: args.scope
103
+ })}`;
104
+ await view.webContents.loadURL(url);
105
+ this.mounted.set(windowId, {
106
+ windowId,
107
+ scope: args.scope,
108
+ view,
109
+ disposeContextMenu
110
+ });
111
+ if (!win.isVisible()) win.show();
112
+ win.focus();
113
+ log.verbose(`mounted "${args.scope}" in window "${windowId}"`);
114
+ return { windowId };
115
+ }
116
+ async focusWindow(windowId) {
117
+ const win = this.ctx.baseWindow.windows.get(windowId);
118
+ if (win && !win.isDestroyed()) {
119
+ if (!win.isVisible()) win.show();
120
+ win.focus();
121
+ }
122
+ return { ok: true };
123
+ }
124
+ async pickFiles() {
125
+ const focusedWin = [...this.ctx.baseWindow.windows.values()].find((win) => win.isFocused());
126
+ const result = await dialog.showOpenDialog({
127
+ ...focusedWin ? { window: focusedWin } : {},
128
+ properties: ["openFile", "multiSelections"],
129
+ title: "Choose Files"
130
+ });
131
+ if (result.canceled || result.filePaths.length === 0) return null;
132
+ return result.filePaths;
133
+ }
134
+ async pickDirectory() {
135
+ const focusedWin = [...this.ctx.baseWindow.windows.values()].find((win) => win.isFocused());
136
+ const result = await dialog.showOpenDialog({
137
+ ...focusedWin ? { window: focusedWin } : {},
138
+ properties: ["openDirectory", "createDirectory"],
139
+ title: "Choose Directory"
140
+ });
141
+ if (result.canceled || result.filePaths.length === 0) return null;
142
+ return result.filePaths[0];
143
+ }
144
+ async openExternal(url) {
145
+ await shell.openExternal(url);
146
+ }
147
+ async openPath(filePath) {
148
+ await shell.openPath(filePath);
149
+ }
150
+ copyToClipboard(text) {
151
+ clipboard.writeText(text);
152
+ }
153
+ };
154
+ runtime.register(WindowService, import.meta);
155
+ //#endregion
156
+ export { WindowService as t };