@hashtree/worker 0.1.25 → 0.1.26

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.
Files changed (38) hide show
  1. package/dist/capabilities/blossomTransport.d.ts +0 -2
  2. package/dist/capabilities/blossomTransport.d.ts.map +1 -1
  3. package/dist/capabilities/blossomTransport.js +2 -59
  4. package/dist/capabilities/blossomTransport.js.map +1 -1
  5. package/dist/capabilities/meshRouterStore.d.ts +71 -0
  6. package/dist/capabilities/meshRouterStore.d.ts.map +1 -0
  7. package/dist/capabilities/meshRouterStore.js +316 -0
  8. package/dist/capabilities/meshRouterStore.js.map +1 -0
  9. package/dist/iris/worker.js +32 -83
  10. package/dist/iris/worker.js.map +1 -1
  11. package/dist/p2p/boundedQueue.d.ts +5 -0
  12. package/dist/p2p/boundedQueue.d.ts.map +1 -1
  13. package/dist/p2p/boundedQueue.js +22 -0
  14. package/dist/p2p/boundedQueue.js.map +1 -1
  15. package/dist/p2p/index.d.ts +1 -0
  16. package/dist/p2p/index.d.ts.map +1 -1
  17. package/dist/p2p/index.js +1 -0
  18. package/dist/p2p/index.js.map +1 -1
  19. package/dist/p2p/meshQueryRouter.d.ts +44 -0
  20. package/dist/p2p/meshQueryRouter.d.ts.map +1 -0
  21. package/dist/p2p/meshQueryRouter.js +228 -0
  22. package/dist/p2p/meshQueryRouter.js.map +1 -0
  23. package/dist/p2p/uploadRateLimiter.d.ts +21 -0
  24. package/dist/p2p/uploadRateLimiter.d.ts.map +1 -0
  25. package/dist/p2p/uploadRateLimiter.js +62 -0
  26. package/dist/p2p/uploadRateLimiter.js.map +1 -0
  27. package/dist/p2p/webrtcController.d.ts +3 -5
  28. package/dist/p2p/webrtcController.d.ts.map +1 -1
  29. package/dist/p2p/webrtcController.js +34 -108
  30. package/dist/p2p/webrtcController.js.map +1 -1
  31. package/dist/p2p/webrtcProxy.d.ts +8 -1
  32. package/dist/p2p/webrtcProxy.d.ts.map +1 -1
  33. package/dist/p2p/webrtcProxy.js +64 -8
  34. package/dist/p2p/webrtcProxy.js.map +1 -1
  35. package/dist/worker.d.ts.map +1 -1
  36. package/dist/worker.js +38 -27
  37. package/dist/worker.js.map +1 -1
  38. package/package.json +1 -1
