const RUN_COALESCE_MAX_INTERVAL = 10 /* min */ * 60 /* sec */ * 1000; /* ms */ export class Messages { channels = $state({}); inChannel(channel) { return this.channels[channel]; } addMessage(channel, id, { at, sender, body }) { let parsedAt = new Date(at); const message = { id, at: parsedAt, body }; let runs = (this.channels[channel] ||= []); let currentRun = runs.slice(-1)[0]; if (currentRun === undefined) { currentRun = { sender, messages: [message] }; runs.push(currentRun); } else { let lastMessage = currentRun.messages.slice(-1)[0]; let newRun = currentRun.sender !== sender || parsedAt - lastMessage.at > RUN_COALESCE_MAX_INTERVAL; if (newRun) { currentRun = { sender, messages: [message] }; runs.push(currentRun); } else { currentRun.messages.push(message); } } return this; } setMessages(messages) { this.channels = {}; for (let { channel, id, at, sender, body } of messages) { this.addMessage(channel, id, { at, sender, body }); } return this; } deleteMessage(messageId) { for (let channel in this.channels) { this.channels[channel] = this.channels[channel] .map(({ sender, messages }) => ({ sender, messages: messages.filter(({ id }) => id != messageId) })) .filter(({ messages }) => messages.length > 0); } return this; } deleteChannel(id) { delete this.channels[id]; return this; } }