@zenbujs/core 0.0.5 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/dist/{advice-config-QYB2qEd_.mjs → advice-config-DXSIo0sg.mjs} +40 -39
  2. package/dist/advice.d.mts +8 -8
  3. package/dist/advice.mjs +2 -2
  4. package/dist/{base-window-BbFRRhKP.mjs → base-window-BxBZ2md_.mjs} +51 -7
  5. package/dist/{transforms-CuTODvDx.d.mts → build-config-Dzg2frpk.d.mts} +98 -28
  6. package/dist/build-config-pWdmLnrk.mjs +53 -0
  7. package/dist/{build-electron-CNJ0dLND.mjs → build-electron-Dsbb1EMl.mjs} +308 -120
  8. package/dist/{build-source-C2puqEVr.mjs → build-source-d1J3shV8.mjs} +62 -27
  9. package/dist/cli/bin.mjs +7 -7
  10. package/dist/cli/build.d.mts +2 -2
  11. package/dist/cli/build.mjs +2 -3
  12. package/dist/cli/resolve-config.mjs +1 -1
  13. package/dist/{cli-C3R1LBMY.mjs → cli-kL6mPgBE.mjs} +2 -2
  14. package/dist/config.d.mts +3 -3
  15. package/dist/config.mjs +2 -3
  16. package/dist/{db-xjvahRFJ.mjs → db-Bc292RYo.mjs} +2 -2
  17. package/dist/db.d.mts +1 -1
  18. package/dist/dev-B2emj0HZ.mjs +301 -0
  19. package/dist/env-bootstrap.d.mts +1 -1
  20. package/dist/events.d.mts +19 -0
  21. package/dist/events.mjs +1 -0
  22. package/dist/host-version-BIrF8tX7.mjs +65 -0
  23. package/dist/index-CVF768Xs.d.mts +783 -0
  24. package/dist/index.d.mts +5 -6
  25. package/dist/index.mjs +2 -2
  26. package/dist/installing-preload.cjs +60 -0
  27. package/dist/launcher.mjs +2615 -122
  28. package/dist/{link-c0_aLWQ3.mjs → link-glX89NV5.mjs} +215 -89
  29. package/dist/{load-config-xMf2wxH8.mjs → load-config-C4Oe2qZO.mjs} +5 -1
  30. package/dist/loaders/zenbu.mjs +102 -0
  31. package/dist/node-loader.mjs +1 -1
  32. package/dist/{publish-source-Dill72NS.mjs → publish-source-Dq2c0iOw.mjs} +2 -2
  33. package/dist/react.d.mts +55 -6
  34. package/dist/react.mjs +116 -5
  35. package/dist/registry-CMp8FYgS.d.mts +47 -0
  36. package/dist/registry-generated.d.mts +26 -0
  37. package/dist/registry-generated.mjs +1 -0
  38. package/dist/registry.d.mts +2 -2
  39. package/dist/{reloader-DzEO8kJr.mjs → reloader-B22UiNA2.mjs} +2 -4
  40. package/dist/{renderer-host-Cau9JK0v.mjs → renderer-host-DD16MXhI.mjs} +152 -43
  41. package/dist/{rpc-JfGv-Wuw.mjs → rpc-C4_NQmpT.mjs} +5 -4
  42. package/dist/{runtime-pCeVzj--.d.mts → runtime-BQWntcOb.d.mts} +85 -48
  43. package/dist/runtime.d.mts +2 -2
  44. package/dist/runtime.mjs +139 -83
  45. package/dist/{schema-Dl85YjXW.d.mts → schema-CjrMVk36.d.mts} +3 -3
  46. package/dist/schema.d.mts +1 -1
  47. package/dist/schema.mjs +1 -1
  48. package/dist/{server-y3PPbh3l.mjs → server-CZLMF8Dj.mjs} +1 -3
  49. package/dist/services/default.d.mts +3 -3
  50. package/dist/services/default.mjs +14 -13
  51. package/dist/services/index.d.mts +2 -280
  52. package/dist/services/index.mjs +8 -7
  53. package/dist/setup-gate.d.mts +1 -1
  54. package/dist/setup-gate.mjs +123 -24
  55. package/dist/{transform-CmFYPmt8.mjs → transform-BzrwkEdf.mjs} +22 -916
  56. package/dist/updater-BtB_Ki1r.mjs +1011 -0
  57. package/dist/{vite-plugins-Do7liKi_.mjs → vite-plugins-tt6KAtyE.mjs} +26 -25
  58. package/dist/vite.d.mts +3 -3
  59. package/dist/vite.mjs +1 -1
  60. package/dist/{window-o2NGUsIb.mjs → window-YFKvAM0l.mjs} +30 -16
  61. package/package.json +17 -4
  62. package/dist/build-config-C3a-o3_B.mjs +0 -23
  63. package/dist/dev-Dazhu66l.mjs +0 -85
  64. package/dist/registry-eX6e2oql.d.mts +0 -61
  65. package/dist/transforms-htxfTwsY.mjs +0 -47
  66. /package/dist/{config-DXRCDUxG.mjs → config-BK78JDRI.mjs} +0 -0
  67. /package/dist/{env-bootstrap-DW2hVhSO.d.mts → env-bootstrap-rTs8KR3-.d.mts} +0 -0
  68. /package/dist/{index-M_lSNBrq.d.mts → index-DeDxePAa.d.mts} +0 -0
  69. /package/dist/{mirror-sync-PDzxhf1w.mjs → mirror-sync-pYU6f3-c.mjs} +0 -0
  70. /package/dist/{monorepo-3avKJwzJ.mjs → monorepo-Dct-kkbQ.mjs} +0 -0
  71. /package/dist/{node-_8xShqxr.mjs → node-BhfLKYCi.mjs} +0 -0
  72. /package/dist/{setup-gate-Dcy8gGPJ.d.mts → setup-gate-BQq0QgZH.d.mts} +0 -0
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-M_lSNBrq.mjs";
2
- import { c as ResolvedServiceRouter, l as ZenbuRegister, o as ResolvedDbRoot, s as ResolvedEvents } from "./registry-eX6e2oql.mjs";
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";
3
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): _$react.ReactElement<{
60
+ }: ZenbuProviderProps): ReactElement<{
61
61
  "data-zenbu-connecting": boolean;
62
- }, string | _$react.JSXElementConstructor<any>> | _$react.ReactElement<{
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
@@ -209,13 +209,12 @@ function ZenbuProvider({ wsUrl, fallback, errorFallback, children }) {
209
209
  ws.close();
210
210
  return;
211
211
  }
212
- const viewMatch = window.location.pathname.match(/^\/views\/([^/]+)\//);
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 (viewScope) {
214
+ if (viewType) {
216
215
  const adviceReload = events?.advice?.reload;
217
216
  if (adviceReload?.subscribe) unsubReload = adviceReload.subscribe((data) => {
218
- if (data?.scope === viewScope) location.reload();
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-CVF768Xs.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 {};
@@ -1,2 +1,2 @@
1
- import { a as Events, c as ResolvedServiceRouter, i as CoreServiceRouter, l as ZenbuRegister, n as CoreEvents, o as ResolvedDbRoot, r as CorePreloads, s as ResolvedEvents, t as CoreDbSections } from "./registry-eX6e2oql.mjs";
2
- export { CoreDbSections, CoreEvents, CorePreloads, CoreServiceRouter, Events, ResolvedDbRoot, ResolvedEvents, ResolvedServiceRouter, ZenbuRegister };
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,7 +1,7 @@
1
1
  import { n as __exportAll } from "./chunk-DsiFFCwN.mjs";
2
2
  import { Service, runtime } from "./runtime.mjs";
3
3
  import { t as createLogger } from "./log-6rzaCV0I.mjs";
4
- import { a as zenbuVitePlugins } from "./vite-plugins-Do7liKi_.mjs";
4
+ import { a as zenbuVitePlugins } from "./vite-plugins-tt6KAtyE.mjs";
5
5
  import os from "node:os";
6
6
  import path, { resolve } from "node:path";
7
7
  import { createHash } from "node:crypto";
@@ -113,9 +113,7 @@ async function startRendererServer(options) {
113
113
  await warmupRendererEntrypoints(server, options.root);
114
114
  return server;
115
115
  }
116
- var ReloaderService = class extends Service {
117
- static key = "reloader";
118
- static deps = {};
116
+ var ReloaderService = class extends Service.create({ key: "reloader" }) {
119
117
  servers = /* @__PURE__ */ new Map();
120
118
  async create(id, root, configFile) {
121
119
  if (this.servers.has(id)) return this.servers.get(id);
@@ -1,10 +1,10 @@
1
1
  import { n as __exportAll } from "./chunk-DsiFFCwN.mjs";
2
- import { Service, getAppEntrypoint, getPlugins, runtime } from "./runtime.mjs";
2
+ import { Service, getAppEntrypoint, getPlugins, runtime, subscribeConfig } from "./runtime.mjs";
3
3
  import { o as getZodDefault } from "./schema-Ca7SxXgS.mjs";
4
4
  import { schema } from "./schema.mjs";
5
5
  import { t as createLogger } from "./log-6rzaCV0I.mjs";
6
- import { t as ServerService } from "./server-y3PPbh3l.mjs";
7
- import { i as INTERNAL_DIR, r as DB_CONFIG_JSON, t as ReloaderService } from "./reloader-DzEO8kJr.mjs";
6
+ import { t as ServerService } from "./server-CZLMF8Dj.mjs";
7
+ import { i as INTERNAL_DIR, r as DB_CONFIG_JSON, t as ReloaderService } from "./reloader-B22UiNA2.mjs";
8
8
  import { a as createBlob, c as makeErrorAck, g as layer$1, h as writeJsonFile, i as cleanupStaleTmpFiles, l as paths, m as validateSession, n as makeRootCache, o as createCollection, p as sendAck, r as broadcastDbUpdate, s as makeAck, t as handleWrite, u as readCollectionItemRange, v as FileSystem } from "./write-DgIRjo23.mjs";
9
9
  import { t as traceKyju } from "./trace-BaVg0rnY.mjs";
10
10
  import { a as createClient, i as dbStringify, n as createRouter, o as createEffectClient, r as dbParse, s as createReplica } from "./transport-F2hv_OEm.mjs";
@@ -15,6 +15,7 @@ import { fileURLToPath, pathToFileURL } from "node:url";
15
15
  import http from "node:http";
16
16
  import fsp from "node:fs/promises";
17
17
  import * as Effect from "effect/Effect";
18
+ import { subscribe } from "@parcel/watcher";
18
19
  import * as Ref from "effect/Ref";
19
20
  import { nanoid } from "nanoid";
20
21
  //#region ../../node_modules/.pnpm/@effect+platform-node@0.104.1_@effect+cluster@0.56.4_@effect+platform@0.94.5_effect@3.2_4dd4c94e7ca0ae112861b6965a5da5f4/node_modules/@effect/platform-node/dist/esm/NodeFileSystem.js
@@ -801,12 +802,13 @@ async function resolveDbPath(argv, app) {
801
802
  //#region src/services/http.ts
802
803
  var http_exports = /* @__PURE__ */ __exportAll({ HttpService: () => HttpService });
803
804
  const log$3 = createLogger("http");
804
- var HttpService = class extends Service {
805
- static key = "http";
806
- static deps = {
805
+ var HttpService = class extends Service.create({
806
+ key: "http",
807
+ deps: {
807
808
  server: ServerService,
808
809
  reloader: ReloaderService
809
- };
810
+ }
811
+ }) {
810
812
  connectedCallbacks = [];
811
813
  disconnectedCallbacks = [];
812
814
  activeConnections = /* @__PURE__ */ new Map();
@@ -1014,7 +1016,7 @@ function resolveConfigPath() {
1014
1016
  * loader-emitted barrel before any service evaluates.
1015
1017
  */
1016
1018
  async function loadAppDbField(configPath) {
1017
- const { loadConfig } = await import("./load-config-xMf2wxH8.mjs").then((n) => n.n);
1019
+ const { loadConfig } = await import("./load-config-C4Oe2qZO.mjs").then((n) => n.n);
1018
1020
  const { resolved } = await loadConfig(path.dirname(configPath));
1019
1021
  return resolved.dbPath;
1020
1022
  }
@@ -1104,9 +1106,10 @@ async function discoverSections() {
1104
1106
  for (const ptm of sorted) log$2.verbose(` ${ptm.name.padEnd(28)} total=${String(ptm.totalMs).padStart(6)} resS=${String(ptm.resolveSchemaMs).padStart(5)} impS=${String(ptm.importSchemaMs).padStart(6)} resM=${String(ptm.resolveMigrationsMs).padStart(5)} impM=${String(ptm.importMigrationsMs).padStart(6)}`);
1105
1107
  return sections;
1106
1108
  }
1107
- var DbService = class extends Service {
1108
- static key = "db";
1109
- static deps = { http: HttpService };
1109
+ var DbService = class extends Service.create({
1110
+ key: "db",
1111
+ deps: { http: HttpService }
1112
+ }) {
1110
1113
  db = null;
1111
1114
  dbRouter = null;
1112
1115
  sectionsHash = "";
@@ -1195,6 +1198,110 @@ var DbService = class extends Service {
1195
1198
  this.setup("kyju-close-on-cleanup", () => async () => {
1196
1199
  await this.close();
1197
1200
  });
1201
+ this.setup("migrations-watcher", () => {
1202
+ const subs = [];
1203
+ let closed = false;
1204
+ let pendingTimer = null;
1205
+ let inFlight = null;
1206
+ let queued = false;
1207
+ const triggerReload = async () => {
1208
+ if (closed) return;
1209
+ if (inFlight) {
1210
+ queued = true;
1211
+ return;
1212
+ }
1213
+ inFlight = runtime.reload("db").catch((err) => {
1214
+ log$2.error("migrations-watcher reload failed:", err);
1215
+ });
1216
+ try {
1217
+ await inFlight;
1218
+ } finally {
1219
+ inFlight = null;
1220
+ if (queued && !closed) {
1221
+ queued = false;
1222
+ scheduleReload();
1223
+ }
1224
+ }
1225
+ };
1226
+ const scheduleReload = () => {
1227
+ if (closed) return;
1228
+ if (pendingTimer) clearTimeout(pendingTimer);
1229
+ pendingTimer = setTimeout(() => {
1230
+ pendingTimer = null;
1231
+ triggerReload();
1232
+ }, 100);
1233
+ };
1234
+ (async () => {
1235
+ for (const plugin of getPlugins()) {
1236
+ const migPath = plugin.migrationsPath;
1237
+ if (!migPath) continue;
1238
+ let isDir = false;
1239
+ try {
1240
+ isDir = (await fsp.stat(migPath)).isDirectory();
1241
+ } catch {
1242
+ continue;
1243
+ }
1244
+ if (!isDir) continue;
1245
+ const journalPath = path.join(migPath, "meta", "_journal.json");
1246
+ try {
1247
+ const sub = await subscribe(migPath, (err, events) => {
1248
+ if (err || closed) return;
1249
+ for (const event of events) {
1250
+ if (event.path === journalPath) {
1251
+ scheduleReload();
1252
+ return;
1253
+ }
1254
+ if (path.dirname(event.path) !== migPath) continue;
1255
+ if (event.type === "update") continue;
1256
+ const ext = path.extname(event.path);
1257
+ if (ext === ".ts" || ext === ".js" || ext === ".mjs") {
1258
+ scheduleReload();
1259
+ return;
1260
+ }
1261
+ }
1262
+ });
1263
+ if (closed) {
1264
+ await sub.unsubscribe().catch(() => {});
1265
+ return;
1266
+ }
1267
+ subs.push(sub);
1268
+ } catch (err) {
1269
+ log$2.error(`migrations-watcher subscribe failed for ${plugin.name}: ${err instanceof Error ? err.message : String(err)}`);
1270
+ }
1271
+ }
1272
+ })().catch((err) => {
1273
+ log$2.error("migrations-watcher setup failed:", err);
1274
+ });
1275
+ return async () => {
1276
+ closed = true;
1277
+ if (pendingTimer) {
1278
+ clearTimeout(pendingTimer);
1279
+ pendingTimer = null;
1280
+ }
1281
+ const toClose = subs.splice(0);
1282
+ await Promise.all(toClose.map((s) => s.unsubscribe().catch(() => {})));
1283
+ };
1284
+ });
1285
+ this.setup("plugin-set-watcher", () => {
1286
+ const fingerprint = (snap) => JSON.stringify([...snap.plugins].map((p) => ({
1287
+ name: p.name,
1288
+ schemaPath: p.schemaPath ?? null,
1289
+ migrationsPath: p.migrationsPath ?? null
1290
+ })).sort((a, b) => a.name.localeCompare(b.name)));
1291
+ let lastHash = null;
1292
+ return subscribeConfig((snap) => {
1293
+ const hash = fingerprint(snap);
1294
+ if (lastHash === null) {
1295
+ lastHash = hash;
1296
+ return;
1297
+ }
1298
+ if (hash === lastHash) return;
1299
+ lastHash = hash;
1300
+ runtime.reload("db").catch((err) => {
1301
+ log$2.error("plugin-set-watcher reload failed:", err);
1302
+ });
1303
+ });
1304
+ });
1198
1305
  this.setup("ws-transport", () => {
1199
1306
  const onConnected = (id, ws) => {
1200
1307
  const dbConn = this.dbRouter.connection({
@@ -1236,68 +1343,69 @@ runtime.register(DbService, import.meta);
1236
1343
  //#region src/services/view-registry.ts
1237
1344
  var view_registry_exports = /* @__PURE__ */ __exportAll({ ViewRegistryService: () => ViewRegistryService });
1238
1345
  const log$1 = createLogger("view-registry");
1239
- var ViewRegistryService = class extends Service {
1240
- static key = "view-registry";
1241
- static deps = {
1346
+ var ViewRegistryService = class extends Service.create({
1347
+ key: "view-registry",
1348
+ deps: {
1242
1349
  reloader: ReloaderService,
1243
1350
  db: DbService
1244
- };
1351
+ }
1352
+ }) {
1245
1353
  views = /* @__PURE__ */ new Map();
1246
1354
  manifestIcons = /* @__PURE__ */ new Map();
1247
- async register(scope, root, configFile, meta) {
1248
- log$1.verbose(`register("${scope}", root="${root}", config="${configFile}")`);
1249
- const existing = this.views.get(scope);
1355
+ async register(type, root, configFile, meta) {
1356
+ log$1.verbose(`register("${type}", root="${root}", config="${configFile}")`);
1357
+ const existing = this.views.get(type);
1250
1358
  if (existing) {
1251
- log$1.verbose(`"${scope}" already exists at ${existing.url}`);
1359
+ log$1.verbose(`"${type}" already exists at ${existing.url}`);
1252
1360
  return existing;
1253
1361
  }
1254
- log$1.verbose(`creating reloader for "${scope}"...`);
1255
- const reloaderEntry = await this.ctx.reloader.create(scope, root, configFile);
1362
+ log$1.verbose(`creating reloader for "${type}"...`);
1363
+ const reloaderEntry = await this.ctx.reloader.create(type, root, configFile);
1256
1364
  log$1.verbose(`reloader created: ${reloaderEntry.url} (port ${reloaderEntry.port})`);
1257
1365
  const entry = {
1258
- scope,
1366
+ type,
1259
1367
  url: reloaderEntry.url,
1260
1368
  port: reloaderEntry.port,
1261
1369
  ownsServer: true,
1262
1370
  meta
1263
1371
  };
1264
- this.views.set(scope, entry);
1372
+ this.views.set(type, entry);
1265
1373
  await this.syncToDb();
1266
- log$1.verbose(`"${scope}" registered at ${entry.url}`);
1374
+ log$1.verbose(`"${type}" registered at ${entry.url}`);
1267
1375
  return entry;
1268
1376
  }
1269
- registerAlias(scope, reloaderId, pathPrefix, meta) {
1270
- const existing = this.views.get(scope);
1377
+ registerAlias(type, reloaderId, pathPrefix, meta) {
1378
+ const existing = this.views.get(type);
1271
1379
  if (existing) return existing;
1272
1380
  const reloaderEntry = this.ctx.reloader.get(reloaderId);
1273
- if (!reloaderEntry) throw new Error(`Reloader "${reloaderId}" not found for alias "${scope}"`);
1381
+ if (!reloaderEntry) throw new Error(`Reloader "${reloaderId}" not found for alias "${type}"`);
1274
1382
  const entry = {
1275
- scope,
1383
+ type,
1276
1384
  url: `${reloaderEntry.url}${pathPrefix}`,
1277
1385
  port: reloaderEntry.port,
1278
1386
  ownsServer: false,
1279
1387
  meta
1280
1388
  };
1281
- this.views.set(scope, entry);
1389
+ this.views.set(type, entry);
1282
1390
  this.syncToDb();
1283
1391
  return entry;
1284
1392
  }
1285
- async unregister(scope) {
1286
- const entry = this.views.get(scope);
1393
+ async unregister(type) {
1394
+ const entry = this.views.get(type);
1287
1395
  if (!entry) return;
1288
- if (entry.ownsServer) await this.ctx.reloader.remove(scope);
1289
- this.views.delete(scope);
1396
+ if (entry.ownsServer) await this.ctx.reloader.remove(type);
1397
+ this.views.delete(type);
1290
1398
  await this.syncToDb();
1291
1399
  }
1292
- get(scope) {
1293
- return this.views.get(scope);
1400
+ get(type) {
1401
+ return this.views.get(type);
1294
1402
  }
1295
1403
  evaluate() {
1296
1404
  this.loadManifestIcons();
1297
1405
  this.syncToDb();
1298
1406
  this.setup("view-registry-cleanup", () => {
1299
1407
  return async () => {
1300
- for (const [scope, entry] of this.views) if (entry.ownsServer) await this.ctx.reloader.remove(scope);
1408
+ for (const [type, entry] of this.views) if (entry.ownsServer) await this.ctx.reloader.remove(type);
1301
1409
  this.views.clear();
1302
1410
  await this.syncToDb();
1303
1411
  };
@@ -1307,16 +1415,16 @@ var ViewRegistryService = class extends Service {
1307
1415
  this.manifestIcons.clear();
1308
1416
  for (const plugin of getPlugins()) {
1309
1417
  if (!plugin.icons) continue;
1310
- for (const [scope, svg] of Object.entries(plugin.icons)) this.manifestIcons.set(scope, svg);
1418
+ for (const [type, svg] of Object.entries(plugin.icons)) this.manifestIcons.set(type, svg);
1311
1419
  }
1312
1420
  }
1313
1421
  async syncToDb() {
1314
1422
  const client = this.ctx.db.effectClient;
1315
1423
  const snapshot = [...this.views.values()].map((e) => ({
1316
- scope: e.scope,
1424
+ type: e.type,
1317
1425
  url: e.url,
1318
1426
  port: e.port,
1319
- icon: this.manifestIcons.get(e.scope),
1427
+ icon: this.manifestIcons.get(e.type),
1320
1428
  meta: e.meta
1321
1429
  }));
1322
1430
  await Effect.runPromise(client.update((root) => {
@@ -1361,12 +1469,13 @@ async function resolveRendererRoot() {
1361
1469
  configFile: await pathExists(viteConfig) ? viteConfig : false
1362
1470
  };
1363
1471
  }
1364
- var RendererHostService = class extends Service {
1365
- static key = "renderer-host";
1366
- static deps = {
1472
+ var RendererHostService = class extends Service.create({
1473
+ key: "renderer-host",
1474
+ deps: {
1367
1475
  reloader: ReloaderService,
1368
1476
  viewRegistry: ViewRegistryService
1369
- };
1477
+ }
1478
+ }) {
1370
1479
  url = "";
1371
1480
  port = 0;
1372
1481
  async evaluate() {
@@ -1,14 +1,15 @@
1
1
  import { n as __exportAll } from "./chunk-DsiFFCwN.mjs";
2
2
  import { Service, runtime } from "./runtime.mjs";
3
3
  import { t as createLogger } from "./log-6rzaCV0I.mjs";
4
- import { s as HttpService } from "./renderer-host-Cau9JK0v.mjs";
4
+ import { s as HttpService } from "./renderer-host-DD16MXhI.mjs";
5
5
  import { n as createRpcRouter, r as createServer } from "./src-Cven45mq.mjs";
6
6
  //#region src/services/rpc.ts
7
7
  var rpc_exports = /* @__PURE__ */ __exportAll({ RpcService: () => RpcService });
8
8
  const log = createLogger("rpc");
9
- var RpcService = class extends Service {
10
- static key = "rpc";
11
- static deps = { http: HttpService };
9
+ var RpcService = class extends Service.create({
10
+ key: "rpc",
11
+ deps: { http: HttpService }
12
+ }) {
12
13
  _emit = null;
13
14
  get emit() {
14
15
  if (!this._emit) throw new Error("RpcService not yet evaluated");