@devframes/hub 0.7.9 → 0.7.11

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.
@@ -1,6 +1,7 @@
1
- import { S as DevframeMessagesClient, _ as DevframeMessageEntryInput } from "../context-CNKFzYdA.mjs";
2
- import { b as DevframeDockUserEntry, h as DevframeDockEntry, i as DevframeCommandEntry, j as RemoteConnectionInfo, m as DevframeDockEntriesGrouped, n as DevframeClientCommand, o as DevframeCommandKeybinding, t as DevframeDocksUserSettings } from "../settings-C5cAtNdE.mjs";
3
- import "../index-BeoLMW0z.mjs";
1
+ import { D as DevframeViewIframe, M as NavTarget, N as RemoteConnectionInfo, b as DevframeDockUserEntry, h as DevframeDockEntry, i as DevframeCommandEntry, m as DevframeDockEntriesGrouped, n as DevframeClientCommand, o as DevframeCommandKeybinding, t as DevframeDocksUserSettings, v as DevframeDockEntryIcon } from "../settings-Brw6_lEi.mjs";
2
+ import { DEFAULT_CATEGORIES_ORDER } from "../constants.mjs";
3
+ import { S as DevframeMessagesClient, _ as DevframeMessageEntryInput } from "../context-CCyi44Ep.mjs";
4
+ import "../index-Dyam2SU1.mjs";
4
5
  import { DevframeClientRpcHost, DevframeConnectionStatus, DevframeRpcClient, DevframeRpcClientOptions, DevframeRpcContext, RpcClientEvents, RpcClientEvents as RpcClientEvents$1 } from "devframe/client";
5
6
  import { EventEmitter } from "devframe/types";
6
7
  import { SharedState } from "devframe/utils/shared-state";
@@ -150,6 +151,34 @@ interface DocksEntriesContext {
150
151
  * @returns Whether the selection was changed successfully
151
152
  */
152
153
  toggleEntry: (id: string) => Promise<boolean>;
154
+ /**
155
+ * Register a **client-only** dock entry, live in this page and merged with
156
+ * the server-provided docks (`devframe:docks` shared state) into
157
+ * {@link entries}. Unlike a dock registered on the node
158
+ * {@link import('../types/docks').DevframeDocksHost}, it never flows into
159
+ * shared state, so it stays local to this client instead of syncing to the
160
+ * hub or other viewers — for a view a client host synthesizes itself.
161
+ *
162
+ * Throws when `id` already names a client dock, unless `force` is set. A
163
+ * client dock sharing an id with a server dock overrides it in the local
164
+ * merge. Returns a handle to {@link DockRegistration.update patch} or
165
+ * {@link DockRegistration.dispose remove} it.
166
+ */
167
+ register: <T extends DevframeDockEntry>(entry: T, force?: boolean) => DockRegistration<T>;
168
+ /**
169
+ * Replace a previously {@link register client-registered} dock entry, keyed
170
+ * by `id`. Throws when no client dock owns that id.
171
+ */
172
+ update: (entry: DevframeDockUserEntry) => void;
173
+ }
174
+ interface DockRegistration<T extends DevframeDockEntry = DevframeDockEntry> {
175
+ /**
176
+ * Patch the registered client dock in place. The `id` is immutable — passing
177
+ * a differing `id` throws.
178
+ */
179
+ update: (patch: Partial<T>) => void;
180
+ /** Remove the client dock from the local merge. */
181
+ dispose: () => void;
153
182
  }
