agent-comms 1.30.0 → 1.32.0
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +1 -1
- package/dist/bridges/mcp/index.d.ts.map +1 -1
- package/dist/bridges/mcp/index.js +3 -11
- package/dist/bridges/mcp/index.js.map +1 -1
- package/dist/core/bridge-mesh.d.ts +14 -0
- package/dist/core/bridge-mesh.d.ts.map +1 -0
- package/dist/core/bridge-mesh.js +19 -0
- package/dist/core/bridge-mesh.js.map +1 -0
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/wire-mesh-transport.d.ts +57 -0
- package/dist/core/wire-mesh-transport.d.ts.map +1 -0
- package/dist/core/wire-mesh-transport.js +466 -0
- package/dist/core/wire-mesh-transport.js.map +1 -0
- package/dist/test/bridge-mesh.test.d.ts +5 -0
- package/dist/test/bridge-mesh.test.d.ts.map +1 -0
- package/dist/test/bridge-mesh.test.js +67 -0
- package/dist/test/bridge-mesh.test.js.map +1 -0
- package/dist/test/delivery-receipt.runner.d.ts +2 -7
- package/dist/test/delivery-receipt.runner.d.ts.map +1 -1
- package/dist/test/delivery-receipt.runner.js +4 -9
- package/dist/test/delivery-receipt.runner.js.map +1 -1
- package/dist/test/test-transport.d.ts +4 -0
- package/dist/test/test-transport.d.ts.map +1 -1
- package/dist/test/test-transport.js +13 -0
- package/dist/test/test-transport.js.map +1 -1
- package/dist/test/wire-mesh-transport-approval.integration.test.d.ts +5 -0
- package/dist/test/wire-mesh-transport-approval.integration.test.d.ts.map +1 -0
- package/dist/test/wire-mesh-transport-approval.integration.test.js +164 -0
- package/dist/test/wire-mesh-transport-approval.integration.test.js.map +1 -0
- package/dist/test/wire-mesh-transport.integration.test.d.ts +5 -0
- package/dist/test/wire-mesh-transport.integration.test.d.ts.map +1 -0
- package/dist/test/wire-mesh-transport.integration.test.js +89 -0
- package/dist/test/wire-mesh-transport.integration.test.js.map +1 -0
- package/package.json +4 -6
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WireMeshTransport — MeshTransport implemented over @exadev/wire-mesh-core, carrying the existing MeshMessage union as an opaque payload rather than inventing new wire semantics. This is the P2 substrate swap's own deliverable: MeshStore, CommsTool, and every existing agent/room/message behaviour above the transport are completely unaffected -- only how bytes move between peers changes.
|
|
3
|
+
*
|
|
4
|
+
* Every agent-comms MeshMessage rides as a single namespaced manage-command verb (FRAME_VERB) under one flat scope (FRAME_SCOPE); the message itself is carried opaquely in the command's own params.message field. This needs no spec/CDDL change: manage-command-params is already an open `{* tstr => any}` socket for exactly this purpose.
|
|
5
|
+
*
|
|
6
|
+
* Peer identity is authenticated at the transport layer, not asserted on the wire: createTlsTransport verifies a peer's presented certificate cryptographically and exposes the result as Connection.peerDeviceId before any MeshMessage is ever exchanged, which is what lets the `pong` self-identification message retire entirely -- there is nothing left for it to prove that the connection itself hasn't already proven.
|
|
7
|
+
*
|
|
8
|
+
* connect_request's accept/reject flow maps onto sendManageRequest's own request/response round trip directly, rather than a separate pair of connect_accepted/connect_rejected messages: manage-request-frame already tolerates arbitrary latency between a request and its response, so "waiting for a human to approve" is simply a manage-response that hasn't been sent yet, not a protocol gap needing its own mechanism. connect_request therefore holds its own IncomingManageRequest open (rather than responding immediately) until acceptConnection/rejectConnection is actually called.
|
|
9
|
+
*/
|
|
10
|
+
import { createTlsTransport } from "@exadev/wire-mesh-core/adapters/tls-transport";
|
|
11
|
+
import { acceptMeshSession, } from "@exadev/wire-mesh-core/domain/mesh-session";
|
|
12
|
+
import { deviceIdToHex } from "@exadev/wire-mesh-core/domain/device-id";
|
|
13
|
+
import { isMeshMessage } from "./wire-protocol.js";
|
|
14
|
+
import { toIdentityPort } from "./wire-mesh-identity.js";
|
|
15
|
+
import { nanoid } from "./nanoid.js";
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// Constants
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
const COORDINATOR_HOST = "127.0.0.1";
|
|
20
|
+
/** This project's own namespaced domain (registrant "exadev.io", local name "agent-comms-v1"), matching namespaced-domain-id's "<registrant>/<local-name>" shape -- registry/core-domains.md's own recommended pattern for a third party. */
|
|
21
|
+
const DOMAIN = "exadev.io/agent-comms-v1";
|
|
22
|
+
/** One verb for the entire MeshMessage union: this phase carries every message opaquely rather than modelling each arm as its own verb, which is core/room's own job once P3 gives this substrate real room semantics. */
|
|
23
|
+
const FRAME_VERB = "exadev.io/agent-comms-v1:frame";
|
|
24
|
+
/** No finer-grained authorisation model exists above "you're a TLS-authenticated member of this mesh" at this phase -- exactly today's TlsTransport model, which does no per-message authorisation either. */
|
|
25
|
+
const FRAME_SCOPE = { kind: "agent-comms-mesh" };
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// Message carriage
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
function buildCommand(message) {
|
|
30
|
+
return { verb: FRAME_VERB, params: { message } };
|
|
31
|
+
}
|
|
32
|
+
/** Extracts and validates the carried MeshMessage from an incoming command. Returns undefined for anything that isn't a well-formed frame -- an unrecognised or malformed payload is dropped, not thrown, the same tolerance TlsTransport's own frame parser already extends to input it can't make sense of. */
|
|
33
|
+
function extractMessage(command) {
|
|
34
|
+
if (command.verb !== FRAME_VERB)
|
|
35
|
+
return undefined;
|
|
36
|
+
const params = command.params;
|
|
37
|
+
if (typeof params !== "object" || params === null)
|
|
38
|
+
return undefined;
|
|
39
|
+
if (!("message" in params))
|
|
40
|
+
return undefined;
|
|
41
|
+
const message = params.message;
|
|
42
|
+
return isMeshMessage(message) ? message : undefined;
|
|
43
|
+
}
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
// WireMeshTransport
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
export class WireMeshTransport {
|
|
48
|
+
wireTransport;
|
|
49
|
+
events;
|
|
50
|
+
identityReady;
|
|
51
|
+
_dataPort = 0;
|
|
52
|
+
_isCoordinator = false;
|
|
53
|
+
shutDown = false;
|
|
54
|
+
/** A method call, not a direct property read -- deliberately, so TS's control-flow narrowing (which does track `this.shutDown` as staying false for the rest of a function once an early `if (this.shutDown) return` has passed, with no awareness that an `await` in between gave a concurrent shutdown() call the chance to flip it) doesn't treat every later re-check in the same async function as unreachable. Each of these re-checks is real: shutdown() can run at any time this function is suspended on an await. */
|
|
55
|
+
isShuttingDown() {
|
|
56
|
+
return this.shutDown;
|
|
57
|
+
}
|
|
58
|
+
// -- Data server (accepts data connections from already-known peers) --
|
|
59
|
+
dataListener;
|
|
60
|
+
// -- Coordinator listeners (the well-known bootstrap port, plus any additional adapters addListener creates) --
|
|
61
|
+
coordinatorListeners = new Map();
|
|
62
|
+
defaultListenerId;
|
|
63
|
+
// -- The session dialled via connectToCoordinator, when this instance is not itself the coordinator --
|
|
64
|
+
coordinatorSession;
|
|
65
|
+
// -- Every live session, keyed by the peer's authenticated device-id hex (== ConnectionHandle.id) -- covers coordinator-client, coordinator-accepted, and peer data sessions alike, since send()/broadcast() must reach whichever kind of session a peer happens to be reachable through. A single-slot-per-key map by construction: mesh formation genuinely establishes TWO independent sessions to the same peer (see the dataDials comment below), and the second one registered here simply overwrites the first as far as addressing goes -- fine for send()/broadcast() (either socket reaches the same peer), but NOT fine for shutdown, which must close every live session regardless of whether it's still reachable through this map. allSessions below exists specifically so shutdown never leaks the one this map's overwrite silently stopped tracking.
|
|
66
|
+
peerSessions = new Map();
|
|
67
|
+
// -- Every live session this transport has ever created, accepted or dialled, for shutdown's own use only -- never used for addressing (peerSessions is), so it never loses track of one session to another sharing the same peer id.
|
|
68
|
+
allSessions = new Set();
|
|
69
|
+
/** Registers a session in both peerSessions (addressing -- last one in for a given peer wins) and allSessions (shutdown -- every session, always). */
|
|
70
|
+
trackSession(key, session) {
|
|
71
|
+
this.peerSessions.set(key, session);
|
|
72
|
+
this.allSessions.add(session);
|
|
73
|
+
}
|
|
74
|
+
// -- Peers this side has dialled via connectToPeer specifically (in flight or established) -- deliberately separate from peerSessions, which also holds sessions this side reached the SAME peer through for an unrelated reason (most concretely, the coordinator-client session connectToCoordinator opens to the coordinator's own device-id). Mesh formation deliberately establishes a second, independent connection in each direction so each side's own acceptor can push its own state (see mesh-store.ts's own handlePeerConnected), so connectToPeer's "don't dial twice" guard must not be satisfied by an unrelated session that merely happens to share the same peer ID.
|
|
75
|
+
dataDials = new Set();
|
|
76
|
+
// -- connect_request frames awaiting a human accept/reject decision, keyed by the requester's device-id hex --
|
|
77
|
+
pendingConnections = new Map();
|
|
78
|
+
constructor(events, identity) {
|
|
79
|
+
this.events = events;
|
|
80
|
+
this.wireTransport = createTlsTransport({
|
|
81
|
+
certificatePem: identity.certificate,
|
|
82
|
+
privateKeyPem: identity.privateKey,
|
|
83
|
+
});
|
|
84
|
+
this.identityReady = toIdentityPort(identity);
|
|
85
|
+
}
|
|
86
|
+
// -- Public getters --
|
|
87
|
+
get dataPort() {
|
|
88
|
+
return this._dataPort;
|
|
89
|
+
}
|
|
90
|
+
get isCoordinator() {
|
|
91
|
+
return this._isCoordinator;
|
|
92
|
+
}
|
|
93
|
+
get hasCoordinatorConnection() {
|
|
94
|
+
return this.coordinatorSession !== undefined;
|
|
95
|
+
}
|
|
96
|
+
// -----------------------------------------------------------------------
|
|
97
|
+
// Connection acceptance -- shared by every listener (coordinator or data)
|
|
98
|
+
// -----------------------------------------------------------------------
|
|
99
|
+
async handleAcceptedConnection(connection, policy, fireOnPeerConnected) {
|
|
100
|
+
if (this.shutDown) {
|
|
101
|
+
await connection.close();
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const peerDeviceId = connection.peerDeviceId;
|
|
105
|
+
if (peerDeviceId === undefined) {
|
|
106
|
+
// No certificate presented at all -- nothing to authenticate this peer against.
|
|
107
|
+
await connection.close();
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const deviceIdHex = deviceIdToHex(peerDeviceId);
|
|
111
|
+
const identity = await this.identityReady;
|
|
112
|
+
const session = await acceptMeshSession(connection, identity, [DOMAIN]);
|
|
113
|
+
if (this.isShuttingDown()) {
|
|
114
|
+
await session.close();
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
this.trackSession(deviceIdHex, session);
|
|
118
|
+
// ConnectionHandle.policy is `?: ListenerPolicy`, not `?: ListenerPolicy | undefined` -- under exactOptionalPropertyTypes these are genuinely different types, so the key must be entirely absent rather than present-with-undefined-value when this listener has no policy of its own.
|
|
119
|
+
const handle = {
|
|
120
|
+
id: deviceIdHex,
|
|
121
|
+
...(policy !== undefined ? { policy } : {}),
|
|
122
|
+
};
|
|
123
|
+
if (fireOnPeerConnected) {
|
|
124
|
+
const info = {
|
|
125
|
+
id: deviceIdHex,
|
|
126
|
+
port: 0,
|
|
127
|
+
startedAt: new Date().toISOString(),
|
|
128
|
+
};
|
|
129
|
+
this.events.onPeerConnected(handle, info);
|
|
130
|
+
}
|
|
131
|
+
this.consumeIncoming(session, handle);
|
|
132
|
+
this.watchForDisconnect(session, handle, deviceIdHex);
|
|
133
|
+
}
|
|
134
|
+
consumeIncoming(session, handle) {
|
|
135
|
+
void (async () => {
|
|
136
|
+
for await (const request of session.incomingManageRequests) {
|
|
137
|
+
if (this.shutDown)
|
|
138
|
+
break;
|
|
139
|
+
await this.dispatchIncoming(request, handle);
|
|
140
|
+
}
|
|
141
|
+
})();
|
|
142
|
+
}
|
|
143
|
+
async dispatchIncoming(request, handle) {
|
|
144
|
+
const message = extractMessage(request.command);
|
|
145
|
+
if (message === undefined) {
|
|
146
|
+
await request.respond({ result: "ok" }).catch(() => undefined);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
if (message.method === "connect_request") {
|
|
150
|
+
// Held open deliberately -- see this file's own header comment. Answered later by acceptConnection/rejectConnection, not here.
|
|
151
|
+
this.pendingConnections.set(handle.id, {
|
|
152
|
+
respond: request.respond,
|
|
153
|
+
dataPort: message.dataPort,
|
|
154
|
+
name: message.name,
|
|
155
|
+
fingerprint: message.fingerprint,
|
|
156
|
+
policy: handle.policy,
|
|
157
|
+
});
|
|
158
|
+
this.events.onConnectionRequest(handle, {
|
|
159
|
+
peerId: handle.id,
|
|
160
|
+
dataPort: message.dataPort,
|
|
161
|
+
name: message.name,
|
|
162
|
+
fingerprint: message.fingerprint,
|
|
163
|
+
});
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
this.route(handle, message);
|
|
167
|
+
await request.respond({ result: "ok" }).catch(() => undefined);
|
|
168
|
+
}
|
|
169
|
+
/** Routes an already-decoded MeshMessage to the matching TransportEvents callback -- the same dispatch regardless of which listener (coordinator or data) accepted the connection it arrived on, since the message's own method, not the port it arrived on, is what determines meaning. */
|
|
170
|
+
route(handle, message) {
|
|
171
|
+
switch (message.method) {
|
|
172
|
+
case "introduce": {
|
|
173
|
+
this.events.onIntroduction(handle, {
|
|
174
|
+
peerId: handle.id,
|
|
175
|
+
dataPort: message.dataPort,
|
|
176
|
+
});
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
case "peer_list": {
|
|
180
|
+
this.events.onPeerList(message.peers);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
case "peer_joined": {
|
|
184
|
+
this.events.onPeerJoined(message.peer);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
case "become_coordinator": {
|
|
188
|
+
this.events.onBecomeCoordinator(message.peerList);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
case "connect_accepted":
|
|
192
|
+
case "connect_rejected": {
|
|
193
|
+
// Never constructed by this transport -- connectToRemote's own sendManageRequest outcome carries this meaning directly. Dropped rather than treated as an error in case a future peer still sends one (forward compatibility with anything else speaking this same opaque-frame domain).
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
default: {
|
|
197
|
+
this.events.onMessage(handle, message);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
watchForDisconnect(session, handle, deviceIdHex) {
|
|
202
|
+
void (async () => {
|
|
203
|
+
for await (const event of session.events) {
|
|
204
|
+
if (event.state.status === "closed") {
|
|
205
|
+
const wasTracked = this.peerSessions.get(deviceIdHex) === session;
|
|
206
|
+
if (wasTracked)
|
|
207
|
+
this.peerSessions.delete(deviceIdHex);
|
|
208
|
+
this.allSessions.delete(session);
|
|
209
|
+
this.pendingConnections.delete(deviceIdHex);
|
|
210
|
+
// A no-op when this session was never a connectToPeer dial (e.g. the coordinator-client or an accepted connection) -- Set.delete on an absent key is always safe.
|
|
211
|
+
this.dataDials.delete(deviceIdHex);
|
|
212
|
+
if (wasTracked && !this.shutDown) {
|
|
213
|
+
this.events.onPeerDisconnected(handle);
|
|
214
|
+
}
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
})();
|
|
219
|
+
}
|
|
220
|
+
// -----------------------------------------------------------------------
|
|
221
|
+
// MeshTransport -- Data server
|
|
222
|
+
// -----------------------------------------------------------------------
|
|
223
|
+
async startDataServer() {
|
|
224
|
+
this.dataListener = await this.wireTransport.listen(`${COORDINATOR_HOST}:0`, (connection) => {
|
|
225
|
+
void this.handleAcceptedConnection(connection, undefined, true);
|
|
226
|
+
});
|
|
227
|
+
const port = this.dataListener.address.split(":").pop();
|
|
228
|
+
this._dataPort = port === undefined ? 0 : Number(port);
|
|
229
|
+
}
|
|
230
|
+
// -----------------------------------------------------------------------
|
|
231
|
+
// MeshTransport -- Coordinator connection (client side)
|
|
232
|
+
// -----------------------------------------------------------------------
|
|
233
|
+
async connectToCoordinator(host, port, peerId, dataPort) {
|
|
234
|
+
const connection = await this.wireTransport.connect(`${host}:${String(port)}`);
|
|
235
|
+
const identity = await this.identityReady;
|
|
236
|
+
const session = await acceptMeshSession(connection, identity, [DOMAIN]);
|
|
237
|
+
this.coordinatorSession = session;
|
|
238
|
+
const coordinatorDeviceId = connection.peerDeviceId;
|
|
239
|
+
if (coordinatorDeviceId !== undefined) {
|
|
240
|
+
const handle = {
|
|
241
|
+
id: deviceIdToHex(coordinatorDeviceId),
|
|
242
|
+
};
|
|
243
|
+
this.trackSession(handle.id, session);
|
|
244
|
+
this.consumeIncoming(session, handle);
|
|
245
|
+
this.watchForDisconnect(session, handle, handle.id);
|
|
246
|
+
}
|
|
247
|
+
// Fire-and-forget, matching the previous transport's own contract: this resolves once the introduction is sent, not once a response arrives -- peer_list/peer_joined/become_coordinator arrive asynchronously via the normal dispatch path above, independent of this call's own promise.
|
|
248
|
+
void session
|
|
249
|
+
.sendManageRequest(buildCommand({ method: "introduce", peerId, dataPort }), FRAME_SCOPE)
|
|
250
|
+
.catch(() => undefined);
|
|
251
|
+
}
|
|
252
|
+
// -----------------------------------------------------------------------
|
|
253
|
+
// MeshTransport -- Become coordinator (server side)
|
|
254
|
+
// -----------------------------------------------------------------------
|
|
255
|
+
async becomeCoordinator(host, port) {
|
|
256
|
+
const id = nanoid(8);
|
|
257
|
+
const listener = await this.wireTransport.listen(`${host}:${String(port)}`, (connection) => {
|
|
258
|
+
const tracked = this.coordinatorListeners.get(id);
|
|
259
|
+
void this.handleAcceptedConnection(connection, tracked?.policy, false);
|
|
260
|
+
});
|
|
261
|
+
this._isCoordinator = true;
|
|
262
|
+
this.coordinatorListeners.set(id, {
|
|
263
|
+
listener,
|
|
264
|
+
policy: "full",
|
|
265
|
+
host,
|
|
266
|
+
port,
|
|
267
|
+
isDefault: true,
|
|
268
|
+
});
|
|
269
|
+
this.defaultListenerId = id;
|
|
270
|
+
}
|
|
271
|
+
// -----------------------------------------------------------------------
|
|
272
|
+
// MeshTransport -- Peer-to-peer data connections
|
|
273
|
+
// -----------------------------------------------------------------------
|
|
274
|
+
async connectToPeer(peer, _ownPeerId) {
|
|
275
|
+
if (this.shutDown || this.dataDials.has(peer.id))
|
|
276
|
+
return;
|
|
277
|
+
this.dataDials.add(peer.id);
|
|
278
|
+
const connection = await this.wireTransport
|
|
279
|
+
.connect(`${COORDINATOR_HOST}:${String(peer.port)}`)
|
|
280
|
+
.catch((error) => {
|
|
281
|
+
this.events.onError?.(error instanceof Error
|
|
282
|
+
? new Error(`connectToPeer(${peer.id}, port ${String(peer.port)}): ${error.message}`)
|
|
283
|
+
: new Error(`connectToPeer(${peer.id}, port ${String(peer.port)}) failed`));
|
|
284
|
+
return undefined;
|
|
285
|
+
});
|
|
286
|
+
if (connection === undefined || this.isShuttingDown()) {
|
|
287
|
+
this.dataDials.delete(peer.id);
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
const peerDeviceId = connection.peerDeviceId;
|
|
291
|
+
if (peerDeviceId === undefined) {
|
|
292
|
+
this.dataDials.delete(peer.id);
|
|
293
|
+
await connection.close();
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
const deviceIdHex = deviceIdToHex(peerDeviceId);
|
|
297
|
+
if (deviceIdHex !== peer.id) {
|
|
298
|
+
// The peer we reached does not hold the key peer.id claims to name -- refuse exactly like a mismatched fingerprint would have under the previous transport.
|
|
299
|
+
this.events.onError?.(new Error(`connectToPeer: peer at port ${String(peer.port)} authenticated as ${deviceIdHex}, expected ${peer.id}`));
|
|
300
|
+
this.dataDials.delete(peer.id);
|
|
301
|
+
await connection.close();
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
const identity = await this.identityReady;
|
|
305
|
+
const session = await acceptMeshSession(connection, identity, [DOMAIN]);
|
|
306
|
+
if (this.isShuttingDown()) {
|
|
307
|
+
this.dataDials.delete(peer.id);
|
|
308
|
+
await session.close();
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
this.trackSession(deviceIdHex, session);
|
|
312
|
+
const handle = { id: deviceIdHex };
|
|
313
|
+
this.consumeIncoming(session, handle);
|
|
314
|
+
this.watchForDisconnect(session, handle, deviceIdHex);
|
|
315
|
+
}
|
|
316
|
+
// -----------------------------------------------------------------------
|
|
317
|
+
// MeshTransport -- Send / broadcast
|
|
318
|
+
// -----------------------------------------------------------------------
|
|
319
|
+
async send(handle, message) {
|
|
320
|
+
const session = this.peerSessions.get(handle.id);
|
|
321
|
+
if (session === undefined)
|
|
322
|
+
return;
|
|
323
|
+
await session
|
|
324
|
+
.sendManageRequest(buildCommand(message), FRAME_SCOPE)
|
|
325
|
+
.catch((error) => {
|
|
326
|
+
this.events.onError?.(error instanceof Error
|
|
327
|
+
? error
|
|
328
|
+
: new Error(`send(${handle.id}) failed: ${String(error)}`));
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
async broadcast(message) {
|
|
332
|
+
const command = buildCommand(message);
|
|
333
|
+
await Promise.all([...this.peerSessions.values()].map((session) => session.sendManageRequest(command, FRAME_SCOPE).catch(() => undefined)));
|
|
334
|
+
}
|
|
335
|
+
// -----------------------------------------------------------------------
|
|
336
|
+
// MeshTransport -- Connection approval (connectToRemote flow)
|
|
337
|
+
// -----------------------------------------------------------------------
|
|
338
|
+
async connectToRemote(host, port, peerId, dataPort, name, fingerprint) {
|
|
339
|
+
const connection = await this.wireTransport.connect(`${host}:${String(port)}`);
|
|
340
|
+
const identity = await this.identityReady;
|
|
341
|
+
const session = await acceptMeshSession(connection, identity, [DOMAIN]);
|
|
342
|
+
const outcome = await session.sendManageRequest(buildCommand({
|
|
343
|
+
method: "connect_request",
|
|
344
|
+
peerId,
|
|
345
|
+
dataPort,
|
|
346
|
+
name,
|
|
347
|
+
fingerprint,
|
|
348
|
+
}), FRAME_SCOPE);
|
|
349
|
+
if (outcome.result === "error") {
|
|
350
|
+
await session.close();
|
|
351
|
+
throw new Error(outcome.message ?? outcome.code);
|
|
352
|
+
}
|
|
353
|
+
const coordinatorDeviceId = connection.peerDeviceId;
|
|
354
|
+
if (coordinatorDeviceId !== undefined) {
|
|
355
|
+
const handle = {
|
|
356
|
+
id: deviceIdToHex(coordinatorDeviceId),
|
|
357
|
+
};
|
|
358
|
+
this.trackSession(handle.id, session);
|
|
359
|
+
this.consumeIncoming(session, handle);
|
|
360
|
+
this.watchForDisconnect(session, handle, handle.id);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
async acceptConnection(handle) {
|
|
364
|
+
const pending = this.pendingConnections.get(handle.id);
|
|
365
|
+
if (pending === undefined) {
|
|
366
|
+
throw new Error(`No pending connection for handle ${handle.id}`);
|
|
367
|
+
}
|
|
368
|
+
this.pendingConnections.delete(handle.id);
|
|
369
|
+
await pending.respond({ result: "ok" });
|
|
370
|
+
const acceptedHandle = {
|
|
371
|
+
id: handle.id,
|
|
372
|
+
...(pending.policy !== undefined ? { policy: pending.policy } : {}),
|
|
373
|
+
};
|
|
374
|
+
this.events.onIntroduction(acceptedHandle, {
|
|
375
|
+
peerId: handle.id,
|
|
376
|
+
dataPort: pending.dataPort,
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
async rejectConnection(handle, reason) {
|
|
380
|
+
const pending = this.pendingConnections.get(handle.id);
|
|
381
|
+
if (pending === undefined) {
|
|
382
|
+
throw new Error(`No pending connection for handle ${handle.id}`);
|
|
383
|
+
}
|
|
384
|
+
this.pendingConnections.delete(handle.id);
|
|
385
|
+
await pending.respond({
|
|
386
|
+
result: "error",
|
|
387
|
+
code: "rejected",
|
|
388
|
+
message: reason,
|
|
389
|
+
});
|
|
390
|
+
const session = this.peerSessions.get(handle.id);
|
|
391
|
+
this.peerSessions.delete(handle.id);
|
|
392
|
+
if (session !== undefined)
|
|
393
|
+
await session.close();
|
|
394
|
+
}
|
|
395
|
+
// -----------------------------------------------------------------------
|
|
396
|
+
// MeshTransport -- Listener management
|
|
397
|
+
// -----------------------------------------------------------------------
|
|
398
|
+
async addListener(host, port, policy) {
|
|
399
|
+
const id = nanoid(8);
|
|
400
|
+
const listener = await this.wireTransport.listen(`${host}:${String(port)}`, (connection) => {
|
|
401
|
+
void this.handleAcceptedConnection(connection, policy, false);
|
|
402
|
+
});
|
|
403
|
+
this.coordinatorListeners.set(id, {
|
|
404
|
+
listener,
|
|
405
|
+
policy,
|
|
406
|
+
host,
|
|
407
|
+
port,
|
|
408
|
+
isDefault: false,
|
|
409
|
+
});
|
|
410
|
+
return id;
|
|
411
|
+
}
|
|
412
|
+
async removeListener(id) {
|
|
413
|
+
if (id === this.defaultListenerId) {
|
|
414
|
+
throw new Error("Cannot remove the default listener");
|
|
415
|
+
}
|
|
416
|
+
const tracked = this.coordinatorListeners.get(id);
|
|
417
|
+
if (tracked === undefined)
|
|
418
|
+
return;
|
|
419
|
+
this.coordinatorListeners.delete(id);
|
|
420
|
+
await tracked.listener.close();
|
|
421
|
+
}
|
|
422
|
+
listListeners() {
|
|
423
|
+
return [...this.coordinatorListeners.entries()].map(([id, tracked]) => ({
|
|
424
|
+
id,
|
|
425
|
+
host: tracked.host,
|
|
426
|
+
port: tracked.port,
|
|
427
|
+
policy: tracked.policy,
|
|
428
|
+
isDefault: tracked.isDefault,
|
|
429
|
+
}));
|
|
430
|
+
}
|
|
431
|
+
// -----------------------------------------------------------------------
|
|
432
|
+
// MeshTransport -- Shutdown / unref
|
|
433
|
+
// -----------------------------------------------------------------------
|
|
434
|
+
async shutdown() {
|
|
435
|
+
this.shutDown = true;
|
|
436
|
+
this.dataDials.clear();
|
|
437
|
+
for (const pending of this.pendingConnections.values()) {
|
|
438
|
+
await pending
|
|
439
|
+
.respond({ result: "error", code: "shutting_down" })
|
|
440
|
+
.catch(() => undefined);
|
|
441
|
+
}
|
|
442
|
+
this.pendingConnections.clear();
|
|
443
|
+
// Every live session, whichever of possibly several to the same peer -- peerSessions alone would only close the last one registered under a shared key, leaving any other (e.g. the coordinator-client session to a peer this side also has a data connection to) still open and accepting, which would make the listener it belongs to wait forever for it to end.
|
|
444
|
+
for (const session of this.allSessions) {
|
|
445
|
+
await session.close().catch(() => undefined);
|
|
446
|
+
}
|
|
447
|
+
this.allSessions.clear();
|
|
448
|
+
this.peerSessions.clear();
|
|
449
|
+
this.coordinatorSession = undefined;
|
|
450
|
+
if (this.dataListener !== undefined) {
|
|
451
|
+
await this.dataListener.close();
|
|
452
|
+
this.dataListener = undefined;
|
|
453
|
+
}
|
|
454
|
+
for (const tracked of this.coordinatorListeners.values()) {
|
|
455
|
+
await tracked.listener.close();
|
|
456
|
+
}
|
|
457
|
+
this.coordinatorListeners.clear();
|
|
458
|
+
}
|
|
459
|
+
unref() {
|
|
460
|
+
this.dataListener?.unref?.();
|
|
461
|
+
for (const tracked of this.coordinatorListeners.values()) {
|
|
462
|
+
tracked.listener.unref?.();
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
//# sourceMappingURL=wire-mesh-transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wire-mesh-transport.js","sourceRoot":"","sources":["../../src/core/wire-mesh-transport.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for createBridgeMesh -- the shared factory every bridge builds its own MeshStore/WireMeshTransport/CommsTool from, replacing the identical four-line block each of the six bridges used to repeat against TlsTransport directly.
|
|
3
|
+
*/
|
|
4
|
+
export {};
|
|
5
|
+
//# sourceMappingURL=bridge-mesh.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge-mesh.test.d.ts","sourceRoot":"","sources":["../../src/test/bridge-mesh.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for createBridgeMesh -- the shared factory every bridge builds its own MeshStore/WireMeshTransport/CommsTool from, replacing the identical four-line block each of the six bridges used to repeat against TlsTransport directly.
|
|
3
|
+
*/
|
|
4
|
+
import * as assert from "node:assert/strict";
|
|
5
|
+
import * as fs from "node:fs";
|
|
6
|
+
import { tmpdir } from "node:os";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import { test } from "node:test";
|
|
9
|
+
import { deviceIdToHex } from "@exadev/wire-mesh-core/domain/device-id";
|
|
10
|
+
import { createBridgeMesh } from "../core/bridge-mesh.js";
|
|
11
|
+
import { loadOrCreateIdentity, } from "../core/identity-store.js";
|
|
12
|
+
import { waitFor } from "./test-transport.js";
|
|
13
|
+
function tempSlot(harness) {
|
|
14
|
+
const dir = fs.mkdtempSync(path.join(tmpdir(), "agent-comms-bridge-mesh-test-"));
|
|
15
|
+
return { harness, cwd: "/tmp/project", dir };
|
|
16
|
+
}
|
|
17
|
+
void test("createBridgeMesh sets peerId to deviceIdToHex(identity.deviceId), not the certificate fingerprint", async () => {
|
|
18
|
+
const slot = tempSlot("test-harness");
|
|
19
|
+
const identity = loadOrCreateIdentity(slot);
|
|
20
|
+
const { store } = createBridgeMesh(slot);
|
|
21
|
+
try {
|
|
22
|
+
assert.strictEqual(store.peerId, deviceIdToHex(Uint8Array.from(identity.deviceId)));
|
|
23
|
+
assert.notStrictEqual(store.peerId, identity.fingerprint);
|
|
24
|
+
}
|
|
25
|
+
finally {
|
|
26
|
+
await store.shutdown();
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
void test("createBridgeMesh wires a WireMeshTransport, not TlsTransport", async () => {
|
|
30
|
+
const slot = tempSlot("test-harness");
|
|
31
|
+
const { store } = createBridgeMesh(slot);
|
|
32
|
+
try {
|
|
33
|
+
// init() is the only way to prove the transport is actually usable end to end, which also confirms it's a WireMeshTransport by construction (createBridgeMesh only ever builds one).
|
|
34
|
+
await store.init();
|
|
35
|
+
assert.ok(store.connected);
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
await store.shutdown();
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
void test("createBridgeMesh passes an explicit coordinatorPort through to MeshStore, forming one shared mesh", async () => {
|
|
42
|
+
const slotA = tempSlot("test-harness-a");
|
|
43
|
+
const slotB = tempSlot("test-harness-b");
|
|
44
|
+
const port = 20_900 + Math.floor(Math.random() * 100);
|
|
45
|
+
const a = createBridgeMesh(slotA, port);
|
|
46
|
+
const b = createBridgeMesh(slotB, port);
|
|
47
|
+
try {
|
|
48
|
+
await a.store.init();
|
|
49
|
+
await b.store.init();
|
|
50
|
+
assert.ok(a.store.connected);
|
|
51
|
+
assert.ok(b.store.connected);
|
|
52
|
+
await a.store.registerAgent({
|
|
53
|
+
name: "peer-a",
|
|
54
|
+
harness: "test-harness-a",
|
|
55
|
+
cwd: "/tmp/project",
|
|
56
|
+
pid: process.pid,
|
|
57
|
+
visibility: "visible",
|
|
58
|
+
tags: [],
|
|
59
|
+
});
|
|
60
|
+
await waitFor(() => b.store.serialise().agents[a.store.peerId] !== undefined, "b sees a's agent, proving both joined the same mesh on the shared coordinatorPort");
|
|
61
|
+
}
|
|
62
|
+
finally {
|
|
63
|
+
await b.store.shutdown();
|
|
64
|
+
await a.store.shutdown();
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
//# sourceMappingURL=bridge-mesh.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge-mesh.test.js","sourceRoot":"","sources":["../../src/test/bridge-mesh.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Delivery receipt test runner — runs each test case in an isolated child
|
|
4
|
-
* process. Tests MUST NOT be run from within a process that has the
|
|
5
|
-
* agent-comms extension loaded (e.g. pi's agent session), because the
|
|
6
|
-
* parent's active TCP handles interfere with child process forking.
|
|
3
|
+
* Delivery receipt test runner — runs each test case in an isolated child process. Tests MUST NOT be run from within a process that has the agent-comms extension loaded (e.g. pi's agent session), because the parent's active TCP handles interfere with child process forking.
|
|
7
4
|
*
|
|
8
|
-
* Usage:
|
|
9
|
-
* pnpm test:delivery # from a clean shell (recommended)
|
|
10
|
-
* node dist/test/delivery-receipt.runner.js
|
|
5
|
+
* Usage: pnpm test:delivery # from a clean shell (recommended) tsx src/test/delivery-receipt.runner.ts
|
|
11
6
|
*/
|
|
12
7
|
export {};
|
|
13
8
|
//# sourceMappingURL=delivery-receipt.runner.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delivery-receipt.runner.d.ts","sourceRoot":"","sources":["../../src/test/delivery-receipt.runner.ts"],"names":[],"mappings":";AACA
|
|
1
|
+
{"version":3,"file":"delivery-receipt.runner.d.ts","sourceRoot":"","sources":["../../src/test/delivery-receipt.runner.ts"],"names":[],"mappings":";AACA;;;;GAIG"}
|
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Delivery receipt test runner — runs each test case in an isolated child
|
|
4
|
-
* process. Tests MUST NOT be run from within a process that has the
|
|
5
|
-
* agent-comms extension loaded (e.g. pi's agent session), because the
|
|
6
|
-
* parent's active TCP handles interfere with child process forking.
|
|
3
|
+
* Delivery receipt test runner — runs each test case in an isolated child process. Tests MUST NOT be run from within a process that has the agent-comms extension loaded (e.g. pi's agent session), because the parent's active TCP handles interfere with child process forking.
|
|
7
4
|
*
|
|
8
|
-
* Usage:
|
|
9
|
-
* pnpm test:delivery # from a clean shell (recommended)
|
|
10
|
-
* node dist/test/delivery-receipt.runner.js
|
|
5
|
+
* Usage: pnpm test:delivery # from a clean shell (recommended) tsx src/test/delivery-receipt.runner.ts
|
|
11
6
|
*/
|
|
12
7
|
import { execFileSync } from "node:child_process";
|
|
13
8
|
import * as path from "node:path";
|
|
14
9
|
import * as url from "node:url";
|
|
15
10
|
const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
|
|
16
|
-
const HELPER = path.join(__dirname, "delivery-receipt.helper.
|
|
11
|
+
const HELPER = path.join(__dirname, "delivery-receipt.helper.ts");
|
|
17
12
|
const tests = [
|
|
18
13
|
"push-room",
|
|
19
14
|
"push-dm",
|
|
@@ -26,7 +21,7 @@ const tests = [
|
|
|
26
21
|
let failed = false;
|
|
27
22
|
for (const t of tests) {
|
|
28
23
|
try {
|
|
29
|
-
const stdout = execFileSync(process.execPath, [HELPER, t], {
|
|
24
|
+
const stdout = execFileSync(process.execPath, ["--import", "tsx", HELPER, t], {
|
|
30
25
|
timeout: 15_000,
|
|
31
26
|
stdio: ["pipe", "pipe", "pipe"],
|
|
32
27
|
encoding: "utf-8",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delivery-receipt.runner.js","sourceRoot":"","sources":["../../src/test/delivery-receipt.runner.ts"],"names":[],"mappings":";AACA
|
|
1
|
+
{"version":3,"file":"delivery-receipt.runner.js","sourceRoot":"","sources":["../../src/test/delivery-receipt.runner.ts"],"names":[],"mappings":";AACA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAEhC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACnE,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,4BAA4B,CAAC,CAAC;AAElE,MAAM,KAAK,GAAG;IACZ,WAAW;IACX,SAAS;IACT,YAAY;IACZ,UAAU;IACV,mBAAmB;IACnB,oBAAoB;IACpB,cAAc;CACf,CAAC;AAEF,IAAI,MAAM,GAAG,KAAK,CAAC;AAEnB,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;IACtB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,YAAY,CACzB,OAAO,CAAC,QAAQ,EAChB,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,EAC9B;YACE,OAAO,EAAE,MAAM;YACf,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;YAC/B,QAAQ,EAAE,OAAO;SAClB,CACF,CAAC;QACF,IAAI,MAAM,CAAC,IAAI,EAAE;YAAE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9C,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IAAC,OAAO,CAAU,EAAE,CAAC;QACpB,MAAM,GAAG,GACP,CAAC,YAAY,KAAK,IAAI,QAAQ,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ;YACjE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,OAAO;YAC9B,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAChB,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;QAC/B,MAAM,GAAG,IAAI,CAAC;QACd,MAAM;IACR,CAAC;AACH,CAAC;AAED,IAAI,CAAC,MAAM,EAAE,CAAC;IACZ,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;AACxD,CAAC;AAED,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC"}
|