@meshwhisper/sdk 0.1.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/README.md +138 -0
- package/dist/browser/index.d.ts +4 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +19 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/chaff/index.d.ts +91 -0
- package/dist/chaff/index.d.ts.map +1 -0
- package/dist/chaff/index.js +268 -0
- package/dist/chaff/index.js.map +1 -0
- package/dist/cluster/index.d.ts +159 -0
- package/dist/cluster/index.d.ts.map +1 -0
- package/dist/cluster/index.js +393 -0
- package/dist/cluster/index.js.map +1 -0
- package/dist/compliance/index.d.ts +129 -0
- package/dist/compliance/index.d.ts.map +1 -0
- package/dist/compliance/index.js +315 -0
- package/dist/compliance/index.js.map +1 -0
- package/dist/crypto/index.d.ts +65 -0
- package/dist/crypto/index.d.ts.map +1 -0
- package/dist/crypto/index.js +146 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/group/index.d.ts +155 -0
- package/dist/group/index.d.ts.map +1 -0
- package/dist/group/index.js +560 -0
- package/dist/group/index.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/namespace/index.d.ts +155 -0
- package/dist/namespace/index.d.ts.map +1 -0
- package/dist/namespace/index.js +278 -0
- package/dist/namespace/index.js.map +1 -0
- package/dist/node/index.d.ts +4 -0
- package/dist/node/index.d.ts.map +1 -0
- package/dist/node/index.js +19 -0
- package/dist/node/index.js.map +1 -0
- package/dist/packet/index.d.ts +63 -0
- package/dist/packet/index.d.ts.map +1 -0
- package/dist/packet/index.js +244 -0
- package/dist/packet/index.js.map +1 -0
- package/dist/permissions/index.d.ts +107 -0
- package/dist/permissions/index.d.ts.map +1 -0
- package/dist/permissions/index.js +282 -0
- package/dist/permissions/index.js.map +1 -0
- package/dist/persistence/idb-storage.d.ts +27 -0
- package/dist/persistence/idb-storage.d.ts.map +1 -0
- package/dist/persistence/idb-storage.js +75 -0
- package/dist/persistence/idb-storage.js.map +1 -0
- package/dist/persistence/index.d.ts +4 -0
- package/dist/persistence/index.d.ts.map +1 -0
- package/dist/persistence/index.js +3 -0
- package/dist/persistence/index.js.map +1 -0
- package/dist/persistence/node-storage.d.ts +33 -0
- package/dist/persistence/node-storage.d.ts.map +1 -0
- package/dist/persistence/node-storage.js +90 -0
- package/dist/persistence/node-storage.js.map +1 -0
- package/dist/persistence/serialization.d.ts +4 -0
- package/dist/persistence/serialization.d.ts.map +1 -0
- package/dist/persistence/serialization.js +49 -0
- package/dist/persistence/serialization.js.map +1 -0
- package/dist/persistence/types.d.ts +29 -0
- package/dist/persistence/types.d.ts.map +1 -0
- package/dist/persistence/types.js +5 -0
- package/dist/persistence/types.js.map +1 -0
- package/dist/ratchet/index.d.ts +80 -0
- package/dist/ratchet/index.d.ts.map +1 -0
- package/dist/ratchet/index.js +259 -0
- package/dist/ratchet/index.js.map +1 -0
- package/dist/reciprocity/index.d.ts +109 -0
- package/dist/reciprocity/index.d.ts.map +1 -0
- package/dist/reciprocity/index.js +311 -0
- package/dist/reciprocity/index.js.map +1 -0
- package/dist/relay/index.d.ts +87 -0
- package/dist/relay/index.d.ts.map +1 -0
- package/dist/relay/index.js +286 -0
- package/dist/relay/index.js.map +1 -0
- package/dist/routing/index.d.ts +136 -0
- package/dist/routing/index.d.ts.map +1 -0
- package/dist/routing/index.js +478 -0
- package/dist/routing/index.js.map +1 -0
- package/dist/sdk/index.d.ts +322 -0
- package/dist/sdk/index.d.ts.map +1 -0
- package/dist/sdk/index.js +1530 -0
- package/dist/sdk/index.js.map +1 -0
- package/dist/sybil/index.d.ts +123 -0
- package/dist/sybil/index.d.ts.map +1 -0
- package/dist/sybil/index.js +491 -0
- package/dist/sybil/index.js.map +1 -0
- package/dist/transport/browser/index.d.ts +34 -0
- package/dist/transport/browser/index.d.ts.map +1 -0
- package/dist/transport/browser/index.js +176 -0
- package/dist/transport/browser/index.js.map +1 -0
- package/dist/transport/local/index.d.ts +57 -0
- package/dist/transport/local/index.d.ts.map +1 -0
- package/dist/transport/local/index.js +442 -0
- package/dist/transport/local/index.js.map +1 -0
- package/dist/transport/negotiator/index.d.ts +79 -0
- package/dist/transport/negotiator/index.d.ts.map +1 -0
- package/dist/transport/negotiator/index.js +289 -0
- package/dist/transport/negotiator/index.js.map +1 -0
- package/dist/transport/node/index.d.ts +56 -0
- package/dist/transport/node/index.d.ts.map +1 -0
- package/dist/transport/node/index.js +209 -0
- package/dist/transport/node/index.js.map +1 -0
- package/dist/transport/noop/index.d.ts +11 -0
- package/dist/transport/noop/index.d.ts.map +1 -0
- package/dist/transport/noop/index.js +20 -0
- package/dist/transport/noop/index.js.map +1 -0
- package/dist/transport/p2p/index.d.ts +109 -0
- package/dist/transport/p2p/index.d.ts.map +1 -0
- package/dist/transport/p2p/index.js +237 -0
- package/dist/transport/p2p/index.js.map +1 -0
- package/dist/transport/websocket/index.d.ts +89 -0
- package/dist/transport/websocket/index.d.ts.map +1 -0
- package/dist/transport/websocket/index.js +498 -0
- package/dist/transport/websocket/index.js.map +1 -0
- package/dist/transport/websocket/serialize.d.ts +5 -0
- package/dist/transport/websocket/serialize.d.ts.map +1 -0
- package/dist/transport/websocket/serialize.js +55 -0
- package/dist/transport/websocket/serialize.js.map +1 -0
- package/dist/types.d.ts +215 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +15 -0
- package/dist/types.js.map +1 -0
- package/dist/x3dh/index.d.ts +120 -0
- package/dist/x3dh/index.d.ts.map +1 -0
- package/dist/x3dh/index.js +290 -0
- package/dist/x3dh/index.js.map +1 -0
- package/package.json +59 -0
- package/src/browser/index.ts +19 -0
- package/src/chaff/index.ts +340 -0
- package/src/cluster/index.ts +482 -0
- package/src/compliance/index.ts +407 -0
- package/src/crypto/index.ts +193 -0
- package/src/group/index.ts +719 -0
- package/src/index.ts +87 -0
- package/src/lz4js.d.ts +58 -0
- package/src/namespace/index.ts +336 -0
- package/src/node/index.ts +19 -0
- package/src/packet/index.ts +326 -0
- package/src/permissions/index.ts +405 -0
- package/src/persistence/idb-storage.ts +83 -0
- package/src/persistence/index.ts +3 -0
- package/src/persistence/node-storage.ts +96 -0
- package/src/persistence/serialization.ts +75 -0
- package/src/persistence/types.ts +33 -0
- package/src/ratchet/index.ts +363 -0
- package/src/reciprocity/index.ts +371 -0
- package/src/relay/index.ts +382 -0
- package/src/routing/index.ts +577 -0
- package/src/sdk/index.ts +1994 -0
- package/src/sybil/index.ts +661 -0
- package/src/transport/browser/index.ts +201 -0
- package/src/transport/local/index.ts +540 -0
- package/src/transport/negotiator/index.ts +397 -0
- package/src/transport/node/index.ts +234 -0
- package/src/transport/noop/index.ts +22 -0
- package/src/transport/p2p/index.ts +345 -0
- package/src/transport/websocket/index.ts +660 -0
- package/src/transport/websocket/serialize.ts +68 -0
- package/src/types.ts +275 -0
- package/src/x3dh/index.ts +388 -0
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// MeshWhisper SDK — Reciprocity Engine
|
|
3
|
+
// Maintains a local relay ledger implementing tit-for-tat
|
|
4
|
+
// relay fairness as described in PRD section 7.3.
|
|
5
|
+
// ============================================================
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// Constants
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
/** Default grace period for newly registered devices (48 hours). */
|
|
10
|
+
const DEFAULT_GRACE_PERIOD_HOURS = 48;
|
|
11
|
+
/** Tier thresholds for reciprocity scoring. */
|
|
12
|
+
const TIER_CONTRIBUTOR_THRESHOLD = 1.0;
|
|
13
|
+
const TIER_BALANCED_THRESHOLD = 0.5;
|
|
14
|
+
const TIER_CONSUMER_THRESHOLD = 0.1;
|
|
15
|
+
/** Relay priority values per tier. */
|
|
16
|
+
const PRIORITY_CONTRIBUTOR = 1.0;
|
|
17
|
+
const PRIORITY_BALANCED = 0.7;
|
|
18
|
+
const PRIORITY_CONSUMER = 0.3;
|
|
19
|
+
const PRIORITY_FREERIDER = 0.0;
|
|
20
|
+
/** Serialization format version. */
|
|
21
|
+
const SERIALIZATION_VERSION = 1;
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// RelayLedger
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
/**
|
|
26
|
+
* Tracks bytes relayed for and by each peer, computes reciprocity scores,
|
|
27
|
+
* and makes relay-priority decisions. Purely local and approximate — there
|
|
28
|
+
* is no global accounting.
|
|
29
|
+
*/
|
|
30
|
+
export class RelayLedger {
|
|
31
|
+
gracePeriodMs;
|
|
32
|
+
entries = new Map();
|
|
33
|
+
deviceId = null;
|
|
34
|
+
deviceRegisteredAt = null;
|
|
35
|
+
constructor(options) {
|
|
36
|
+
const hours = options?.gracePeriodHours ?? DEFAULT_GRACE_PERIOD_HOURS;
|
|
37
|
+
if (hours < 0) {
|
|
38
|
+
throw new RangeError('gracePeriodHours must be non-negative');
|
|
39
|
+
}
|
|
40
|
+
this.gracePeriodMs = hours * 60 * 60 * 1000;
|
|
41
|
+
}
|
|
42
|
+
// -----------------------------------------------------------------------
|
|
43
|
+
// Ledger operations
|
|
44
|
+
// -----------------------------------------------------------------------
|
|
45
|
+
/**
|
|
46
|
+
* Record that we relayed `bytes` of data on behalf of `peerId`.
|
|
47
|
+
*/
|
|
48
|
+
recordRelayedForPeer(peerId, bytes) {
|
|
49
|
+
if (bytes < 0) {
|
|
50
|
+
throw new RangeError('bytes must be non-negative');
|
|
51
|
+
}
|
|
52
|
+
const entry = this.getOrCreateEntry(peerId);
|
|
53
|
+
entry.bytesRelayedForThem += bytes;
|
|
54
|
+
entry.lastUpdated = Date.now();
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Record that `peerId` relayed `bytes` of data for us.
|
|
58
|
+
*/
|
|
59
|
+
recordPeerRelayedForUs(peerId, bytes) {
|
|
60
|
+
if (bytes < 0) {
|
|
61
|
+
throw new RangeError('bytes must be non-negative');
|
|
62
|
+
}
|
|
63
|
+
const entry = this.getOrCreateEntry(peerId);
|
|
64
|
+
entry.bytesTheyRelayedForUs += bytes;
|
|
65
|
+
entry.lastUpdated = Date.now();
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Return the ledger entry for a given peer, or `null` if none exists.
|
|
69
|
+
*/
|
|
70
|
+
getEntry(peerId) {
|
|
71
|
+
const entry = this.entries.get(peerId);
|
|
72
|
+
return entry ? { ...entry } : null;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Return a snapshot of all ledger entries.
|
|
76
|
+
*/
|
|
77
|
+
getAllEntries() {
|
|
78
|
+
return Array.from(this.entries.values()).map((e) => ({ ...e }));
|
|
79
|
+
}
|
|
80
|
+
// -----------------------------------------------------------------------
|
|
81
|
+
// Score computation
|
|
82
|
+
// -----------------------------------------------------------------------
|
|
83
|
+
/**
|
|
84
|
+
* Compute the reciprocity score for a specific peer.
|
|
85
|
+
*
|
|
86
|
+
* Score = bytes_relayed_for_them / bytes_they_relayed_for_us
|
|
87
|
+
*
|
|
88
|
+
* - If neither party has relayed anything, returns 1.0 (neutral).
|
|
89
|
+
* - If we have relayed for them but they haven't for us, returns Infinity
|
|
90
|
+
* (we are a pure contributor to this peer).
|
|
91
|
+
* - If they have relayed for us but we haven't for them, returns 0.0
|
|
92
|
+
* (we are a pure consumer from this peer).
|
|
93
|
+
*/
|
|
94
|
+
getScore(peerId) {
|
|
95
|
+
const entry = this.entries.get(peerId);
|
|
96
|
+
if (!entry) {
|
|
97
|
+
return 1.0; // unknown peer — treat as neutral
|
|
98
|
+
}
|
|
99
|
+
return this.computeScore(entry.bytesRelayedForThem, entry.bytesTheyRelayedForUs);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Compute the aggregate reciprocity score across all peers.
|
|
103
|
+
*
|
|
104
|
+
* Uses total bytes relayed for all peers vs total bytes all peers
|
|
105
|
+
* relayed for us.
|
|
106
|
+
*/
|
|
107
|
+
getGlobalScore() {
|
|
108
|
+
let totalRelayedForThem = 0;
|
|
109
|
+
let totalTheyRelayedForUs = 0;
|
|
110
|
+
for (const entry of this.entries.values()) {
|
|
111
|
+
totalRelayedForThem += entry.bytesRelayedForThem;
|
|
112
|
+
totalTheyRelayedForUs += entry.bytesTheyRelayedForUs;
|
|
113
|
+
}
|
|
114
|
+
return this.computeScore(totalRelayedForThem, totalTheyRelayedForUs);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Determine the reciprocity tier for a given peer.
|
|
118
|
+
*/
|
|
119
|
+
getTier(peerId) {
|
|
120
|
+
if (this.isInGracePeriod()) {
|
|
121
|
+
return 'balanced';
|
|
122
|
+
}
|
|
123
|
+
const score = this.getScore(peerId);
|
|
124
|
+
return RelayLedger.tierFromScore(score);
|
|
125
|
+
}
|
|
126
|
+
// -----------------------------------------------------------------------
|
|
127
|
+
// Relay priority
|
|
128
|
+
// -----------------------------------------------------------------------
|
|
129
|
+
/**
|
|
130
|
+
* Determine whether we should relay traffic for this peer.
|
|
131
|
+
*
|
|
132
|
+
* Free-riders are refused unless we are still in our grace period.
|
|
133
|
+
*/
|
|
134
|
+
shouldRelay(peerId) {
|
|
135
|
+
if (this.isInGracePeriod()) {
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
return this.getTier(peerId) !== 'freerider';
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Return a relay-queue priority between 0.0 and 1.0 for this peer.
|
|
142
|
+
*
|
|
143
|
+
* Higher values mean packets for/from this peer should be relayed sooner.
|
|
144
|
+
*/
|
|
145
|
+
getRelayPriority(peerId) {
|
|
146
|
+
const tier = this.getTier(peerId);
|
|
147
|
+
switch (tier) {
|
|
148
|
+
case 'contributor':
|
|
149
|
+
return PRIORITY_CONTRIBUTOR;
|
|
150
|
+
case 'balanced':
|
|
151
|
+
return PRIORITY_BALANCED;
|
|
152
|
+
case 'consumer':
|
|
153
|
+
return PRIORITY_CONSUMER;
|
|
154
|
+
case 'freerider':
|
|
155
|
+
return PRIORITY_FREERIDER;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// -----------------------------------------------------------------------
|
|
159
|
+
// Grace period
|
|
160
|
+
// -----------------------------------------------------------------------
|
|
161
|
+
/**
|
|
162
|
+
* Register this device, recording the current time as the creation
|
|
163
|
+
* timestamp for grace-period purposes.
|
|
164
|
+
*/
|
|
165
|
+
registerDevice(deviceId) {
|
|
166
|
+
if (!deviceId) {
|
|
167
|
+
throw new TypeError('deviceId must be a non-empty string');
|
|
168
|
+
}
|
|
169
|
+
this.deviceId = deviceId;
|
|
170
|
+
this.deviceRegisteredAt = Date.now();
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Returns `true` if this device was registered within the configured
|
|
174
|
+
* grace period (default 48 hours).
|
|
175
|
+
*/
|
|
176
|
+
isInGracePeriod() {
|
|
177
|
+
if (this.deviceRegisteredAt === null) {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
return Date.now() - this.deviceRegisteredAt < this.gracePeriodMs;
|
|
181
|
+
}
|
|
182
|
+
// -----------------------------------------------------------------------
|
|
183
|
+
// Ledger maintenance
|
|
184
|
+
// -----------------------------------------------------------------------
|
|
185
|
+
/**
|
|
186
|
+
* Apply exponential decay to every entry in the ledger.
|
|
187
|
+
*
|
|
188
|
+
* Multiplies both byte counters by `factor` (should be between 0 and 1).
|
|
189
|
+
* This prevents ancient history from permanently dominating the score.
|
|
190
|
+
*/
|
|
191
|
+
decayLedger(factor) {
|
|
192
|
+
if (factor < 0 || factor > 1) {
|
|
193
|
+
throw new RangeError('decay factor must be between 0 and 1');
|
|
194
|
+
}
|
|
195
|
+
for (const entry of this.entries.values()) {
|
|
196
|
+
entry.bytesRelayedForThem = Math.floor(entry.bytesRelayedForThem * factor);
|
|
197
|
+
entry.bytesTheyRelayedForUs = Math.floor(entry.bytesTheyRelayedForUs * factor);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Remove entries for peers whose `lastUpdated` timestamp is older
|
|
202
|
+
* than `maxAgeMs` milliseconds ago.
|
|
203
|
+
*/
|
|
204
|
+
pruneInactive(maxAgeMs) {
|
|
205
|
+
if (maxAgeMs < 0) {
|
|
206
|
+
throw new RangeError('maxAgeMs must be non-negative');
|
|
207
|
+
}
|
|
208
|
+
const cutoff = Date.now() - maxAgeMs;
|
|
209
|
+
for (const [peerId, entry] of this.entries) {
|
|
210
|
+
if (entry.lastUpdated < cutoff) {
|
|
211
|
+
this.entries.delete(peerId);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Clear all ledger entries. Device registration is preserved.
|
|
217
|
+
*/
|
|
218
|
+
reset() {
|
|
219
|
+
this.entries.clear();
|
|
220
|
+
}
|
|
221
|
+
// -----------------------------------------------------------------------
|
|
222
|
+
// Serialization
|
|
223
|
+
// -----------------------------------------------------------------------
|
|
224
|
+
/**
|
|
225
|
+
* Serialize the entire ledger state to a `Uint8Array` for persistence.
|
|
226
|
+
*/
|
|
227
|
+
serialize() {
|
|
228
|
+
const payload = {
|
|
229
|
+
version: SERIALIZATION_VERSION,
|
|
230
|
+
gracePeriodHours: this.gracePeriodMs / (60 * 60 * 1000),
|
|
231
|
+
deviceId: this.deviceId,
|
|
232
|
+
deviceRegisteredAt: this.deviceRegisteredAt,
|
|
233
|
+
entries: this.getAllEntries(),
|
|
234
|
+
};
|
|
235
|
+
const json = JSON.stringify(payload);
|
|
236
|
+
return new TextEncoder().encode(json);
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Restore a `RelayLedger` from previously serialized data.
|
|
240
|
+
*/
|
|
241
|
+
static deserialize(data) {
|
|
242
|
+
let parsed;
|
|
243
|
+
try {
|
|
244
|
+
const json = new TextDecoder().decode(data);
|
|
245
|
+
parsed = JSON.parse(json);
|
|
246
|
+
}
|
|
247
|
+
catch {
|
|
248
|
+
throw new Error('Failed to deserialize RelayLedger: invalid data');
|
|
249
|
+
}
|
|
250
|
+
if (parsed.version !== SERIALIZATION_VERSION) {
|
|
251
|
+
throw new Error(`Unsupported RelayLedger serialization version: ${parsed.version}`);
|
|
252
|
+
}
|
|
253
|
+
const ledger = new RelayLedger({
|
|
254
|
+
gracePeriodHours: parsed.gracePeriodHours,
|
|
255
|
+
});
|
|
256
|
+
if (parsed.deviceId !== null && parsed.deviceRegisteredAt !== null) {
|
|
257
|
+
ledger.deviceId = parsed.deviceId;
|
|
258
|
+
ledger.deviceRegisteredAt = parsed.deviceRegisteredAt;
|
|
259
|
+
}
|
|
260
|
+
for (const entry of parsed.entries) {
|
|
261
|
+
ledger.entries.set(entry.peerId, {
|
|
262
|
+
peerId: entry.peerId,
|
|
263
|
+
bytesRelayedForThem: entry.bytesRelayedForThem,
|
|
264
|
+
bytesTheyRelayedForUs: entry.bytesTheyRelayedForUs,
|
|
265
|
+
lastUpdated: entry.lastUpdated,
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
return ledger;
|
|
269
|
+
}
|
|
270
|
+
// -----------------------------------------------------------------------
|
|
271
|
+
// Static helpers
|
|
272
|
+
// -----------------------------------------------------------------------
|
|
273
|
+
/**
|
|
274
|
+
* Map a numeric reciprocity score to a tier label.
|
|
275
|
+
*/
|
|
276
|
+
static tierFromScore(score) {
|
|
277
|
+
if (score > TIER_CONTRIBUTOR_THRESHOLD)
|
|
278
|
+
return 'contributor';
|
|
279
|
+
if (score >= TIER_BALANCED_THRESHOLD)
|
|
280
|
+
return 'balanced';
|
|
281
|
+
if (score >= TIER_CONSUMER_THRESHOLD)
|
|
282
|
+
return 'consumer';
|
|
283
|
+
return 'freerider';
|
|
284
|
+
}
|
|
285
|
+
// -----------------------------------------------------------------------
|
|
286
|
+
// Private helpers
|
|
287
|
+
// -----------------------------------------------------------------------
|
|
288
|
+
getOrCreateEntry(peerId) {
|
|
289
|
+
let entry = this.entries.get(peerId);
|
|
290
|
+
if (!entry) {
|
|
291
|
+
entry = {
|
|
292
|
+
peerId,
|
|
293
|
+
bytesRelayedForThem: 0,
|
|
294
|
+
bytesTheyRelayedForUs: 0,
|
|
295
|
+
lastUpdated: Date.now(),
|
|
296
|
+
};
|
|
297
|
+
this.entries.set(peerId, entry);
|
|
298
|
+
}
|
|
299
|
+
return entry;
|
|
300
|
+
}
|
|
301
|
+
computeScore(relayedForThem, theyRelayedForUs) {
|
|
302
|
+
if (relayedForThem === 0 && theyRelayedForUs === 0) {
|
|
303
|
+
return 1.0; // no data — neutral
|
|
304
|
+
}
|
|
305
|
+
if (theyRelayedForUs === 0) {
|
|
306
|
+
return Infinity; // pure contributor
|
|
307
|
+
}
|
|
308
|
+
return relayedForThem / theyRelayedForUs;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/reciprocity/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { StoredBlob } from "../types";
|
|
2
|
+
export interface RelayStoreOptions {
|
|
3
|
+
maxStorageBytes?: number;
|
|
4
|
+
defaultTTLHours?: number;
|
|
5
|
+
}
|
|
6
|
+
export declare class RelayStore {
|
|
7
|
+
private readonly maxStorageBytes;
|
|
8
|
+
private readonly defaultTTLHours;
|
|
9
|
+
/** All stored blobs keyed by blob id. */
|
|
10
|
+
private readonly blobs;
|
|
11
|
+
/** Secondary index: destHash hex -> set of blob ids. */
|
|
12
|
+
private readonly destIndex;
|
|
13
|
+
/** Track insertion order for LRU eviction (oldest first). */
|
|
14
|
+
private readonly insertionOrder;
|
|
15
|
+
private currentStorageBytes;
|
|
16
|
+
private pruneTimer;
|
|
17
|
+
constructor(options?: RelayStoreOptions);
|
|
18
|
+
private destKey;
|
|
19
|
+
private isExpired;
|
|
20
|
+
/**
|
|
21
|
+
* Store an encrypted blob. Returns false if storage is full even after
|
|
22
|
+
* evicting the oldest blobs.
|
|
23
|
+
*/
|
|
24
|
+
storeBlob(blob: StoredBlob): boolean;
|
|
25
|
+
/** Retrieve all stored blobs for a given destination hash. */
|
|
26
|
+
getBlobs(destHash: Uint8Array): StoredBlob[];
|
|
27
|
+
/** Remove a single blob by id. */
|
|
28
|
+
removeBlob(id: string): void;
|
|
29
|
+
/** Remove all blobs targeting a specific destination hash. */
|
|
30
|
+
removeBlobsForDest(destHash: Uint8Array): void;
|
|
31
|
+
/** Remove all expired blobs. Returns count of blobs removed. */
|
|
32
|
+
pruneExpired(): number;
|
|
33
|
+
/** Start automatic periodic pruning. */
|
|
34
|
+
startPruneInterval(intervalMs?: number): void;
|
|
35
|
+
/** Stop automatic periodic pruning. */
|
|
36
|
+
stopPruneInterval(): void;
|
|
37
|
+
/** Bytes currently consumed by stored blobs. */
|
|
38
|
+
getStorageUsed(): number;
|
|
39
|
+
/** Configured maximum storage capacity in bytes. */
|
|
40
|
+
getStorageCapacity(): number;
|
|
41
|
+
/** Total number of blobs currently stored. */
|
|
42
|
+
getBlobCount(): number;
|
|
43
|
+
/**
|
|
44
|
+
* Handle a presence announcement. When a peer announces it is online we
|
|
45
|
+
* return (and remove) all blobs matching its destination hash.
|
|
46
|
+
*
|
|
47
|
+
* Destination hashes rotate hourly. The caller should provide both the
|
|
48
|
+
* current-epoch and the previous-epoch destination hashes so we can match
|
|
49
|
+
* blobs stored under either.
|
|
50
|
+
*/
|
|
51
|
+
handlePresenceAnnouncement(destHash: Uint8Array): StoredBlob[];
|
|
52
|
+
handlePresenceAnnouncement(destHash: Uint8Array, previousEpochDestHash?: Uint8Array): StoredBlob[];
|
|
53
|
+
/**
|
|
54
|
+
* Decide whether a blob should be forwarded to a closer relay.
|
|
55
|
+
* Returns true when the blob still has remaining hops and a closer relay
|
|
56
|
+
* is available.
|
|
57
|
+
*/
|
|
58
|
+
shouldForward(blob: StoredBlob, closerRelayAvailable: boolean): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Prepare a blob for multi-hop forwarding.
|
|
61
|
+
* Returns a new StoredBlob with decremented hopsRemaining and a fresh id.
|
|
62
|
+
*/
|
|
63
|
+
prepareForward(blob: StoredBlob): StoredBlob;
|
|
64
|
+
}
|
|
65
|
+
export interface StoreAndForwardStats {
|
|
66
|
+
blobCount: number;
|
|
67
|
+
bytesUsed: number;
|
|
68
|
+
oldestBlobAge: number;
|
|
69
|
+
}
|
|
70
|
+
export declare class StoreAndForwardManager {
|
|
71
|
+
private readonly store;
|
|
72
|
+
constructor(store: RelayStore);
|
|
73
|
+
/**
|
|
74
|
+
* Store an encrypted payload destined for an offline peer.
|
|
75
|
+
* Returns the generated blob id, or throws if storage is completely full.
|
|
76
|
+
*/
|
|
77
|
+
storeForDelivery(destHash: Uint8Array, encryptedPayload: Uint8Array, ttlHours?: number): string;
|
|
78
|
+
/**
|
|
79
|
+
* Called when a peer comes online. Returns all stored blobs for its
|
|
80
|
+
* destination hash and removes them from the store.
|
|
81
|
+
*/
|
|
82
|
+
deliverStored(destHash: Uint8Array): StoredBlob[];
|
|
83
|
+
/** Return aggregate stats about the relay store. */
|
|
84
|
+
getStats(): StoreAndForwardStats;
|
|
85
|
+
private computeOldestAge;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/relay/index.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAiD3C,MAAM,WAAW,iBAAiB;IAChC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IAEzC,yCAAyC;IACzC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;IAEvD,wDAAwD;IACxD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkC;IAE5D,6DAA6D;IAC7D,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAgB;IAE/C,OAAO,CAAC,mBAAmB,CAAK;IAChC,OAAO,CAAC,UAAU,CAA+C;gBAErD,OAAO,CAAC,EAAE,iBAAiB;IAOvC,OAAO,CAAC,OAAO;IAMf,OAAO,CAAC,SAAS;IAOjB;;;OAGG;IACH,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO;IAoCpC,8DAA8D;IAC9D,QAAQ,CAAC,QAAQ,EAAE,UAAU,GAAG,UAAU,EAAE;IAY5C,kCAAkC;IAClC,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAkB5B,8DAA8D;IAC9D,kBAAkB,CAAC,QAAQ,EAAE,UAAU,GAAG,IAAI;IAY9C,gEAAgE;IAChE,YAAY,IAAI,MAAM;IActB,wCAAwC;IACxC,kBAAkB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI;IAY7C,uCAAuC;IACvC,iBAAiB,IAAI,IAAI;IASzB,gDAAgD;IAChD,cAAc,IAAI,MAAM;IAIxB,oDAAoD;IACpD,kBAAkB,IAAI,MAAM;IAI5B,8CAA8C;IAC9C,YAAY,IAAI,MAAM;IAMtB;;;;;;;OAOG;IACH,0BAA0B,CAAC,QAAQ,EAAE,UAAU,GAAG,UAAU,EAAE;IAC9D,0BAA0B,CACxB,QAAQ,EAAE,UAAU,EACpB,qBAAqB,CAAC,EAAE,UAAU,GACjC,UAAU,EAAE;IAwBf;;;;OAIG;IACH,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,oBAAoB,EAAE,OAAO,GAAG,OAAO;IAIvE;;;OAGG;IACH,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU;CAW7C;AAMD,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,qBAAa,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAa;gBAEvB,KAAK,EAAE,UAAU;IAI7B;;;OAGG;IACH,gBAAgB,CACd,QAAQ,EAAE,UAAU,EACpB,gBAAgB,EAAE,UAAU,EAC5B,QAAQ,CAAC,EAAE,MAAM,GAChB,MAAM;IAoBT;;;OAGG;IACH,aAAa,CAAC,QAAQ,EAAE,UAAU,GAAG,UAAU,EAAE;IAIjD,oDAAoD;IACpD,QAAQ,IAAI,oBAAoB;IAkBhC,OAAO,CAAC,gBAAgB;CAWzB"}
|