@zenbujs/core 0.0.5 → 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-QYB2qEd_.mjs → advice-config-DXSIo0sg.mjs} +40 -39
- package/dist/advice.d.mts +8 -8
- package/dist/advice.mjs +2 -2
- package/dist/{base-window-BbFRRhKP.mjs → base-window-BxBZ2md_.mjs} +51 -7
- package/dist/{transforms-CuTODvDx.d.mts → build-config-Dzg2frpk.d.mts} +98 -28
- package/dist/build-config-pWdmLnrk.mjs +53 -0
- package/dist/{build-electron-CNJ0dLND.mjs → build-electron-Dsbb1EMl.mjs} +308 -120
- package/dist/{build-source-C2puqEVr.mjs → build-source-d1J3shV8.mjs} +62 -27
- 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 +1 -1
- package/dist/{cli-C3R1LBMY.mjs → cli-kL6mPgBE.mjs} +2 -2
- package/dist/config.d.mts +3 -3
- package/dist/config.mjs +2 -3
- package/dist/{db-xjvahRFJ.mjs → db-Bc292RYo.mjs} +2 -2
- package/dist/db.d.mts +1 -1
- package/dist/dev-B2emj0HZ.mjs +301 -0
- package/dist/env-bootstrap.d.mts +1 -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 +2 -2
- package/dist/installing-preload.cjs +60 -0
- package/dist/launcher.mjs +2615 -122
- package/dist/{link-c0_aLWQ3.mjs → link-glX89NV5.mjs} +215 -89
- package/dist/{load-config-xMf2wxH8.mjs → load-config-C4Oe2qZO.mjs} +5 -1
- package/dist/loaders/zenbu.mjs +102 -0
- package/dist/node-loader.mjs +1 -1
- package/dist/{publish-source-Dill72NS.mjs → publish-source-Dq2c0iOw.mjs} +2 -2
- package/dist/react.d.mts +55 -6
- package/dist/react.mjs +116 -5
- 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-DzEO8kJr.mjs → reloader-B22UiNA2.mjs} +2 -4
- package/dist/{renderer-host-Cau9JK0v.mjs → renderer-host-DD16MXhI.mjs} +152 -43
- package/dist/{rpc-JfGv-Wuw.mjs → rpc-C4_NQmpT.mjs} +5 -4
- package/dist/{runtime-pCeVzj--.d.mts → runtime-BQWntcOb.d.mts} +85 -48
- package/dist/runtime.d.mts +2 -2
- package/dist/runtime.mjs +139 -83
- package/dist/{schema-Dl85YjXW.d.mts → schema-CjrMVk36.d.mts} +3 -3
- package/dist/schema.d.mts +1 -1
- package/dist/schema.mjs +1 -1
- package/dist/{server-y3PPbh3l.mjs → server-CZLMF8Dj.mjs} +1 -3
- package/dist/services/default.d.mts +3 -3
- package/dist/services/default.mjs +14 -13
- package/dist/services/index.d.mts +2 -280
- package/dist/services/index.mjs +8 -7
- package/dist/setup-gate.d.mts +1 -1
- package/dist/setup-gate.mjs +117 -24
- package/dist/{transform-CmFYPmt8.mjs → transform-BzrwkEdf.mjs} +22 -916
- package/dist/updater-DCkz9M1c.mjs +1008 -0
- package/dist/{vite-plugins-Do7liKi_.mjs → vite-plugins-tt6KAtyE.mjs} +26 -25
- package/dist/vite.d.mts +3 -3
- package/dist/vite.mjs +1 -1
- package/dist/{window-o2NGUsIb.mjs → window-YFKvAM0l.mjs} +30 -16
- package/package.json +15 -2
- package/dist/build-config-C3a-o3_B.mjs +0 -23
- package/dist/dev-Dazhu66l.mjs +0 -85
- package/dist/registry-eX6e2oql.d.mts +0 -61
- package/dist/transforms-htxfTwsY.mjs +0 -47
- /package/dist/{config-DXRCDUxG.mjs → config-BK78JDRI.mjs} +0 -0
- /package/dist/{env-bootstrap-DW2hVhSO.d.mts → env-bootstrap-rTs8KR3-.d.mts} +0 -0
- /package/dist/{index-M_lSNBrq.d.mts → index-DeDxePAa.d.mts} +0 -0
- /package/dist/{mirror-sync-PDzxhf1w.mjs → mirror-sync-pYU6f3-c.mjs} +0 -0
- /package/dist/{monorepo-3avKJwzJ.mjs → monorepo-Dct-kkbQ.mjs} +0 -0
- /package/dist/{node-_8xShqxr.mjs → node-BhfLKYCi.mjs} +0 -0
- /package/dist/{setup-gate-Dcy8gGPJ.d.mts → setup-gate-BQq0QgZH.d.mts} +0 -0
|
@@ -5,22 +5,74 @@ type SetupFn = () => SetupCleanup;
|
|
|
5
5
|
interface ServiceSlot {
|
|
6
6
|
error: unknown | null;
|
|
7
7
|
instance: Service | null;
|
|
8
|
-
ServiceClass:
|
|
8
|
+
ServiceClass: ServiceConstructor;
|
|
9
9
|
status: "blocked" | "evaluating" | "ready" | "failed";
|
|
10
10
|
}
|
|
11
|
-
type AnyServiceClass = abstract new (...args: any[]) => Service
|
|
12
|
-
|
|
13
|
-
type OptionalDep<R extends DepRef = DepRef> = {
|
|
14
|
-
__optional: true;
|
|
15
|
-
ref: R;
|
|
11
|
+
type AnyServiceClass = (abstract new (...args: any[]) => Service) & {
|
|
12
|
+
key: string;
|
|
16
13
|
};
|
|
17
|
-
type DepEntry =
|
|
18
|
-
type DepInstance<D> = D extends
|
|
14
|
+
type DepEntry = AnyServiceClass | string;
|
|
15
|
+
type DepInstance<D> = D extends AnyServiceClass ? InstanceType<D> : unknown;
|
|
19
16
|
type ResolveCtx<TDeps> = { [K in keyof TDeps]: DepInstance<TDeps[K]> };
|
|
20
|
-
|
|
17
|
+
/**
|
|
18
|
+
* A concrete service class registered with the runtime. Always has a
|
|
19
|
+
* `static key` (set by `Service.create`) and an optional `static deps`
|
|
20
|
+
* map. Used as the parameter type of `runtime.register`.
|
|
21
|
+
*/
|
|
22
|
+
type ServiceConstructor = (new (...args: any[]) => Service) & {
|
|
23
|
+
key: string;
|
|
24
|
+
deps?: Record<string, DepEntry>;
|
|
25
|
+
};
|
|
21
26
|
declare abstract class Service {
|
|
22
|
-
static key: string;
|
|
23
27
|
static deps: Record<string, DepEntry>;
|
|
28
|
+
/**
|
|
29
|
+
* Define a Service base class. The returned abstract class has
|
|
30
|
+
* `static key`, `static deps`, and a typed `this.ctx` already set up;
|
|
31
|
+
* extend it and add your `evaluate()` body.
|
|
32
|
+
*
|
|
33
|
+
* export class WindowService extends Service.create({
|
|
34
|
+
* key: "window",
|
|
35
|
+
* deps: {
|
|
36
|
+
* baseWindow: BaseWindowService,
|
|
37
|
+
* http: HttpService,
|
|
38
|
+
* },
|
|
39
|
+
* }) {
|
|
40
|
+
* evaluate() {
|
|
41
|
+
* this.ctx.baseWindow // BaseWindowService
|
|
42
|
+
* this.ctx.http // HttpService
|
|
43
|
+
* }
|
|
44
|
+
* }
|
|
45
|
+
*
|
|
46
|
+
* `key` is a required field on the config object, so TypeScript errors
|
|
47
|
+
* if you forget it. `deps` is optional (defaults to no deps).
|
|
48
|
+
*
|
|
49
|
+
* For dynamic / optional access to another service, use
|
|
50
|
+
* `runtime.get(SomeService, cb)` instead of declaring it in `deps`.
|
|
51
|
+
*/
|
|
52
|
+
static create<TKey extends string, TDeps extends Record<string, DepEntry> = {}>(config: {
|
|
53
|
+
key: TKey;
|
|
54
|
+
deps?: TDeps;
|
|
55
|
+
}): (abstract new () => {
|
|
56
|
+
ctx: ResolveCtx<TDeps>; /** @internal */
|
|
57
|
+
__setupCleanups: Map<string, (reason: CleanupReason) => void | Promise<void>>;
|
|
58
|
+
evaluate(): void | Promise<void>;
|
|
59
|
+
setup(key: string, fn: SetupFn): void;
|
|
60
|
+
/**
|
|
61
|
+
* Run `fn` and return its result. Historically reported a boot-trace span;
|
|
62
|
+
* now a thin wrapper preserved for caller ergonomics inside service
|
|
63
|
+
* `evaluate()` bodies.
|
|
64
|
+
*/
|
|
65
|
+
trace<T>(_name: string, fn: () => T | Promise<T>, _meta?: Record<string, unknown>): Promise<T>;
|
|
66
|
+
traceSync<T>(_name: string, fn: () => T, _meta?: Record<string, unknown>): T; /** @internal */
|
|
67
|
+
__cleanupAllSetups(reason?: CleanupReason): Promise<void>;
|
|
68
|
+
}) & {
|
|
69
|
+
key: TKey;
|
|
70
|
+
deps: Record<string, DepEntry>;
|
|
71
|
+
create<TKey extends string, TDeps extends Record<string, DepEntry> = {}>(config: {
|
|
72
|
+
key: TKey;
|
|
73
|
+
deps?: TDeps;
|
|
74
|
+
}): /*elided*/any;
|
|
75
|
+
};
|
|
24
76
|
ctx: any;
|
|
25
77
|
/** @internal */
|
|
26
78
|
__setupCleanups: Map<string, (reason: CleanupReason) => void | Promise<void>>;
|
|
@@ -36,41 +88,6 @@ declare abstract class Service {
|
|
|
36
88
|
/** @internal */
|
|
37
89
|
__cleanupAllSetups(reason?: CleanupReason): Promise<void>;
|
|
38
90
|
}
|
|
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
91
|
declare class ServiceRuntime {
|
|
75
92
|
private definitions;
|
|
76
93
|
private dependentsIndex;
|
|
@@ -80,15 +97,35 @@ declare class ServiceRuntime {
|
|
|
80
97
|
private registrationTokens;
|
|
81
98
|
private slots;
|
|
82
99
|
private onReconciledCallbacks;
|
|
83
|
-
|
|
100
|
+
private subscribers;
|
|
101
|
+
register(ServiceClass: ServiceConstructor, importMeta?: ImportMeta | null): void;
|
|
84
102
|
getAllKeys(): string[];
|
|
85
103
|
getSlot(key: string): ServiceSlot | undefined;
|
|
86
104
|
whenIdle(): Promise<void>;
|
|
87
105
|
reloadAll(): Promise<void>;
|
|
106
|
+
/**
|
|
107
|
+
* Reload a single service by key. No-op if the key is not registered.
|
|
108
|
+
* Used by infrastructure that watches resources outside dynohot's
|
|
109
|
+
* import-graph (e.g. the migrations directory watcher in DbService) and
|
|
110
|
+
* needs to nudge a specific service to re-evaluate without leaning on
|
|
111
|
+
* the devtools-only `__zenbu_dev__.reloadService` hook.
|
|
112
|
+
*/
|
|
113
|
+
reload(key: string): Promise<void>;
|
|
88
114
|
shutdown(): Promise<void>;
|
|
115
|
+
/**
|
|
116
|
+
* Subscribe to a service. Behavior-subject style: the callback fires
|
|
117
|
+
* synchronously once with the current value (the live instance if ready,
|
|
118
|
+
* `undefined` otherwise), then again on every reconcile of that service —
|
|
119
|
+
* so you see the new instance after each HMR. Pass through `undefined`
|
|
120
|
+
* when the service tears down or unregisters.
|
|
121
|
+
*
|
|
122
|
+
* Returns an unsubscribe function. Always call it from a `setup()` cleanup
|
|
123
|
+
* (or wherever you'd otherwise leak callbacks across reloads).
|
|
124
|
+
*/
|
|
89
125
|
get<T extends Service>(ref: {
|
|
90
126
|
key: string;
|
|
91
|
-
}):
|
|
127
|
+
}, cb: (instance: T | undefined) => void): () => void;
|
|
128
|
+
private fireSubscribers;
|
|
92
129
|
buildRouter(): Record<string, Record<string, (...args: any[]) => any>>;
|
|
93
130
|
onReconciled(cb: (changedKeys: string[]) => void): () => void;
|
|
94
131
|
private resolveDepSlot;
|
|
@@ -178,4 +215,4 @@ declare function getConfig(): ConfigSnapshot;
|
|
|
178
215
|
*/
|
|
179
216
|
declare function subscribeConfig(callback: (snapshot: ConfigSnapshot) => void): () => void;
|
|
180
217
|
//#endregion
|
|
181
|
-
export {
|
|
218
|
+
export { unregisterPlugin as _, ServiceConstructor as a, getConfig as c, getSplashPath as d, registerAppEntrypoint as f, subscribeConfig as g, runtime as h, Service as i, getPlugin as l, replacePlugins as m, ConfigSnapshot as n, ServiceRuntime as o, registerPlugin as p, PluginRecord as r, getAppEntrypoint as s, CleanupReason as t, getPlugins as u };
|
package/dist/runtime.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as
|
|
2
|
-
export { CleanupReason, ConfigSnapshot, PluginRecord, Service, ServiceRuntime, getAppEntrypoint, getConfig, getPlugin, getPlugins, getSplashPath,
|
|
1
|
+
import { _ as unregisterPlugin, a as ServiceConstructor, c as getConfig, d as getSplashPath, f as registerAppEntrypoint, g as subscribeConfig, h as runtime, i as Service, l as getPlugin, m as replacePlugins, n as ConfigSnapshot, o as ServiceRuntime, p as registerPlugin, r as PluginRecord, s as getAppEntrypoint, t as CleanupReason, u as getPlugins } from "./runtime-BQWntcOb.mjs";
|
|
2
|
+
export { CleanupReason, ConfigSnapshot, PluginRecord, Service, ServiceConstructor, ServiceRuntime, getAppEntrypoint, getConfig, getPlugin, getPlugins, getSplashPath, registerAppEntrypoint, registerPlugin, replacePlugins, runtime, subscribeConfig, unregisterPlugin };
|
package/dist/runtime.mjs
CHANGED
|
@@ -1,30 +1,50 @@
|
|
|
1
1
|
//#region src/runtime.ts
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
const DEFAULT_SHUTDOWN_TIMEOUT_MS = 5e3;
|
|
3
|
+
function readShutdownTimeoutMs() {
|
|
4
|
+
const raw = process.env.ZENBU_SHUTDOWN_TIMEOUT_MS;
|
|
5
|
+
if (!raw) return DEFAULT_SHUTDOWN_TIMEOUT_MS;
|
|
6
|
+
const value = Number(raw);
|
|
7
|
+
return Number.isFinite(value) && value > 0 ? value : DEFAULT_SHUTDOWN_TIMEOUT_MS;
|
|
7
8
|
}
|
|
8
|
-
function
|
|
9
|
-
if (typeof entry === "string") return
|
|
10
|
-
|
|
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
|
-
};
|
|
9
|
+
function resolveDepKey(entry) {
|
|
10
|
+
if (typeof entry === "string") return entry;
|
|
11
|
+
return entry.key;
|
|
24
12
|
}
|
|
25
13
|
var Service = class {
|
|
26
|
-
static
|
|
27
|
-
|
|
14
|
+
static deps = {};
|
|
15
|
+
/**
|
|
16
|
+
* Define a Service base class. The returned abstract class has
|
|
17
|
+
* `static key`, `static deps`, and a typed `this.ctx` already set up;
|
|
18
|
+
* extend it and add your `evaluate()` body.
|
|
19
|
+
*
|
|
20
|
+
* export class WindowService extends Service.create({
|
|
21
|
+
* key: "window",
|
|
22
|
+
* deps: {
|
|
23
|
+
* baseWindow: BaseWindowService,
|
|
24
|
+
* http: HttpService,
|
|
25
|
+
* },
|
|
26
|
+
* }) {
|
|
27
|
+
* evaluate() {
|
|
28
|
+
* this.ctx.baseWindow // BaseWindowService
|
|
29
|
+
* this.ctx.http // HttpService
|
|
30
|
+
* }
|
|
31
|
+
* }
|
|
32
|
+
*
|
|
33
|
+
* `key` is a required field on the config object, so TypeScript errors
|
|
34
|
+
* if you forget it. `deps` is optional (defaults to no deps).
|
|
35
|
+
*
|
|
36
|
+
* For dynamic / optional access to another service, use
|
|
37
|
+
* `runtime.get(SomeService, cb)` instead of declaring it in `deps`.
|
|
38
|
+
*/
|
|
39
|
+
static create(config) {
|
|
40
|
+
const { key, deps } = config;
|
|
41
|
+
const resolvedDeps = deps ?? {};
|
|
42
|
+
class ConfiguredService extends Service {
|
|
43
|
+
static key = key;
|
|
44
|
+
static deps = resolvedDeps;
|
|
45
|
+
}
|
|
46
|
+
return ConfiguredService;
|
|
47
|
+
}
|
|
28
48
|
ctx;
|
|
29
49
|
/** @internal */
|
|
30
50
|
__setupCleanups = /* @__PURE__ */ new Map();
|
|
@@ -61,30 +81,6 @@ var Service = class {
|
|
|
61
81
|
this.__setupCleanups.clear();
|
|
62
82
|
}
|
|
63
83
|
};
|
|
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
84
|
const SERVICE_BASE_METHODS = new Set(Object.getOwnPropertyNames(Service.prototype));
|
|
89
85
|
var ServiceRuntime = class {
|
|
90
86
|
definitions = /* @__PURE__ */ new Map();
|
|
@@ -95,11 +91,14 @@ var ServiceRuntime = class {
|
|
|
95
91
|
registrationTokens = /* @__PURE__ */ new Map();
|
|
96
92
|
slots = /* @__PURE__ */ new Map();
|
|
97
93
|
onReconciledCallbacks = [];
|
|
94
|
+
subscribers = /* @__PURE__ */ new Map();
|
|
98
95
|
register(ServiceClass, importMeta) {
|
|
99
96
|
const hot = importMeta?.hot ?? null;
|
|
100
|
-
const
|
|
101
|
-
if (
|
|
102
|
-
|
|
97
|
+
const slotKey = ServiceClass.key;
|
|
98
|
+
if (typeof slotKey !== "string" || slotKey.length === 0) {
|
|
99
|
+
const name = ServiceClass.name ?? "<anonymous>";
|
|
100
|
+
throw new Error(`[runtime] service "${name}" is missing \`static key\`. Define it via \`Service.create({ key: "...", ... })\`.`);
|
|
101
|
+
}
|
|
103
102
|
this.definitions.set(slotKey, ServiceClass);
|
|
104
103
|
const slot = this.slots.get(slotKey);
|
|
105
104
|
if (slot) slot.ServiceClass = ServiceClass;
|
|
@@ -138,6 +137,18 @@ var ServiceRuntime = class {
|
|
|
138
137
|
await this.scheduleReconcile(keys);
|
|
139
138
|
await this.whenIdle();
|
|
140
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* Reload a single service by key. No-op if the key is not registered.
|
|
142
|
+
* Used by infrastructure that watches resources outside dynohot's
|
|
143
|
+
* import-graph (e.g. the migrations directory watcher in DbService) and
|
|
144
|
+
* needs to nudge a specific service to re-evaluate without leaning on
|
|
145
|
+
* the devtools-only `__zenbu_dev__.reloadService` hook.
|
|
146
|
+
*/
|
|
147
|
+
async reload(key) {
|
|
148
|
+
if (!this.slots.has(key)) return;
|
|
149
|
+
await this.scheduleReconcile([key]);
|
|
150
|
+
await this.whenIdle();
|
|
151
|
+
}
|
|
141
152
|
async shutdown() {
|
|
142
153
|
try {
|
|
143
154
|
await this.whenIdle();
|
|
@@ -151,10 +162,49 @@ var ServiceRuntime = class {
|
|
|
151
162
|
this.dirtyKeys.clear();
|
|
152
163
|
this.registrationTokens.clear();
|
|
153
164
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
165
|
+
/**
|
|
166
|
+
* Subscribe to a service. Behavior-subject style: the callback fires
|
|
167
|
+
* synchronously once with the current value (the live instance if ready,
|
|
168
|
+
* `undefined` otherwise), then again on every reconcile of that service —
|
|
169
|
+
* so you see the new instance after each HMR. Pass through `undefined`
|
|
170
|
+
* when the service tears down or unregisters.
|
|
171
|
+
*
|
|
172
|
+
* Returns an unsubscribe function. Always call it from a `setup()` cleanup
|
|
173
|
+
* (or wherever you'd otherwise leak callbacks across reloads).
|
|
174
|
+
*/
|
|
175
|
+
get(ref, cb) {
|
|
176
|
+
const key = ref.key;
|
|
177
|
+
let subs = this.subscribers.get(key);
|
|
178
|
+
if (!subs) {
|
|
179
|
+
subs = /* @__PURE__ */ new Set();
|
|
180
|
+
this.subscribers.set(key, subs);
|
|
181
|
+
}
|
|
182
|
+
const wrapped = cb;
|
|
183
|
+
subs.add(wrapped);
|
|
184
|
+
const slot = this.slots.get(key);
|
|
185
|
+
const current = slot?.status === "ready" && slot.instance ? slot.instance : void 0;
|
|
186
|
+
try {
|
|
187
|
+
cb(current);
|
|
188
|
+
} catch (e) {
|
|
189
|
+
console.error(`[hot] runtime.get subscriber for "${key}" threw:`, e);
|
|
190
|
+
}
|
|
191
|
+
return () => {
|
|
192
|
+
const set = this.subscribers.get(key);
|
|
193
|
+
if (!set) return;
|
|
194
|
+
set.delete(wrapped);
|
|
195
|
+
if (set.size === 0) this.subscribers.delete(key);
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
fireSubscribers(key) {
|
|
199
|
+
const subs = this.subscribers.get(key);
|
|
200
|
+
if (!subs || subs.size === 0) return;
|
|
201
|
+
const slot = this.slots.get(key);
|
|
202
|
+
const instance = slot?.status === "ready" && slot.instance ? slot.instance : void 0;
|
|
203
|
+
for (const cb of [...subs]) try {
|
|
204
|
+
cb(instance);
|
|
205
|
+
} catch (e) {
|
|
206
|
+
console.error(`[hot] runtime.get subscriber for "${key}" threw:`, e);
|
|
207
|
+
}
|
|
158
208
|
}
|
|
159
209
|
buildRouter() {
|
|
160
210
|
const router = {};
|
|
@@ -188,15 +238,9 @@ var ServiceRuntime = class {
|
|
|
188
238
|
const deps = ServiceClass.deps ?? {};
|
|
189
239
|
const ctx = {};
|
|
190
240
|
for (const [name, entry] of Object.entries(deps)) {
|
|
191
|
-
const
|
|
241
|
+
const key = resolveDepKey(entry);
|
|
192
242
|
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
|
-
}
|
|
243
|
+
if (!slot || slot.status !== "ready" || !slot.instance) throw new Error(`Dependency "${key}" not ready for "${ServiceClass.key}"`);
|
|
200
244
|
ctx[name] = slot.instance;
|
|
201
245
|
}
|
|
202
246
|
instance.ctx = ctx;
|
|
@@ -206,7 +250,7 @@ var ServiceRuntime = class {
|
|
|
206
250
|
for (const [slotKey, ServiceClass] of this.definitions) {
|
|
207
251
|
const deps = ServiceClass.deps ?? {};
|
|
208
252
|
for (const entry of Object.values(deps)) {
|
|
209
|
-
const
|
|
253
|
+
const depKey = resolveDepKey(entry);
|
|
210
254
|
const dependents = next.get(depKey) ?? /* @__PURE__ */ new Set();
|
|
211
255
|
dependents.add(slotKey);
|
|
212
256
|
next.set(depKey, dependents);
|
|
@@ -228,8 +272,7 @@ var ServiceRuntime = class {
|
|
|
228
272
|
const deps = ServiceClass.deps ?? {};
|
|
229
273
|
const missing = [];
|
|
230
274
|
for (const entry of Object.values(deps)) {
|
|
231
|
-
const
|
|
232
|
-
if (isOptional) continue;
|
|
275
|
+
const key = resolveDepKey(entry);
|
|
233
276
|
const slot = this.resolveDepSlot(key);
|
|
234
277
|
if (!slot || slot.status !== "ready" || !slot.instance) missing.push(key);
|
|
235
278
|
}
|
|
@@ -254,7 +297,24 @@ var ServiceRuntime = class {
|
|
|
254
297
|
slot.instance = null;
|
|
255
298
|
slot.status = "blocked";
|
|
256
299
|
slot.error = null;
|
|
257
|
-
if (instance)
|
|
300
|
+
if (instance) {
|
|
301
|
+
const reason = options.reason ?? "shutdown";
|
|
302
|
+
const timeoutMs = readShutdownTimeoutMs();
|
|
303
|
+
const cleanup = instance.__cleanupAllSetups(reason);
|
|
304
|
+
let timer = null;
|
|
305
|
+
const timeout = new Promise((resolve) => {
|
|
306
|
+
timer = setTimeout(() => {
|
|
307
|
+
console.error(`[hot] ${key} ${reason} cleanup timed out after ${timeoutMs}ms; forcing teardown`);
|
|
308
|
+
resolve();
|
|
309
|
+
}, timeoutMs);
|
|
310
|
+
timer.unref?.();
|
|
311
|
+
});
|
|
312
|
+
try {
|
|
313
|
+
await Promise.race([cleanup, timeout]);
|
|
314
|
+
} finally {
|
|
315
|
+
if (timer) clearTimeout(timer);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
258
318
|
if (options.removeSlot) this.slots.delete(key);
|
|
259
319
|
}
|
|
260
320
|
async unregister(key, token) {
|
|
@@ -263,6 +323,7 @@ var ServiceRuntime = class {
|
|
|
263
323
|
this.definitions.delete(key);
|
|
264
324
|
await this.teardownService(key, { removeSlot: true });
|
|
265
325
|
this.rebuildDependentsIndex();
|
|
326
|
+
this.fireSubscribers(key);
|
|
266
327
|
await this.scheduleReconcile([key]);
|
|
267
328
|
}
|
|
268
329
|
async scheduleReconcile(keys) {
|
|
@@ -294,38 +355,33 @@ var ServiceRuntime = class {
|
|
|
294
355
|
if (ServiceClass) affected.set(key, ServiceClass);
|
|
295
356
|
}
|
|
296
357
|
const levels = this.topologicalLevels(affected);
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
for (const
|
|
358
|
+
const wasReady = /* @__PURE__ */ new Set();
|
|
359
|
+
for (const key of affectedKeys) if (this.slots.get(key)?.status === "ready") wasReady.add(key);
|
|
360
|
+
for (const level of [...levels].reverse()) await Promise.all(level.map((key) => this.teardownService(key, { reason: "reload" })));
|
|
361
|
+
for (const level of levels) await Promise.all(level.map((key) => this.reconcileKey(key, wasReady)));
|
|
362
|
+
for (const key of affectedKeys) this.fireSubscribers(key);
|
|
302
363
|
if (affectedKeys.length > 0) for (const cb of this.onReconciledCallbacks) try {
|
|
303
364
|
cb(affectedKeys);
|
|
304
365
|
} catch (e) {
|
|
305
366
|
console.error("[hot] onReconciled callback failed:", e);
|
|
306
367
|
}
|
|
307
368
|
}
|
|
308
|
-
async reconcileKey(key) {
|
|
369
|
+
async reconcileKey(key, wasReady) {
|
|
309
370
|
const ServiceClass = this.definitions.get(key);
|
|
310
371
|
if (!ServiceClass) return;
|
|
311
372
|
const slot = this.ensureSlot(key, ServiceClass);
|
|
312
373
|
slot.ServiceClass = ServiceClass;
|
|
313
374
|
const missingDeps = this.listMissingDeps(ServiceClass);
|
|
314
375
|
if (missingDeps.length > 0) {
|
|
315
|
-
const shouldLog = slot.instance !== null || slot.status !== "blocked";
|
|
316
376
|
await this.teardownService(key, { reason: "reload" });
|
|
317
|
-
if (
|
|
377
|
+
if (wasReady.has(key)) console.log(`[hot] ${key} waiting on: ${missingDeps.join(", ")}`);
|
|
318
378
|
return;
|
|
319
379
|
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
instance = new ServiceClass();
|
|
323
|
-
slot.instance = instance;
|
|
324
|
-
} else Object.setPrototypeOf(instance, ServiceClass.prototype);
|
|
380
|
+
const instance = new ServiceClass();
|
|
381
|
+
slot.instance = instance;
|
|
325
382
|
slot.status = "evaluating";
|
|
326
383
|
slot.error = null;
|
|
327
384
|
try {
|
|
328
|
-
await instance.__cleanupAllSetups("reload");
|
|
329
385
|
this.injectCtx(instance, ServiceClass);
|
|
330
386
|
await instance.evaluate();
|
|
331
387
|
slot.status = "ready";
|
|
@@ -347,11 +403,11 @@ var ServiceRuntime = class {
|
|
|
347
403
|
const deps = ServiceClass.deps ?? {};
|
|
348
404
|
let degree = 0;
|
|
349
405
|
for (const entry of Object.values(deps)) {
|
|
350
|
-
const
|
|
406
|
+
const depKey = resolveDepKey(entry);
|
|
351
407
|
if (keys.has(depKey)) {
|
|
352
408
|
degree++;
|
|
353
409
|
dependents.get(depKey).push(slotKey);
|
|
354
|
-
}
|
|
410
|
+
}
|
|
355
411
|
}
|
|
356
412
|
inDegree.set(slotKey, degree);
|
|
357
413
|
}
|
|
@@ -519,4 +575,4 @@ function subscribeConfig(callback) {
|
|
|
519
575
|
};
|
|
520
576
|
}
|
|
521
577
|
//#endregion
|
|
522
|
-
export { Service, ServiceRuntime, getAppEntrypoint, getConfig, getPlugin, getPlugins, getSplashPath,
|
|
578
|
+
export { Service, ServiceRuntime, getAppEntrypoint, getConfig, getPlugin, getPlugins, getSplashPath, registerAppEntrypoint, registerPlugin, replacePlugins, runtime, subscribeConfig, unregisterPlugin };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { m as Field, v as Schema } from "./index-
|
|
1
|
+
import { m as Field, v as Schema } from "./index-DeDxePAa.mjs";
|
|
2
2
|
import zod from "zod";
|
|
3
3
|
|
|
4
4
|
//#region src/schema.d.ts
|
|
5
5
|
declare const viewRegistryEntrySchema: zod.ZodObject<{
|
|
6
|
-
|
|
6
|
+
type: zod.ZodString;
|
|
7
7
|
url: zod.ZodString;
|
|
8
8
|
port: zod.ZodNumber;
|
|
9
9
|
icon: zod.ZodOptional<zod.ZodString>;
|
|
@@ -30,7 +30,7 @@ declare const windowPrefsSchema: zod.ZodObject<{
|
|
|
30
30
|
}, zod.core.$strip>;
|
|
31
31
|
declare const schema: Schema<{
|
|
32
32
|
lastKnownViewRegistry: Field<zod.ZodArray<zod.ZodObject<{
|
|
33
|
-
|
|
33
|
+
type: zod.ZodString;
|
|
34
34
|
url: zod.ZodString;
|
|
35
35
|
port: zod.ZodNumber;
|
|
36
36
|
icon: zod.ZodOptional<zod.ZodString>;
|
package/dist/schema.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as WindowPrefs, i as WindowBounds, n as SchemaRoot, o as schema, r as ViewRegistryEntry, t as CoreSchema } from "./schema-
|
|
1
|
+
import { a as WindowPrefs, i as WindowBounds, n as SchemaRoot, o as schema, r as ViewRegistryEntry, t as CoreSchema } from "./schema-CjrMVk36.mjs";
|
|
2
2
|
export { CoreSchema, SchemaRoot, ViewRegistryEntry, WindowBounds, WindowPrefs, schema };
|
package/dist/schema.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import { a as f, i as createSchema } from "./schema-Ca7SxXgS.mjs";
|
|
|
2
2
|
import zod from "zod";
|
|
3
3
|
//#region src/schema.ts
|
|
4
4
|
const viewRegistryEntrySchema = zod.object({
|
|
5
|
-
|
|
5
|
+
type: zod.string(),
|
|
6
6
|
url: zod.string(),
|
|
7
7
|
port: zod.number(),
|
|
8
8
|
icon: zod.string().optional(),
|
|
@@ -7,9 +7,7 @@ import { WebSocketServer } from "ws";
|
|
|
7
7
|
//#region src/services/server.ts
|
|
8
8
|
var server_exports = /* @__PURE__ */ __exportAll({ ServerService: () => ServerService });
|
|
9
9
|
const log = createLogger("server");
|
|
10
|
-
var ServerService = class extends Service {
|
|
11
|
-
static key = "server";
|
|
12
|
-
static deps = {};
|
|
10
|
+
var ServerService = class extends Service.create({ key: "server" }) {
|
|
13
11
|
server = null;
|
|
14
12
|
wss = null;
|
|
15
13
|
port = 0;
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Loads and registers all built-in services. Kept separate from
|
|
4
4
|
* `./index.ts` (which statically re-exports the service classes for
|
|
5
|
-
* `
|
|
6
|
-
* eagerly loading every service module before `setupGate()` has
|
|
7
|
-
* chance to bootstrap env vars and `process.chdir(projectRoot)`.
|
|
5
|
+
* `Service.withDeps(...)` consumers) so that `setup-gate` can import it
|
|
6
|
+
* without eagerly loading every service module before `setupGate()` has
|
|
7
|
+
* had a chance to bootstrap env vars and `process.chdir(projectRoot)`.
|
|
8
8
|
*/
|
|
9
9
|
declare function defaultServices(): Promise<void>;
|
|
10
10
|
//#endregion
|
|
@@ -2,21 +2,22 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Loads and registers all built-in services. Kept separate from
|
|
4
4
|
* `./index.ts` (which statically re-exports the service classes for
|
|
5
|
-
* `
|
|
6
|
-
* eagerly loading every service module before `setupGate()` has
|
|
7
|
-
* chance to bootstrap env vars and `process.chdir(projectRoot)`.
|
|
5
|
+
* `Service.withDeps(...)` consumers) so that `setup-gate` can import it
|
|
6
|
+
* without eagerly loading every service module before `setupGate()` has
|
|
7
|
+
* had a chance to bootstrap env vars and `process.chdir(projectRoot)`.
|
|
8
8
|
*/
|
|
9
9
|
async function defaultServices() {
|
|
10
|
-
await import("../server-
|
|
11
|
-
await import("../reloader-
|
|
12
|
-
await import("../renderer-host-
|
|
13
|
-
await import("../renderer-host-
|
|
14
|
-
await import("../renderer-host-
|
|
15
|
-
await import("../base-window-
|
|
16
|
-
await import("../rpc-
|
|
17
|
-
await import("../renderer-host-
|
|
18
|
-
await import("../window-
|
|
19
|
-
await import("../advice-config-
|
|
10
|
+
await import("../server-CZLMF8Dj.mjs").then((n) => n.n);
|
|
11
|
+
await import("../reloader-B22UiNA2.mjs").then((n) => n.n);
|
|
12
|
+
await import("../renderer-host-DD16MXhI.mjs").then((n) => n.n);
|
|
13
|
+
await import("../renderer-host-DD16MXhI.mjs").then((n) => n.c);
|
|
14
|
+
await import("../renderer-host-DD16MXhI.mjs").then((n) => n.o);
|
|
15
|
+
await import("../base-window-BxBZ2md_.mjs").then((n) => n.r);
|
|
16
|
+
await import("../rpc-C4_NQmpT.mjs").then((n) => n.n);
|
|
17
|
+
await import("../renderer-host-DD16MXhI.mjs").then((n) => n.i);
|
|
18
|
+
await import("../window-YFKvAM0l.mjs").then((n) => n.n);
|
|
19
|
+
await import("../advice-config-DXSIo0sg.mjs").then((n) => n.t);
|
|
20
|
+
await import("../updater-DCkz9M1c.mjs").then((n) => n.n);
|
|
20
21
|
}
|
|
21
22
|
//#endregion
|
|
22
23
|
export { defaultServices };
|