@solarpunkltd/swarm-chat-js 8.0.0 → 9.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/README.md CHANGED
@@ -6,8 +6,8 @@ that feed. The browser talks only to a Bee node or gateway, never to a web serve
6
6
 
7
7
  The library needs its server,
8
8
  [Solar-Punk-Ltd/swarm-chat-aggregator-js](https://github.com/Solar-Punk-Ltd/swarm-chat-aggregator-js), which listens on
9
- the inbox and writes the feed. Version 8 of the library reads and writes the v8 message format only, and a v7 message
10
- fails its shape check.
9
+ the inbox and writes the feed. Version 9 of the library reads and writes the v9 message format only, and a message of any
10
+ earlier version fails its shape check.
11
11
 
12
12
  ## How it works
13
13
 
@@ -74,25 +74,26 @@ await chat.stop();
74
74
 
75
75
  ## Settings
76
76
 
77
- | Setting | Meaning |
78
- | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
79
- | `user.privateKey` | Signs every message. A viewer that only reads may pass any key. |
80
- | `user.nickname` | The name on every message, 1 to 20 characters. Nothing can be sent without one. |
81
- | `user.binding` | Optional. A signed-in viewer's Swarm ID chat binding, `{ msg, sig }`, for the chat address of `user.privateKey`. Every message then carries it. |
82
- | `infra.beeUrl` | The Bee node or gateway the chat is read through, and written through when `infra.writeUrl` is not set. |
83
- | `infra.writeUrl` | Optional. The Bee node or gateway the inbox writes go through, such as a write gateway that stamps them, when they go somewhere other than the reads. |
84
- | `infra.stamp` | The batch the inbox writes are stamped with. Left out for a gateway that stamps writes itself. |
85
- | `infra.via` | Required. Who pays for the inbox writes, `MessageVia.GATEWAY` or `MessageVia.OWN_STAMP`, as every message says in `via`. |
86
- | `infra.gsocTopic` | The inbox's identifier string, the same for every chat. |
87
- | `infra.gsocResourceId` | The mined key every sender signs inbox writes with. The server's operator mines it. |
88
- | `infra.chatTopic` | The chat's topic, which every message carries and the feed is named by. |
89
- | `infra.chatAddress` | The server's feed owner address. |
90
- | `infra.pollingInterval` | The shortest wait between two polls, and the first wait after the gateway failed, 1,000 ms by default. |
91
- | `infra.socReadTimeout` | One feed slot read, 5,000 ms by default. |
92
- | `infra.feedReadTimeout` | The head lookup and a history file download, 15,000 ms by default. A head lookup that runs out of time reads the chat from slot 0. |
93
- | `infra.gsocWriteTimeout` | One inbox write, 10,000 ms by default. |
94
- | `infra.noteSlotMs` | The server's `NOTE_SLOT_MS`, 2,000 ms by default. It is part of every note's address, so a different value finds no notes and polls instead. |
95
- | `infra.noteHeartbeatMs` | The server's `NOTE_HEARTBEAT_MS`, 30,000 ms by default, which sets how far back an opening looks for a note. |
77
+ | Setting | Meaning |
78
+ | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
79
+ | `user.privateKey` | Signs every message. A viewer that only reads may pass any key. |
80
+ | `user.nickname` | The name on every message, 1 to 20 characters, not ending in `.eth` as a reader sees it. Nothing can be sent without one. |
81
+ | `user.binding` | Optional. A signed-in viewer's Swarm ID chat binding, `{ msg, sig }`, for the chat address of `user.privateKey`. Every message then carries it. |
82
+ | `user.walletLink` | Optional, only with `user.binding`. The viewer's Swarm ID wallet link, `{ msg, wsig, asig }`, for the binding's account. Every message then carries it. |
83
+ | `infra.beeUrl` | The Bee node or gateway the chat is read through, and written through when `infra.writeUrl` is not set. |
84
+ | `infra.writeUrl` | Optional. The Bee node or gateway the inbox writes go through, such as a write gateway that stamps them, when they go somewhere other than the reads. |
85
+ | `infra.stamp` | The batch the inbox writes are stamped with. Left out for a gateway that stamps writes itself. |
86
+ | `infra.via` | Required. Who pays for the inbox writes, `MessageVia.GATEWAY` or `MessageVia.OWN_STAMP`, as every message says in `via`. |
87
+ | `infra.gsocTopic` | The inbox's identifier string, the same for every chat. |
88
+ | `infra.gsocResourceId` | The mined key every sender signs inbox writes with. The server's operator mines it. |
89
+ | `infra.chatTopic` | The chat's topic, which every message carries and the feed is named by. |
90
+ | `infra.chatAddress` | The server's feed owner address. |
91
+ | `infra.pollingInterval` | The shortest wait between two polls, and the first wait after the gateway failed, 1,000 ms by default. |
92
+ | `infra.socReadTimeout` | One feed slot read, 5,000 ms by default. |
93
+ | `infra.feedReadTimeout` | The head lookup and a history file download, 15,000 ms by default. A head lookup that runs out of time reads the chat from slot 0. |
94
+ | `infra.gsocWriteTimeout` | One inbox write, 10,000 ms by default. |
95
+ | `infra.noteSlotMs` | The server's `NOTE_SLOT_MS`, 2,000 ms by default. It is part of every note's address, so a different value finds no notes and polls instead. |
96
+ | `infra.noteHeartbeatMs` | The server's `NOTE_HEARTBEAT_MS`, 30,000 ms by default, which sets how far back an opening looks for a note. |
96
97
 
97
98
  ## Methods
98
99
 
@@ -133,7 +134,7 @@ follow `MESSAGE_REQUEST_ERROR` for the same `id`, and a viewer settles on the re
133
134
  A `MessageData` has `id`, `type`, `message` (the text or emoji), `username`, `address`, `timestamp` (the server's
134
135
  receive time, or the sender's clock while pending), `targetMessageId` for a reply or reaction, `index` (the feed index,
135
136
  -1 while pending) and `signedMessage`, the message exactly as its sender signed it. Everything else the message says,
136
- its topic, its signature, the sender's clock, `via`, `own` and the binding, is read from `signedMessage`, and a page
137
+ its topic, its signature, the sender's clock, `via` and the binding, is read from `signedMessage`, and a page
137
138
  that shows who sent it hands `signedMessage` to `verifyChatMessage`. See [Verifying](#verifying).
138
139
 
139
140
  ## The message, for servers and tools
@@ -151,27 +152,28 @@ else count(check.reason);
151
152
 
152
153
  A message is a JSON object of at most 3,072 bytes of UTF-8, its fields in this order:
153
154
 
154
- | Field | Meaning |
155
- | -------- | ------------------------------------------------------------------------------------------------------------ |
156
- | `v` | `8` |
157
- | `topic` | The chat's topic, 1 to 128 characters |
158
- | `id` | A random id, 32 lowercase hex characters |
159
- | `type` | `text`, `thread` (a reply, `target` is the parent) or `reaction` (`target` is the message, `text` the emoji) |
160
- | `target` | The id it refers to, or `""` for a text |
161
- | `text` | 1 to 500 characters |
162
- | `name` | 1 to 20 characters |
163
- | `addr` | The sender's chat address, 40 lowercase hex characters without `0x` |
164
- | `ts` | The sender's clock in milliseconds |
165
- | `via` | Who paid for the inbox write: `gateway` (the gateway's stamp) or `own-stamp` (the sender's own) |
166
- | `own` | `true` when the sender also keeps a copy of the message in its own feed |
167
- | `idb` | Only for a signed-in sender: its Swarm ID chat binding, `{ msg, sig }` |
168
- | `sig` | 130 lowercase hex characters of r, s and v, with v 27 or 28 and s in the lower half |
155
+ | Field | Meaning |
156
+ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
157
+ | `v` | `9` |
158
+ | `topic` | The chat's topic, 1 to 128 characters |
159
+ | `id` | A random id, 32 lowercase hex characters |
160
+ | `type` | `text`, `thread` (a reply, `target` is the parent) or `reaction` (`target` is the message, `text` the emoji) |
161
+ | `target` | The id it refers to, or `""` for a text |
162
+ | `text` | 1 to 500 characters |
163
+ | `name` | 1 to 20 characters, none a Unicode format or control character (`\p{Cf}`, `\p{Cc}`) but U+200C and U+200D, no blank letter, not ending in `.eth` as a reader sees it |
164
+ | `addr` | The sender's chat address, 40 lowercase hex characters without `0x` |
165
+ | `ts` | The sender's clock in milliseconds |
166
+ | `via` | Who paid for the inbox write: `gateway` (the gateway's stamp) or `own-stamp` (the sender's own) |
167
+ | `idb` | Only for a signed-in sender: its Swarm ID chat binding, `{ msg, sig }` |
168
+ | `wl` | Only beside `idb`, for a sender who shows an ENS name: its Swarm ID wallet link, `{ msg, wsig, asig }` |
169
+ | `sig` | 130 lowercase hex characters of r, s and v, with v 27 or 28 and s in the lower half |
169
170
 
170
171
  Characters are counted as Unicode code points, so an emoji counts once, and `countCharacters` counts the same way for
171
172
  a composer. The signed bytes are the UTF-8 of
172
- `JSON.stringify([8, topic, id, type, target, text, name, addr, ts, via, own, idb?.msg ?? '', idb?.sig ?? ''])`, signed
173
- with bee-js's `PrivateKey.sign` and checked with `Signature.recoverPublicKey`, both over the raw bytes. So `via`, `own`
174
- and the binding cannot be changed or taken off without breaking the signature. Every signature has a second valid
173
+ `JSON.stringify([9, topic, id, type, target, text, name, addr, ts, via, idb?.msg ?? '', idb?.sig ?? ''])`, with
174
+ `wl.msg`, `wl.wsig` and `wl.asig` appended to the array when the message carries a wallet link, signed with bee-js's
175
+ `PrivateKey.sign` and checked with `Signature.recoverPublicKey`, both over the raw bytes. So `via`, the binding
176
+ and the wallet link cannot be changed, added or taken off without breaking the signature. Every signature has a second valid
175
177
  spelling, s replaced by n - s with v flipped, and bee-js reads any v but 27 as 28, so the check refuses all but the
176
178
  low s spelling with v 27 or 28, the one bee-js signs. One message has one valid signature.
177
179
 
@@ -197,6 +199,33 @@ only with `allowLocalHttp`), the chat address is `0x` and 40 lowercase hex chara
197
199
  milliseconds. `sig` is EIP-191 `personal_sign` over `msg`, written as the fork writes it: `0x` and 130 lowercase hex
198
200
  characters of r, s and v, v 27 or 28 and s in the lower half. Recovering it gives the account's address.
199
201
 
202
+ ### The Swarm ID wallet link
203
+
204
+ Swarm ID never tells a site the wallet an account is secured with. A person who wants readers to see their ENS name
205
+ turns on "Show my ENS name on sites" there, and Swarm ID then gives the site a wallet link: the statement, signed by the
206
+ wallet and countersigned by the account's own key, that the two belong to the same person. Its canonical description
207
+ is `docs/Wallet-Link.md` in the Swarm ID fork, solarpunk-id, and this library reads it exactly as the fork's
208
+ `verifyWalletLink` does, without importing the fork. Swarm ID hands it over as
209
+ `{ message, walletSignature, accountSignature }`, and a message carries it as `{ msg, wsig, asig }`. `msg` is five lines
210
+ joined by `\n`:
211
+
212
+ ```text
213
+ Swarm ID wallet link v1
214
+ I link this wallet to the Swarm ID account below, so sites may show my ENS name beside its messages.
215
+ Account: 0x<the binding's account>
216
+ Wallet: 0x<the wallet>
217
+ Date: 2026-10-15T12:00:00.000Z
218
+ ```
219
+
220
+ The second line is read exactly. It is there because a wallet shows the person only the text it signs, so the sentence
221
+ tells them what the signature does. Both addresses are `0x` and 40 lowercase hex characters, and the date is ISO 8601
222
+ UTC with milliseconds. `wsig` and
223
+ `asig` are EIP-191 `personal_sign` over `msg` by the wallet and by the account, each `0x` and 130 lowercase hex
224
+ characters of r, s and v, v 27 or 28 and s in the lower half.
225
+
226
+ A message carries a link only beside its binding, and the link counts toward the 3,072 byte cap. The largest message
227
+ with a binding and a link is 2,376 bytes.
228
+
200
229
  ### Verifying
201
230
 
202
231
  `verifyChatMessage(value, { origin, allowLocalHttp? })` checks a message's shape and its signature, and then, when it
@@ -205,6 +234,13 @@ recovers an account, and its site is `origin`. It returns `{ ok: true, message,
205
234
  `{ account, site, date }` for a signed-in sender and `null` for a guest. A message whose binding fails is refused with
206
235
  the reason `binding` and is never shown as a guest.
207
236
 
237
+ When the message also carries a wallet link, the link's text must be those five lines, its account the binding's
238
+ account, its wallet signature must recover its wallet and its account signature its account. `identity` then also has
239
+ `wallet`, the checked wallet address. A link that fails refuses the message with the reason `binding` too, its detail
240
+ starting `wallet link:`. The check looks nothing up. A page that shows an ENS name takes `identity.wallet` to its own
241
+ lookup, such as the fork's `resolveVerifiedEnsName`, which requires the wallet's reverse record and the name's forward
242
+ record to agree, over an Ethereum endpoint the page names.
243
+
208
244
  `origin` is required, the bare origin of the site whose chat this is, such as `https://example.com`. A binding signed
209
245
  for one site therefore never passes in another site's chat because a caller left the origin out. A JavaScript caller
210
246
  that passes none anyway gets every bound message refused as `binding`. The server passes its configured site origin,
@@ -223,24 +259,31 @@ entry's `msg` or, while pending, the message as it was signed. It never throws,
223
259
 
224
260
  ### The own feed
225
261
 
226
- A sender that also keeps a copy of each message it sends says so with `own: true`. The copies live in a feed owned by
227
- the sender's chat address `addr`, under the topic `ownFeedTopic(chatTopic)`, which is `swarm-chat-own-feed-v1:` and the
228
- chat's topic, turned into a feed topic with `Topic.fromString` as the chat's own feed is. This library does not write
229
- that feed yet, so `SwarmChat` always sends `own: false`.
230
-
231
- | Export | Use |
232
- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
233
- | `parseChatMessage(bytes, { origin })` | The server's check of a raw payload: byte cap, UTF-8, JSON, then `verifyChatMessage`. Never throws. |
234
- | `verifyChatMessage(value, { origin })` | Shape, signature and binding of a parsed object, with the sender's identity. Never throws. |
235
- | `createChatMessage(key, draft)` | Builds and signs, throwing a `ChatMessageError` for anything the check would refuse. `via` is required. |
236
- | `MessageType`, `MessageVia` | The values of `type` and `via`. |
237
- | `checkChatBinding(binding, addr, options?)`, `chatBindingSchema` | The binding check on its own and its shape. Its `origin` is optional, for a sender checking its own binding. |
238
- | `ownFeedTopic(chatTopic)`, `OWN_FEED_TOPIC_PREFIX` | The topic of a sender's own feed of copies. |
239
- | `chatMessageSchema`, `hasValidSignature`, `signedBytes`, `encodeChatMessage` | The parts. |
240
- | `feedEntrySchema`, `parseFeedEntry` | The feed entry, `{v, seq, at, msg, history}`. |
241
- | `historyFileSchema`, `parseHistoryFile` | The history file, `{v, topic, fromSeq, toSeq, messages, prev}`. |
242
-
243
- The feed entry and the history file carry `v` 8 like the message. A feed entry, at most 4,096 bytes, holds a message at
262
+ A sender may also keep a copy of each message it sends in a feed of its own, so anyone can compare that feed with the
263
+ chat. The copies live in a feed owned by the sender's chat address `addr`, under the topic `ownFeedTopic(chatTopic)`,
264
+ which is `swarm-chat-own-feed-v1:` and the chat's topic, turned into a feed topic with `Topic.fromString` as the chat's
265
+ own feed is. A copy is the signed payload itself. The message says nothing about a copy, so whether one exists is read
266
+ from that feed.
267
+
268
+ The library does not write the copy. A page that keeps copies passes its own inbox write, a `GsocWrite`, as
269
+ `new SwarmChat(settings, { write })`. It is handed the signed payload, the same bytes on every resend, and writes the
270
+ copy beside the inbox write.
271
+
272
+ | Export | Use |
273
+ | ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
274
+ | `parseChatMessage(bytes, { origin })` | The server's check of a raw payload: byte cap, UTF-8, JSON, then `verifyChatMessage`. Never throws. |
275
+ | `verifyChatMessage(value, { origin })` | Shape, signature and binding of a parsed object, with the sender's identity. Never throws. |
276
+ | `displayNameProblem(name)` | `null` for a name a message may carry, else `'length'` (not 1 to 20 characters), `'invisible'` (a format or control character) or `'ens-like'` (reads as ending in `.eth`). |
277
+ | `createChatMessage(key, draft)` | Builds and signs, throwing a `ChatMessageError` for anything the check would refuse. `via` is required. |
278
+ | `MessageType`, `MessageVia` | The values of `type` and `via`. |
279
+ | `checkChatBinding(binding, addr, options?)`, `chatBindingSchema` | The binding check on its own and its shape. Its `origin` is optional, for a sender checking its own binding. |
280
+ | `checkWalletLink(link, account)`, `walletLinkSchema` | The wallet link check on its own, for the binding's account, and its shape. |
281
+ | `ownFeedTopic(chatTopic)`, `OWN_FEED_TOPIC_PREFIX` | The topic of a sender's own feed of copies. |
282
+ | `chatMessageSchema`, `hasValidSignature`, `signedBytes`, `encodeChatMessage` | The parts. |
283
+ | `feedEntrySchema`, `parseFeedEntry` | The feed entry, `{v, seq, at, msg, history}`. |
284
+ | `historyFileSchema`, `parseHistoryFile` | The history file, `{v, topic, fromSeq, toSeq, messages, prev}`. |
285
+
286
+ The feed entry and the history file carry `v` 9 like the message. A feed entry, at most 4,096 bytes, holds a message at
244
287
  the byte cap inside its largest wrapper.
245
288
 
246
289
  ## Slot notes, for servers and tools
@@ -269,6 +312,44 @@ notes are found it trusts its own clock, moving reads earlier only when that bou
269
312
  no note is found for longer than a heartbeat, it waits out the whole bound from then on, which is never early. A
270
313
  clock that runs behind sees every stamp as old as it expects, so its messages arrive as late as it runs behind.
271
314
 
315
+ ## Changes in 9.0
316
+
317
+ - A message may carry the sender's Swarm ID wallet link, `wl`, beside its binding, signed with the rest. A verified
318
+ link puts the wallet on `identity.wallet`, and a link that fails refuses the message as `binding`.
319
+ - The message is version 9, its `v` and the first element of its signed bytes both `9`, and so is every feed entry and
320
+ history file. A message, entry or history file of version 8 fails its shape check, whether or not it carries `own`,
321
+ so a reader and a server on 9.0 never read one that 8.x wrote, and the break shows as a version rather than as a
322
+ missing field.
323
+ - The message no longer carries `own`. It is gone from the shape, the signed bytes and the payload, and `infra.own` and
324
+ the draft's `own` are gone with it. Whether a sender keeps a copy is read from its own feed. A message that carries
325
+ `own`, which is every message 8.0 and 8.1 signed, is refused as `shape`, and so is a feed entry or history row that
326
+ holds one.
327
+ - A name with a Unicode format or control character, such as the right-to-left override U+202E or a zero width space,
328
+ is refused as `shape`, since it can make one name look like another. The zero width non-joiner U+200C and the zero
329
+ width joiner U+200D are allowed, because Persian and Indic names and joined emoji such as a family need them. The
330
+ blank letters and marks are refused with them, since they show as nothing and have no honest use in a name: the
331
+ braille blank U+2800, the Hangul fillers U+115F, U+1160, U+3164 and U+FFA0, the combining grapheme joiner U+034F and
332
+ the Khmer inherent vowels U+17B4 and U+17B5. Variation selectors such as U+FE0F stay allowed, since emoji need them.
333
+ - A name that reads as ending in `.eth` is refused as `shape`, since a page shows a verified ENS name where the
334
+ chosen name would be and a chosen one could pass for it. The check reads a skeleton of the name, the name as a
335
+ reader sees it: NFKD normalised, so fullwidth and other compatibility forms fold and an accented letter loses its
336
+ accent, with every character Unicode's confusables data maps to the full stop read as `.` (the Arabic-Indic zeros,
337
+ the Syriac full stops and the musical augmentation dot among them) and the ideographic full stop U+3002 too, since
338
+ ENS reads it as one, without the Unicode default ignorable code points, the braille blank or any nonspacing or
339
+ enclosing mark, with the letters the confusables data maps to `e`, `t` or `h` read as those letters (Cyrillic `е`,
340
+ `т`, `н` and `Т`, Armenian `հ` and Greek `Ε`, `Τ`, `Η` among them), lower-cased, trimmed, and stripped of trailing
341
+ spaces and dots. The name is refused when that skeleton ends in `.eth`. So `vitalik.eth`, `Vitalik.ETH`,
342
+ `vitalik.eth.`, `vitalik.еth` (Cyrillic `е`), `vitalik٠eth` (Arabic-Indic zero), `vitalik.eth` followed by U+FE0F,
343
+ `J.Eth` and `VITALIK.ETH` are all refused, while `vitalik eth`, `vitalik-eth`, `vitalik_eth`, `vitalik·eth`,
344
+ `Kenneth`, `Seth`, `Ethan` and `J.Ethan` pass.
345
+ - `SwarmChat` takes `user.walletLink`, `createChatMessage` takes `wl`, and `checkWalletLink` checks a link on its own.
346
+ - A server on 8.x refuses every version 9 message as `shape`. Update the server before any page sends one.
347
+
348
+ ## Changes in 8.1
349
+
350
+ - `infra.own` signs every message with `own: true`, for a page whose write keeps a copy in the sender's own feed. Left
351
+ out, messages say `own: false` as in 8.0.
352
+
272
353
  ## Changes in 8.0
