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