@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.
- package/dist/{advice-config-BLXjqjGN.mjs → advice-config-DXSIo0sg.mjs} +49 -38
- package/dist/advice.d.mts +8 -8
- package/dist/advice.mjs +2 -2
- package/dist/base-window-BxBZ2md_.mjs +143 -0
- package/dist/build-config-Dzg2frpk.d.mts +215 -0
- package/dist/build-config-pWdmLnrk.mjs +53 -0
- package/dist/{build-electron-C3Beey84.mjs → build-electron-Dsbb1EMl.mjs} +308 -120
- package/dist/{build-source-BvC4bPqH.mjs → build-source-d1J3shV8.mjs} +62 -27
- package/dist/chunk-DsiFFCwN.mjs +16 -0
- package/dist/cli/bin.mjs +7 -7
- package/dist/cli/build.d.mts +2 -2
- package/dist/cli/build.mjs +2 -3
- package/dist/cli/resolve-config.mjs +3 -2
- package/dist/{cli-F0B4dvSg.mjs → cli-kL6mPgBE.mjs} +4 -4
- package/dist/{config-BlRXeUXx.mjs → config-BK78JDRI.mjs} +1 -1
- package/dist/config.d.mts +3 -2
- package/dist/config.mjs +3 -3
- package/dist/{db-Cd5ETuPG.mjs → db-Bc292RYo.mjs} +2 -2
- package/dist/db.d.mts +1 -1
- package/dist/db.mjs +2 -2
- package/dist/dev-B2emj0HZ.mjs +301 -0
- package/dist/env-bootstrap.d.mts +1 -1
- package/dist/env-bootstrap.mjs +52 -1
- package/dist/events.d.mts +19 -0
- package/dist/events.mjs +1 -0
- package/dist/host-version-BIrF8tX7.mjs +65 -0
- package/dist/index-w5QyDjuf.d.mts +780 -0
- package/dist/index.d.mts +5 -6
- package/dist/index.mjs +5 -5
- package/dist/installing-preload.cjs +60 -0
- package/dist/launcher.mjs +2615 -122
- package/dist/{link-BJmsKgPa.mjs → link-glX89NV5.mjs} +215 -89
- package/dist/{load-config-BG2tPIfF.mjs → load-config-C4Oe2qZO.mjs} +22 -3
- package/dist/loaders/zenbu.d.mts +1 -0
- package/dist/loaders/zenbu.mjs +108 -86
- package/dist/{monorepo-DCruz9Jx.mjs → monorepo-Dct-kkbQ.mjs} +3 -0
- package/dist/node-loader.mjs +1 -1
- package/dist/{publish-source-34Hn9zb0.mjs → publish-source-Dq2c0iOw.mjs} +2 -2
- package/dist/react.d.mts +56 -7
- package/dist/react.mjs +118 -7
- package/dist/registry-CMp8FYgS.d.mts +47 -0
- package/dist/registry-generated.d.mts +26 -0
- package/dist/registry-generated.mjs +1 -0
- package/dist/registry.d.mts +2 -2
- package/dist/{reloader-DJoCB0bC.mjs → reloader-B22UiNA2.mjs} +7 -7
- package/dist/{renderer-host-ztaSIOGx.mjs → renderer-host-DD16MXhI.mjs} +178 -57
- package/dist/{rpc-CsgWnlZx.mjs → rpc-C4_NQmpT.mjs} +11 -8
- package/dist/rpc.d.mts +1 -1
- package/dist/rpc.mjs +1 -1
- package/dist/runtime-BQWntcOb.d.mts +218 -0
- package/dist/runtime.d.mts +2 -2
- package/dist/runtime.mjs +578 -2
- package/dist/{schema-DvT61x2_.d.mts → schema-CjrMVk36.d.mts} +3 -3
- package/dist/schema.d.mts +1 -1
- package/dist/schema.mjs +27 -1
- package/dist/{server-DB3Eki_G.mjs → server-CZLMF8Dj.mjs} +6 -6
- package/dist/services/default.d.mts +3 -3
- package/dist/services/default.mjs +14 -13
- package/dist/services/index.d.mts +2 -276
- package/dist/services/index.mjs +8 -7
- package/dist/setup-gate.d.mts +1 -1
- package/dist/setup-gate.mjs +341 -1
- package/dist/{transform-DJH3vN4b.mjs → transform-BzrwkEdf.mjs} +23 -917
- package/dist/{transport-BMSzG2-F.mjs → transport-F2hv_OEm.mjs} +1 -1
- package/dist/updater-DCkz9M1c.mjs +1008 -0
- package/dist/{vite-plugins-t4MlFcz3.mjs → vite-plugins-tt6KAtyE.mjs} +27 -26
- package/dist/vite.d.mts +3 -3
- package/dist/vite.mjs +1 -1
- package/dist/{window-DUvMTons.mjs → window-YFKvAM0l.mjs} +36 -19
- package/dist/{write-9dRFczGJ.mjs → write-DgIRjo23.mjs} +1 -1
- package/package.json +18 -5
- package/dist/advice-config-D6K_a7e9.mjs +0 -2
- package/dist/base-window-D8CpxMU3.mjs +0 -94
- package/dist/base-window-OXg2KSyP.mjs +0 -2
- package/dist/build-config-BwnnfrN-.mjs +0 -23
- package/dist/chunk-Dm34NbLt.mjs +0 -6
- package/dist/config-Ch1FreWU.mjs +0 -2
- package/dist/db-Bz_CDIWg.mjs +0 -2
- package/dist/dev-DLutFPyo.mjs +0 -85
- package/dist/env-bootstrap-rj7I-59x.mjs +0 -53
- package/dist/http-B36qtsm0.mjs +0 -2
- package/dist/load-config-CQG4297M.mjs +0 -2
- package/dist/registry-CioEYLI5.d.mts +0 -61
- package/dist/reloader-FeHKV2jd.mjs +0 -2
- package/dist/renderer-host-BQpS0ZM2.mjs +0 -2
- package/dist/rpc-D_s7-WZe.mjs +0 -2
- package/dist/runtime-C95iyVn6.mjs +0 -461
- package/dist/runtime-CsiDppGF.d.mts +0 -149
- package/dist/schema-dGK6qkfR.mjs +0 -28
- package/dist/server-CgzQOPSW.mjs +0 -2
- package/dist/setup-gate-D8XfYY52.mjs +0 -140
- package/dist/transforms-DVoy8dCu.mjs +0 -47
- package/dist/transforms-EVd5Fgyk.d.mts +0 -136
- package/dist/view-registry-2zePxTEg.mjs +0 -2
- package/dist/window-S3TlTXlK.mjs +0 -2
- /package/dist/{env-bootstrap-uCKbw2q8.d.mts → env-bootstrap-rTs8KR3-.d.mts} +0 -0
- /package/dist/{index-CE0iPntP.d.mts → index-C-ALz_SH.d.mts} +0 -0
- /package/dist/{index-CKKoxA9V.d.mts → index-ClXLQ1fw.d.mts} +0 -0
- /package/dist/{index-UK58xuoR.d.mts → index-DeDxePAa.d.mts} +0 -0
- /package/dist/{log-CyKv8hQg.mjs → log-6rzaCV0I.mjs} +0 -0
- /package/dist/{mirror-sync-EiWvdzTJ.mjs → mirror-sync-pYU6f3-c.mjs} +0 -0
- /package/dist/{node-CvZnTx53.mjs → node-BhfLKYCi.mjs} +0 -0
- /package/dist/{schema-CIg4GzHQ.mjs → schema-Ca7SxXgS.mjs} +0 -0
- /package/dist/{setup-gate-D62nX5lk.d.mts → setup-gate-BQq0QgZH.d.mts} +0 -0
- /package/dist/{src-pELM4_iH.mjs → src-Cven45mq.mjs} +0 -0
- /package/dist/{trace-DCB7qFzT.mjs → trace-BaVg0rnY.mjs} +0 -0
package/dist/loaders/zenbu.mjs
CHANGED
|
@@ -1,16 +1,9 @@
|
|
|
1
|
-
import { createRequire } from "node:module";
|
|
2
1
|
import fs from "node:fs";
|
|
3
2
|
import path from "node:path";
|
|
4
3
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
5
4
|
import { execFileSync } from "node:child_process";
|
|
6
5
|
//#region src/loaders/zenbu.ts
|
|
7
6
|
const verbose = process.env.ZENBU_VERBOSE === "1";
|
|
8
|
-
const { subscribe } = createRequire(import.meta.url)("@parcel/watcher");
|
|
9
|
-
let registerWatcherClosable = () => {};
|
|
10
|
-
try {
|
|
11
|
-
const pause = await import("@zenbujs/hmr/pause");
|
|
12
|
-
registerWatcherClosable = typeof pause.registerWatcherClosable === "function" ? pause.registerWatcherClosable : registerWatcherClosable;
|
|
13
|
-
} catch {}
|
|
14
7
|
const loaderName = "zenbu-loader";
|
|
15
8
|
let tracePort = null;
|
|
16
9
|
const stats = {
|
|
@@ -19,26 +12,24 @@ const stats = {
|
|
|
19
12
|
loadCount: 0,
|
|
20
13
|
loadMs: 0
|
|
21
14
|
};
|
|
22
|
-
const barrels = /* @__PURE__ */ new Map();
|
|
23
|
-
const dirWatchers = /* @__PURE__ */ new Map();
|
|
24
15
|
let resolvedPayload = null;
|
|
25
16
|
let resolvedPluginSourceFiles = [];
|
|
26
17
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
*
|
|
35
|
-
* `execFileSync` blocks the loader for ~300ms per HMR cycle, which is fine.
|
|
18
|
+
* Set of absolute service file paths derived from the resolved payload.
|
|
19
|
+
* Used by the `file://` branch in `load()` to decide which user files
|
|
20
|
+
* should have `runtime.register(...)` auto-injected. Refreshed alongside
|
|
21
|
+
* `resolvedPayload` whenever the loader picks up a new config snapshot.
|
|
22
|
+
*/
|
|
23
|
+
let serviceFileSet = /* @__PURE__ */ new Set();
|
|
24
|
+
/**
|
|
25
|
+
* Number of times we've materialized the plugin root since boot.
|
|
36
26
|
*/
|
|
37
27
|
let pluginsRootInvocations = 0;
|
|
38
28
|
function initialize(data) {
|
|
39
29
|
if (data?.payload) {
|
|
40
30
|
resolvedPayload = data.payload;
|
|
41
31
|
resolvedPluginSourceFiles = data.pluginSourceFiles ?? [];
|
|
32
|
+
serviceFileSet = collectServiceFiles(data.payload);
|
|
42
33
|
}
|
|
43
34
|
if (data?.tracePort) {
|
|
44
35
|
tracePort = data.tracePort;
|
|
@@ -67,56 +58,88 @@ function expandGlob(pattern) {
|
|
|
67
58
|
if (!fs.existsSync(dir)) return [];
|
|
68
59
|
return fs.readdirSync(dir).filter((file) => regex.test(file)).map((file) => path.resolve(dir, file));
|
|
69
60
|
}
|
|
70
|
-
function
|
|
71
|
-
|
|
72
|
-
try {
|
|
73
|
-
return new Set(fs.readdirSync(dir).filter((file) => regex.test(file)));
|
|
74
|
-
} catch {
|
|
75
|
-
return /* @__PURE__ */ new Set();
|
|
76
|
-
}
|
|
61
|
+
function buildSource(imports) {
|
|
62
|
+
return imports.map((specifier) => `import ${JSON.stringify(specifier)}\n`).join("");
|
|
77
63
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
64
|
+
/**
|
|
65
|
+
* Matches the canonical service declaration shape after the upstream HMR
|
|
66
|
+
* loader (dynohot) has transformed the module. Dynohot strips the
|
|
67
|
+
* `export` keyword and minifies the source, so the regex must not
|
|
68
|
+
* require `export` and must tolerate a non-whitespace separator (e.g.
|
|
69
|
+
* `;class Foo extends Service.create(...)`). The `\b` boundary still
|
|
70
|
+
* rejects `subclass Foo` matches inside identifiers/comments.
|
|
71
|
+
*
|
|
72
|
+
* export class FooService extends Service.create({ ... }) { ... }
|
|
73
|
+
* ;class FooService extends Service.create({...}) {...} // post-dynohot
|
|
74
|
+
*
|
|
75
|
+
* `zen link` runs on the original on-disk source (pre-dynohot), so it
|
|
76
|
+
* keeps the `export` requirement in `discoverServices` to avoid matching
|
|
77
|
+
* non-exported helper classes.
|
|
78
|
+
*/
|
|
79
|
+
const SERVICE_CLASS_RE = /\bclass\s+(\w+)\s+extends\s+Service\.create\s*\(/g;
|
|
80
|
+
/**
|
|
81
|
+
* Decode the loader's `source` payload (which Node permits as string,
|
|
82
|
+
* Buffer, ArrayBuffer, or any TypedArray) into a plain UTF-8 string.
|
|
83
|
+
*/
|
|
84
|
+
function decodeSource(source) {
|
|
85
|
+
if (typeof source === "string") return source;
|
|
86
|
+
if (source instanceof Uint8Array) return Buffer.from(source).toString("utf8");
|
|
87
|
+
if (source instanceof ArrayBuffer) return Buffer.from(source).toString("utf8");
|
|
88
|
+
return String(source);
|
|
93
89
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
90
|
+
/**
|
|
91
|
+
* Tail-append a `runtime.register(<Class>, import.meta)` call to the
|
|
92
|
+
* loader result so user service files don't have to carry the boilerplate.
|
|
93
|
+
*
|
|
94
|
+
* - Idempotent: if the source already contains `runtime.register(`
|
|
95
|
+
* (manual migration leftover, or a user choosing to register
|
|
96
|
+
* explicitly), we leave it untouched.
|
|
97
|
+
* - Errors loudly when zero or multiple service classes are found, since
|
|
98
|
+
* the runtime's HMR model is "one slot per import.meta".
|
|
99
|
+
* - The runtime singleton imported here resolves through the loader's
|
|
100
|
+
* own `@zenbujs/core` short-circuit in `resolve()`, so the registered
|
|
101
|
+
* class lands in the same registry the rest of the framework reads.
|
|
102
|
+
*/
|
|
103
|
+
function appendAutoRegister(downstream, filePath) {
|
|
104
|
+
if (!downstream || typeof downstream !== "object") return downstream;
|
|
105
|
+
const result = downstream;
|
|
106
|
+
if (result.format !== "module") return downstream;
|
|
107
|
+
if (result.source == null) return downstream;
|
|
108
|
+
const source = decodeSource(result.source);
|
|
109
|
+
if (/\bruntime\s*\.\s*register\s*\(/.test(source)) return {
|
|
110
|
+
...result,
|
|
111
|
+
source
|
|
112
|
+
};
|
|
113
|
+
SERVICE_CLASS_RE.lastIndex = 0;
|
|
114
|
+
const matches = [...source.matchAll(SERVICE_CLASS_RE)];
|
|
115
|
+
if (matches.length === 0) throw new Error(`[zenbu-loader] auto-register: no \`class <Name> extends Service.create({ ... })\` found in ${filePath}.\n Either rewrite the class to use Service.create or add an explicit \`runtime.register(<Class>, import.meta)\`.`);
|
|
116
|
+
if (matches.length > 1) {
|
|
117
|
+
const names = matches.map((m) => m[1]).join(", ");
|
|
118
|
+
throw new Error(`[zenbu-loader] auto-register: ${matches.length} service classes (${names}) in ${filePath}.\n The HMR model is one service per file; split into separate files.`);
|
|
119
|
+
}
|
|
120
|
+
const tail = `\n;import { runtime as __zenbu_runtime__ } from "@zenbujs/core/runtime";\n__zenbu_runtime__.register(${matches[0][1]}, import.meta);\n`;
|
|
121
|
+
return {
|
|
122
|
+
...result,
|
|
123
|
+
source: source + tail
|
|
124
|
+
};
|
|
117
125
|
}
|
|
118
|
-
|
|
119
|
-
|
|
126
|
+
/**
|
|
127
|
+
* Expand each plugin's `services` glob list into a flat set of absolute
|
|
128
|
+
* file paths. Consulted by the `file://` branch in `load()` to decide
|
|
129
|
+
* whether to auto-inject `runtime.register(...)` for the loaded module.
|
|
130
|
+
*
|
|
131
|
+
* Glob expansion uses the same `expandGlob` (and therefore the same
|
|
132
|
+
* `fs.readdirSync` snapshot) that `buildPluginBarrel` uses, so the set
|
|
133
|
+
* stays in lockstep with what the barrel actually imports.
|
|
134
|
+
*/
|
|
135
|
+
function collectServiceFiles(payload) {
|
|
136
|
+
const set = /* @__PURE__ */ new Set();
|
|
137
|
+
for (const plugin of payload.plugins) for (const entry of plugin.services) {
|
|
138
|
+
const resolved = path.isAbsolute(entry) ? entry : path.resolve(plugin.dir, entry);
|
|
139
|
+
if (resolved.includes("*")) for (const f of expandGlob(resolved)) set.add(f);
|
|
140
|
+
else set.add(resolved);
|
|
141
|
+
}
|
|
142
|
+
return set;
|
|
120
143
|
}
|
|
121
144
|
/**
|
|
122
145
|
* Read the resolved config from the process global. setup-gate populates
|
|
@@ -164,6 +187,7 @@ function getResolvedConfig(configPath) {
|
|
|
164
187
|
const fresh = resolveConfigViaSubprocess(path.dirname(configPath));
|
|
165
188
|
resolvedPayload = fresh.payload;
|
|
166
189
|
resolvedPluginSourceFiles = fresh.pluginSourceFiles;
|
|
190
|
+
serviceFileSet = collectServiceFiles(fresh.payload);
|
|
167
191
|
return fresh;
|
|
168
192
|
}
|
|
169
193
|
/**
|
|
@@ -190,38 +214,30 @@ function buildRegistryModule(payload) {
|
|
|
190
214
|
return [
|
|
191
215
|
"import { replacePlugins, registerAppEntrypoint } from \"@zenbujs/core/runtime\"",
|
|
192
216
|
`replacePlugins(${JSON.stringify(payload.plugins)})`,
|
|
193
|
-
`registerAppEntrypoint(${JSON.stringify(payload.appEntrypoint)})`,
|
|
217
|
+
`registerAppEntrypoint(${JSON.stringify(payload.appEntrypoint)}, ${JSON.stringify(payload.splashPath)})`,
|
|
194
218
|
"import.meta.hot?.accept()"
|
|
195
219
|
].join("\n") + "\n";
|
|
196
220
|
}
|
|
197
221
|
/**
|
|
198
222
|
* Generate a per-plugin barrel: just service-file imports anchored at the
|
|
199
223
|
* plugin's `dir`. Glob-form entries get expanded via `fs.readdirSync` and
|
|
200
|
-
*
|
|
201
|
-
* barrel when service files are added/removed
|
|
224
|
+
* glob directories are registered with `context.hot.watch()` so dynohot
|
|
225
|
+
* reloads the generated barrel when service files are added/removed.
|
|
202
226
|
*/
|
|
203
227
|
function buildPluginBarrel(plugin) {
|
|
204
228
|
const imports = [];
|
|
205
229
|
const watchPaths = new Set([plugin.dir]);
|
|
206
|
-
const globs = [];
|
|
207
230
|
for (const entry of plugin.services) {
|
|
208
231
|
const resolved = path.isAbsolute(entry) ? entry : path.resolve(plugin.dir, entry);
|
|
209
232
|
if (resolved.includes("*")) {
|
|
210
233
|
const dir = path.dirname(resolved);
|
|
211
|
-
const regex = globRegex(path.basename(resolved));
|
|
212
234
|
watchPaths.add(dir);
|
|
213
|
-
globs.push({
|
|
214
|
-
dir,
|
|
215
|
-
regex,
|
|
216
|
-
snapshot: snapshotDir(dir, regex)
|
|
217
|
-
});
|
|
218
235
|
for (const file of expandGlob(resolved)) imports.push(pathToFileURL(file).href);
|
|
219
236
|
} else imports.push(pathToFileURL(resolved).href);
|
|
220
237
|
}
|
|
221
238
|
return {
|
|
222
239
|
source: `${buildSource(imports)}import.meta.hot?.accept()\n`,
|
|
223
|
-
watchPaths
|
|
224
|
-
globs
|
|
240
|
+
watchPaths
|
|
225
241
|
};
|
|
226
242
|
}
|
|
227
243
|
const CORE_PACKAGE_ROOT_FOR_LOADER = (() => {
|
|
@@ -316,6 +332,19 @@ function loadImpl(url, context, nextLoad) {
|
|
|
316
332
|
shortCircuit: true
|
|
317
333
|
};
|
|
318
334
|
}
|
|
335
|
+
if (url.startsWith("file://")) {
|
|
336
|
+
let filePath;
|
|
337
|
+
try {
|
|
338
|
+
filePath = fileURLToPath(url);
|
|
339
|
+
} catch {
|
|
340
|
+
filePath = "";
|
|
341
|
+
}
|
|
342
|
+
if (filePath && serviceFileSet.has(filePath)) {
|
|
343
|
+
const downstream = nextLoad(url, context);
|
|
344
|
+
if (downstream && typeof downstream.then === "function") return Promise.resolve(downstream).then((r) => appendAutoRegister(r, filePath));
|
|
345
|
+
return appendAutoRegister(downstream, filePath);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
319
348
|
if (url.startsWith("zenbu:barrel?")) {
|
|
320
349
|
const params = new URL(url).searchParams;
|
|
321
350
|
const pluginRaw = decodeURIComponent(params.get("plugin") ?? "");
|
|
@@ -325,16 +354,9 @@ function loadImpl(url, context, nextLoad) {
|
|
|
325
354
|
} catch (err) {
|
|
326
355
|
throw new Error(`[zenbu-loader] bad plugin payload: ${err.message}`);
|
|
327
356
|
}
|
|
328
|
-
const { source, watchPaths
|
|
357
|
+
const { source, watchPaths } = buildPluginBarrel(plugin);
|
|
329
358
|
if (context.hot?.watch) for (const watchPath of watchPaths) context.hot.watch(pathToFileURL(watchPath));
|
|
330
|
-
if (
|
|
331
|
-
barrels.set(url, {
|
|
332
|
-
hot: context.hot,
|
|
333
|
-
globs
|
|
334
|
-
});
|
|
335
|
-
for (const glob of globs) ensureDirWatcher(glob.dir);
|
|
336
|
-
}
|
|
337
|
-
if (verbose) console.log(`[zenbu-loader] generated barrel for plugin ${plugin.name} (${source.split("\n").filter(Boolean).length} imports, ${watchPaths.size} watches, ${globs.length} globs)`);
|
|
359
|
+
if (verbose) console.log(`[zenbu-loader] generated barrel for plugin ${plugin.name} (${source.split("\n").filter(Boolean).length} imports, ${watchPaths.size} watches)`);
|
|
338
360
|
return {
|
|
339
361
|
format: "module",
|
|
340
362
|
source,
|
|
@@ -3,6 +3,9 @@ import os from "node:os";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { execFileSync } from "node:child_process";
|
|
5
5
|
//#region src/cli/commands/monorepo.ts
|
|
6
|
+
/**
|
|
7
|
+
* todo: should only be exposed when an env var is passed
|
|
8
|
+
*/
|
|
6
9
|
const MARKER_FILE = ".zenbu-dev-link";
|
|
7
10
|
const DEFAULT_MONOREPO = path.join(os.homedir(), ".zenbu", "plugins", "zenbu");
|
|
8
11
|
function resolveProjectDir() {
|
package/dist/node-loader.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as require_lib, t as zenbuAdviceTransform } from "./transform-
|
|
1
|
+
import { n as require_lib, t as zenbuAdviceTransform } from "./transform-BzrwkEdf.mjs";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
3
|
//#region ../advice/src/node-loader.ts
|
|
4
4
|
var import_lib = require_lib();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as init, r as push } from "./mirror-sync-
|
|
1
|
+
import { t as loadConfig } from "./load-config-C4Oe2qZO.mjs";
|
|
2
|
+
import { n as init, r as push } from "./mirror-sync-pYU6f3-c.mjs";
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { execFileSync } from "node:child_process";
|
package/dist/react.d.mts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { f as CollectionRefBrand, h as InferCollectionItem, n as connectReplica, o as ClientProxy, p as CollectionRefValue, u as CollectionState, y as SchemaShape } from "./index-
|
|
2
|
-
import {
|
|
3
|
-
import { n as
|
|
1
|
+
import { f as CollectionRefBrand, h as InferCollectionItem, n as connectReplica, o as ClientProxy, p as CollectionRefValue, u as CollectionState, y as SchemaShape } from "./index-DeDxePAa.mjs";
|
|
2
|
+
import { n as EventProxy, r as RouterProxy } from "./index-C-ALz_SH.mjs";
|
|
3
|
+
import { i as ZenbuRegister, n as ResolvedEvents, r as ResolvedServiceRouter, t as ResolvedDbRoot } from "./registry-CMp8FYgS.mjs";
|
|
4
4
|
import * as _$react from "react";
|
|
5
|
-
import { ReactNode } from "react";
|
|
5
|
+
import { CSSProperties, ReactElement, ReactNode } from "react";
|
|
6
6
|
|
|
7
7
|
//#region ../kyju/src/v2/react/index.d.ts
|
|
8
8
|
type CollectionResult<Item> = {
|
|
@@ -57,9 +57,9 @@ declare function ZenbuProvider({
|
|
|
57
57
|
fallback,
|
|
58
58
|
errorFallback,
|
|
59
59
|
children
|
|
60
|
-
}: ZenbuProviderProps):
|
|
60
|
+
}: ZenbuProviderProps): ReactElement<{
|
|
61
61
|
"data-zenbu-connecting": boolean;
|
|
62
|
-
}, string | _$react.JSXElementConstructor<any>> |
|
|
62
|
+
}, string | _$react.JSXElementConstructor<any>> | ReactElement<{
|
|
63
63
|
"data-zenbu-error": boolean;
|
|
64
64
|
}, string | _$react.JSXElementConstructor<any>> | _$react.FunctionComponentElement<_$react.ProviderProps<ConnectionState | null>>;
|
|
65
65
|
declare function useRpc(): RouterProxy<RegisteredServiceRouter>;
|
|
@@ -72,5 +72,54 @@ type DbClient = {
|
|
|
72
72
|
};
|
|
73
73
|
declare function useDbClient(): DbClient;
|
|
74
74
|
declare function useEvents(): EventProxy<RegisteredEvents>;
|
|
75
|
+
/**
|
|
76
|
+
* Mounts a registered view (separate Vite root, registered via
|
|
77
|
+
* `ViewRegistryService.register(type, …)`) inside an `<iframe>` and:
|
|
78
|
+
*
|
|
79
|
+
* 1. **Auto-inherits auth from the parent iframe's URL.** Reads `wsPort` /
|
|
80
|
+
* `wsToken` from `window.location.search` and forwards them in the
|
|
81
|
+
* child URL so the child's `<ZenbuProvider>` connects without the
|
|
82
|
+
* consumer wiring anything.
|
|
83
|
+
* 2. **Mount-once src.** The iframe's `src` is set on first mount and
|
|
84
|
+
* *never updated*. Toggling `visible` only flips `style.display` —
|
|
85
|
+
* state inside the child (sockets, ghostty terminals, etc.) survives
|
|
86
|
+
* visibility changes.
|
|
87
|
+
* 3. **Initial args via URL.** `args` is encoded as base64 JSON in
|
|
88
|
+
* `?args=` on first paint so the child can render without waiting on
|
|
89
|
+
* a postMessage handshake. Use `useViewArgs<T>()` inside the child
|
|
90
|
+
* to read.
|
|
91
|
+
* 4. **Reactive args via postMessage.** When `args` changes after mount,
|
|
92
|
+
* we send `{ kind: "zenbu:view-args", args }` to the iframe's
|
|
93
|
+
* `contentWindow`. URL is *not* rewritten (iframe stays alive).
|
|
94
|
+
*
|
|
95
|
+
* Child sessions die on unmount. There is no cache: if the consumer
|
|
96
|
+
* unmounts the `<View>` element, any state inside it (e.g. PTY sockets)
|
|
97
|
+
* is gone. Caller is responsible for explicit teardown via RPC if
|
|
98
|
+
* needed.
|
|
99
|
+
*/
|
|
100
|
+
type ViewProps = {
|
|
101
|
+
/** Registered view type — first arg to `ViewRegistryService.register`. */type: string; /** Initial args; serialized into the child URL as base64-JSON. */
|
|
102
|
+
args?: Record<string, unknown>; /** When false, sets `style.display: none`. Iframe is NOT unmounted. */
|
|
103
|
+
visible?: boolean;
|
|
104
|
+
style?: CSSProperties;
|
|
105
|
+
className?: string;
|
|
106
|
+
onLoad?: () => void; /** Rendered while the view registry has not yet reported a URL for this type. */
|
|
107
|
+
fallback?: ReactNode;
|
|
108
|
+
};
|
|
109
|
+
declare function View({
|
|
110
|
+
type,
|
|
111
|
+
args,
|
|
112
|
+
visible,
|
|
113
|
+
style,
|
|
114
|
+
className,
|
|
115
|
+
onLoad,
|
|
116
|
+
fallback
|
|
117
|
+
}: ViewProps): ReactElement;
|
|
118
|
+
/**
|
|
119
|
+
* Read the current view args inside a child iframe rendered by `<View>`.
|
|
120
|
+
* Initial value comes from `?args=` in the iframe's URL; updates arrive
|
|
121
|
+
* via `postMessage` and re-render this hook's caller.
|
|
122
|
+
*/
|
|
123
|
+
declare function useViewArgs<T extends Record<string, unknown>>(): T;
|
|
75
124
|
//#endregion
|
|
76
|
-
export { type CollectionRefValue, DbClient, ZenbuProvider, ZenbuProviderProps, type ZenbuRegister, useCollection, useDb, useDbClient, useEvents, useRpc };
|
|
125
|
+
export { type CollectionRefValue, DbClient, View, ViewProps, ZenbuProvider, ZenbuProviderProps, type ZenbuRegister, useCollection, useDb, useDbClient, useEvents, useRpc, useViewArgs };
|
package/dist/react.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { i as dbStringify, r as dbParse, t as connectReplica } from "./transport-
|
|
2
|
-
import { t as connectRpc } from "./src-
|
|
1
|
+
import { i as dbStringify, r as dbParse, t as connectReplica } from "./transport-F2hv_OEm.mjs";
|
|
2
|
+
import { t as connectRpc } from "./src-Cven45mq.mjs";
|
|
3
3
|
import { createContext, createElement, useCallback, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
4
4
|
//#region ../kyju/src/v2/react/index.ts
|
|
5
5
|
function createKyjuReact() {
|
|
@@ -209,13 +209,12 @@ function ZenbuProvider({ wsUrl, fallback, errorFallback, children }) {
|
|
|
209
209
|
ws.close();
|
|
210
210
|
return;
|
|
211
211
|
}
|
|
212
|
-
const
|
|
213
|
-
const viewScope = viewMatch ? viewMatch[1] : null;
|
|
212
|
+
const viewType = window.location.pathname.match(/^\/views\/([^/]+)\//)?.[1] ?? new URLSearchParams(window.location.search).get("type");
|
|
214
213
|
let unsubReload = null;
|
|
215
|
-
if (
|
|
214
|
+
if (viewType) {
|
|
216
215
|
const adviceReload = events?.advice?.reload;
|
|
217
216
|
if (adviceReload?.subscribe) unsubReload = adviceReload.subscribe((data) => {
|
|
218
|
-
if (data?.
|
|
217
|
+
if (data?.type === "*" || data?.type === viewType) location.reload();
|
|
219
218
|
});
|
|
220
219
|
}
|
|
221
220
|
cleanupRef.current = () => {
|
|
@@ -287,5 +286,117 @@ function useDbClient() {
|
|
|
287
286
|
function useEvents() {
|
|
288
287
|
return useConnection().events;
|
|
289
288
|
}
|
|
289
|
+
const VIEW_ARGS_MESSAGE_KIND = "zenbu:view-args";
|
|
290
|
+
const VIEW_ARGS_PARAM_LIMIT = 1500;
|
|
291
|
+
function encodeViewArgs(args) {
|
|
292
|
+
if (!args) return null;
|
|
293
|
+
try {
|
|
294
|
+
return btoa(unescape(encodeURIComponent(JSON.stringify(args))));
|
|
295
|
+
} catch (err) {
|
|
296
|
+
console.warn("[zenbu/View] failed to encode args:", err);
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
function decodeViewArgs(encoded) {
|
|
301
|
+
if (!encoded) return {};
|
|
302
|
+
try {
|
|
303
|
+
return JSON.parse(decodeURIComponent(escape(atob(encoded))));
|
|
304
|
+
} catch (err) {
|
|
305
|
+
console.warn("[zenbu/View] failed to decode args:", err);
|
|
306
|
+
return {};
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
function buildViewUrl(baseUrl, type, encodedArgs) {
|
|
310
|
+
const trimmed = baseUrl.replace(/\/$/, "");
|
|
311
|
+
const parentParams = new URLSearchParams(window.location.search);
|
|
312
|
+
const params = new URLSearchParams();
|
|
313
|
+
const wsPort = parentParams.get("wsPort");
|
|
314
|
+
const wsToken = parentParams.get("wsToken");
|
|
315
|
+
if (wsPort) params.set("wsPort", wsPort);
|
|
316
|
+
if (wsToken) params.set("wsToken", wsToken);
|
|
317
|
+
params.set("type", type);
|
|
318
|
+
if (encodedArgs) params.set("args", encodedArgs);
|
|
319
|
+
return `${trimmed}/?${params.toString()}`;
|
|
320
|
+
}
|
|
321
|
+
function shallowJSONEqual(a, b) {
|
|
322
|
+
try {
|
|
323
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
324
|
+
} catch {
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
function View({ type, args, visible = true, style, className, onLoad, fallback = null }) {
|
|
329
|
+
const url = useDb((root) => root.plugin.core.lastKnownViewRegistry.find((v) => v.type === type)?.url ?? null);
|
|
330
|
+
const iframeRef = useRef(null);
|
|
331
|
+
const initialUrlRef = useRef(null);
|
|
332
|
+
const lastArgsRef = useRef(null);
|
|
333
|
+
const loadedRef = useRef(false);
|
|
334
|
+
if (initialUrlRef.current === null && url) {
|
|
335
|
+
const encoded = encodeViewArgs(args);
|
|
336
|
+
if (encoded && encoded.length > VIEW_ARGS_PARAM_LIMIT) console.warn(`[zenbu/View] args for "${type}" exceed ${VIEW_ARGS_PARAM_LIMIT} chars in URL — consider postMessage-only updates.`);
|
|
337
|
+
lastArgsRef.current = encoded;
|
|
338
|
+
initialUrlRef.current = buildViewUrl(url, type, encoded);
|
|
339
|
+
}
|
|
340
|
+
useEffect(() => {
|
|
341
|
+
if (!iframeRef.current) return;
|
|
342
|
+
const encoded = encodeViewArgs(args);
|
|
343
|
+
if (shallowJSONEqual(encoded, lastArgsRef.current)) return;
|
|
344
|
+
lastArgsRef.current = encoded;
|
|
345
|
+
const send = () => {
|
|
346
|
+
iframeRef.current?.contentWindow?.postMessage({
|
|
347
|
+
kind: VIEW_ARGS_MESSAGE_KIND,
|
|
348
|
+
args: args ?? {}
|
|
349
|
+
}, "*");
|
|
350
|
+
};
|
|
351
|
+
if (loadedRef.current) send();
|
|
352
|
+
else {
|
|
353
|
+
const iframe = iframeRef.current;
|
|
354
|
+
const onceLoaded = () => {
|
|
355
|
+
send();
|
|
356
|
+
iframe.removeEventListener("load", onceLoaded);
|
|
357
|
+
};
|
|
358
|
+
iframe.addEventListener("load", onceLoaded);
|
|
359
|
+
return () => iframe.removeEventListener("load", onceLoaded);
|
|
360
|
+
}
|
|
361
|
+
}, [args]);
|
|
362
|
+
if (!initialUrlRef.current) return createElement("span", { "data-zenbu-view-pending": type }, fallback);
|
|
363
|
+
return createElement("iframe", {
|
|
364
|
+
ref: iframeRef,
|
|
365
|
+
src: initialUrlRef.current,
|
|
366
|
+
className,
|
|
367
|
+
style: {
|
|
368
|
+
border: "none",
|
|
369
|
+
...style,
|
|
370
|
+
display: visible ? style?.display ?? "block" : "none"
|
|
371
|
+
},
|
|
372
|
+
onLoad: () => {
|
|
373
|
+
loadedRef.current = true;
|
|
374
|
+
onLoad?.();
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Read the current view args inside a child iframe rendered by `<View>`.
|
|
380
|
+
* Initial value comes from `?args=` in the iframe's URL; updates arrive
|
|
381
|
+
* via `postMessage` and re-render this hook's caller.
|
|
382
|
+
*/
|
|
383
|
+
function useViewArgs() {
|
|
384
|
+
const [args, setArgs] = useState(() => {
|
|
385
|
+
return decodeViewArgs(new URLSearchParams(typeof window !== "undefined" ? window.location.search : "").get("args"));
|
|
386
|
+
});
|
|
387
|
+
useEffect(() => {
|
|
388
|
+
const handler = (event) => {
|
|
389
|
+
if (event.source !== window.parent) return;
|
|
390
|
+
const data = event.data;
|
|
391
|
+
if (!data || typeof data !== "object") return;
|
|
392
|
+
if (data.kind !== VIEW_ARGS_MESSAGE_KIND) return;
|
|
393
|
+
const next = data.args;
|
|
394
|
+
if (next && typeof next === "object") setArgs(next);
|
|
395
|
+
};
|
|
396
|
+
window.addEventListener("message", handler);
|
|
397
|
+
return () => window.removeEventListener("message", handler);
|
|
398
|
+
}, []);
|
|
399
|
+
return args;
|
|
400
|
+
}
|
|
290
401
|
//#endregion
|
|
291
|
-
export { ZenbuProvider, useCollection, useDb, useDbClient, useEvents, useRpc };
|
|
402
|
+
export { View, ZenbuProvider, useCollection, useDb, useDbClient, useEvents, useRpc, useViewArgs };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
//#region src/registry.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The registry seam.
|
|
4
|
+
*
|
|
5
|
+
* `ZenbuRegister` is the empty interface that downstream apps (and
|
|
6
|
+
* core's own `pnpm link:types` output) augment via:
|
|
7
|
+
*
|
|
8
|
+
* declare module "@zenbujs/core/registry" {
|
|
9
|
+
* interface ZenbuRegister {
|
|
10
|
+
* db: DbRoot
|
|
11
|
+
* rpc: ServiceRouter
|
|
12
|
+
* events: PluginEvents
|
|
13
|
+
* }
|
|
14
|
+
* }
|
|
15
|
+
*
|
|
16
|
+
* Server services (`DbService.client`, `RpcService.emit`) and renderer
|
|
17
|
+
* hooks (`useDb`, `useRpc`, `useEvents`) all read their types from
|
|
18
|
+
* `ZenbuRegister` via the `Resolved*` aliases below, so each TS program
|
|
19
|
+
* sees its own merged surface without generics at the call site.
|
|
20
|
+
*
|
|
21
|
+
* Concrete types live elsewhere:
|
|
22
|
+
* - core's published surface: `@zenbujs/core/registry-generated`
|
|
23
|
+
* (regenerated by `pnpm link:types`, shipped via tsdown -> dist/)
|
|
24
|
+
* - downstream's user-side surface: `<app>/types/services.ts` etc.
|
|
25
|
+
* (regenerated by `zen link`)
|
|
26
|
+
*
|
|
27
|
+
* registry.ts itself stays minimal on purpose: only the augmentation
|
|
28
|
+
* target + plug-and-play fallbacks. Anything more would need to be
|
|
29
|
+
* hand-maintained, and we want the link generator to be the single
|
|
30
|
+
* source of truth.
|
|
31
|
+
*
|
|
32
|
+
* Mirrors the pattern TanStack Router uses for `Register`.
|
|
33
|
+
*/
|
|
34
|
+
interface ZenbuRegister {}
|
|
35
|
+
type ResolvedDbRoot = ZenbuRegister extends {
|
|
36
|
+
db: infer T;
|
|
37
|
+
} ? T : {
|
|
38
|
+
plugin: {};
|
|
39
|
+
};
|
|
40
|
+
type ResolvedServiceRouter = ZenbuRegister extends {
|
|
41
|
+
rpc: infer T;
|
|
42
|
+
} ? T : {};
|
|
43
|
+
type ResolvedEvents = ZenbuRegister extends {
|
|
44
|
+
events: infer T;
|
|
45
|
+
} ? T : {};
|
|
46
|
+
//#endregion
|
|
47
|
+
export { ZenbuRegister as i, ResolvedEvents as n, ResolvedServiceRouter as r, ResolvedDbRoot as t };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Events } from "./events.mjs";
|
|
2
|
+
import { n as SchemaRoot } from "./schema-CjrMVk36.mjs";
|
|
3
|
+
import { c as DbService, d as ServerService, i as BaseWindowService, l as HttpService, n as WindowService, o as RendererHostService, r as RpcService, s as ViewRegistryService, t as UpdaterService, u as ReloaderService } from "./index-w5QyDjuf.mjs";
|
|
4
|
+
|
|
5
|
+
//#region src/registry-generated.d.ts
|
|
6
|
+
type ServiceBase = "evaluate" | "shutdown" | "constructor" | "effect" | "__cleanupAllEffects" | "__effectCleanups" | "ctx";
|
|
7
|
+
type ExtractRpcMethods<T> = { [K in Exclude<keyof T, ServiceBase | `_${string}`> as T[K] extends ((...args: any[]) => any) ? K : never]: T[K] };
|
|
8
|
+
type CoreServiceRouter = {
|
|
9
|
+
"base-window": ExtractRpcMethods<BaseWindowService>;
|
|
10
|
+
db: ExtractRpcMethods<DbService>;
|
|
11
|
+
http: ExtractRpcMethods<HttpService>;
|
|
12
|
+
reloader: ExtractRpcMethods<ReloaderService>;
|
|
13
|
+
"renderer-host": ExtractRpcMethods<RendererHostService>;
|
|
14
|
+
rpc: ExtractRpcMethods<RpcService>;
|
|
15
|
+
server: ExtractRpcMethods<ServerService>;
|
|
16
|
+
updater: ExtractRpcMethods<UpdaterService>;
|
|
17
|
+
"view-registry": ExtractRpcMethods<ViewRegistryService>;
|
|
18
|
+
window: ExtractRpcMethods<WindowService>;
|
|
19
|
+
};
|
|
20
|
+
type CoreEvents = Events;
|
|
21
|
+
type CoreDbSections = {
|
|
22
|
+
core: SchemaRoot;
|
|
23
|
+
};
|
|
24
|
+
type CorePreloads = {};
|
|
25
|
+
//#endregion
|
|
26
|
+
export { CoreDbSections, CoreEvents, CorePreloads, CoreServiceRouter };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/registry.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
1
|
+
import { i as ZenbuRegister, n as ResolvedEvents, r as ResolvedServiceRouter, t as ResolvedDbRoot } from "./registry-CMp8FYgS.mjs";
|
|
2
|
+
export { ResolvedDbRoot, ResolvedEvents, ResolvedServiceRouter, ZenbuRegister };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { n as __exportAll } from "./chunk-DsiFFCwN.mjs";
|
|
2
|
+
import { Service, runtime } from "./runtime.mjs";
|
|
3
|
+
import { t as createLogger } from "./log-6rzaCV0I.mjs";
|
|
4
|
+
import { a as zenbuVitePlugins } from "./vite-plugins-tt6KAtyE.mjs";
|
|
4
5
|
import os from "node:os";
|
|
5
6
|
import path, { resolve } from "node:path";
|
|
6
7
|
import { createHash } from "node:crypto";
|
|
@@ -15,6 +16,7 @@ const DB_CONFIG_JSON = path.join(INTERNAL_DIR, "db.json");
|
|
|
15
16
|
path.join(INTERNAL_DIR, "plugin-setup-state.json");
|
|
16
17
|
//#endregion
|
|
17
18
|
//#region src/services/reloader.ts
|
|
19
|
+
var reloader_exports = /* @__PURE__ */ __exportAll({ ReloaderService: () => ReloaderService });
|
|
18
20
|
const log = createLogger("reloader");
|
|
19
21
|
function safeCacheSegment(value) {
|
|
20
22
|
return value.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64) || "renderer";
|
|
@@ -111,9 +113,7 @@ async function startRendererServer(options) {
|
|
|
111
113
|
await warmupRendererEntrypoints(server, options.root);
|
|
112
114
|
return server;
|
|
113
115
|
}
|
|
114
|
-
var ReloaderService = class extends Service {
|
|
115
|
-
static key = "reloader";
|
|
116
|
-
static deps = {};
|
|
116
|
+
var ReloaderService = class extends Service.create({ key: "reloader" }) {
|
|
117
117
|
servers = /* @__PURE__ */ new Map();
|
|
118
118
|
async create(id, root, configFile) {
|
|
119
119
|
if (this.servers.has(id)) return this.servers.get(id);
|
|
@@ -161,4 +161,4 @@ var ReloaderService = class extends Service {
|
|
|
161
161
|
};
|
|
162
162
|
runtime.register(ReloaderService, import.meta);
|
|
163
163
|
//#endregion
|
|
164
|
-
export {
|
|
164
|
+
export { INTERNAL_DIR as i, reloader_exports as n, DB_CONFIG_JSON as r, ReloaderService as t };
|