dsh-interconnect 0.11.16 → 0.11.17
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/dsh.plugin.json +1 -1
- package/lib/index.js +29 -31
- package/lib/interconnect/index.js +29 -31
- package/lib/interconnect/index.js.map +2 -2
- package/lib/tool-interconnect/index.js +29 -31
- package/lib/tool-interconnect/index.js.map +2 -2
- package/lib/types/interconnect/index.d.ts +10 -8
- package/lib/types/interconnect/index.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -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`. */
|
|
@@ -998,28 +998,28 @@ var InterconnectService = class extends Service {
|
|
|
998
998
|
socket.ping();
|
|
999
999
|
}
|
|
1000
1000
|
}, 3e4);
|
|
1001
|
-
|
|
1001
|
+
ctx.on("agent/status", ({ agent, status }) => {
|
|
1002
1002
|
this.fanout({ kind: "agent/status", sessionId: String(agent.session.id), status });
|
|
1003
|
-
})
|
|
1004
|
-
|
|
1003
|
+
});
|
|
1004
|
+
ctx.on("agent/created", ({ agent }) => {
|
|
1005
1005
|
this.fanout({ kind: "agent/created", sessionId: String(agent.session.id) });
|
|
1006
|
-
})
|
|
1007
|
-
|
|
1006
|
+
});
|
|
1007
|
+
ctx.on("agent/disposed", ({ agent }) => {
|
|
1008
1008
|
this.fanout({ kind: "agent/disposed", sessionId: String(agent.session.id) });
|
|
1009
|
-
})
|
|
1010
|
-
|
|
1009
|
+
});
|
|
1010
|
+
ctx.on("session/created", (session) => {
|
|
1011
1011
|
const parentSessionId = session.header.parentSession === void 0 ? void 0 : String(session.header.parentSession);
|
|
1012
1012
|
this.fanout({
|
|
1013
1013
|
kind: "session/created",
|
|
1014
1014
|
sessionId: String(session.id),
|
|
1015
1015
|
...parentSessionId === void 0 ? {} : { parentSessionId }
|
|
1016
1016
|
});
|
|
1017
|
-
})
|
|
1018
|
-
|
|
1017
|
+
});
|
|
1018
|
+
ctx.on("session/disposed", (session) => {
|
|
1019
1019
|
this.senders.delete(String(session.id));
|
|
1020
1020
|
this.fanout({ kind: "session/disposed", sessionId: String(session.id) });
|
|
1021
|
-
})
|
|
1022
|
-
|
|
1021
|
+
});
|
|
1022
|
+
ctx.on("subagent/end", (info) => {
|
|
1023
1023
|
if (!info.local) return;
|
|
1024
1024
|
this.fanout({
|
|
1025
1025
|
kind: "subagent/end",
|
|
@@ -1027,10 +1027,7 @@ var InterconnectService = class extends Service {
|
|
|
1027
1027
|
childSessionId: String(info.id),
|
|
1028
1028
|
stopReason: info.stopReason
|
|
1029
1029
|
});
|
|
1030
|
-
})
|
|
1031
|
-
ctx.effect(() => () => {
|
|
1032
|
-
for (const dispose of this.subscriptions.splice(0)) dispose();
|
|
1033
|
-
}, "interconnect: event subscriptions");
|
|
1030
|
+
});
|
|
1034
1031
|
ctx.effect(() => () => {
|
|
1035
1032
|
if (this.heartbeatTimer !== void 0) clearInterval(this.heartbeatTimer);
|
|
1036
1033
|
for (const state of this.linkStates.values()) state.close();
|
|
@@ -1220,10 +1217,12 @@ var InterconnectService = class extends Service {
|
|
|
1220
1217
|
* dialed link plus the peer's inbound one), so one event must leave over one
|
|
1221
1218
|
* of them. Which one is decided by local ownership, not by the peer: a dialed
|
|
1222
1219
|
* socket is a configured peer's link and always sends. An inbound socket is
|
|
1223
|
-
* skipped only when
|
|
1224
|
-
*
|
|
1225
|
-
*
|
|
1226
|
-
*
|
|
1220
|
+
* skipped only when an open dialed link covers the id that socket itself
|
|
1221
|
+
* announced — either because `Config.peers` lists that peer under the id, or
|
|
1222
|
+
* because the peer announced the id over that dialed link — so an
|
|
1223
|
+
* announcement can suppress nothing but a duplicate the controlled link
|
|
1224
|
+
* already carries. An impostor cannot drop an event for a peer, and without a
|
|
1225
|
+
* dialed link every inbound socket receives it.
|
|
1227
1226
|
*
|
|
1228
1227
|
* That holds once a peer's announcement has been seen. Between this
|
|
1229
1228
|
* instance's dialed link opening and the peer's `hello` arriving on its
|
|
@@ -1242,7 +1241,10 @@ var InterconnectService = class extends Service {
|
|
|
1242
1241
|
continue;
|
|
1243
1242
|
}
|
|
1244
1243
|
const dialedPeer = this.dialedPeerOf.get(socket);
|
|
1245
|
-
if (dialedPeer
|
|
1244
|
+
if (dialedPeer === void 0) continue;
|
|
1245
|
+
covered.add(dialedPeer);
|
|
1246
|
+
const announced = this.peerOf.get(socket);
|
|
1247
|
+
if (announced !== void 0) covered.add(announced);
|
|
1246
1248
|
}
|
|
1247
1249
|
for (const socket of this.sockets) {
|
|
1248
1250
|
if (this.dialedPeerOf.get(socket) === void 0) {
|
|
@@ -1274,12 +1276,7 @@ var InterconnectService = class extends Service {
|
|
|
1274
1276
|
if (query.kind === "ping") {
|
|
1275
1277
|
result = { pong: true, instance: this.instanceId };
|
|
1276
1278
|
} else if (query.kind === "list") {
|
|
1277
|
-
|
|
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);
|
|
1279
|
+
result = this.listSessions(this.listRowsBudgetBytes(reqId));
|
|
1283
1280
|
} else {
|
|
1284
1281
|
const payload = {
|
|
1285
1282
|
sender: this.peerOf.get(socket) ?? "unknown-peer",
|
|
@@ -1311,10 +1308,11 @@ var InterconnectService = class extends Service {
|
|
|
1311
1308
|
* Bytes one `list` answer may spend on its `sessions` rows: the frame cap
|
|
1312
1309
|
* minus the serialized envelope that answer will carry. The envelope holds
|
|
1313
1310
|
* the peer-supplied `reqId` and this instance's own id, so it is measured per
|
|
1314
|
-
* answer instead of reserved with a fixed constant.
|
|
1311
|
+
* answer instead of reserved with a fixed constant. Both ids are bounded
|
|
1312
|
+
* ({@link MAX_REQUEST_ID_CHARS} and {@link MAX_INSTANCE_ID_CHARS} characters),
|
|
1313
|
+
* so the envelope always fits and the budget is always positive.
|
|
1315
1314
|
* @param reqId - the request id the answer has to echo.
|
|
1316
|
-
* @returns the byte budget for the rows
|
|
1317
|
-
* exceeds the cap and so cannot be sent at all.
|
|
1315
|
+
* @returns the byte budget for the rows.
|
|
1318
1316
|
*/
|
|
1319
1317
|
listRowsBudgetBytes(reqId) {
|
|
1320
1318
|
const envelope = {
|