154
183
  interface DockEntryState {
155
184
  entryMeta: DevframeDockEntry;
@@ -227,6 +256,127 @@ declare function getDevframeClientContext(): DevframeClientContext | undefined;
227
256
  */
228
257
  declare function setDevframeClientContext(ctx: DevframeClientContext | undefined): void;
229
258
  //#endregion
259
+ //#region src/client/frame-nav.d.ts
260
+ /**
261
+ * Shared-iframe soft navigation — the viewer-side half of a host↔iframe
262
+ * `postMessage` protocol.
263
+ *
264
+ * An {@link DevframeViewIframe.subTabs anchor} iframe dock owns one live iframe
265
+ * (its {@link DevframeViewIframe.frameId frameId}); the embedded app ships a
266
+ * tiny **nav shim** that announces its tabs and answers navigation over
267
+ * `postMessage`. This adapter, auto-attached by the client host when the anchor
268
+ * iframe mounts, runs the ready handshake, turns the reported tab manifest into
269
+ * **client-only** member docks (via {@link DocksEntriesContext.register}), and
270
+ * drives the bidirectional nav loop:
271
+ *
272
+ * - selecting a member dock posts a `navigate` (client-side, no reload);
273
+ * - the app posts `navigated` on any internal navigation, moving the dock
274
+ * highlight to match.
275
+ *
276
+ * The protocol is server-free (works cross-origin and in static builds) and
277
+ * decoupled — the embedded app takes no hub/RPC dependency, only the shim.
278
+ */
279
+ /** `postMessage` channel tag shared by both halves of the protocol. */
280
+ declare const FRAME_NAV_CHANNEL = "devframe:frame-nav";
281
+ /** Protocol version. */
282
+ declare const FRAME_NAV_VERSION = 1;
283
+ /** Envelope every frame-nav message carries. */
284
+ interface FrameNavEnvelope {
285
+ channel: typeof FRAME_NAV_CHANNEL;
286
+ v: typeof FRAME_NAV_VERSION;
287
+ frameId: string;
288
+ /** Direction tag; each side ignores messages with its own `from`. */
289
+ from: 'host' | 'frame';
290
+ }
291
+ /**
292
+ * One tab in the manifest the shim reports. Maps directly onto a dock entry, so
293
+ * a materialized member dock is first-class.
294
+ */
295
+ interface FrameTab {
296
+ /** Unique within the frame. The member dock id becomes `<frameId>:<id>`. */
297
+ id: string;
298
+ title: string;
299
+ icon?: DevframeDockEntryIcon;
300
+ /** Soft-nav target the app maps to its own router. */
301
+ navTarget: NavTarget;
302
+ /**
303
+ * Absolute or anchor-relative URL used for the boot deep-link and the
304
+ * hard-nav fallback. When omitted, one is derived from the anchor URL +
305
+ * `navTarget.path` (hash routing).
306
+ */
307
+ fallbackUrl?: string;
308
+ badge?: string;
309
+ order?: number;
310
+ category?: string;
311
+ when?: string;
312
+ groupId?: string;
313
+ }
314
+ /** Host → frame message payloads (without the {@link FrameNavEnvelope}). */
315
+ type FrameNavHostPayload = {
316
+ type: 'hello';
317
+ } | {
318
+ type: 'navigate';
319
+ tabId: string;
320
+ navTarget: NavTarget;
321
+ };
322
+ /** Host → frame messages. */
323
+ type FrameNavHostMessage = FrameNavEnvelope & {
324
+ from: 'host';
325
+ } & FrameNavHostPayload;
326
+ /** Frame → host messages. */
327
+ type FrameNavFrameMessage = FrameNavEnvelope & {
328
+ from: 'frame';
329
+ } & ({
330
+ type: 'ready';
331
+ tabs: FrameTab[];
332
+ current?: string;
333
+ } | {
334
+ type: 'manifest';
335
+ tabs: FrameTab[];
336
+ current?: string;
337
+ } | {
338
+ type: 'navigated';
339
+ tabId?: string;
340
+ navTarget?: NavTarget;
341
+ });
342
+ /** Minimal window surface the adapter listens on (injectable for tests). */
343
+ interface FrameNavListenTarget {
344
+ addEventListener: (type: 'message', listener: (ev: MessageEvent) => void) => void;
345
+ removeEventListener: (type: 'message', listener: (ev: MessageEvent) => void) => void;
346
+ }
347
+ interface FrameNavClientOptions {
348
+ /** The shared frame id (defaults to the anchor's, else the anchor id). */
349
+ frameId: string;
350
+ /** The anchor iframe dock entry — supplies url/icon/groupId defaults. */
351
+ anchor: DevframeViewIframe;
352
+ /** The live iframe element hosting the embedded app. */
353
+ iframe: Pick<HTMLIFrameElement, 'contentWindow' | 'src'>;
354
+ /** Client docks context — to register members and drive selection. */
355
+ docks: Pick<DocksEntriesContext, 'register' | 'switchEntry' | 'getStateById'>;
356
+ /**
357
+ * Window to receive the frame's `message` events on (the host page window).
358
+ * Defaults to `globalThis`.
359
+ */
360
+ window?: FrameNavListenTarget;
361
+ /** Expected origin for `postMessage`; derived from the anchor URL otherwise. */
362
+ origin?: string;
363
+ /** @default 3000 */
364
+ handshakeTimeoutMs?: number;
365
+ }
366
+ interface FrameNavClient {
367
+ /** Whether the shim has completed its `ready` handshake. */
368
+ readonly ready: boolean;
369
+ /** The tab id currently shown in the frame, or `null`. */
370
+ readonly currentTabId: string | null;
371
+ dispose: () => void;
372
+ }
373
+ /**
374
+ * Attach the frame-nav adapter to a mounted anchor iframe. Returns a handle
375
+ * exposing readiness/current state and a `dispose()` that removes every member
376
+ * dock it registered and detaches its listener.
377
+ */
378
+ declare function attachFrameNavClient(options: FrameNavClientOptions): FrameNavClient;
379
+ //#endregion
230
380
  //#region src/client/host.d.ts
231
381
  interface DevframeClientHostOptions {
232
382
  /**
@@ -312,4 +462,4 @@ declare function parseRemoteConnection(input?: string): RemoteConnectionInfo | n
312
462
  */
313
463
  declare function connectRemoteDevframe(options?: ConnectRemoteDevframeOptions): Promise<DevframeRpcClient>;
314
464
  //#endregion
315
- export { CLIENT_CONTEXT_KEY, CommandsContext, ConnectRemoteDevframeOptions, DevframeClientContext, DevframeClientHost, DevframeClientHostOptions, type DevframeClientRpcHost, DockClientScriptContext, DockClientType, DockEntryState, DockEntryStateEvents, DockPanelStorage, DockRenderer, DockRendererInstance, DockRendererMountOptions, DockRenderersContext, DocksConnectionContext, DocksContext, DocksEntriesContext, DocksPanelContext, MessagesClientOptions, type RpcClientEvents, WhenClauseContext, connectRemoteDevframe, createDevframeClientHost, createMessagesClient, getDevframeClientContext, parseRemoteConnection, setDevframeClientContext };
465
+ export { CLIENT_CONTEXT_KEY, CommandsContext, ConnectRemoteDevframeOptions, DEFAULT_CATEGORIES_ORDER, DevframeClientContext, DevframeClientHost, DevframeClientHostOptions, type DevframeClientRpcHost, DockClientScriptContext, DockClientType, DockEntryState, DockEntryStateEvents, DockPanelStorage, DockRegistration, DockRenderer, DockRendererInstance, DockRendererMountOptions, DockRenderersContext, DocksConnectionContext, DocksContext, DocksEntriesContext, DocksPanelContext, FRAME_NAV_CHANNEL, FRAME_NAV_VERSION, FrameNavClient, FrameNavClientOptions, FrameNavEnvelope, FrameNavFrameMessage, FrameNavHostMessage, FrameNavHostPayload, FrameNavListenTarget, FrameTab, MessagesClientOptions, type RpcClientEvents, WhenClauseContext, attachFrameNavClient, connectRemoteDevframe, createDevframeClientHost, createMessagesClient, getDevframeClientContext, parseRemoteConnection, setDevframeClientContext };
@@ -21,6 +21,210 @@ function setDevframeClientContext(ctx) {
21
21
  globalThis[CLIENT_CONTEXT_KEY] = ctx;
22
22
  }
23
23
  //#endregion
24
+ //#region src/client/frame-nav.ts
25
+ /**
26
+ * Shared-iframe soft navigation — the viewer-side half of a host↔iframe
27
+ * `postMessage` protocol.
28
+ *
29
+ * An {@link DevframeViewIframe.subTabs anchor} iframe dock owns one live iframe
30
+ * (its {@link DevframeViewIframe.frameId frameId}); the embedded app ships a
31
+ * tiny **nav shim** that announces its tabs and answers navigation over
32
+ * `postMessage`. This adapter, auto-attached by the client host when the anchor
33
+ * iframe mounts, runs the ready handshake, turns the reported tab manifest into
34
+ * **client-only** member docks (via {@link DocksEntriesContext.register}), and
35
+ * drives the bidirectional nav loop:
36
+ *
37
+ * - selecting a member dock posts a `navigate` (client-side, no reload);
38
+ * - the app posts `navigated` on any internal navigation, moving the dock
39
+ * highlight to match.
40
+ *
41
+ * The protocol is server-free (works cross-origin and in static builds) and
42
+ * decoupled — the embedded app takes no hub/RPC dependency, only the shim.
43
+ */
44
+ /** `postMessage` channel tag shared by both halves of the protocol. */
45
+ const FRAME_NAV_CHANNEL = "devframe:frame-nav";
46
+ /** Protocol version. */
47
+ const FRAME_NAV_VERSION = 1;
48
+ /**
49
+ * Attach the frame-nav adapter to a mounted anchor iframe. Returns a handle
50
+ * exposing readiness/current state and a `dispose()` that removes every member
51
+ * dock it registered and detaches its listener.
52
+ */
53
+ function attachFrameNavClient(options) {
54
+ const { frameId, anchor, iframe, docks } = options;
55
+ const listenTarget = options.window ?? globalThis;
56
+ const expectedOrigin = options.origin ?? resolveOrigin(anchor.url);
57
+ const timeoutMs = options.handshakeTimeoutMs ?? anchor.subTabs?.handshakeTimeoutMs ?? 3e3;
58
+ const members = /* @__PURE__ */ new Map();
59
+ let ready = false;
60
+ let currentTabId = null;
61
+ let disposed = false;
62
+ let handshakeTimer;
63
+ function post(message) {
64
+ iframe.contentWindow?.postMessage({
65
+ channel: FRAME_NAV_CHANNEL,
66
+ v: 1,
67
+ frameId,
68
+ from: "host",
69
+ ...message
70
+ }, expectedOrigin);
71
+ }
72
+ function onMessage(ev) {
73
+ if (disposed) return;
74
+ if (expectedOrigin !== "*" && ev.origin !== expectedOrigin) return;
75
+ const data = ev.data;
76
+ if (!data || data.channel !== "devframe:frame-nav" || data.v !== 1 || data.frameId !== frameId || data.from !== "frame") return;
77
+ switch (data.type) {
78
+ case "ready":
79
+ case "manifest":
80
+ markReady();
81
+ reconcileManifest(data.tabs ?? [], data.current);
82
+ break;
83
+ case "navigated":
84
+ onNavigated(data.tabId);
85
+ break;
86
+ }
87
+ }
88
+ function markReady() {
89
+ ready = true;
90
+ if (handshakeTimer !== void 0) {
91
+ clearTimeout(handshakeTimer);
92
+ handshakeTimer = void 0;
93
+ }
94
+ }
95
+ function memberId(tabId) {
96
+ return `${frameId}:${tabId}`;
97
+ }
98
+ function buildMemberEntry(tab) {
99
+ const entry = {
100
+ id: memberId(tab.id),
101
+ type: "iframe",
102
+ title: tab.title,
103
+ icon: tab.icon ?? anchor.icon,
104
+ frameId,
105
+ url: tab.fallbackUrl ?? deriveFallbackUrl(anchor.url, tab.navTarget),
106
+ navTarget: tab.navTarget
107
+ };
108
+ if (tab.badge !== void 0) entry.badge = tab.badge;
109
+ if (tab.order !== void 0) entry.defaultOrder = tab.order;
110
+ if (tab.category !== void 0) entry.category = tab.category;
111
+ if (tab.when !== void 0) entry.when = tab.when;
112
+ const groupId = tab.groupId ?? anchor.groupId;
113
+ if (groupId !== void 0) entry.groupId = groupId;
114
+ return entry;
115
+ }
116
+ function reconcileManifest(tabs, current) {
117
+ const incoming = new Set(tabs.map((t) => t.id));
118
+ for (const tab of tabs) {
119
+ const entry = buildMemberEntry(tab);
120
+ const existing = members.get(tab.id);
121
+ if (existing) {
122
+ existing.tab = tab;
123
+ existing.handle.update(entry);
124
+ } else {
125
+ const record = {
126
+ tab,
127
+ handle: docks.register(entry)
128
+ };
129
+ record.off = docks.getStateById(entry.id)?.events.on("entry:activated", () => onMemberActivated(tab.id));
130
+ members.set(tab.id, record);
131
+ }
132
+ }
133
+ for (const [tabId, record] of [...members]) {
134
+ if (incoming.has(tabId)) continue;
135
+ record.off?.();
136
+ record.handle.dispose();
137
+ members.delete(tabId);
138
+ if (currentTabId === tabId) currentTabId = null;
139
+ }
140
+ if (current !== void 0 && current !== currentTabId && members.has(current)) {
141
+ currentTabId = current;
142
+ docks.switchEntry(memberId(current));
143
+ }
144
+ }
145
+ function onMemberActivated(tabId) {
146
+ if (disposed || tabId === currentTabId) return;
147
+ const record = members.get(tabId);
148
+ if (!record) return;
149
+ currentTabId = tabId;
150
+ if (ready) post({
151
+ type: "navigate",
152
+ tabId,
153
+ navTarget: record.tab.navTarget
154
+ });
155
+ else hardNav(record.tab);
156
+ }
157
+ function onNavigated(tabId) {
158
+ if (disposed || !tabId || !members.has(tabId) || tabId === currentTabId) return;
159
+ currentTabId = tabId;
160
+ docks.switchEntry(memberId(tabId));
161
+ }
162
+ function hardNav(tab) {
163
+ iframe.src = tab.fallbackUrl ?? deriveFallbackUrl(anchor.url, tab.navTarget);
164
+ }
165
+ listenTarget.addEventListener("message", onMessage);
166
+ post({ type: "hello" });
167
+ handshakeTimer = setTimeout(() => {
168
+ handshakeTimer = void 0;
169
+ }, timeoutMs);
170
+ return {
171
+ get ready() {
172
+ return ready;
173
+ },
174
+ get currentTabId() {
175
+ return currentTabId;
176
+ },
177
+ dispose() {
178
+ if (disposed) return;
179
+ disposed = true;
180
+ if (handshakeTimer !== void 0) clearTimeout(handshakeTimer);
181
+ listenTarget.removeEventListener("message", onMessage);
182
+ for (const record of members.values()) {
183
+ record.off?.();
184
+ record.handle.dispose();
185
+ }
186
+ members.clear();
187
+ }
188
+ };
189
+ }
190
+ /** Resolve the origin to lock `postMessage` to; `'*'` when unresolvable. */
191
+ function resolveOrigin(url) {
192
+ const base = globalThis.location?.href;
193
+ try {
194
+ return new URL(url).origin;
195
+ } catch {}
196
+ if (base) try {
197
+ return new URL(url, base).origin;
198
+ } catch {}
199
+ return "*";
200
+ }
201
+ /**
202
+ * Derive a deep-link/fallback URL from the anchor base + a nav target, using
203
+ * hash routing (the safest generic for SPA routers). `state` cannot ride a URL
204
+ * and is intentionally dropped here.
205
+ */
206
+ function deriveFallbackUrl(base, navTarget) {
207
+ const href = globalThis.location?.href;
208
+ let url;
209
+ try {
210
+ url = new URL(base, href ?? "http://localhost");
211
+ } catch {
212
+ return base;
213
+ }
214
+ const path = navTarget.path.startsWith("#") ? navTarget.path.slice(1) : navTarget.path;
215
+ let hash = `#${path}`;
216
+ const query = navTarget.query;
217
+ if (query) {
218
+ const params = new URLSearchParams();
219
+ for (const [key, value] of Object.entries(query)) if (typeof value === "string") params.set(key, value);
220
+ else for (const v of value) params.append(key, v);
221
+ const qs = params.toString();
222
+ if (qs) hash += (path.includes("?") ? "&" : "?") + qs;
223
+ }
224
+ url.hash = hash;
225
+ return url.toString();
226
+ }
227
+ //#endregion
24
228
  //#region src/client/messages.ts
25
229
  /**
26
230
  * Build a browser-side {@link DevframeMessagesClient} that writes into the
@@ -98,6 +302,9 @@ async function createDevframeClientHost(options = {}) {
98
302
  ]);
99
303
  let selectedId = null;
100
304
  const entryToStateMap = /* @__PURE__ */ new Map();
305
+ const clientDocks = /* @__PURE__ */ new Map();
306
+ const frameNavAdapters = /* @__PURE__ */ new Map();
307
+ const loadScriptsEnabled = options.loadClientScripts ?? true;
101
308
  const panel = createPanelContext(clientType);
102
309
  const docks = createDocksContext();
103
310
  const commands = createCommandsContext();
@@ -147,7 +354,7 @@ async function createDevframeClientHost(options = {}) {
147
354
  if (getDevframeClientContext()) console.warn("[@devframes/hub] A client host context is already published on this page — replacing it. Boot createDevframeClientHost() once per page (e.g. HTML injection combined with a manual import boots it twice).");
148
355
  setDevframeClientContext(context);
149
356
  const loadedScripts = /* @__PURE__ */ new Set();
150
- if (options.loadClientScripts ?? true) {
357
+ if (loadScriptsEnabled) {
151
358
  loadClientScripts();
152
359
  disposers.push(docksState.on("updated", loadClientScripts));
153
360
  }
@@ -155,6 +362,8 @@ async function createDevframeClientHost(options = {}) {
155
362
  context,
156
363
  dispose() {
157
364
  for (const off of disposers.splice(0)) off();
365
+ for (const disposeAdapter of frameNavAdapters.values()) disposeAdapter();
366
+ frameNavAdapters.clear();
158
367
  if (mountedRenderers) for (const disposeMount of [...mountedRenderers]) disposeMount();
159
368
  if (getDevframeClientContext() === context) setDevframeClientContext(void 0);
160
369
  }
@@ -169,19 +378,66 @@ async function createDevframeClientHost(options = {}) {
169
378
  events: createEventEmitter()
170
379
  };
171
380
  }
381
+ function maybeAttachFrameNav(meta, state) {
382
+ if (meta.type !== "iframe") return;
383
+ const anchor = meta;
384
+ if (!anchor.subTabs) return;
385
+ const frameId = anchor.frameId ?? anchor.id;
386
+ const start = (iframe) => {
387
+ if (frameNavAdapters.has(frameId)) return;
388
+ const adapter = attachFrameNavClient({
389
+ frameId,
390
+ anchor,
391
+ iframe,
392
+ docks
393
+ });
394
+ frameNavAdapters.set(frameId, adapter.dispose);
395
+ };
396
+ if (state.domElements.iframe) start(state.domElements.iframe);
397
+ state.events.on("dom:iframe:mounted", start);
398
+ }
399
+ function currentEntries() {
400
+ const server = docksState.value();
401
+ if (clientDocks.size === 0) return server;
402
+ const merged = [];
403
+ const seen = /* @__PURE__ */ new Set();
404
+ for (const entry of server) {
405
+ merged.push(clientDocks.get(entry.id) ?? entry);
406
+ seen.add(entry.id);
407
+ }
408
+ for (const [id, entry] of clientDocks) if (!seen.has(id)) merged.push(entry);
409
+ return merged;
410
+ }
411
+ function refreshEntries() {
412
+ reconcileEntries();
413
+ if (loadScriptsEnabled) loadClientScripts();
414
+ }
172
415
  function reconcileEntries() {
173
- const entries = docksState.value();
416
+ const entries = currentEntries();
174
417
  const seen = /* @__PURE__ */ new Set();
175
418
  for (const meta of entries) {
176
419
  seen.add(meta.id);
177
420
  const existing = entryToStateMap.get(meta.id);
178
- if (!existing) entryToStateMap.set(meta.id, createDockEntryState(meta));
179
- else if (existing.entryMeta !== meta) {
421
+ if (!existing) {
422
+ const state = createDockEntryState(meta);
423
+ entryToStateMap.set(meta.id, state);
424
+ maybeAttachFrameNav(meta, state);
425
+ } else if (existing.entryMeta !== meta) {
180
426
  existing.entryMeta = meta;
181
427
  existing.events.emit("entry:updated", meta);
182
428
  }
183
429
  }
184
- for (const id of [...entryToStateMap.keys()]) if (!seen.has(id)) entryToStateMap.delete(id);
430
+ for (const id of [...entryToStateMap.keys()]) {
431
+ if (seen.has(id)) continue;
432
+ const removed = entryToStateMap.get(id);
433
+ entryToStateMap.delete(id);
434
+ const removedMeta = removed?.entryMeta;
435
+ if (removedMeta?.type === "iframe" && removedMeta.subTabs) {
436
+ const frameId = removedMeta.frameId ?? id;
437
+ frameNavAdapters.get(frameId)?.();
438
+ frameNavAdapters.delete(frameId);
439
+ }
440
+ }
185
441
  docks.entries = entries;
186
442
  docks.groupedEntries = groupByCategory(entries);
187
443
  if (selectedId && !entryToStateMap.has(selectedId)) selectedId = null;
@@ -203,7 +459,32 @@ async function createDevframeClientHost(options = {}) {
203
459
  settings,
204
460
  getStateById: (id) => entryToStateMap.get(id),
205
461
  switchEntry,
206
- toggleEntry: (id) => selectedId === id ? switchEntry(null) : switchEntry(id)
462
+ toggleEntry: (id) => selectedId === id ? switchEntry(null) : switchEntry(id),
463
+ register(entry, force) {
464
+ if (clientDocks.has(entry.id) && !force) throw new Error(`[@devframes/hub] a client dock "${entry.id}" is already registered — pass force to overwrite`);
465
+ clientDocks.set(entry.id, entry);
466
+ refreshEntries();
467
+ return {
468
+ update: (patch) => {
469
+ if (patch.id && patch.id !== entry.id) throw new Error(`[@devframes/hub] cannot change a dock id ("${entry.id}" → "${patch.id}")`);
470
+ const existing = clientDocks.get(entry.id);
471
+ if (!existing) throw new Error(`[@devframes/hub] client dock "${entry.id}" was removed — register it again to update`);
472
+ clientDocks.set(entry.id, {
473
+ ...existing,
474
+ ...patch
475
+ });
476
+ refreshEntries();
477
+ },
478
+ dispose: () => {
479
+ if (clientDocks.delete(entry.id)) refreshEntries();
480
+ }
481
+ };
482
+ },
483
+ update(entry) {
484
+ if (!clientDocks.has(entry.id)) throw new Error(`[@devframes/hub] no client dock "${entry.id}" to update — register it first`);
485
+ clientDocks.set(entry.id, entry);
486
+ refreshEntries();
487
+ }
207
488
  };
208
489
  }
209
490
  async function switchEntry(id) {
@@ -293,7 +574,7 @@ async function createDevframeClientHost(options = {}) {
293
574
  return entry.action ?? entry.renderer ?? entry.clientScript;
294
575
  }
295
576
  function loadClientScripts() {
296
- for (const entry of docksState.value()) {
577
+ for (const entry of currentEntries()) {
297
578
  const script = clientScriptOf(entry);
298
579
  if (!script?.importFrom || loadedScripts.has(entry.id)) continue;
299
580
  loadedScripts.add(entry.id);
@@ -344,9 +625,12 @@ function createPanelContext(clientType) {
344
625
  };
345
626
  }
346
627
  function groupByCategory(entries) {
628
+ const groupsById = /* @__PURE__ */ new Map();
629
+ for (const entry of entries) if (entry.type === "group") groupsById.set(entry.id, entry);
347
630
  const groups = /* @__PURE__ */ new Map();
348
631
  for (const entry of entries) {
349
- const category = entry.category ?? "default";
632
+ const resolvedGroup = entry.groupId ? groupsById.get(entry.groupId) : void 0;
633
+ const category = resolvedGroup ? resolvedGroup.category ?? "default" : entry.category ?? "default";
350
634
  let list = groups.get(category);
351
635
  if (!list) {
352
636
  list = [];
@@ -442,4 +726,4 @@ async function connectRemoteDevframe(options = {}) {
442
726
  });
443
727
  }
444
728
  //#endregion
445
- export { CLIENT_CONTEXT_KEY, connectRemoteDevframe, createDevframeClientHost, createMessagesClient, getDevframeClientContext, parseRemoteConnection, setDevframeClientContext };
729
+ export { CLIENT_CONTEXT_KEY, DEFAULT_CATEGORIES_ORDER, FRAME_NAV_CHANNEL, FRAME_NAV_VERSION, attachFrameNavClient, connectRemoteDevframe, createDevframeClientHost, createMessagesClient, getDevframeClientContext, parseRemoteConnection, setDevframeClientContext };
@@ -1,6 +1,16 @@
1
- import { t as DevframeDocksUserSettings } from "./settings-C5cAtNdE.mjs";
1
+ import { t as DevframeDocksUserSettings } from "./settings-Brw6_lEi.mjs";
2
2
  export * from "devframe/constants";
3
3
  //#region src/constants.d.ts
4
+ /**
5
+ * The default ordering weight for each known dock category — lower sorts
6
+ * earlier. Downstream viewers (e.g. `@vitejs/devtools-kit`) import this as the
7
+ * single source of truth so the hub and its viewers agree on category order.
8
+ * `framework` sorts first; `~builtin` (the viewer's own built-in views) last.
9
+ *
10
+ * The buckets read from "closest to your app" → "platform / analysis" →
11
+ * "peripheral". Gaps between the weights are intentional: a kit can interleave
12
+ * its own categories (or override these) without editing this table.
13
+ */
4
14
  declare const DEFAULT_CATEGORIES_ORDER: Record<string, number>;
5
15
  declare const DEFAULT_STATE_USER_SETTINGS: () => DevframeDocksUserSettings;
6
16
  //#endregion
@@ -1,11 +1,25 @@
1
1
  export * from "devframe/constants";
2
2
  //#region src/constants.ts
3
+ /**
4
+ * The default ordering weight for each known dock category — lower sorts
5
+ * earlier. Downstream viewers (e.g. `@vitejs/devtools-kit`) import this as the
6
+ * single source of truth so the hub and its viewers agree on category order.
7
+ * `framework` sorts first; `~builtin` (the viewer's own built-in views) last.
8
+ *
9
+ * The buckets read from "closest to your app" → "platform / analysis" →
10
+ * "peripheral". Gaps between the weights are intentional: a kit can interleave
11
+ * its own categories (or override these) without editing this table.
12
+ */
3
13
  const DEFAULT_CATEGORIES_ORDER = {
14
+ "framework": -100,
4
15
  "default": 0,
5
16
  "app": 100,
6
- "framework": 200,
17
+ "ui": 150,
18
+ "data": 250,
7
19
  "web": 300,
20
+ "performance": 350,
8
21
  "advanced": 400,
22
+ "docs": 500,
9
23
  "~builtin": 1e3
10
24
  };
11
25
  const DEFAULT_STATE_USER_SETTINGS = () => ({
@@ -1,4 +1,4 @@
1
- import { F as JsonRenderer, P as JsonRenderSpec, S as DevframeDocksHost, c as DevframeCommandsHost, p as DevframeDockActivation, v as DevframeDockEntryIcon } from "./settings-C5cAtNdE.mjs";
1
+ import { I as JsonRenderSpec, L as JsonRenderer, S as DevframeDocksHost, c as DevframeCommandsHost, p as DevframeDockActivation, v as DevframeDockEntryIcon } from "./settings-Brw6_lEi.mjs";
2
2
  import { CreateHostContextOptions } from "devframe/node";
3
3
  import { DevframeHost, DevframeNodeContext, EventEmitter } from "devframe/types";
4
4
  import { ChildProcess } from "node:child_process";
@@ -1,5 +1,5 @@
1
- import "./context-CNKFzYdA.mjs";
2
- import "./settings-C5cAtNdE.mjs";
1
+ import "./settings-Brw6_lEi.mjs";
2
+ import "./context-CCyi44Ep.mjs";
3
3
  import { RpcDefinitionsFilter, RpcDefinitionsToFunctions } from "devframe/rpc";
4
4
  import { ConnectionMeta as ConnectionMeta$1, DevframeCapabilities, DevframeDiagnosticsDefinition, DevframeDiagnosticsHost, DevframeDiagnosticsLogger, DevframeHost as DevframeHost$1, DevframeNodeRpcSession, DevframeRpcClientFunctions, DevframeRpcServerFunctions, DevframeRpcSharedStates, DevframeViewHost, EntriesToObject, EventEmitter as EventEmitter$1, EventUnsubscribe, EventsMap, PartialWithoutId, RpcBroadcastOptions, RpcFunctionsHost, RpcSharedStateGetOptions, RpcSharedStateHost, RpcStreamingChannel, RpcStreamingChannelOptions, RpcStreamingHost, Thenable } from "devframe/types";
5
5
  export { RpcStreamingChannel as C, Thenable as E, RpcSharedStateHost as S, RpcStreamingHost as T, RpcBroadcastOptions as _, DevframeDiagnosticsLogger as a, RpcFunctionsHost as b, DevframeRpcClientFunctions as c, DevframeViewHost as d, EntriesToObject as f, PartialWithoutId as g, EventsMap as h, DevframeDiagnosticsHost as i, DevframeRpcServerFunctions as l, EventUnsubscribe as m, DevframeCapabilities as n, DevframeHost$1 as o, EventEmitter$1 as p, DevframeDiagnosticsDefinition as r, DevframeNodeRpcSession as s, ConnectionMeta$1 as t, DevframeRpcSharedStates as u, RpcDefinitionsFilter as v, RpcStreamingChannelOptions as w, RpcSharedStateGetOptions as x, RpcDefinitionsToFunctions as y };
package/dist/index.d.mts CHANGED
@@ -1,6 +1,7 @@
1
- import { C as DevframeMessagesHost, S as DevframeMessagesClient, T as DevframeMessagesListDelta, _ as DevframeMessageEntryInput, a as DevframeChildProcessOutput, b as DevframeMessageLevel, c as DevframePtyExecuteOptions, d as DevframeTerminalSessionBase, f as DevframeTerminalStatus, g as DevframeMessageEntryFrom, h as DevframeMessageEntry, i as DevframeChildProcessExecuteOptions, l as DevframePtyTerminalSession, m as DevframeMessageElementPosition, n as DevframeHubContext, o as DevframeChildProcessResult, p as DevframeTerminalsHost, s as DevframeChildProcessTerminalSession, t as CreateHubContextOptions, u as DevframeTerminalSession, v as DevframeMessageFilePosition, w as DevframeMessagesLevelShortcuts, x as DevframeMessageShortcutInput, y as DevframeMessageHandle } from "./context-CNKFzYdA.mjs";
2
- import { A as DevframeViewLauncherStatus, C as DevframeViewAction, D as DevframeViewIframe, E as DevframeViewGroup, F as JsonRenderer, M as RemoteDockOptions, N as JsonRenderElement, O as DevframeViewJsonRender, P as JsonRenderSpec, S as DevframeDocksHost, T as DevframeViewCustomRender, _ as DevframeDockEntryCategory, a as DevframeCommandHandle, b as DevframeDockUserEntry, c as DevframeCommandsHost, d as DevframeServerCommandInput, f as ClientScriptEntry, g as DevframeDockEntryBase, h as DevframeDockEntry, i as DevframeCommandEntry, j as RemoteConnectionInfo, k as DevframeViewLauncher, l as DevframeCommandsHostEvents, m as DevframeDockEntriesGrouped, n as DevframeClientCommand, o as DevframeCommandKeybinding, p as DevframeDockActivation, r as DevframeCommandBase, s as DevframeCommandShortcutOverrides, t as DevframeDocksUserSettings, u as DevframeServerCommandEntry, v as DevframeDockEntryIcon, w as DevframeViewBuiltin, x as DevframeDocksActiveState, y as DevframeDockEntryRegistry } from "./settings-C5cAtNdE.mjs";
3
- import { C as RpcStreamingChannel, E as Thenable, S as RpcSharedStateHost, T as RpcStreamingHost, _ as RpcBroadcastOptions, a as DevframeDiagnosticsLogger, b as RpcFunctionsHost, c as DevframeRpcClientFunctions, d as DevframeViewHost, f as EntriesToObject, g as PartialWithoutId, h as EventsMap, i as DevframeDiagnosticsHost, l as DevframeRpcServerFunctions, m as EventUnsubscribe, n as DevframeCapabilities, o as DevframeHost, p as EventEmitter, r as DevframeDiagnosticsDefinition, s as DevframeNodeRpcSession, t as ConnectionMeta, u as DevframeRpcSharedStates, v as RpcDefinitionsFilter, w as RpcStreamingChannelOptions, x as RpcSharedStateGetOptions, y as RpcDefinitionsToFunctions } from "./index-BeoLMW0z.mjs";
1
+ import { A as DevframeViewLauncherStatus, C as DevframeViewAction, D as DevframeViewIframe, E as DevframeViewGroup, F as JsonRenderElement, I as JsonRenderSpec, L as JsonRenderer, M as NavTarget, N as RemoteConnectionInfo, O as DevframeViewJsonRender, P as RemoteDockOptions, S as DevframeDocksHost, T as DevframeViewCustomRender, _ as DevframeDockEntryCategory, a as DevframeCommandHandle, b as DevframeDockUserEntry, c as DevframeCommandsHost, d as DevframeServerCommandInput, f as ClientScriptEntry, g as DevframeDockEntryBase, h as DevframeDockEntry, i as DevframeCommandEntry, j as FrameSubTabsConfig, k as DevframeViewLauncher, l as DevframeCommandsHostEvents, m as DevframeDockEntriesGrouped, n as DevframeClientCommand, o as DevframeCommandKeybinding, p as DevframeDockActivation, r as DevframeCommandBase, s as DevframeCommandShortcutOverrides, t as DevframeDocksUserSettings, u as DevframeServerCommandEntry, v as DevframeDockEntryIcon, w as DevframeViewBuiltin, x as DevframeDocksActiveState, y as DevframeDockEntryRegistry } from "./settings-Brw6_lEi.mjs";
2
+ import { DEFAULT_CATEGORIES_ORDER } from "./constants.mjs";
3
+ import { C as DevframeMessagesHost, S as DevframeMessagesClient, T as DevframeMessagesListDelta, _ as DevframeMessageEntryInput, a as DevframeChildProcessOutput, b as DevframeMessageLevel, c as DevframePtyExecuteOptions, d as DevframeTerminalSessionBase, f as DevframeTerminalStatus, g as DevframeMessageEntryFrom, h as DevframeMessageEntry, i as DevframeChildProcessExecuteOptions, l as DevframePtyTerminalSession, m as DevframeMessageElementPosition, n as DevframeHubContext, o as DevframeChildProcessResult, p as DevframeTerminalsHost, s as DevframeChildProcessTerminalSession, t as CreateHubContextOptions, u as DevframeTerminalSession, v as DevframeMessageFilePosition, w as DevframeMessagesLevelShortcuts, x as DevframeMessageShortcutInput, y as DevframeMessageHandle } from "./context-CCyi44Ep.mjs";
4
+ import { C as RpcStreamingChannel, E as Thenable, S as RpcSharedStateHost, T as RpcStreamingHost, _ as RpcBroadcastOptions, a as DevframeDiagnosticsLogger, b as RpcFunctionsHost, c as DevframeRpcClientFunctions, d as DevframeViewHost, f as EntriesToObject, g as PartialWithoutId, h as EventsMap, i as DevframeDiagnosticsHost, l as DevframeRpcServerFunctions, m as EventUnsubscribe, n as DevframeCapabilities, o as DevframeHost, p as EventEmitter, r as DevframeDiagnosticsDefinition, s as DevframeNodeRpcSession, t as ConnectionMeta, u as DevframeRpcSharedStates, v as RpcDefinitionsFilter, w as RpcStreamingChannelOptions, x as RpcSharedStateGetOptions, y as RpcDefinitionsToFunctions } from "./index-Dyam2SU1.mjs";
4
5
  import { WhenContext, WhenExpression } from "devframe/utils/when";
5
6
  //#region src/define.d.ts
6
7
  declare const defineHubRpcFunction: <NAME extends string, TYPE extends import("devframe/rpc").RpcFunctionType, ARGS extends any[], RETURN = void, const AS extends import("devframe/rpc").RpcArgsSchema | undefined = undefined, const RS extends import("devframe/rpc").RpcReturnSchema | undefined = undefined>(definition: import("devframe/rpc").RpcFunctionDefinition<NAME, TYPE, ARGS, RETURN, AS, RS, DevframeHubContext>) => import("devframe/rpc").RpcFunctionDefinition<NAME, TYPE, ARGS, RETURN, AS, RS, DevframeHubContext>;
@@ -19,4 +20,4 @@ declare function defineDockEntry<const T extends DevframeDockUserEntry, const W
19
20
  */
20
21
  declare function defineJsonRenderSpec(spec: JsonRenderSpec): JsonRenderSpec;
21
22
  //#endregion
22
- export { type ClientScriptEntry, type ConnectionMeta, type CreateHubContextOptions, type DevframeCapabilities, type DevframeChildProcessExecuteOptions, type DevframeChildProcessOutput, type DevframeChildProcessResult, type DevframeChildProcessTerminalSession, type DevframeClientCommand, type DevframeCommandBase, type DevframeCommandEntry, type DevframeCommandHandle, type DevframeCommandKeybinding, type DevframeCommandShortcutOverrides, type DevframeCommandsHost, type DevframeCommandsHostEvents, type DevframeDiagnosticsDefinition, type DevframeDiagnosticsHost, type DevframeDiagnosticsLogger, type DevframeDockActivation, type DevframeDockEntriesGrouped, type DevframeDockEntry, type DevframeDockEntryBase, type DevframeDockEntryCategory, type DevframeDockEntryIcon, type DevframeDockEntryRegistry, type DevframeDockUserEntry, type DevframeDocksActiveState, type DevframeDocksHost, type DevframeDocksUserSettings, type DevframeHost, type DevframeHubContext, type DevframeMessageElementPosition, type DevframeMessageEntry, type DevframeMessageEntryFrom, type DevframeMessageEntryInput, type DevframeMessageFilePosition, type DevframeMessageHandle, type DevframeMessageLevel, type DevframeMessageShortcutInput, type DevframeMessagesClient, type DevframeMessagesHost, type DevframeMessagesLevelShortcuts, type DevframeMessagesListDelta, type DevframeNodeRpcSession, type DevframePtyExecuteOptions, type DevframePtyTerminalSession, type DevframeRpcClientFunctions, type DevframeRpcServerFunctions, type DevframeRpcSharedStates, type DevframeServerCommandEntry, type DevframeServerCommandInput, type DevframeTerminalSession, type DevframeTerminalSessionBase, type DevframeTerminalStatus, type DevframeTerminalsHost, type DevframeViewAction, type DevframeViewBuiltin, type DevframeViewCustomRender, type DevframeViewGroup, type DevframeViewHost, type DevframeViewIframe, type DevframeViewJsonRender, type DevframeViewLauncher, type DevframeViewLauncherStatus, type EntriesToObject, type EventEmitter, type EventUnsubscribe, type EventsMap, type JsonRenderElement, type JsonRenderSpec, type JsonRenderer, type PartialWithoutId, type RemoteConnectionInfo, type RemoteDockOptions, type RpcBroadcastOptions, type RpcDefinitionsFilter, type RpcDefinitionsToFunctions, type RpcFunctionsHost, type RpcSharedStateGetOptions, type RpcSharedStateHost, type RpcStreamingChannel, type RpcStreamingChannelOptions, type RpcStreamingHost, type Thenable, defineCommand, defineDockEntry, defineHubRpcFunction, defineJsonRenderSpec };
23
+ export { type ClientScriptEntry, type ConnectionMeta, type CreateHubContextOptions, DEFAULT_CATEGORIES_ORDER, type DevframeCapabilities, type DevframeChildProcessExecuteOptions, type DevframeChildProcessOutput, type DevframeChildProcessResult, type DevframeChildProcessTerminalSession, type DevframeClientCommand, type DevframeCommandBase, type DevframeCommandEntry, type DevframeCommandHandle, type DevframeCommandKeybinding, type DevframeCommandShortcutOverrides, type DevframeCommandsHost, type DevframeCommandsHostEvents, type DevframeDiagnosticsDefinition, type DevframeDiagnosticsHost, type DevframeDiagnosticsLogger, type DevframeDockActivation, type DevframeDockEntriesGrouped, type DevframeDockEntry, type DevframeDockEntryBase, type DevframeDockEntryCategory, type DevframeDockEntryIcon, type DevframeDockEntryRegistry, type DevframeDockUserEntry, type DevframeDocksActiveState, type DevframeDocksHost, type DevframeDocksUserSettings, type DevframeHost, type DevframeHubContext, type DevframeMessageElementPosition, type DevframeMessageEntry, type DevframeMessageEntryFrom, type DevframeMessageEntryInput, type DevframeMessageFilePosition, type DevframeMessageHandle, type DevframeMessageLevel, type DevframeMessageShortcutInput, type DevframeMessagesClient, type DevframeMessagesHost, type DevframeMessagesLevelShortcuts, type DevframeMessagesListDelta, type DevframeNodeRpcSession, type DevframePtyExecuteOptions, type DevframePtyTerminalSession, type DevframeRpcClientFunctions, type DevframeRpcServerFunctions, type DevframeRpcSharedStates, type DevframeServerCommandEntry, type DevframeServerCommandInput, type DevframeTerminalSession, type DevframeTerminalSessionBase, type DevframeTerminalStatus, type DevframeTerminalsHost, type DevframeViewAction, type DevframeViewBuiltin, type DevframeViewCustomRender, type DevframeViewGroup, type DevframeViewHost, type DevframeViewIframe, type DevframeViewJsonRender, type DevframeViewLauncher, type DevframeViewLauncherStatus, type EntriesToObject, type EventEmitter, type EventUnsubscribe, type EventsMap, type FrameSubTabsConfig, type JsonRenderElement, type JsonRenderSpec, type JsonRenderer, type NavTarget, type PartialWithoutId, type RemoteConnectionInfo, type RemoteDockOptions, type RpcBroadcastOptions, type RpcDefinitionsFilter, type RpcDefinitionsToFunctions, type RpcFunctionsHost, type RpcSharedStateGetOptions, type RpcSharedStateHost, type RpcStreamingChannel, type RpcStreamingChannelOptions, type RpcStreamingHost, type Thenable, defineCommand, defineDockEntry, defineHubRpcFunction, defineJsonRenderSpec };
package/dist/index.mjs CHANGED
@@ -1,2 +1,3 @@
1
+ import { DEFAULT_CATEGORIES_ORDER } from "./constants.mjs";
1
2
  import { i as defineJsonRenderSpec, n as defineDockEntry, r as defineHubRpcFunction, t as defineCommand } from "./define-Pbx8dsKz.mjs";
2
- export { defineCommand, defineDockEntry, defineHubRpcFunction, defineJsonRenderSpec };
3
+ export { DEFAULT_CATEGORIES_ORDER, defineCommand, defineDockEntry, defineHubRpcFunction, defineJsonRenderSpec };
@@ -1,5 +1,6 @@
1
- import { C as DevframeMessagesHost$1, T as DevframeMessagesListDelta, _ as DevframeMessageEntryInput, c as DevframePtyExecuteOptions, d as DevframeTerminalSessionBase, h as DevframeMessageEntry, i as DevframeChildProcessExecuteOptions, l as DevframePtyTerminalSession, n as DevframeHubContext, p as DevframeTerminalsHost$1, r as createHubContext, s as DevframeChildProcessTerminalSession, t as CreateHubContextOptions, u as DevframeTerminalSession, x as DevframeMessageShortcutInput, y as DevframeMessageHandle } from "../context-CNKFzYdA.mjs";
2
- import { D as DevframeViewIframe, S as DevframeDocksHost$1, a as DevframeCommandHandle, b as DevframeDockUserEntry, c as DevframeCommandsHost$1, d as DevframeServerCommandInput, f as ClientScriptEntry, h as DevframeDockEntry, t as DevframeDocksUserSettings, u as DevframeServerCommandEntry } from "../settings-C5cAtNdE.mjs";
1
+ import { D as DevframeViewIframe, S as DevframeDocksHost$1, a as DevframeCommandHandle, b as DevframeDockUserEntry, c as DevframeCommandsHost$1, d as DevframeServerCommandInput, f as ClientScriptEntry, h as DevframeDockEntry, t as DevframeDocksUserSettings, u as DevframeServerCommandEntry } from "../settings-Brw6_lEi.mjs";
2
+ import { DEFAULT_CATEGORIES_ORDER } from "../constants.mjs";
3
+ import { C as DevframeMessagesHost$1, T as DevframeMessagesListDelta, _ as DevframeMessageEntryInput, c as DevframePtyExecuteOptions, d as DevframeTerminalSessionBase, h as DevframeMessageEntry, i as DevframeChildProcessExecuteOptions, l as DevframePtyTerminalSession, n as DevframeHubContext, p as DevframeTerminalsHost$1, r as createHubContext, s as DevframeChildProcessTerminalSession, t as CreateHubContextOptions, u as DevframeTerminalSession, x as DevframeMessageShortcutInput, y as DevframeMessageHandle } from "../context-CCyi44Ep.mjs";
3
4
  import { RpcFunctionDefinitionAny } from "devframe/rpc";
4
5
  import { DevframeDefinition } from "devframe/types";
5
6
  import { SharedState } from "devframe/utils/shared-state";
@@ -382,4 +383,4 @@ declare const builtinHubRpcDeclarations: readonly RpcFunctionDefinitionAny[];
382
383
  */
383
384
  declare function createSimpleClientScript(fn: string | ((ctx: any) => void)): ClientScriptEntry;
384
385
  //#endregion
385
- export { CreateHubContextOptions, DevframeCommandsHost, DevframeDocksHost, DevframeHubContext, DevframeMessagesHost, DevframeTerminalsHost, MountDevframeOptions, builtinHubRpcDeclarations, createHubContext, createSimpleClientScript, hubCommandsExecute, hubDocksActivate, hubMessagesAdd, hubMessagesClear, hubMessagesRemove, hubMessagesUpdate, hubTerminalsRemove, hubTerminalsResize, hubTerminalsRestart, hubTerminalsTerminate, hubTerminalsWrite, mountDevframe };
386
+ export { CreateHubContextOptions, DEFAULT_CATEGORIES_ORDER, DevframeCommandsHost, DevframeDocksHost, DevframeHubContext, DevframeMessagesHost, DevframeTerminalsHost, MountDevframeOptions, builtinHubRpcDeclarations, createHubContext, createSimpleClientScript, hubCommandsExecute, hubDocksActivate, hubMessagesAdd, hubMessagesClear, hubMessagesRemove, hubMessagesUpdate, hubTerminalsRemove, hubTerminalsResize, hubTerminalsRestart, hubTerminalsTerminate, hubTerminalsWrite, mountDevframe };
@@ -1,5 +1,5 @@
1
+ import { DEFAULT_CATEGORIES_ORDER, DEFAULT_STATE_USER_SETTINGS } from "../constants.mjs";
1
2
  import { r as defineHubRpcFunction } from "../define-Pbx8dsKz.mjs";
2
- import { DEFAULT_STATE_USER_SETTINGS } from "../constants.mjs";
3
3
  import { REMOTE_CONNECTION_KEY } from "devframe/constants";
4
4
  import { createEventEmitter } from "devframe/utils/events";
5
5
  import { createHostContext, createStorage } from "devframe/node";
@@ -6611,4 +6611,4 @@ function createSimpleClientScript(fn) {
6611
6611
  };
6612
6612
  }
6613
6613
  //#endregion
6614
- export { DevframeCommandsHost, DevframeDocksHost, DevframeMessagesHost, DevframeTerminalsHost, builtinHubRpcDeclarations, createHubContext, createSimpleClientScript, hubCommandsExecute, hubDocksActivate, hubMessagesAdd, hubMessagesClear, hubMessagesRemove, hubMessagesUpdate, hubTerminalsRemove, hubTerminalsResize, hubTerminalsRestart, hubTerminalsTerminate, hubTerminalsWrite, mountDevframe };
6614
+ export { DEFAULT_CATEGORIES_ORDER, DevframeCommandsHost, DevframeDocksHost, DevframeMessagesHost, DevframeTerminalsHost, builtinHubRpcDeclarations, createHubContext, createSimpleClientScript, hubCommandsExecute, hubDocksActivate, hubMessagesAdd, hubMessagesClear, hubMessagesRemove, hubMessagesUpdate, hubTerminalsRemove, hubTerminalsResize, hubTerminalsRestart, hubTerminalsTerminate, hubTerminalsWrite, mountDevframe };
@@ -76,7 +76,7 @@ interface DevframeDockActivation {
76
76
  interface DevframeDocksActiveState {
77
77
  activation: DevframeDockActivation | null;
78
78
  }
79
- type DevframeDockEntryCategory = 'app' | 'framework' | 'web' | 'advanced' | 'default' | '~builtin' | (string & {});
79
+ type DevframeDockEntryCategory = 'framework' | 'app' | 'ui' | 'data' | 'web' | 'performance' | 'advanced' | 'docs' | 'default' | '~builtin' | (string & {});
80
80
  type DevframeDockEntryIcon = string | {
81
81
  light: string;
82
82
  dark: string;
@@ -92,7 +92,19 @@ interface DevframeDockEntryBase {
92
92
  */
93
93
  defaultOrder?: number;
94
94
  /**
95
- * The category of the entry
95
+ * The category of the entry — a field with a dual role that depends on
96
+ * whether {@link groupId} resolves to a registered {@link DevframeViewGroup}:
97
+ *
98
+ * - **Ungrouped (or orphan) entry** — `category` is the entry's OUTER bucket
99
+ * on the dock bar, ordered by {@link import('../constants').DEFAULT_CATEGORIES_ORDER}.
100
+ * - **Grouped entry** (a `groupId` that resolves to a registered group) —
101
+ * the OUTER bucket is instead the group's own `category`, and this field is
102
+ * reinterpreted as the entry's IN-GROUP sub-category, used to sub-divide and
103
+ * sort members inside the group's popover / sub-navigation.
104
+ *
105
+ * Falls back to `'default'` when omitted — both as an outer bucket and, for a
106
+ * grouped member, as its in-group sub-bucket.
107
+ *
96
108
  * @default 'default'
97
109
  */
98
110
  category?: DevframeDockEntryCategory;
@@ -118,8 +130,14 @@ interface DevframeDockEntryBase {
118
130
  *
119
131
  * This is a flat pointer — membership, not containment. The entry stays an
120
132
  * independently-registered, top-level entry; only its rendering is grouped
121
- * downstream. If the referenced group is never registered, the entry renders
122
- * as a normal top-level entry (orphan tolerance).
133
+ * downstream.
134
+ *
135
+ * When the referenced group **is** registered, it supplies the entry's OUTER
136
+ * dock-bar category (the group's own {@link category}), and this entry's own
137
+ * {@link category} is reinterpreted as its IN-GROUP sub-category. When the
138
+ * referenced group is **never** registered, the entry renders as a normal
139
+ * top-level entry and falls back to using its own {@link category} as the
140
+ * outer bucket (orphan tolerance).
123
141
  *
124
142
  * @see {@link DevframeViewGroup}
125
143
  */
@@ -144,12 +162,37 @@ interface DevframeViewIframe extends DevframeDockEntryBase {
144
162
  * The id of the iframe, if multiple tabs is assigned with the same id, the iframe will be shared.
145
163
  *
146
164
  * When not provided, it would be treated as a unique frame.
165
+ *
166
+ * `frameId` is an axis independent of {@link DevframeDockEntryBase.groupId}:
167
+ * it decides *which* iframe element a dock renders into (and which soft-nav
168
+ * pool it joins), while `groupId` only affects dock-bar grouping. Docks that
169
+ * share a `frameId` may live in one group, several groups, or none.
147
170
  */
148
171
  frameId?: string;
149
172
  /**
150
173
  * Optional client script to import into the iframe
151
174
  */
152
175
  clientScript?: ClientScriptEntry;
176
+ /**
177
+ * Soft-navigation target within a shared frame. Set on a **member** dock
178
+ * (one of several docks sharing a {@link frameId}) to describe which internal
179
+ * view the embedded app should show. The hub treats {@link NavTarget.path} as
180
+ * opaque and hands it to the frame's nav shim over `postMessage`; switching to
181
+ * this dock performs client-side navigation instead of reloading the iframe.
182
+ *
183
+ * The anchor dock (the one flagged with {@link subTabs}) leaves this unset.
184
+ */
185
+ navTarget?: NavTarget;
186
+ /**
187
+ * Marks this iframe as a **shared-frame anchor** whose sub-tabs are discovered
188
+ * at runtime over a host↔iframe `postMessage` protocol. The client host
189
+ * auto-attaches the frame-nav adapter when this iframe mounts: it runs the
190
+ * ready handshake, materializes one client-only member dock per reported tab
191
+ * (grouped/soft-navigated via this anchor's {@link frameId}), and drives the
192
+ * live navigation loop. Absent a shim, the anchor simply renders as a single
193
+ * plain iframe dock.
194
+ */
195
+ subTabs?: FrameSubTabsConfig;
153
196
  /**
154
197
  * Enable remote-UI mode: the hub injects a connection descriptor
155
198
  * (WS URL + pre-approved auth token) into the iframe URL so a hosted
@@ -163,6 +206,35 @@ interface DevframeViewIframe extends DevframeDockEntryBase {
163
206
  */
164
207
  remote?: boolean | RemoteDockOptions;
165
208
  }
209
+ /**
210
+ * A structured, soft-navigation target within a shared frame. `path` is opaque
211
+ * to the hub — the embedded app maps it onto its own router.
212
+ *
213
+ * Kept to `path` + `query` so the shape survives shared-state's `Immutable`
214
+ * projection cleanly (a `DevframeViewIframe` must still narrow back from its
215
+ * immutable form). An `unknown`/recursive history-`state` field breaks that
216
+ * round-trip, so richer per-navigation state is intentionally out of scope for
217
+ * now — carry it in `query` or the app's own store.
218
+ */
219
+ interface NavTarget {
220
+ path: string;
221
+ query?: Record<string, string | readonly string[]>;
222
+ }
223
+ /**
224
+ * Configuration for a {@link DevframeViewIframe.subTabs shared-frame anchor}.
225
+ */
226
+ interface FrameSubTabsConfig {
227
+ /** Transport for tab discovery + the live nav loop. */
228
+ protocol: 'postmessage';
229
+ /**
230
+ * How long (ms) the adapter waits for the shim's `ready` before treating the
231
+ * frame as having no shim (the anchor renders as a single plain iframe dock,
232
+ * and a navigation requested before readiness hard-navigates).
233
+ *
234
+ * @default 3000
235
+ */
236
+ handshakeTimeoutMs?: number;
237
+ }
166
238
  interface RemoteDockOptions {
167
239
  /**
168
240
  * How to pass the connection descriptor to the hosted page.
@@ -282,6 +354,12 @@ interface DevframeViewJsonRender extends DevframeDockEntryBase {
282
354
  * through the same `register`/`update`/`values` machinery as every other entry,
283
355
  * keyed by `id`.
284
356
  *
357
+ * The group's `category` is the OUTER bucket for the group button itself AND
358
+ * for every one of its members — a member's own `category` no longer decides
359
+ * its outer bucket, but is reinterpreted as an in-group sub-category that
360
+ * sub-divides and sorts members inside this group. A group with no `category`
361
+ * buckets itself and its members under `'default'`.
362
+ *
285
363
  * Grouping is one level deep: a group entry must not itself set `groupId`.
286
364
  */
287
365
  interface DevframeViewGroup extends DevframeDockEntryBase {
@@ -451,4 +529,4 @@ interface DevframeDocksUserSettings {
451
529
  commandShortcuts: DevframeCommandShortcutOverrides;
452
530
  }
453
531
  //#endregion
454
- export { DevframeViewLauncherStatus as A, DevframeViewAction as C, DevframeViewIframe as D, DevframeViewGroup as E, JsonRenderer as F, RemoteDockOptions as M, JsonRenderElement as N, DevframeViewJsonRender as O, JsonRenderSpec as P, DevframeDocksHost as S, DevframeViewCustomRender as T, DevframeDockEntryCategory as _, DevframeCommandHandle as a, DevframeDockUserEntry as b, DevframeCommandsHost as c, DevframeServerCommandInput as d, ClientScriptEntry as f, DevframeDockEntryBase as g, DevframeDockEntry as h, DevframeCommandEntry as i, RemoteConnectionInfo as j, DevframeViewLauncher as k, DevframeCommandsHostEvents as l, DevframeDockEntriesGrouped as m, DevframeClientCommand as n, DevframeCommandKeybinding as o, DevframeDockActivation as p, DevframeCommandBase as r, DevframeCommandShortcutOverrides as s, DevframeDocksUserSettings as t, DevframeServerCommandEntry as u, DevframeDockEntryIcon as v, DevframeViewBuiltin as w, DevframeDocksActiveState as x, DevframeDockEntryRegistry as y };
532
+ export { DevframeViewLauncherStatus as A, DevframeViewAction as C, DevframeViewIframe as D, DevframeViewGroup as E, JsonRenderElement as F, JsonRenderSpec as I, JsonRenderer as L, NavTarget as M, RemoteConnectionInfo as N, DevframeViewJsonRender as O, RemoteDockOptions as P, DevframeDocksHost as S, DevframeViewCustomRender as T, DevframeDockEntryCategory as _, DevframeCommandHandle as a, DevframeDockUserEntry as b, DevframeCommandsHost as c, DevframeServerCommandInput as d, ClientScriptEntry as f, DevframeDockEntryBase as g, DevframeDockEntry as h, DevframeCommandEntry as i, FrameSubTabsConfig as j, DevframeViewLauncher as k, DevframeCommandsHostEvents as l, DevframeDockEntriesGrouped as m, DevframeClientCommand as n, DevframeCommandKeybinding as o, DevframeDockActivation as p, DevframeCommandBase as r, DevframeCommandShortcutOverrides as s, DevframeDocksUserSettings as t, DevframeServerCommandEntry as u, DevframeDockEntryIcon as v, DevframeViewBuiltin as w, DevframeDocksActiveState as x, DevframeDockEntryRegistry as y };
@@ -1,4 +1,4 @@
1
- import { C as DevframeMessagesHost, S as DevframeMessagesClient, T as DevframeMessagesListDelta, _ as DevframeMessageEntryInput, a as DevframeChildProcessOutput, b as DevframeMessageLevel, c as DevframePtyExecuteOptions, d as DevframeTerminalSessionBase, f as DevframeTerminalStatus, g as DevframeMessageEntryFrom, h as DevframeMessageEntry, i as DevframeChildProcessExecuteOptions, l as DevframePtyTerminalSession, m as DevframeMessageElementPosition, n as DevframeHubContext, o as DevframeChildProcessResult, p as DevframeTerminalsHost, s as DevframeChildProcessTerminalSession, t as CreateHubContextOptions, u as DevframeTerminalSession, v as DevframeMessageFilePosition, w as DevframeMessagesLevelShortcuts, x as DevframeMessageShortcutInput, y as DevframeMessageHandle } from "../context-CNKFzYdA.mjs";
2
- import { A as DevframeViewLauncherStatus, C as DevframeViewAction, D as DevframeViewIframe, E as DevframeViewGroup, F as JsonRenderer, M as RemoteDockOptions, N as JsonRenderElement, O as DevframeViewJsonRender, P as JsonRenderSpec, S as DevframeDocksHost, T as DevframeViewCustomRender, _ as DevframeDockEntryCategory, a as DevframeCommandHandle, b as DevframeDockUserEntry, c as DevframeCommandsHost, d as DevframeServerCommandInput, f as ClientScriptEntry, g as DevframeDockEntryBase, h as DevframeDockEntry, i as DevframeCommandEntry, j as RemoteConnectionInfo, k as DevframeViewLauncher, l as DevframeCommandsHostEvents, m as DevframeDockEntriesGrouped, n as DevframeClientCommand, o as DevframeCommandKeybinding, p as DevframeDockActivation, r as DevframeCommandBase, s as DevframeCommandShortcutOverrides, t as DevframeDocksUserSettings, u as DevframeServerCommandEntry, v as DevframeDockEntryIcon, w as DevframeViewBuiltin, x as DevframeDocksActiveState, y as DevframeDockEntryRegistry } from "../settings-C5cAtNdE.mjs";
3
- import { C as RpcStreamingChannel, E as Thenable, S as RpcSharedStateHost, T as RpcStreamingHost, _ as RpcBroadcastOptions, a as DevframeDiagnosticsLogger, b as RpcFunctionsHost, c as DevframeRpcClientFunctions, d as DevframeViewHost, f as EntriesToObject, g as PartialWithoutId, h as EventsMap, i as DevframeDiagnosticsHost, l as DevframeRpcServerFunctions, m as EventUnsubscribe, n as DevframeCapabilities, o as DevframeHost, p as EventEmitter, r as DevframeDiagnosticsDefinition, s as DevframeNodeRpcSession, t as ConnectionMeta, u as DevframeRpcSharedStates, v as RpcDefinitionsFilter, w as RpcStreamingChannelOptions, x as RpcSharedStateGetOptions, y as RpcDefinitionsToFunctions } from "../index-BeoLMW0z.mjs";
4
- export { ClientScriptEntry, type ConnectionMeta, type CreateHubContextOptions, type DevframeCapabilities, DevframeChildProcessExecuteOptions, DevframeChildProcessOutput, DevframeChildProcessResult, DevframeChildProcessTerminalSession, DevframeClientCommand, DevframeCommandBase, DevframeCommandEntry, DevframeCommandHandle, DevframeCommandKeybinding, DevframeCommandShortcutOverrides, DevframeCommandsHost, DevframeCommandsHostEvents, type DevframeDiagnosticsDefinition, type DevframeDiagnosticsHost, type DevframeDiagnosticsLogger, DevframeDockActivation, DevframeDockEntriesGrouped, DevframeDockEntry, DevframeDockEntryBase, DevframeDockEntryCategory, DevframeDockEntryIcon, DevframeDockEntryRegistry, DevframeDockUserEntry, DevframeDocksActiveState, DevframeDocksHost, DevframeDocksUserSettings, type DevframeHost, type DevframeHubContext, DevframeMessageElementPosition, DevframeMessageEntry, DevframeMessageEntryFrom, DevframeMessageEntryInput, DevframeMessageFilePosition, DevframeMessageHandle, DevframeMessageLevel, DevframeMessageShortcutInput, DevframeMessagesClient, DevframeMessagesHost, DevframeMessagesLevelShortcuts, DevframeMessagesListDelta, type DevframeNodeRpcSession, DevframePtyExecuteOptions, DevframePtyTerminalSession, type DevframeRpcClientFunctions, type DevframeRpcServerFunctions, type DevframeRpcSharedStates, DevframeServerCommandEntry, DevframeServerCommandInput, DevframeTerminalSession, DevframeTerminalSessionBase, DevframeTerminalStatus, DevframeTerminalsHost, DevframeViewAction, DevframeViewBuiltin, DevframeViewCustomRender, DevframeViewGroup, type DevframeViewHost, DevframeViewIframe, DevframeViewJsonRender, DevframeViewLauncher, DevframeViewLauncherStatus, type EntriesToObject, type EventEmitter, type EventUnsubscribe, type EventsMap, JsonRenderElement, JsonRenderSpec, JsonRenderer, type PartialWithoutId, RemoteConnectionInfo, RemoteDockOptions, type RpcBroadcastOptions, type RpcDefinitionsFilter, type RpcDefinitionsToFunctions, type RpcFunctionsHost, type RpcSharedStateGetOptions, type RpcSharedStateHost, type RpcStreamingChannel, type RpcStreamingChannelOptions, type RpcStreamingHost, type Thenable };
1
+ import { A as DevframeViewLauncherStatus, C as DevframeViewAction, D as DevframeViewIframe, E as DevframeViewGroup, F as JsonRenderElement, I as JsonRenderSpec, L as JsonRenderer, M as NavTarget, N as RemoteConnectionInfo, O as DevframeViewJsonRender, P as RemoteDockOptions, S as DevframeDocksHost, T as DevframeViewCustomRender, _ as DevframeDockEntryCategory, a as DevframeCommandHandle, b as DevframeDockUserEntry, c as DevframeCommandsHost, d as DevframeServerCommandInput, f as ClientScriptEntry, g as DevframeDockEntryBase, h as DevframeDockEntry, i as DevframeCommandEntry, j as FrameSubTabsConfig, k as DevframeViewLauncher, l as DevframeCommandsHostEvents, m as DevframeDockEntriesGrouped, n as DevframeClientCommand, o as DevframeCommandKeybinding, p as DevframeDockActivation, r as DevframeCommandBase, s as DevframeCommandShortcutOverrides, t as DevframeDocksUserSettings, u as DevframeServerCommandEntry, v as DevframeDockEntryIcon, w as DevframeViewBuiltin, x as DevframeDocksActiveState, y as DevframeDockEntryRegistry } from "../settings-Brw6_lEi.mjs";
2
+ import { C as DevframeMessagesHost, S as DevframeMessagesClient, T as DevframeMessagesListDelta, _ as DevframeMessageEntryInput, a as DevframeChildProcessOutput, b as DevframeMessageLevel, c as DevframePtyExecuteOptions, d as DevframeTerminalSessionBase, f as DevframeTerminalStatus, g as DevframeMessageEntryFrom, h as DevframeMessageEntry, i as DevframeChildProcessExecuteOptions, l as DevframePtyTerminalSession, m as DevframeMessageElementPosition, n as DevframeHubContext, o as DevframeChildProcessResult, p as DevframeTerminalsHost, s as DevframeChildProcessTerminalSession, t as CreateHubContextOptions, u as DevframeTerminalSession, v as DevframeMessageFilePosition, w as DevframeMessagesLevelShortcuts, x as DevframeMessageShortcutInput, y as DevframeMessageHandle } from "../context-CCyi44Ep.mjs";
3
+ import { C as RpcStreamingChannel, E as Thenable, S as RpcSharedStateHost, T as RpcStreamingHost, _ as RpcBroadcastOptions, a as DevframeDiagnosticsLogger, b as RpcFunctionsHost, c as DevframeRpcClientFunctions, d as DevframeViewHost, f as EntriesToObject, g as PartialWithoutId, h as EventsMap, i as DevframeDiagnosticsHost, l as DevframeRpcServerFunctions, m as EventUnsubscribe, n as DevframeCapabilities, o as DevframeHost, p as EventEmitter, r as DevframeDiagnosticsDefinition, s as DevframeNodeRpcSession, t as ConnectionMeta, u as DevframeRpcSharedStates, v as RpcDefinitionsFilter, w as RpcStreamingChannelOptions, x as RpcSharedStateGetOptions, y as RpcDefinitionsToFunctions } from "../index-Dyam2SU1.mjs";
4
+ export { ClientScriptEntry, type ConnectionMeta, type CreateHubContextOptions, type DevframeCapabilities, DevframeChildProcessExecuteOptions, DevframeChildProcessOutput, DevframeChildProcessResult, DevframeChildProcessTerminalSession, DevframeClientCommand, DevframeCommandBase, DevframeCommandEntry, DevframeCommandHandle, DevframeCommandKeybinding, DevframeCommandShortcutOverrides, DevframeCommandsHost, DevframeCommandsHostEvents, type DevframeDiagnosticsDefinition, type DevframeDiagnosticsHost, type DevframeDiagnosticsLogger, DevframeDockActivation, DevframeDockEntriesGrouped, DevframeDockEntry, DevframeDockEntryBase, DevframeDockEntryCategory, DevframeDockEntryIcon, DevframeDockEntryRegistry, DevframeDockUserEntry, DevframeDocksActiveState, DevframeDocksHost, DevframeDocksUserSettings, type DevframeHost, type DevframeHubContext, DevframeMessageElementPosition, DevframeMessageEntry, DevframeMessageEntryFrom, DevframeMessageEntryInput, DevframeMessageFilePosition, DevframeMessageHandle, DevframeMessageLevel, DevframeMessageShortcutInput, DevframeMessagesClient, DevframeMessagesHost, DevframeMessagesLevelShortcuts, DevframeMessagesListDelta, type DevframeNodeRpcSession, DevframePtyExecuteOptions, DevframePtyTerminalSession, type DevframeRpcClientFunctions, type DevframeRpcServerFunctions, type DevframeRpcSharedStates, DevframeServerCommandEntry, DevframeServerCommandInput, DevframeTerminalSession, DevframeTerminalSessionBase, DevframeTerminalStatus, DevframeTerminalsHost, DevframeViewAction, DevframeViewBuiltin, DevframeViewCustomRender, DevframeViewGroup, type DevframeViewHost, DevframeViewIframe, DevframeViewJsonRender, DevframeViewLauncher, DevframeViewLauncherStatus, type EntriesToObject, type EventEmitter, type EventUnsubscribe, type EventsMap, FrameSubTabsConfig, JsonRenderElement, JsonRenderSpec, JsonRenderer, NavTarget, type PartialWithoutId, RemoteConnectionInfo, RemoteDockOptions, type RpcBroadcastOptions, type RpcDefinitionsFilter, type RpcDefinitionsToFunctions, type RpcFunctionsHost, type RpcSharedStateGetOptions, type RpcSharedStateHost, type RpcStreamingChannel, type RpcStreamingChannelOptions, type RpcStreamingHost, type Thenable };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@devframes/hub",
3
3
  "type": "module",
4
- "version": "0.7.9",
4
+ "version": "0.7.11",
5
5
  "description": "Framework-neutral hub layer for devframe — docks, terminals, messages, commands.",
6
6
  "author": "Anthony Fu <anthonyfu117@hotmail.com>",
7
7
  "license": "MIT",
@@ -33,7 +33,7 @@
33
33
  "dist"
34
34
  ],
35
35
  "peerDependencies": {
36
- "devframe": "0.7.9"
36
+ "devframe": "0.7.11"
37
37
  },
38
38
  "dependencies": {
39
39
  "birpc": "^4.0.0",
@@ -48,7 +48,7 @@
48
48
  "@types/node": "^26.1.1",
49
49
  "mlly": "^1.8.2",
50
50
  "tsdown": "^0.22.12",
51
- "devframe": "0.7.9"
51
+ "devframe": "0.7.11"
52
52
  },
53
53
  "scripts": {
54
54
  "build": "tsdown",