@solarpunkltd/swarm-chat-js 8.0.0 → 8.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -2
- package/dist/chat.d.ts +5 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +3 -3
- package/dist/sender.d.ts +5 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -83,6 +83,7 @@ await chat.stop();
|
|
|
83
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
84
|
| `infra.stamp` | The batch the inbox writes are stamped with. Left out for a gateway that stamps writes itself. |
|
|
85
85
|
| `infra.via` | Required. Who pays for the inbox writes, `MessageVia.GATEWAY` or `MessageVia.OWN_STAMP`, as every message says in `via`. |
|
|
86
|
+
| `infra.own` | Optional, `false` by default. Whether the sender keeps a copy of every message in its own feed, as every message says in `own`. See the own feed. |
|
|
86
87
|
| `infra.gsocTopic` | The inbox's identifier string, the same for every chat. |
|
|
87
88
|
| `infra.gsocResourceId` | The mined key every sender signs inbox writes with. The server's operator mines it. |
|
|
88
89
|
| `infra.chatTopic` | The chat's topic, which every message carries and the feed is named by. |
|
|
@@ -225,8 +226,13 @@ entry's `msg` or, while pending, the message as it was signed. It never throws,
|
|
|
225
226
|
|
|
226
227
|
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
228
|
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.
|
|
229
|
-
|
|
229
|
+
chat's topic, turned into a feed topic with `Topic.fromString` as the chat's own feed is.
|
|
230
|
+
|
|
231
|
+
`SwarmChat` signs `own: true` when `infra.own` is `true`, once per message, so the pending message a page shows and every
|
|
232
|
+
resend carry it too. The library does not write the copy itself. A page that keeps copies passes its own inbox write,
|
|
233
|
+
a `GsocWrite`, as `new SwarmChat(settings, { write })`. It is handed the signed payload, the same bytes on every resend.
|
|
234
|
+
A write that stores the copy from those bytes before it writes them to the inbox never sends a message that claims a
|
|
235
|
+
copy it does not have.
|
|
230
236
|
|
|
231
237
|
| Export | Use |
|
|
232
238
|
| ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
@@ -269,6 +275,11 @@ notes are found it trusts its own clock, moving reads earlier only when that bou
|
|
|
269
275
|
no note is found for longer than a heartbeat, it waits out the whole bound from then on, which is never early. A
|
|
270
276
|
clock that runs behind sees every stamp as old as it expects, so its messages arrive as late as it runs behind.
|
|
271
277
|
|
|
278
|
+
## Changes in 8.1
|
|
279
|
+
|
|
280
|
+
- `infra.own` signs every message with `own: true`, for a page whose write keeps a copy in the sender's own feed. Left
|
|
281
|
+
out, messages say `own: false` as in 8.0.
|
|
282
|
+
|
|
272
283
|
## Changes in 8.0
|
|
273
284
|
|
|
274
285
|
- 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
|
@@ -28,6 +28,11 @@ export interface ChatSettings {
|
|
|
28
28
|
stamp?: string;
|
|
29
29
|
/** Who pays for the inbox writes, the gateway's stamp or the sender's own, as every message says in `via`. */
|
|
30
30
|
via: MessageVia;
|
|
31
|
+
/**
|
|
32
|
+
* Whether the sender keeps a copy of every message in its own feed, as every message says in `own`. False when left
|
|
33
|
+
* out. The chat writes no copy: a `write` passed in `ChatParts` stores it from the payload it is handed.
|
|
34
|
+
*/
|
|
35
|
+
own?: boolean;
|
|
31
36
|
/** The inbox's identifier string, one for every chat, as the server listens on it. */
|
|
32
37
|
gsocTopic: string;
|
|
33
38
|
/** The mined key every sender signs inbox writes with, which puts them in the server node's neighbourhood. */
|
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-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}),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}:{},...a.own===void 0?{}:{own:a.own}},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;
|
package/dist/index.js
CHANGED
|
@@ -502,8 +502,7 @@ var ve = class {
|
|
|
502
502
|
send(e) {
|
|
503
503
|
let { message: t, bytes: n } = l(this.key, {
|
|
504
504
|
...e,
|
|
505
|
-
...this.profile
|
|
506
|
-
own: !1
|
|
505
|
+
...this.profile
|
|
507
506
|
}), r = {
|
|
508
507
|
message: t,
|
|
509
508
|
bytes: n,
|
|
@@ -596,7 +595,8 @@ var Ce = class {
|
|
|
596
595
|
this.key = new I($(n.privateKey)), this.topic = r.chatTopic, this.profile = {
|
|
597
596
|
name: n.nickname,
|
|
598
597
|
via: r.via,
|
|
599
|
-
...n.binding ? { idb: n.binding } : {}
|
|
598
|
+
...n.binding ? { idb: n.binding } : {},
|
|
599
|
+
...r.own === void 0 ? {} : { own: r.own }
|
|
600
600
|
}, this.openRetryMs = t.openRetryMs ?? xe, this.senderSettings = {
|
|
601
601
|
...Q,
|
|
602
602
|
isLive: () => this.status === X.LIVE,
|
package/dist/sender.d.ts
CHANGED
|
@@ -33,6 +33,11 @@ export interface SenderProfile {
|
|
|
33
33
|
via: MessageVia;
|
|
34
34
|
/** The sender's Swarm ID chat binding, for a signed-in sender only. */
|
|
35
35
|
idb?: ChatBinding;
|
|
36
|
+
/**
|
|
37
|
+
* Whether the sender keeps a copy of every message in its own feed, false when left out. The library writes no copy:
|
|
38
|
+
* the `GsocWrite` that keeps one stores it from the payload it is handed, before or after the inbox write.
|
|
39
|
+
*/
|
|
40
|
+
own?: boolean;
|
|
36
41
|
}
|
|
37
42
|
/**
|
|
38
43
|
* Sends signed messages as GSOC writes and keeps each one pending until the chat feed shows it. A pending message is
|