wireweave 0.3.22 → 0.3.25
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 +1 -1
- package/src/relay-pool.js +20 -3
- package/src/wireweave.js +13 -0
package/package.json
CHANGED
package/src/relay-pool.js
CHANGED
|
@@ -12,6 +12,9 @@ const DEFAULT_RELAYS = [
|
|
|
12
12
|
];
|
|
13
13
|
|
|
14
14
|
const SEEN_MAX = 10000;
|
|
15
|
+
const PENDING_MAX = 500;
|
|
16
|
+
const PENDING_TTL_MS = 120000;
|
|
17
|
+
const jitter = (ms) => Math.round(ms * (0.75 + Math.random() * 0.5));
|
|
15
18
|
|
|
16
19
|
const lruTouch = (map, key) => {
|
|
17
20
|
if (map.has(key)) { map.delete(key); map.set(key, 1); return false; }
|
|
@@ -36,16 +39,22 @@ export class RelayPool extends EventTarget {
|
|
|
36
39
|
this.subs = new Map();
|
|
37
40
|
this.pending = [];
|
|
38
41
|
this.seen = new Map();
|
|
42
|
+
this._reconnectTimers = new Map();
|
|
43
|
+
this._closed = false;
|
|
39
44
|
this.verifyEvent = verifyEvent;
|
|
40
45
|
this.WS = WebSocketImpl || (typeof WebSocket !== 'undefined' ? WebSocket : null);
|
|
41
46
|
if (!this.WS) throw new Error('No WebSocket implementation available');
|
|
42
47
|
}
|
|
43
48
|
|
|
44
49
|
connect() {
|
|
50
|
+
this._closed = false;
|
|
45
51
|
for (const url of this.urls) this._open(url);
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
disconnect() {
|
|
55
|
+
this._closed = true;
|
|
56
|
+
for (const [, t] of this._reconnectTimers) clearTimeout(t);
|
|
57
|
+
this._reconnectTimers.clear();
|
|
49
58
|
for (const [, r] of this.relays) {
|
|
50
59
|
if (r.ws) {
|
|
51
60
|
r.ws.onclose = null; r.ws.onerror = null; r.ws.onopen = null; r.ws.onmessage = null;
|
|
@@ -58,6 +67,8 @@ export class RelayPool extends EventTarget {
|
|
|
58
67
|
}
|
|
59
68
|
|
|
60
69
|
_open(url) {
|
|
70
|
+
if (this._closed) return;
|
|
71
|
+
this._reconnectTimers.delete(url);
|
|
61
72
|
const existing = this.relays.get(url);
|
|
62
73
|
if (existing?.ws && (existing.ws.readyState === 0 || existing.ws.readyState === 1)) return;
|
|
63
74
|
const relay = existing || { ws: null, status: 'connecting', subIds: new Set(), latencyMs: null, failCount: 0, reconnectDelay: 1000, _reqSentAt: null, _openedAt: null };
|
|
@@ -94,7 +105,9 @@ export class RelayPool extends EventTarget {
|
|
|
94
105
|
if (sustained) { relay.failCount = 0; relay.reconnectDelay = 1000; }
|
|
95
106
|
else { relay.failCount++; relay.reconnectDelay = Math.min(relay.reconnectDelay * 2, 30000); }
|
|
96
107
|
relay._openedAt = null;
|
|
97
|
-
|
|
108
|
+
if (this._closed) return;
|
|
109
|
+
const t = setTimeout(() => this._open(url), jitter(relay.reconnectDelay));
|
|
110
|
+
this._reconnectTimers.set(url, t);
|
|
98
111
|
};
|
|
99
112
|
}
|
|
100
113
|
|
|
@@ -156,13 +169,17 @@ export class RelayPool extends EventTarget {
|
|
|
156
169
|
sent = true;
|
|
157
170
|
}
|
|
158
171
|
}
|
|
159
|
-
if (!sent)
|
|
172
|
+
if (!sent) {
|
|
173
|
+
this.pending.push({ event, ts: Date.now() });
|
|
174
|
+
if (this.pending.length > PENDING_MAX) this.pending.splice(0, this.pending.length - PENDING_MAX);
|
|
175
|
+
}
|
|
160
176
|
return sent;
|
|
161
177
|
}
|
|
162
178
|
|
|
163
179
|
_drainPending() {
|
|
180
|
+
const cutoff = Date.now() - PENDING_TTL_MS;
|
|
164
181
|
const pending = this.pending.splice(0);
|
|
165
|
-
for (const
|
|
182
|
+
for (const p of pending) { if (p.ts >= cutoff) this.publish(p.event); }
|
|
166
183
|
}
|
|
167
184
|
|
|
168
185
|
isConnected() {
|
package/src/wireweave.js
CHANGED
|
@@ -12,6 +12,7 @@ import { createSettings } from './settings.js';
|
|
|
12
12
|
import { createMedia } from './media.js';
|
|
13
13
|
import { createPages } from './pages.js';
|
|
14
14
|
import { createDM } from './dm.js';
|
|
15
|
+
import { createDataSession } from './data.js';
|
|
15
16
|
import { register } from './debug.js';
|
|
16
17
|
|
|
17
18
|
export const createWireweave = ({
|
|
@@ -86,12 +87,24 @@ export const createWireweave = ({
|
|
|
86
87
|
return dm;
|
|
87
88
|
};
|
|
88
89
|
|
|
90
|
+
// DataSession is lazy for the same reason as DM: requires xstate and FSM.
|
|
91
|
+
// onSwitch accumulates subscriptions across all visited servers (idempotent
|
|
92
|
+
// Map pattern) — no unsubscribe on server switch by design so offline data
|
|
93
|
+
// from prior servers remains cached.
|
|
94
|
+
let data = null;
|
|
95
|
+
const ensureData = ({ room = '', displayName = 'Guest', namespace = '' } = {}) => {
|
|
96
|
+
if (!data) data = createDataSession({ fsm, xstate, relayPool: pool, auth, namespace });
|
|
97
|
+
return data;
|
|
98
|
+
};
|
|
99
|
+
|
|
89
100
|
const api = {
|
|
90
101
|
pool, auth, fsm, message, bans, roles, settings, pages, media, channels, servers, chat,
|
|
91
102
|
get voice() { return voice; },
|
|
92
103
|
ensureVoice,
|
|
93
104
|
get dm() { return dm; },
|
|
94
105
|
ensureDM,
|
|
106
|
+
get data() { return data; },
|
|
107
|
+
ensureData,
|
|
95
108
|
setCurrentChannel,
|
|
96
109
|
get currentChannelId() { return currentChannelId; },
|
|
97
110
|
get currentServerId() { return servers.currentServerId; }
|