@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.
- package/LICENSE +11 -0
- package/dist/advice-config-CjgkEf2E.mjs +135 -0
- package/dist/advice-config-Cy133IQP.mjs +2 -0
- package/dist/advice-runtime.d.mts +35 -0
- package/dist/advice-runtime.mjs +131 -0
- package/dist/advice.d.mts +36 -0
- package/dist/advice.mjs +2 -0
- package/dist/base-window-BUt8pwbw.mjs +94 -0
- package/dist/base-window-DEIAk618.mjs +2 -0
- package/dist/build-config-pbv0w4oN.mjs +17 -0
- package/dist/build-electron-B4Gd0Gi4.mjs +516 -0
- package/dist/build-source-_q1n1zTV.mjs +162 -0
- package/dist/chunk-Dm34NbLt.mjs +6 -0
- package/dist/cli/bin.d.mts +1 -0
- package/dist/cli/bin.mjs +88 -0
- package/dist/cli/build.d.mts +53 -0
- package/dist/cli/build.mjs +48 -0
- package/dist/cli-BLbQQIVB.mjs +8054 -0
- package/dist/config-CdVrW85P.mjs +59 -0
- package/dist/config-LK73dJmO.mjs +2 -0
- package/dist/db-ByKPbnP6.mjs +2 -0
- package/dist/db-DhuAJrye.mjs +531 -0
- package/dist/db.d.mts +16 -0
- package/dist/db.mjs +16 -0
- package/dist/dev-BuqklM0k.mjs +85 -0
- package/dist/env-bootstrap-BtVME-CU.d.mts +16 -0
- package/dist/env-bootstrap-rj7I-59x.mjs +53 -0
- package/dist/env-bootstrap.d.mts +2 -0
- package/dist/env-bootstrap.mjs +2 -0
- package/dist/http-IBcLzbYu.mjs +2 -0
- package/dist/index-Bhlbyrn7.d.mts +63 -0
- package/dist/index-CPZ5d6Hl.d.mts +442 -0
- package/dist/index-FtE8MXJ_.d.mts +1 -0
- package/dist/index.d.mts +6 -0
- package/dist/index.mjs +5 -0
- package/dist/launcher.mjs +173 -0
- package/dist/link-6roQ7Cn6.mjs +580 -0
- package/dist/loaders/zenbu.d.mts +22 -0
- package/dist/loaders/zenbu.mjs +267 -0
- package/dist/log-CyKv8hQg.mjs +20 -0
- package/dist/mirror-sync-CodOnwkD.mjs +332 -0
- package/dist/monorepo-CmGPHsVm.mjs +119 -0
- package/dist/node-D4M19_mV.mjs +5 -0
- package/dist/node-loader.d.mts +17 -0
- package/dist/node-loader.mjs +33 -0
- package/dist/pause-DvAUNmKn.mjs +52 -0
- package/dist/publish-source-BVgB62Zj.mjs +131 -0
- package/dist/react.d.mts +76 -0
- package/dist/react.mjs +291 -0
- package/dist/registry-Dh_e7HU1.d.mts +61 -0
- package/dist/registry.d.mts +2 -0
- package/dist/registry.mjs +1 -0
- package/dist/reloader-BCkLjDhS.mjs +2 -0
- package/dist/reloader-lLAJ3lqg.mjs +164 -0
- package/dist/renderer-host-Bg8QdeeH.mjs +1508 -0
- package/dist/renderer-host-DpvBPTHJ.mjs +2 -0
- package/dist/rpc-BwwQK6hD.mjs +71 -0
- package/dist/rpc-CqitnyR4.mjs +2 -0
- package/dist/rpc.d.mts +2 -0
- package/dist/rpc.mjs +2 -0
- package/dist/runtime-CjqDr8Yf.d.mts +109 -0
- package/dist/runtime-DUFKDIe4.mjs +409 -0
- package/dist/runtime.d.mts +2 -0
- package/dist/runtime.mjs +2 -0
- package/dist/schema-CIg4GzHQ.mjs +100 -0
- package/dist/schema-DMoSkwUx.d.mts +62 -0
- package/dist/schema-dGK6qkfR.mjs +28 -0
- package/dist/schema.d.mts +2 -0
- package/dist/schema.mjs +2 -0
- package/dist/server-BXwZEQ-n.mjs +66 -0
- package/dist/server-DjrZUbbu.mjs +2 -0
- package/dist/services/default.d.mts +11 -0
- package/dist/services/default.mjs +22 -0
- package/dist/services/index.d.mts +276 -0
- package/dist/services/index.mjs +7 -0
- package/dist/setup-gate-BeD6WS6d.mjs +110 -0
- package/dist/setup-gate-BqOzm7zp.d.mts +4 -0
- package/dist/setup-gate.d.mts +2 -0
- package/dist/setup-gate.mjs +2 -0
- package/dist/src-pELM4_iH.mjs +376 -0
- package/dist/trace-DCB7qFzT.mjs +10 -0
- package/dist/transform-DJH3vN4b.mjs +84041 -0
- package/dist/transport-BMSzG2-F.mjs +1045 -0
- package/dist/view-registry-BualWgAf.mjs +2 -0
- package/dist/vite-plugins-Bh3SCOw-.mjs +331 -0
- package/dist/vite.d.mts +68 -0
- package/dist/vite.mjs +2 -0
- package/dist/window-CM2a9Kyc.mjs +2 -0
- package/dist/window-CmmpCVX6.mjs +156 -0
- package/dist/write-9dRFczGJ.mjs +1248 -0
- package/migrations/0000_migration.ts +34 -0
- package/migrations/meta/0000_snapshot.json +18 -0
- package/migrations/meta/_journal.json +10 -0
- package/package.json +124 -0
|
@@ -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 };
|
package/dist/vite.d.mts
ADDED
|
@@ -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,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 };
|