dsh-interconnect 0.11.16 → 0.11.18

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.
@@ -838,6 +838,7 @@ var PLUGIN_SOURCE = "dsh-interconnect";
838
838
  var MAX_LINK_FRAME_BYTES = 1024 * 1024;
839
839
  var LINK_HANDSHAKE_TIMEOUT_MS = 1e4;
840
840
  var LINK_CHANNEL = "/interconnect/link";
841
+ var MAX_INSTANCE_ID_CHARS = 256;
841
842
  var MAX_REQUEST_ID_CHARS = 256;
842
843
  var MAX_LISTED_SESSIONS = 100;
843
844
  var frameFitsLink = (frame) => Buffer.byteLength(JSON.stringify(frame), "utf8") <= MAX_LINK_FRAME_BYTES;
@@ -931,7 +932,7 @@ var linkFrameSchema = Schema.union([
931
932
  var InterconnectService = class extends Service {
932
933
  static inject = ["agents", "credentials"];
933
934
  static Config = Schema.object({
934
- instanceId: Schema.string().default("dsh"),
935
+ instanceId: Schema.string().max(MAX_INSTANCE_ID_CHARS).default("dsh"),
935
936
  requestTimeoutMs: Schema.natural().max(6e4).default(1e4),
936
937
  peers: Schema.dict(Schema.string()).default({}),
937
938
  delivery: Schema.union([Schema.const("followup"), Schema.const("steer"), Schema.const("inject")]).default("followup"),
@@ -941,7 +942,6 @@ var InterconnectService = class extends Service {
941
942
  requestTimeoutMs;
942
943
  delivery;
943
944
  allowResume;
944
- subscriptions = [];
945
945
  server = new WebSocketServer({ noServer: true, maxPayload: MAX_LINK_FRAME_BYTES });
946
946
  sockets = /* @__PURE__ */ new Set();
947
947
  /** Outbound peer links keyed by the peer's `instanceId`. */
@@ -951,6 +951,8 @@ var InterconnectService = class extends Service {
951
951
  peerOf = /* @__PURE__ */ new WeakMap();
952
952
  /** Configured peer an outbound dial owns a socket for; absent on inbound sockets. */
953
953
  dialedPeerOf = /* @__PURE__ */ new WeakMap();
954
+ /** Dialed sockets already reported as announcing an id other than their configured key. */
955
+ mismatchWarned = /* @__PURE__ */ new WeakSet();
954
956
  /** Sender each local session last received a send from, keyed by local session id. */
955
957
  senders = /* @__PURE__ */ new Map();
956
958
  /** In-flight frames sent over a peer link, keyed by `reqId`, awaiting a correlated result. */
@@ -998,28 +1000,28 @@ var InterconnectService = class extends Service {
998
1000
  socket.ping();
999
1001
  }
1000
1002
  }, 3e4);
1001
- this.subscriptions.push(ctx.on("agent/status", ({ agent, status }) => {
1003
+ ctx.on("agent/status", ({ agent, status }) => {
1002
1004
  this.fanout({ kind: "agent/status", sessionId: String(agent.session.id), status });
1003
- }));
1004
- this.subscriptions.push(ctx.on("agent/created", ({ agent }) => {
1005
+ });
1006
+ ctx.on("agent/created", ({ agent }) => {
1005
1007
  this.fanout({ kind: "agent/created", sessionId: String(agent.session.id) });
1006
- }));
1007
- this.subscriptions.push(ctx.on("agent/disposed", ({ agent }) => {
1008
+ });
1009
+ ctx.on("agent/disposed", ({ agent }) => {
1008
1010
  this.fanout({ kind: "agent/disposed", sessionId: String(agent.session.id) });
1009
- }));
1010
- this.subscriptions.push(ctx.on("session/created", (session) => {
1011
+ });
1012
+ ctx.on("session/created", (session) => {
1011
1013
  const parentSessionId = session.header.parentSession === void 0 ? void 0 : String(session.header.parentSession);
1012
1014
  this.fanout({
1013
1015
  kind: "session/created",
1014
1016
  sessionId: String(session.id),
1015
1017
  ...parentSessionId === void 0 ? {} : { parentSessionId }
1016
1018
  });
1017
- }));
1018
- this.subscriptions.push(ctx.on("session/disposed", (session) => {
1019
+ });
1020
+ ctx.on("session/disposed", (session) => {
1019
1021
  this.senders.delete(String(session.id));
1020
1022
  this.fanout({ kind: "session/disposed", sessionId: String(session.id) });
1021
- }));
1022
- this.subscriptions.push(ctx.on("subagent/end", (info) => {
1023
+ });
1024
+ ctx.on("subagent/end", (info) => {
1023
1025
  if (!info.local) return;
1024
1026
  this.fanout({
1025
1027
  kind: "subagent/end",
@@ -1027,10 +1029,7 @@ var InterconnectService = class extends Service {
1027
1029
  childSessionId: String(info.id),
1028
1030
  stopReason: info.stopReason
1029
1031
  });
1030
- }));
1031
- ctx.effect(() => () => {
1032
- for (const dispose of this.subscriptions.splice(0)) dispose();
1033
- }, "interconnect: event subscriptions");
1032
+ });
1034
1033
  ctx.effect(() => () => {
1035
1034
  if (this.heartbeatTimer !== void 0) clearInterval(this.heartbeatTimer);
1036
1035
  for (const state of this.linkStates.values()) state.close();
@@ -1220,10 +1219,12 @@ var InterconnectService = class extends Service {
1220
1219
  * dialed link plus the peer's inbound one), so one event must leave over one
1221
1220
  * of them. Which one is decided by local ownership, not by the peer: a dialed
1222
1221
  * socket is a configured peer's link and always sends. An inbound socket is
1223
- * skipped only when a dialed link to the id that socket itself announced is
1224
- * open, so an announcement can suppress nothing but a duplicate the
1225
- * controlled link already carries — an impostor cannot drop an event for a
1226
- * peer, and without a dialed link every inbound socket receives it.
1222
+ * skipped only when this instance has an open dialed link configured under
1223
+ * the id that socket itself announced, so a self-reported announcement can
1224
+ * never silence another peer's link; with no such dialed link every inbound
1225
+ * socket receives the event. A peer listed under a key other than the id it
1226
+ * announces is warned about once per link, because then its own inbound
1227
+ * socket is not attributable and the peer receives each event twice.
1227
1228
  *
1228
1229
  * That holds once a peer's announcement has been seen. Between this
1229
1230
  * instance's dialed link opening and the peer's `hello` arriving on its
@@ -1274,12 +1275,7 @@ var InterconnectService = class extends Service {
1274
1275
  if (query.kind === "ping") {
1275
1276
  result = { pong: true, instance: this.instanceId };
1276
1277
  } else if (query.kind === "list") {
1277
- const rowBudget = this.listRowsBudgetBytes(reqId);
1278
- if (rowBudget < 0) {
1279
- this.ctx.logger.warn("interconnect: list answer cannot fit the link frame cap; not answering");
1280
- return;
1281
- }
1282
- result = this.listSessions(rowBudget);
1278
+ result = this.listSessions(this.listRowsBudgetBytes(reqId));
1283
1279
  } else {
1284
1280
  const payload = {
1285
1281
  sender: this.peerOf.get(socket) ?? "unknown-peer",
@@ -1311,10 +1307,11 @@ var InterconnectService = class extends Service {
1311
1307
  * Bytes one `list` answer may spend on its `sessions` rows: the frame cap
1312
1308
  * minus the serialized envelope that answer will carry. The envelope holds
1313
1309
  * the peer-supplied `reqId` and this instance's own id, so it is measured per
1314
- * answer instead of reserved with a fixed constant.
1310
+ * answer instead of reserved with a fixed constant. Both ids are bounded
1311
+ * ({@link MAX_REQUEST_ID_CHARS} and {@link MAX_INSTANCE_ID_CHARS} characters),
1312
+ * so the envelope always fits and the budget is always positive.
1315
1313
  * @param reqId - the request id the answer has to echo.
1316
- * @returns the byte budget for the rows, negative when even an empty answer
1317
- * exceeds the cap and so cannot be sent at all.
1314
+ * @returns the byte budget for the rows.
1318
1315
  */
1319
1316
  listRowsBudgetBytes(reqId) {
1320
1317
  const envelope = {
@@ -1579,6 +1576,13 @@ var InterconnectService = class extends Service {
1579
1576
  const frame = parsed;
1580
1577
  if (frame.type === "hello") {
1581
1578
  this.peerOf.set(socket, frame.sender);
1579
+ const dialedPeer = this.dialedPeerOf.get(socket);
1580
+ if (dialedPeer !== void 0 && dialedPeer !== frame.sender && !this.mismatchWarned.has(socket)) {
1581
+ this.mismatchWarned.add(socket);
1582
+ this.ctx.logger.warn(
1583
+ `interconnect: peer configured as ${dialedPeer} announces ${frame.sender}; list a peer under the instanceId it announces, or the duplicate inbound link is not recognised`
1584
+ );
1585
+ }
1582
1586
  return;
1583
1587
  }
1584
1588
  if (frame.type === "event") {