@devframes/hub 0.5.4 → 0.6.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/index.d.mts +68 -4
- package/dist/client/index.mjs +282 -3
- package/dist/constants.d.mts +1 -1
- package/dist/context-DVh4gk8f.d.mts +331 -0
- package/dist/index.d.mts +4 -4
- package/dist/index.mjs +1 -1
- package/dist/node/index.d.mts +125 -3
- package/dist/node/index.mjs +325 -20
- package/dist/settings-B9YjSEcl.d.mts +348 -0
- package/dist/types/index.d.mts +4 -4
- package/package.json +10 -6
- package/dist/context-Dox-G9vt.d.mts +0 -433
- package/dist/settings-Bp5Ax6Os.d.mts +0 -131
- /package/dist/{define-tHP6fX6A.mjs → define-Dp-x6d09.mjs} +0 -0
- /package/dist/{index-BWTfvdqa.d.mts → index-Dic9q4eN.d.mts} +0 -0
package/dist/node/index.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { r as defineHubRpcFunction } from "../define-
|
|
1
|
+
import { r as defineHubRpcFunction } from "../define-Dp-x6d09.mjs";
|
|
2
2
|
import { DEFAULT_STATE_USER_SETTINGS } from "../constants.mjs";
|
|
3
3
|
import { REMOTE_CONNECTION_KEY } from "devframe/constants";
|
|
4
|
+
import { createEventEmitter } from "devframe/utils/events";
|
|
4
5
|
import { createHostContext, createStorage } from "devframe/node";
|
|
5
6
|
import { debounce } from "perfect-debounce";
|
|
6
|
-
import { createEventEmitter } from "devframe/utils/events";
|
|
7
7
|
import { defineDiagnostics } from "nostics";
|
|
8
8
|
import { colors } from "devframe/utils/colors";
|
|
9
9
|
import { ansiFormatter } from "nostics/formatters/ansi";
|
|
@@ -33,8 +33,14 @@ const diagnostics = defineDiagnostics({
|
|
|
33
33
|
why: (p) => `Dock with id "${p.id}" is already registered`,
|
|
34
34
|
fix: "Use the `force` parameter to overwrite an existing registration."
|
|
35
35
|
},
|
|
36
|
-
DF8101: {
|
|
37
|
-
|
|
36
|
+
DF8101: {
|
|
37
|
+
why: (p) => `Cannot change the id of dock "${p.id}" to "${p.attempted}". Dock ids are immutable once registered`,
|
|
38
|
+
fix: (p) => `Remove \`id\` from the patch to keep updating "${p.id}", or call register() with the full entry to add "${p.attempted}" as a new dock.`
|
|
39
|
+
},
|
|
40
|
+
DF8102: {
|
|
41
|
+
why: (p) => `Dock with id "${p.id}" is not registered and cannot be updated`,
|
|
42
|
+
fix: (p) => `Call register() to add "${p.id}" as a new dock, or check the id for typos.`
|
|
43
|
+
},
|
|
38
44
|
DF8103: {
|
|
39
45
|
why: (p) => `Dock entry "${p.id}" cannot set groupId to its own id`,
|
|
40
46
|
fix: "Point groupId at a different group entry, or omit it."
|
|
@@ -43,10 +49,19 @@ const diagnostics = defineDiagnostics({
|
|
|
43
49
|
why: (p) => `Dock group "${p.id}" cannot itself belong to a group (nested groups are unsupported)`,
|
|
44
50
|
fix: "Remove groupId from the group entry; nest members one level only."
|
|
45
51
|
},
|
|
52
|
+
DF8105: {
|
|
53
|
+
why: (p) => `Devframe "${p.name}" (id "${p.id}") is already mounted on this hub`,
|
|
54
|
+
fix: "Each devframe is deduplicated by id. Set `duplicationStrategy: \"duplicate\"` on the definition to let instances coexist, `\"silent\"` to drop duplicates quietly, or `\"throw\"` to surface them as errors."
|
|
55
|
+
},
|
|
46
56
|
DF8200: { why: (p) => `Terminal session with id "${p.id}" already registered` },
|
|
47
57
|
DF8201: { why: (p) => `Terminal session with id "${p.id}" not registered` },
|
|
58
|
+
DF8202: {
|
|
59
|
+
why: (p) => `Terminal session "${p.id}" does not accept input`,
|
|
60
|
+
fix: "Spawn it via ctx.terminals.startPtySession() to get an interactive, writable session."
|
|
61
|
+
},
|
|
62
|
+
DF8203: { why: (p) => `Failed to spawn PTY session for "${p.command}": ${p.reason}` },
|
|
48
63
|
DF8400: { why: (p) => `Command "${p.id}" is already registered` },
|
|
49
|
-
DF8401: { why: "Cannot change the id of a command. Use register() to add new commands
|
|
64
|
+
DF8401: { why: "Cannot change the id of a command. Use register() to add new commands" },
|
|
50
65
|
DF8402: { why: (p) => `Command "${p.id}" is not registered` },
|
|
51
66
|
DF8403: {
|
|
52
67
|
why: (p) => `Command id "${p.id}" is already used by another command or child command`,
|
|
@@ -267,7 +282,10 @@ var DevframeDocksHost = class {
|
|
|
267
282
|
this.views.set(view.id, view);
|
|
268
283
|
this.events.emit("dock:entry:updated", view);
|
|
269
284
|
return { update: (patch) => {
|
|
270
|
-
if (patch.id && patch.id !== view.id) throw diagnostics.DF8101(
|
|
285
|
+
if (patch.id && patch.id !== view.id) throw diagnostics.DF8101({
|
|
286
|
+
id: view.id,
|
|
287
|
+
attempted: patch.id
|
|
288
|
+
});
|
|
271
289
|
this.update(Object.assign(this.views.get(view.id), patch));
|
|
272
290
|
} };
|
|
273
291
|
}
|
|
@@ -306,13 +324,6 @@ var DevframeDocksHost = class {
|
|
|
306
324
|
//#region src/node/host-messages.ts
|
|
307
325
|
const MAX_ENTRIES = 1e3;
|
|
308
326
|
const MAX_REMOVALS = 1e3;
|
|
309
|
-
function recordRemoval(removals, id, time) {
|
|
310
|
-
removals.push({
|
|
311
|
-
id,
|
|
312
|
-
time
|
|
313
|
-
});
|
|
314
|
-
if (removals.length > MAX_REMOVALS) removals.splice(0, removals.length - MAX_REMOVALS);
|
|
315
|
-
}
|
|
316
327
|
var DevframeMessagesHost = class {
|
|
317
328
|
context;
|
|
318
329
|
entries = /* @__PURE__ */ new Map();
|
|
@@ -323,9 +334,25 @@ var DevframeMessagesHost = class {
|
|
|
323
334
|
removals = [];
|
|
324
335
|
_autoDeleteTimers = /* @__PURE__ */ new Map();
|
|
325
336
|
_clock = 0;
|
|
337
|
+
/**
|
|
338
|
+
* The tick of the newest removal record dropped from the capped
|
|
339
|
+
* `removals` log — cursors older than this can't get a reliable delta
|
|
340
|
+
* and fall back to a full snapshot in {@link listSince}.
|
|
341
|
+
*/
|
|
342
|
+
_removalsTrimmedAt = 0;
|
|
326
343
|
_tick() {
|
|
327
344
|
return ++this._clock;
|
|
328
345
|
}
|
|
346
|
+
_recordRemoval(id, time) {
|
|
347
|
+
this.removals.push({
|
|
348
|
+
id,
|
|
349
|
+
time
|
|
350
|
+
});
|
|
351
|
+
if (this.removals.length > MAX_REMOVALS) {
|
|
352
|
+
const dropped = this.removals.splice(0, this.removals.length - MAX_REMOVALS);
|
|
353
|
+
this._removalsTrimmedAt = dropped[dropped.length - 1].time;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
329
356
|
constructor(context) {
|
|
330
357
|
this.context = context;
|
|
331
358
|
}
|
|
@@ -385,18 +412,75 @@ var DevframeMessagesHost = class {
|
|
|
385
412
|
}
|
|
386
413
|
this.entries.delete(id);
|
|
387
414
|
this.lastModified.delete(id);
|
|
388
|
-
|
|
415
|
+
this._recordRemoval(id, this._tick());
|
|
389
416
|
this.events.emit("message:removed", id);
|
|
390
417
|
}
|
|
418
|
+
info(message, extra) {
|
|
419
|
+
return this.add({
|
|
420
|
+
...extra,
|
|
421
|
+
message,
|
|
422
|
+
level: "info"
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
warn(message, extra) {
|
|
426
|
+
return this.add({
|
|
427
|
+
...extra,
|
|
428
|
+
message,
|
|
429
|
+
level: "warn"
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
error(message, extra) {
|
|
433
|
+
return this.add({
|
|
434
|
+
...extra,
|
|
435
|
+
message,
|
|
436
|
+
level: "error"
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
success(message, extra) {
|
|
440
|
+
return this.add({
|
|
441
|
+
...extra,
|
|
442
|
+
message,
|
|
443
|
+
level: "success"
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
debug(message, extra) {
|
|
447
|
+
return this.add({
|
|
448
|
+
...extra,
|
|
449
|
+
message,
|
|
450
|
+
level: "debug"
|
|
451
|
+
});
|
|
452
|
+
}
|
|
391
453
|
async clear() {
|
|
392
454
|
for (const timer of this._autoDeleteTimers.values()) clearTimeout(timer);
|
|
393
455
|
this._autoDeleteTimers.clear();
|
|
394
456
|
const tick = this._tick();
|
|
395
|
-
for (const id of this.entries.keys())
|
|
457
|
+
for (const id of this.entries.keys()) this._recordRemoval(id, tick);
|
|
396
458
|
this.entries.clear();
|
|
397
459
|
this.lastModified.clear();
|
|
398
460
|
this.events.emit("message:cleared");
|
|
399
461
|
}
|
|
462
|
+
listSince(since) {
|
|
463
|
+
const version = this._clock;
|
|
464
|
+
if (since == null || since < this._removalsTrimmedAt || since > version) return {
|
|
465
|
+
entries: Array.from(this.entries.values()),
|
|
466
|
+
removedIds: [],
|
|
467
|
+
version,
|
|
468
|
+
full: true
|
|
469
|
+
};
|
|
470
|
+
const entries = [];
|
|
471
|
+
for (const [id, entry] of this.entries) {
|
|
472
|
+
const mod = this.lastModified.get(id);
|
|
473
|
+
if (mod != null && mod > since) entries.push(entry);
|
|
474
|
+
}
|
|
475
|
+
const removedIds = [];
|
|
476
|
+
for (const removal of this.removals) if (removal.time > since) removedIds.push(removal.id);
|
|
477
|
+
return {
|
|
478
|
+
entries,
|
|
479
|
+
removedIds,
|
|
480
|
+
version,
|
|
481
|
+
full: false
|
|
482
|
+
};
|
|
483
|
+
}
|
|
400
484
|
_createHandle(id) {
|
|
401
485
|
const host = this;
|
|
402
486
|
return {
|
|
@@ -419,6 +503,8 @@ var DevframeMessagesHost = class {
|
|
|
419
503
|
*/
|
|
420
504
|
const TERMINAL_STREAM_CHANNEL = "devframe:terminals";
|
|
421
505
|
const TERMINAL_REPLAY_WINDOW = 1e3;
|
|
506
|
+
/** TERM handed to spawned PTYs; also used to reject fallback process labels. */
|
|
507
|
+
const PTY_TERM_NAME = "xterm-256color";
|
|
422
508
|
var DevframeTerminalsHost = class {
|
|
423
509
|
context;
|
|
424
510
|
sessions = /* @__PURE__ */ new Map();
|
|
@@ -576,10 +662,123 @@ var DevframeTerminalsHost = class {
|
|
|
576
662
|
this.register(session);
|
|
577
663
|
return Promise.resolve(session);
|
|
578
664
|
}
|
|
665
|
+
async startPtySession(executeOptions, terminal) {
|
|
666
|
+
if (this.sessions.has(terminal.id)) throw diagnostics.DF8200({ id: terminal.id });
|
|
667
|
+
const { spawn } = await import("zigpty");
|
|
668
|
+
const cols = executeOptions.cols ?? 80;
|
|
669
|
+
const rows = executeOptions.rows ?? 24;
|
|
670
|
+
let controller;
|
|
671
|
+
let pty;
|
|
672
|
+
let runId = 0;
|
|
673
|
+
let streamClosed = false;
|
|
674
|
+
const closeStream = () => {
|
|
675
|
+
if (streamClosed) return;
|
|
676
|
+
streamClosed = true;
|
|
677
|
+
try {
|
|
678
|
+
controller?.close();
|
|
679
|
+
} catch {}
|
|
680
|
+
};
|
|
681
|
+
const errorStream = (error) => {
|
|
682
|
+
if (streamClosed) return;
|
|
683
|
+
streamClosed = true;
|
|
684
|
+
try {
|
|
685
|
+
controller?.error(error);
|
|
686
|
+
} catch {}
|
|
687
|
+
};
|
|
688
|
+
const stream = new ReadableStream({
|
|
689
|
+
start(_controller) {
|
|
690
|
+
controller = _controller;
|
|
691
|
+
},
|
|
692
|
+
cancel() {
|
|
693
|
+
pty?.kill();
|
|
694
|
+
pty = void 0;
|
|
695
|
+
closeStream();
|
|
696
|
+
}
|
|
697
|
+
});
|
|
698
|
+
const spawnPty = () => {
|
|
699
|
+
const currentRun = ++runId;
|
|
700
|
+
const proc = spawn(executeOptions.command, executeOptions.args ?? [], {
|
|
701
|
+
name: PTY_TERM_NAME,
|
|
702
|
+
cols,
|
|
703
|
+
rows,
|
|
704
|
+
cwd: executeOptions.cwd ?? process$1.cwd(),
|
|
705
|
+
env: {
|
|
706
|
+
TERM: PTY_TERM_NAME,
|
|
707
|
+
COLORTERM: "truecolor",
|
|
708
|
+
FORCE_COLOR: "1",
|
|
709
|
+
...executeOptions.env ?? {}
|
|
710
|
+
}
|
|
711
|
+
});
|
|
712
|
+
proc.onData((data) => {
|
|
713
|
+
if (streamClosed || currentRun !== runId) return;
|
|
714
|
+
controller?.enqueue(typeof data === "string" ? data : data.toString("utf8"));
|
|
715
|
+
});
|
|
716
|
+
proc.onExit(() => {
|
|
717
|
+
if (currentRun === runId) closeStream();
|
|
718
|
+
});
|
|
719
|
+
return proc;
|
|
720
|
+
};
|
|
721
|
+
try {
|
|
722
|
+
pty = spawnPty();
|
|
723
|
+
} catch (error) {
|
|
724
|
+
errorStream(error);
|
|
725
|
+
throw diagnostics.DF8203({
|
|
726
|
+
command: executeOptions.command,
|
|
727
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
const session = {
|
|
731
|
+
...terminal,
|
|
732
|
+
status: "running",
|
|
733
|
+
interactive: true,
|
|
734
|
+
stream,
|
|
735
|
+
type: "pty",
|
|
736
|
+
executeOptions,
|
|
737
|
+
write: (data) => {
|
|
738
|
+
try {
|
|
739
|
+
pty?.write(data);
|
|
740
|
+
} catch {}
|
|
741
|
+
},
|
|
742
|
+
resize: (nextCols, nextRows) => {
|
|
743
|
+
try {
|
|
744
|
+
pty?.resize(Math.max(1, nextCols), Math.max(1, nextRows));
|
|
745
|
+
} catch {}
|
|
746
|
+
},
|
|
747
|
+
getProcessName: () => {
|
|
748
|
+
try {
|
|
749
|
+
const name = pty?.process;
|
|
750
|
+
return name && name !== PTY_TERM_NAME ? name : void 0;
|
|
751
|
+
} catch {
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
},
|
|
755
|
+
terminate: async () => {
|
|
756
|
+
pty?.kill();
|
|
757
|
+
pty = void 0;
|
|
758
|
+
closeStream();
|
|
759
|
+
},
|
|
760
|
+
restart: async () => {
|
|
761
|
+
pty?.kill();
|
|
762
|
+
pty = spawnPty();
|
|
763
|
+
}
|
|
764
|
+
};
|
|
765
|
+
this.register(session);
|
|
766
|
+
return session;
|
|
767
|
+
}
|
|
579
768
|
};
|
|
580
769
|
//#endregion
|
|
581
770
|
//#region src/node/rpc-builtins.ts
|
|
582
771
|
/**
|
|
772
|
+
* Resolve an interactive (PTY) terminal session by id, or throw. Sessions
|
|
773
|
+
* spawned via `startChildProcess` are output-only and are rejected here.
|
|
774
|
+
*/
|
|
775
|
+
function resolveInteractiveSession(sessions, id) {
|
|
776
|
+
const session = sessions.get(id);
|
|
777
|
+
if (!session) throw diagnostics.DF8201({ id });
|
|
778
|
+
if (typeof session.write !== "function") throw diagnostics.DF8202({ id });
|
|
779
|
+
return session;
|
|
780
|
+
}
|
|
781
|
+
/**
|
|
583
782
|
* `hub:commands:execute` — Invoke a registered server command by id. The
|
|
584
783
|
* arguments after `id` are forwarded to the command's `handler(...)`.
|
|
585
784
|
* Returns whatever the handler returns.
|
|
@@ -595,12 +794,85 @@ const hubCommandsExecute = defineHubRpcFunction({
|
|
|
595
794
|
} })
|
|
596
795
|
});
|
|
597
796
|
/**
|
|
797
|
+
* `hub:messages:add` — Add a message from a browser client into the hub's
|
|
798
|
+
* messages subsystem. Marked `from: 'browser'`. Returns the serializable
|
|
799
|
+
* entry (the mutation handle stays server-side).
|
|
800
|
+
*
|
|
801
|
+
* Pairs with the client-side {@link import('../client').createDevframeClientHost}
|
|
802
|
+
* context, whose `messages` client dispatches through these built-ins so a
|
|
803
|
+
* dock client script can report into the same feed the server writes to.
|
|
804
|
+
*/
|
|
805
|
+
const hubMessagesAdd = defineHubRpcFunction({
|
|
806
|
+
name: "hub:messages:add",
|
|
807
|
+
type: "action",
|
|
808
|
+
jsonSerializable: true,
|
|
809
|
+
setup: (context) => ({ async handler(input) {
|
|
810
|
+
return (await context.messages.add({
|
|
811
|
+
...input,
|
|
812
|
+
from: "browser"
|
|
813
|
+
})).entry;
|
|
814
|
+
} })
|
|
815
|
+
});
|
|
816
|
+
/** `hub:messages:update` — Patch a message by id; returns the updated entry (or `undefined`). */
|
|
817
|
+
const hubMessagesUpdate = defineHubRpcFunction({
|
|
818
|
+
name: "hub:messages:update",
|
|
819
|
+
type: "action",
|
|
820
|
+
jsonSerializable: true,
|
|
821
|
+
setup: (context) => ({ async handler(id, patch) {
|
|
822
|
+
return context.messages.update(id, patch);
|
|
823
|
+
} })
|
|
824
|
+
});
|
|
825
|
+
/** `hub:messages:remove` — Remove a message by id. */
|
|
826
|
+
const hubMessagesRemove = defineHubRpcFunction({
|
|
827
|
+
name: "hub:messages:remove",
|
|
828
|
+
type: "action",
|
|
829
|
+
setup: (context) => ({ async handler(id) {
|
|
830
|
+
await context.messages.remove(id);
|
|
831
|
+
} })
|
|
832
|
+
});
|
|
833
|
+
/** `hub:messages:clear` — Remove every message. */
|
|
834
|
+
const hubMessagesClear = defineHubRpcFunction({
|
|
835
|
+
name: "hub:messages:clear",
|
|
836
|
+
type: "action",
|
|
837
|
+
setup: (context) => ({ async handler() {
|
|
838
|
+
await context.messages.clear();
|
|
839
|
+
} })
|
|
840
|
+
});
|
|
841
|
+
/**
|
|
842
|
+
* `hub:terminals:write` — Send input to an interactive PTY session spawned
|
|
843
|
+
* via `ctx.terminals.startPtySession`. Lets a hub-aware terminal UI (e.g. the
|
|
844
|
+
* terminals plugin) drive a session owned by another plugin.
|
|
845
|
+
*/
|
|
846
|
+
const hubTerminalsWrite = defineHubRpcFunction({
|
|
847
|
+
name: "hub:terminals:write",
|
|
848
|
+
type: "action",
|
|
849
|
+
setup: (context) => ({ async handler(id, data) {
|
|
850
|
+
resolveInteractiveSession(context.terminals.sessions, id).write(data);
|
|
851
|
+
} })
|
|
852
|
+
});
|
|
853
|
+
/** `hub:terminals:resize` — Resize an interactive PTY session by id. */
|
|
854
|
+
const hubTerminalsResize = defineHubRpcFunction({
|
|
855
|
+
name: "hub:terminals:resize",
|
|
856
|
+
type: "action",
|
|
857
|
+
setup: (context) => ({ async handler(id, cols, rows) {
|
|
858
|
+
resolveInteractiveSession(context.terminals.sessions, id).resize(cols, rows);
|
|
859
|
+
} })
|
|
860
|
+
});
|
|
861
|
+
/**
|
|
598
862
|
* Framework-neutral RPC declarations auto-registered by
|
|
599
863
|
* {@link createHubContext}. Provide additional RPCs by passing your own
|
|
600
864
|
* array via `CreateHubContextOptions.builtinRpcDeclarations`; the hub's
|
|
601
865
|
* list is prepended automatically.
|
|
602
866
|
*/
|
|
603
|
-
const builtinHubRpcDeclarations = [
|
|
867
|
+
const builtinHubRpcDeclarations = [
|
|
868
|
+
hubCommandsExecute,
|
|
869
|
+
hubMessagesAdd,
|
|
870
|
+
hubMessagesUpdate,
|
|
871
|
+
hubMessagesRemove,
|
|
872
|
+
hubMessagesClear,
|
|
873
|
+
hubTerminalsWrite,
|
|
874
|
+
hubTerminalsResize
|
|
875
|
+
];
|
|
604
876
|
//#endregion
|
|
605
877
|
//#region src/node/context.ts
|
|
606
878
|
/**
|
|
@@ -680,6 +952,18 @@ async function createHubContext(options) {
|
|
|
680
952
|
//#endregion
|
|
681
953
|
//#region src/node/mount-devframe.ts
|
|
682
954
|
/**
|
|
955
|
+
* Find the next free dock id derived from `baseId`. Returns `baseId`
|
|
956
|
+
* when it is unused, otherwise appends `-2`, `-3`, … until a free slot
|
|
957
|
+
* is found. Used by the `'duplicate'` strategy so co-existing instances
|
|
958
|
+
* never collide in the dock registry.
|
|
959
|
+
*/
|
|
960
|
+
function nextAvailableDockId(views, baseId) {
|
|
961
|
+
if (!views.has(baseId)) return baseId;
|
|
962
|
+
let n = 2;
|
|
963
|
+
while (views.has(`${baseId}-${n}`)) n++;
|
|
964
|
+
return `${baseId}-${n}`;
|
|
965
|
+
}
|
|
966
|
+
/**
|
|
683
967
|
* Framework-neutral primitive — mounts a {@link DevframeDefinition} as a
|
|
684
968
|
* dock inside a hub-aware context: serves the devframe's SPA at the
|
|
685
969
|
* resolved base path, synthesizes an iframe dock entry from the
|
|
@@ -690,10 +974,31 @@ async function createHubContext(options) {
|
|
|
690
974
|
* Vite `Plugin` whose `devtools.setup` ultimately delegates here.
|
|
691
975
|
*/
|
|
692
976
|
async function mountDevframe(ctx, d, options = {}) {
|
|
693
|
-
const
|
|
694
|
-
|
|
977
|
+
const strategy = d.duplicationStrategy ?? "warn";
|
|
978
|
+
const isDuplicate = ctx.docks.views.has(d.id);
|
|
979
|
+
if (isDuplicate && strategy !== "duplicate") {
|
|
980
|
+
if (strategy === "throw") throw diagnostics.DF8105({
|
|
981
|
+
id: d.id,
|
|
982
|
+
name: d.name
|
|
983
|
+
});
|
|
984
|
+
if (strategy === "warn") diagnostics.DF8105({
|
|
985
|
+
id: d.id,
|
|
986
|
+
name: d.name
|
|
987
|
+
});
|
|
988
|
+
return;
|
|
989
|
+
}
|
|
990
|
+
const id = isDuplicate ? nextAvailableDockId(ctx.docks.views, d.id) : d.id;
|
|
991
|
+
const base = options.base ?? (id === d.id ? resolveBasePath(d, "hosted") : resolveBasePath({
|
|
992
|
+
...d,
|
|
993
|
+
id,
|
|
994
|
+
basePath: void 0
|
|
995
|
+
}, "hosted"));
|
|
996
|
+
if (d.cli?.distDir) {
|
|
997
|
+
ctx.views.hostStatic(base, resolve(d.cli.distDir));
|
|
998
|
+
await ctx.host.mountConnectionMeta?.(base);
|
|
999
|
+
}
|
|
695
1000
|
ctx.docks.register({
|
|
696
|
-
id
|
|
1001
|
+
id,
|
|
697
1002
|
title: d.name,
|
|
698
1003
|
icon: d.icon ?? "ph:plug-duotone",
|
|
699
1004
|
...options.dock,
|
|
@@ -6142,4 +6447,4 @@ function createSimpleClientScript(fn) {
|
|
|
6142
6447
|
};
|
|
6143
6448
|
}
|
|
6144
6449
|
//#endregion
|
|
6145
|
-
export { DevframeCommandsHost, DevframeDocksHost, DevframeMessagesHost, DevframeTerminalsHost, builtinHubRpcDeclarations, createHubContext, createSimpleClientScript, hubCommandsExecute, mountDevframe };
|
|
6450
|
+
export { DevframeCommandsHost, DevframeDocksHost, DevframeMessagesHost, DevframeTerminalsHost, builtinHubRpcDeclarations, createHubContext, createSimpleClientScript, hubCommandsExecute, hubMessagesAdd, hubMessagesClear, hubMessagesRemove, hubMessagesUpdate, hubTerminalsResize, hubTerminalsWrite, mountDevframe };
|