devframe 0.1.19 → 0.1.20

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 (67) hide show
  1. package/README.md +2 -2
  2. package/dist/adapters/build.d.mts +1 -1
  3. package/dist/adapters/build.mjs +9 -6
  4. package/dist/adapters/cli.d.mts +1 -1
  5. package/dist/adapters/cli.mjs +1 -1
  6. package/dist/adapters/dev.d.mts +2 -2
  7. package/dist/adapters/dev.mjs +1 -1
  8. package/dist/adapters/embedded.d.mts +1 -1
  9. package/dist/adapters/kit.d.mts +1 -1
  10. package/dist/adapters/mcp.d.mts +1 -1
  11. package/dist/adapters/mcp.mjs +6 -3
  12. package/dist/adapters/vite.d.mts +1 -1
  13. package/dist/adapters/vite.mjs +1 -1
  14. package/dist/client/index.d.mts +42 -6
  15. package/dist/client/index.mjs +1673 -2
  16. package/dist/constants.d.mts +1 -1
  17. package/dist/{context-BsNZMCnr.mjs → context-BfvbAyGk.mjs} +428 -40
  18. package/dist/{dev-Djy5hbgs.mjs → dev-B8i_CBlQ.mjs} +6 -5
  19. package/dist/{devtool-CIqONpYU.d.mts → devtool-Bm6zZAw5.d.mts} +365 -27
  20. package/dist/host-h3-BMvrFzIJ.mjs +24 -0
  21. package/dist/{index-BwrLhNmz.d.mts → index-BCo03GEF.d.mts} +1 -1
  22. package/dist/index.d.mts +4 -4
  23. package/dist/node/index.d.mts +44 -7
  24. package/dist/node/index.mjs +5 -5
  25. package/dist/recipes/open-helpers.d.mts +1 -1
  26. package/dist/recipes/open-helpers.mjs +3 -1
  27. package/dist/rpc/index.d.mts +2 -2
  28. package/dist/rpc/index.mjs +2 -2
  29. package/dist/rpc/transports/ws-client.d.mts +1 -1
  30. package/dist/rpc/transports/ws-client.mjs +1 -1
  31. package/dist/rpc/transports/ws-server.d.mts +1 -1
  32. package/dist/rpc/transports/ws-server.mjs +1 -1
  33. package/dist/{rpc-D7LxIh8t.mjs → rpc-INbWfHoX.mjs} +1 -1
  34. package/dist/{serialization-BN2ZQEE9.mjs → serialization-DwKi05Pn.mjs} +1 -1
  35. package/dist/{server-CaUeMcAh.d.mts → server-DksyT-um.d.mts} +1 -1
  36. package/dist/{server-DrBxa6ZV.mjs → server-qRRM8t3v.mjs} +27 -2
  37. package/dist/{static-dump-cyGfMmRf.mjs → static-dump-C1aVSwxY.mjs} +1 -1
  38. package/dist/types/index.d.mts +4 -4
  39. package/dist/utils/events.d.mts +1 -1
  40. package/dist/utils/shared-state.d.mts +2 -2
  41. package/dist/utils/shared-state.mjs +1 -1
  42. package/dist/utils/state.d.mts +2 -1
  43. package/dist/utils/state.mjs +1 -1
  44. package/dist/utils/streaming-channel.d.mts +2 -0
  45. package/dist/utils/streaming-channel.mjs +255 -0
  46. package/dist/utils/when.d.mts +1 -1
  47. package/dist/{ws-client-DOYwYluO.d.mts → ws-client-DQySVfF_.d.mts} +1 -1
  48. package/dist/{ws-server-DHMeNOY_.d.mts → ws-server-VQqESKAs.d.mts} +13 -1
  49. package/package.json +9 -17
  50. package/skills/devframe/README.md +13 -0
  51. package/skills/devframe/SKILL.md +452 -0
  52. package/skills/devframe/templates/counter-devtool.ts +29 -0
  53. package/skills/devframe/templates/spa-devtool.ts +33 -0
  54. package/skills/devframe/templates/vite-client.ts +11 -0
  55. package/dist/client-C6w_NshP.mjs +0 -1569
  56. package/dist/helpers/nuxt/index.d.mts +0 -46
  57. package/dist/helpers/nuxt/index.mjs +0 -58
  58. package/dist/helpers/nuxt/runtime/plugin.client.d.mts +0 -8
  59. package/dist/helpers/nuxt/runtime/plugin.client.mjs +0 -12
  60. package/dist/host-h3-w3c0t8ZO.mjs +0 -18
  61. package/dist/immer-HjMAm3b6.mjs +0 -894
  62. /package/dist/{_shared-BcPXmcjq.mjs → _shared-S-Ujqz_L.mjs} +0 -0
  63. /package/dist/{main-CuGOfqoX.mjs → main-DpINGndA.mjs} +0 -0
  64. /package/dist/{open-JfacLHs0.mjs → open-BtOOEldu.mjs} +0 -0
  65. /package/dist/{transports-DSV5_5QM.mjs → transports-BPUzHhI2.mjs} +0 -0
  66. /package/dist/{types-gWbe-b2R.d.mts → types-ag029cAe.d.mts} +0 -0
  67. /package/dist/{when-BAE663Hv.d.mts → when-aBBXAEh5.d.mts} +0 -0
