Stores the site-wide chat's messages and each user's read marker.

The WebSocket route (routes/ws.ts) writes messages and moves read markers, then broadcasts the result. routes/chat.ts reads the history, a page at a time.

Functions

f
chatMessageMentionsEveryone(id: string): boolean

Checks whether message id is flagged mentionsEveryone, false when there is no such message. The WebSocket route reads it before an edit, to notify everyone only when the edit adds @everyone.

f
createChatMessage(
userId: string,
body: string,
replyToId?: string
): ChatMessage

Stores a message from userId on a chat_send, and claims the pasted images it links to. A replyToId naming no message is dropped, and the message is posted as no reply. The message mentionsEveryone when it says @everyone and userId may. The caller broadcasts the result, and notifies everyone when it is flagged.

f
deleteChatMessage(
id: string,
requestingUserId: string,
canModerate: boolean
): void

Deletes a message on a chat_delete. canModerate lets a moderator delete anyone's message. Replies to it keep their replyToId, without its preview.

f
getChatMessagesAfter(
after: ChatCursor,
limit?
): ChatMessage[]

Returns the first limit messages after after, oldest first. The chatbox uses it to fetch what it missed while the socket was down. limit is clamped to 1–100.

f
getChatReadState(userId: string): ChatReadState

Returns how far userId has read the chat. A user who never opened it has read up to their registration, so the history from before it isn't unread.

f
getRecentChatMessages(
limit?,
before?: ChatCursor
): ChatMessage[]

Returns the latest limit messages, or with before the limit messages just older than it, oldest first either way. limit is clamped to 1–100.

f
markChatRead(
userId: string,
at: string
): ChatReadState

Moves userId's read marker to at, a message's created_at, on a chat_read. It never moves back, so a lagging tab can't undo a newer tab's read. It never passes the newest message, so a timestamp from the future can't mark messages read before they are sent.

f
updateChatMessage(
id: string,
body: string,
requestingUserId: string,
canModerate: boolean
): ChatMessage

Replaces a message's body on a chat_edit, and claims any image the new body links to. canModerate lets a moderator edit anyone's message. The flag mentionsEveryone is set again from the new body and the author's role, not the editor's: a moderator's edit can't make a user's message reach everyone. The caller broadcasts the result.

Interfaces

I
ChatCursor

Passed by routes/chat.ts to page through the history, from the message the client already has at one end. Messages are ordered by createdAt, then by id, so a page boundary between two messages sent in the same millisecond skips neither.

I
ChatReadState

Returned to the WebSocket route by getChatReadState and markChatRead. The route sends it in welcome and in chat_read_update, and the client shows unread on the chat's badge.