@solarpunkltd/swarm-chat-js 7.3.0 → 8.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 +118 -20
- package/dist/chat.d.ts +14 -2
- package/dist/events.d.ts +9 -5
- package/dist/index.cjs +1 -1
- package/dist/index.js +102 -99
- package/dist/message/binding.d.ts +48 -0
- package/dist/message/canonicalSignature.d.ts +6 -0
- package/dist/message/entry.d.ts +25 -6
- package/dist/message/index.d.ts +2 -0
- package/dist/message/message.d.ts +60 -14
- package/dist/message/ownFeed.d.ts +9 -0
- package/dist/message-Bmwh3SCs.cjs +3 -0
- package/dist/message-Dbh8qrpg.js +455 -0
- package/dist/message.cjs +1 -1
- package/dist/message.js +2 -308
- package/dist/sender.d.ts +16 -4
- package/package.json +13 -10
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Bee as
|
|
1
|
+
import { A as e, B as t, C as n, D as r, E as i, F as a, H as o, I as s, L as c, M as l, N as ee, O as u, P as d, R as f, S as p, T as m, V as te, _ as ne, a as re, b as ie, c as h, d as g, f as _, g as v, h as y, i as ae, j as oe, k as b, l as x, m as S, n as C, o as w, p as T, r as E, s as D, t as O, u as k, v as A, w as se, x as ce, y as j, z as M } from "./message-Dbh8qrpg.js";
|
|
2
|
+
import { Bee as N, BeeResponseError as P, Identifier as F, PrivateKey as I, Topic as L } from "@ethersphere/bee-js";
|
|
3
3
|
//#region src/events.ts
|
|
4
|
-
var
|
|
4
|
+
var R = {
|
|
5
5
|
LOADING_INIT: "loadingInit",
|
|
6
6
|
LOADING_PREVIOUS_MESSAGES: "loadingPreviousMessages",
|
|
7
7
|
MESSAGE_RECEIVED: "messageReceived",
|
|
@@ -13,13 +13,13 @@ var F = {
|
|
|
13
13
|
MESSAGE_SKIPPED: "messageSkipped",
|
|
14
14
|
ERROR: "error"
|
|
15
15
|
};
|
|
16
|
-
function
|
|
17
|
-
return
|
|
16
|
+
function z(e) {
|
|
17
|
+
return V(e, -1, e.ts);
|
|
18
18
|
}
|
|
19
|
-
function
|
|
20
|
-
return
|
|
19
|
+
function B(e) {
|
|
20
|
+
return V(e.msg, e.seq, e.at);
|
|
21
21
|
}
|
|
22
|
-
function
|
|
22
|
+
function V(e, t, n) {
|
|
23
23
|
return {
|
|
24
24
|
id: e.id,
|
|
25
25
|
type: e.type,
|
|
@@ -28,13 +28,11 @@ function R(e, t, n) {
|
|
|
28
28
|
address: e.addr,
|
|
29
29
|
timestamp: n,
|
|
30
30
|
...e.target ? { targetMessageId: e.target } : {},
|
|
31
|
-
chatTopic: e.topic,
|
|
32
|
-
signature: e.sig,
|
|
33
31
|
index: t,
|
|
34
|
-
|
|
32
|
+
signedMessage: e
|
|
35
33
|
};
|
|
36
34
|
}
|
|
37
|
-
var
|
|
35
|
+
var H = class {
|
|
38
36
|
constructor() {
|
|
39
37
|
this.listeners = /* @__PURE__ */ new Map(), this.on = (e, t) => {
|
|
40
38
|
this.listeners.set(e, [...this.listeners.get(e) ?? [], t]);
|
|
@@ -51,7 +49,7 @@ var z = class {
|
|
|
51
49
|
console.error(`a listener for ${e} threw`, t);
|
|
52
50
|
}
|
|
53
51
|
}
|
|
54
|
-
},
|
|
52
|
+
}, U = 2e4, W = class {
|
|
55
53
|
constructor(e, t) {
|
|
56
54
|
this.spacingMs = e, this.now = t, this.missedAt = /* @__PURE__ */ new Map();
|
|
57
55
|
}
|
|
@@ -75,68 +73,68 @@ var z = class {
|
|
|
75
73
|
expired(e, t) {
|
|
76
74
|
return e > t || t - e >= this.spacingMs;
|
|
77
75
|
}
|
|
78
|
-
},
|
|
76
|
+
}, G = class extends Error {
|
|
79
77
|
constructor(e) {
|
|
80
78
|
super("the feed head lookup did not answer in time", e), this.name = "HeadLookupTimeoutError";
|
|
81
79
|
}
|
|
82
|
-
},
|
|
80
|
+
}, K = class extends Error {
|
|
83
81
|
constructor(e, t) {
|
|
84
82
|
super(`feed slot ${e} was served but could not be read`, t), this.index = e, this.name = "UnreadableSlotError";
|
|
85
83
|
}
|
|
86
84
|
};
|
|
87
|
-
function
|
|
88
|
-
return e instanceof
|
|
85
|
+
function q(e) {
|
|
86
|
+
return e instanceof P && (e.status === 404 || e.status === 500);
|
|
89
87
|
}
|
|
90
|
-
async function
|
|
88
|
+
async function J(e, t) {
|
|
91
89
|
try {
|
|
92
90
|
return await t();
|
|
93
91
|
} catch (t) {
|
|
94
|
-
if (
|
|
95
|
-
throw t instanceof
|
|
92
|
+
if (q(t)) return null;
|
|
93
|
+
throw t instanceof P ? t : new K(e, { cause: t });
|
|
96
94
|
}
|
|
97
95
|
}
|
|
98
|
-
function
|
|
99
|
-
let
|
|
96
|
+
function le(e, t, n, r, i = C) {
|
|
97
|
+
let a = L.fromString(n), o = (n) => e.feed.makeReader(a, t, Y(n));
|
|
100
98
|
return {
|
|
101
|
-
readNote: (
|
|
102
|
-
readSlot: (e) =>
|
|
99
|
+
readNote: (a) => J(a, async () => (await e.soc.makeReader(t, Y(r.slotReadMs)).download(D(n, i, a))).payload.toUint8Array()),
|
|
100
|
+
readSlot: (e) => J(e, async () => (await o(r.slotReadMs).downloadPayload({ index: e })).payload.toUint8Array()),
|
|
103
101
|
async readHead() {
|
|
104
|
-
let n =
|
|
102
|
+
let n = Y(r.feedReadMs);
|
|
105
103
|
try {
|
|
106
|
-
let { payload: r, feedIndex: i } = await e.feed.makeReader(
|
|
104
|
+
let { payload: r, feedIndex: i } = await e.feed.makeReader(a, t, n).downloadPayload();
|
|
107
105
|
return {
|
|
108
106
|
index: Number(i.toBigInt()),
|
|
109
107
|
payload: r.toUint8Array()
|
|
110
108
|
};
|
|
111
109
|
} catch (e) {
|
|
112
|
-
if (
|
|
113
|
-
throw n.signal?.aborted ? new
|
|
110
|
+
if (q(e)) return null;
|
|
111
|
+
throw n.signal?.aborted ? new G({ cause: e }) : e;
|
|
114
112
|
}
|
|
115
113
|
},
|
|
116
114
|
async readFile(t) {
|
|
117
|
-
return (await e.data.download(t, void 0,
|
|
115
|
+
return (await e.data.download(t, void 0, Y(r.feedReadMs))).toUint8Array();
|
|
118
116
|
}
|
|
119
117
|
};
|
|
120
118
|
}
|
|
121
|
-
function
|
|
119
|
+
function Y(e) {
|
|
122
120
|
return { signal: AbortSignal.timeout(e) };
|
|
123
121
|
}
|
|
124
|
-
var
|
|
125
|
-
function
|
|
126
|
-
let a = new
|
|
122
|
+
var ue = "0123456789abcdef".repeat(4);
|
|
123
|
+
function de(e, t, n, r, i) {
|
|
124
|
+
let a = new I(n), o = F.fromString(r);
|
|
127
125
|
return async (n) => {
|
|
128
|
-
await e.messaging.gsocSend(t, a, o, n, { deferred: !1 },
|
|
126
|
+
await e.messaging.gsocSend(t, a, o, n, { deferred: !1 }, Y(i.writeMs));
|
|
129
127
|
};
|
|
130
128
|
}
|
|
131
129
|
//#endregion
|
|
132
130
|
//#region src/follower.ts
|
|
133
|
-
var
|
|
131
|
+
var X = {
|
|
134
132
|
LIVE: "live",
|
|
135
133
|
RECONNECTING: "reconnecting",
|
|
136
134
|
STALLED: "stalled"
|
|
137
|
-
},
|
|
135
|
+
}, fe = {
|
|
138
136
|
pollIntervalMs: 1e3,
|
|
139
|
-
missingReadSpacingMs:
|
|
137
|
+
missingReadSpacingMs: U,
|
|
140
138
|
maxSlotsPerPoll: 16,
|
|
141
139
|
unservedPollsBeforeProbe: 3,
|
|
142
140
|
unreadablePollsBeforeFailure: 3,
|
|
@@ -154,16 +152,16 @@ var Y = {
|
|
|
154
152
|
stallAfterMs: 8e3,
|
|
155
153
|
random: Math.random,
|
|
156
154
|
now: Date.now
|
|
157
|
-
},
|
|
155
|
+
}, Z = class extends Error {
|
|
158
156
|
constructor(e) {
|
|
159
157
|
super(`the gateway keeps answering feed slot ${e} with something that is not a chunk`), this.index = e, this.name = "UnreadableGatewayError";
|
|
160
158
|
}
|
|
161
|
-
},
|
|
159
|
+
}, pe = class {
|
|
162
160
|
constructor(e, t, n, r = {}, i = null) {
|
|
163
161
|
this.source = e, this.topic = t, this.events = n, this.notes = i, this.next = 0, this.ceiling = null, this.nextNoteSlot = 0, this.lastNoteFoundAt = 0, this.unservedPolls = 0, this.nextProbeAt = 0, this.unreadablePolls = 0, this.gatewayFailures = 0, this.missed = /* @__PURE__ */ new Map(), this.timer = null, this.generation = 0, this.running = !1, this.status = null, this.settings = {
|
|
164
|
-
...
|
|
162
|
+
...fe,
|
|
165
163
|
...r
|
|
166
|
-
}, this.pacer = new
|
|
164
|
+
}, this.pacer = new W(this.settings.missingReadSpacingMs, this.settings.now);
|
|
167
165
|
}
|
|
168
166
|
get nextIndex() {
|
|
169
167
|
return this.next;
|
|
@@ -225,7 +223,7 @@ var Y = {
|
|
|
225
223
|
try {
|
|
226
224
|
t = await this.source.readSlot(e);
|
|
227
225
|
} catch (e) {
|
|
228
|
-
if (e instanceof
|
|
226
|
+
if (e instanceof K) return "unreadable";
|
|
229
227
|
throw e;
|
|
230
228
|
}
|
|
231
229
|
return t === null ? this.pacer.missed(e) : this.pacer.found(e), t;
|
|
@@ -249,7 +247,7 @@ var Y = {
|
|
|
249
247
|
this.unreadablePolls = 0;
|
|
250
248
|
continue;
|
|
251
249
|
}
|
|
252
|
-
if (this.unreadablePolls >= this.settings.unreadablePollsBeforeFailure) throw new
|
|
250
|
+
if (this.unreadablePolls >= this.settings.unreadablePollsBeforeFailure) throw new Z(n);
|
|
253
251
|
}
|
|
254
252
|
return t;
|
|
255
253
|
}
|
|
@@ -305,16 +303,16 @@ var Y = {
|
|
|
305
303
|
}
|
|
306
304
|
}
|
|
307
305
|
accept(e, t) {
|
|
308
|
-
let n =
|
|
306
|
+
let n = A(t, e, this.topic);
|
|
309
307
|
n.ok ? (this.notes?.clock.observe(n.value.at, this.settings.now()), this.events.entry(n.value)) : this.events.skipped(e, n.reason, n.detail);
|
|
310
308
|
}
|
|
311
309
|
gatewayFailed(e) {
|
|
312
|
-
this.gatewayFailures++, this.setStatus(
|
|
310
|
+
this.gatewayFailures++, this.setStatus(X.RECONNECTING), this.events.error(e);
|
|
313
311
|
}
|
|
314
312
|
gatewayAnswered() {
|
|
315
313
|
this.gatewayFailures = 0;
|
|
316
314
|
let e = this.settings.now(), t = [...this.missed.values()].some((t) => e - t >= this.settings.stallAfterMs);
|
|
317
|
-
this.setStatus(t ?
|
|
315
|
+
this.setStatus(t ? X.STALLED : X.LIVE);
|
|
318
316
|
}
|
|
319
317
|
backoffMs() {
|
|
320
318
|
let { pollIntervalMs: e, backoffCapMs: t, random: n } = this.settings, r = Math.min(t, e * 2 ** this.gatewayFailures);
|
|
@@ -323,7 +321,7 @@ var Y = {
|
|
|
323
321
|
setStatus(e) {
|
|
324
322
|
e !== this.status && (this.status = e, this.events.status(e));
|
|
325
323
|
}
|
|
326
|
-
},
|
|
324
|
+
}, me = 16, he = class {
|
|
327
325
|
constructor(e, t, n, r = null) {
|
|
328
326
|
this.source = e, this.topic = t, this.events = n, this.notes = r, this.older = null, this.loading = null;
|
|
329
327
|
}
|
|
@@ -368,7 +366,7 @@ var Y = {
|
|
|
368
366
|
try {
|
|
369
367
|
return await this.source.readHead();
|
|
370
368
|
} catch (e) {
|
|
371
|
-
if (e instanceof
|
|
369
|
+
if (e instanceof G) return this.events.error(e), null;
|
|
372
370
|
throw e;
|
|
373
371
|
}
|
|
374
372
|
}
|
|
@@ -383,30 +381,30 @@ var Y = {
|
|
|
383
381
|
async loadOlderOnce() {
|
|
384
382
|
let e = this.older;
|
|
385
383
|
if (e === null) return [];
|
|
386
|
-
let t = await this.source.readFile(e.ref), n =
|
|
384
|
+
let t = await this.source.readFile(e.ref), n = j(t, this.topic, e);
|
|
387
385
|
if (!n.ok) throw this.older = null, Error(`history file ${e.ref} refused (${n.reason}): ${n.detail}`);
|
|
388
386
|
return this.report(n.value.skipped), this.older = n.value.prev, n.value.rows;
|
|
389
387
|
}
|
|
390
388
|
async newestLink(e, t) {
|
|
391
389
|
let n = t === void 0 ? e : e - 1;
|
|
392
390
|
if (t !== void 0) {
|
|
393
|
-
let n =
|
|
391
|
+
let n = A(t, e, this.topic);
|
|
394
392
|
if (n.ok) return n.value.history;
|
|
395
393
|
}
|
|
396
|
-
for (let t = n; t >= Math.max(0, e -
|
|
394
|
+
for (let t = n; t >= Math.max(0, e - me); t--) {
|
|
397
395
|
let e = await this.source.readSlot(t).catch((e) => {
|
|
398
|
-
if (e instanceof
|
|
396
|
+
if (e instanceof K) return null;
|
|
399
397
|
throw e;
|
|
400
398
|
});
|
|
401
399
|
if (e === null) continue;
|
|
402
|
-
let n =
|
|
400
|
+
let n = A(e, t, this.topic);
|
|
403
401
|
if (n.ok) return n.value.history;
|
|
404
402
|
}
|
|
405
403
|
return null;
|
|
406
404
|
}
|
|
407
405
|
async readFile(e) {
|
|
408
406
|
try {
|
|
409
|
-
let t =
|
|
407
|
+
let t = j(await this.source.readFile(e.ref), this.topic, e);
|
|
410
408
|
return t.ok ? (this.report(t.value.skipped), this.older = t.value.prev, t.value.rows) : (this.events.error(/* @__PURE__ */ Error(`history file ${e.ref} refused (${t.reason}): ${t.detail}`)), "refused");
|
|
411
409
|
} catch (t) {
|
|
412
410
|
return this.events.error(t), this.older = e, null;
|
|
@@ -415,18 +413,18 @@ var Y = {
|
|
|
415
413
|
report(e) {
|
|
416
414
|
e > 0 && this.events.skipped(e);
|
|
417
415
|
}
|
|
418
|
-
},
|
|
419
|
-
slotMs:
|
|
420
|
-
heartbeatMs:
|
|
416
|
+
}, ge = {
|
|
417
|
+
slotMs: C,
|
|
418
|
+
heartbeatMs: O,
|
|
421
419
|
marginMs: 1e3,
|
|
422
420
|
scanBatch: 4,
|
|
423
421
|
clockLimitMs: 3e5,
|
|
424
|
-
missingReadSpacingMs:
|
|
422
|
+
missingReadSpacingMs: U
|
|
425
423
|
};
|
|
426
|
-
function
|
|
424
|
+
function _e(e) {
|
|
427
425
|
return typeof e.readNote == "function";
|
|
428
426
|
}
|
|
429
|
-
var
|
|
427
|
+
var ve = class {
|
|
430
428
|
constructor(e) {
|
|
431
429
|
this.limitMs = e, this.aheadAtMost = Infinity, this.trusted = !0;
|
|
432
430
|
}
|
|
@@ -443,21 +441,21 @@ var de = class {
|
|
|
443
441
|
let e = Number.isFinite(this.aheadAtMost), t = this.trusted || !e ? Math.min(0, this.aheadAtMost) : this.aheadAtMost;
|
|
444
442
|
return Math.max(-this.limitMs, Math.min(this.limitMs, t));
|
|
445
443
|
}
|
|
446
|
-
},
|
|
444
|
+
}, ye = class {
|
|
447
445
|
constructor(e, t, n) {
|
|
448
446
|
this.source = e, this.now = n, this.counts = {
|
|
449
447
|
found: 0,
|
|
450
448
|
empty: 0
|
|
451
449
|
}, this.settings = {
|
|
452
|
-
...
|
|
450
|
+
...ge,
|
|
453
451
|
...t
|
|
454
|
-
}, this.clock = new
|
|
452
|
+
}, this.clock = new ve(this.settings.clockLimitMs), this.pacer = new W(this.settings.missingReadSpacingMs, n);
|
|
455
453
|
}
|
|
456
454
|
lastReadableSlot(e = this.now()) {
|
|
457
|
-
return
|
|
455
|
+
return k(e - this.settings.marginMs - this.clock.ms, this.settings.slotMs) - 1;
|
|
458
456
|
}
|
|
459
457
|
readableAt(e) {
|
|
460
|
-
return
|
|
458
|
+
return x(e, this.settings.slotMs) + this.settings.marginMs + this.clock.ms;
|
|
461
459
|
}
|
|
462
460
|
get lookBackSlots() {
|
|
463
461
|
return Math.ceil(this.settings.heartbeatMs / this.settings.slotMs) + 2;
|
|
@@ -471,10 +469,10 @@ var de = class {
|
|
|
471
469
|
try {
|
|
472
470
|
t = await this.source.readNote(e), t === null && this.pacer.missed(e);
|
|
473
471
|
} catch (e) {
|
|
474
|
-
if (!(e instanceof
|
|
472
|
+
if (!(e instanceof K)) throw e;
|
|
475
473
|
t = null;
|
|
476
474
|
}
|
|
477
|
-
let n = t === null ? null :
|
|
475
|
+
let n = t === null ? null : g(t);
|
|
478
476
|
return n === null ? (this.counts.empty++, null) : (this.counts.found++, this.clock.observe(n.writtenAt, this.now()), n);
|
|
479
477
|
}
|
|
480
478
|
async scan(e, t) {
|
|
@@ -494,17 +492,17 @@ var de = class {
|
|
|
494
492
|
maxResends: 5,
|
|
495
493
|
reactionWindowMs: 1e3,
|
|
496
494
|
isLive: () => !0
|
|
497
|
-
},
|
|
495
|
+
}, be = class {
|
|
498
496
|
constructor(e, t, n, r, i = Q) {
|
|
499
|
-
this.key = e, this.
|
|
497
|
+
this.key = e, this.profile = t, this.write = n, this.events = r, this.settings = i, this.outgoing = /* @__PURE__ */ new Map(), this.reactions = /* @__PURE__ */ new Map(), this.stopped = !1;
|
|
500
498
|
}
|
|
501
499
|
get address() {
|
|
502
500
|
return this.key.publicKey().address().toHex();
|
|
503
501
|
}
|
|
504
502
|
send(e) {
|
|
505
|
-
let { message: t, bytes: n } =
|
|
503
|
+
let { message: t, bytes: n } = l(this.key, {
|
|
506
504
|
...e,
|
|
507
|
-
|
|
505
|
+
...this.profile
|
|
508
506
|
}), r = {
|
|
509
507
|
message: t,
|
|
510
508
|
bytes: n,
|
|
@@ -581,22 +579,27 @@ var de = class {
|
|
|
581
579
|
clearTimer(e) {
|
|
582
580
|
e.timer &&= (clearTimeout(e.timer), null);
|
|
583
581
|
}
|
|
584
|
-
},
|
|
582
|
+
}, xe = [
|
|
585
583
|
1e3,
|
|
586
584
|
2e3,
|
|
587
585
|
4e3,
|
|
588
586
|
8e3
|
|
589
|
-
],
|
|
587
|
+
], Se = 3;
|
|
590
588
|
function $(e) {
|
|
591
589
|
return (e.startsWith("0x") ? e.slice(2) : e).toLowerCase();
|
|
592
590
|
}
|
|
593
|
-
var
|
|
591
|
+
var Ce = class {
|
|
594
592
|
constructor(e, t = {}) {
|
|
595
|
-
this.emitter = new
|
|
593
|
+
this.emitter = new H(), this.seen = /* @__PURE__ */ new Set(), this.status = null, this.generation = 0, this.running = !1, this.starting = null, this.openTimer = null, this.wakeOpen = null;
|
|
596
594
|
let { user: n, infra: r } = e;
|
|
597
|
-
this.key = new
|
|
595
|
+
this.key = new I($(n.privateKey)), this.topic = r.chatTopic, this.profile = {
|
|
596
|
+
name: n.nickname,
|
|
597
|
+
via: r.via,
|
|
598
|
+
...n.binding ? { idb: n.binding } : {},
|
|
599
|
+
...r.own === void 0 ? {} : { own: r.own }
|
|
600
|
+
}, this.openRetryMs = t.openRetryMs ?? xe, this.senderSettings = {
|
|
598
601
|
...Q,
|
|
599
|
-
isLive: () => this.status ===
|
|
602
|
+
isLive: () => this.status === X.LIVE,
|
|
600
603
|
...t.sender
|
|
601
604
|
};
|
|
602
605
|
let i = {
|
|
@@ -608,28 +611,28 @@ var ge = class {
|
|
|
608
611
|
...r.noteHeartbeatMs === void 0 ? {} : { heartbeatMs: r.noteHeartbeatMs },
|
|
609
612
|
...t.notes
|
|
610
613
|
};
|
|
611
|
-
this.source = t.source ??
|
|
614
|
+
this.source = t.source ?? le(new N(r.beeUrl), $(r.chatAddress), r.chatTopic, i, a.slotMs), this.write = t.write ?? de(new N(r.writeUrl ?? r.beeUrl), r.stamp ? $(r.stamp) : ue, $(r.gsocResourceId), r.gsocTopic, i);
|
|
612
615
|
let o = t.follower?.now ?? (() => Date.now()), s = {
|
|
613
616
|
pollIntervalMs: r.pollingInterval ?? 1e3,
|
|
614
617
|
...t.follower,
|
|
615
618
|
now: o
|
|
616
619
|
}, c = this.source;
|
|
617
|
-
this.notes =
|
|
620
|
+
this.notes = _e(c) ? new ye(c, a, o) : null, this.follower = new pe(this.source, this.topic, {
|
|
618
621
|
entry: (e) => this.show(e),
|
|
619
|
-
skipped: (e, t, n) => this.emitter.emit(
|
|
622
|
+
skipped: (e, t, n) => this.emitter.emit(R.MESSAGE_SKIPPED, {
|
|
620
623
|
index: e,
|
|
621
624
|
reason: t,
|
|
622
625
|
detail: n
|
|
623
626
|
}),
|
|
624
627
|
status: (e) => this.setStatus(e),
|
|
625
|
-
error: (e) => this.emitter.emit(
|
|
626
|
-
}, s, this.notes), this.history = new
|
|
627
|
-
skipped: (e) => this.emitter.emit(
|
|
628
|
+
error: (e) => this.emitter.emit(R.ERROR, e)
|
|
629
|
+
}, s, this.notes), this.history = new he(this.source, this.topic, {
|
|
630
|
+
skipped: (e) => this.emitter.emit(R.MESSAGE_SKIPPED, {
|
|
628
631
|
index: -1,
|
|
629
632
|
reason: "history-row",
|
|
630
633
|
detail: `${e} rows of a history file`
|
|
631
634
|
}),
|
|
632
|
-
error: (e) => this.emitter.emit(
|
|
635
|
+
error: (e) => this.emitter.emit(R.ERROR, e)
|
|
633
636
|
}, this.notes), this.sender = this.makeSender();
|
|
634
637
|
}
|
|
635
638
|
getEmitter() {
|
|
@@ -657,7 +660,7 @@ var ge = class {
|
|
|
657
660
|
if (!n) throw Error("a reaction names the message it reacts to");
|
|
658
661
|
return this.sender.react(this.topic, n, e), null;
|
|
659
662
|
}
|
|
660
|
-
return
|
|
663
|
+
return z(this.sender.send({
|
|
661
664
|
topic: this.topic,
|
|
662
665
|
type: t,
|
|
663
666
|
target: n ?? "",
|
|
@@ -668,12 +671,12 @@ var ge = class {
|
|
|
668
671
|
return this.sender.retry(typeof e == "string" ? e : e.id);
|
|
669
672
|
}
|
|
670
673
|
async fetchPreviousMessages() {
|
|
671
|
-
this.emitter.emit(
|
|
674
|
+
this.emitter.emit(R.LOADING_PREVIOUS_MESSAGES, !0);
|
|
672
675
|
try {
|
|
673
676
|
let e = this.generation, t = await this.history.loadOlder();
|
|
674
677
|
return e === this.generation ? this.showRows(t) : [];
|
|
675
678
|
} finally {
|
|
676
|
-
this.emitter.emit(
|
|
679
|
+
this.emitter.emit(R.LOADING_PREVIOUS_MESSAGES, !1);
|
|
677
680
|
}
|
|
678
681
|
}
|
|
679
682
|
hasPreviousMessages() {
|
|
@@ -683,16 +686,16 @@ var ge = class {
|
|
|
683
686
|
return [...e].sort((e, t) => e.index >= 0 && t.index >= 0 ? e.index - t.index : e.index >= 0 || t.index >= 0 ? e.index >= 0 ? -1 : 1 : e.timestamp - t.timestamp);
|
|
684
687
|
}
|
|
685
688
|
async open(e) {
|
|
686
|
-
this.emitter.emit(
|
|
689
|
+
this.emitter.emit(R.LOADING_INIT, !0);
|
|
687
690
|
let t = 0;
|
|
688
691
|
for (; e === this.generation;) try {
|
|
689
692
|
let t = await this.history.open();
|
|
690
693
|
if (e !== this.generation) return;
|
|
691
|
-
this.showRows(t.rows), this.follower.start(t.startAt, t.notes), this.emitter.emit(
|
|
694
|
+
this.showRows(t.rows), this.follower.start(t.startAt, t.notes), this.emitter.emit(R.LOADING_INIT, !1);
|
|
692
695
|
return;
|
|
693
696
|
} catch (n) {
|
|
694
697
|
if (e !== this.generation) return;
|
|
695
|
-
t++, this.emitter.emit(
|
|
698
|
+
t++, this.emitter.emit(R.ERROR, n), this.setStatus(X.RECONNECTING), t === Se && this.emitter.emit(R.CRITICAL_ERROR, n), await this.waitToOpen(this.openRetryMs[Math.min(t, this.openRetryMs.length) - 1] ?? 8e3);
|
|
696
699
|
}
|
|
697
700
|
}
|
|
698
701
|
waitToOpen(e) {
|
|
@@ -705,31 +708,31 @@ var ge = class {
|
|
|
705
708
|
});
|
|
706
709
|
}
|
|
707
710
|
makeSender() {
|
|
708
|
-
return new
|
|
709
|
-
pending: (e) => this.emitter.emit(
|
|
710
|
-
written: (e) => this.emitter.emit(
|
|
711
|
+
return new be(this.key, this.profile, this.write, {
|
|
712
|
+
pending: (e) => this.emitter.emit(R.MESSAGE_REQUEST_INITIATED, z(e)),
|
|
713
|
+
written: (e) => this.emitter.emit(R.MESSAGE_REQUEST_UPLOADED, z(e)),
|
|
711
714
|
failed: (e, t) => {
|
|
712
|
-
this.emitter.emit(
|
|
715
|
+
this.emitter.emit(R.ERROR, t), this.emitter.emit(R.MESSAGE_REQUEST_ERROR, z(e));
|
|
713
716
|
},
|
|
714
717
|
confirmed: () => {}
|
|
715
718
|
}, this.senderSettings);
|
|
716
719
|
}
|
|
717
720
|
show(e) {
|
|
718
|
-
this.seen.has(e.seq) || (this.seen.add(e.seq), this.sender.confirm(e.msg), this.emitter.emit(
|
|
721
|
+
this.seen.has(e.seq) || (this.seen.add(e.seq), this.sender.confirm(e.msg), this.emitter.emit(R.MESSAGE_RECEIVED, B(e)));
|
|
719
722
|
}
|
|
720
723
|
showRows(e) {
|
|
721
724
|
let t = [];
|
|
722
725
|
for (let n of e) {
|
|
723
726
|
if (this.seen.has(n.seq)) continue;
|
|
724
727
|
this.seen.add(n.seq), this.sender.confirm(n.msg);
|
|
725
|
-
let e =
|
|
726
|
-
t.push(e), this.emitter.emit(
|
|
728
|
+
let e = B(n);
|
|
729
|
+
t.push(e), this.emitter.emit(R.MESSAGE_RECEIVED, e);
|
|
727
730
|
}
|
|
728
731
|
return t;
|
|
729
732
|
}
|
|
730
733
|
setStatus(e) {
|
|
731
|
-
e !== this.status && (this.status = e, this.emitter.emit(
|
|
734
|
+
e !== this.status && (this.status = e, this.emitter.emit(R.STATUS, e));
|
|
732
735
|
}
|
|
733
736
|
};
|
|
734
737
|
//#endregion
|
|
735
|
-
export {
|
|
738
|
+
export { M as CHAT_BINDING_TITLE, H as ChatEmitter, p as ChatMessageError, O as DEFAULT_NOTE_HEARTBEAT_MS, C as DEFAULT_NOTE_SLOT_MS, R as EVENTS, X as FeedStatus, G as HeadLookupTimeoutError, t as MAX_BINDING_CHARACTERS, T as MAX_ENTRY_BYTES, n as MAX_MESSAGE_BYTES, se as MAX_NAME_CHARACTERS, E as MAX_NOTE_BYTES, m as MAX_TEXT_CHARACTERS, i as MAX_TOPIC_CHARACTERS, r as MESSAGE_VERSION, u as MessageType, b as MessageVia, ae as NOTE_VERSION, ie as OWN_FEED_TOPIC_PREFIX, Ce as SwarmChat, Z as UnreadableGatewayError, K as UnreadableSlotError, te as chatBindingSchema, e as chatMessageSchema, o as checkChatBinding, oe as countCharacters, l as createChatMessage, ee as encodeChatMessage, re as encodeSlotNote, S as feedEntrySchema, d as hasValidSignature, y as historyFileSchema, v as historyLinkSchema, ne as historyRowSchema, a as newMessageId, w as noteAddress, D as noteIdentifier, h as noteIdentifierText, x as noteSlotEnd, k as noteSlotOf, ce as ownFeedTopic, s as parseChatMessage, A as parseFeedEntry, j as parseHistoryFile, g as parseSlotNote, c as signedBytes, _ as slotNoteSchema, f as verifyChatMessage };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* The Swarm ID chat binding: the account's statement, signed with its own key, that a chat address on one site is its
|
|
4
|
+
* own. The Swarm ID fork (solarpunk-id, `lib/src/utils/chat-binding.ts`) makes it, and this module reads it exactly as
|
|
5
|
+
* the fork's `verifyChatBinding` does, without importing the fork: the same four lines, the same clean site origin,
|
|
6
|
+
* the same EIP-191 personal_sign recovery with v 27 or 28 and a low s.
|
|
7
|
+
*/
|
|
8
|
+
/** The first line, which also versions the binding format. */
|
|
9
|
+
export declare const CHAT_BINDING_TITLE = "Swarm ID chat binding v1";
|
|
10
|
+
/** The fork's own bound on a binding's text. */
|
|
11
|
+
export declare const MAX_BINDING_CHARACTERS = 512;
|
|
12
|
+
/**
|
|
13
|
+
* A binding as a message carries it. `sig` is spelled as the fork writes it, `0x` and 130 lowercase hex characters
|
|
14
|
+
* of r, s and v, so one binding has one spelling inside the signed bytes.
|
|
15
|
+
*/
|
|
16
|
+
export declare const chatBindingSchema: z.ZodObject<{
|
|
17
|
+
msg: z.ZodString;
|
|
18
|
+
sig: z.ZodString;
|
|
19
|
+
}, z.core.$strict>;
|
|
20
|
+
export type ChatBinding = z.infer<typeof chatBindingSchema>;
|
|
21
|
+
/** Who a verified binding says the sender is. */
|
|
22
|
+
export interface ChatIdentity {
|
|
23
|
+
/** The Swarm ID account that signed the binding, `0x` and 40 lowercase hex characters. */
|
|
24
|
+
account: string;
|
|
25
|
+
/** The site the binding was signed for, a bare origin. */
|
|
26
|
+
site: string;
|
|
27
|
+
/** When the account says it signed, ISO 8601 UTC. */
|
|
28
|
+
date: string;
|
|
29
|
+
}
|
|
30
|
+
export interface BindingOptions {
|
|
31
|
+
/** The origin the reader runs on. When given, a binding for any other site is refused. */
|
|
32
|
+
origin?: string;
|
|
33
|
+
/** Accept a binding for `http://localhost`, `http://127.0.0.1` or `http://[::1]`, as only a development build signs. */
|
|
34
|
+
allowLocalHttp?: boolean;
|
|
35
|
+
}
|
|
36
|
+
export type BindingCheck = {
|
|
37
|
+
ok: true;
|
|
38
|
+
identity: ChatIdentity;
|
|
39
|
+
} | {
|
|
40
|
+
ok: false;
|
|
41
|
+
detail: string;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Reads a binding for the chat address `addr` (40 lowercase hex characters, no `0x`). Refuses every text but the four
|
|
45
|
+
* lines the fork writes, a binding for another chat address, one for another site than `origin` when that is given,
|
|
46
|
+
* and a signature nothing recovers an account from. Never throws.
|
|
47
|
+
*/
|
|
48
|
+
export declare function checkChatBinding(binding: ChatBinding, addr: string, options?: BindingOptions): BindingCheck;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether r and s, 64 hex characters each, are in range with s in the lower half of the curve order. Every ECDSA
|
|
3
|
+
* signature has a second valid spelling with s replaced by n - s and v flipped, which recovers the same signer, so
|
|
4
|
+
* refusing the high s one leaves one valid signature per signed text. bee-js and the Swarm ID fork both sign low s.
|
|
5
|
+
*/
|
|
6
|
+
export declare function isCanonicalSignature(rHex: string, sHex: string): boolean;
|
package/dist/message/entry.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
/**
|
|
3
3
|
* What the server writes: one feed entry per message at indices 0, 1, 2 and on, and one history file per chat that
|
|
4
|
-
* the entries point to. The server builds these and the reader checks their shape.
|
|
5
|
-
* message's signature, because the server checked
|
|
4
|
+
* the entries point to. The server builds these and the reader checks their shape. Their `v` is MESSAGE_VERSION. The
|
|
5
|
+
* reader does not check each message's signature or binding, because the server checked both before publishing. A
|
|
6
|
+
* page that shows who sent a message verifies `msg` itself with `verifyChatMessage`, in a Web Worker.
|
|
6
7
|
*/
|
|
7
8
|
/** A feed entry is always one chunk, so bee-js never wraps it. */
|
|
8
9
|
export declare const MAX_ENTRY_BYTES = 4096;
|
|
@@ -12,11 +13,11 @@ export declare const historyLinkSchema: z.ZodObject<{
|
|
|
12
13
|
}, z.core.$strict>;
|
|
13
14
|
export type HistoryLink = z.infer<typeof historyLinkSchema>;
|
|
14
15
|
export declare const feedEntrySchema: z.ZodObject<{
|
|
15
|
-
v: z.ZodLiteral<
|
|
16
|
+
v: z.ZodLiteral<8>;
|
|
16
17
|
seq: z.ZodNumber;
|
|
17
18
|
at: z.ZodNumber;
|
|
18
19
|
msg: z.ZodObject<{
|
|
19
|
-
v: z.ZodLiteral<
|
|
20
|
+
v: z.ZodLiteral<8>;
|
|
20
21
|
topic: z.ZodString;
|
|
21
22
|
id: z.ZodString;
|
|
22
23
|
type: z.ZodEnum<{
|
|
@@ -29,6 +30,15 @@ export declare const feedEntrySchema: z.ZodObject<{
|
|
|
29
30
|
name: z.ZodString;
|
|
30
31
|
addr: z.ZodString;
|
|
31
32
|
ts: z.ZodNumber;
|
|
33
|
+
via: z.ZodEnum<{
|
|
34
|
+
gateway: "gateway";
|
|
35
|
+
"own-stamp": "own-stamp";
|
|
36
|
+
}>;
|
|
37
|
+
own: z.ZodBoolean;
|
|
38
|
+
idb: z.ZodOptional<z.ZodObject<{
|
|
39
|
+
msg: z.ZodString;
|
|
40
|
+
sig: z.ZodString;
|
|
41
|
+
}, z.core.$strict>>;
|
|
32
42
|
sig: z.ZodString;
|
|
33
43
|
}, z.core.$strict>;
|
|
34
44
|
history: z.ZodNullable<z.ZodObject<{
|
|
@@ -41,7 +51,7 @@ export declare const historyRowSchema: z.ZodObject<{
|
|
|
41
51
|
seq: z.ZodNumber;
|
|
42
52
|
at: z.ZodNumber;
|
|
43
53
|
msg: z.ZodObject<{
|
|
44
|
-
v: z.ZodLiteral<
|
|
54
|
+
v: z.ZodLiteral<8>;
|
|
45
55
|
topic: z.ZodString;
|
|
46
56
|
id: z.ZodString;
|
|
47
57
|
type: z.ZodEnum<{
|
|
@@ -54,13 +64,22 @@ export declare const historyRowSchema: z.ZodObject<{
|
|
|
54
64
|
name: z.ZodString;
|
|
55
65
|
addr: z.ZodString;
|
|
56
66
|
ts: z.ZodNumber;
|
|
67
|
+
via: z.ZodEnum<{
|
|
68
|
+
gateway: "gateway";
|
|
69
|
+
"own-stamp": "own-stamp";
|
|
70
|
+
}>;
|
|
71
|
+
own: z.ZodBoolean;
|
|
72
|
+
idb: z.ZodOptional<z.ZodObject<{
|
|
73
|
+
msg: z.ZodString;
|
|
74
|
+
sig: z.ZodString;
|
|
75
|
+
}, z.core.$strict>>;
|
|
57
76
|
sig: z.ZodString;
|
|
58
77
|
}, z.core.$strict>;
|
|
59
78
|
}, z.core.$strict>;
|
|
60
79
|
export type HistoryRow = z.infer<typeof historyRowSchema>;
|
|
61
80
|
/** A row that fails its shape is left out and counted, so one bad row never hides the rest of the file. */
|
|
62
81
|
export declare const historyFileSchema: z.ZodObject<{
|
|
63
|
-
v: z.ZodLiteral<
|
|
82
|
+
v: z.ZodLiteral<8>;
|
|
64
83
|
topic: z.ZodString;
|
|
65
84
|
fromSeq: z.ZodNumber;
|
|
66
85
|
toSeq: z.ZodNumber;
|