@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/rpc-D_s7-WZe.mjs
DELETED
|
@@ -1,461 +0,0 @@
|
|
|
1
|
-
//#region src/runtime.ts
|
|
2
|
-
function optional(ref) {
|
|
3
|
-
return {
|
|
4
|
-
__optional: true,
|
|
5
|
-
ref
|
|
6
|
-
};
|
|
7
|
-
}
|
|
8
|
-
function resolveDep(entry) {
|
|
9
|
-
if (typeof entry === "string") return {
|
|
10
|
-
key: entry,
|
|
11
|
-
optional: false
|
|
12
|
-
};
|
|
13
|
-
if (typeof entry === "object" && entry !== null && "__optional" in entry) {
|
|
14
|
-
const ref = entry.ref;
|
|
15
|
-
return {
|
|
16
|
-
key: typeof ref === "string" ? ref : ref.key,
|
|
17
|
-
optional: true
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
return {
|
|
21
|
-
key: entry.key,
|
|
22
|
-
optional: false
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
var Service = class {
|
|
26
|
-
static key;
|
|
27
|
-
static deps;
|
|
28
|
-
ctx;
|
|
29
|
-
/** @internal */
|
|
30
|
-
__setupCleanups = /* @__PURE__ */ new Map();
|
|
31
|
-
evaluate() {}
|
|
32
|
-
setup(key, fn) {
|
|
33
|
-
const existing = this.__setupCleanups.get(key);
|
|
34
|
-
if (existing) try {
|
|
35
|
-
existing("reload");
|
|
36
|
-
} catch (e) {
|
|
37
|
-
console.error(`[hot] setup cleanup "${key}" failed:`, e);
|
|
38
|
-
}
|
|
39
|
-
const cleanup = fn();
|
|
40
|
-
if (cleanup) this.__setupCleanups.set(key, cleanup);
|
|
41
|
-
else this.__setupCleanups.delete(key);
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Run `fn` and return its result. Historically reported a boot-trace span;
|
|
45
|
-
* now a thin wrapper preserved for caller ergonomics inside service
|
|
46
|
-
* `evaluate()` bodies.
|
|
47
|
-
*/
|
|
48
|
-
trace(_name, fn, _meta) {
|
|
49
|
-
return Promise.resolve(fn());
|
|
50
|
-
}
|
|
51
|
-
traceSync(_name, fn, _meta) {
|
|
52
|
-
return fn();
|
|
53
|
-
}
|
|
54
|
-
/** @internal */
|
|
55
|
-
async __cleanupAllSetups(reason = "shutdown") {
|
|
56
|
-
for (const [key, cleanup] of this.__setupCleanups) try {
|
|
57
|
-
await cleanup(reason);
|
|
58
|
-
} catch (e) {
|
|
59
|
-
console.error(`[hot] setup cleanup "${key}" failed:`, e);
|
|
60
|
-
}
|
|
61
|
-
this.__setupCleanups.clear();
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
/**
|
|
65
|
-
* Declare a Service base class with typed deps. The returned class has
|
|
66
|
-
* `static deps = <your map>` already set, and `this.ctx` is auto-typed
|
|
67
|
-
* from the dep classes — no `declare ctx` needed in the subclass.
|
|
68
|
-
*
|
|
69
|
-
* export class WindowService extends serviceWithDeps({
|
|
70
|
-
* baseWindow: BaseWindowService,
|
|
71
|
-
* http: HttpService,
|
|
72
|
-
* }) {
|
|
73
|
-
* static key = "window"
|
|
74
|
-
* evaluate() {
|
|
75
|
-
* this.ctx.baseWindow // BaseWindowService
|
|
76
|
-
* this.ctx.http // HttpService
|
|
77
|
-
* }
|
|
78
|
-
* }
|
|
79
|
-
*
|
|
80
|
-
* `optional(SomeService)` is supported and produces `Instance | undefined`.
|
|
81
|
-
*/
|
|
82
|
-
function serviceWithDeps(deps) {
|
|
83
|
-
class ServiceWithDeps extends Service {
|
|
84
|
-
static deps = deps;
|
|
85
|
-
}
|
|
86
|
-
return ServiceWithDeps;
|
|
87
|
-
}
|
|
88
|
-
const SERVICE_BASE_METHODS = new Set(Object.getOwnPropertyNames(Service.prototype));
|
|
89
|
-
var ServiceRuntime = class {
|
|
90
|
-
definitions = /* @__PURE__ */ new Map();
|
|
91
|
-
dependentsIndex = /* @__PURE__ */ new Map();
|
|
92
|
-
dirtyKeys = /* @__PURE__ */ new Set();
|
|
93
|
-
drainError = null;
|
|
94
|
-
draining = null;
|
|
95
|
-
registrationTokens = /* @__PURE__ */ new Map();
|
|
96
|
-
slots = /* @__PURE__ */ new Map();
|
|
97
|
-
onReconciledCallbacks = [];
|
|
98
|
-
register(ServiceClass, importMeta) {
|
|
99
|
-
const hot = importMeta?.hot ?? null;
|
|
100
|
-
const baseKey = ServiceClass.key;
|
|
101
|
-
if (!baseKey) throw new Error("Service must have a static key property");
|
|
102
|
-
const slotKey = baseKey;
|
|
103
|
-
this.definitions.set(slotKey, ServiceClass);
|
|
104
|
-
const slot = this.slots.get(slotKey);
|
|
105
|
-
if (slot) slot.ServiceClass = ServiceClass;
|
|
106
|
-
else this.slots.set(slotKey, {
|
|
107
|
-
error: null,
|
|
108
|
-
instance: null,
|
|
109
|
-
ServiceClass,
|
|
110
|
-
status: "blocked"
|
|
111
|
-
});
|
|
112
|
-
this.rebuildDependentsIndex();
|
|
113
|
-
hot?.accept();
|
|
114
|
-
const token = Symbol(slotKey);
|
|
115
|
-
this.registrationTokens.set(slotKey, token);
|
|
116
|
-
hot?.prune?.(() => {
|
|
117
|
-
this.unregister(slotKey, token);
|
|
118
|
-
});
|
|
119
|
-
this.scheduleReconcile([slotKey]);
|
|
120
|
-
}
|
|
121
|
-
getAllKeys() {
|
|
122
|
-
return [...this.slots.keys()];
|
|
123
|
-
}
|
|
124
|
-
getSlot(key) {
|
|
125
|
-
return this.slots.get(key);
|
|
126
|
-
}
|
|
127
|
-
async whenIdle() {
|
|
128
|
-
while (this.draining) await this.draining;
|
|
129
|
-
if (this.drainError) {
|
|
130
|
-
const error = this.drainError;
|
|
131
|
-
this.drainError = null;
|
|
132
|
-
throw error;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
async reloadAll() {
|
|
136
|
-
const keys = [...this.slots.keys()];
|
|
137
|
-
if (keys.length === 0) return;
|
|
138
|
-
await this.scheduleReconcile(keys);
|
|
139
|
-
await this.whenIdle();
|
|
140
|
-
}
|
|
141
|
-
async shutdown() {
|
|
142
|
-
try {
|
|
143
|
-
await this.whenIdle();
|
|
144
|
-
} catch (error) {
|
|
145
|
-
console.error("[hot] runtime idle wait failed during shutdown:", error);
|
|
146
|
-
}
|
|
147
|
-
const keys = [...this.slots.keys()].reverse();
|
|
148
|
-
for (const key of keys) await this.teardownService(key, { removeSlot: true });
|
|
149
|
-
this.definitions.clear();
|
|
150
|
-
this.dependentsIndex.clear();
|
|
151
|
-
this.dirtyKeys.clear();
|
|
152
|
-
this.registrationTokens.clear();
|
|
153
|
-
}
|
|
154
|
-
get(ref) {
|
|
155
|
-
const slot = this.slots.get(ref.key);
|
|
156
|
-
if (!slot || slot.status !== "ready" || !slot.instance) throw new Error(`Service "${ref.key}" not ready. Is it registered and evaluated?`);
|
|
157
|
-
return slot.instance;
|
|
158
|
-
}
|
|
159
|
-
buildRouter() {
|
|
160
|
-
const router = {};
|
|
161
|
-
for (const [slotKey, slot] of this.slots) {
|
|
162
|
-
if (slot.status !== "ready" || !slot.instance) continue;
|
|
163
|
-
const proto = Object.getPrototypeOf(slot.instance);
|
|
164
|
-
const methods = {};
|
|
165
|
-
for (const name of Object.getOwnPropertyNames(proto)) {
|
|
166
|
-
if (SERVICE_BASE_METHODS.has(name)) continue;
|
|
167
|
-
if (name.startsWith("_")) continue;
|
|
168
|
-
const desc = Object.getOwnPropertyDescriptor(proto, name);
|
|
169
|
-
if (!desc || typeof desc.value !== "function") continue;
|
|
170
|
-
const instance = slot.instance;
|
|
171
|
-
methods[name] = (...args) => instance[name](...args);
|
|
172
|
-
}
|
|
173
|
-
if (Object.keys(methods).length > 0) router[slotKey] = methods;
|
|
174
|
-
}
|
|
175
|
-
return router;
|
|
176
|
-
}
|
|
177
|
-
onReconciled(cb) {
|
|
178
|
-
this.onReconciledCallbacks.push(cb);
|
|
179
|
-
return () => {
|
|
180
|
-
const idx = this.onReconciledCallbacks.indexOf(cb);
|
|
181
|
-
if (idx >= 0) this.onReconciledCallbacks.splice(idx, 1);
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
resolveDepSlot(depKey) {
|
|
185
|
-
return this.slots.get(depKey);
|
|
186
|
-
}
|
|
187
|
-
injectCtx(instance, ServiceClass) {
|
|
188
|
-
const deps = ServiceClass.deps ?? {};
|
|
189
|
-
const ctx = {};
|
|
190
|
-
for (const [name, entry] of Object.entries(deps)) {
|
|
191
|
-
const { key, optional: isOptional } = resolveDep(entry);
|
|
192
|
-
const slot = this.resolveDepSlot(key);
|
|
193
|
-
if (!slot || slot.status !== "ready" || !slot.instance) {
|
|
194
|
-
if (isOptional) {
|
|
195
|
-
ctx[name] = void 0;
|
|
196
|
-
continue;
|
|
197
|
-
}
|
|
198
|
-
throw new Error(`Dependency "${key}" not ready for "${ServiceClass.key}"`);
|
|
199
|
-
}
|
|
200
|
-
ctx[name] = slot.instance;
|
|
201
|
-
}
|
|
202
|
-
instance.ctx = ctx;
|
|
203
|
-
}
|
|
204
|
-
rebuildDependentsIndex() {
|
|
205
|
-
const next = /* @__PURE__ */ new Map();
|
|
206
|
-
for (const [slotKey, ServiceClass] of this.definitions) {
|
|
207
|
-
const deps = ServiceClass.deps ?? {};
|
|
208
|
-
for (const entry of Object.values(deps)) {
|
|
209
|
-
const { key: depKey } = resolveDep(entry);
|
|
210
|
-
const dependents = next.get(depKey) ?? /* @__PURE__ */ new Set();
|
|
211
|
-
dependents.add(slotKey);
|
|
212
|
-
next.set(depKey, dependents);
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
this.dependentsIndex = next;
|
|
216
|
-
}
|
|
217
|
-
getAffectedKeys(changedKeys) {
|
|
218
|
-
const affected = /* @__PURE__ */ new Set();
|
|
219
|
-
const visit = (key) => {
|
|
220
|
-
if (affected.has(key)) return;
|
|
221
|
-
affected.add(key);
|
|
222
|
-
for (const dependent of this.dependentsIndex.get(key) ?? []) visit(dependent);
|
|
223
|
-
};
|
|
224
|
-
for (const key of changedKeys) visit(key);
|
|
225
|
-
return [...affected].filter((key) => this.definitions.has(key));
|
|
226
|
-
}
|
|
227
|
-
listMissingDeps(ServiceClass) {
|
|
228
|
-
const deps = ServiceClass.deps ?? {};
|
|
229
|
-
const missing = [];
|
|
230
|
-
for (const entry of Object.values(deps)) {
|
|
231
|
-
const { key, optional: isOptional } = resolveDep(entry);
|
|
232
|
-
if (isOptional) continue;
|
|
233
|
-
const slot = this.resolveDepSlot(key);
|
|
234
|
-
if (!slot || slot.status !== "ready" || !slot.instance) missing.push(key);
|
|
235
|
-
}
|
|
236
|
-
return missing;
|
|
237
|
-
}
|
|
238
|
-
ensureSlot(key, ServiceClass) {
|
|
239
|
-
const existing = this.slots.get(key);
|
|
240
|
-
if (existing) return existing;
|
|
241
|
-
const slot = {
|
|
242
|
-
error: null,
|
|
243
|
-
instance: null,
|
|
244
|
-
ServiceClass,
|
|
245
|
-
status: "blocked"
|
|
246
|
-
};
|
|
247
|
-
this.slots.set(key, slot);
|
|
248
|
-
return slot;
|
|
249
|
-
}
|
|
250
|
-
async teardownService(key, options = {}) {
|
|
251
|
-
const slot = this.slots.get(key);
|
|
252
|
-
if (!slot) return;
|
|
253
|
-
const instance = slot.instance;
|
|
254
|
-
slot.instance = null;
|
|
255
|
-
slot.status = "blocked";
|
|
256
|
-
slot.error = null;
|
|
257
|
-
if (instance) await instance.__cleanupAllSetups(options.reason ?? "shutdown");
|
|
258
|
-
if (options.removeSlot) this.slots.delete(key);
|
|
259
|
-
}
|
|
260
|
-
async unregister(key, token) {
|
|
261
|
-
if (this.registrationTokens.get(key) !== token) return;
|
|
262
|
-
this.registrationTokens.delete(key);
|
|
263
|
-
this.definitions.delete(key);
|
|
264
|
-
await this.teardownService(key, { removeSlot: true });
|
|
265
|
-
this.rebuildDependentsIndex();
|
|
266
|
-
await this.scheduleReconcile([key]);
|
|
267
|
-
}
|
|
268
|
-
async scheduleReconcile(keys) {
|
|
269
|
-
for (const key of keys) this.dirtyKeys.add(key);
|
|
270
|
-
if (this.draining) return this.draining;
|
|
271
|
-
this.draining = (async () => {
|
|
272
|
-
try {
|
|
273
|
-
while (this.dirtyKeys.size > 0) {
|
|
274
|
-
const batch = [...this.dirtyKeys];
|
|
275
|
-
this.dirtyKeys.clear();
|
|
276
|
-
await this.reconcileBatch(batch);
|
|
277
|
-
}
|
|
278
|
-
} catch (error) {
|
|
279
|
-
this.drainError = error;
|
|
280
|
-
console.error("[hot] runtime reconcile failed:", error);
|
|
281
|
-
} finally {
|
|
282
|
-
this.draining = null;
|
|
283
|
-
if (this.dirtyKeys.size > 0) this.scheduleReconcile([]);
|
|
284
|
-
}
|
|
285
|
-
})();
|
|
286
|
-
return this.draining;
|
|
287
|
-
}
|
|
288
|
-
async reconcileBatch(changedKeys) {
|
|
289
|
-
const affectedKeys = this.getAffectedKeys(changedKeys);
|
|
290
|
-
if (affectedKeys.length === 0) return;
|
|
291
|
-
const affected = /* @__PURE__ */ new Map();
|
|
292
|
-
for (const key of affectedKeys) {
|
|
293
|
-
const ServiceClass = this.definitions.get(key);
|
|
294
|
-
if (ServiceClass) affected.set(key, ServiceClass);
|
|
295
|
-
}
|
|
296
|
-
const levels = this.topologicalLevels(affected);
|
|
297
|
-
for (const level of [...levels].reverse()) await Promise.all(level.map(async (key) => {
|
|
298
|
-
const slot = this.slots.get(key);
|
|
299
|
-
if (slot?.instance) await slot.instance.__cleanupAllSetups("reload");
|
|
300
|
-
}));
|
|
301
|
-
for (const level of levels) await Promise.all(level.map((key) => this.reconcileKey(key)));
|
|
302
|
-
if (affectedKeys.length > 0) for (const cb of this.onReconciledCallbacks) try {
|
|
303
|
-
cb(affectedKeys);
|
|
304
|
-
} catch (e) {
|
|
305
|
-
console.error("[hot] onReconciled callback failed:", e);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
async reconcileKey(key) {
|
|
309
|
-
const ServiceClass = this.definitions.get(key);
|
|
310
|
-
if (!ServiceClass) return;
|
|
311
|
-
const slot = this.ensureSlot(key, ServiceClass);
|
|
312
|
-
slot.ServiceClass = ServiceClass;
|
|
313
|
-
const missingDeps = this.listMissingDeps(ServiceClass);
|
|
314
|
-
if (missingDeps.length > 0) {
|
|
315
|
-
const shouldLog = slot.instance !== null || slot.status !== "blocked";
|
|
316
|
-
await this.teardownService(key, { reason: "reload" });
|
|
317
|
-
if (shouldLog) console.log(`[hot] ${key} waiting on: ${missingDeps.join(", ")}`);
|
|
318
|
-
return;
|
|
319
|
-
}
|
|
320
|
-
let instance = slot.instance;
|
|
321
|
-
if (!instance) {
|
|
322
|
-
instance = new ServiceClass();
|
|
323
|
-
slot.instance = instance;
|
|
324
|
-
} else Object.setPrototypeOf(instance, ServiceClass.prototype);
|
|
325
|
-
slot.status = "evaluating";
|
|
326
|
-
slot.error = null;
|
|
327
|
-
try {
|
|
328
|
-
await instance.__cleanupAllSetups("reload");
|
|
329
|
-
this.injectCtx(instance, ServiceClass);
|
|
330
|
-
await instance.evaluate();
|
|
331
|
-
slot.status = "ready";
|
|
332
|
-
} catch (e) {
|
|
333
|
-
slot.status = "failed";
|
|
334
|
-
slot.error = e;
|
|
335
|
-
console.error(`[hot] ${key} failed to evaluate:`, e);
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
topologicalLevels(services) {
|
|
339
|
-
const keys = new Set(services.keys());
|
|
340
|
-
const inDegree = /* @__PURE__ */ new Map();
|
|
341
|
-
const dependents = /* @__PURE__ */ new Map();
|
|
342
|
-
for (const key of keys) {
|
|
343
|
-
inDegree.set(key, 0);
|
|
344
|
-
dependents.set(key, []);
|
|
345
|
-
}
|
|
346
|
-
for (const [slotKey, ServiceClass] of services) {
|
|
347
|
-
const deps = ServiceClass.deps ?? {};
|
|
348
|
-
let degree = 0;
|
|
349
|
-
for (const entry of Object.values(deps)) {
|
|
350
|
-
const { key: depKey, optional: isOptional } = resolveDep(entry);
|
|
351
|
-
if (keys.has(depKey)) {
|
|
352
|
-
degree++;
|
|
353
|
-
dependents.get(depKey).push(slotKey);
|
|
354
|
-
} else if (isOptional) continue;
|
|
355
|
-
}
|
|
356
|
-
inDegree.set(slotKey, degree);
|
|
357
|
-
}
|
|
358
|
-
const levels = [];
|
|
359
|
-
let queue = [...keys].filter((k) => inDegree.get(k) === 0);
|
|
360
|
-
while (queue.length > 0) {
|
|
361
|
-
levels.push(queue);
|
|
362
|
-
const next = [];
|
|
363
|
-
for (const key of queue) for (const dep of dependents.get(key)) {
|
|
364
|
-
const d = inDegree.get(dep) - 1;
|
|
365
|
-
inDegree.set(dep, d);
|
|
366
|
-
if (d === 0) next.push(dep);
|
|
367
|
-
}
|
|
368
|
-
queue = next;
|
|
369
|
-
}
|
|
370
|
-
const resolved = levels.flat();
|
|
371
|
-
if (resolved.length !== keys.size) {
|
|
372
|
-
const missing = [...keys].filter((k) => !resolved.includes(k));
|
|
373
|
-
throw new Error(`Circular dependency detected involving: ${missing.join(", ")}`);
|
|
374
|
-
}
|
|
375
|
-
return levels;
|
|
376
|
-
}
|
|
377
|
-
};
|
|
378
|
-
/**
|
|
379
|
-
* fixme: i don't think these commments make sense
|
|
380
|
-
*/
|
|
381
|
-
/**
|
|
382
|
-
* Devtools-only handles, attached to the global so they aren't part of the
|
|
383
|
-
* public `ServiceRuntime` autocomplete surface. Same shape React DevTools
|
|
384
|
-
* uses (`__REACT_DEVTOOLS_GLOBAL_HOOK__`): user code reading
|
|
385
|
-
* `runtime.<...>` never lands on these methods; you only find them if you
|
|
386
|
-
* specifically type `globalThis.__zenbu_dev__`. Kept here (next to the
|
|
387
|
-
* runtime that owns the state) because the hook reaches into private
|
|
388
|
-
* implementation details — `scheduleReconcile` stays `private` on the
|
|
389
|
-
* class; the cast lives inside the encapsulation boundary.
|
|
390
|
-
*/
|
|
391
|
-
function installDevHook(rt) {
|
|
392
|
-
const internals = rt;
|
|
393
|
-
globalThis.__zenbu_dev__ = { reloadService: async (key) => {
|
|
394
|
-
if (!internals.definitions.has(key)) throw new Error(`No service registered for key "${key}"`);
|
|
395
|
-
await internals.scheduleReconcile([key]);
|
|
396
|
-
await rt.whenIdle();
|
|
397
|
-
} };
|
|
398
|
-
}
|
|
399
|
-
const runtime = (() => {
|
|
400
|
-
const existing = globalThis.__zenbu_service_runtime__;
|
|
401
|
-
if (existing) {
|
|
402
|
-
Object.setPrototypeOf(existing, ServiceRuntime.prototype);
|
|
403
|
-
installDevHook(existing);
|
|
404
|
-
return existing;
|
|
405
|
-
}
|
|
406
|
-
const fresh = new ServiceRuntime();
|
|
407
|
-
globalThis.__zenbu_service_runtime__ = fresh;
|
|
408
|
-
installDevHook(fresh);
|
|
409
|
-
return fresh;
|
|
410
|
-
})();
|
|
411
|
-
function getPluginRegistry() {
|
|
412
|
-
const slot = globalThis;
|
|
413
|
-
if (!slot.__zenbu_plugin_registry__) slot.__zenbu_plugin_registry__ = {
|
|
414
|
-
plugins: /* @__PURE__ */ new Map(),
|
|
415
|
-
appEntrypoint: null
|
|
416
|
-
};
|
|
417
|
-
return slot.__zenbu_plugin_registry__;
|
|
418
|
-
}
|
|
419
|
-
/**
|
|
420
|
-
* Register a plugin's resolved manifest. Idempotent — replaces any existing
|
|
421
|
-
* entry for the same `name`. Called by the loader-emitted barrel; user code
|
|
422
|
-
* normally does not call this directly.
|
|
423
|
-
*/
|
|
424
|
-
function registerPlugin(record) {
|
|
425
|
-
getPluginRegistry().plugins.set(record.name, record);
|
|
426
|
-
}
|
|
427
|
-
/**
|
|
428
|
-
* Drop a plugin from the registry. Used when the loader regenerates the
|
|
429
|
-
* barrel and needs to clear stale entries.
|
|
430
|
-
*/
|
|
431
|
-
function unregisterPlugin(name) {
|
|
432
|
-
getPluginRegistry().plugins.delete(name);
|
|
433
|
-
}
|
|
434
|
-
/**
|
|
435
|
-
* Replace the entire plugin set in one shot. The loader uses this on every
|
|
436
|
-
* barrel regeneration so removed plugins disappear cleanly.
|
|
437
|
-
*/
|
|
438
|
-
function replacePlugins(records) {
|
|
439
|
-
const reg = getPluginRegistry();
|
|
440
|
-
reg.plugins.clear();
|
|
441
|
-
for (const record of records) reg.plugins.set(record.name, record);
|
|
442
|
-
}
|
|
443
|
-
function getPlugins() {
|
|
444
|
-
return [...getPluginRegistry().plugins.values()];
|
|
445
|
-
}
|
|
446
|
-
function getPlugin(name) {
|
|
447
|
-
return getPluginRegistry().plugins.get(name);
|
|
448
|
-
}
|
|
449
|
-
/**
|
|
450
|
-
* Set the boot-window HTML path. Called once by the loader-emitted barrel.
|
|
451
|
-
* Consumers (`view-registry`, `vite-plugins`) ask for it via
|
|
452
|
-
* `getAppEntrypoint()`.
|
|
453
|
-
*/
|
|
454
|
-
function registerAppEntrypoint(htmlPath) {
|
|
455
|
-
getPluginRegistry().appEntrypoint = htmlPath;
|
|
456
|
-
}
|
|
457
|
-
function getAppEntrypoint() {
|
|
458
|
-
return getPluginRegistry().appEntrypoint;
|
|
459
|
-
}
|
|
460
|
-
//#endregion
|
|
461
|
-
export { getPlugins as a, registerPlugin as c, serviceWithDeps as d, unregisterPlugin as f, getPlugin as i, replacePlugins as l, ServiceRuntime as n, optional as o, getAppEntrypoint as r, registerAppEntrypoint as s, Service as t, runtime as u };
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
//#region src/runtime.d.ts
|
|
2
|
-
type CleanupReason = "reload" | "shutdown";
|
|
3
|
-
type SetupCleanup = ((reason: CleanupReason) => void | Promise<void>) | void;
|
|
4
|
-
type SetupFn = () => SetupCleanup;
|
|
5
|
-
interface ServiceSlot {
|
|
6
|
-
error: unknown | null;
|
|
7
|
-
instance: Service | null;
|
|
8
|
-
ServiceClass: typeof Service;
|
|
9
|
-
status: "blocked" | "evaluating" | "ready" | "failed";
|
|
10
|
-
}
|
|
11
|
-
type AnyServiceClass = abstract new (...args: any[]) => Service;
|
|
12
|
-
type DepRef = AnyServiceClass | string;
|
|
13
|
-
type OptionalDep<R extends DepRef = DepRef> = {
|
|
14
|
-
__optional: true;
|
|
15
|
-
ref: R;
|
|
16
|
-
};
|
|
17
|
-
type DepEntry = DepRef | OptionalDep;
|
|
18
|
-
type DepInstance<D> = D extends OptionalDep<infer R> ? R extends AnyServiceClass ? InstanceType<R> | undefined : unknown : D extends AnyServiceClass ? InstanceType<D> : unknown;
|
|
19
|
-
type ResolveCtx<TDeps> = { [K in keyof TDeps]: DepInstance<TDeps[K]> };
|
|
20
|
-
declare function optional<R extends DepRef>(ref: R): OptionalDep<R>;
|
|
21
|
-
declare abstract class Service {
|
|
22
|
-
static key: string;
|
|
23
|
-
static deps: Record<string, DepEntry>;
|
|
24
|
-
ctx: any;
|
|
25
|
-
/** @internal */
|
|
26
|
-
__setupCleanups: Map<string, (reason: CleanupReason) => void | Promise<void>>;
|
|
27
|
-
evaluate(): void | Promise<void>;
|
|
28
|
-
setup(key: string, fn: SetupFn): void;
|
|
29
|
-
/**
|
|
30
|
-
* Run `fn` and return its result. Historically reported a boot-trace span;
|
|
31
|
-
* now a thin wrapper preserved for caller ergonomics inside service
|
|
32
|
-
* `evaluate()` bodies.
|
|
33
|
-
*/
|
|
34
|
-
trace<T>(_name: string, fn: () => T | Promise<T>, _meta?: Record<string, unknown>): Promise<T>;
|
|
35
|
-
traceSync<T>(_name: string, fn: () => T, _meta?: Record<string, unknown>): T;
|
|
36
|
-
/** @internal */
|
|
37
|
-
__cleanupAllSetups(reason?: CleanupReason): Promise<void>;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Declare a Service base class with typed deps. The returned class has
|
|
41
|
-
* `static deps = <your map>` already set, and `this.ctx` is auto-typed
|
|
42
|
-
* from the dep classes — no `declare ctx` needed in the subclass.
|
|
43
|
-
*
|
|
44
|
-
* export class WindowService extends serviceWithDeps({
|
|
45
|
-
* baseWindow: BaseWindowService,
|
|
46
|
-
* http: HttpService,
|
|
47
|
-
* }) {
|
|
48
|
-
* static key = "window"
|
|
49
|
-
* evaluate() {
|
|
50
|
-
* this.ctx.baseWindow // BaseWindowService
|
|
51
|
-
* this.ctx.http // HttpService
|
|
52
|
-
* }
|
|
53
|
-
* }
|
|
54
|
-
*
|
|
55
|
-
* `optional(SomeService)` is supported and produces `Instance | undefined`.
|
|
56
|
-
*/
|
|
57
|
-
declare function serviceWithDeps<TDeps extends Record<string, DepEntry>>(deps: TDeps): (abstract new () => {
|
|
58
|
-
ctx: ResolveCtx<TDeps>; /** @internal */
|
|
59
|
-
__setupCleanups: Map<string, (reason: CleanupReason) => void | Promise<void>>;
|
|
60
|
-
evaluate(): void | Promise<void>;
|
|
61
|
-
setup(key: string, fn: SetupFn): void;
|
|
62
|
-
/**
|
|
63
|
-
* Run `fn` and return its result. Historically reported a boot-trace span;
|
|
64
|
-
* now a thin wrapper preserved for caller ergonomics inside service
|
|
65
|
-
* `evaluate()` bodies.
|
|
66
|
-
*/
|
|
67
|
-
trace<T>(_name: string, fn: () => T | Promise<T>, _meta?: Record<string, unknown>): Promise<T>;
|
|
68
|
-
traceSync<T>(_name: string, fn: () => T, _meta?: Record<string, unknown>): T; /** @internal */
|
|
69
|
-
__cleanupAllSetups(reason?: CleanupReason): Promise<void>;
|
|
70
|
-
}) & {
|
|
71
|
-
deps: Record<string, DepEntry>;
|
|
72
|
-
key: string;
|
|
73
|
-
};
|
|
74
|
-
declare class ServiceRuntime {
|
|
75
|
-
private definitions;
|
|
76
|
-
private dependentsIndex;
|
|
77
|
-
private dirtyKeys;
|
|
78
|
-
private drainError;
|
|
79
|
-
private draining;
|
|
80
|
-
private registrationTokens;
|
|
81
|
-
private slots;
|
|
82
|
-
private onReconciledCallbacks;
|
|
83
|
-
register(ServiceClass: typeof Service, importMeta?: ImportMeta | null): void;
|
|
84
|
-
getAllKeys(): string[];
|
|
85
|
-
getSlot(key: string): ServiceSlot | undefined;
|
|
86
|
-
whenIdle(): Promise<void>;
|
|
87
|
-
reloadAll(): Promise<void>;
|
|
88
|
-
shutdown(): Promise<void>;
|
|
89
|
-
get<T extends Service>(ref: {
|
|
90
|
-
key: string;
|
|
91
|
-
}): T;
|
|
92
|
-
buildRouter(): Record<string, Record<string, (...args: any[]) => any>>;
|
|
93
|
-
onReconciled(cb: (changedKeys: string[]) => void): () => void;
|
|
94
|
-
private resolveDepSlot;
|
|
95
|
-
private injectCtx;
|
|
96
|
-
private rebuildDependentsIndex;
|
|
97
|
-
private getAffectedKeys;
|
|
98
|
-
private listMissingDeps;
|
|
99
|
-
private ensureSlot;
|
|
100
|
-
private teardownService;
|
|
101
|
-
private unregister;
|
|
102
|
-
private scheduleReconcile;
|
|
103
|
-
private reconcileBatch;
|
|
104
|
-
private reconcileKey;
|
|
105
|
-
private topologicalLevels;
|
|
106
|
-
}
|
|
107
|
-
declare const runtime: ServiceRuntime;
|
|
108
|
-
/**
|
|
109
|
-
* A plugin manifest after the loader has resolved every relative path to
|
|
110
|
-
* absolute. Mirrors `ResolvedPlugin` in `cli/lib/build-config.ts` but is
|
|
111
|
-
* declared inline here to avoid runtime.ts importing CLI code.
|
|
112
|
-
*/
|
|
113
|
-
interface PluginRecord {
|
|
114
|
-
name: string;
|
|
115
|
-
dir: string;
|
|
116
|
-
services: string[];
|
|
117
|
-
schemaPath?: string;
|
|
118
|
-
migrationsPath?: string;
|
|
119
|
-
preloadPath?: string;
|
|
120
|
-
eventsPath?: string;
|
|
121
|
-
icons?: Record<string, string>;
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* Register a plugin's resolved manifest. Idempotent — replaces any existing
|
|
125
|
-
* entry for the same `name`. Called by the loader-emitted barrel; user code
|
|
126
|
-
* normally does not call this directly.
|
|
127
|
-
*/
|
|
128
|
-
declare function registerPlugin(record: PluginRecord): void;
|
|
129
|
-
/**
|
|
130
|
-
* Drop a plugin from the registry. Used when the loader regenerates the
|
|
131
|
-
* barrel and needs to clear stale entries.
|
|
132
|
-
*/
|
|
133
|
-
declare function unregisterPlugin(name: string): void;
|
|
134
|
-
/**
|
|
135
|
-
* Replace the entire plugin set in one shot. The loader uses this on every
|
|
136
|
-
* barrel regeneration so removed plugins disappear cleanly.
|
|
137
|
-
*/
|
|
138
|
-
declare function replacePlugins(records: PluginRecord[]): void;
|
|
139
|
-
declare function getPlugins(): PluginRecord[];
|
|
140
|
-
declare function getPlugin(name: string): PluginRecord | undefined;
|
|
141
|
-
/**
|
|
142
|
-
* Set the boot-window HTML path. Called once by the loader-emitted barrel.
|
|
143
|
-
* Consumers (`view-registry`, `vite-plugins`) ask for it via
|
|
144
|
-
* `getAppEntrypoint()`.
|
|
145
|
-
*/
|
|
146
|
-
declare function registerAppEntrypoint(htmlPath: string): void;
|
|
147
|
-
declare function getAppEntrypoint(): string | null;
|
|
148
|
-
//#endregion
|
|
149
|
-
export { getAppEntrypoint as a, optional as c, replacePlugins as d, runtime as f, ServiceRuntime as i, registerAppEntrypoint as l, unregisterPlugin as m, PluginRecord as n, getPlugin as o, serviceWithDeps as p, Service as r, getPlugins as s, CleanupReason as t, registerPlugin as u };
|
package/dist/schema-dGK6qkfR.mjs
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { a as f, i as createSchema } from "./schema-CIg4GzHQ.mjs";
|
|
2
|
-
import zod from "zod";
|
|
3
|
-
//#region src/schema.ts
|
|
4
|
-
const viewRegistryEntrySchema = zod.object({
|
|
5
|
-
scope: zod.string(),
|
|
6
|
-
url: zod.string(),
|
|
7
|
-
port: zod.number(),
|
|
8
|
-
icon: zod.string().optional(),
|
|
9
|
-
meta: zod.object({
|
|
10
|
-
kind: zod.string().optional(),
|
|
11
|
-
sidebar: zod.boolean().optional(),
|
|
12
|
-
bottomPanel: zod.boolean().optional(),
|
|
13
|
-
label: zod.string().optional()
|
|
14
|
-
}).optional()
|
|
15
|
-
});
|
|
16
|
-
const windowBoundsSchema = zod.object({
|
|
17
|
-
x: zod.number(),
|
|
18
|
-
y: zod.number(),
|
|
19
|
-
width: zod.number(),
|
|
20
|
-
height: zod.number()
|
|
21
|
-
});
|
|
22
|
-
const windowPrefsSchema = zod.object({ lastKnownBounds: windowBoundsSchema.optional() });
|
|
23
|
-
const schema = createSchema({
|
|
24
|
-
lastKnownViewRegistry: f.array(viewRegistryEntrySchema).default([]),
|
|
25
|
-
windowPrefs: f.record(zod.string(), windowPrefsSchema).default({})
|
|
26
|
-
});
|
|
27
|
-
//#endregion
|
|
28
|
-
export { schema as t };
|
package/dist/server-CgzQOPSW.mjs
DELETED