agent-comms 5.1.0 → 5.2.1
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 +24 -7
- package/dist/bridges/cc-peer/front-controller.d.ts +2 -0
- package/dist/bridges/cc-peer/front-controller.d.ts.map +1 -1
- package/dist/bridges/cc-peer/front-controller.js +2 -1
- package/dist/bridges/cc-peer/front-controller.js.map +1 -1
- package/dist/bridges/cc-peer/front-relay.d.ts +8 -4
- package/dist/bridges/cc-peer/front-relay.d.ts.map +1 -1
- package/dist/bridges/cc-peer/front-relay.js +28 -23
- package/dist/bridges/cc-peer/front-relay.js.map +1 -1
- package/dist/bridges/cc-peer/front-runtime.d.ts.map +1 -1
- package/dist/bridges/cc-peer/front-runtime.js +2 -1
- package/dist/bridges/cc-peer/front-runtime.js.map +1 -1
- package/dist/bridges/user/tui.d.ts.map +1 -1
- package/dist/bridges/user/tui.js +2 -1
- package/dist/bridges/user/tui.js.map +1 -1
- package/dist/bridges/user/web/contract.d.ts +201 -13
- package/dist/bridges/user/web/contract.d.ts.map +1 -1
- package/dist/bridges/user/web/dist/bundle.js +1 -1
- package/dist/bridges/user/web/dist/mesh-worker.js +1 -1
- package/dist/bridges/user/web/dist/sw.js +1 -1
- package/dist/bridges/user/web/frontend/messages.d.ts.map +1 -1
- package/dist/bridges/user/web/frontend/messages.js +2 -1
- package/dist/bridges/user/web/frontend/messages.js.map +1 -1
- package/dist/bridges/user/web/frontend/tab-contract.d.ts +60 -4
- package/dist/bridges/user/web/frontend/tab-contract.d.ts.map +1 -1
- package/dist/bridges/user/web/frontend/types.d.ts +2 -2
- package/dist/bridges/user/web/frontend/types.d.ts.map +1 -1
- package/dist/bridges/user/web/router.d.ts +60 -4
- package/dist/bridges/user/web/router.d.ts.map +1 -1
- package/dist/core/bridge.d.ts.map +1 -1
- package/dist/core/bridge.js +2 -1
- package/dist/core/bridge.js.map +1 -1
- package/dist/core/comms-store.d.ts +18 -3
- package/dist/core/comms-store.d.ts.map +1 -1
- package/dist/core/delivery-engine.d.ts +3 -2
- package/dist/core/delivery-engine.d.ts.map +1 -1
- package/dist/core/delivery-engine.js +6 -4
- package/dist/core/delivery-engine.js.map +1 -1
- package/dist/core/gossip-directory.d.ts +3 -0
- package/dist/core/gossip-directory.d.ts.map +1 -1
- package/dist/core/gossip-directory.js +7 -0
- package/dist/core/gossip-directory.js.map +1 -1
- package/dist/core/mesh-store-shared.d.ts +3 -0
- package/dist/core/mesh-store-shared.d.ts.map +1 -1
- package/dist/core/mesh-store-shared.js +8 -0
- package/dist/core/mesh-store-shared.js.map +1 -1
- package/dist/core/mesh-store.d.ts +5 -5
- package/dist/core/mesh-store.d.ts.map +1 -1
- package/dist/core/mesh-store.js +11 -38
- package/dist/core/mesh-store.js.map +1 -1
- package/dist/core/room-messaging.d.ts +8 -4
- package/dist/core/room-messaging.d.ts.map +1 -1
- package/dist/core/room-messaging.js +41 -18
- package/dist/core/room-messaging.js.map +1 -1
- package/dist/core/room-protocol.d.ts +17 -6
- package/dist/core/room-protocol.d.ts.map +1 -1
- package/dist/core/room-protocol.js +100 -18
- package/dist/core/room-protocol.js.map +1 -1
- package/dist/core/send-outcome.d.ts +28 -0
- package/dist/core/send-outcome.d.ts.map +1 -0
- package/dist/core/send-outcome.js +49 -0
- package/dist/core/send-outcome.js.map +1 -0
- package/dist/core/store.d.ts +4 -4
- package/dist/core/store.d.ts.map +1 -1
- package/dist/core/store.js +11 -2
- package/dist/core/store.js.map +1 -1
- package/dist/core/test/bridge.unit.test.js +1 -1
- package/dist/core/test/bridge.unit.test.js.map +1 -1
- package/dist/core/tool.d.ts.map +1 -1
- package/dist/core/tool.js +19 -5
- package/dist/core/tool.js.map +1 -1
- package/dist/core/transport-events.d.ts +19 -0
- package/dist/core/transport-events.d.ts.map +1 -0
- package/dist/core/transport-events.js +46 -0
- package/dist/core/transport-events.js.map +1 -0
- package/dist/core/transport.d.ts +4 -0
- package/dist/core/transport.d.ts.map +1 -1
- package/dist/core/types.d.ts +90 -7
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +23 -3
- package/dist/core/types.js.map +1 -1
- package/dist/core/wire-mesh-transport.d.ts.map +1 -1
- package/dist/core/wire-mesh-transport.js +4 -3
- package/dist/core/wire-mesh-transport.js.map +1 -1
- package/dist/test/agent-comms-version-gossip.integration.test.js +1 -0
- package/dist/test/agent-comms-version-gossip.integration.test.js.map +1 -1
- package/dist/test/agent-self-gossip.integration.test.js +1 -0
- package/dist/test/agent-self-gossip.integration.test.js.map +1 -1
- package/dist/test/become-coordinator-actual-port.integration.test.js +1 -0
- package/dist/test/become-coordinator-actual-port.integration.test.js.map +1 -1
- package/dist/test/cc-peer-front-relay.unit.test.js +144 -18
- package/dist/test/cc-peer-front-relay.unit.test.js.map +1 -1
- package/dist/test/cc-peer-fronted-approval.integration.test.js +20 -3
- package/dist/test/cc-peer-fronted-approval.integration.test.js.map +1 -1
- package/dist/test/data-sync-frame-handling.integration.test.js +1 -0
- package/dist/test/data-sync-frame-handling.integration.test.js.map +1 -1
- package/dist/test/delivery-engine-delivery.unit.test.js +2 -2
- package/dist/test/delivery-engine-delivery.unit.test.js.map +1 -1
- package/dist/test/delivery-engine-directed-notify.unit.test.js +2 -2
- package/dist/test/delivery-engine-directed-notify.unit.test.js.map +1 -1
- package/dist/test/delivery-receipt.helper.js +3 -3
- package/dist/test/delivery-receipt.helper.js.map +1 -1
- package/dist/test/dm-delivery-status.integration.test.d.ts +5 -0
- package/dist/test/dm-delivery-status.integration.test.d.ts.map +1 -0
- package/dist/test/dm-delivery-status.integration.test.js +77 -0
- package/dist/test/dm-delivery-status.integration.test.js.map +1 -0
- package/dist/test/dm-first-contact.integration.test.js +3 -3
- package/dist/test/dm-first-contact.integration.test.js.map +1 -1
- package/dist/test/gateway-forwarding.integration.test.js +2 -2
- package/dist/test/gateway-forwarding.integration.test.js.map +1 -1
- package/dist/test/gateway-trust.integration.test.js +1 -1
- package/dist/test/gateway-trust.integration.test.js.map +1 -1
- package/dist/test/gossip-directory-aggregation.integration.test.js +1 -0
- package/dist/test/gossip-directory-aggregation.integration.test.js.map +1 -1
- package/dist/test/gossip-listener-addresses.integration.test.js +1 -0
- package/dist/test/gossip-listener-addresses.integration.test.js.map +1 -1
- package/dist/test/hosted-rooms-gossip.integration.test.js +1 -0
- package/dist/test/hosted-rooms-gossip.integration.test.js.map +1 -1
- package/dist/test/hub-mode-session.integration.test.js +1 -0
- package/dist/test/hub-mode-session.integration.test.js.map +1 -1
- package/dist/test/hub-session-dispatch.unit.test.js +1 -0
- package/dist/test/hub-session-dispatch.unit.test.js.map +1 -1
- package/dist/test/hub-todevice-routing.integration.test.js +2 -2
- package/dist/test/hub-todevice-routing.integration.test.js.map +1 -1
- package/dist/test/listener-policy.integration.test.js +1 -0
- package/dist/test/listener-policy.integration.test.js.map +1 -1
- package/dist/test/mesh-graph-trace.integration.test.js +1 -0
- package/dist/test/mesh-graph-trace.integration.test.js.map +1 -1
- package/dist/test/presence-readvertise.integration.test.js +1 -0
- package/dist/test/presence-readvertise.integration.test.js.map +1 -1
- package/dist/test/query-version.integration.test.js +4 -2
- package/dist/test/query-version.integration.test.js.map +1 -1
- package/dist/test/room-join-approval-timeout.integration.test.js +1 -1
- package/dist/test/room-join-approval-timeout.integration.test.js.map +1 -1
- package/dist/test/room-messaging-durable-send.unit.test.js +3 -1
- package/dist/test/room-messaging-durable-send.unit.test.js.map +1 -1
- package/dist/test/room-messaging.unit.test.js +106 -15
- package/dist/test/room-messaging.unit.test.js.map +1 -1
- package/dist/test/room-protocol-admission.unit.test.js +9 -161
- package/dist/test/room-protocol-admission.unit.test.js.map +1 -1
- package/dist/test/room-protocol-retry-queue.unit.test.d.ts +2 -0
- package/dist/test/room-protocol-retry-queue.unit.test.d.ts.map +1 -0
- package/dist/test/room-protocol-retry-queue.unit.test.js +275 -0
- package/dist/test/room-protocol-retry-queue.unit.test.js.map +1 -0
- package/dist/test/room-protocol.helper.d.ts +60 -0
- package/dist/test/room-protocol.helper.d.ts.map +1 -0
- package/dist/test/room-protocol.helper.js +168 -0
- package/dist/test/room-protocol.helper.js.map +1 -0
- package/dist/test/room-protocol.unit.test.js +4 -159
- package/dist/test/room-protocol.unit.test.js.map +1 -1
- package/dist/test/room-read-directed.integration.test.js +3 -2
- package/dist/test/room-read-directed.integration.test.js.map +1 -1
- package/dist/test/room-router.unit.test.js +1 -0
- package/dist/test/room-router.unit.test.js.map +1 -1
- package/dist/test/send-outcome.unit.test.d.ts +2 -0
- package/dist/test/send-outcome.unit.test.d.ts.map +1 -0
- package/dist/test/send-outcome.unit.test.js +52 -0
- package/dist/test/send-outcome.unit.test.js.map +1 -0
- package/dist/test/wire-mesh-transport-gateway-trust.integration.test.js +4 -2
- package/dist/test/wire-mesh-transport-gateway-trust.integration.test.js.map +1 -1
- package/dist/test/wire-mesh-transport-hub.integration.test.js +1 -0
- package/dist/test/wire-mesh-transport-hub.integration.test.js.map +1 -1
- package/dist/test/wire-mesh-transport-shutdown-unref.integration.test.js +1 -0
- package/dist/test/wire-mesh-transport-shutdown-unref.integration.test.js.map +1 -1
- package/dist/test/wire-mesh-transport.integration.test.js +1 -0
- package/dist/test/wire-mesh-transport.integration.test.js.map +1 -1
- package/dist/test/wss-remote-connect.integration.test.js +1 -0
- package/dist/test/wss-remote-connect.integration.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Direct, DI-based unit tests for what RoomProtocol reports about a directed room-domain request and what its retry queue does with one nobody answered: the outcome each caller is handed back, the delivery_status events a queued message's own sender is told about as it is held, dropped, expired, retried or refused, and the bounds that stop the queue growing without limit. See room-protocol.unit.test.ts and room-protocol-admission.unit.test.ts for the receiving side and the admission flow; all three share the harness in room-protocol.helper.ts.
|
|
3
|
+
*/
|
|
4
|
+
import { describe, expect, it } from "vitest";
|
|
5
|
+
import { saveRoomToken } from "../core/identity-store.js";
|
|
6
|
+
import { dmRoomPath, ownerNamedRoomPath } from "../core/room-path.js";
|
|
7
|
+
import { MAX_PENDING_ROOM_REQUESTS_PER_MEMBER, PENDING_ROOM_REQUEST_TTL_MS, } from "../core/mesh-store-shared.js";
|
|
8
|
+
import { randomId } from "../core/random-id.js";
|
|
9
|
+
import { bytesToHex } from "wire-mesh-core/domain/device-id";
|
|
10
|
+
import { makeHarness, mintRoomToken, } from "./room-protocol.helper.js";
|
|
11
|
+
/** A token whose own bytes never matter here: the sending side attaches whatever this store persisted without inspecting it, and every assertion in this file is about the outcome the transport answers with, never about verification. */
|
|
12
|
+
const OPAQUE_TOKEN = "opaque";
|
|
13
|
+
/** A well under the age bound, so a test that expects an entry to survive a sweep is not relying on the sweep never running. */
|
|
14
|
+
const WELL_WITHIN_TTL_MS = 1_000;
|
|
15
|
+
/** This harness's own canonical owner-named room path. Every real send names a room by its canonical path, and reporting a delivery status parses that path to tell a room message from a DM, so a test using a made-up path would be exercising something production never produces. */
|
|
16
|
+
function roomPath(h) {
|
|
17
|
+
return ownerNamedRoomPath(h.ids.ownerId, "general");
|
|
18
|
+
}
|
|
19
|
+
/** Persists a room:member token for roomPath, which flushPendingRoomRequests requires before it will retry anything queued against that path. */
|
|
20
|
+
async function persistToken(h, path) {
|
|
21
|
+
saveRoomToken({ harness: "test", cwd: "room-protocol", dir: h.slotDir }, path, await mintRoomToken(h.ids.ownerPort, h.ids.ownerId, path));
|
|
22
|
+
}
|
|
23
|
+
/** A room.send's own params, carrying a real message-id so a delivery status can be reported against it. Returns both the params and the hex id the status events will name. */
|
|
24
|
+
function roomSendParams() {
|
|
25
|
+
const messageId = randomId();
|
|
26
|
+
return {
|
|
27
|
+
params: { verb: "room.send", "message-id": messageId, text: "hi" },
|
|
28
|
+
messageId: bytesToHex(messageId),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/** Every delivery_status event this harness's delivery engine was asked to queue, in order. */
|
|
32
|
+
function deliveryStatuses(h) {
|
|
33
|
+
return h.queueDelivery.mock.calls
|
|
34
|
+
.map((call) => call[1])
|
|
35
|
+
.filter((event) => typeof event === "object" &&
|
|
36
|
+
event !== null &&
|
|
37
|
+
"type" in event &&
|
|
38
|
+
event.type === "delivery_status");
|
|
39
|
+
}
|
|
40
|
+
describe("RoomProtocol — sendRoomRequestToMember outcomes", () => {
|
|
41
|
+
it("reports a delivered request as delivered and queues nothing", async () => {
|
|
42
|
+
const h = await makeHarness();
|
|
43
|
+
await persistToken(h, roomPath(h));
|
|
44
|
+
h.sendRoomRequest.mockResolvedValue({ result: "ok" });
|
|
45
|
+
const outcome = await h.protocol.sendRoomRequestToMember(h.ids.memberId, roomPath(h), OPAQUE_TOKEN, roomSendParams().params);
|
|
46
|
+
expect(outcome).toEqual({ kind: "delivered" });
|
|
47
|
+
h.sendRoomRequest.mockClear();
|
|
48
|
+
await h.protocol.flushPendingRoomRequests(h.ids.memberId);
|
|
49
|
+
expect(h.sendRoomRequest).not.toHaveBeenCalled();
|
|
50
|
+
});
|
|
51
|
+
it("reports a timed-out request as undelivered and holds it for retry", async () => {
|
|
52
|
+
const h = await makeHarness();
|
|
53
|
+
await persistToken(h, roomPath(h));
|
|
54
|
+
h.sendRoomRequest.mockResolvedValue({ result: "error", code: "timeout" });
|
|
55
|
+
const { params } = roomSendParams();
|
|
56
|
+
const outcome = await h.protocol.sendRoomRequestToMember(h.ids.memberId, roomPath(h), OPAQUE_TOKEN, params);
|
|
57
|
+
expect(outcome).toEqual({ kind: "undelivered", reason: "timeout" });
|
|
58
|
+
h.sendRoomRequest.mockClear();
|
|
59
|
+
h.sendRoomRequest.mockResolvedValue({ result: "ok" });
|
|
60
|
+
await h.protocol.flushPendingRoomRequests(h.ids.memberId);
|
|
61
|
+
expect(h.sendRoomRequest).toHaveBeenCalledTimes(1);
|
|
62
|
+
});
|
|
63
|
+
it("reports a request the transport rejected outright as a lost connection", async () => {
|
|
64
|
+
const h = await makeHarness();
|
|
65
|
+
await persistToken(h, roomPath(h));
|
|
66
|
+
h.sendRoomRequest.mockRejectedValue(new Error("connection dropped"));
|
|
67
|
+
const outcome = await h.protocol.sendRoomRequestToMember(h.ids.memberId, roomPath(h), OPAQUE_TOKEN, roomSendParams().params);
|
|
68
|
+
expect(outcome).toEqual({
|
|
69
|
+
kind: "undelivered",
|
|
70
|
+
reason: "connection_lost",
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
it("reports a refusal without queuing it, since no retry can change the answer", async () => {
|
|
74
|
+
const h = await makeHarness();
|
|
75
|
+
await persistToken(h, roomPath(h));
|
|
76
|
+
h.sendRoomRequest.mockResolvedValue({
|
|
77
|
+
result: "error",
|
|
78
|
+
code: "unauthorized",
|
|
79
|
+
});
|
|
80
|
+
const outcome = await h.protocol.sendRoomRequestToMember(h.ids.memberId, roomPath(h), OPAQUE_TOKEN, roomSendParams().params);
|
|
81
|
+
expect(outcome).toEqual({ kind: "refused", code: "unauthorized" });
|
|
82
|
+
h.sendRoomRequest.mockClear();
|
|
83
|
+
await h.protocol.flushPendingRoomRequests(h.ids.memberId);
|
|
84
|
+
expect(h.sendRoomRequest).not.toHaveBeenCalled();
|
|
85
|
+
});
|
|
86
|
+
it("emits no delivery status for the send it just answered directly", async () => {
|
|
87
|
+
const h = await makeHarness();
|
|
88
|
+
await persistToken(h, roomPath(h));
|
|
89
|
+
h.sendRoomRequest.mockResolvedValue({
|
|
90
|
+
result: "error",
|
|
91
|
+
code: "not_connected",
|
|
92
|
+
});
|
|
93
|
+
await h.protocol.sendRoomRequestToMember(h.ids.memberId, roomPath(h), OPAQUE_TOKEN, roomSendParams().params);
|
|
94
|
+
// The caller is already holding the queued outcome this call returned, so repeating it as an event would tell the one observer that matters something it has just been told. Delivery status events exist for what happens to a message afterwards, out of band of any call.
|
|
95
|
+
expect(deliveryStatuses(h)).toEqual([]);
|
|
96
|
+
});
|
|
97
|
+
it("reports nothing for a request carrying no message of this sender's own", async () => {
|
|
98
|
+
const h = await makeHarness();
|
|
99
|
+
await persistToken(h, roomPath(h));
|
|
100
|
+
h.sendRoomRequest.mockResolvedValue({ result: "error", code: "timeout" });
|
|
101
|
+
await h.protocol.sendRoomRequestToMember(h.ids.memberId, roomPath(h), OPAQUE_TOKEN, {
|
|
102
|
+
verb: "room.read",
|
|
103
|
+
messages: [randomId()],
|
|
104
|
+
});
|
|
105
|
+
h.sendRoomRequest.mockResolvedValue({ result: "ok" });
|
|
106
|
+
await h.protocol.flushPendingRoomRequests(h.ids.memberId);
|
|
107
|
+
expect(deliveryStatuses(h)).toEqual([]);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
describe("RoomProtocol — retry queue delivery reporting", () => {
|
|
111
|
+
it("tells the sender a queued message was delivered once the member is reachable", async () => {
|
|
112
|
+
const h = await makeHarness();
|
|
113
|
+
const dmPath = dmRoomPath(h.ids.ownerId, h.ids.memberId);
|
|
114
|
+
await persistToken(h, dmPath);
|
|
115
|
+
h.sendRoomRequest.mockResolvedValue({
|
|
116
|
+
result: "error",
|
|
117
|
+
code: "not_connected",
|
|
118
|
+
});
|
|
119
|
+
const { params, messageId } = roomSendParams();
|
|
120
|
+
await h.protocol.sendRoomRequestToMember(h.ids.memberId, dmPath, OPAQUE_TOKEN, params);
|
|
121
|
+
h.sendRoomRequest.mockResolvedValue({ result: "ok" });
|
|
122
|
+
await h.protocol.flushPendingRoomRequests(h.ids.memberId);
|
|
123
|
+
expect(deliveryStatuses(h)).toEqual([
|
|
124
|
+
{
|
|
125
|
+
type: "delivery_status",
|
|
126
|
+
messageId,
|
|
127
|
+
agent: h.ids.memberId,
|
|
128
|
+
delivery: { status: "delivered" },
|
|
129
|
+
},
|
|
130
|
+
]);
|
|
131
|
+
});
|
|
132
|
+
it("names the room for a room message and omits it for a DM", async () => {
|
|
133
|
+
const h = await makeHarness();
|
|
134
|
+
await persistToken(h, roomPath(h));
|
|
135
|
+
h.sendRoomRequest.mockResolvedValue({ result: "error", code: "timeout" });
|
|
136
|
+
const { params } = roomSendParams();
|
|
137
|
+
await h.protocol.sendRoomRequestToMember(h.ids.memberId, roomPath(h), OPAQUE_TOKEN, params);
|
|
138
|
+
h.sendRoomRequest.mockResolvedValue({ result: "ok" });
|
|
139
|
+
await h.protocol.flushPendingRoomRequests(h.ids.memberId);
|
|
140
|
+
expect(deliveryStatuses(h)[0]?.room).toBe(roomPath(h));
|
|
141
|
+
});
|
|
142
|
+
it("tells the sender a retried message was refused, and stops retrying it", async () => {
|
|
143
|
+
const h = await makeHarness();
|
|
144
|
+
const dmPath = dmRoomPath(h.ids.ownerId, h.ids.memberId);
|
|
145
|
+
await persistToken(h, dmPath);
|
|
146
|
+
h.sendRoomRequest.mockResolvedValue({ result: "error", code: "timeout" });
|
|
147
|
+
const { params, messageId } = roomSendParams();
|
|
148
|
+
await h.protocol.sendRoomRequestToMember(h.ids.memberId, dmPath, OPAQUE_TOKEN, params);
|
|
149
|
+
h.sendRoomRequest.mockResolvedValue({ result: "error", code: "denied" });
|
|
150
|
+
await h.protocol.flushPendingRoomRequests(h.ids.memberId);
|
|
151
|
+
expect(deliveryStatuses(h)).toEqual([
|
|
152
|
+
{
|
|
153
|
+
type: "delivery_status",
|
|
154
|
+
messageId,
|
|
155
|
+
agent: h.ids.memberId,
|
|
156
|
+
delivery: { status: "refused", code: "denied" },
|
|
157
|
+
},
|
|
158
|
+
]);
|
|
159
|
+
h.sendRoomRequest.mockClear();
|
|
160
|
+
await h.protocol.flushPendingRoomRequests(h.ids.memberId);
|
|
161
|
+
expect(h.sendRoomRequest).not.toHaveBeenCalled();
|
|
162
|
+
});
|
|
163
|
+
it("holds a message whose retry also failed, without telling the sender anything new", async () => {
|
|
164
|
+
const h = await makeHarness();
|
|
165
|
+
await persistToken(h, roomPath(h));
|
|
166
|
+
h.sendRoomRequest.mockResolvedValue({
|
|
167
|
+
result: "error",
|
|
168
|
+
code: "not_connected",
|
|
169
|
+
});
|
|
170
|
+
await h.protocol.sendRoomRequestToMember(h.ids.memberId, roomPath(h), OPAQUE_TOKEN, roomSendParams().params);
|
|
171
|
+
await h.protocol.flushPendingRoomRequests(h.ids.memberId);
|
|
172
|
+
expect(deliveryStatuses(h)).toEqual([]);
|
|
173
|
+
h.sendRoomRequest.mockResolvedValue({ result: "ok" });
|
|
174
|
+
await h.protocol.flushPendingRoomRequests(h.ids.memberId);
|
|
175
|
+
expect(deliveryStatuses(h).map((event) => event.delivery.status)).toEqual([
|
|
176
|
+
"delivered",
|
|
177
|
+
]);
|
|
178
|
+
});
|
|
179
|
+
it("drops a queued message this store no longer holds a room token for", async () => {
|
|
180
|
+
const h = await makeHarness();
|
|
181
|
+
h.sendRoomRequest.mockResolvedValue({ result: "error", code: "timeout" });
|
|
182
|
+
const { params, messageId } = roomSendParams();
|
|
183
|
+
await h.protocol.sendRoomRequestToMember(h.ids.memberId, roomPath(h), OPAQUE_TOKEN, params);
|
|
184
|
+
h.sendRoomRequest.mockClear();
|
|
185
|
+
await h.protocol.flushPendingRoomRequests(h.ids.memberId);
|
|
186
|
+
expect(h.sendRoomRequest).not.toHaveBeenCalled();
|
|
187
|
+
expect(deliveryStatuses(h)).toEqual([
|
|
188
|
+
{
|
|
189
|
+
type: "delivery_status",
|
|
190
|
+
messageId,
|
|
191
|
+
agent: h.ids.memberId,
|
|
192
|
+
delivery: { status: "dropped" },
|
|
193
|
+
room: roomPath(h),
|
|
194
|
+
},
|
|
195
|
+
]);
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
describe("RoomProtocol — retry queue bounds", () => {
|
|
199
|
+
it("drops the oldest queued message beyond the per-member bound and says so", async () => {
|
|
200
|
+
const h = await makeHarness();
|
|
201
|
+
await persistToken(h, roomPath(h));
|
|
202
|
+
h.sendRoomRequest.mockResolvedValue({ result: "error", code: "timeout" });
|
|
203
|
+
const first = roomSendParams();
|
|
204
|
+
await h.protocol.sendRoomRequestToMember(h.ids.memberId, roomPath(h), OPAQUE_TOKEN, first.params);
|
|
205
|
+
for (let i = 0; i < MAX_PENDING_ROOM_REQUESTS_PER_MEMBER; i++) {
|
|
206
|
+
await h.protocol.sendRoomRequestToMember(h.ids.memberId, roomPath(h), OPAQUE_TOKEN, roomSendParams().params);
|
|
207
|
+
}
|
|
208
|
+
expect(deliveryStatuses(h)).toEqual([
|
|
209
|
+
{
|
|
210
|
+
type: "delivery_status",
|
|
211
|
+
messageId: first.messageId,
|
|
212
|
+
agent: h.ids.memberId,
|
|
213
|
+
delivery: { status: "dropped" },
|
|
214
|
+
room: roomPath(h),
|
|
215
|
+
},
|
|
216
|
+
]);
|
|
217
|
+
h.sendRoomRequest.mockClear();
|
|
218
|
+
h.sendRoomRequest.mockResolvedValue({ result: "ok" });
|
|
219
|
+
await h.protocol.flushPendingRoomRequests(h.ids.memberId);
|
|
220
|
+
expect(h.sendRoomRequest).toHaveBeenCalledTimes(MAX_PENDING_ROOM_REQUESTS_PER_MEMBER);
|
|
221
|
+
});
|
|
222
|
+
it("gives up on a queued message older than the age bound and tells the sender it expired", async () => {
|
|
223
|
+
const h = await makeHarness();
|
|
224
|
+
await persistToken(h, roomPath(h));
|
|
225
|
+
h.sendRoomRequest.mockResolvedValue({ result: "error", code: "timeout" });
|
|
226
|
+
const stale = roomSendParams();
|
|
227
|
+
await h.protocol.sendRoomRequestToMember(h.ids.memberId, roomPath(h), OPAQUE_TOKEN, stale.params);
|
|
228
|
+
h.advanceClock(PENDING_ROOM_REQUEST_TTL_MS + WELL_WITHIN_TTL_MS);
|
|
229
|
+
h.sendRoomRequest.mockClear();
|
|
230
|
+
h.sendRoomRequest.mockResolvedValue({ result: "ok" });
|
|
231
|
+
await h.protocol.flushPendingRoomRequests(h.ids.memberId);
|
|
232
|
+
expect(h.sendRoomRequest).not.toHaveBeenCalled();
|
|
233
|
+
expect(deliveryStatuses(h)).toEqual([
|
|
234
|
+
{
|
|
235
|
+
type: "delivery_status",
|
|
236
|
+
messageId: stale.messageId,
|
|
237
|
+
agent: h.ids.memberId,
|
|
238
|
+
delivery: { status: "expired" },
|
|
239
|
+
room: roomPath(h),
|
|
240
|
+
},
|
|
241
|
+
]);
|
|
242
|
+
});
|
|
243
|
+
it("keeps a message that has not reached the age bound", async () => {
|
|
244
|
+
const h = await makeHarness();
|
|
245
|
+
await persistToken(h, roomPath(h));
|
|
246
|
+
h.sendRoomRequest.mockResolvedValue({ result: "error", code: "timeout" });
|
|
247
|
+
await h.protocol.sendRoomRequestToMember(h.ids.memberId, roomPath(h), OPAQUE_TOKEN, roomSendParams().params);
|
|
248
|
+
h.advanceClock(PENDING_ROOM_REQUEST_TTL_MS - WELL_WITHIN_TTL_MS);
|
|
249
|
+
h.sendRoomRequest.mockClear();
|
|
250
|
+
h.sendRoomRequest.mockResolvedValue({ result: "ok" });
|
|
251
|
+
await h.protocol.flushPendingRoomRequests(h.ids.memberId);
|
|
252
|
+
expect(h.sendRoomRequest).toHaveBeenCalledTimes(1);
|
|
253
|
+
expect(deliveryStatuses(h).map((event) => event.delivery.status)).toEqual([
|
|
254
|
+
"delivered",
|
|
255
|
+
]);
|
|
256
|
+
});
|
|
257
|
+
it("does not let a failed retry refresh a message's age", async () => {
|
|
258
|
+
const h = await makeHarness();
|
|
259
|
+
await persistToken(h, roomPath(h));
|
|
260
|
+
h.sendRoomRequest.mockResolvedValue({ result: "error", code: "timeout" });
|
|
261
|
+
await h.protocol.sendRoomRequestToMember(h.ids.memberId, roomPath(h), OPAQUE_TOKEN, roomSendParams().params);
|
|
262
|
+
// A member that keeps briefly reappearing and failing must not be able to keep a message pending forever, so each failed retry re-queues it with the age it already had.
|
|
263
|
+
const halfTtl = PENDING_ROOM_REQUEST_TTL_MS / 2;
|
|
264
|
+
h.advanceClock(halfTtl);
|
|
265
|
+
await h.protocol.flushPendingRoomRequests(h.ids.memberId);
|
|
266
|
+
h.advanceClock(halfTtl + WELL_WITHIN_TTL_MS);
|
|
267
|
+
h.sendRoomRequest.mockClear();
|
|
268
|
+
await h.protocol.flushPendingRoomRequests(h.ids.memberId);
|
|
269
|
+
expect(h.sendRoomRequest).not.toHaveBeenCalled();
|
|
270
|
+
expect(deliveryStatuses(h).map((event) => event.delivery.status)).toEqual([
|
|
271
|
+
"expired",
|
|
272
|
+
]);
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
//# sourceMappingURL=room-protocol-retry-queue.unit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"room-protocol-retry-queue.unit.test.js","sourceRoot":"","sources":["../../src/test/room-protocol-retry-queue.unit.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shared DI harness every RoomProtocol unit-test file builds against: real identities and real minted tokens (token verification here is genuinely cryptographic, unlike room-messaging.ts's sending side, which never inspects a token's own structure), a fake transport whose sendRoomRequest each test drives, and a fake delivery engine whose calls each test asserts on. Extracted so the three RoomProtocol test files share one harness rather than each carrying its own copy of it.
|
|
3
|
+
*/
|
|
4
|
+
import { vi } from "vitest";
|
|
5
|
+
import type { CapabilityToken } from "wire-mesh-core/generated/protocol";
|
|
6
|
+
import type { IncomingManageRequest } from "wire-mesh-core/domain/mesh-session";
|
|
7
|
+
import { toIdentityPort } from "../core/wire-mesh-identity.js";
|
|
8
|
+
import { RoomProtocol, type RoomProtocolDeps } from "../core/room-protocol.js";
|
|
9
|
+
import type { AgentIdentity, Room } from "../core/types.js";
|
|
10
|
+
/** Far longer than any test runs, so a pending join is never expired unless a test says so. */
|
|
11
|
+
export declare const JOIN_DECISION_TIMEOUT_MS = 600000;
|
|
12
|
+
export declare const TOKEN_TTL_MS = 60000;
|
|
13
|
+
/** A device-id is a 64-character lowercase hex SHA-256 digest; room-path.ts's assertDeviceIdHex rejects anything shorter. */
|
|
14
|
+
export declare const DEVICE_ID_HEX_LENGTH = 64;
|
|
15
|
+
/** Distinct, real random ids for fixture message/ref/token ids -- randomId() is the exact utility production code (admitRoomJoin, sendRoomMessageDirected) uses for the identical purpose, so these fixtures need no arbitrary literal bytes of their own. */
|
|
16
|
+
export declare const SAMPLE_MESSAGE_ID: Uint8Array<ArrayBuffer>;
|
|
17
|
+
/** A message-id this store will never recognise, standing in for "already expired from history". */
|
|
18
|
+
export declare const UNRECOGNISED_MESSAGE_ID: Uint8Array<ArrayBuffer>;
|
|
19
|
+
/** Arbitrary, distinctive placeholder bytes for a message-ref's own id. */
|
|
20
|
+
export declare const SAMPLE_REF_ID: Uint8Array<ArrayBuffer>;
|
|
21
|
+
export declare const SAMPLE_TOKEN_ID: Uint8Array<ArrayBuffer>;
|
|
22
|
+
export declare function room(overrides?: Partial<Room>): Room;
|
|
23
|
+
export declare function agent(overrides?: Partial<AgentIdentity>): AgentIdentity;
|
|
24
|
+
export interface Identities {
|
|
25
|
+
ownerId: string;
|
|
26
|
+
ownerPort: Awaited<ReturnType<typeof toIdentityPort>>;
|
|
27
|
+
memberId: string;
|
|
28
|
+
}
|
|
29
|
+
export declare function makeIdentities(): Promise<Identities>;
|
|
30
|
+
export declare function mintRoomToken(issuerPort: Awaited<ReturnType<typeof toIdentityPort>>, bearerHex: string, roomPath: string): Promise<CapabilityToken>;
|
|
31
|
+
export interface Harness {
|
|
32
|
+
deps: RoomProtocolDeps;
|
|
33
|
+
/** Moves this harness's own clock, the one RoomProtocol reads for queue ages, forward by the given number of milliseconds. Every other collaborator reads the same clock, so a test that jumps it forward is jumping the store's whole notion of now, exactly as real elapsed time would. */
|
|
34
|
+
advanceClock: (ms: number) => void;
|
|
35
|
+
protocol: RoomProtocol;
|
|
36
|
+
ids: Identities;
|
|
37
|
+
slotDir: string;
|
|
38
|
+
queueDelivery: ReturnType<typeof vi.fn>;
|
|
39
|
+
fireLocalDelivery: ReturnType<typeof vi.fn>;
|
|
40
|
+
bump: ReturnType<typeof vi.fn>;
|
|
41
|
+
recordMemberOp: ReturnType<typeof vi.fn>;
|
|
42
|
+
refreshMembership: ReturnType<typeof vi.fn>;
|
|
43
|
+
broadcastPatch: ReturnType<typeof vi.fn>;
|
|
44
|
+
deliverToRoom: ReturnType<typeof vi.fn>;
|
|
45
|
+
revokeMemberGrant: ReturnType<typeof vi.fn>;
|
|
46
|
+
sendRoomRequest: ReturnType<typeof vi.fn>;
|
|
47
|
+
}
|
|
48
|
+
export declare function makeHarness(): Promise<Harness>;
|
|
49
|
+
export declare function handle(deviceHex: string): {
|
|
50
|
+
id: string;
|
|
51
|
+
};
|
|
52
|
+
export declare function manageRequest(overrides?: {
|
|
53
|
+
scope?: {
|
|
54
|
+
kind: string;
|
|
55
|
+
path?: string;
|
|
56
|
+
};
|
|
57
|
+
token?: CapabilityToken | undefined;
|
|
58
|
+
params?: Record<string, unknown>;
|
|
59
|
+
}): IncomingManageRequest;
|
|
60
|
+
//# sourceMappingURL=room-protocol.helper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"room-protocol.helper.d.ts","sourceRoot":"","sources":["../../src/test/room-protocol.helper.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAQ5B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,KAAK,EACV,qBAAqB,EAEtB,MAAM,oCAAoC,CAAC;AAG5C,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE/E,OAAO,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAE5D,+FAA+F;AAC/F,eAAO,MAAM,wBAAwB,SAAU,CAAC;AAEhD,eAAO,MAAM,YAAY,QAAS,CAAC;AACnC,6HAA6H;AAC7H,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,8PAA8P;AAC9P,eAAO,MAAM,iBAAiB,yBAAa,CAAC;AAC5C,oGAAoG;AACpG,eAAO,MAAM,uBAAuB,yBAAa,CAAC;AAClD,2EAA2E;AAC3E,eAAO,MAAM,aAAa,yBAAa,CAAC;AACxC,eAAO,MAAM,eAAe,yBAAa,CAAC;AAE1C,wBAAgB,IAAI,CAAC,SAAS,GAAE,OAAO,CAAC,IAAI,CAAM,GAAG,IAAI,CAiBxD;AAED,wBAAgB,KAAK,CAAC,SAAS,GAAE,OAAO,CAAC,aAAa,CAAM,GAAG,aAAa,CAe3E;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,CAAC;IACtD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,UAAU,CAAC,CAQ1D;AAED,wBAAsB,aAAa,CACjC,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,EACtD,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,eAAe,CAAC,CAe1B;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,gBAAgB,CAAC;IACvB,6RAA6R;IAC7R,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,QAAQ,EAAE,YAAY,CAAC;IACvB,GAAG,EAAE,UAAU,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IACxC,iBAAiB,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAC5C,IAAI,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAC/B,cAAc,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IACzC,iBAAiB,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAC5C,cAAc,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IACzC,aAAa,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IACxC,iBAAiB,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAC5C,eAAe,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;CAC3C;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CA4EpD;AAED,wBAAgB,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAExD;AAED,wBAAgB,aAAa,CAC3B,SAAS,GAAE;IACT,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,KAAK,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC7B,GACL,qBAAqB,CAQvB"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shared DI harness every RoomProtocol unit-test file builds against: real identities and real minted tokens (token verification here is genuinely cryptographic, unlike room-messaging.ts's sending side, which never inspects a token's own structure), a fake transport whose sendRoomRequest each test drives, and a fake delivery engine whose calls each test asserts on. Extracted so the three RoomProtocol test files share one harness rather than each carrying its own copy of it.
|
|
3
|
+
*/
|
|
4
|
+
import { 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 { RoomProtocol } from "../core/room-protocol.js";
|
|
16
|
+
import { randomId } from "../core/random-id.js";
|
|
17
|
+
/** Far longer than any test runs, so a pending join is never expired unless a test says so. */
|
|
18
|
+
export const JOIN_DECISION_TIMEOUT_MS = 600_000;
|
|
19
|
+
export const TOKEN_TTL_MS = 60_000;
|
|
20
|
+
/** A device-id is a 64-character lowercase hex SHA-256 digest; room-path.ts's assertDeviceIdHex rejects anything shorter. */
|
|
21
|
+
export const DEVICE_ID_HEX_LENGTH = 64;
|
|
22
|
+
/** Distinct, real random ids for fixture message/ref/token ids -- randomId() is the exact utility production code (admitRoomJoin, sendRoomMessageDirected) uses for the identical purpose, so these fixtures need no arbitrary literal bytes of their own. */
|
|
23
|
+
export const SAMPLE_MESSAGE_ID = randomId();
|
|
24
|
+
/** A message-id this store will never recognise, standing in for "already expired from history". */
|
|
25
|
+
export const UNRECOGNISED_MESSAGE_ID = randomId();
|
|
26
|
+
/** Arbitrary, distinctive placeholder bytes for a message-ref's own id. */
|
|
27
|
+
export const SAMPLE_REF_ID = randomId();
|
|
28
|
+
export const SAMPLE_TOKEN_ID = randomId();
|
|
29
|
+
export function room(overrides = {}) {
|
|
30
|
+
return {
|
|
31
|
+
id: "room-1",
|
|
32
|
+
version: 1,
|
|
33
|
+
name: "room-name",
|
|
34
|
+
type: "public",
|
|
35
|
+
owner: "",
|
|
36
|
+
createdAt: "2026-01-01T00:00:00.000Z",
|
|
37
|
+
description: "a room",
|
|
38
|
+
members: [],
|
|
39
|
+
invited: [],
|
|
40
|
+
memberJoins: {},
|
|
41
|
+
memberLeaves: {},
|
|
42
|
+
invitedJoins: {},
|
|
43
|
+
invitedLeaves: {},
|
|
44
|
+
...overrides,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export function agent(overrides = {}) {
|
|
48
|
+
return {
|
|
49
|
+
id: "",
|
|
50
|
+
version: 1,
|
|
51
|
+
name: "agent-name",
|
|
52
|
+
harness: "pi",
|
|
53
|
+
cwd: "/tmp/agent",
|
|
54
|
+
pid: 1,
|
|
55
|
+
startedAt: "2026-01-01T00:00:00.000Z",
|
|
56
|
+
visibility: "visible",
|
|
57
|
+
status: "active",
|
|
58
|
+
tags: [],
|
|
59
|
+
subscribedRooms: [],
|
|
60
|
+
...overrides,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export async function makeIdentities() {
|
|
64
|
+
const owner = generateIdentity();
|
|
65
|
+
const member = generateIdentity();
|
|
66
|
+
return {
|
|
67
|
+
ownerId: bytesToHex(Uint8Array.from(owner.deviceId)),
|
|
68
|
+
ownerPort: await toIdentityPort(owner),
|
|
69
|
+
memberId: bytesToHex(Uint8Array.from(member.deviceId)),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
export async function mintRoomToken(issuerPort, bearerHex, roomPath) {
|
|
73
|
+
const clock = createSystemClock();
|
|
74
|
+
const verdict = await mintCapabilityToken({
|
|
75
|
+
identity: issuerPort,
|
|
76
|
+
clock,
|
|
77
|
+
tokenId: SAMPLE_TOKEN_ID,
|
|
78
|
+
bearer: deviceIdFromHex(bearerHex),
|
|
79
|
+
capability: "room:member",
|
|
80
|
+
scope: { kind: "room", path: roomPath },
|
|
81
|
+
expires: clock.now() + TOKEN_TTL_MS,
|
|
82
|
+
delegationsRemaining: 0,
|
|
83
|
+
});
|
|
84
|
+
if (!verdict.ok)
|
|
85
|
+
throw new Error("expected the fixture token to mint successfully");
|
|
86
|
+
return verdict.token;
|
|
87
|
+
}
|
|
88
|
+
export async function makeHarness() {
|
|
89
|
+
const ids = await makeIdentities();
|
|
90
|
+
const systemClock = createSystemClock();
|
|
91
|
+
let clockOffsetMs = 0;
|
|
92
|
+
const clock = { now: () => systemClock.now() + clockOffsetMs };
|
|
93
|
+
const slotDir = fs.mkdtempSync(path.join(tmpdir(), "room-protocol-test-"));
|
|
94
|
+
const slot = { harness: "test", cwd: "room-protocol", dir: slotDir };
|
|
95
|
+
// saveRoomToken/saveIssuedRoomGrant write into this slot's own persisted identity file, which must already exist on disk -- unrelated to which crypto identity requireIdentity() uses for minting/verifying, purely a filesystem bookkeeping precondition.
|
|
96
|
+
loadOrCreateIdentity(slot);
|
|
97
|
+
const queueDelivery = vi.fn();
|
|
98
|
+
const fireLocalDelivery = vi.fn();
|
|
99
|
+
const bump = vi.fn();
|
|
100
|
+
const recordMemberOp = vi.fn();
|
|
101
|
+
const refreshMembership = vi.fn();
|
|
102
|
+
const broadcastPatch = vi.fn().mockResolvedValue(undefined);
|
|
103
|
+
const deliverToRoom = vi.fn().mockResolvedValue(undefined);
|
|
104
|
+
const revokeMemberGrant = vi.fn().mockResolvedValue(undefined);
|
|
105
|
+
const sendRoomRequest = vi
|
|
106
|
+
.fn()
|
|
107
|
+
.mockResolvedValue({ result: "ok" });
|
|
108
|
+
const deps = {
|
|
109
|
+
rooms: new Map(),
|
|
110
|
+
messages: new Map(),
|
|
111
|
+
dms: new Map(),
|
|
112
|
+
agents: new Map(),
|
|
113
|
+
dmRequestsInitiatedByMe: new Set(),
|
|
114
|
+
getPeerId: () => ids.ownerId,
|
|
115
|
+
requireIdentity: () => ({
|
|
116
|
+
identity: ids.ownerPort,
|
|
117
|
+
clock,
|
|
118
|
+
slot,
|
|
119
|
+
revocation: createRevocationView(),
|
|
120
|
+
dataStorage: {},
|
|
121
|
+
userIdentity: {},
|
|
122
|
+
userIdentityOptions: {},
|
|
123
|
+
}),
|
|
124
|
+
requireTransport: () => ({ sendRoomRequest }),
|
|
125
|
+
deliveryEngine: {
|
|
126
|
+
queueDelivery,
|
|
127
|
+
fireLocalDelivery,
|
|
128
|
+
bump,
|
|
129
|
+
recordMemberOp,
|
|
130
|
+
refreshMembership,
|
|
131
|
+
broadcastPatch,
|
|
132
|
+
deliverToRoom,
|
|
133
|
+
},
|
|
134
|
+
joinDecisionTimeoutMs: JOIN_DECISION_TIMEOUT_MS,
|
|
135
|
+
revokeMemberGrant,
|
|
136
|
+
};
|
|
137
|
+
return {
|
|
138
|
+
deps,
|
|
139
|
+
advanceClock: (ms) => {
|
|
140
|
+
clockOffsetMs += ms;
|
|
141
|
+
},
|
|
142
|
+
protocol: new RoomProtocol(deps),
|
|
143
|
+
ids,
|
|
144
|
+
slotDir,
|
|
145
|
+
queueDelivery,
|
|
146
|
+
fireLocalDelivery,
|
|
147
|
+
bump,
|
|
148
|
+
recordMemberOp,
|
|
149
|
+
refreshMembership,
|
|
150
|
+
broadcastPatch,
|
|
151
|
+
deliverToRoom,
|
|
152
|
+
revokeMemberGrant,
|
|
153
|
+
sendRoomRequest,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
export function handle(deviceHex) {
|
|
157
|
+
return { id: deviceHex };
|
|
158
|
+
}
|
|
159
|
+
export function manageRequest(overrides = {}) {
|
|
160
|
+
return {
|
|
161
|
+
requestId: 1,
|
|
162
|
+
command: { verb: "room:member", params: overrides.params ?? {} },
|
|
163
|
+
scope: overrides.scope ?? { kind: "room", path: "room-1" },
|
|
164
|
+
token: overrides.token,
|
|
165
|
+
respond: vi.fn().mockResolvedValue(undefined),
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=room-protocol.helper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"room-protocol.helper.js","sourceRoot":"","sources":["../../src/test/room-protocol.helper.ts"],"names":[],"mappings":"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"}
|