@solarpunkltd/swarm-chat-js 7.2.0 → 8.0.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/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
- import { ChatMessageError as e, DEFAULT_NOTE_HEARTBEAT_MS as t, DEFAULT_NOTE_SLOT_MS as n, MAX_ENTRY_BYTES as r, MAX_MESSAGE_BYTES as i, MAX_NAME_CHARACTERS as a, MAX_NOTE_BYTES as o, MAX_TEXT_CHARACTERS as s, MAX_TOPIC_CHARACTERS as c, MESSAGE_VERSION as l, MessageType as u, NOTE_VERSION as d, chatMessageSchema as f, checkChatMessage as p, countCharacters as m, createChatMessage as h, encodeChatMessage as g, encodeSlotNote as _, feedEntrySchema as v, hasValidSignature as ee, historyFileSchema as te, historyLinkSchema as y, historyRowSchema as ne, newMessageId as b, noteAddress as x, noteIdentifier as S, noteIdentifierText as C, noteSlotEnd as w, noteSlotOf as T, parseChatMessage as E, parseFeedEntry as D, parseHistoryFile as O, parseSlotNote as k, signedBytes as A, slotNoteSchema as re } from "./message.js";
2
- import { Bee as j, BeeResponseError as M, Identifier as N, PrivateKey as P, Topic as F } from "@ethersphere/bee-js";
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 I = {
4
+ var R = {
5
5
  LOADING_INIT: "loadingInit",
6
6
  LOADING_PREVIOUS_MESSAGES: "loadingPreviousMessages",
7
7
  MESSAGE_RECEIVED: "messageReceived",
@@ -13,13 +13,13 @@ var I = {
13
13
  MESSAGE_SKIPPED: "messageSkipped",
14
14
  ERROR: "error"
15
15
  };
16
- function L(e) {
17
- return z(e, -1, e.ts);
16
+ function z(e) {
17
+ return V(e, -1, e.ts);
18
18
  }
19
- function R(e) {
20
- return z(e.msg, e.seq, e.at);
19
+ function B(e) {
20
+ return V(e.msg, e.seq, e.at);
21
21
  }
22
- function z(e, t, n) {
22
+ function V(e, t, n) {
23
23
  return {
24
24
  id: e.id,
25
25
  type: e.type,
@@ -28,13 +28,11 @@ function z(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
- sentAt: e.ts
32
+ signedMessage: e
35
33
  };
36
34
  }
37
- var B = class {
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,67 +49,92 @@ var B = class {
51
49
  console.error(`a listener for ${e} threw`, t);
52
50
  }
53
51
  }
54
- }, V = class extends Error {
52
+ }, U = 2e4, W = class {
53
+ constructor(e, t) {
54
+ this.spacingMs = e, this.now = t, this.missedAt = /* @__PURE__ */ new Map();
55
+ }
56
+ readableAt(e, t = this.now()) {
57
+ let n = this.missedAt.get(e);
58
+ return n === void 0 || this.expired(n, t) ? -Infinity : n + this.spacingMs;
59
+ }
60
+ mayRead(e, t = this.now()) {
61
+ return t >= this.readableAt(e, t);
62
+ }
63
+ missed(e, t = this.now()) {
64
+ for (let [e, n] of this.missedAt) this.expired(n, t) && this.missedAt.delete(e);
65
+ this.missedAt.set(e, t);
66
+ }
67
+ found(e) {
68
+ this.missedAt.delete(e);
69
+ }
70
+ clear() {
71
+ this.missedAt.clear();
72
+ }
73
+ expired(e, t) {
74
+ return e > t || t - e >= this.spacingMs;
75
+ }
76
+ }, G = class extends Error {
55
77
  constructor(e) {
56
78
  super("the feed head lookup did not answer in time", e), this.name = "HeadLookupTimeoutError";
57
79
  }
58
- }, H = class extends Error {
80
+ }, K = class extends Error {
59
81
  constructor(e, t) {
60
82
  super(`feed slot ${e} was served but could not be read`, t), this.index = e, this.name = "UnreadableSlotError";
61
83
  }
62
84
  };
63
- function U(e) {
64
- return e instanceof M && (e.status === 404 || e.status === 500);
85
+ function q(e) {
86
+ return e instanceof P && (e.status === 404 || e.status === 500);
65
87
  }
66
- async function W(e, t) {
88
+ async function J(e, t) {
67
89
  try {
68
90
  return await t();
69
91
  } catch (t) {
70
- if (U(t)) return null;
71
- throw t instanceof M ? t : new H(e, { cause: t });
92
+ if (q(t)) return null;
93
+ throw t instanceof P ? t : new K(e, { cause: t });
72
94
  }
73
95
  }
74
- function G(e, t, r, i, a = n) {
75
- let o = F.fromString(r), s = (n) => e.feed.makeReader(o, t, K(n));
96
+ function le(e, t, n, r, i = C) {
97
+ let a = L.fromString(n), o = (n) => e.feed.makeReader(a, t, Y(n));
76
98
  return {
77
- readNote: (n) => W(n, async () => (await e.soc.makeReader(t, K(i.slotReadMs)).download(S(r, a, n))).payload.toUint8Array()),
78
- readSlot: (e) => W(e, async () => (await s(i.slotReadMs).downloadPayload({ index: e })).payload.toUint8Array()),
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()),
79
101
  async readHead() {
80
- let n = K(i.feedReadMs);
102
+ let n = Y(r.feedReadMs);
81
103
  try {
82
- let { payload: r, feedIndex: i } = await e.feed.makeReader(o, t, n).downloadPayload();
104
+ let { payload: r, feedIndex: i } = await e.feed.makeReader(a, t, n).downloadPayload();
83
105
  return {
84
106
  index: Number(i.toBigInt()),
85
107
  payload: r.toUint8Array()
86
108
  };
87
109
  } catch (e) {
88
- if (U(e)) return null;
89
- throw n.signal?.aborted ? new V({ cause: e }) : e;
110
+ if (q(e)) return null;
111
+ throw n.signal?.aborted ? new G({ cause: e }) : e;
90
112
  }
91
113
  },
92
114
  async readFile(t) {
93
- return (await e.data.download(t, void 0, K(i.feedReadMs))).toUint8Array();
115
+ return (await e.data.download(t, void 0, Y(r.feedReadMs))).toUint8Array();
94
116
  }
95
117
  };
96
118
  }
97
- function K(e) {
119
+ function Y(e) {
98
120
  return { signal: AbortSignal.timeout(e) };
99
121
  }
100
- var ie = "0123456789abcdef".repeat(4);
101
- function q(e, t, n, r, i) {
102
- let a = new P(n), o = N.fromString(r);
122
+ var ue = "0123456789abcdef".repeat(4);
123
+ function de(e, t, n, r, i) {
124
+ let a = new I(n), o = F.fromString(r);
103
125
  return async (n) => {
104
- await e.messaging.gsocSend(t, a, o, n, { deferred: !1 }, K(i.writeMs));
126
+ await e.messaging.gsocSend(t, a, o, n, { deferred: !1 }, Y(i.writeMs));
105
127
  };
106
128
  }
107
129
  //#endregion
108
130
  //#region src/follower.ts
109
- var J = {
131
+ var X = {
110
132
  LIVE: "live",
111
133
  RECONNECTING: "reconnecting",
112
134
  STALLED: "stalled"
113
- }, Y = {
135
+ }, fe = {
114
136
  pollIntervalMs: 1e3,
137
+ missingReadSpacingMs: U,
115
138
  maxSlotsPerPoll: 16,
116
139
  unservedPollsBeforeProbe: 3,
117
140
  unreadablePollsBeforeFailure: 3,
@@ -129,16 +152,16 @@ var J = {
129
152
  stallAfterMs: 8e3,
130
153
  random: Math.random,
131
154
  now: Date.now
132
- }, X = class extends Error {
155
+ }, Z = class extends Error {
133
156
  constructor(e) {
134
157
  super(`the gateway keeps answering feed slot ${e} with something that is not a chunk`), this.index = e, this.name = "UnreadableGatewayError";
135
158
  }
136
- }, ae = class {
159
+ }, pe = class {
137
160
  constructor(e, t, n, r = {}, i = null) {
138
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 = {
139
- ...Y,
162
+ ...fe,
140
163
  ...r
141
- };
164
+ }, this.pacer = new W(this.settings.missingReadSpacingMs, this.settings.now);
142
165
  }
143
166
  get nextIndex() {
144
167
  return this.next;
@@ -150,7 +173,7 @@ var J = {
150
173
  return this.ceiling !== null;
151
174
  }
152
175
  start(e, t = null) {
153
- this.stop(), this.next = e, this.ceiling = t?.newest ?? null, this.nextNoteSlot = t?.nextNoteSlot ?? (this.notes ? this.notes.lastReadableSlot() + 1 : 0), this.lastNoteFoundAt = this.settings.now(), this.resetRefusals(), this.unreadablePolls = 0, this.gatewayFailures = 0, this.missed.clear(), this.status = null, this.running = !0, this.schedule(0);
176
+ this.stop(), this.next = e, this.ceiling = t?.newest ?? null, this.nextNoteSlot = t?.nextNoteSlot ?? (this.notes ? this.notes.lastReadableSlot() + 1 : 0), this.lastNoteFoundAt = this.settings.now(), this.resetRefusals(), this.unreadablePolls = 0, this.gatewayFailures = 0, this.missed.clear(), this.pacer.clear(), this.status = null, this.running = !0, this.schedule(0);
154
177
  }
155
178
  stop() {
156
179
  this.running = !1, this.generation++, this.timer &&= (clearTimeout(this.timer), null);
@@ -177,7 +200,11 @@ var J = {
177
200
  }
178
201
  }
179
202
  untilNextRead() {
180
- return this.ceiling === null || this.notes === null ? this.settings.pollIntervalMs : Math.max(0, this.notes.readableAt(this.nextNoteSlot) - this.settings.now());
203
+ let e = this.settings.now(), t = (t) => {
204
+ let n = this.pacer.readableAt(t);
205
+ return n > e ? n : e + this.settings.pollIntervalMs;
206
+ }, n = [...this.missed.keys()].map(t);
207
+ return this.notes !== null && n.push(this.notes.readableAt(this.nextNoteSlot)), this.ceiling === null && n.push(t(this.next)), Math.max(0, Math.min(...n) - e);
181
208
  }
182
209
  async readDueNotes(e, t) {
183
210
  let n = this.settings.now(), r = e.lastReadableSlot(n);
@@ -192,19 +219,24 @@ var J = {
192
219
  }
193
220
  }
194
221
  async read(e) {
222
+ let t;
195
223
  try {
196
- return await this.source.readSlot(e);
224
+ t = await this.source.readSlot(e);
197
225
  } catch (e) {
198
- if (e instanceof H) return "unreadable";
226
+ if (e instanceof K) return "unreadable";
199
227
  throw e;
200
228
  }
229
+ return t === null ? this.pacer.missed(e) : this.pacer.found(e), t;
230
+ }
231
+ async readUnnamed(e) {
232
+ return this.pacer.mayRead(e) ? this.read(e) : "held";
201
233
  }
202
234
  async walk(e) {
203
235
  for (let t = 0; t < this.settings.maxSlotsPerPoll; t++) {
204
236
  let n = this.next;
205
237
  if (this.ceiling !== null && n > this.ceiling) return t;
206
- let r = await this.read(n);
207
- if (e !== this.generation) return t;
238
+ let r = this.ceiling === null ? await this.readUnnamed(n) : await this.read(n);
239
+ if (e !== this.generation || r === "held") return t;
208
240
  if (this.ceiling !== null && (r === null || r === "unreadable")) {
209
241
  this.remember(n), this.next = n + 1;
210
242
  continue;
@@ -215,7 +247,7 @@ var J = {
215
247
  this.unreadablePolls = 0;
216
248
  continue;
217
249
  }
218
- if (this.unreadablePolls >= this.settings.unreadablePollsBeforeFailure) throw new X(n);
250
+ if (this.unreadablePolls >= this.settings.unreadablePollsBeforeFailure) throw new Z(n);
219
251
  }
220
252
  return t;
221
253
  }
@@ -225,8 +257,8 @@ var J = {
225
257
  }
226
258
  shouldProbe() {
227
259
  if (this.unservedPolls !== this.nextProbeAt) return !1;
228
- let { probeIntervalCapMs: e, pollIntervalMs: t } = this.settings, n = Math.max(1, Math.ceil(e / t));
229
- return this.nextProbeAt += Math.min(this.nextProbeAt, n), !0;
260
+ let { probeIntervalCapMs: e, pollIntervalMs: t, missingReadSpacingMs: n } = this.settings, r = Math.max(1, Math.ceil(e / Math.max(t, n)));
261
+ return this.nextProbeAt += Math.min(this.nextProbeAt, r), !0;
230
262
  }
231
263
  resetRefusals() {
232
264
  this.unservedPolls = 0, this.nextProbeAt = this.settings.unservedPollsBeforeProbe;
@@ -234,17 +266,17 @@ var J = {
234
266
  async probePast(e, t) {
235
267
  let n = /* @__PURE__ */ new Set([e]);
236
268
  for (let r of this.settings.probeDistances) {
237
- let i = e + r, a = await this.read(i);
269
+ let i = e + r, a = await this.readUnnamed(i);
238
270
  if (t !== this.generation) return !1;
239
- if (a === null || a === "unreadable") {
271
+ if (a === null || a === "unreadable" || a === "held") {
240
272
  n.add(i);
241
273
  continue;
242
274
  }
243
275
  this.resetRefusals(), this.remember(e);
244
276
  for (let r = e + 1; r < i; r++) {
245
- let e = n.has(r) ? null : await this.read(r);
277
+ let e = n.has(r) ? null : await this.readUnnamed(r);
246
278
  if (t !== this.generation) return !1;
247
- e === null || e === "unreadable" ? this.remember(r) : this.accept(r, e);
279
+ e === null || e === "unreadable" || e === "held" ? this.remember(r) : this.accept(r, e);
248
280
  }
249
281
  return this.next = i + 1, this.accept(i, a), !0;
250
282
  }
@@ -262,7 +294,7 @@ var J = {
262
294
  async readMissed(e) {
263
295
  let t = this.settings.now();
264
296
  for (let [e, n] of this.missed) t - n >= this.settings.missedExpiryMs && (this.missed.delete(e), this.events.skipped(e, "unreachable", "not served within the time a stepped-past slot is kept"));
265
- let n = [...this.missed.keys()].slice(0, this.settings.missedReadsPerPoll);
297
+ let n = [...this.missed.keys()].filter((e) => this.pacer.mayRead(e, t)).slice(0, this.settings.missedReadsPerPoll);
266
298
  for (let t of n) {
267
299
  let n = await this.read(t);
268
300
  if (e !== this.generation) return;
@@ -271,16 +303,16 @@ var J = {
271
303
  }
272
304
  }
273
305
  accept(e, t) {
274
- let n = D(t, e, this.topic);
306
+ let n = A(t, e, this.topic);
275
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);
276
308
  }
277
309
  gatewayFailed(e) {
278
- this.gatewayFailures++, this.setStatus(J.RECONNECTING), this.events.error(e);
310
+ this.gatewayFailures++, this.setStatus(X.RECONNECTING), this.events.error(e);
279
311
  }
280
312
  gatewayAnswered() {
281
313
  this.gatewayFailures = 0;
282
314
  let e = this.settings.now(), t = [...this.missed.values()].some((t) => e - t >= this.settings.stallAfterMs);
283
- this.setStatus(t ? J.STALLED : J.LIVE);
315
+ this.setStatus(t ? X.STALLED : X.LIVE);
284
316
  }
285
317
  backoffMs() {
286
318
  let { pollIntervalMs: e, backoffCapMs: t, random: n } = this.settings, r = Math.min(t, e * 2 ** this.gatewayFailures);
@@ -289,7 +321,7 @@ var J = {
289
321
  setStatus(e) {
290
322
  e !== this.status && (this.status = e, this.events.status(e));
291
323
  }
292
- }, oe = 16, se = class {
324
+ }, me = 16, he = class {
293
325
  constructor(e, t, n, r = null) {
294
326
  this.source = e, this.topic = t, this.events = n, this.notes = r, this.older = null, this.loading = null;
295
327
  }
@@ -334,7 +366,7 @@ var J = {
334
366
  try {
335
367
  return await this.source.readHead();
336
368
  } catch (e) {
337
- if (e instanceof V) return this.events.error(e), null;
369
+ if (e instanceof G) return this.events.error(e), null;
338
370
  throw e;
339
371
  }
340
372
  }
@@ -349,30 +381,30 @@ var J = {
349
381
  async loadOlderOnce() {
350
382
  let e = this.older;
351
383
  if (e === null) return [];
352
- let t = await this.source.readFile(e.ref), n = O(t, this.topic, e);
384
+ let t = await this.source.readFile(e.ref), n = j(t, this.topic, e);
353
385
  if (!n.ok) throw this.older = null, Error(`history file ${e.ref} refused (${n.reason}): ${n.detail}`);
354
386
  return this.report(n.value.skipped), this.older = n.value.prev, n.value.rows;
355
387
  }
356
388
  async newestLink(e, t) {
357
389
  let n = t === void 0 ? e : e - 1;
358
390
  if (t !== void 0) {
359
- let n = D(t, e, this.topic);
391
+ let n = A(t, e, this.topic);
360
392
  if (n.ok) return n.value.history;
361
393
  }
362
- for (let t = n; t >= Math.max(0, e - oe); t--) {
394
+ for (let t = n; t >= Math.max(0, e - me); t--) {
363
395
  let e = await this.source.readSlot(t).catch((e) => {
364
- if (e instanceof H) return null;
396
+ if (e instanceof K) return null;
365
397
  throw e;
366
398
  });
367
399
  if (e === null) continue;
368
- let n = D(e, t, this.topic);
400
+ let n = A(e, t, this.topic);
369
401
  if (n.ok) return n.value.history;
370
402
  }
371
403
  return null;
372
404
  }
373
405
  async readFile(e) {
374
406
  try {
375
- let t = O(await this.source.readFile(e.ref), this.topic, e);
407
+ let t = j(await this.source.readFile(e.ref), this.topic, e);
376
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");
377
409
  } catch (t) {
378
410
  return this.events.error(t), this.older = e, null;
@@ -381,17 +413,18 @@ var J = {
381
413
  report(e) {
382
414
  e > 0 && this.events.skipped(e);
383
415
  }
384
- }, ce = {
385
- slotMs: n,
386
- heartbeatMs: t,
416
+ }, ge = {
417
+ slotMs: C,
418
+ heartbeatMs: O,
387
419
  marginMs: 1e3,
388
420
  scanBatch: 4,
389
- clockLimitMs: 3e5
421
+ clockLimitMs: 3e5,
422
+ missingReadSpacingMs: U
390
423
  };
391
- function le(e) {
424
+ function _e(e) {
392
425
  return typeof e.readNote == "function";
393
426
  }
394
- var ue = class {
427
+ var ve = class {
395
428
  constructor(e) {
396
429
  this.limitMs = e, this.aheadAtMost = Infinity, this.trusted = !0;
397
430
  }
@@ -408,21 +441,21 @@ var ue = class {
408
441
  let e = Number.isFinite(this.aheadAtMost), t = this.trusted || !e ? Math.min(0, this.aheadAtMost) : this.aheadAtMost;
409
442
  return Math.max(-this.limitMs, Math.min(this.limitMs, t));
410
443
  }
411
- }, Z = class {
444
+ }, ye = class {
412
445
  constructor(e, t, n) {
413
446
  this.source = e, this.now = n, this.counts = {
414
447
  found: 0,
415
448
  empty: 0
416
449
  }, this.settings = {
417
- ...ce,
450
+ ...ge,
418
451
  ...t
419
- }, this.clock = new ue(this.settings.clockLimitMs);
452
+ }, this.clock = new ve(this.settings.clockLimitMs), this.pacer = new W(this.settings.missingReadSpacingMs, n);
420
453
  }
421
454
  lastReadableSlot(e = this.now()) {
422
- return T(e - this.settings.marginMs - this.clock.ms, this.settings.slotMs) - 1;
455
+ return k(e - this.settings.marginMs - this.clock.ms, this.settings.slotMs) - 1;
423
456
  }
424
457
  readableAt(e) {
425
- return w(e, this.settings.slotMs) + this.settings.marginMs + this.clock.ms;
458
+ return x(e, this.settings.slotMs) + this.settings.marginMs + this.clock.ms;
426
459
  }
427
460
  get lookBackSlots() {
428
461
  return Math.ceil(this.settings.heartbeatMs / this.settings.slotMs) + 2;
@@ -431,14 +464,15 @@ var ue = class {
431
464
  return this.settings.heartbeatMs + 2 * this.settings.slotMs + this.settings.marginMs;
432
465
  }
433
466
  async read(e) {
467
+ if (!this.pacer.mayRead(e)) return null;
434
468
  let t;
435
469
  try {
436
- t = await this.source.readNote(e);
470
+ t = await this.source.readNote(e), t === null && this.pacer.missed(e);
437
471
  } catch (e) {
438
- if (!(e instanceof H)) throw e;
472
+ if (!(e instanceof K)) throw e;
439
473
  t = null;
440
474
  }
441
- let n = t === null ? null : k(t);
475
+ let n = t === null ? null : g(t);
442
476
  return n === null ? (this.counts.empty++, null) : (this.counts.found++, this.clock.observe(n.writtenAt, this.now()), n);
443
477
  }
444
478
  async scan(e, t) {
@@ -458,17 +492,18 @@ var ue = class {
458
492
  maxResends: 5,
459
493
  reactionWindowMs: 1e3,
460
494
  isLive: () => !0
461
- }, de = class {
495
+ }, be = class {
462
496
  constructor(e, t, n, r, i = Q) {
463
- this.key = e, this.name = t, this.write = n, this.events = r, this.settings = i, this.outgoing = /* @__PURE__ */ new Map(), this.reactions = /* @__PURE__ */ new Map(), this.stopped = !1;
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;
464
498
  }
465
499
  get address() {
466
500
  return this.key.publicKey().address().toHex();
467
501
  }
468
502
  send(e) {
469
- let { message: t, bytes: n } = h(this.key, {
503
+ let { message: t, bytes: n } = l(this.key, {
470
504
  ...e,
471
- name: this.name
505
+ ...this.profile,
506
+ own: !1
472
507
  }), r = {
473
508
  message: t,
474
509
  bytes: n,
@@ -545,22 +580,26 @@ var ue = class {
545
580
  clearTimer(e) {
546
581
  e.timer &&= (clearTimeout(e.timer), null);
547
582
  }
548
- }, fe = [
583
+ }, xe = [
549
584
  1e3,
550
585
  2e3,
551
586
  4e3,
552
587
  8e3
553
- ], pe = 3;
588
+ ], Se = 3;
554
589
  function $(e) {
555
590
  return (e.startsWith("0x") ? e.slice(2) : e).toLowerCase();
556
591
  }
557
- var me = class {
592
+ var Ce = class {
558
593
  constructor(e, t = {}) {
559
- this.emitter = new B(), this.seen = /* @__PURE__ */ new Set(), this.status = null, this.generation = 0, this.running = !1, this.starting = null, this.openTimer = null, this.wakeOpen = null;
594
+ 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;
560
595
  let { user: n, infra: r } = e;
561
- this.key = new P($(n.privateKey)), this.topic = r.chatTopic, this.nickname = n.nickname, this.openRetryMs = t.openRetryMs ?? fe, this.senderSettings = {
596
+ this.key = new I($(n.privateKey)), this.topic = r.chatTopic, this.profile = {
597
+ name: n.nickname,
598
+ via: r.via,
599
+ ...n.binding ? { idb: n.binding } : {}
600
+ }, this.openRetryMs = t.openRetryMs ?? xe, this.senderSettings = {
562
601
  ...Q,
563
- isLive: () => this.status === J.LIVE,
602
+ isLive: () => this.status === X.LIVE,
564
603
  ...t.sender
565
604
  };
566
605
  let i = {
@@ -572,28 +611,28 @@ var me = class {
572
611
  ...r.noteHeartbeatMs === void 0 ? {} : { heartbeatMs: r.noteHeartbeatMs },
573
612
  ...t.notes
574
613
  };
575
- this.source = t.source ?? G(new j(r.beeUrl), $(r.chatAddress), r.chatTopic, i, a.slotMs), this.write = t.write ?? q(new j(r.writeUrl ?? r.beeUrl), r.stamp ? $(r.stamp) : ie, $(r.gsocResourceId), r.gsocTopic, i);
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);
576
615
  let o = t.follower?.now ?? (() => Date.now()), s = {
577
616
  pollIntervalMs: r.pollingInterval ?? 1e3,
578
617
  ...t.follower,
579
618
  now: o
580
619
  }, c = this.source;
581
- this.notes = le(c) ? new Z(c, a, o) : null, this.follower = new ae(this.source, this.topic, {
620
+ this.notes = _e(c) ? new ye(c, a, o) : null, this.follower = new pe(this.source, this.topic, {
582
621
  entry: (e) => this.show(e),
583
- skipped: (e, t, n) => this.emitter.emit(I.MESSAGE_SKIPPED, {
622
+ skipped: (e, t, n) => this.emitter.emit(R.MESSAGE_SKIPPED, {
584
623
  index: e,
585
624
  reason: t,
586
625
  detail: n
587
626
  }),
588
627
  status: (e) => this.setStatus(e),
589
- error: (e) => this.emitter.emit(I.ERROR, e)
590
- }, s, this.notes), this.history = new se(this.source, this.topic, {
591
- skipped: (e) => this.emitter.emit(I.MESSAGE_SKIPPED, {
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, {
592
631
  index: -1,
593
632
  reason: "history-row",
594
633
  detail: `${e} rows of a history file`
595
634
  }),
596
- error: (e) => this.emitter.emit(I.ERROR, e)
635
+ error: (e) => this.emitter.emit(R.ERROR, e)
597
636
  }, this.notes), this.sender = this.makeSender();
598
637
  }
599
638
  getEmitter() {
@@ -621,7 +660,7 @@ var me = class {
621
660
  if (!n) throw Error("a reaction names the message it reacts to");
622
661
  return this.sender.react(this.topic, n, e), null;
623
662
  }
624
- return L(this.sender.send({
663
+ return z(this.sender.send({
625
664
  topic: this.topic,
626
665
  type: t,
627
666
  target: n ?? "",
@@ -632,12 +671,12 @@ var me = class {
632
671
  return this.sender.retry(typeof e == "string" ? e : e.id);
633
672
  }
634
673
  async fetchPreviousMessages() {
635
- this.emitter.emit(I.LOADING_PREVIOUS_MESSAGES, !0);
674
+ this.emitter.emit(R.LOADING_PREVIOUS_MESSAGES, !0);
636
675
  try {
637
676
  let e = this.generation, t = await this.history.loadOlder();
638
677
  return e === this.generation ? this.showRows(t) : [];
639
678
  } finally {
640
- this.emitter.emit(I.LOADING_PREVIOUS_MESSAGES, !1);
679
+ this.emitter.emit(R.LOADING_PREVIOUS_MESSAGES, !1);
641
680
  }
642
681
  }
643
682
  hasPreviousMessages() {
@@ -647,16 +686,16 @@ var me = class {
647
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);
648
687
  }
649
688
  async open(e) {
650
- this.emitter.emit(I.LOADING_INIT, !0);
689
+ this.emitter.emit(R.LOADING_INIT, !0);
651
690
  let t = 0;
652
691
  for (; e === this.generation;) try {
653
692
  let t = await this.history.open();
654
693
  if (e !== this.generation) return;
655
- this.showRows(t.rows), this.follower.start(t.startAt, t.notes), this.emitter.emit(I.LOADING_INIT, !1);
694
+ this.showRows(t.rows), this.follower.start(t.startAt, t.notes), this.emitter.emit(R.LOADING_INIT, !1);
656
695
  return;
657
696
  } catch (n) {
658
697
  if (e !== this.generation) return;
659
- t++, this.emitter.emit(I.ERROR, n), this.setStatus(J.RECONNECTING), t === pe && this.emitter.emit(I.CRITICAL_ERROR, n), await this.waitToOpen(this.openRetryMs[Math.min(t, this.openRetryMs.length) - 1] ?? 8e3);
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);
660
699
  }
661
700
  }
662
701
  waitToOpen(e) {
@@ -669,31 +708,31 @@ var me = class {
669
708
  });
670
709
  }
671
710
  makeSender() {
672
- return new de(this.key, this.nickname, this.write, {
673
- pending: (e) => this.emitter.emit(I.MESSAGE_REQUEST_INITIATED, L(e)),
674
- written: (e) => this.emitter.emit(I.MESSAGE_REQUEST_UPLOADED, L(e)),
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)),
675
714
  failed: (e, t) => {
676
- this.emitter.emit(I.ERROR, t), this.emitter.emit(I.MESSAGE_REQUEST_ERROR, L(e));
715
+ this.emitter.emit(R.ERROR, t), this.emitter.emit(R.MESSAGE_REQUEST_ERROR, z(e));
677
716
  },
678
717
  confirmed: () => {}
679
718
  }, this.senderSettings);
680
719
  }
681
720
  show(e) {
682
- this.seen.has(e.seq) || (this.seen.add(e.seq), this.sender.confirm(e.msg), this.emitter.emit(I.MESSAGE_RECEIVED, R(e)));
721
+ this.seen.has(e.seq) || (this.seen.add(e.seq), this.sender.confirm(e.msg), this.emitter.emit(R.MESSAGE_RECEIVED, B(e)));
683
722
  }
684
723
  showRows(e) {
685
724
  let t = [];
686
725
  for (let n of e) {
687
726
  if (this.seen.has(n.seq)) continue;
688
727
  this.seen.add(n.seq), this.sender.confirm(n.msg);
689
- let e = R(n);
690
- t.push(e), this.emitter.emit(I.MESSAGE_RECEIVED, e);
728
+ let e = B(n);
729
+ t.push(e), this.emitter.emit(R.MESSAGE_RECEIVED, e);
691
730
  }
692
731
  return t;
693
732
  }
694
733
  setStatus(e) {
695
- e !== this.status && (this.status = e, this.emitter.emit(I.STATUS, e));
734
+ e !== this.status && (this.status = e, this.emitter.emit(R.STATUS, e));
696
735
  }
697
736
  };
698
737
  //#endregion
699
- export { B as ChatEmitter, e as ChatMessageError, t as DEFAULT_NOTE_HEARTBEAT_MS, n as DEFAULT_NOTE_SLOT_MS, I as EVENTS, J as FeedStatus, V as HeadLookupTimeoutError, r as MAX_ENTRY_BYTES, i as MAX_MESSAGE_BYTES, a as MAX_NAME_CHARACTERS, o as MAX_NOTE_BYTES, s as MAX_TEXT_CHARACTERS, c as MAX_TOPIC_CHARACTERS, l as MESSAGE_VERSION, u as MessageType, d as NOTE_VERSION, me as SwarmChat, X as UnreadableGatewayError, H as UnreadableSlotError, f as chatMessageSchema, p as checkChatMessage, m as countCharacters, h as createChatMessage, g as encodeChatMessage, _ as encodeSlotNote, v as feedEntrySchema, ee as hasValidSignature, te as historyFileSchema, y as historyLinkSchema, ne as historyRowSchema, b as newMessageId, x as noteAddress, S as noteIdentifier, C as noteIdentifierText, w as noteSlotEnd, T as noteSlotOf, E as parseChatMessage, D as parseFeedEntry, O as parseHistoryFile, k as parseSlotNote, A as signedBytes, re as slotNoteSchema };
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;