273
354
 
274
355
  - The v8 message adds `via`, `own` and, for a signed-in sender, `idb`, its Swarm ID chat binding, all signed. A v7
package/dist/chat.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ChatEmitter, type MessageData } from './events.js';
2
2
  import { FeedStatus, type FollowerSettings } from './follower.js';
3
- import { MessageType, type ChatBinding, type MessageVia } from './message/index.js';
3
+ import { MessageType, type ChatBinding, type MessageVia, type WalletLink } from './message/index.js';
4
4
  import { type NoteSettings } from './notes.js';
5
5
  import { type GsocWrite, type SenderSettings } from './sender.js';
6
6
  import { type ChatSource } from './swarm.js';
@@ -15,6 +15,13 @@ export interface ChatSettings {
15
15
  * carries it, and a reader that verifies it shows the account. Left out for a guest.
16
16
  */
17
17
  binding?: ChatBinding;
18
+ /**
19
+ * The Swarm ID wallet link of a signed-in viewer who shows an ENS name, whose account must be `binding`'s. Swarm
20
+ * ID's `connectionInfo.identity.walletLink` gives it as `{ message, walletSignature, accountSignature }`, passed
21
+ * here as `{ msg, wsig, asig }`. Every message then carries it, and a reader that verifies it learns the wallet.
22
+ * Left out otherwise, and refused without a binding.
23
+ */
24
+ walletLink?: WalletLink;
18
25
  };
