agent-comms 4.1.9 → 4.2.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 +3 -1
- package/dist/bridges/cc-peer/approval-commands.d.ts +26 -0
- package/dist/bridges/cc-peer/approval-commands.d.ts.map +1 -0
- package/dist/bridges/cc-peer/approval-commands.js +56 -0
- package/dist/bridges/cc-peer/approval-commands.js.map +1 -0
- package/dist/bridges/cc-peer/bridge.d.ts +2 -0
- package/dist/bridges/cc-peer/bridge.d.ts.map +1 -1
- package/dist/bridges/cc-peer/bridge.js +16 -8
- package/dist/bridges/cc-peer/bridge.js.map +1 -1
- package/dist/bridges/cc-peer/default-front.d.ts +2 -0
- package/dist/bridges/cc-peer/default-front.d.ts.map +1 -1
- package/dist/bridges/cc-peer/default-front.js +1 -0
- package/dist/bridges/cc-peer/default-front.js.map +1 -1
- package/dist/bridges/cc-peer/front-relay.d.ts +2 -0
- package/dist/bridges/cc-peer/front-relay.d.ts.map +1 -1
- package/dist/bridges/cc-peer/front-relay.js +17 -9
- package/dist/bridges/cc-peer/front-relay.js.map +1 -1
- package/dist/bridges/cc-peer/front-runtime.d.ts +2 -0
- package/dist/bridges/cc-peer/front-runtime.d.ts.map +1 -1
- package/dist/bridges/cc-peer/front-runtime.js +2 -0
- package/dist/bridges/cc-peer/front-runtime.js.map +1 -1
- package/dist/bridges/cc-peer/run.d.ts.map +1 -1
- package/dist/bridges/cc-peer/run.js +5 -1
- package/dist/bridges/cc-peer/run.js.map +1 -1
- package/dist/core/mesh-store.d.ts.map +1 -1
- package/dist/core/mesh-store.js +1 -0
- package/dist/core/mesh-store.js.map +1 -1
- package/dist/core/room-discovery.d.ts +16 -0
- package/dist/core/room-discovery.d.ts.map +1 -0
- package/dist/core/room-discovery.js +39 -0
- package/dist/core/room-discovery.js.map +1 -0
- package/dist/core/room-lifecycle.d.ts +6 -3
- package/dist/core/room-lifecycle.d.ts.map +1 -1
- package/dist/core/room-lifecycle.js +19 -41
- package/dist/core/room-lifecycle.js.map +1 -1
- package/dist/core/room-lookup.d.ts +10 -4
- package/dist/core/room-lookup.d.ts.map +1 -1
- package/dist/core/room-lookup.js +18 -13
- package/dist/core/room-lookup.js.map +1 -1
- package/dist/core/room-messaging.d.ts +2 -0
- package/dist/core/room-messaging.d.ts.map +1 -1
- package/dist/core/room-messaging.js +2 -3
- package/dist/core/room-messaging.js.map +1 -1
- package/dist/test/cc-peer-approval-commands.unit.test.d.ts +2 -0
- package/dist/test/cc-peer-approval-commands.unit.test.d.ts.map +1 -0
- package/dist/test/cc-peer-approval-commands.unit.test.js +110 -0
- package/dist/test/cc-peer-approval-commands.unit.test.js.map +1 -0
- package/dist/test/cc-peer-bridge.unit.test.js +107 -0
- package/dist/test/cc-peer-bridge.unit.test.js.map +1 -1
- package/dist/test/cc-peer-front-relay.unit.test.js +113 -0
- package/dist/test/cc-peer-front-relay.unit.test.js.map +1 -1
- package/dist/test/cc-peer-fronted-approval.integration.test.d.ts +5 -0
- package/dist/test/cc-peer-fronted-approval.integration.test.d.ts.map +1 -0
- package/dist/test/cc-peer-fronted-approval.integration.test.js +125 -0
- package/dist/test/cc-peer-fronted-approval.integration.test.js.map +1 -0
- package/dist/test/room-join-by-bare-name.integration.test.d.ts +5 -0
- package/dist/test/room-join-by-bare-name.integration.test.d.ts.map +1 -0
- package/dist/test/room-join-by-bare-name.integration.test.js +130 -0
- package/dist/test/room-join-by-bare-name.integration.test.js.map +1 -0
- package/dist/test/room-lifecycle-bare-name.unit.test.d.ts +2 -0
- package/dist/test/room-lifecycle-bare-name.unit.test.d.ts.map +1 -0
- package/dist/test/room-lifecycle-bare-name.unit.test.js +180 -0
- package/dist/test/room-lifecycle-bare-name.unit.test.js.map +1 -0
- package/dist/test/room-lookup.unit.test.d.ts +2 -0
- package/dist/test/room-lookup.unit.test.d.ts.map +1 -0
- package/dist/test/room-lookup.unit.test.js +59 -0
- package/dist/test/room-lookup.unit.test.js.map +1 -0
- package/dist/test/room-messaging-durable-send.unit.test.js +2 -0
- package/dist/test/room-messaging-durable-send.unit.test.js.map +1 -1
- package/dist/test/room-messaging.unit.test.js +24 -1
- package/dist/test/room-messaging.unit.test.js.map +1 -1
- package/dist/test/test-transport.d.ts +2 -2
- package/dist/test/test-transport.d.ts.map +1 -1
- package/dist/test/test-transport.js +2 -1
- package/dist/test/test-transport.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration test for the whole first-contact path to a session reached only through cc-peer: a real store fronted by buildFrontedSessionRecord, a real CommsTool, and a fake cc-peer peer standing in for the session. The session is told what to send, sends it, and that alone admits the requester.
|
|
3
|
+
*/
|
|
4
|
+
import { test, expect } from "vitest";
|
|
5
|
+
import { MeshStore } from "../core/mesh-store.js";
|
|
6
|
+
import { CommsTool } from "../core/tool.js";
|
|
7
|
+
import { dmRoomPath } from "../core/room-path.js";
|
|
8
|
+
import { buildFrontedSessionRecord } from "../bridges/cc-peer/front-relay.js";
|
|
9
|
+
import { waitFor, wireTestTransport } from "./test-transport.js";
|
|
10
|
+
let nextPort = 24_450;
|
|
11
|
+
function freshPort() {
|
|
12
|
+
nextPort += 1;
|
|
13
|
+
return nextPort;
|
|
14
|
+
}
|
|
15
|
+
const PEER_NAME = "agent-comms-front";
|
|
16
|
+
const SESSION_PID = 4242;
|
|
17
|
+
async function registered(port, name) {
|
|
18
|
+
const store = new MeshStore({ coordinatorPort: port });
|
|
19
|
+
await wireTestTransport(store);
|
|
20
|
+
await store.init();
|
|
21
|
+
await store.registerAgent({
|
|
22
|
+
name,
|
|
23
|
+
harness: "test",
|
|
24
|
+
cwd: `/test/${name}`,
|
|
25
|
+
pid: process.pid,
|
|
26
|
+
visibility: "visible",
|
|
27
|
+
tags: [],
|
|
28
|
+
});
|
|
29
|
+
return store;
|
|
30
|
+
}
|
|
31
|
+
test("a session with no agent-comms tool admits a first-contact DM by messaging the front, and hears the outcome", async () => {
|
|
32
|
+
const port = freshPort();
|
|
33
|
+
const sender = await registered(port, "sender");
|
|
34
|
+
const fronted = await registered(port, "fronted");
|
|
35
|
+
await waitFor(() => sender.serialise().agents[fronted.peerId] !== undefined, "the sender sees the fronted agent");
|
|
36
|
+
const toSession = [];
|
|
37
|
+
const record = buildFrontedSessionRecord({
|
|
38
|
+
entry: {
|
|
39
|
+
pid: SESSION_PID,
|
|
40
|
+
cwd: "/test/fronted",
|
|
41
|
+
version: "2.1.278",
|
|
42
|
+
messagingSocketPath: "/tmp/cc-socks/fronted.sock",
|
|
43
|
+
},
|
|
44
|
+
peerName: PEER_NAME,
|
|
45
|
+
agentId: fronted.peerId,
|
|
46
|
+
roomId: "unused",
|
|
47
|
+
store: fronted,
|
|
48
|
+
tool: new CommsTool(fronted),
|
|
49
|
+
peer: {
|
|
50
|
+
send: async (_target, body) => {
|
|
51
|
+
toSession.push(body);
|
|
52
|
+
return Promise.resolve({ msgId: "m" });
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
aliasPool: { ensure: async () => Promise.resolve() },
|
|
56
|
+
aliasDirectory: { ensure: (correspondent) => `mesh-${correspondent}` },
|
|
57
|
+
});
|
|
58
|
+
try {
|
|
59
|
+
const dmPath = dmRoomPath(sender.peerId, fronted.peerId);
|
|
60
|
+
const send = sender.sendDm(sender.peerId, fronted.peerId, "hello session");
|
|
61
|
+
await waitFor(() => toSession.some((body) => body.includes("accept ")), "the session is told a request is waiting");
|
|
62
|
+
const instruction = toSession.find((body) => body.includes("accept "));
|
|
63
|
+
const command = instruction
|
|
64
|
+
?.split("\n")
|
|
65
|
+
.find((line) => line.startsWith("accept "));
|
|
66
|
+
expect(command).toBe(`accept ${dmPath} ${sender.peerId}`);
|
|
67
|
+
expect(instruction).toContain(`"${PEER_NAME}"`);
|
|
68
|
+
// The session replies with exactly the line it was given.
|
|
69
|
+
record.handleInbound({
|
|
70
|
+
from: `uds:${record.messagingSocketPath}`,
|
|
71
|
+
body: command ?? "",
|
|
72
|
+
});
|
|
73
|
+
const sent = await send;
|
|
74
|
+
await waitFor(() => (fronted.serialise().dms[dmPath] ?? []).some((m) => m.id === sent.id), "the fronted agent receives the DM");
|
|
75
|
+
await waitFor(() => toSession.some((body) => body.startsWith("Accepted ")), "the session hears the outcome");
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
await fronted.shutdown();
|
|
79
|
+
await sender.shutdown();
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
test("a session that rejects a first-contact DM makes the sender's dm fail", async () => {
|
|
83
|
+
const port = freshPort();
|
|
84
|
+
const sender = await registered(port, "sender");
|
|
85
|
+
const fronted = await registered(port, "fronted");
|
|
86
|
+
await waitFor(() => sender.serialise().agents[fronted.peerId] !== undefined, "the sender sees the fronted agent");
|
|
87
|
+
const toSession = [];
|
|
88
|
+
const record = buildFrontedSessionRecord({
|
|
89
|
+
entry: {
|
|
90
|
+
pid: SESSION_PID,
|
|
91
|
+
cwd: "/test/fronted",
|
|
92
|
+
version: "2.1.278",
|
|
93
|
+
messagingSocketPath: "/tmp/cc-socks/fronted.sock",
|
|
94
|
+
},
|
|
95
|
+
peerName: PEER_NAME,
|
|
96
|
+
agentId: fronted.peerId,
|
|
97
|
+
roomId: "unused",
|
|
98
|
+
store: fronted,
|
|
99
|
+
tool: new CommsTool(fronted),
|
|
100
|
+
peer: {
|
|
101
|
+
send: async (_target, body) => {
|
|
102
|
+
toSession.push(body);
|
|
103
|
+
return Promise.resolve({ msgId: "m" });
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
aliasPool: { ensure: async () => Promise.resolve() },
|
|
107
|
+
aliasDirectory: { ensure: (correspondent) => `mesh-${correspondent}` },
|
|
108
|
+
});
|
|
109
|
+
try {
|
|
110
|
+
const dmPath = dmRoomPath(sender.peerId, fronted.peerId);
|
|
111
|
+
const send = sender.sendDm(sender.peerId, fronted.peerId, "unwelcome");
|
|
112
|
+
const settled = expect(send).rejects.toThrow(/was refused \(denied\)/);
|
|
113
|
+
await waitFor(() => toSession.some((body) => body.includes("reject ")), "the session is told a request is waiting");
|
|
114
|
+
record.handleInbound({
|
|
115
|
+
body: `reject ${dmPath} ${sender.peerId} not now`,
|
|
116
|
+
});
|
|
117
|
+
await settled;
|
|
118
|
+
await waitFor(() => toSession.some((body) => body.startsWith("Rejected ")), "the session hears the outcome");
|
|
119
|
+
}
|
|
120
|
+
finally {
|
|
121
|
+
await fronted.shutdown();
|
|
122
|
+
await sender.shutdown();
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
//# sourceMappingURL=cc-peer-fronted-approval.integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cc-peer-fronted-approval.integration.test.js","sourceRoot":"","sources":["../../src/test/cc-peer-fronted-approval.integration.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agent-comms#246 -- list_rooms shows a room hosted by another device by its bare name, so join_room must accept that same bare name, not only the full `<hostDevice>/<name>` room-path. Over a real relay hub the joiner has never received the host's room through any legacy full-state-sync, so the only thing that tells it the room exists is the host's gossiped hosted-room advert: exactly the discovery source list_rooms itself reads, and therefore the one a bare name has to resolve against.
|
|
3
|
+
*/
|
|
4
|
+
export {};
|
|
5
|
+
//# sourceMappingURL=room-join-by-bare-name.integration.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"room-join-by-bare-name.integration.test.d.ts","sourceRoot":"","sources":["../../src/test/room-join-by-bare-name.integration.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agent-comms#246 -- list_rooms shows a room hosted by another device by its bare name, so join_room must accept that same bare name, not only the full `<hostDevice>/<name>` room-path. Over a real relay hub the joiner has never received the host's room through any legacy full-state-sync, so the only thing that tells it the room exists is the host's gossiped hosted-room advert: exactly the discovery source list_rooms itself reads, and therefore the one a bare name has to resolve against.
|
|
3
|
+
*/
|
|
4
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
5
|
+
import { MeshStore } from "../core/mesh-store.js";
|
|
6
|
+
import { CommsTool } from "../core/tool.js";
|
|
7
|
+
import { buildAction } from "../core/bridge.js";
|
|
8
|
+
import { wireTestTransportWithHub } from "./test-transport.js";
|
|
9
|
+
import { realHubOverWs, waitForCondition } from "./hub-helpers.js";
|
|
10
|
+
const GOSSIP_INTERVAL_MS = 100;
|
|
11
|
+
const POLL_INTERVAL_MS = 25;
|
|
12
|
+
const DISCOVERY_TIMEOUT_MS = 10_000;
|
|
13
|
+
const cleanups = [];
|
|
14
|
+
afterEach(async () => {
|
|
15
|
+
for (const close of cleanups.splice(0)) {
|
|
16
|
+
await close();
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
/** Polls an async condition until it holds. hub-helpers' waitForCondition only accepts a synchronous predicate, and listRooms is async. */
|
|
20
|
+
async function eventually(condition) {
|
|
21
|
+
const deadline = Date.now() + DISCOVERY_TIMEOUT_MS;
|
|
22
|
+
while (!(await condition())) {
|
|
23
|
+
if (Date.now() > deadline) {
|
|
24
|
+
throw new Error("condition not met within timeout");
|
|
25
|
+
}
|
|
26
|
+
await new Promise((resolve) => {
|
|
27
|
+
setTimeout(resolve, POLL_INTERVAL_MS);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/** Wires a MeshStore onto the hub at hubUrl with a short gossip cadence, so a room it hosts is advertised to the other hub peers quickly. Never calls MeshStore.init(): hub mode has no local-mesh coordinator election, and calling it would risk colliding with an unrelated coordinator on the well-known port. */
|
|
32
|
+
async function connectedStore(hubUrl, name) {
|
|
33
|
+
const store = new MeshStore();
|
|
34
|
+
const { transport } = await wireTestTransportWithHub(store, {
|
|
35
|
+
presenceReadvertiseIntervalMs: GOSSIP_INTERVAL_MS,
|
|
36
|
+
});
|
|
37
|
+
await store.registerAgent({
|
|
38
|
+
name,
|
|
39
|
+
harness: "test",
|
|
40
|
+
cwd: `/test/${name}`,
|
|
41
|
+
pid: process.pid,
|
|
42
|
+
visibility: "visible",
|
|
43
|
+
tags: [],
|
|
44
|
+
});
|
|
45
|
+
await transport.connectHub?.(hubUrl);
|
|
46
|
+
await waitForCondition(() => transport.hub.isConnected);
|
|
47
|
+
return {
|
|
48
|
+
store,
|
|
49
|
+
ctx: {
|
|
50
|
+
agentId: store.peerId,
|
|
51
|
+
harness: "test",
|
|
52
|
+
cwd: `/test/${name}`,
|
|
53
|
+
pid: process.pid,
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/** A hub peer only broadcasts its own adverts onto the hub once it trusts at least one other hub device (GatewayTrust's hasAny gate), so every store in these tests trusts every other one. */
|
|
58
|
+
function trustEachOther(stores) {
|
|
59
|
+
for (const store of stores) {
|
|
60
|
+
for (const other of stores) {
|
|
61
|
+
if (other !== store)
|
|
62
|
+
store.gatewayTrust.add(other.peerId);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
describe("addressing a gossip-discovered room by the bare name list_rooms shows", () => {
|
|
67
|
+
it("join_room resolves the bare name to the hosting device's room-path and joins it", async () => {
|
|
68
|
+
const hub = await realHubOverWs();
|
|
69
|
+
cleanups.push(hub.close);
|
|
70
|
+
const owner = await connectedStore(hub.url, "owner");
|
|
71
|
+
const requester = await connectedStore(hub.url, "requester");
|
|
72
|
+
trustEachOther([owner.store, requester.store]);
|
|
73
|
+
const room = await owner.store.createRoom({
|
|
74
|
+
name: "e2e-test",
|
|
75
|
+
type: "public",
|
|
76
|
+
owner: owner.store.peerId,
|
|
77
|
+
description: "",
|
|
78
|
+
});
|
|
79
|
+
expect(await requester.store.getRoom(room.id)).toBeUndefined();
|
|
80
|
+
await eventually(async () => (await requester.store.listRooms(requester.store.peerId)).some((listed) => listed.name === "e2e-test"));
|
|
81
|
+
const tool = new CommsTool(requester.store);
|
|
82
|
+
const joinResult = tool.handle(requester.ctx, buildAction({ action: "join_room", room: "e2e-test" }));
|
|
83
|
+
await waitForCondition(() => owner.store
|
|
84
|
+
.listPendingRoomJoins()
|
|
85
|
+
.some((pending) => pending.roomPath === room.id));
|
|
86
|
+
owner.store.acceptRoomJoin(room.id, requester.store.peerId);
|
|
87
|
+
const result = await joinResult;
|
|
88
|
+
expect(result.isError).toBe(false);
|
|
89
|
+
expect(result.content).not.toContain("not a valid room-path");
|
|
90
|
+
const joined = await requester.store.getRoom(room.id);
|
|
91
|
+
expect(joined?.members).toContain(requester.store.peerId);
|
|
92
|
+
await requester.store.shutdown();
|
|
93
|
+
await owner.store.shutdown();
|
|
94
|
+
});
|
|
95
|
+
it("refuses to pick between two hosts advertising the same room name, naming both candidates", async () => {
|
|
96
|
+
const hub = await realHubOverWs();
|
|
97
|
+
cleanups.push(hub.close);
|
|
98
|
+
const first = await connectedStore(hub.url, "first");
|
|
99
|
+
const second = await connectedStore(hub.url, "second");
|
|
100
|
+
const requester = await connectedStore(hub.url, "requester");
|
|
101
|
+
trustEachOther([first.store, second.store, requester.store]);
|
|
102
|
+
const firstRoom = await first.store.createRoom({
|
|
103
|
+
name: "e2e-test",
|
|
104
|
+
type: "public",
|
|
105
|
+
owner: first.store.peerId,
|
|
106
|
+
description: "",
|
|
107
|
+
});
|
|
108
|
+
const secondRoom = await second.store.createRoom({
|
|
109
|
+
name: "e2e-test",
|
|
110
|
+
type: "public",
|
|
111
|
+
owner: second.store.peerId,
|
|
112
|
+
description: "",
|
|
113
|
+
});
|
|
114
|
+
await eventually(async () => {
|
|
115
|
+
const rooms = await requester.store.listRooms(requester.store.peerId);
|
|
116
|
+
return (rooms.some((listed) => listed.id === firstRoom.id) &&
|
|
117
|
+
rooms.some((listed) => listed.id === secondRoom.id));
|
|
118
|
+
});
|
|
119
|
+
const tool = new CommsTool(requester.store);
|
|
120
|
+
const result = await tool.handle(requester.ctx, buildAction({ action: "join_room", room: "e2e-test" }));
|
|
121
|
+
expect(result.isError).toBe(true);
|
|
122
|
+
expect(result.content).toContain("AMBIGUOUS_ROOM_NAME");
|
|
123
|
+
expect(result.content).toContain(firstRoom.id);
|
|
124
|
+
expect(result.content).toContain(secondRoom.id);
|
|
125
|
+
await requester.store.shutdown();
|
|
126
|
+
await second.store.shutdown();
|
|
127
|
+
await first.store.shutdown();
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
//# sourceMappingURL=room-join-by-bare-name.integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"room-join-by-bare-name.integration.test.js","sourceRoot":"","sources":["../../src/test/room-join-by-bare-name.integration.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"room-lifecycle-bare-name.unit.test.d.ts","sourceRoot":"","sources":["../../src/test/room-lifecycle-bare-name.unit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Direct, DI-based unit tests for how RoomLifecycle resolves a bare room name (agent-comms#246): listRooms surfaces a room discovered through another device's gossiped hosted-room advert under its bare `name`, so every room action that accepts a name has to resolve against the same discovered rooms, not only against rooms already replicated into this store's own map.
|
|
3
|
+
*/
|
|
4
|
+
import { describe, expect, it, vi } from "vitest";
|
|
5
|
+
import * as fs from "node:fs";
|
|
6
|
+
import * as path from "node:path";
|
|
7
|
+
import { tmpdir } from "node:os";
|
|
8
|
+
import { bytesToHex, deviceIdFromHex } from "wire-mesh-core/domain/device-id";
|
|
9
|
+
import { mintCapabilityToken } from "wire-mesh-core/domain/tokens";
|
|
10
|
+
import { createSystemClock } from "wire-mesh-core/adapters/system-clock";
|
|
11
|
+
import { createRevocationView } from "wire-mesh-core/domain/revocation-view";
|
|
12
|
+
import { generateIdentity } from "../core/identity.js";
|
|
13
|
+
import { loadOrCreateIdentity } from "../core/identity-store.js";
|
|
14
|
+
import { toIdentityPort } from "../core/wire-mesh-identity.js";
|
|
15
|
+
import { ownerNamedRoomPath } from "../core/room-path.js";
|
|
16
|
+
import { randomId } from "../core/random-id.js";
|
|
17
|
+
import { RoomLifecycle, } from "../core/room-lifecycle.js";
|
|
18
|
+
const TOKEN_TTL_MS = 60_000;
|
|
19
|
+
function room(overrides = {}) {
|
|
20
|
+
return {
|
|
21
|
+
id: "room-1",
|
|
22
|
+
version: 1,
|
|
23
|
+
name: "room-name",
|
|
24
|
+
type: "public",
|
|
25
|
+
owner: "",
|
|
26
|
+
createdAt: "2026-01-01T00:00:00.000Z",
|
|
27
|
+
description: "a room",
|
|
28
|
+
members: [],
|
|
29
|
+
invited: [],
|
|
30
|
+
memberJoins: {},
|
|
31
|
+
memberLeaves: {},
|
|
32
|
+
invitedJoins: {},
|
|
33
|
+
invitedLeaves: {},
|
|
34
|
+
...overrides,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/** A RoomLifecycle whose transport fake answers listKnownDevices from whatever advertise() last set, and whose sendRoomRequest records the room-path it was asked to join. */
|
|
38
|
+
async function makeHarness() {
|
|
39
|
+
const self = generateIdentity();
|
|
40
|
+
const hostA = generateIdentity();
|
|
41
|
+
const hostB = generateIdentity();
|
|
42
|
+
const selfPort = await toIdentityPort(self);
|
|
43
|
+
const selfId = bytesToHex(Uint8Array.from(self.deviceId));
|
|
44
|
+
const hostAId = bytesToHex(Uint8Array.from(hostA.deviceId));
|
|
45
|
+
const hostBId = bytesToHex(Uint8Array.from(hostB.deviceId));
|
|
46
|
+
const slotDir = fs.mkdtempSync(path.join(tmpdir(), "room-bare-name-test-"));
|
|
47
|
+
const slot = { harness: "test", cwd: "room-bare-name", dir: slotDir };
|
|
48
|
+
loadOrCreateIdentity(slot);
|
|
49
|
+
let adverts = [];
|
|
50
|
+
const sendRoomRequest = vi.fn();
|
|
51
|
+
const rooms = new Map();
|
|
52
|
+
const deps = {
|
|
53
|
+
rooms,
|
|
54
|
+
messages: new Map(),
|
|
55
|
+
agents: new Map(),
|
|
56
|
+
dmRequestsInitiatedByMe: new Set(),
|
|
57
|
+
getPeerId: () => selfId,
|
|
58
|
+
requireIdentity: () => ({
|
|
59
|
+
identity: selfPort,
|
|
60
|
+
clock: createSystemClock(),
|
|
61
|
+
slot,
|
|
62
|
+
revocation: createRevocationView(),
|
|
63
|
+
dataStorage: {},
|
|
64
|
+
userIdentity: {},
|
|
65
|
+
userIdentityOptions: {},
|
|
66
|
+
}),
|
|
67
|
+
requireTransport: () => ({
|
|
68
|
+
sendRoomRequest,
|
|
69
|
+
listKnownDevices: () => [hostAId, hostBId].map((deviceId) => ({
|
|
70
|
+
deviceId,
|
|
71
|
+
advert: {
|
|
72
|
+
"room/hosted": adverts
|
|
73
|
+
.filter((advert) => advert.hostId === deviceId)
|
|
74
|
+
.map(({ path: advertPath, name }) => ({
|
|
75
|
+
path: advertPath,
|
|
76
|
+
name,
|
|
77
|
+
type: "public",
|
|
78
|
+
description: "",
|
|
79
|
+
})),
|
|
80
|
+
},
|
|
81
|
+
})),
|
|
82
|
+
}),
|
|
83
|
+
deliveryEngine: {
|
|
84
|
+
bump: vi.fn(),
|
|
85
|
+
recordMemberOp: vi.fn(),
|
|
86
|
+
refreshMembership: vi.fn(),
|
|
87
|
+
broadcastPatch: vi.fn().mockResolvedValue(undefined),
|
|
88
|
+
deliverToRoom: vi.fn().mockResolvedValue(undefined),
|
|
89
|
+
deliverToMember: vi.fn().mockResolvedValue(undefined),
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
const hostAPort = await toIdentityPort(hostA);
|
|
93
|
+
return {
|
|
94
|
+
lifecycle: new RoomLifecycle(deps),
|
|
95
|
+
rooms,
|
|
96
|
+
selfId,
|
|
97
|
+
hostA: hostAId,
|
|
98
|
+
hostB: hostBId,
|
|
99
|
+
sendRoomRequest,
|
|
100
|
+
advertise: (next) => {
|
|
101
|
+
adverts = next;
|
|
102
|
+
},
|
|
103
|
+
grantFor: async (roomPath) => {
|
|
104
|
+
const clock = createSystemClock();
|
|
105
|
+
const verdict = await mintCapabilityToken({
|
|
106
|
+
identity: hostAPort,
|
|
107
|
+
clock,
|
|
108
|
+
tokenId: randomId(),
|
|
109
|
+
bearer: deviceIdFromHex(selfId),
|
|
110
|
+
capability: "room:member",
|
|
111
|
+
scope: { kind: "room", path: roomPath },
|
|
112
|
+
expires: clock.now() + TOKEN_TTL_MS,
|
|
113
|
+
delegationsRemaining: 0,
|
|
114
|
+
});
|
|
115
|
+
if (!verdict.ok)
|
|
116
|
+
throw new Error("expected the fixture token to mint successfully");
|
|
117
|
+
return {
|
|
118
|
+
result: "ok",
|
|
119
|
+
"granted-token": verdict.token,
|
|
120
|
+
members: [{ device: deviceIdFromHex(hostAId) }],
|
|
121
|
+
};
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
describe("RoomLifecycle bare-name resolution over gossip-discovered rooms", () => {
|
|
126
|
+
it("joinRoom sends the join request for the discovered room's full path when given its bare name", async () => {
|
|
127
|
+
const h = await makeHarness();
|
|
128
|
+
const roomPath = ownerNamedRoomPath(h.hostA, "e2e-test");
|
|
129
|
+
h.advertise([{ hostId: h.hostA, path: roomPath, name: "e2e-test" }]);
|
|
130
|
+
h.sendRoomRequest.mockResolvedValue(await h.grantFor(roomPath));
|
|
131
|
+
const joined = await h.lifecycle.joinRoom("e2e-test", h.selfId);
|
|
132
|
+
expect(joined.id).toBe(roomPath);
|
|
133
|
+
expect(h.sendRoomRequest).toHaveBeenCalledWith(h.hostA, expect.anything(), {
|
|
134
|
+
kind: "room",
|
|
135
|
+
path: roomPath,
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
it("throws AMBIGUOUS_ROOM_NAME naming every candidate when two hosts advertise the same name", async () => {
|
|
139
|
+
const h = await makeHarness();
|
|
140
|
+
const pathA = ownerNamedRoomPath(h.hostA, "e2e-test");
|
|
141
|
+
const pathB = ownerNamedRoomPath(h.hostB, "e2e-test");
|
|
142
|
+
h.advertise([
|
|
143
|
+
{ hostId: h.hostA, path: pathA, name: "e2e-test" },
|
|
144
|
+
{ hostId: h.hostB, path: pathB, name: "e2e-test" },
|
|
145
|
+
]);
|
|
146
|
+
const rejection = h.lifecycle.joinRoom("e2e-test", h.selfId);
|
|
147
|
+
await expect(rejection).rejects.toMatchObject({
|
|
148
|
+
code: "AMBIGUOUS_ROOM_NAME",
|
|
149
|
+
});
|
|
150
|
+
await expect(rejection).rejects.toThrow(pathA);
|
|
151
|
+
await expect(rejection).rejects.toThrow(pathB);
|
|
152
|
+
expect(h.sendRoomRequest).not.toHaveBeenCalled();
|
|
153
|
+
});
|
|
154
|
+
it("treats a discovered room and a replicated copy of the same room as one candidate, not an ambiguity", async () => {
|
|
155
|
+
const h = await makeHarness();
|
|
156
|
+
const roomPath = ownerNamedRoomPath(h.hostA, "e2e-test");
|
|
157
|
+
h.rooms.set(roomPath, room({ id: roomPath, name: "e2e-test", owner: h.hostA }));
|
|
158
|
+
h.advertise([{ hostId: h.hostA, path: roomPath, name: "e2e-test" }]);
|
|
159
|
+
h.sendRoomRequest.mockResolvedValue(await h.grantFor(roomPath));
|
|
160
|
+
const joined = await h.lifecycle.joinRoom("e2e-test", h.selfId);
|
|
161
|
+
expect(joined.id).toBe(roomPath);
|
|
162
|
+
});
|
|
163
|
+
it("throws AMBIGUOUS_ROOM_NAME when a local room and a discovered room from another host share a name", async () => {
|
|
164
|
+
const h = await makeHarness();
|
|
165
|
+
const localPath = ownerNamedRoomPath(h.selfId, "e2e-test");
|
|
166
|
+
const remotePath = ownerNamedRoomPath(h.hostA, "e2e-test");
|
|
167
|
+
h.rooms.set(localPath, room({ id: localPath, name: "e2e-test", owner: h.selfId }));
|
|
168
|
+
h.advertise([{ hostId: h.hostA, path: remotePath, name: "e2e-test" }]);
|
|
169
|
+
await expect(h.lifecycle.joinRoom("e2e-test", h.selfId)).rejects.toMatchObject({ code: "AMBIGUOUS_ROOM_NAME" });
|
|
170
|
+
});
|
|
171
|
+
it("still accepts the full room-path of a discovered room", async () => {
|
|
172
|
+
const h = await makeHarness();
|
|
173
|
+
const roomPath = ownerNamedRoomPath(h.hostA, "e2e-test");
|
|
174
|
+
h.advertise([{ hostId: h.hostA, path: roomPath, name: "e2e-test" }]);
|
|
175
|
+
h.sendRoomRequest.mockResolvedValue(await h.grantFor(roomPath));
|
|
176
|
+
const joined = await h.lifecycle.joinRoom(roomPath, h.selfId);
|
|
177
|
+
expect(joined.id).toBe(roomPath);
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
//# sourceMappingURL=room-lifecycle-bare-name.unit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"room-lifecycle-bare-name.unit.test.js","sourceRoot":"","sources":["../../src/test/room-lifecycle-bare-name.unit.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"room-lookup.unit.test.d.ts","sourceRoot":"","sources":["../../src/test/room-lookup.unit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for resolveRoomId, the one place a caller-supplied room id or plain room name is turned into a real room id. The candidates it resolves against are whatever the caller knows of, replicated or merely discovered through gossip (agent-comms#246), so these tests drive it with bare `{ id, name }` refs.
|
|
3
|
+
*/
|
|
4
|
+
import { describe, expect, it } from "vitest";
|
|
5
|
+
import { resolveRoomId } from "../core/room-lookup.js";
|
|
6
|
+
import { CommsError } from "../core/store.js";
|
|
7
|
+
/** A device-id is a 64-character lowercase hex SHA-256 digest. */
|
|
8
|
+
const DEVICE_ID_HEX_LENGTH = 64;
|
|
9
|
+
const HOST_A = "a".repeat(DEVICE_ID_HEX_LENGTH);
|
|
10
|
+
const HOST_B = "b".repeat(DEVICE_ID_HEX_LENGTH);
|
|
11
|
+
describe("resolveRoomId", () => {
|
|
12
|
+
it("returns an id that already names a known room unchanged", () => {
|
|
13
|
+
const id = `${HOST_A}/general`;
|
|
14
|
+
expect(resolveRoomId([{ id, name: "general" }], id)).toBe(id);
|
|
15
|
+
});
|
|
16
|
+
it("resolves a bare name to the id of the single room carrying it", () => {
|
|
17
|
+
const id = `${HOST_A}/e2e-test`;
|
|
18
|
+
expect(resolveRoomId([
|
|
19
|
+
{ id, name: "e2e-test" },
|
|
20
|
+
{ id: `${HOST_A}/other`, name: "other" },
|
|
21
|
+
], "e2e-test")).toBe(id);
|
|
22
|
+
});
|
|
23
|
+
it("returns a string matching no known room unchanged, leaving not-found handling to the caller", () => {
|
|
24
|
+
expect(resolveRoomId([{ id: `${HOST_A}/general`, name: "general" }], "unknown")).toBe("unknown");
|
|
25
|
+
expect(resolveRoomId([], "unknown")).toBe("unknown");
|
|
26
|
+
});
|
|
27
|
+
it("counts the same room supplied twice as one candidate", () => {
|
|
28
|
+
const id = `${HOST_A}/general`;
|
|
29
|
+
expect(resolveRoomId([
|
|
30
|
+
{ id, name: "general" },
|
|
31
|
+
{ id, name: "general" },
|
|
32
|
+
], "general")).toBe(id);
|
|
33
|
+
});
|
|
34
|
+
it("throws AMBIGUOUS_ROOM_NAME listing every candidate id when distinct rooms share the name", () => {
|
|
35
|
+
const first = `${HOST_A}/general`;
|
|
36
|
+
const second = `${HOST_B}/general`;
|
|
37
|
+
let thrown;
|
|
38
|
+
try {
|
|
39
|
+
resolveRoomId([
|
|
40
|
+
{ id: first, name: "general" },
|
|
41
|
+
{ id: second, name: "general" },
|
|
42
|
+
], "general");
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
thrown = error;
|
|
46
|
+
}
|
|
47
|
+
expect(thrown).toBeInstanceOf(CommsError);
|
|
48
|
+
expect(thrown).toMatchObject({ code: "AMBIGUOUS_ROOM_NAME" });
|
|
49
|
+
expect(thrown).toHaveProperty("message", expect.stringContaining(`${first}, ${second}`));
|
|
50
|
+
});
|
|
51
|
+
it("prefers an exact id match over a name match on another room", () => {
|
|
52
|
+
const id = `${HOST_A}/general`;
|
|
53
|
+
expect(resolveRoomId([
|
|
54
|
+
{ id, name: "general" },
|
|
55
|
+
{ id: `${HOST_B}/x`, name: id },
|
|
56
|
+
], id)).toBe(id);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
//# sourceMappingURL=room-lookup.unit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"room-lookup.unit.test.js","sourceRoot":"","sources":["../../src/test/room-lookup.unit.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -78,6 +78,8 @@ async function makeHarness() {
|
|
|
78
78
|
// This harness only sends room messages, never DMs, so DM admission is never reached.
|
|
79
79
|
requestDmAccess: async () => undefined,
|
|
80
80
|
resolveAgent: async () => undefined,
|
|
81
|
+
// Every send here already names the room by its real path.
|
|
82
|
+
resolveRoomId: (roomIdOrName) => roomIdOrName,
|
|
81
83
|
};
|
|
82
84
|
return {
|
|
83
85
|
messaging: new RoomMessaging(deps),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"room-messaging-durable-send.unit.test.js","sourceRoot":"","sources":["../../src/test/room-messaging-durable-send.unit.test.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"room-messaging-durable-send.unit.test.js","sourceRoot":"","sources":["../../src/test/room-messaging-durable-send.unit.test.ts"],"names":[],"mappings":"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"}
|