@mh-gg/relay-runtime 0.1.1-alpha.20260613T085325975Z
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/package.json +26 -0
- package/src/encryptedRoomRuntime.cjs +641 -0
- package/src/encryptedRoomRuntimeManager.cjs +131 -0
- package/src/index.cjs +152 -0
- package/src/pluginRuntimeHost.cjs +779 -0
- package/test/encryptedRoomRuntime.test.cjs +729 -0
- package/test/operation-role-keys.test.cjs +346 -0
- package/test/plugin-runtime-manager.test.cjs +651 -0
- package/test/relay-runtime.test.cjs +219 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
const assert = require("node:assert/strict");
|
|
2
|
+
const { EventEmitter } = require("node:events");
|
|
3
|
+
const test = require("node:test");
|
|
4
|
+
|
|
5
|
+
const {
|
|
6
|
+
createEncryptedRoomRuntimeManager,
|
|
7
|
+
createPeerReconnectTracker,
|
|
8
|
+
isNewerStore,
|
|
9
|
+
relayRoomStoreSnapshot,
|
|
10
|
+
waitForPeerOpen
|
|
11
|
+
} = require("..");
|
|
12
|
+
|
|
13
|
+
function hexId(prefix) {
|
|
14
|
+
return String(prefix).padStart(64, "0");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function operationEvent(id, overrides = {}) {
|
|
18
|
+
const eventId = hexId(id);
|
|
19
|
+
return {
|
|
20
|
+
id: eventId,
|
|
21
|
+
pubkey: overrides.pubkey || "pk_" + eventId.slice(0, 8),
|
|
22
|
+
created_at: 1760000000,
|
|
23
|
+
kind: overrides.kind ?? 9001,
|
|
24
|
+
tags: [
|
|
25
|
+
["scheme", overrides.scheme ?? "matterhorn.operation.v2"],
|
|
26
|
+
["d", overrides.roomName || "room"],
|
|
27
|
+
["stream", overrides.stream || "stream:general"],
|
|
28
|
+
["hlc", overrides.hlc || `000000000000001:000000:${overrides.nodeId || "node"}`],
|
|
29
|
+
["member", overrides.member || "alice"],
|
|
30
|
+
["device", overrides.device || "d1"],
|
|
31
|
+
["seq", String(overrides.seq ?? 0)],
|
|
32
|
+
["plugin", overrides.plugin || "chat"],
|
|
33
|
+
["type", overrides.type || "message.send"],
|
|
34
|
+
["role", overrides.role || "member"],
|
|
35
|
+
["epoch", overrides.epoch || "e1"],
|
|
36
|
+
["op-id", overrides.opId || `op_${id}`],
|
|
37
|
+
["payload-hash", overrides.payloadHash || `ph_${id}`]
|
|
38
|
+
],
|
|
39
|
+
content: "encrypted"
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function roomStore(roomName, version = 1) {
|
|
44
|
+
return {
|
|
45
|
+
roomName,
|
|
46
|
+
roomPeerId: `${roomName}-peer`,
|
|
47
|
+
roomSecret: "secret",
|
|
48
|
+
admins: {},
|
|
49
|
+
seenMutations: [],
|
|
50
|
+
state: {
|
|
51
|
+
version,
|
|
52
|
+
updatedAt: version,
|
|
53
|
+
details: {},
|
|
54
|
+
guests: {},
|
|
55
|
+
posts: [],
|
|
56
|
+
comments: [],
|
|
57
|
+
adminIds: []
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
test("relay room store snapshots clone matching room stores", () => {
|
|
63
|
+
const store = roomStore("runtime-room", 1);
|
|
64
|
+
store.state.guests.alice = { id: "alice", name: "Alice", avatar: "A" };
|
|
65
|
+
|
|
66
|
+
const snapshot = relayRoomStoreSnapshot("runtime-room", store);
|
|
67
|
+
assert.equal(snapshot.roomName, "runtime-room");
|
|
68
|
+
assert.notEqual(snapshot, store);
|
|
69
|
+
assert.deepEqual(snapshot.state.guests.alice, { id: "alice", name: "Alice", avatar: "A" });
|
|
70
|
+
assert.equal(relayRoomStoreSnapshot("other-room", store), undefined);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test("encrypted room runtime manager creates, snapshots, restores, and removes rooms", () => {
|
|
74
|
+
const manager = createEncryptedRoomRuntimeManager({ maxEventsPerStream: 2 });
|
|
75
|
+
assert.equal(manager.hasRoom("room-a"), false);
|
|
76
|
+
assert.deepEqual(manager.searchNgrams("missing", { tokens: ["t"] }), { events: [], matches: [], total: 0, queryTokenCount: 0 });
|
|
77
|
+
assert.deepEqual(manager.ngramIndexStats("missing"), { targets: 0, indexEvents: 0, tokenPostingLists: 0, postings: 0 });
|
|
78
|
+
|
|
79
|
+
const inserted = manager.insertEvent("room-a", operationEvent("e1", { roomName: "room-a" }));
|
|
80
|
+
assert.equal(inserted.ok, true);
|
|
81
|
+
assert.equal(inserted.inserted, true);
|
|
82
|
+
assert.equal(manager.hasRoom("room-a"), true);
|
|
83
|
+
assert.deepEqual(manager.listRooms(), ["room-a"]);
|
|
84
|
+
|
|
85
|
+
const snapshot = manager.snapshot();
|
|
86
|
+
assert.equal(snapshot["room-a"].roomName, "room-a");
|
|
87
|
+
assert.equal(snapshot["room-a"].events.length, 1);
|
|
88
|
+
|
|
89
|
+
const restored = createEncryptedRoomRuntimeManager();
|
|
90
|
+
assert.deepEqual(restored.restore(snapshot), { ok: true, rooms: 1, inserted: 1 });
|
|
91
|
+
assert.deepEqual(restored.listRooms(), ["room-a"]);
|
|
92
|
+
assert.equal(restored.removeRoom("room-a"), true);
|
|
93
|
+
assert.equal(restored.removeRoom("room-a"), false);
|
|
94
|
+
assert.deepEqual(restored.restore(null), { ok: true, rooms: 0, inserted: 0 });
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("encrypted room runtime manager rebuilds only mapped room events", () => {
|
|
98
|
+
const warnings = [];
|
|
99
|
+
const manager = createEncryptedRoomRuntimeManager({ logger: { warn: (...args) => warnings.push(args) } });
|
|
100
|
+
const validOperation = operationEvent("e2", { roomName: "room-b", stream: "s1" });
|
|
101
|
+
const validNgram = {
|
|
102
|
+
...operationEvent("e3", { roomName: "room-b", kind: 9013, stream: "s2" }),
|
|
103
|
+
tags: [
|
|
104
|
+
["room", "room-b"],
|
|
105
|
+
["stream", "s2"],
|
|
106
|
+
["hlc", "000000000000002:000000:node"],
|
|
107
|
+
["member", "alice"]
|
|
108
|
+
],
|
|
109
|
+
content: JSON.stringify({
|
|
110
|
+
kind: "matterhorn.room-index-ngram",
|
|
111
|
+
version: 1,
|
|
112
|
+
suite: "matterhorn.ngram.hmac-sha256.v1",
|
|
113
|
+
targetEventId: "target",
|
|
114
|
+
tokens: ["abcdefghijklmnopqrstuvwxyz"]
|
|
115
|
+
})
|
|
116
|
+
};
|
|
117
|
+
const ignoredBadScheme = operationEvent("e4", { roomName: "room-b", scheme: "legacy" });
|
|
118
|
+
const ignoredKind = operationEvent("e5", { roomName: "room-b", kind: 1 });
|
|
119
|
+
|
|
120
|
+
const result = manager.rebuildFromEvents((filters) => {
|
|
121
|
+
assert.deepEqual(filters, [{ kinds: [9001, 9013] }]);
|
|
122
|
+
return [validOperation, validNgram, ignoredBadScheme, ignoredKind, null];
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
assert.deepEqual(result, { ok: true, inserted: 2, operationEvents: 1, ngramIndexEvents: 1 });
|
|
126
|
+
assert.deepEqual(manager.listRooms(), ["room-b"]);
|
|
127
|
+
assert.equal(manager.getRoom("room-b").get(validOperation.id).id, validOperation.id);
|
|
128
|
+
assert.deepEqual(warnings, []);
|
|
129
|
+
|
|
130
|
+
const failed = manager.rebuildFromEvents(() => {
|
|
131
|
+
throw new Error("boom");
|
|
132
|
+
});
|
|
133
|
+
assert.deepEqual(failed, { ok: true, inserted: 0, operationEvents: 0, ngramIndexEvents: 0 });
|
|
134
|
+
assert.equal(warnings.length, 1);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test("isNewerStore compares version before timestamp", () => {
|
|
138
|
+
assert.equal(isNewerStore(roomStore("newer", 2), roomStore("newer", 1)), true);
|
|
139
|
+
assert.equal(isNewerStore(roomStore("older", 1), roomStore("older", 2)), false);
|
|
140
|
+
const left = roomStore("same", 1);
|
|
141
|
+
const right = roomStore("same", 1);
|
|
142
|
+
left.updatedAt = 3;
|
|
143
|
+
right.updatedAt = 2;
|
|
144
|
+
assert.equal(isNewerStore(left, right), true);
|
|
145
|
+
right.updatedAt = 4;
|
|
146
|
+
assert.equal(isNewerStore(left, right), false);
|
|
147
|
+
left.updatedAt = 4;
|
|
148
|
+
assert.equal(isNewerStore(left, right), false);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test("waitForPeerOpen resolves on open and rejects on error", async () => {
|
|
152
|
+
const openingPeer = new EventEmitter();
|
|
153
|
+
openingPeer.open = false;
|
|
154
|
+
openingPeer.id = "opening-peer";
|
|
155
|
+
const opened = waitForPeerOpen(openingPeer, "opening peer", 100);
|
|
156
|
+
openingPeer.emit("open", "opening-peer");
|
|
157
|
+
assert.equal(await opened, "opening-peer");
|
|
158
|
+
|
|
159
|
+
const failingPeer = new EventEmitter();
|
|
160
|
+
failingPeer.open = false;
|
|
161
|
+
const failed = waitForPeerOpen(failingPeer, "failing peer", 100);
|
|
162
|
+
failingPeer.emit("error", new Error("failed"));
|
|
163
|
+
await assert.rejects(failed, /failed/);
|
|
164
|
+
|
|
165
|
+
const openPeer = { open: true, id: "already-open" };
|
|
166
|
+
assert.equal(await waitForPeerOpen(openPeer, "open peer", 100), "already-open");
|
|
167
|
+
|
|
168
|
+
const timeoutPeer = new EventEmitter();
|
|
169
|
+
timeoutPeer.open = false;
|
|
170
|
+
await assert.rejects(waitForPeerOpen(timeoutPeer, "timeout peer", 1), /timeout peer did not open/);
|
|
171
|
+
|
|
172
|
+
const listenerPeer = new EventEmitter();
|
|
173
|
+
listenerPeer.open = false;
|
|
174
|
+
listenerPeer.off = undefined;
|
|
175
|
+
const openedWithRemoveListener = waitForPeerOpen(listenerPeer, "listener peer", 100);
|
|
176
|
+
listenerPeer.emit("open", "listener-peer");
|
|
177
|
+
assert.equal(await openedWithRemoveListener, "listener-peer");
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
test("peer reconnect tracker logs once and warns after repeated reconnects", () => {
|
|
181
|
+
const warnings = [];
|
|
182
|
+
const debugs = [];
|
|
183
|
+
const logs = [];
|
|
184
|
+
const previousLog = console.log;
|
|
185
|
+
const previousNow = Date.now;
|
|
186
|
+
let now = previousNow();
|
|
187
|
+
Date.now = () => now;
|
|
188
|
+
console.log = (message) => logs.push(message);
|
|
189
|
+
try {
|
|
190
|
+
const tracker = createPeerReconnectTracker({
|
|
191
|
+
debug: (message) => debugs.push(message),
|
|
192
|
+
warn: (message) => warnings.push(message),
|
|
193
|
+
threshold: 2,
|
|
194
|
+
windowMs: 1000
|
|
195
|
+
});
|
|
196
|
+
const peer = { id: "peer-a" };
|
|
197
|
+
tracker.logOpen("relay peer", "peer-a", peer);
|
|
198
|
+
tracker.logOpen("relay peer", "peer-a", peer);
|
|
199
|
+
tracker.warn(peer, "relay peer", "network");
|
|
200
|
+
now += 1;
|
|
201
|
+
tracker.warn(peer, "relay peer", "network");
|
|
202
|
+
|
|
203
|
+
assert.deepEqual(logs, ["relay peer is live as peer-a"]);
|
|
204
|
+
assert.equal(debugs.some((message) => message.includes("reopened as peer-a")), true);
|
|
205
|
+
assert.equal(warnings.length, 1);
|
|
206
|
+
assert.equal(tracker.summary()[0].warned, true);
|
|
207
|
+
assert.equal(tracker.stablePeerId(peer), "peer-a");
|
|
208
|
+
assert.equal(tracker.stablePeerId({}), "unknown");
|
|
209
|
+
} finally {
|
|
210
|
+
Date.now = previousNow;
|
|
211
|
+
console.log = previousLog;
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
test("peer reconnect tracker defaults do not warn before threshold", () => {
|
|
216
|
+
const tracker = createPeerReconnectTracker();
|
|
217
|
+
tracker.warn({ MatterhornStableId: "peer-b" }, "relay peer", "network");
|
|
218
|
+
assert.equal(tracker.summary()[0].warned, false);
|
|
219
|
+
});
|