19
26
  infra: {
20
27
  /** The Bee node or gateway the chat is read through, and written through too when `writeUrl` is not set. */
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./message-Bmwh3SCs.cjs");let t=require("@ethersphere/bee-js");var n={LOADING_INIT:`loadingInit`,LOADING_PREVIOUS_MESSAGES:`loadingPreviousMessages`,MESSAGE_RECEIVED:`messageReceived`,MESSAGE_REQUEST_INITIATED:`messageRequestInitiated`,MESSAGE_REQUEST_UPLOADED:`messageRequestUploaded`,MESSAGE_REQUEST_ERROR:`messageRequestError`,CRITICAL_ERROR:`criticalError`,STATUS:`status`,MESSAGE_SKIPPED:`messageSkipped`,ERROR:`error`};function r(e){return a(e,-1,e.ts)}function i(e){return a(e.msg,e.seq,e.at)}function a(e,t,n){return{id:e.id,type:e.type,message:e.text,username:e.name,address:e.addr,timestamp:n,...e.target?{targetMessageId:e.target}:{},index:t,signedMessage:e}}var o=class{constructor(){this.listeners=new Map,this.on=(e,t)=>{this.listeners.set(e,[...this.listeners.get(e)??[],t])},this.off=(e,t)=>{this.listeners.set(e,(this.listeners.get(e)??[]).filter(e=>e!==t))},this.cleanAll=()=>{this.listeners.clear()}}emit(e,t){for(let n of this.listeners.get(e)??[])try{n(t)}catch(t){console.error(`a listener for ${e} threw`,t)}}},s=2e4,c=class{constructor(e,t){this.spacingMs=e,this.now=t,this.missedAt=new Map}readableAt(e,t=this.now()){let n=this.missedAt.get(e);return n===void 0||this.expired(n,t)?-1/0:n+this.spacingMs}mayRead(e,t=this.now()){return t>=this.readableAt(e,t)}missed(e,t=this.now()){for(let[e,n]of this.missedAt)this.expired(n,t)&&this.missedAt.delete(e);this.missedAt.set(e,t)}found(e){this.missedAt.delete(e)}clear(){this.missedAt.clear()}expired(e,t){return e>t||t-e>=this.spacingMs}},l=class extends Error{constructor(e){super(`the feed head lookup did not answer in time`,e),this.name=`HeadLookupTimeoutError`}},u=class extends Error{constructor(e,t){super(`feed slot ${e} was served but could not be read`,t),this.index=e,this.name=`UnreadableSlotError`}};function d(e){return e instanceof t.BeeResponseError&&(e.status===404||e.status===500)}async function f(e,n){try{return await n()}catch(n){if(d(n))return null;throw n instanceof t.BeeResponseError?n:new u(e,{cause:n})}}function p(n,r,i,a,o=e.n){let s=t.Topic.fromString(i),c=e=>n.feed.makeReader(s,r,m(e));return{readNote:t=>f(t,async()=>(await n.soc.makeReader(r,m(a.slotReadMs)).download(e.s(i,o,t))).payload.toUint8Array()),readSlot:e=>f(e,async()=>(await c(a.slotReadMs).downloadPayload({index:e})).payload.toUint8Array()),async readHead(){let e=m(a.feedReadMs);try{let{payload:t,feedIndex:i}=await n.feed.makeReader(s,r,e).downloadPayload();return{index:Number(i.toBigInt()),payload:t.toUint8Array()}}catch(t){if(d(t))return null;throw e.signal?.aborted?new l({cause:t}):t}},async readFile(e){return(await n.data.download(e,void 0,m(a.feedReadMs))).toUint8Array()}}}function m(e){return{signal:AbortSignal.timeout(e)}}var h=`0123456789abcdef`.repeat(4);function g(e,n,r,i,a){let o=new t.PrivateKey(r),s=t.Identifier.fromString(i);return async t=>{await e.messaging.gsocSend(n,o,s,t,{deferred:!1},m(a.writeMs))}}var _={LIVE:`live`,RECONNECTING:`reconnecting`,STALLED:`stalled`},v={pollIntervalMs:1e3,missingReadSpacingMs:s,maxSlotsPerPoll:16,unservedPollsBeforeProbe:3,unreadablePollsBeforeFailure:3,probeIntervalCapMs:6e4,probeDistances:[1,2,4,8],missedLimit:32,missedReadsPerPoll:4,missedExpiryMs:3e5,backoffCapMs:8e3,stallAfterMs:8e3,random:Math.random,now:Date.now},y=class extends Error{constructor(e){super(`the gateway keeps answering feed slot ${e} with something that is not a chunk`),this.index=e,this.name=`UnreadableGatewayError`}},b=class{constructor(e,t,n,r={},i=null){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=new Map,this.timer=null,this.generation=0,this.running=!1,this.status=null,this.settings={...v,...r},this.pacer=new c(this.settings.missingReadSpacingMs,this.settings.now)}get nextIndex(){return this.next}get missedIndices(){return[...this.missed.keys()]}get ledByNotes(){return this.ceiling!==null}start(e,t=null){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)}stop(){this.running=!1,this.generation++,this.timer&&=(clearTimeout(this.timer),null)}schedule(e){let t=this.generation;this.timer=setTimeout(()=>{this.timer=null,this.poll(t)},e)}async poll(e){let t=0,n=!1;try{this.notes!==null&&await this.readDueNotes(this.notes,e),t=await this.walk(e),await this.readMissed(e)}catch(t){n=!0,e===this.generation&&this.gatewayFailed(t)}if(e===this.generation&&this.running){if(n){this.schedule(this.backoffMs());return}this.gatewayAnswered(),this.schedule(t>=this.settings.maxSlotsPerPoll?0:this.untilNextRead())}}untilNextRead(){let e=this.settings.now(),t=t=>{let n=this.pacer.readableAt(t);return n>e?n:e+this.settings.pollIntervalMs},n=[...this.missed.keys()].map(t);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)}async readDueNotes(e,t){let n=this.settings.now(),r=e.lastReadableSlot(n);if(r<this.nextNoteSlot)return;let i=Math.max(this.nextNoteSlot,r-e.lookBackSlots+1),a=await e.scan(r,i);if(t===this.generation){if(this.nextNoteSlot=r+1,a){this.lastNoteFoundAt=n,this.ceiling=Math.max(this.ceiling??-1,a.note.newest,this.next-1);return}n-this.lastNoteFoundAt>=e.silenceMs&&(this.lastNoteFoundAt=n,e.clock.distrust(),this.nextNoteSlot=Math.min(this.nextNoteSlot,e.lastReadableSlot(n)+1))}}async read(e){let t;try{t=await this.source.readSlot(e)}catch(e){if(e instanceof u)return`unreadable`;throw e}return t===null?this.pacer.missed(e):this.pacer.found(e),t}async readUnnamed(e){return this.pacer.mayRead(e)?this.read(e):`held`}async walk(e){for(let t=0;t<this.settings.maxSlotsPerPoll;t++){let n=this.next;if(this.ceiling!==null&&n>this.ceiling)return t;let r=this.ceiling===null?await this.readUnnamed(n):await this.read(n);if(e!==this.generation||r===`held`)return t;if(this.ceiling!==null&&(r===null||r===`unreadable`)){this.remember(n),this.next=n+1;continue}if(r===null||r===`unreadable`){if(t===0){if(this.unservedPolls++,this.unreadablePolls=r===`unreadable`?this.unreadablePolls+1:0,this.shouldProbe()&&await this.probePast(n,e)){this.unreadablePolls=0;continue}if(this.unreadablePolls>=this.settings.unreadablePollsBeforeFailure)throw new y(n)}return t}this.resetRefusals(),this.unreadablePolls=0,this.next=n+1,this.accept(n,r)}return this.settings.maxSlotsPerPoll}shouldProbe(){if(this.unservedPolls!==this.nextProbeAt)return!1;let{probeIntervalCapMs:e,pollIntervalMs:t,missingReadSpacingMs:n}=this.settings,r=Math.max(1,Math.ceil(e/Math.max(t,n)));return this.nextProbeAt+=Math.min(this.nextProbeAt,r),!0}resetRefusals(){this.unservedPolls=0,this.nextProbeAt=this.settings.unservedPollsBeforeProbe}async probePast(e,t){let n=new Set([e]);for(let r of this.settings.probeDistances){let i=e+r,a=await this.readUnnamed(i);if(t!==this.generation)return!1;if(a===null||a===`unreadable`||a===`held`){n.add(i);continue}this.resetRefusals(),this.remember(e);for(let r=e+1;r<i;r++){let e=n.has(r)?null:await this.readUnnamed(r);if(t!==this.generation)return!1;e===null||e===`unreadable`||e===`held`?this.remember(r):this.accept(r,e)}return this.next=i+1,this.accept(i,a),!0}return!1}remember(e){if(!this.missed.has(e)){if(this.missed.size>=this.settings.missedLimit){this.events.skipped(e,`unreachable`,`stepped past with the retry list full`);return}this.missed.set(e,this.settings.now())}}async readMissed(e){let t=this.settings.now();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`));let n=[...this.missed.keys()].filter(e=>this.pacer.mayRead(e,t)).slice(0,this.settings.missedReadsPerPoll);for(let t of n){let n=await this.read(t);if(e!==this.generation)return;let r=this.missed.get(t);this.missed.delete(t),n!==null&&n!==`unreadable`?this.accept(t,n):r!==void 0&&this.missed.set(t,r)}}accept(t,n){let r=e.v(n,t,this.topic);r.ok?(this.notes?.clock.observe(r.value.at,this.settings.now()),this.events.entry(r.value)):this.events.skipped(t,r.reason,r.detail)}gatewayFailed(e){this.gatewayFailures++,this.setStatus(_.RECONNECTING),this.events.error(e)}gatewayAnswered(){this.gatewayFailures=0;let e=this.settings.now(),t=[...this.missed.values()].some(t=>e-t>=this.settings.stallAfterMs);this.setStatus(t?_.STALLED:_.LIVE)}backoffMs(){let{pollIntervalMs:e,backoffCapMs:t,random:n}=this.settings,r=Math.min(t,e*2**this.gatewayFailures);return r/2+n()*r/2}setStatus(e){e!==this.status&&(this.status=e,this.events.status(e))}},x=16,S=class{constructor(e,t,n,r=null){this.source=e,this.topic=t,this.events=n,this.notes=r,this.older=null,this.loading=null}async open(){this.older=null;let e=await this.newestNote();if(e!==null)return this.openAt(e.newest,e);let t=await this.readHead();return t===null?{startAt:0,rows:[],notes:null}:this.openAt(t.index,null,t.payload)}async newestNote(){if(this.notes===null)return null;let e=this.notes.lastReadableSlot(),t=await this.notes.scan(e,e-this.notes.lookBackSlots+1);return t===null?null:{newest:t.note.newest,nextNoteSlot:e+1}}async openAt(e,t,n){let r=e<0?null:await this.newestLink(e,n);if(r===null)return{startAt:0,rows:[],notes:t};let i=await this.readFile(r);return i===`refused`?{startAt:0,rows:[],notes:t}:{startAt:r.toSeq+1,rows:i??[],notes:t}}async readHead(){try{return await this.source.readHead()}catch(e){if(e instanceof l)return this.events.error(e),null;throw e}}hasOlder(){return this.older!==null}loadOlder(){return this.loading??=this.loadOlderOnce().finally(()=>{this.loading=null}),this.loading}async loadOlderOnce(){let t=this.older;if(t===null)return[];let n=await this.source.readFile(t.ref),r=e.y(n,this.topic,t);if(!r.ok)throw this.older=null,Error(`history file ${t.ref} refused (${r.reason}): ${r.detail}`);return this.report(r.value.skipped),this.older=r.value.prev,r.value.rows}async newestLink(t,n){let r=n===void 0?t:t-1;if(n!==void 0){let r=e.v(n,t,this.topic);if(r.ok)return r.value.history}for(let n=r;n>=Math.max(0,t-x);n--){let t=await this.source.readSlot(n).catch(e=>{if(e instanceof u)return null;throw e});if(t===null)continue;let r=e.v(t,n,this.topic);if(r.ok)return r.value.history}return null}async readFile(t){try{let n=e.y(await this.source.readFile(t.ref),this.topic,t);return n.ok?(this.report(n.value.skipped),this.older=n.value.prev,n.value.rows):(this.events.error(Error(`history file ${t.ref} refused (${n.reason}): ${n.detail}`)),`refused`)}catch(e){return this.events.error(e),this.older=t,null}}report(e){e>0&&this.events.skipped(e)}},C={slotMs:e.n,heartbeatMs:e.t,marginMs:1e3,scanBatch:4,clockLimitMs:3e5,missingReadSpacingMs:s};function w(e){return typeof e.readNote==`function`}var T=class{constructor(e){this.limitMs=e,this.aheadAtMost=1/0,this.trusted=!0}observe(e,t){this.aheadAtMost=Math.min(this.aheadAtMost,t-e)}distrust(){this.trusted=!1}get isTrusted(){return this.trusted}get ms(){let e=Number.isFinite(this.aheadAtMost),t=this.trusted||!e?Math.min(0,this.aheadAtMost):this.aheadAtMost;return Math.max(-this.limitMs,Math.min(this.limitMs,t))}},E=class{constructor(e,t,n){this.source=e,this.now=n,this.counts={found:0,empty:0},this.settings={...C,...t},this.clock=new T(this.settings.clockLimitMs),this.pacer=new c(this.settings.missingReadSpacingMs,n)}lastReadableSlot(t=this.now()){return e.u(t-this.settings.marginMs-this.clock.ms,this.settings.slotMs)-1}readableAt(t){return e.l(t,this.settings.slotMs)+this.settings.marginMs+this.clock.ms}get lookBackSlots(){return Math.ceil(this.settings.heartbeatMs/this.settings.slotMs)+2}get silenceMs(){return this.settings.heartbeatMs+2*this.settings.slotMs+this.settings.marginMs}async read(t){if(!this.pacer.mayRead(t))return null;let n;try{n=await this.source.readNote(t),n===null&&this.pacer.missed(t)}catch(e){if(!(e instanceof u))throw e;n=null}let r=n===null?null:e.d(n);return r===null?(this.counts.empty++,null):(this.counts.found++,this.clock.observe(r.writtenAt,this.now()),r)}async scan(e,t){for(let n=e;n>=t;n-=this.settings.scanBatch){let e=[];for(let r=n;r>n-this.settings.scanBatch&&r>=t;r--)e.push(r);let r=await Promise.all(e.map(e=>this.read(e))),i=r.findIndex(e=>e!==null);if(i>=0)return{slot:e[i],note:r[i]}}return null}},D={resendAfterMs:1e4,maxResends:5,reactionWindowMs:1e3,isLive:()=>!0},O=class{constructor(e,t,n,r,i=D){this.key=e,this.profile=t,this.write=n,this.events=r,this.settings=i,this.outgoing=new Map,this.reactions=new Map,this.stopped=!1}get address(){return this.key.publicKey().address().toHex()}send(t){let{message:n,bytes:r}=e.M(this.key,{...t,...this.profile,own:!1}),i={message:n,bytes:r,writes:0,written:!1,inFlight:!1,timer:null,lastError:null};return this.outgoing.set(n.id,i),this.events.pending(n),this.attempt(i),n}react(t,n,r){let i=JSON.stringify([t,n,r]),a=this.reactions.get(i);if(a){a.taps++;return}let o=setTimeout(()=>{let a=this.reactions.get(i);this.reactions.delete(i),a&&a.taps%2==1&&!this.stopped&&this.send({topic:t,type:e.O.REACTION,target:n,text:r})},this.settings.reactionWindowMs);this.reactions.set(i,{taps:1,timer:o})}confirm(e){if(e.addr!==this.address)return;let t=this.outgoing.get(e.id);t&&(this.clearTimer(t),this.outgoing.delete(e.id),this.events.confirmed(t.message))}retry(e){let t=this.outgoing.get(e);return!t||this.stopped?!1:(this.clearTimer(t),t.writes=0,t.inFlight||this.attempt(t),!0)}isPending(e){return this.outgoing.has(e)}stop(){this.stopped=!0;for(let e of this.outgoing.values())this.clearTimer(e);for(let{timer:e}of this.reactions.values())clearTimeout(e);this.reactions.clear()}attempt(e){!this.stopped&&this.outgoing.has(e.message.id)&&(e.writes++,e.inFlight=!0,this.write(e.bytes).then(()=>{e.inFlight=!1,!e.written&&this.outgoing.has(e.message.id)&&(e.written=!0,this.events.written(e.message)),this.scheduleNext(e)},t=>{e.inFlight=!1,e.lastError=t,this.scheduleNext(e)}))}scheduleNext(e){!this.stopped&&this.outgoing.has(e.message.id)&&(e.timer=setTimeout(()=>{if(e.timer=null,!this.settings.isLive()){this.scheduleNext(e);return}if(e.writes>this.settings.maxResends){this.events.failed(e.message,e.lastError??Error(`never seen on the chat feed`));return}this.attempt(e)},this.settings.resendAfterMs))}clearTimer(e){e.timer&&=(clearTimeout(e.timer),null)}},k=[1e3,2e3,4e3,8e3],A=3;function j(e){return(e.startsWith(`0x`)?e.slice(2):e).toLowerCase()}var M=class{constructor(e,r={}){this.emitter=new o,this.seen=new Set,this.status=null,this.generation=0,this.running=!1,this.starting=null,this.openTimer=null,this.wakeOpen=null;let{user:i,infra:a}=e;this.key=new t.PrivateKey(j(i.privateKey)),this.topic=a.chatTopic,this.profile={name:i.nickname,via:a.via,...i.binding?{idb:i.binding}:{}},this.openRetryMs=r.openRetryMs??k,this.senderSettings={...D,isLive:()=>this.status===_.LIVE,...r.sender};let s={slotReadMs:a.socReadTimeout??5e3,feedReadMs:a.feedReadTimeout??15e3,writeMs:a.gsocWriteTimeout??1e4},c={...a.noteSlotMs===void 0?{}:{slotMs:a.noteSlotMs},...a.noteHeartbeatMs===void 0?{}:{heartbeatMs:a.noteHeartbeatMs},...r.notes};this.source=r.source??p(new t.Bee(a.beeUrl),j(a.chatAddress),a.chatTopic,s,c.slotMs),this.write=r.write??g(new t.Bee(a.writeUrl??a.beeUrl),a.stamp?j(a.stamp):h,j(a.gsocResourceId),a.gsocTopic,s);let l=r.follower?.now??(()=>Date.now()),u={pollIntervalMs:a.pollingInterval??1e3,...r.follower,now:l},d=this.source;this.notes=w(d)?new E(d,c,l):null,this.follower=new b(this.source,this.topic,{entry:e=>this.show(e),skipped:(e,t,r)=>this.emitter.emit(n.MESSAGE_SKIPPED,{index:e,reason:t,detail:r}),status:e=>this.setStatus(e),error:e=>this.emitter.emit(n.ERROR,e)},u,this.notes),this.history=new S(this.source,this.topic,{skipped:e=>this.emitter.emit(n.MESSAGE_SKIPPED,{index:-1,reason:`history-row`,detail:`${e} rows of a history file`}),error:e=>this.emitter.emit(n.ERROR,e)},this.notes),this.sender=this.makeSender()}getEmitter(){return this.emitter}getStatus(){return this.status}getAddress(){return this.key.publicKey().address().toHex()}start(){if(this.running)return this.starting??Promise.resolve();this.running=!0,this.generation++,this.seen.clear(),this.sender=this.makeSender();let e=this.open(this.generation).finally(()=>{this.starting===e&&(this.starting=null)});return this.starting=e,e}async stop(){this.running=!1,this.generation++,this.openTimer&&=(clearTimeout(this.openTimer),null),this.wakeOpen?.(),this.follower.stop(),this.sender.stop()}async sendMessage(t,n,i){if(n===e.O.REACTION){if(!i)throw Error(`a reaction names the message it reacts to`);return this.sender.react(this.topic,i,t),null}return r(this.sender.send({topic:this.topic,type:n,target:i??``,text:t}))}retrySendMessage(e){return this.sender.retry(typeof e==`string`?e:e.id)}async fetchPreviousMessages(){this.emitter.emit(n.LOADING_PREVIOUS_MESSAGES,!0);try{let e=this.generation,t=await this.history.loadOlder();return e===this.generation?this.showRows(t):[]}finally{this.emitter.emit(n.LOADING_PREVIOUS_MESSAGES,!1)}}hasPreviousMessages(){return this.history.hasOlder()}orderMessages(e){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)}async open(e){this.emitter.emit(n.LOADING_INIT,!0);let t=0;for(;e===this.generation;)try{let t=await this.history.open();if(e!==this.generation)return;this.showRows(t.rows),this.follower.start(t.startAt,t.notes),this.emitter.emit(n.LOADING_INIT,!1);return}catch(r){if(e!==this.generation)return;t++,this.emitter.emit(n.ERROR,r),this.setStatus(_.RECONNECTING),t===A&&this.emitter.emit(n.CRITICAL_ERROR,r),await this.waitToOpen(this.openRetryMs[Math.min(t,this.openRetryMs.length)-1]??8e3)}}waitToOpen(e){return new Promise(t=>{this.wakeOpen=()=>{this.wakeOpen=null,t()},this.openTimer=setTimeout(()=>{this.openTimer=null,this.wakeOpen?.()},e)})}makeSender(){return new O(this.key,this.profile,this.write,{pending:e=>this.emitter.emit(n.MESSAGE_REQUEST_INITIATED,r(e)),written:e=>this.emitter.emit(n.MESSAGE_REQUEST_UPLOADED,r(e)),failed:(e,t)=>{this.emitter.emit(n.ERROR,t),this.emitter.emit(n.MESSAGE_REQUEST_ERROR,r(e))},confirmed:()=>{}},this.senderSettings)}show(e){this.seen.has(e.seq)||(this.seen.add(e.seq),this.sender.confirm(e.msg),this.emitter.emit(n.MESSAGE_RECEIVED,i(e)))}showRows(e){let t=[];for(let r of e){if(this.seen.has(r.seq))continue;this.seen.add(r.seq),this.sender.confirm(r.msg);let e=i(r);t.push(e),this.emitter.emit(n.MESSAGE_RECEIVED,e)}return t}setStatus(e){e!==this.status&&(this.status=e,this.emitter.emit(n.STATUS,e))}};exports.CHAT_BINDING_TITLE=e.z,exports.ChatEmitter=o,exports.ChatMessageError=e.S,exports.DEFAULT_NOTE_HEARTBEAT_MS=e.t,exports.DEFAULT_NOTE_SLOT_MS=e.n,exports.EVENTS=n,exports.FeedStatus=_,exports.HeadLookupTimeoutError=l,exports.MAX_BINDING_CHARACTERS=e.B,exports.MAX_ENTRY_BYTES=e.p,exports.MAX_MESSAGE_BYTES=e.C,exports.MAX_NAME_CHARACTERS=e.w,exports.MAX_NOTE_BYTES=e.r,exports.MAX_TEXT_CHARACTERS=e.T,exports.MAX_TOPIC_CHARACTERS=e.E,exports.MESSAGE_VERSION=e.D,exports.MessageType=e.O,exports.MessageVia=e.k,exports.NOTE_VERSION=e.i,exports.OWN_FEED_TOPIC_PREFIX=e.b,exports.SwarmChat=M,exports.UnreadableGatewayError=y,exports.UnreadableSlotError=u,exports.chatBindingSchema=e.V,exports.chatMessageSchema=e.A,exports.checkChatBinding=e.H,exports.countCharacters=e.j,exports.createChatMessage=e.M,exports.encodeChatMessage=e.N,exports.encodeSlotNote=e.a,exports.feedEntrySchema=e.m,exports.hasValidSignature=e.P,exports.historyFileSchema=e.h,exports.historyLinkSchema=e.g,exports.historyRowSchema=e._,exports.newMessageId=e.F,exports.noteAddress=e.o,exports.noteIdentifier=e.s,exports.noteIdentifierText=e.c,exports.noteSlotEnd=e.l,exports.noteSlotOf=e.u,exports.ownFeedTopic=e.x,exports.parseChatMessage=e.I,exports.parseFeedEntry=e.v,exports.parseHistoryFile=e.y,exports.parseSlotNote=e.d,exports.signedBytes=e.L,exports.slotNoteSchema=e.f,exports.verifyChatMessage=e.R;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./message-DBi9VeRs.cjs");let t=require("@ethersphere/bee-js");var n={LOADING_INIT:`loadingInit`,LOADING_PREVIOUS_MESSAGES:`loadingPreviousMessages`,MESSAGE_RECEIVED:`messageReceived`,MESSAGE_REQUEST_INITIATED:`messageRequestInitiated`,MESSAGE_REQUEST_UPLOADED:`messageRequestUploaded`,MESSAGE_REQUEST_ERROR:`messageRequestError`,CRITICAL_ERROR:`criticalError`,STATUS:`status`,MESSAGE_SKIPPED:`messageSkipped`,ERROR:`error`};function r(e){return a(e,-1,e.ts)}function i(e){return a(e.msg,e.seq,e.at)}function a(e,t,n){return{id:e.id,type:e.type,message:e.text,username:e.name,address:e.addr,timestamp:n,...e.target?{targetMessageId:e.target}:{},index:t,signedMessage:e}}var o=class{constructor(){this.listeners=new Map,this.on=(e,t)=>{this.listeners.set(e,[...this.listeners.get(e)??[],t])},this.off=(e,t)=>{this.listeners.set(e,(this.listeners.get(e)??[]).filter(e=>e!==t))},this.cleanAll=()=>{this.listeners.clear()}}emit(e,t){for(let n of this.listeners.get(e)??[])try{n(t)}catch(t){console.error(`a listener for ${e} threw`,t)}}},s=2e4,c=class{constructor(e,t){this.spacingMs=e,this.now=t,this.missedAt=new Map}readableAt(e,t=this.now()){let n=this.missedAt.get(e);return n===void 0||this.expired(n,t)?-1/0:n+this.spacingMs}mayRead(e,t=this.now()){return t>=this.readableAt(e,t)}missed(e,t=this.now()){for(let[e,n]of this.missedAt)this.expired(n,t)&&this.missedAt.delete(e);this.missedAt.set(e,t)}found(e){this.missedAt.delete(e)}clear(){this.missedAt.clear()}expired(e,t){return e>t||t-e>=this.spacingMs}},l=class extends Error{constructor(e){super(`the feed head lookup did not answer in time`,e),this.name=`HeadLookupTimeoutError`}},u=class extends Error{constructor(e,t){super(`feed slot ${e} was served but could not be read`,t),this.index=e,this.name=`UnreadableSlotError`}};function d(e){return e instanceof t.BeeResponseError&&(e.status===404||e.status===500)}async function f(e,n){try{return await n()}catch(n){if(d(n))return null;throw n instanceof t.BeeResponseError?n:new u(e,{cause:n})}}function p(n,r,i,a,o=e.n){let s=t.Topic.fromString(i),c=e=>n.feed.makeReader(s,r,m(e));return{readNote:t=>f(t,async()=>(await n.soc.makeReader(r,m(a.slotReadMs)).download(e.s(i,o,t))).payload.toUint8Array()),readSlot:e=>f(e,async()=>(await c(a.slotReadMs).downloadPayload({index:e})).payload.toUint8Array()),async readHead(){let e=m(a.feedReadMs);try{let{payload:t,feedIndex:i}=await n.feed.makeReader(s,r,e).downloadPayload();return{index:Number(i.toBigInt()),payload:t.toUint8Array()}}catch(t){if(d(t))return null;throw e.signal?.aborted?new l({cause:t}):t}},async readFile(e){return(await n.data.download(e,void 0,m(a.feedReadMs))).toUint8Array()}}}function m(e){return{signal:AbortSignal.timeout(e)}}var h=`0123456789abcdef`.repeat(4);function g(e,n,r,i,a){let o=new t.PrivateKey(r),s=t.Identifier.fromString(i);return async t=>{await e.messaging.gsocSend(n,o,s,t,{deferred:!1},m(a.writeMs))}}var _={LIVE:`live`,RECONNECTING:`reconnecting`,STALLED:`stalled`},v={pollIntervalMs:1e3,missingReadSpacingMs:s,maxSlotsPerPoll:16,unservedPollsBeforeProbe:3,unreadablePollsBeforeFailure:3,probeIntervalCapMs:6e4,probeDistances:[1,2,4,8],missedLimit:32,missedReadsPerPoll:4,missedExpiryMs:3e5,backoffCapMs:8e3,stallAfterMs:8e3,random:Math.random,now:Date.now},y=class extends Error{constructor(e){super(`the gateway keeps answering feed slot ${e} with something that is not a chunk`),this.index=e,this.name=`UnreadableGatewayError`}},b=class{constructor(e,t,n,r={},i=null){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=new Map,this.timer=null,this.generation=0,this.running=!1,this.status=null,this.settings={...v,...r},this.pacer=new c(this.settings.missingReadSpacingMs,this.settings.now)}get nextIndex(){return this.next}get missedIndices(){return[...this.missed.keys()]}get ledByNotes(){return this.ceiling!==null}start(e,t=null){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)}stop(){this.running=!1,this.generation++,this.timer&&=(clearTimeout(this.timer),null)}schedule(e){let t=this.generation;this.timer=setTimeout(()=>{this.timer=null,this.poll(t)},e)}async poll(e){let t=0,n=!1;try{this.notes!==null&&await this.readDueNotes(this.notes,e),t=await this.walk(e),await this.readMissed(e)}catch(t){n=!0,e===this.generation&&this.gatewayFailed(t)}if(e===this.generation&&this.running){if(n){this.schedule(this.backoffMs());return}this.gatewayAnswered(),this.schedule(t>=this.settings.maxSlotsPerPoll?0:this.untilNextRead())}}untilNextRead(){let e=this.settings.now(),t=t=>{let n=this.pacer.readableAt(t);return n>e?n:e+this.settings.pollIntervalMs},n=[...this.missed.keys()].map(t);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)}async readDueNotes(e,t){let n=this.settings.now(),r=e.lastReadableSlot(n);if(r<this.nextNoteSlot)return;let i=Math.max(this.nextNoteSlot,r-e.lookBackSlots+1),a=await e.scan(r,i);if(t===this.generation){if(this.nextNoteSlot=r+1,a){this.lastNoteFoundAt=n,this.ceiling=Math.max(this.ceiling??-1,a.note.newest,this.next-1);return}n-this.lastNoteFoundAt>=e.silenceMs&&(this.lastNoteFoundAt=n,e.clock.distrust(),this.nextNoteSlot=Math.min(this.nextNoteSlot,e.lastReadableSlot(n)+1))}}async read(e){let t;try{t=await this.source.readSlot(e)}catch(e){if(e instanceof u)return`unreadable`;throw e}return t===null?this.pacer.missed(e):this.pacer.found(e),t}async readUnnamed(e){return this.pacer.mayRead(e)?this.read(e):`held`}async walk(e){for(let t=0;t<this.settings.maxSlotsPerPoll;t++){let n=this.next;if(this.ceiling!==null&&n>this.ceiling)return t;let r=this.ceiling===null?await this.readUnnamed(n):await this.read(n);if(e!==this.generation||r===`held`)return t;if(this.ceiling!==null&&(r===null||r===`unreadable`)){this.remember(n),this.next=n+1;continue}if(r===null||r===`unreadable`){if(t===0){if(this.unservedPolls++,this.unreadablePolls=r===`unreadable`?this.unreadablePolls+1:0,this.shouldProbe()&&await this.probePast(n,e)){this.unreadablePolls=0;continue}if(this.unreadablePolls>=this.settings.unreadablePollsBeforeFailure)throw new y(n)}return t}this.resetRefusals(),this.unreadablePolls=0,this.next=n+1,this.accept(n,r)}return this.settings.maxSlotsPerPoll}shouldProbe(){if(this.unservedPolls!==this.nextProbeAt)return!1;let{probeIntervalCapMs:e,pollIntervalMs:t,missingReadSpacingMs:n}=this.settings,r=Math.max(1,Math.ceil(e/Math.max(t,n)));return this.nextProbeAt+=Math.min(this.nextProbeAt,r),!0}resetRefusals(){this.unservedPolls=0,this.nextProbeAt=this.settings.unservedPollsBeforeProbe}async probePast(e,t){let n=new Set([e]);for(let r of this.settings.probeDistances){let i=e+r,a=await this.readUnnamed(i);if(t!==this.generation)return!1;if(a===null||a===`unreadable`||a===`held`){n.add(i);continue}this.resetRefusals(),this.remember(e);for(let r=e+1;r<i;r++){let e=n.has(r)?null:await this.readUnnamed(r);if(t!==this.generation)return!1;e===null||e===`unreadable`||e===`held`?this.remember(r):this.accept(r,e)}return this.next=i+1,this.accept(i,a),!0}return!1}remember(e){if(!this.missed.has(e)){if(this.missed.size>=this.settings.missedLimit){this.events.skipped(e,`unreachable`,`stepped past with the retry list full`);return}this.missed.set(e,this.settings.now())}}async readMissed(e){let t=this.settings.now();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`));let n=[...this.missed.keys()].filter(e=>this.pacer.mayRead(e,t)).slice(0,this.settings.missedReadsPerPoll);for(let t of n){let n=await this.read(t);if(e!==this.generation)return;let r=this.missed.get(t);this.missed.delete(t),n!==null&&n!==`unreadable`?this.accept(t,n):r!==void 0&&this.missed.set(t,r)}}accept(t,n){let r=e.v(n,t,this.topic);r.ok?(this.notes?.clock.observe(r.value.at,this.settings.now()),this.events.entry(r.value)):this.events.skipped(t,r.reason,r.detail)}gatewayFailed(e){this.gatewayFailures++,this.setStatus(_.RECONNECTING),this.events.error(e)}gatewayAnswered(){this.gatewayFailures=0;let e=this.settings.now(),t=[...this.missed.values()].some(t=>e-t>=this.settings.stallAfterMs);this.setStatus(t?_.STALLED:_.LIVE)}backoffMs(){let{pollIntervalMs:e,backoffCapMs:t,random:n}=this.settings,r=Math.min(t,e*2**this.gatewayFailures);return r/2+n()*r/2}setStatus(e){e!==this.status&&(this.status=e,this.events.status(e))}},x=16,S=class{constructor(e,t,n,r=null){this.source=e,this.topic=t,this.events=n,this.notes=r,this.older=null,this.loading=null}async open(){this.older=null;let e=await this.newestNote();if(e!==null)return this.openAt(e.newest,e);let t=await this.readHead();return t===null?{startAt:0,rows:[],notes:null}:this.openAt(t.index,null,t.payload)}async newestNote(){if(this.notes===null)return null;let e=this.notes.lastReadableSlot(),t=await this.notes.scan(e,e-this.notes.lookBackSlots+1);return t===null?null:{newest:t.note.newest,nextNoteSlot:e+1}}async openAt(e,t,n){let r=e<0?null:await this.newestLink(e,n);if(r===null)return{startAt:0,rows:[],notes:t};let i=await this.readFile(r);return i===`refused`?{startAt:0,rows:[],notes:t}:{startAt:r.toSeq+1,rows:i??[],notes:t}}async readHead(){try{return await this.source.readHead()}catch(e){if(e instanceof l)return this.events.error(e),null;throw e}}hasOlder(){return this.older!==null}loadOlder(){return this.loading??=this.loadOlderOnce().finally(()=>{this.loading=null}),this.loading}async loadOlderOnce(){let t=this.older;if(t===null)return[];let n=await this.source.readFile(t.ref),r=e.y(n,this.topic,t);if(!r.ok)throw this.older=null,Error(`history file ${t.ref} refused (${r.reason}): ${r.detail}`);return this.report(r.value.skipped),this.older=r.value.prev,r.value.rows}async newestLink(t,n){let r=n===void 0?t:t-1;if(n!==void 0){let r=e.v(n,t,this.topic);if(r.ok)return r.value.history}for(let n=r;n>=Math.max(0,t-x);n--){let t=await this.source.readSlot(n).catch(e=>{if(e instanceof u)return null;throw e});if(t===null)continue;let r=e.v(t,n,this.topic);if(r.ok)return r.value.history}return null}async readFile(t){try{let n=e.y(await this.source.readFile(t.ref),this.topic,t);return n.ok?(this.report(n.value.skipped),this.older=n.value.prev,n.value.rows):(this.events.error(Error(`history file ${t.ref} refused (${n.reason}): ${n.detail}`)),`refused`)}catch(e){return this.events.error(e),this.older=t,null}}report(e){e>0&&this.events.skipped(e)}},C={slotMs:e.n,heartbeatMs:e.t,marginMs:1e3,scanBatch:4,clockLimitMs:3e5,missingReadSpacingMs:s};function w(e){return typeof e.readNote==`function`}var T=class{constructor(e){this.limitMs=e,this.aheadAtMost=1/0,this.trusted=!0}observe(e,t){this.aheadAtMost=Math.min(this.aheadAtMost,t-e)}distrust(){this.trusted=!1}get isTrusted(){return this.trusted}get ms(){let e=Number.isFinite(this.aheadAtMost),t=this.trusted||!e?Math.min(0,this.aheadAtMost):this.aheadAtMost;return Math.max(-this.limitMs,Math.min(this.limitMs,t))}},E=class{constructor(e,t,n){this.source=e,this.now=n,this.counts={found:0,empty:0},this.settings={...C,...t},this.clock=new T(this.settings.clockLimitMs),this.pacer=new c(this.settings.missingReadSpacingMs,n)}lastReadableSlot(t=this.now()){return e.u(t-this.settings.marginMs-this.clock.ms,this.settings.slotMs)-1}readableAt(t){return e.l(t,this.settings.slotMs)+this.settings.marginMs+this.clock.ms}get lookBackSlots(){return Math.ceil(this.settings.heartbeatMs/this.settings.slotMs)+2}get silenceMs(){return this.settings.heartbeatMs+2*this.settings.slotMs+this.settings.marginMs}async read(t){if(!this.pacer.mayRead(t))return null;let n;try{n=await this.source.readNote(t),n===null&&this.pacer.missed(t)}catch(e){if(!(e instanceof u))throw e;n=null}let r=n===null?null:e.d(n);return r===null?(this.counts.empty++,null):(this.counts.found++,this.clock.observe(r.writtenAt,this.now()),r)}async scan(e,t){for(let n=e;n>=t;n-=this.settings.scanBatch){let e=[];for(let r=n;r>n-this.settings.scanBatch&&r>=t;r--)e.push(r);let r=await Promise.all(e.map(e=>this.read(e))),i=r.findIndex(e=>e!==null);if(i>=0)return{slot:e[i],note:r[i]}}return null}},D={resendAfterMs:1e4,maxResends:5,reactionWindowMs:1e3,isLive:()=>!0},O=class{constructor(e,t,n,r,i=D){this.key=e,this.profile=t,this.write=n,this.events=r,this.settings=i,this.outgoing=new Map,this.reactions=new Map,this.stopped=!1}get address(){return this.key.publicKey().address().toHex()}send(t){let{message:n,bytes:r}=e.M(this.key,{...t,...this.profile}),i={message:n,bytes:r,writes:0,written:!1,inFlight:!1,timer:null,lastError:null};return this.outgoing.set(n.id,i),this.events.pending(n),this.attempt(i),n}react(t,n,r){let i=JSON.stringify([t,n,r]),a=this.reactions.get(i);if(a){a.taps++;return}let o=setTimeout(()=>{let a=this.reactions.get(i);this.reactions.delete(i),a&&a.taps%2==1&&!this.stopped&&this.send({topic:t,type:e.O.REACTION,target:n,text:r})},this.settings.reactionWindowMs);this.reactions.set(i,{taps:1,timer:o})}confirm(e){if(e.addr!==this.address)return;let t=this.outgoing.get(e.id);t&&(this.clearTimer(t),this.outgoing.delete(e.id),this.events.confirmed(t.message))}retry(e){let t=this.outgoing.get(e);return!t||this.stopped?!1:(this.clearTimer(t),t.writes=0,t.inFlight||this.attempt(t),!0)}isPending(e){return this.outgoing.has(e)}stop(){this.stopped=!0;for(let e of this.outgoing.values())this.clearTimer(e);for(let{timer:e}of this.reactions.values())clearTimeout(e);this.reactions.clear()}attempt(e){!this.stopped&&this.outgoing.has(e.message.id)&&(e.writes++,e.inFlight=!0,this.write(e.bytes).then(()=>{e.inFlight=!1,!e.written&&this.outgoing.has(e.message.id)&&(e.written=!0,this.events.written(e.message)),this.scheduleNext(e)},t=>{e.inFlight=!1,e.lastError=t,this.scheduleNext(e)}))}scheduleNext(e){!this.stopped&&this.outgoing.has(e.message.id)&&(e.timer=setTimeout(()=>{if(e.timer=null,!this.settings.isLive()){this.scheduleNext(e);return}if(e.writes>this.settings.maxResends){this.events.failed(e.message,e.lastError??Error(`never seen on the chat feed`));return}this.attempt(e)},this.settings.resendAfterMs))}clearTimer(e){e.timer&&=(clearTimeout(e.timer),null)}},k=[1e3,2e3,4e3,8e3],A=3;function j(e){return(e.startsWith(`0x`)?e.slice(2):e).toLowerCase()}var M=class{constructor(e,r={}){this.emitter=new o,this.seen=new Set,this.status=null,this.generation=0,this.running=!1,this.starting=null,this.openTimer=null,this.wakeOpen=null;let{user:i,infra:a}=e;this.key=new t.PrivateKey(j(i.privateKey)),this.topic=a.chatTopic,this.profile={name:i.nickname,via:a.via,...i.binding?{idb:i.binding}:{},...i.walletLink?{wl:i.walletLink}:{}},this.openRetryMs=r.openRetryMs??k,this.senderSettings={...D,isLive:()=>this.status===_.LIVE,...r.sender};let s={slotReadMs:a.socReadTimeout??5e3,feedReadMs:a.feedReadTimeout??15e3,writeMs:a.gsocWriteTimeout??1e4},c={...a.noteSlotMs===void 0?{}:{slotMs:a.noteSlotMs},...a.noteHeartbeatMs===void 0?{}:{heartbeatMs:a.noteHeartbeatMs},...r.notes};this.source=r.source??p(new t.Bee(a.beeUrl),j(a.chatAddress),a.chatTopic,s,c.slotMs),this.write=r.write??g(new t.Bee(a.writeUrl??a.beeUrl),a.stamp?j(a.stamp):h,j(a.gsocResourceId),a.gsocTopic,s);let l=r.follower?.now??(()=>Date.now()),u={pollIntervalMs:a.pollingInterval??1e3,...r.follower,now:l},d=this.source;this.notes=w(d)?new E(d,c,l):null,this.follower=new b(this.source,this.topic,{entry:e=>this.show(e),skipped:(e,t,r)=>this.emitter.emit(n.MESSAGE_SKIPPED,{index:e,reason:t,detail:r}),status:e=>this.setStatus(e),error:e=>this.emitter.emit(n.ERROR,e)},u,this.notes),this.history=new S(this.source,this.topic,{skipped:e=>this.emitter.emit(n.MESSAGE_SKIPPED,{index:-1,reason:`history-row`,detail:`${e} rows of a history file`}),error:e=>this.emitter.emit(n.ERROR,e)},this.notes),this.sender=this.makeSender()}getEmitter(){return this.emitter}getStatus(){return this.status}getAddress(){return this.key.publicKey().address().toHex()}start(){if(this.running)return this.starting??Promise.resolve();this.running=!0,this.generation++,this.seen.clear(),this.sender=this.makeSender();let e=this.open(this.generation).finally(()=>{this.starting===e&&(this.starting=null)});return this.starting=e,e}async stop(){this.running=!1,this.generation++,this.openTimer&&=(clearTimeout(this.openTimer),null),this.wakeOpen?.(),this.follower.stop(),this.sender.stop()}async sendMessage(t,n,i){if(n===e.O.REACTION){if(!i)throw Error(`a reaction names the message it reacts to`);return this.sender.react(this.topic,i,t),null}return r(this.sender.send({topic:this.topic,type:n,target:i??``,text:t}))}retrySendMessage(e){return this.sender.retry(typeof e==`string`?e:e.id)}async fetchPreviousMessages(){this.emitter.emit(n.LOADING_PREVIOUS_MESSAGES,!0);try{let e=this.generation,t=await this.history.loadOlder();return e===this.generation?this.showRows(t):[]}finally{this.emitter.emit(n.LOADING_PREVIOUS_MESSAGES,!1)}}hasPreviousMessages(){return this.history.hasOlder()}orderMessages(e){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)}async open(e){this.emitter.emit(n.LOADING_INIT,!0);let t=0;for(;e===this.generation;)try{let t=await this.history.open();if(e!==this.generation)return;this.showRows(t.rows),this.follower.start(t.startAt,t.notes),this.emitter.emit(n.LOADING_INIT,!1);return}catch(r){if(e!==this.generation)return;t++,this.emitter.emit(n.ERROR,r),this.setStatus(_.RECONNECTING),t===A&&this.emitter.emit(n.CRITICAL_ERROR,r),await this.waitToOpen(this.openRetryMs[Math.min(t,this.openRetryMs.length)-1]??8e3)}}waitToOpen(e){return new Promise(t=>{this.wakeOpen=()=>{this.wakeOpen=null,t()},this.openTimer=setTimeout(()=>{this.openTimer=null,this.wakeOpen?.()},e)})}makeSender(){return new O(this.key,this.profile,this.write,{pending:e=>this.emitter.emit(n.MESSAGE_REQUEST_INITIATED,r(e)),written:e=>this.emitter.emit(n.MESSAGE_REQUEST_UPLOADED,r(e)),failed:(e,t)=>{this.emitter.emit(n.ERROR,t),this.emitter.emit(n.MESSAGE_REQUEST_ERROR,r(e))},confirmed:()=>{}},this.senderSettings)}show(e){this.seen.has(e.seq)||(this.seen.add(e.seq),this.sender.confirm(e.msg),this.emitter.emit(n.MESSAGE_RECEIVED,i(e)))}showRows(e){let t=[];for(let r of e){if(this.seen.has(r.seq))continue;this.seen.add(r.seq),this.sender.confirm(r.msg);let e=i(r);t.push(e),this.emitter.emit(n.MESSAGE_RECEIVED,e)}return t}setStatus(e){e!==this.status&&(this.status=e,this.emitter.emit(n.STATUS,e))}};exports.CHAT_BINDING_TITLE=e.G,exports.ChatEmitter=o,exports.ChatMessageError=e.S,exports.DEFAULT_NOTE_HEARTBEAT_MS=e.t,exports.DEFAULT_NOTE_SLOT_MS=e.n,exports.EVENTS=n,exports.FeedStatus=_,exports.HeadLookupTimeoutError=l,exports.MAX_BINDING_CHARACTERS=e.K,exports.MAX_ENTRY_BYTES=e.p,exports.MAX_MESSAGE_BYTES=e.C,exports.MAX_NAME_CHARACTERS=e.w,exports.MAX_NOTE_BYTES=e.r,exports.MAX_TEXT_CHARACTERS=e.T,exports.MAX_TOPIC_CHARACTERS=e.E,exports.MAX_WALLET_LINK_CHARACTERS=e.B,exports.MESSAGE_VERSION=e.D,exports.MessageType=e.O,exports.MessageVia=e.k,exports.NOTE_VERSION=e.i,exports.OWN_FEED_TOPIC_PREFIX=e.b,exports.SwarmChat=M,exports.UnreadableGatewayError=y,exports.UnreadableSlotError=u,exports.WALLET_LINK_STATEMENT=e.V,exports.WALLET_LINK_TITLE=e.H,exports.chatBindingSchema=e.q,exports.chatMessageSchema=e.A,exports.checkChatBinding=e.J,exports.checkWalletLink=e.U,exports.countCharacters=e.j,exports.createChatMessage=e.M,exports.displayNameProblem=e.N,exports.encodeChatMessage=e.P,exports.encodeSlotNote=e.a,exports.feedEntrySchema=e.m,exports.hasValidSignature=e.F,exports.historyFileSchema=e.h,exports.historyLinkSchema=e.g,exports.historyRowSchema=e._,exports.newMessageId=e.I,exports.noteAddress=e.o,exports.noteIdentifier=e.s,exports.noteIdentifierText=e.c,exports.noteSlotEnd=e.l,exports.noteSlotOf=e.u,exports.ownFeedTopic=e.x,exports.parseChatMessage=e.L,exports.parseFeedEntry=e.v,exports.parseHistoryFile=e.y,exports.parseSlotNote=e.d,exports.signedBytes=e.R,exports.slotNoteSchema=e.f,exports.verifyChatMessage=e.z,exports.walletLinkSchema=e.W;