@@ -0,0 +1,228 @@
1
+ import { MAX_HTL, createRequest, decrementHTL, encodeRequest, hashToKey, shouldForward, verifyHash, } from '@hashtree/nostr';
2
+ class SlidingWindowRateLimiter {
3
+ maxEvents;
4
+ windowMs;
5
+ eventsByPeer = new Map();
6
+ constructor(maxEvents, windowMs) {
7
+ this.maxEvents = maxEvents;
8
+ this.windowMs = windowMs;
9
+ }
10
+ allow(peerId) {
11
+ const now = Date.now();
12
+ const events = this.eventsByPeer.get(peerId) ?? [];
13
+ let firstActiveIndex = 0;
14
+ while (firstActiveIndex < events.length && now - events[firstActiveIndex] >= this.windowMs) {
15
+ firstActiveIndex += 1;
16
+ }
17
+ if (firstActiveIndex > 0) {
18
+ events.splice(0, firstActiveIndex);
19
+ }
20
+ if (events.length >= this.maxEvents) {
21
+ this.eventsByPeer.set(peerId, events);
22
+ return false;
23
+ }
24
+ events.push(now);
25
+ this.eventsByPeer.set(peerId, events);
26
+ return true;
27
+ }
28
+ resetPeer(peerId) {
29
+ this.eventsByPeer.delete(peerId);
30
+ }
31
+ clear() {
32
+ this.eventsByPeer.clear();
33
+ }
34
+ }
35
+ export class MeshQueryRouter {
36
+ localStore;
37
+ requestTimeoutMs;
38
+ rateLimiter;
39
+ peers = new Map();
40
+ hashesByRequester = new Map();
41
+ inFlightByHash = new Map();
42
+ pendingUpstreamFetches = new Map();
43
+ upstreamFetch;
44
+ constructor(config) {
45
+ this.localStore = config.localStore;
46
+ this.requestTimeoutMs = config.requestTimeoutMs;
47
+ this.upstreamFetch = config.upstreamFetch;
48
+ this.rateLimiter = new SlidingWindowRateLimiter(config.maxForwardsPerPeerWindow ?? 64, config.forwardRateLimitWindowMs ?? 1000);
49
+ }
50
+ registerPeer(peer) {
51
+ this.peers.set(peer.peerId, peer);
52
+ }
53
+ removePeer(peerId) {
54
+ const hashes = this.hashesByRequester.get(peerId);
55
+ if (hashes) {
56
+ for (const hashKey of Array.from(hashes)) {
57
+ const inFlight = this.inFlightByHash.get(hashKey);
58
+ if (!inFlight)
59
+ continue;
60
+ inFlight.requesterIds.delete(peerId);
61
+ if (inFlight.requesterIds.size === 0) {
62
+ this.clearQuery(hashKey);
63
+ }
64
+ }
65
+ }
66
+ this.hashesByRequester.delete(peerId);
67
+ this.peers.delete(peerId);
68
+ this.rateLimiter.resetPeer(peerId);
69
+ }
70
+ setUpstreamFetch(upstreamFetch) {
71
+ this.upstreamFetch = upstreamFetch;
72
+ }
73
+ hasInFlight(hashKey) {
74
+ return this.inFlightByHash.has(hashKey);
75
+ }
76
+ stop() {
77
+ for (const hashKey of Array.from(this.inFlightByHash.keys())) {
78
+ this.clearQuery(hashKey);
79
+ }
80
+ this.hashesByRequester.clear();
81
+ this.pendingUpstreamFetches.clear();
82
+ this.rateLimiter.clear();
83
+ }
84
+ async handleRequest(requesterId, req) {
85
+ const hashKey = hashToKey(req.h);
86
+ const requester = this.peers.get(requesterId);
87
+ if (!requester) {
88
+ return;
89
+ }
90
+ const local = await this.localStore.get(req.h);
91
+ if (local) {
92
+ await requester.sendResponse(req.h, local);
93
+ return;
94
+ }
95
+ const begin = this.beginQuery(hashKey, requesterId);
96
+ if (begin === 'suppressed') {
97
+ requester.onForwardedSuppressed?.();
98
+ return;
99
+ }
100
+ if (begin === 'rate_limited') {
101
+ return;
102
+ }
103
+ const upstreamActive = this.startUpstreamFetch(hashKey, req.h);
104
+ const forwarded = this.forwardRequest(requesterId, req.h, req.htl ?? MAX_HTL);
105
+ if (forwarded > 0) {
106
+ requester.onForwardedRequest?.();
107
+ return;
108
+ }
109
+ if (!upstreamActive) {
110
+ this.clearQuery(hashKey);
111
+ }
112
+ }
113
+ async resolve(hash, data) {
114
+ const hashKey = hashToKey(hash);
115
+ const requesterIds = this.clearQuery(hashKey);
116
+ if (requesterIds.length === 0) {
117
+ return;
118
+ }
119
+ await this.localStore.put(hash, data).catch(() => false);
120
+ for (const requesterId of requesterIds) {
121
+ const requester = this.peers.get(requesterId);
122
+ if (!requester) {
123
+ continue;
124
+ }
125
+ requester.onForwardedResolved?.();
126
+ await requester.sendResponse(hash, data);
127
+ }
128
+ }
129
+ beginQuery(hashKey, requesterId) {
130
+ const existing = this.inFlightByHash.get(hashKey);
131
+ if (existing) {
132
+ this.trackRequester(hashKey, existing.requesterIds, requesterId);
133
+ return 'suppressed';
134
+ }
135
+ if (!this.rateLimiter.allow(requesterId)) {
136
+ return 'rate_limited';
137
+ }
138
+ const requesterIds = new Set();
139
+ this.trackRequester(hashKey, requesterIds, requesterId);
140
+ const timeoutId = setTimeout(() => {
141
+ this.clearQuery(hashKey);
142
+ }, this.requestTimeoutMs);
143
+ this.inFlightByHash.set(hashKey, { requesterIds, timeoutId });
144
+ return 'new';
145
+ }
146
+ clearQuery(hashKey) {
147
+ const inFlight = this.inFlightByHash.get(hashKey);
148
+ if (!inFlight) {
149
+ return [];
150
+ }
151
+ clearTimeout(inFlight.timeoutId);
152
+ this.inFlightByHash.delete(hashKey);
153
+ const requesterIds = Array.from(inFlight.requesterIds);
154
+ for (const requesterId of requesterIds) {
155
+ const hashes = this.hashesByRequester.get(requesterId);
156
+ if (!hashes)
157
+ continue;
158
+ hashes.delete(hashKey);
159
+ if (hashes.size === 0) {
160
+ this.hashesByRequester.delete(requesterId);
161
+ }
162
+ }
163
+ return requesterIds;
164
+ }
165
+ trackRequester(hashKey, requesterIds, requesterId) {
166
+ requesterIds.add(requesterId);
167
+ let hashes = this.hashesByRequester.get(requesterId);
168
+ if (!hashes) {
169
+ hashes = new Set();
170
+ this.hashesByRequester.set(requesterId, hashes);
171
+ }
172
+ hashes.add(hashKey);
173
+ }
174
+ forwardRequest(requesterId, hash, htl) {
175
+ if (!shouldForward(htl)) {
176
+ return 0;
177
+ }
178
+ const requester = this.peers.get(requesterId);
179
+ if (!requester) {
180
+ return 0;
181
+ }
182
+ const nextHtl = decrementHTL(htl, requester.getHtlConfig());
183
+ let forwarded = 0;
184
+ for (const peer of this.peers.values()) {
185
+ if (peer.peerId === requesterId || !peer.canSend()) {
186
+ continue;
187
+ }
188
+ if (peer.sendRequest(hash, nextHtl)) {
189
+ forwarded += 1;
190
+ }
191
+ }
192
+ return forwarded;
193
+ }
194
+ startUpstreamFetch(hashKey, hash) {
195
+ if (!this.upstreamFetch) {
196
+ return false;
197
+ }
198
+ const existing = this.pendingUpstreamFetches.get(hashKey);
199
+ if (existing) {
200
+ return true;
201
+ }
202
+ let pending;
203
+ pending = this.upstreamFetch(hash)
204
+ .then(async (data) => {
205
+ if (!data) {
206
+ return null;
207
+ }
208
+ const valid = await verifyHash(data, hash);
209
+ if (!valid) {
210
+ return null;
211
+ }
212
+ await this.resolve(hash, data);
213
+ return data;
214
+ })
215
+ .catch(() => null)
216
+ .finally(() => {
217
+ if (this.pendingUpstreamFetches.get(hashKey) === pending) {
218
+ this.pendingUpstreamFetches.delete(hashKey);
219
+ }
220
+ });
221
+ this.pendingUpstreamFetches.set(hashKey, pending);
222
+ return true;
223
+ }
224
+ }
225
+ export function encodeForwardRequest(hash, htl) {
226
+ return new Uint8Array(encodeRequest(createRequest(hash, htl)));
227
+ }
228
+ //# sourceMappingURL=meshQueryRouter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meshQueryRouter.js","sourceRoot":"","sources":["../../src/p2p/meshQueryRouter.ts"],"names":[],"mappings":"AACA,OAAO,EACL,OAAO,EACP,aAAa,EACb,YAAY,EACZ,aAAa,EACb,SAAS,EACT,aAAa,EACb,UAAU,GAGX,MAAM,iBAAiB,CAAC;AA4BzB,MAAM,wBAAwB;IACX,SAAS,CAAS;IAClB,QAAQ,CAAS;IACjB,YAAY,GAAG,IAAI,GAAG,EAAoB,CAAC;IAE5D,YAAY,SAAiB,EAAE,QAAgB;QAC7C,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,MAAc;QAClB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACnD,IAAI,gBAAgB,GAAG,CAAC,CAAC;QACzB,OAAO,gBAAgB,GAAG,MAAM,CAAC,MAAM,IAAI,GAAG,GAAG,MAAM,CAAC,gBAAgB,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC3F,gBAAgB,IAAI,CAAC,CAAC;QACxB,CAAC;QACD,IAAI,gBAAgB,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC;QACrC,CAAC;QAED,IAAI,MAAM,CAAC,MAAM,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACpC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACtC,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjB,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACtC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,SAAS,CAAC,MAAc;QACtB,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC;IAED,KAAK;QACH,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;IAC5B,CAAC;CACF;AAED,MAAM,OAAO,eAAe;IACT,UAAU,CAAQ;IAClB,gBAAgB,CAAS;IACzB,WAAW,CAA2B;IACtC,KAAK,GAAG,IAAI,GAAG,EAA+B,CAAC;IAC/C,iBAAiB,GAAG,IAAI,GAAG,EAAuB,CAAC;IACnD,cAAc,GAAG,IAAI,GAAG,EAAyB,CAAC;IAClD,sBAAsB,GAAG,IAAI,GAAG,EAAsC,CAAC;IAChF,aAAa,CAAoD;IAEzE,YAAY,MAA6B;QACvC,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;QACpC,IAAI,CAAC,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,CAAC;QAChD,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC;QAC1C,IAAI,CAAC,WAAW,GAAG,IAAI,wBAAwB,CAC7C,MAAM,CAAC,wBAAwB,IAAI,EAAE,EACrC,MAAM,CAAC,wBAAwB,IAAI,IAAI,CACxC,CAAC;IACJ,CAAC;IAED,YAAY,CAAC,IAAyB;QACpC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACpC,CAAC;IAED,UAAU,CAAC,MAAc;QACvB,MAAM,MAAM,GAAG,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAClD,IAAI,MAAM,EAAE,CAAC;YACX,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;gBACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBAClD,IAAI,CAAC,QAAQ;oBAAE,SAAS;gBACxB,QAAQ,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBACrC,IAAI,QAAQ,CAAC,YAAY,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;oBACrC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;gBAC3B,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACtC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC1B,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC;IAED,gBAAgB,CAAC,aAAgE;QAC/E,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;IACrC,CAAC;IAED,WAAW,CAAC,OAAe;QACzB,OAAO,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;IAED,IAAI;QACF,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YAC7D,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAC3B,CAAC;QACD,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,CAAC;QAC/B,IAAI,CAAC,sBAAsB,CAAC,KAAK,EAAE,CAAC;QACpC,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,WAAmB,EAAE,GAAgB;QACvD,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACjC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAC9C,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO;QACT,CAAC;QAED,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC/C,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;YAC3C,OAAO;QACT,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QACpD,IAAI,KAAK,KAAK,YAAY,EAAE,CAAC;YAC3B,SAAS,CAAC,qBAAqB,EAAE,EAAE,CAAC;YACpC,OAAO;QACT,CAAC;QACD,IAAI,KAAK,KAAK,cAAc,EAAE,CAAC;YAC7B,OAAO;QACT,CAAC;QAED,MAAM,cAAc,GAAG,IAAI,CAAC,kBAAkB,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;QAC/D,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,IAAI,OAAO,CAAC,CAAC;QAC9E,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;YAClB,SAAS,CAAC,kBAAkB,EAAE,EAAE,CAAC;YACjC,OAAO;QACT,CAAC;QAED,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,IAAgB,EAAE,IAAgB;QAC9C,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAChC,MAAM,YAAY,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAC9C,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9B,OAAO;QACT,CAAC;QAED,MAAM,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;QACzD,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;YACvC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YAC9C,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,SAAS;YACX,CAAC;YACD,SAAS,CAAC,mBAAmB,EAAE,EAAE,CAAC;YAClC,MAAM,SAAS,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IAEO,UAAU,CAAC,OAAe,EAAE,WAAmB;QACrD,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAClD,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,QAAQ,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;YACjE,OAAO,YAAY,CAAC;QACtB,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;YACzC,OAAO,cAAc,CAAC;QACxB,CAAC;QAED,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAC;QACvC,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,YAAY,EAAE,WAAW,CAAC,CAAC;QACxD,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;YAChC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAC3B,CAAC,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAE1B,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC,CAAC;QAC9D,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,UAAU,CAAC,OAAe;QAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAClD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,YAAY,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QACjC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAEpC,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QACvD,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;YACvC,MAAM,MAAM,GAAG,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YACvD,IAAI,CAAC,MAAM;gBAAE,SAAS;YACtB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YACvB,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;gBACtB,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC;QAED,OAAO,YAAY,CAAC;IACtB,CAAC;IAEO,cAAc,CAAC,OAAe,EAAE,YAAyB,EAAE,WAAmB;QACpF,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAC9B,IAAI,MAAM,GAAG,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACrD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;YAC3B,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QAClD,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACtB,CAAC;IAEO,cAAc,CAAC,WAAmB,EAAE,IAAgB,EAAE,GAAW;QACvE,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,OAAO,CAAC,CAAC;QACX,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAC9C,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO,CAAC,CAAC;QACX,CAAC;QAED,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,EAAE,SAAS,CAAC,YAAY,EAAE,CAAC,CAAC;QAC5D,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YACvC,IAAI,IAAI,CAAC,MAAM,KAAK,WAAW,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;gBACnD,SAAS;YACX,CAAC;YAED,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC;gBACpC,SAAS,IAAI,CAAC,CAAC;YACjB,CAAC;QACH,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAEO,kBAAkB,CAAC,OAAe,EAAE,IAAgB;QAC1D,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC1D,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,OAAmC,CAAC;QACxC,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC;aAC/B,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;YACnB,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,OAAO,IAAI,CAAC;YACd,CAAC;YAED,MAAM,KAAK,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAC3C,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO,IAAI,CAAC;YACd,CAAC;YAED,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAC/B,OAAO,IAAI,CAAC;QACd,CAAC,CAAC;aACD,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;aACjB,OAAO,CAAC,GAAG,EAAE;YACZ,IAAI,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,OAAO,EAAE,CAAC;gBACzD,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAC9C,CAAC;QACH,CAAC,CAAC,CAAC;QAEL,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAClD,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAgB,EAAE,GAAW;IAChE,OAAO,IAAI,UAAU,CAAC,aAAa,CAAC,aAAa,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;AACjE,CAAC"}
@@ -0,0 +1,21 @@
1
+ type UploadRateLimiterConfig = {
2
+ bytesPerSecond?: number | null;
3
+ now?: () => number;
4
+ };
5
+ type UploadReservation = {
6
+ allowed: boolean;
7
+ delayMs: number;
8
+ };
9
+ export declare class UploadRateLimiter {
10
+ private bytesPerSecond;
11
+ private availableBytes;
12
+ private lastRefillMs;
13
+ private readonly now;
14
+ constructor(config?: UploadRateLimiterConfig);
15
+ setBytesPerSecond(bytesPerSecond?: number | null): void;
16
+ getBytesPerSecond(): number | null;
17
+ reserve(byteLength: number): UploadReservation;
18
+ private refill;
19
+ }
20
+ export {};
21
+ //# sourceMappingURL=uploadRateLimiter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uploadRateLimiter.d.ts","sourceRoot":"","sources":["../../src/p2p/uploadRateLimiter.ts"],"names":[],"mappings":"AAAA,KAAK,uBAAuB,GAAG;IAC7B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB,CAAC;AAEF,KAAK,iBAAiB,GAAG;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AASF,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;gBAEvB,MAAM,GAAE,uBAA4B;IAOhD,iBAAiB,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAUvD,iBAAiB,IAAI,MAAM,GAAG,IAAI;IAIlC,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,iBAAiB;IAyB9C,OAAO,CAAC,MAAM;CAef"}
@@ -0,0 +1,62 @@
1
+ function normalizeBytesPerSecond(value) {
2
+ if (!Number.isFinite(value) || !value || value <= 0) {
3
+ return null;
4
+ }
5
+ return Math.floor(value);
6
+ }
7
+ export class UploadRateLimiter {
8
+ bytesPerSecond;
9
+ availableBytes;
10
+ lastRefillMs;
11
+ now;
12
+ constructor(config = {}) {
13
+ this.now = config.now ?? (() => performance.now());
14
+ this.bytesPerSecond = normalizeBytesPerSecond(config.bytesPerSecond);
15
+ this.availableBytes = this.bytesPerSecond ?? Number.POSITIVE_INFINITY;
16
+ this.lastRefillMs = this.now();
17
+ }
18
+ setBytesPerSecond(bytesPerSecond) {
19
+ const nowMs = this.now();
20
+ this.refill(nowMs);
21
+ this.bytesPerSecond = normalizeBytesPerSecond(bytesPerSecond);
22
+ this.availableBytes = this.bytesPerSecond
23
+ ? Math.min(this.availableBytes, this.bytesPerSecond)
24
+ : Number.POSITIVE_INFINITY;
25
+ this.lastRefillMs = nowMs;
26
+ }
27
+ getBytesPerSecond() {
28
+ return this.bytesPerSecond;
29
+ }
30
+ reserve(byteLength) {
31
+ if (byteLength <= 0) {
32
+ return { allowed: true, delayMs: 0 };
33
+ }
34
+ const limit = this.bytesPerSecond;
35
+ if (!limit) {
36
+ return { allowed: true, delayMs: 0 };
37
+ }
38
+ const nowMs = this.now();
39
+ this.refill(nowMs);
40
+ if (this.availableBytes >= byteLength) {
41
+ this.availableBytes = Math.max(0, this.availableBytes - byteLength);
42
+ return { allowed: true, delayMs: 0 };
43
+ }
44
+ const missingBytes = byteLength - this.availableBytes;
45
+ return {
46
+ allowed: false,
47
+ delayMs: Math.max(4, Math.ceil((missingBytes / limit) * 1000)),
48
+ };
49
+ }
50
+ refill(nowMs) {
51
+ const limit = this.bytesPerSecond;
52
+ if (!limit) {
53
+ this.availableBytes = Number.POSITIVE_INFINITY;
54
+ this.lastRefillMs = nowMs;
55
+ return;
56
+ }
57
+ const elapsedMs = Math.max(0, nowMs - this.lastRefillMs);
58
+ this.lastRefillMs = nowMs;
59
+ this.availableBytes = Math.min(limit, this.availableBytes + (elapsedMs * limit) / 1000);
60
+ }
61
+ }
62
+ //# sourceMappingURL=uploadRateLimiter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uploadRateLimiter.js","sourceRoot":"","sources":["../../src/p2p/uploadRateLimiter.ts"],"names":[],"mappings":"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"}
@@ -22,6 +22,7 @@ export interface WebRTCControllerConfig {
22
22
  localStore: Store;
23
23
  sendCommand: (cmd: WebRTCCommand) => void;
24
24
  sendSignaling: (msg: SignalingMessage, recipientPubkey?: string) => Promise<void>;
25
+ upstreamFetch?: (hash: Uint8Array) => Promise<Uint8Array | null>;
25
26
  getFollows?: () => Set<string>;
26
27
  requestTimeout?: number;
27
28
  forwardRateLimit?: {
@@ -44,7 +45,7 @@ export declare class WebRTCController {
44
45
  private requestTimeout;
45
46
  private debug;
46
47
  private recentRequests;
47
- private forwardingMachine;
48
+ private readonly meshRouter;
48
49
  private readonly peerSelector;
49
50
  private routing;
50
51
  private poolConfig;
@@ -117,10 +118,7 @@ export declare class WebRTCController {
117
118
  private processRequest;
118
119
  private handleResponse;
119
120
  private sendResponse;
120
- private getForwardTargets;
121
- private forwardRequest;
122
- private pushToRequesters;
123
- private clearRequesterMarkers;
121
+ private sendRequestToPeer;
124
122
  /**
125
123
  * Request data from peers
126
124
  */
@@ -1 +1 @@
1
- {"version":3,"file":"webrtcController.d.ts","sourceRoot":"","sources":["../../src/p2p/webrtcController.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"webrtcController.d.ts","sourceRoot":"","sources":["../../src/p2p/webrtcController.ts"],"names":[],"mappings":"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"}
@@ -15,9 +15,9 @@
15
15
  * - Data channel I/O
16
16
  */
17
17
  import { fromHex, sha256, toHex } from '@hashtree/core';
18
- import { MAX_HTL, MSG_TYPE_REQUEST, MSG_TYPE_RESPONSE, FRAGMENT_SIZE, PeerId, encodeRequest, encodeResponse, parseMessage, createRequest, createResponse, createFragmentResponse, hashToKey, verifyHash, generatePeerHTLConfig, decrementHTL, shouldForward, PeerSelector, buildHedgedWavePlan, normalizeDispatchConfig, syncSelectorPeers, } from '@hashtree/nostr';
18
+ import { MAX_HTL, MSG_TYPE_REQUEST, MSG_TYPE_RESPONSE, FRAGMENT_SIZE, PeerId, encodeRequest, encodeResponse, parseMessage, createRequest, createResponse, createFragmentResponse, hashToKey, verifyHash, generatePeerHTLConfig, PeerSelector, buildHedgedWavePlan, normalizeDispatchConfig, syncSelectorPeers, } from '@hashtree/nostr';
19
19
  import { LRUCache } from './lruCache.js';
20
- import { QueryForwardingMachine } from './queryForwardingMachine.js';
20
+ import { MeshQueryRouter, encodeForwardRequest } from './meshQueryRouter.js';
21
21
  const PEER_METADATA_POINTER_SLOT_KEY = 'hashtree-webrtc/peer-metadata/latest/v1';
22
22
  const DEFAULT_REQUEST_DISPATCH = {
23
23
  initialFanout: 2,
@@ -39,7 +39,7 @@ export class WebRTCController {
39
39
  requestTimeout;
40
40
  debug;
41
41
  recentRequests = new LRUCache(1000);
42
- forwardingMachine;
42
+ meshRouter;
43
43
  peerSelector;
44
44
  routing;
45
45
  // Pool configuration - reasonable defaults, settings sync will override
@@ -64,13 +64,12 @@ export class WebRTCController {
64
64
  };
65
65
  this.peerSelector = PeerSelector.withStrategy(this.routing.selectionStrategy);
66
66
  this.peerSelector.setFairness(this.routing.fairnessEnabled);
67
- this.forwardingMachine = new QueryForwardingMachine({
67
+ this.meshRouter = new MeshQueryRouter({
68
+ localStore: this.localStore,
68
69
  requestTimeoutMs: this.requestTimeout,
70
+ upstreamFetch: config.upstreamFetch,
69
71
  maxForwardsPerPeerWindow: config.forwardRateLimit?.maxForwardsPerPeerWindow,
70
72
  forwardRateLimitWindowMs: config.forwardRateLimit?.windowMs,
71
- onForwardTimeout: ({ hashKey, requesterIds }) => {
72
- this.clearRequesterMarkers(hashKey, requesterIds);
73
- },
74
73
  });
75
74
  // Default classifier: check if pubkey is in follows
76
75
  const getFollows = config.getFollows ?? (() => new Set());
@@ -102,7 +101,7 @@ export class WebRTCController {
102
101
  for (const peerId of this.peers.keys()) {
103
102
  this.closePeer(peerId);
104
103
  }
105
- this.forwardingMachine.stop();
104
+ this.meshRouter.stop();
106
105
  }
107
106
  // ============================================================================
108
107
  // Signaling
@@ -302,7 +301,6 @@ export class WebRTCController {
302
301
  answerCreated: false,
303
302
  htlConfig: generatePeerHTLConfig(),
304
303
  pendingRequests: new Map(),
305
- theirRequests: new LRUCache(200),
306
304
  stats: {
307
305
  requestsSent: 0,
308
306
  requestsReceived: 0,
@@ -320,6 +318,22 @@ export class WebRTCController {
320
318
  };
321
319
  this.peers.set(peerId, peer);
322
320
  this.peerSelector.addPeer(peerId);
321
+ this.meshRouter.registerPeer({
322
+ peerId,
323
+ canSend: () => peer.dataChannelReady,
324
+ getHtlConfig: () => peer.htlConfig,
325
+ sendRequest: (hash, htl) => this.sendRequestToPeer(peer, hash, htl),
326
+ sendResponse: async (hash, data) => this.sendResponse(peer, hash, data),
327
+ onForwardedRequest: () => {
328
+ peer.stats.forwardedRequests++;
329
+ },
330
+ onForwardedResolved: () => {
331
+ peer.stats.forwardedResolved++;
332
+ },
333
+ onForwardedSuppressed: () => {
334
+ peer.stats.forwardedSuppressed++;
335
+ },
336
+ });
323
337
  this.sendCommand({ type: 'rtc:createPeer', peerId, pubkey });
324
338
  return peer;
325
339
  }
@@ -341,7 +355,7 @@ export class WebRTCController {
341
355
  this.peers.delete(peerId);
342
356
  this.pendingRemoteCandidates.delete(peerId);
343
357
  this.peerSelector.removePeer(peerId);
344
- this.forwardingMachine.removePeer(peerId);
358
+ this.meshRouter.removePeer(peerId);
345
359
  this.log(`Closed peer: ${peerId.slice(0, 20)}`);
346
360
  }
347
361
  // ============================================================================
@@ -694,53 +708,14 @@ export class WebRTCController {
694
708
  await this.processRequest(peer, req);
695
709
  }
696
710
  async processRequest(peer, req) {
697
- const hashKey = hashToKey(req.h);
698
- // Try to get from local store
699
- const data = await this.localStore.get(req.h);
700
- if (data) {
701
- // Send response
702
- await this.sendResponse(peer, req.h, data);
703
- }
704
- else {
705
- // Track their request for later push
706
- peer.theirRequests.set(hashKey, {
707
- hash: req.h,
708
- requestedAt: Date.now(),
709
- });
710
- // Forward if HTL allows
711
- const htl = req.htl ?? MAX_HTL;
712
- if (shouldForward(htl)) {
713
- const newHtl = decrementHTL(htl, peer.htlConfig);
714
- const decision = this.forwardingMachine.beginForward(hashKey, peer.peerId, this.getForwardTargets(peer.peerId));
715
- if (decision.kind === 'suppressed') {
716
- peer.stats.forwardedSuppressed++;
717
- return;
718
- }
719
- if (decision.kind === 'rate_limited') {
720
- peer.theirRequests.delete(hashKey);
721
- this.log(`Forward rate-limited for ${peer.peerId.slice(0, 20)} hash ${hashKey.slice(0, 16)}`);
722
- return;
723
- }
724
- if (decision.kind === 'no_targets') {
725
- peer.theirRequests.delete(hashKey);
726
- return;
727
- }
728
- const forwarded = this.forwardRequest(req.h, decision.targets, newHtl);
729
- if (forwarded <= 0) {
730
- const requesterIds = this.forwardingMachine.cancelForward(hashKey);
731
- this.clearRequesterMarkers(hashKey, requesterIds);
732
- return;
733
- }
734
- peer.stats.forwardedRequests++;
735
- }
736
- }
711
+ await this.meshRouter.handleRequest(peer.peerId, req);
737
712
  }
738
713
  async handleResponse(peer, res) {
739
714
  peer.stats.responsesReceived++;
740
715
  const hashKey = hashToKey(res.h);
741
716
  const pending = peer.pendingRequests.get(hashKey);
742
717
  if (!pending) {
743
- const hasRequesters = Array.from(this.peers.values()).some(p => p.theirRequests.has(hashKey));
718
+ const hasRequesters = this.meshRouter.hasInFlight(hashKey);
744
719
  // Late response: cache if we requested this hash recently
745
720
  const requestedAt = this.recentRequests.get(hashKey);
746
721
  if (!requestedAt && !hasRequesters)
@@ -757,8 +732,7 @@ export class WebRTCController {
757
732
  this.recentRequests.delete(hashKey);
758
733
  }
759
734
  if (hasRequesters) {
760
- await this.pushToRequesters(res.h, res.d, peer.peerId);
761
- this.forwardingMachine.resolveForward(hashKey);
735
+ await this.meshRouter.resolve(res.h, res.d);
762
736
  }
763
737
  }
764
738
  return;
@@ -773,9 +747,7 @@ export class WebRTCController {
773
747
  await this.localStore.put(res.h, res.d);
774
748
  this.peerSelector.recordSuccess(peer.peerId, elapsedMs, res.d.length);
775
749
  pending.resolve(res.d);
776
- // Push to peers who requested this
777
- await this.pushToRequesters(res.h, res.d, peer.peerId);
778
- this.forwardingMachine.resolveForward(hashKey);
750
+ await this.meshRouter.resolve(res.h, res.d);
779
751
  }
780
752
  else {
781
753
  this.log(`Hash mismatch from ${peer.peerId}`);
@@ -805,59 +777,13 @@ export class WebRTCController {
805
777
  this.sendDataToPeer(peer, encoded);
806
778
  }
807
779
  }
808
- getForwardTargets(excludePeerId) {
809
- const targets = [];
810
- for (const [peerId, peer] of this.peers) {
811
- if (peerId === excludePeerId)
812
- continue;
813
- if (!peer.dataChannelReady)
814
- continue;
815
- targets.push(peerId);
816
- }
817
- return targets;
818
- }
819
- forwardRequest(hash, targetPeerIds, htl) {
820
- const hashKey = hashToKey(hash);
821
- let forwarded = 0;
822
- for (const peerId of targetPeerIds) {
823
- const peer = this.peers.get(peerId);
824
- if (!peer || !peer.dataChannelReady)
825
- continue;
826
- // Set up pending request so we can process the response
827
- const timeout = setTimeout(() => {
828
- peer.pendingRequests.delete(hashKey);
829
- }, this.requestTimeout);
830
- peer.pendingRequests.set(hashKey, {
831
- hash,
832
- resolve: () => {
833
- // Response will be pushed to original requester via pushToRequesters
834
- },
835
- timeout,
836
- });
837
- const req = createRequest(hash, htl);
838
- const encoded = new Uint8Array(encodeRequest(req));
839
- this.sendDataToPeer(peer, encoded);
840
- forwarded++;
841
- }
842
- return forwarded;
843
- }
844
- async pushToRequesters(hash, data, excludePeerId) {
845
- const hashKey = hashToKey(hash);
846
- for (const [peerId, peer] of this.peers) {
847
- if (peerId === excludePeerId)
848
- continue;
849
- const theirReq = peer.theirRequests.get(hashKey);
850
- if (theirReq) {
851
- peer.theirRequests.delete(hashKey);
852
- peer.stats.forwardedResolved++;
853
- await this.sendResponse(peer, hash, data);
854
- }
855
- }
856
- }
857
- clearRequesterMarkers(hashKey, requesterIds) {
858
- for (const requesterId of requesterIds) {
859
- this.peers.get(requesterId)?.theirRequests.delete(hashKey);
780
+ sendRequestToPeer(peer, hash, htl) {
781
+ if (!peer.dataChannelReady) {
782
+ return false;
860
783
  }
784
+ const encoded = encodeForwardRequest(hash, htl);
785
+ this.sendDataToPeer(peer, encoded);
786
+ return true;
861
787
  }
862
788
  // ============================================================================
863
789
  // Public API