const e = require("bare-events"),
s = require("b4a"),
t = 200
class i {
constructor(e) {
;((this.value = e), (this.prev = null), (this.next = null))
}
}
class h {
constructor(e) {
;((this.value = e), (this.refs = 0), (this.gc = null))
}
}
class n {
constructor() {
;((this.head = null), (this.tail = null), (this.size = 0))
}
add(e) {
const s = new i(e)
return (
this.tail ? ((this.tail.next = s), (s.prev = this.tail)) : (this.head = s),
(this.tail = s),
this.size++,
s
)
}
remove(e) {
;(e.prev ? (e.prev.next = e.next) : (this.head = e.next),
e.next ? (e.next.prev = e.prev) : (this.tail = e.prev),
this.size--)
}
shift() {
const e = this.head
return e ? (this.remove(e), e.value) : null
}
}
class o {
constructor(e) {
;((this._maxSize = e), (this._m = new Map()), (this._gc = new n()))
}
get size() {
return this._m.size
}
maybeEvict() {
for (; this._m.size > this._maxSize && this._gc.size > 0; ) {
const e = this._gc.shift()
this._m.delete(e)
}
}
set(e, s) {
const t = this._m.get(e)
if (t) return void (t.value = s)
const i = new h(s)
;((i.gc = this._gc.add(e)), this._m.set(e, i))
}
get(e) {
return this._m.get(e)?.value
}
ref(e) {
const s = this._m.get(e)
s && (s.refs++ > 0 || (this._gc.remove(s.gc), (s.gc = null)))
}
unref(e) {
const s = this._m.get(e)
s && 0 !== s.refs && (--s.refs > 0 || (s.gc = this._gc.add(e)))
}
forceGC(e) {
const s = this._maxSize
;((this._maxSize = e), this.maybeEvict(), (this._maxSize = s))
}
}
class a extends e {
constructor({ size: e = 200 } = {}) {
;(super(), (this._cache = new o(e)))
}
get size() {
return this._cache.size
}
id(e) {}
cacheId(e) {}
diff(e, s) {
return !0
}
ref(e) {
this._cache.ref(e)
}
unref(e) {
this._cache.unref(e)
}
maybeGC() {
this._cache.maybeEvict()
}
getRaw(e) {
return this._cache.get(this.constructor.cacheId(e))
}
get(e) {
return this._cache.get(e)
}
add(e, s) {
const t = s?.cacheId || this.constructor.cacheId(this.id(e)),
i = this._cache.get(t)
return ((i && !this.diff(i, e)) || (this._cache.set(t, e), this.emit("update", t, e)), t)
}
}
class c extends a {
static cacheId(e) {
return s.toString(e, "hex")
}
id(e) {
return e.key
}
diff(e, s) {
return e.profile.timestamp !== s.profile.timestamp
}
}
class r extends a {
static cacheId(e) {
return s.toString(e, "hex")
}
id(e) {
return e.key
}
diff(e, s) {
return (
e.status.isActive !== s.status.isActive ||
e.status.isIndexing !== s.status.isIndexing ||
e.profile.name !== s.profile.name
)
}
}
class d extends a {
static cacheId(e) {
return s.toString(e, "hex")
}
id(e) {
return e.roomKey
}
diff(e, s) {
return !0
}
}
class m extends a {
static cacheId({ key: e, seq: t }) {
return `${s.toString(e, "hex")}-${t}`
}
id(e) {
return e.id
}
diff(e, s) {
return !0
}
}
class g extends a {
static cacheId({ key: e, seq: t }) {
return `${s.toString(e, "hex")}-${t}`
}
id(e) {
return e.id
}
diff(e, s) {
return !0
}
}
class u extends e {
constructor(e) {
;(super(),
(this.view = e),
(this.status = null),
(this.member = null),
(this.devices = []),
(this.memberKey = null),
(this.deviceKeys = []),
(this._clock = 0),
(this._memberId = null),
(this._deviceIds = []))
}
_unref() {
this._memberId && this.view.members.unref(this._memberId)
for (const e of this._deviceIds) this.view.devices.unref(e)
}
_ref() {
this._memberId && this.view.members.ref(this._memberId)
for (const e of this._deviceIds) this.view.devices.ref(e)
}
_inflate() {
;((this.member = this.view.members.get(this._memberId)),
(this.devices = this._deviceIds.map((e) => this.view.devices.get(e))))
}
onMemberChanged() {
;(this._inflate(), this.emit("update:member"), this.emit("update"))
}
onDeviceChanged() {
;(this._inflate(), this.emit("update:device"), this.emit("update"))
}
onReset({ memberKey: e, deviceKeys: s, status: t }) {
;(this._unref(),
(this.status = t),
(this.memberKey = e),
(this.deviceKeys = s),
(this._memberId = c.cacheId(this.memberKey)),
(this._deviceIds = s.map((e) => r.cacheId(e))),
this._ref(),
this._inflate(),
this.emit("reset"))
}
onWant(e) {
this._clock = e
}
onHave(e) {
e === this._clock && (this.emit("have", e), this.emit("update"))
}
onCancel(e) {
e === this._clock && (this._clock = 0)
}
}
class l {
constructor(e, s, t) {
;((this.id = e),
(this.cacheId = s),
(this.role = t.role),
(this.digest = t.digest),
(this.config = t.config),
(this.message = t.message),
(this.messageId = t.messageId),
(this.messageCacheId = m.cacheId(this.messageId)))
}
with(e) {
return new l(this.id, this.cacheId, { ...this, ...e })
}
}
class f extends e {
constructor(e) {
;(super(), (this.view = e))
}
ref(e) {
;(this.view.rooms.ref(e.cacheId), e.messageCacheId && this.view.messages.ref(e.messageCacheId))
}
unref(e) {
;(this.view.rooms.unref(e.cacheId),
e.messageCacheId && this.view.messages.unref(e.messageCacheId))
}
onRoleChanged({ id: e, role: s }) {
const t = this.view.rooms.get(e)
if (!t) return
const i = t.with({ role: s })
;(this.view.rooms.add(i, { cacheId: e }), this.emit("update:role", i))
}
onDigestChanged({ id: e, digest: s }) {
const t = this.view.rooms.get(e)
if (!t) return
const i = t.with({ digest: s })
;(this.view.rooms.add(i, { cacheId: e }), this.emit("update:digest", i))
}
onConfigChanged({ id: e, config: s }) {
const t = this.view.rooms.get(e)
if (!t) return
const i = t.with({ config: s })
;(this.view.rooms.add(i, { cacheId: e }), this.emit("update:config", i))
}
onLastMessageChanged({ id: e, messageId: s }) {
const t = this.view.rooms.get(e)
if (!t) return
const i = m.cacheId(s),
h = this.view.messages.get(i),
n = t.with({ messageId: s, messageCacheId: i, message: h })
;(this.view.rooms.add(n, { cacheId: e }), this.emit("update:message", n))
}
onAdd(e, { cacheId: t = null } = {}) {
t || (t = s.toString(e.id, "hex"))
const i = m.cacheId(e.messageId),
h =
(this.view.messages.get(i),
{
role: e.role,
digest: e.digest,
config: e.config,
messageId: e.messageId,
messageCacheId: i,
message: this.view.messages.get(i),
})
let n = this.view.rooms.get(t)
return (
(n = n ? n.with(h) : new l(e.id, t, h)),
this.view.rooms.add(n, { cacheId: t }),
this.emit("update:reset", n),
n
)
}
}
class I {
constructor(e, s, t) {
;((this.id = e),
(this.cacheId = s),
(this.role = t.role),
(this.chat = t.chat),
(this.member = t.member),
(this.reactions = t.reactions),
(this.memberKey = t.memberKey),
(this.memberId = t.memberId))
}
with(e) {
return new I(this.id, this.cacheId, { ...this, ...e })
}
}
class _ extends e {
constructor(e) {
;(super(), (this.view = e))
}
ref(e) {
;(this.view.messages.ref(e.cacheId), e.memberId && this.view.members.ref(e.memberId))
}
unref(e) {
;(this.view.messages.unref(e.cacheId), e.memberId && this.view.members.unref(e.memberId))
}
onChatChanged({ chat: e }) {
const s = m.cacheId(e.id),
t = this.view.messages.get(s)
if (!t) return
const i = t.with({ chat: e })
;(this.view.messages.add(i, { cacheId: s }),
this.emit("update:chat", { chat: e, messages: [i] }))
}
onRoleChanged({ ids: e, role: s }) {
const t = []
for (const i of e) {
const e = m.cacheId(i),
h = this.view.messages.get(e)
if (!h) continue
const n = h.with({ role: s })
;(this.view.messages.add(n, { cacheId: e }), t.push(n))
}
t.length > 0 && this.emit("update:role", { ids: e, role: s, messages: t })
}
onMemberChanged({ ids: e, memberKey: s }) {
const t = this.view.members.get(c.cacheId(s))
if (!t) return
const i = []
for (const s of e) {
const e = m.cacheId(s),
h = this.view.messages.get(e)
if (!h) continue
const n = h.with({ member: t })
;(this.view.messages.add(n, { cacheId: e }), i.push(n))
}
i.length > 0 && this.emit("update:member", { ids: e, memberKey: s, messages: i })
}
onReactionsChanged({ id: e, reactions: s }) {
const t = m.cacheId(e),
i = this.view.messages.get(t)
if (!i) return
const h = i.with({ reactions: s })
;(this.view.messages.add(h, { cacheId: t }),
this.emit("update:reactions", { id: e, reactions: s, messages: [h] }))
}
onAdd(e, { cacheId: s = null } = {}) {
s || (s = m.cacheId(e.chat.id))
const t = c.cacheId(e.memberKey),
i = e.memberKey
let h = this.view.messages.get(s)
if (!h) {
const n = {
reactions: this.view.reactions.get(s),
member: this.view.members.get(t),
chat: e.chat,
role: e.role,
memberKey: i,
memberId: t,
}
;((h = new I(e.chat.id, s, n)), this.view.messages.add(h, { cacheId: s }))
}
return (this.emit("update:reset", h), h)
}
}
class v extends e {
constructor(e) {
;(super(),
(this.view = e),
(this.pendingInvitations = []),
(this.identityJoinRequests = []),
(this.clock = 0),
(this._pending = !0),
(this._invitationIds = new Set()),
(this._joinRequestIds = new Set()))
}
onWant(e) {
;((this.clock = e), (this._pending = !0))
}
onHave(e) {
e === this.clock && ((this._pending = !1), this.emit("have", e), this.emit("update"))
}
onCancel(e) {
e === this.clock && ((this.clock = 0), (this._pending = !0))
}
onReset({ pendingInvitations: e, identityJoinRequests: t }) {
const i = new Set(e.map((e) => s.toString(e.id, "hex"))),
h = new Set(t.map((e) => s.toString(e.deviceKey, "hex"))),
n = !b(this._invitationIds, i),
o = !b(this._joinRequestIds, h)
;(n || o) &&
((this.pendingInvitations = e),
(this.identityJoinRequests = t),
(this._invitationIds = i),
(this._joinRequestIds = h),
this.emit("reset"),
this._pending || this.emit("update"))
}
}
class w extends e {
constructor(e) {
;(super(),
(this.view = e),
(this.rooms = null),
(this.keys = null),
(this.start = 0),
(this.end = 0),
(this.total = 0),
(this.clock = 0),
(this._pending = !0),
(this._ids = null),
(this._cacheIdSet = null))
}
_unref() {
if (this.rooms) for (const e of this.rooms) e && this.view.roomInfo.unref(e)
}
_ref() {
if (this._ids)
for (const e of this._ids) {
this.view.rooms.ref(e)
const s = this.view.rooms.get(e)
s?.messageCacheId && this.view.messages.ref(s.messageCacheId)
}
}
_refreshRooms() {
this.rooms = this._ids.map((e) => this.view.rooms.get(e))
}
onRoomChanged(e, s) {
this._cacheIdSet &&
this._cacheIdSet.has(e.cacheId) &&
(this._unref(),
this._refreshRooms(),
this._ref(),
this.emit("update:" + s, e),
this._pending || this.emit("update"))
}
onWant(e, s, t) {
;((this.clock = e), (this.start = s), (this.end = t), (this._pending = !0))
}
onHave(e) {
e === this.clock && ((this._pending = !1), this.emit("have", e), this.emit("update"))
}
onCancel(e) {
e === this.clock &&
((this.start = 0), (this.end = 0), (this._pending = !0), (this._cacheIdSet = null))
}
onReset({ keys: e, start: t, end: i, total: h }) {
const n = this._ids
if (
((this.keys = e),
(this.start = t),
(this.end = i),
(this.total = h),
(this._ids = e.map((e) => s.toString(e, "hex"))),
(this._cacheIdSet = new Set(this._ids)),
this._ref(),
n)
)
for (const e of n) {
const s = this.view.rooms.get(e)
s && this.view.roomInfo.unref(s)
}
;(this._refreshRooms(), this.emit("reset"), this._pending || this.emit("update"))
}
}
class p extends e {
constructor(e) {
;(super(),
(this.view = e),
(this.messages = null),
(this.ids = null),
(this.room = null),
(this.roomKey = null),
(this.start = 0),
(this.end = 0),
(this.total = 0),
(this.isBottom = !1),
(this.clock = 0),
(this._pending = !0),
(this._ids = null),
(this._cacheIdSet = null),
(this._roomCacheId = null))
}
_unref() {
if (this._cacheIds)
for (const e of this._cacheIds) {
const s = this.view.messages.get(e)
s && this.view.messageInfo.unref(s)
}
}
_ref() {
if (this._cacheIds)
for (const e of this._cacheIds) {
this.view.messages.ref(e)
const s = this.view.messages.get(e)
s?.memberId && this.view.members.ref(s.memberId)
}
}
_refreshMessages() {
this.messages = this._cacheIds.map((e) => this.view.messages.get(e))
}
_refreshRoom() {
this.room = this._roomCacheId ? this.view.rooms.get(this._roomCacheId) : null
}
onRoomChanged(e, s) {
this._roomCacheId &&
this._roomCacheId === e.cacheId &&
(this._refreshRoom(),
this.emit("update:room:" + s, this.room),
this.emit("update:room", this.room),
this._pending || this.emit("update"))
}
onMessagesChanged(e, s) {
const t = e.filter((e) => this._cacheIdSet?.has(e.cacheId))
0 !== t.length &&
(this._unref(),
this._refreshMessages(),
this._ref(),
this.emit("update:" + s, t),
this._pending || this.emit("update"))
}
onWant(e, s, t, i, h) {
;((this.clock = e),
(this.roomKey = s),
(this._roomCacheId = d.cacheId(s)),
(this.start = t),
(this.size = i),
(this.isBottom = h),
(this._pending = !0))
}
onHave(e) {
e === this.clock && ((this._pending = !1), this.emit("have", e), this.emit("update"))
}
onCancel(e) {
e === this.clock &&
((this.room = null),
(this.roomKey = null),
(this.start = 0),
(this.end = 0),
(this._pending = !0),
(this._roomCacheId = null),
(this._cacheIdSet = null))
}
onReset({ ids: e, roomKey: s, start: t, size: i, total: h, isBottom: n }) {
const o = this._cacheIds
if (
((this.ids = e),
(this.roomKey = s),
(this.start = t),
(this.size = i),
(this.total = h),
(this.isBottom = n),
(this._roomCacheId = d.cacheId(s)),
(this._cacheIds = e.map((e) => m.cacheId(e))),
(this._cacheIdSet = new Set(this._cacheIds)),
this._ref(),
o)
)
for (const e of o) {
const s = this.view.messages.get(e)
s && this.view.messageInfo.unref(s)
}
;(this._refreshMessages(),
this._refreshRoom(),
this.emit("reset"),
this._pending || this.emit("update"))
}
}
function b(e, s) {
if (e.size !== s.size) return !1
for (const t of e) if (!s.has(t)) return !1
return !0
}
module.exports = class {
constructor() {
;((this.members = new c()),
(this.devices = new r()),
(this.reactions = new g()),
(this.messages = new m()),
(this.rooms = new d()),
(this.identity = new u(this)),
(this.pairing = new v(this)),
(this.lobby = new w(this)),
(this.chat = new p(this)),
(this.roomInfo = new f(this)),
(this.messageInfo = new _(this)),
this.roomInfo.on("update:reset", (e) => {
this.chat.onRoomChanged(e, "reset")
}),
this.roomInfo.on("update:role", (e) => {
;(this.lobby.onRoomChanged(e, "role"), this.chat.onRoomChanged(e, "role"))
}),
this.roomInfo.on("update:digest", (e) => {
;(this.lobby.onRoomChanged(e, "digest"), this.chat.onRoomChanged(e, "digest"))
}),
this.roomInfo.on("update:config", (e) => {
;(this.lobby.onRoomChanged(e, "config"), this.chat.onRoomChanged(e, "config"))
}),
this.roomInfo.on("update:message", (e) => {
this.lobby.onRoomChanged(e, "message")
}),
this.messageInfo.on("update:chat", ({ messages: e }) =>
this.chat.onMessagesChanged(e, "chat"),
),
this.messageInfo.on("update:role", ({ messages: e }) =>
this.chat.onMessagesChanged(e, "role"),
),
this.messageInfo.on("update:member", ({ messages: e }) =>
this.chat.onMessagesChanged(e, "member"),
),
this.messageInfo.on("update:reactions", ({ messages: e }) =>
this.chat.onMessagesChanged(e, "reactions"),
))
}
}