@@ -1,4 +1,4 @@
1
- import { V as DevToolsDocksUserSettings } from "./devtool-CIqONpYU.mjs";
1
+ import { Z as DevToolsDocksUserSettings } from "./devtool-Bm6zZAw5.mjs";
2
2
 
3
3
  //#region src/constants.d.ts
4
4
  declare const DEVTOOLS_MOUNT_PATH = "/.devtools/";
@@ -1,11 +1,12 @@
1
1
  import { t as import_dist } from "./human-id-CHS0s28X.mjs";
2
- import { o as RpcFunctionsCollectorBase } from "./rpc-D7LxIh8t.mjs";
3
- import { s as diagnostics$1 } from "./serialization-BN2ZQEE9.mjs";
2
+ import { o as RpcFunctionsCollectorBase } from "./rpc-INbWfHoX.mjs";
3
+ import { s as diagnostics$1 } from "./serialization-DwKi05Pn.mjs";
4
4
  import { defineRpcFunction } from "./index.mjs";
5
5
  import { createEventEmitter } from "./utils/events.mjs";
6
6
  import { DEFAULT_STATE_USER_SETTINGS, REMOTE_CONNECTION_KEY } from "./constants.mjs";
7
7
  import { nanoid } from "./utils/nanoid.mjs";
8
8
  import { createSharedState } from "./utils/shared-state.mjs";
9
+ import { createStreamReader, createStreamSink } from "./utils/streaming-channel.mjs";
9
10
  import { builtinModules } from "node:module";
10
11
  import { consoleReporter, createLogger, defineDiagnostics } from "logs-sdk";
11
12
  import fs, { existsSync } from "node:fs";
@@ -18,7 +19,6 @@ import v8 from "node:v8";
18
19
  import { format, formatWithOptions, inspect } from "node:util";
19
20
  import c from "ansis";
20
21
  import { ansiFormatter } from "logs-sdk/formatters/ansi";
21
- import { homedir } from "node:os";
22
22
  import { isatty } from "node:tty";
23
23
  //#region src/node/auth-revoke.ts
24
24
  /**
@@ -38,7 +38,7 @@ async function revokeActiveConnectionsForToken(context, token) {
38
38
  }
39
39
  if (affectedSessionIds.size === 0) return;
40
40
  await rpcHost.broadcast({
41
- method: "devtoolskit:internal:auth:revoked",
41
+ method: "devframe:auth:revoked",
42
42
  args: [],
43
43
  filter: (client) => affectedSessionIds.has(client.$meta.id)
44
44
  });
@@ -5575,7 +5575,7 @@ const ContextUtils = { createSimpleClientScript(fn) {
5575
5575
  //#endregion
5576
5576
  //#region src/node/diagnostics.ts
5577
5577
  const diagnostics = defineDiagnostics({
5578
- docsBase: "https://devtools.vite.dev/devframe/errors",
5578
+ docsBase: "https://devfra.me/errors",
5579
5579
  codes: {
5580
5580
  DF0001: {
5581
5581
  message: (p) => `Dock with id "${p.id}" is already registered`,
@@ -5610,6 +5610,23 @@ const diagnostics = defineDiagnostics({
5610
5610
  message: "`ctx.logs` is deprecated and will be removed in a future release. Use `ctx.messages` instead.",
5611
5611
  hint: "Replace any access to `ctx.logs` (or `context.logs`) with `ctx.messages`. The runtime behavior is identical.",
5612
5612
  level: "warn"
5613
+ },
5614
+ DF0029: {
5615
+ message: (p) => `Stream "${p.channel}#${p.id}" dropped ${p.dropped} chunk(s) after exceeding the client high-water mark.`,
5616
+ hint: "The consumer is too slow for the producer. Raise `highWaterMark` on the subscription, slow the producer, or batch chunks.",
5617
+ level: "warn"
5618
+ },
5619
+ DF0030: {
5620
+ message: (p) => `Stream "${p.channel}#${p.id}" is unknown — no producer has called \`channel.start({ id: "${p.id}" })\`.`,
5621
+ hint: "Ensure the server-side producer is running before clients subscribe, or check for typos in the stream id."
5622
+ },
5623
+ DF0031: {
5624
+ message: (p) => `Cannot write to closed stream "${p.channel}#${p.id}".`,
5625
+ hint: "Track the producer lifecycle — guard writes with the `stream.signal.aborted` flag."
5626
+ },
5627
+ DF0032: {
5628
+ message: (p) => `Streaming channel "${p.channel}" is already registered.`,
5629
+ hint: "Each channel name must be unique within a context. Pick a different name or reuse the existing channel handle."
5613
5630
  }
5614
5631
  }
5615
5632
  });
@@ -5903,7 +5920,7 @@ const internalContextMap = /* @__PURE__ */ new WeakMap();
5903
5920
  function getInternalContext(context) {
5904
5921
  if (!internalContextMap.has(context)) {
5905
5922
  const storage = createStorage({
5906
- filepath: join(homedir(), ".vite/devtools/auth.json"),
5923
+ filepath: join(context.host.getStorageDir("global"), "auth.json"),
5907
5924
  initialValue: { trusted: {} }
5908
5925
  });
5909
5926
  const remoteTokens = /* @__PURE__ */ new Map();
@@ -5982,8 +5999,8 @@ var DevToolsDockHost = class {
5982
5999
  this.context = context;
5983
6000
  }
5984
6001
  async init() {
5985
- this.userSettings = await this.context.rpc.sharedState.get("devtoolskit:internal:user-settings", { sharedState: createStorage({
5986
- filepath: join(this.context.workspaceRoot, "node_modules/.vite/devtools/settings.json"),
6002
+ this.userSettings = await this.context.rpc.sharedState.get("devframe:user-settings", { sharedState: createStorage({
6003
+ filepath: join(this.context.host.getStorageDir("workspace"), "settings.json"),
5987
6004
  initialValue: DEFAULT_STATE_USER_SETTINGS()
5988
6005
  }) });
5989
6006
  }
@@ -6074,7 +6091,6 @@ var DevToolsDockHost = class {
6074
6091
  token,
6075
6092
  options
6076
6093
  });
6077
- if (view.when === void 0) view.when = "mode != build";
6078
6094
  }
6079
6095
  };
6080
6096
  //#endregion
@@ -6333,7 +6349,8 @@ function createDebug(namespace, options) {
6333
6349
  enable(process.env.DEBUG || "");
6334
6350
  //#endregion
6335
6351
  //#region src/node/rpc-shared-state.ts
6336
- const debug = createDebug("vite:devtools:rpc:state:changed");
6352
+ const debug$1 = createDebug("vite:devtools:rpc:state:changed");
6353
+ const debugSubscribe = createDebug("vite:devtools:rpc:state:subscribe");
6337
6354
  function createRpcSharedStateServerHost(rpc) {
6338
6355
  const sharedState = /* @__PURE__ */ new Map();
6339
6356
  const keyAddedListeners = /* @__PURE__ */ new Set();
@@ -6341,12 +6358,12 @@ function createRpcSharedStateServerHost(rpc) {
6341
6358
  const offs = [];
6342
6359
  offs.push(state.on("updated", (fullState, patches, syncId) => {
6343
6360
  if (patches) {
6344
- debug("patch", {
6361
+ debug$1("patch", {
6345
6362
  key,
6346
6363
  syncId
6347
6364
  });
6348
6365
  rpc.broadcast({
6349
- method: "devtoolskit:internal:rpc:client-state:patch",
6366
+ method: "devframe:rpc:client-state:patch",
6350
6367
  args: [
6351
6368
  key,
6352
6369
  patches,
@@ -6355,12 +6372,12 @@ function createRpcSharedStateServerHost(rpc) {
6355
6372
  filter: (client) => client.$meta.subscribedStates.has(key)
6356
6373
  });
6357
6374
  } else {
6358
- debug("updated", {
6375
+ debug$1("updated", {
6359
6376
  key,
6360
6377
  syncId
6361
6378
  });
6362
6379
  rpc.broadcast({
6363
- method: "devtoolskit:internal:rpc:client-state:updated",
6380
+ method: "devframe:rpc:client-state:updated",
6364
6381
  args: [
6365
6382
  key,
6366
6383
  fullState,
@@ -6374,11 +6391,11 @@ function createRpcSharedStateServerHost(rpc) {
6374
6391
  for (const off of offs) off();
6375
6392
  };
6376
6393
  }
6377
- return {
6394
+ const host = {
6378
6395
  get: async (key, options) => {
6379
6396
  if (sharedState.has(key)) return sharedState.get(key);
6380
6397
  if (options?.initialValue === void 0 && options?.sharedState === void 0) throw logger.DF0013({ key }).throw();
6381
- debug("new-state", key);
6398
+ debug$1("new-state", key);
6382
6399
  const state = options.sharedState ?? createSharedState({
6383
6400
  initialValue: options.initialValue,
6384
6401
  enablePatches: false
@@ -6398,6 +6415,344 @@ function createRpcSharedStateServerHost(rpc) {
6398
6415
  };
6399
6416
  }
6400
6417
  };
6418
+ rpc.register({
6419
+ name: "devframe:rpc:server-state:subscribe",
6420
+ type: "event",
6421
+ handler(key) {
6422
+ const session = rpc.getCurrentRpcSession();
6423
+ if (!session) return;
6424
+ debugSubscribe("subscribe", {
6425
+ key,
6426
+ session: session.meta.id
6427
+ });
6428
+ session.meta.subscribedStates.add(key);
6429
+ }
6430
+ });
6431
+ rpc.register({
6432
+ name: "devframe:rpc:server-state:get",
6433
+ type: "query",
6434
+ handler: async (key) => {
6435
+ if (!sharedState.has(key)) return void 0;
6436
+ return (await host.get(key)).value();
6437
+ },
6438
+ dump: () => ({ inputs: host.keys().map((key) => [key]) })
6439
+ });
6440
+ rpc.register({
6441
+ name: "devframe:rpc:server-state:set",
6442
+ type: "query",
6443
+ handler: async (key, value, syncId) => {
6444
+ (await host.get(key, { initialValue: value })).mutate(() => value, syncId);
6445
+ }
6446
+ });
6447
+ rpc.register({
6448
+ name: "devframe:rpc:server-state:patch",
6449
+ type: "query",
6450
+ handler: async (key, patches, syncId) => {
6451
+ if (!sharedState.has(key)) return;
6452
+ (await host.get(key)).patch(patches, syncId);
6453
+ }
6454
+ });
6455
+ return host;
6456
+ }
6457
+ //#endregion
6458
+ //#region src/node/rpc-streaming.ts
6459
+ const debug = createDebug("vite:devtools:rpc:streaming");
6460
+ const STREAM_KEY_SEPARATOR = "";
6461
+ function streamKey(channel, id) {
6462
+ return `${channel}${STREAM_KEY_SEPARATOR}${id}`;
6463
+ }
6464
+ /**
6465
+ * Build the server-side streaming host. Mirrors the layout of
6466
+ * `createRpcSharedStateServerHost` — registers a fixed set of internal
6467
+ * RPC methods (`subscribe` / `unsubscribe` / `cancel`) once, then per-channel
6468
+ * state lives in a `Map<channelName, ChannelState>`.
6469
+ */
6470
+ function createRpcStreamingServerHost(rpc) {
6471
+ const channels = /* @__PURE__ */ new Map();
6472
+ function findStream(channelName, id) {
6473
+ return channels.get(channelName)?.streams.get(id);
6474
+ }
6475
+ function freeStreamNow(state, id) {
6476
+ const record = state.streams.get(id);
6477
+ if (!record) return;
6478
+ if (record.retentionTimer) {
6479
+ clearTimeout(record.retentionTimer);
6480
+ record.retentionTimer = void 0;
6481
+ }
6482
+ for (const off of record.unbinders) off();
6483
+ state.streams.delete(id);
6484
+ debug("freed", state.name, id);
6485
+ }
6486
+ function maybeFreeStream(state, id) {
6487
+ const record = state.streams.get(id);
6488
+ if (!record) return;
6489
+ if (!record.sink.closed || record.subscribers.size > 0) return;
6490
+ const retention = state.options.closedStreamRetention;
6491
+ if (retention <= 0) {
6492
+ freeStreamNow(state, id);
6493
+ return;
6494
+ }
6495
+ if (record.retentionTimer) return;
6496
+ record.retentionTimer = setTimeout(freeStreamNow, retention, state, id);
6497
+ }
6498
+ function cancelRetention(record) {
6499
+ if (record.retentionTimer) {
6500
+ clearTimeout(record.retentionTimer);
6501
+ record.retentionTimer = void 0;
6502
+ }
6503
+ }
6504
+ rpc.register({
6505
+ name: "devframe:streaming:subscribe",
6506
+ type: "event",
6507
+ handler(channelName, id, opts) {
6508
+ const state = channels.get(channelName);
6509
+ if (!state) {
6510
+ logger.DF0030({
6511
+ channel: channelName,
6512
+ id
6513
+ }).log();
6514
+ return;
6515
+ }
6516
+ const record = state.streams.get(id);
6517
+ if (!record) {
6518
+ logger.DF0030({
6519
+ channel: channelName,
6520
+ id
6521
+ }).log();
6522
+ return;
6523
+ }
6524
+ const session = rpc.getCurrentRpcSession();
6525
+ if (!session) return;
6526
+ const key = streamKey(channelName, id);
6527
+ session.meta.subscribedStreams ??= /* @__PURE__ */ new Set();
6528
+ session.meta.subscribedStreams.add(key);
6529
+ record.subscribers.add(session.meta);
6530
+ cancelRetention(record);
6531
+ const afterSeq = opts?.afterSeq ?? 0;
6532
+ for (const buffered of record.sink.buffer) if (buffered.seq > afterSeq) rpc.broadcast({
6533
+ method: "devframe:streaming:chunk",
6534
+ args: [
6535
+ channelName,
6536
+ id,
6537
+ buffered.seq,
6538
+ buffered.chunk
6539
+ ],
6540
+ event: true,
6541
+ optional: true,
6542
+ filter: (client) => client.$meta === session.meta
6543
+ });
6544
+ if (record.sink.closed) rpc.broadcast({
6545
+ method: "devframe:streaming:end",
6546
+ args: [
6547
+ channelName,
6548
+ id,
6549
+ void 0
6550
+ ],
6551
+ event: true,
6552
+ optional: true,
6553
+ filter: (client) => client.$meta === session.meta
6554
+ });
6555
+ }
6556
+ });
6557
+ rpc.register({
6558
+ name: "devframe:streaming:unsubscribe",
6559
+ type: "event",
6560
+ handler(channelName, id) {
6561
+ const state = channels.get(channelName);
6562
+ const record = state?.streams.get(id);
6563
+ const session = rpc.getCurrentRpcSession();
6564
+ if (!session) return;
6565
+ session.meta.subscribedStreams?.delete(streamKey(channelName, id));
6566
+ if (state && record) {
6567
+ record.subscribers.delete(session.meta);
6568
+ maybeFreeStream(state, id);
6569
+ }
6570
+ }
6571
+ });
6572
+ rpc.register({
6573
+ name: "devframe:streaming:cancel",
6574
+ type: "event",
6575
+ handler(channelName, id) {
6576
+ const record = findStream(channelName, id);
6577
+ if (!record) return;
6578
+ const session = rpc.getCurrentRpcSession();
6579
+ if (!session) return;
6580
+ record.subscribers.delete(session.meta);
6581
+ session.meta.subscribedStreams?.delete(streamKey(channelName, id));
6582
+ if (record.subscribers.size === 0) record.sink.abort("cancelled by client");
6583
+ }
6584
+ });
6585
+ rpc.register({
6586
+ name: "devframe:streaming:upload-chunk",
6587
+ type: "event",
6588
+ handler(channelName, id, seq, chunk) {
6589
+ const record = channels.get(channelName)?.inbound.get(id);
6590
+ if (!record) {
6591
+ logger.DF0030({
6592
+ channel: channelName,
6593
+ id
6594
+ }).log();
6595
+ return;
6596
+ }
6597
+ if (!record.uploaderMeta) {
6598
+ const session = rpc.getCurrentRpcSession();
6599
+ if (session) {
6600
+ record.uploaderMeta = session.meta;
6601
+ session.meta.uploadingStreams ??= /* @__PURE__ */ new Set();
6602
+ session.meta.uploadingStreams.add(streamKey(channelName, id));
6603
+ }
6604
+ }
6605
+ record.reader._push(seq, chunk);
6606
+ }
6607
+ });
6608
+ rpc.register({
6609
+ name: "devframe:streaming:upload-end",
6610
+ type: "event",
6611
+ handler(channelName, id, error) {
6612
+ const state = channels.get(channelName);
6613
+ const record = state?.inbound.get(id);
6614
+ if (!record) return;
6615
+ record.reader._end(error);
6616
+ if (record.uploaderMeta) record.uploaderMeta.uploadingStreams?.delete(streamKey(channelName, id));
6617
+ state?.inbound.delete(id);
6618
+ }
6619
+ });
6620
+ function createChannel(name, opts = {}) {
6621
+ if (channels.has(name)) throw logger.DF0032({ channel: name }).throw();
6622
+ const replayWindow = opts.replayWindow ?? 0;
6623
+ const state = {
6624
+ name,
6625
+ options: {
6626
+ replayWindow,
6627
+ closedStreamRetention: opts.closedStreamRetention ?? (replayWindow > 0 ? 3e4 : 0)
6628
+ },
6629
+ streams: /* @__PURE__ */ new Map(),
6630
+ inbound: /* @__PURE__ */ new Map()
6631
+ };
6632
+ channels.set(name, state);
6633
+ function start(startOpts = {}) {
6634
+ const sink = createStreamSink({
6635
+ id: startOpts.id,
6636
+ replayWindow: state.options.replayWindow
6637
+ });
6638
+ const record = {
6639
+ sink,
6640
+ subscribers: /* @__PURE__ */ new Set(),
6641
+ unbinders: []
6642
+ };
6643
+ state.streams.set(sink.id, record);
6644
+ record.unbinders.push(sink.events.on("chunk", (seq, chunk) => {
6645
+ rpc.broadcast({
6646
+ method: "devframe:streaming:chunk",
6647
+ args: [
6648
+ name,
6649
+ sink.id,
6650
+ seq,
6651
+ chunk
6652
+ ],
6653
+ event: true,
6654
+ optional: true,
6655
+ filter: (client) => record.subscribers.has(client.$meta)
6656
+ });
6657
+ }));
6658
+ record.unbinders.push(sink.events.on("end", (error) => {
6659
+ rpc.broadcast({
6660
+ method: "devframe:streaming:end",
6661
+ args: [
6662
+ name,
6663
+ sink.id,
6664
+ error
6665
+ ],
6666
+ event: true,
6667
+ optional: true,
6668
+ filter: (client) => record.subscribers.has(client.$meta)
6669
+ });
6670
+ maybeFreeStream(state, sink.id);
6671
+ }));
6672
+ return sink;
6673
+ }
6674
+ async function pipeFrom(readable, startOpts = {}) {
6675
+ const sink = start(startOpts);
6676
+ readable.pipeTo(sink.writable, { signal: sink.signal }).catch(() => {});
6677
+ return sink;
6678
+ }
6679
+ function get(id) {
6680
+ return state.streams.get(id)?.sink;
6681
+ }
6682
+ function ids() {
6683
+ return Array.from(state.streams.keys());
6684
+ }
6685
+ function openInbound(inboundOpts = {}) {
6686
+ let inboundRecord;
6687
+ const reader = createStreamReader({
6688
+ id: inboundOpts.id,
6689
+ onCancel() {
6690
+ const targetMeta = inboundRecord?.uploaderMeta;
6691
+ if (!targetMeta) return;
6692
+ rpc.broadcast({
6693
+ method: "devframe:streaming:upload-cancel",
6694
+ args: [name, reader.id],
6695
+ event: true,
6696
+ optional: true,
6697
+ filter: (client) => client.$meta === targetMeta
6698
+ });
6699
+ }
6700
+ });
6701
+ inboundRecord = { reader };
6702
+ state.inbound.set(reader.id, inboundRecord);
6703
+ debug("opened-inbound", name, reader.id);
6704
+ return reader;
6705
+ }
6706
+ return {
6707
+ name,
6708
+ start,
6709
+ pipeFrom,
6710
+ get,
6711
+ ids,
6712
+ openInbound
6713
+ };
6714
+ }
6715
+ function parseKey(key) {
6716
+ const sepIdx = key.indexOf(STREAM_KEY_SEPARATOR);
6717
+ if (sepIdx < 0) return void 0;
6718
+ return {
6719
+ channelName: key.slice(0, sepIdx),
6720
+ id: key.slice(sepIdx + 1)
6721
+ };
6722
+ }
6723
+ return {
6724
+ create: createChannel,
6725
+ _onSessionDisconnected(meta) {
6726
+ if (meta.subscribedStreams) {
6727
+ for (const key of meta.subscribedStreams) {
6728
+ const parsed = parseKey(key);
6729
+ if (!parsed) continue;
6730
+ const state = channels.get(parsed.channelName);
6731
+ const record = state?.streams.get(parsed.id);
6732
+ if (!state || !record) continue;
6733
+ record.subscribers.delete(meta);
6734
+ if (record.subscribers.size === 0 && !record.sink.closed) record.sink.abort("all subscribers disconnected");
6735
+ maybeFreeStream(state, parsed.id);
6736
+ }
6737
+ meta.subscribedStreams.clear();
6738
+ }
6739
+ if (meta.uploadingStreams) {
6740
+ for (const key of meta.uploadingStreams) {
6741
+ const parsed = parseKey(key);
6742
+ if (!parsed) continue;
6743
+ const state = channels.get(parsed.channelName);
6744
+ const record = state?.inbound.get(parsed.id);
6745
+ if (!state || !record) continue;
6746
+ record.reader._end({
6747
+ name: "UploadDisconnected",
6748
+ message: "Uploader disconnected before completing the stream"
6749
+ });
6750
+ state.inbound.delete(parsed.id);
6751
+ }
6752
+ meta.uploadingStreams.clear();
6753
+ }
6754
+ }
6755
+ };
6401
6756
  }
6402
6757
  //#endregion
6403
6758
  //#region src/node/host-functions.ts
@@ -6411,8 +6766,20 @@ var RpcFunctionsHost = class extends RpcFunctionsCollectorBase {
6411
6766
  constructor(context) {
6412
6767
  super(context);
6413
6768
  this.sharedState = createRpcSharedStateServerHost(this);
6769
+ this.streaming = createRpcStreamingServerHost(this);
6414
6770
  }
6415
6771
  sharedState;
6772
+ streaming;
6773
+ /**
6774
+ * Adapters call this from their WS `onDisconnected` hook so downstream
6775
+ * hosts (streaming, …) can free per-session state. Public-ish because
6776
+ * tests / custom adapters may want to mirror it.
6777
+ *
6778
+ * @internal
6779
+ */
6780
+ _emitSessionDisconnected(meta) {
6781
+ this.streaming._onSessionDisconnected(meta);
6782
+ }
6416
6783
  async invokeLocal(method, ...args) {
6417
6784
  if (!this.definitions.has(method)) throw logger.DF0006({ name: String(method) }).throw();
6418
6785
  const handler = await this.getHandler(method);
@@ -6543,13 +6910,32 @@ var DevToolsMessagesHost = class {
6543
6910
  };
6544
6911
  //#endregion
6545
6912
  //#region src/node/host-terminals.ts
6913
+ /**
6914
+ * Channel name used for terminal stream output. Built into devframe so the
6915
+ * standalone client (`packages/core/src/client/webcomponents/state/terminals.ts`)
6916
+ * can subscribe by a stable, well-known name.
6917
+ */
6918
+ const TERMINAL_STREAM_CHANNEL = "devframe:terminals";
6919
+ const TERMINAL_REPLAY_WINDOW = 1e3;
6546
6920
  var DevToolsTerminalHost = class {
6547
6921
  sessions = /* @__PURE__ */ new Map();
6548
6922
  events = createEventEmitter();
6549
6923
  _boundStreams = /* @__PURE__ */ new Map();
6924
+ _channel;
6550
6925
  constructor(context) {
6551
6926
  this.context = context;
6552
6927
  }
6928
+ /**
6929
+ * Lazily acquire the streaming channel — `context.rpc` isn't assigned
6930
+ * until after every host is constructed, so we can't grab it in the
6931
+ * constructor.
6932
+ */
6933
+ getStreamingChannel() {
6934
+ if (this._channel) return this._channel;
6935
+ if (!this.context.rpc?.streaming) return void 0;
6936
+ this._channel = this.context.rpc.streaming.create(TERMINAL_STREAM_CHANNEL, { replayWindow: TERMINAL_REPLAY_WINDOW });
6937
+ return this._channel;
6938
+ }
6553
6939
  register(session) {
6554
6940
  if (this.sessions.has(session.id)) throw logger.DF0004({ id: session.id }).throw();
6555
6941
  this.sessions.set(session.id, session);
@@ -6577,26 +6963,31 @@ var DevToolsTerminalHost = class {
6577
6963
  this._boundStreams.delete(session.id);
6578
6964
  if (!session.stream) return;
6579
6965
  session.buffer ||= [];
6580
- const events = this.events;
6581
- const writer = new WritableStream({ write(chunk) {
6582
- session.buffer.push(chunk);
6583
- events.emit("terminal:session:stream-chunk", {
6584
- id: session.id,
6585
- chunks: [chunk],
6586
- ts: Date.now()
6587
- });
6588
- } });
6589
- session.stream.pipeTo(writer);
6966
+ const sessionBuffer = session.buffer;
6967
+ const sink = this.getStreamingChannel()?.start({ id: session.id });
6968
+ const writer = new WritableStream({
6969
+ write(chunk) {
6970
+ sessionBuffer.push(chunk);
6971
+ sink?.write(chunk);
6972
+ },
6973
+ close() {
6974
+ sink?.close();
6975
+ },
6976
+ abort(reason) {
6977
+ sink?.error(reason);
6978
+ }
6979
+ });
6980
+ session.stream.pipeTo(writer).catch(() => {});
6590
6981
  this._boundStreams.set(session.id, {
6591
6982
  dispose: () => {
6592
- writer.close();
6983
+ if (sink && !sink.closed) sink.close();
6593
6984
  },
6594
6985
  stream: session.stream
6595
6986
  });
6596
6987
  }
6597
6988
  async startChildProcess(executeOptions, terminal) {
6598
6989
  if (this.sessions.has(terminal.id)) throw logger.DF0004({ id: terminal.id }).throw();
6599
- const { exec } = await import("./main-CuGOfqoX.mjs");
6990
+ const { exec } = await import("./main-DpINGndA.mjs");
6600
6991
  let controller;
6601
6992
  const stream = new ReadableStream({ start(_controller) {
6602
6993
  controller = _controller;
@@ -6674,6 +7065,7 @@ const agentInvokeTool = defineRpcFunction({
6674
7065
  const agentListResources = defineRpcFunction({
6675
7066
  name: "devframe:agent:list-resources",
6676
7067
  type: "query",
7068
+ jsonSerializable: true,
6677
7069
  setup: (ctx) => {
6678
7070
  return { async handler() {
6679
7071
  return ctx.agent.list().resources;
@@ -6693,6 +7085,7 @@ const BUILTIN_AGENT_RPC = [
6693
7085
  defineRpcFunction({
6694
7086
  name: "devframe:agent:list-tools",
6695
7087
  type: "query",
7088
+ jsonSerializable: true,
6696
7089
  setup: (ctx) => {
6697
7090
  return { async handler() {
6698
7091
  return ctx.agent.list().tools;
@@ -6704,6 +7097,7 @@ const BUILTIN_AGENT_RPC = [
6704
7097
  defineRpcFunction({
6705
7098
  name: "devframe:agent:read-resource",
6706
7099
  type: "query",
7100
+ jsonSerializable: true,
6707
7101
  setup: (ctx) => {
6708
7102
  return { async handler(id) {
6709
7103
  return await ctx.agent.read(id);
@@ -6767,7 +7161,7 @@ async function createHostContext(options) {
6767
7161
  context.agent = new DevToolsAgentHost(context);
6768
7162
  let jrCounter = 0;
6769
7163
  context.createJsonRenderer = (initialSpec) => {
6770
- const stateKey = `devtoolskit:internal:json-render:${jrCounter++}`;
7164
+ const stateKey = `devframe:json-render:${jrCounter++}`;
6771
7165
  const statePromise = rpcHost.sharedState.get(stateKey, { initialValue: initialSpec });
6772
7166
  return {
6773
7167
  _stateKey: stateKey,
@@ -6787,26 +7181,20 @@ async function createHostContext(options) {
6787
7181
  for (const fn of BUILTIN_AGENT_RPC) rpcHost.register(fn);
6788
7182
  for (const fn of builtinRpcDeclarations) rpcHost.register(fn);
6789
7183
  await docksHost.init();
6790
- const docksSharedState = await rpcHost.sharedState.get("devtoolskit:internal:docks", { initialValue: [] });
7184
+ const docksSharedState = await rpcHost.sharedState.get("devframe:docks", { initialValue: [] });
6791
7185
  docksHost.events.on("dock:entry:updated", debounce(() => {
6792
7186
  docksSharedState.mutate(() => context.docks.values());
6793
7187
  }, mode === "build" ? 0 : 10));
6794
7188
  terminalsHost.events.on("terminal:session:updated", debounce(() => {
6795
7189
  rpcHost.broadcast({
6796
- method: "devtoolskit:internal:terminals:updated",
7190
+ method: "devframe:terminals:updated",
6797
7191
  args: []
6798
7192
  });
6799
7193
  docksSharedState.mutate(() => context.docks.values());
6800
7194
  }, mode === "build" ? 0 : 10));
6801
- terminalsHost.events.on("terminal:session:stream-chunk", (data) => {
6802
- rpcHost.broadcast({
6803
- method: "devtoolskit:internal:terminals:stream-chunk",
6804
- args: [data]
6805
- });
6806
- });
6807
7195
  const debouncedMessagesUpdate = debounce(() => {
6808
7196
  rpcHost.broadcast({
6809
- method: "devtoolskit:internal:messages:updated",
7197
+ method: "devframe:messages:updated",
6810
7198
  args: []
6811
7199
  });
6812
7200
  docksSharedState.mutate(() => context.docks.values());
@@ -6815,7 +7203,7 @@ async function createHostContext(options) {
6815
7203
  messagesHost.events.on("message:updated", () => debouncedMessagesUpdate());
6816
7204
  messagesHost.events.on("message:removed", () => debouncedMessagesUpdate());
6817
7205
  messagesHost.events.on("message:cleared", () => debouncedMessagesUpdate());
6818
- const commandsSharedState = await rpcHost.sharedState.get("devtoolskit:internal:commands", { initialValue: [] });
7206
+ const commandsSharedState = await rpcHost.sharedState.get("devframe:commands", { initialValue: [] });
6819
7207
  const debouncedCommandsSync = debounce(() => {
6820
7208
  commandsSharedState.mutate(() => commandsHost.list());
6821
7209
  }, mode === "build" ? 0 : 10);
@@ -6824,4 +7212,4 @@ async function createHostContext(options) {
6824
7212
  return context;
6825
7213
  }
6826
7214
  //#endregion
6827
- export { revokeAuthToken as _, RpcFunctionsHost as a, getInternalContext as c, DevToolsDiagnosticsHost as d, DevToolsCommandsHost as f, revokeActiveConnectionsForToken as g, ContextUtils as h, DevToolsMessagesHost as i, internalContextMap as l, logger as m, DevToolsViewHost as n, createRpcSharedStateServerHost as o, DevToolsAgentHost as p, DevToolsTerminalHost as r, DevToolsDockHost as s, createHostContext as t, createStorage as u };
7215
+ export { revokeActiveConnectionsForToken as _, RpcFunctionsHost as a, DevToolsDockHost as c, createStorage as d, DevToolsDiagnosticsHost as f, ContextUtils as g, logger as h, DevToolsMessagesHost as i, getInternalContext as l, DevToolsAgentHost as m, DevToolsViewHost as n, createRpcStreamingServerHost as o, DevToolsCommandsHost as p, DevToolsTerminalHost as r, createRpcSharedStateServerHost as s, createHostContext as t, internalContextMap as u, revokeAuthToken as v };
@@ -1,8 +1,8 @@
1
- import { t as createHostContext } from "./context-BsNZMCnr.mjs";
1
+ import { t as createHostContext } from "./context-BfvbAyGk.mjs";
2
2
  import { DEVTOOLS_CONNECTION_META_FILENAME } from "./constants.mjs";
3
- import { t as createH3DevToolsHost } from "./host-h3-w3c0t8ZO.mjs";
4
- import { t as startHttpAndWs } from "./server-DrBxa6ZV.mjs";
5
- import { n as resolveBasePath, t as normalizeBasePath } from "./_shared-BcPXmcjq.mjs";
3
+ import { t as createH3DevToolsHost } from "./host-h3-BMvrFzIJ.mjs";
4
+ import { t as startHttpAndWs } from "./server-qRRM8t3v.mjs";
5
+ import { n as resolveBasePath, t as normalizeBasePath } from "./_shared-S-Ujqz_L.mjs";
6
6
  import { resolve } from "pathe";
7
7
  import process$1 from "node:process";
8
8
  import { networkInterfaces } from "node:os";
@@ -266,6 +266,7 @@ async function createDevServer(def, options = {}) {
266
266
  const app = options.app ?? createApp();
267
267
  const h3Host = createH3DevToolsHost({
268
268
  origin: `http://${host}:${port}`,
269
+ appName: def.id,
269
270
  mount: (base, dir) => {
270
271
  app.use(base, fromNodeMiddleware(sirv(dir, {
271
272
  dev: true,
@@ -311,7 +312,7 @@ async function maybeOpenBrowser(def, flags, origin, override) {
311
312
  if (resolved === void 0 || resolved === false) return;
312
313
  const target = typeof resolved === "string" ? resolveOpenTarget(origin, resolved) : origin;
313
314
  try {
314
- const { default: open } = await import("./open-JfacLHs0.mjs");
315
+ const { default: open } = await import("./open-BtOOEldu.mjs");
315
316
  await open(target);
316
317
  } catch {}
317
318
  }