How to Handle Message Reactions and Read Receipts in LINEJS
To handle message reactions and read receipts in LINEJS, use the Message.react() and Message.read() methods for high-level operations, or call client.base.talk.react() and client.base.talk.sendChatChecked() for direct service access.
LINEJS is a TypeScript client library that abstracts the LINE Messaging API into an intuitive service layer. When you handle message reactions and read receipts in LINEJS, you interact with a three-tier architecture: high-level Message wrappers, underlying service implementations, and Thrift RPC builders. This guide covers both the convenient instance methods and the low-level service calls used by the evex-dev/linejs codebase.
Understanding the LINEJS Architecture
LINEJS organizes messaging operations into distinct layers that ultimately generate Thrift RPCs. At the highest level, the Message class in packages/linejs/client/features/message/talk.ts provides user-friendly methods. These wrap the TalkService in packages/linejs/base/service/talk/mod.ts, which constructs payloads using builders defined in packages/linejs/base/thrift/readwrite/struct.ts. All communication flows through protocol 4 (the "Talk" protocol) to the /S4 endpoint.
The two primary operations follow this flow:
- React to a message:
Message.react()→TalkService.react()→LINEStruct.react_args→/S4 - Send read receipt:
Message.read()→TalkService.sendChatChecked()→LINEStruct.sendChatChecked_args→/S4
How to React to Messages in LINEJS
You can add emoji reactions using either the high-level Message API or direct service calls. Both approaches generate the same react RPC defined in the LINE protocol.
Using the High-Level Message API
The simplest approach uses the react() method available on Message instances. When you receive a message through the event system, call react() with a MessageReactionType enum value.
import { MessageReactionType } from "@evex/linejs-types";
import { LineClient } from "@evex/linejs";
async function addReaction(client: LineClient, msgId: string) {
const msg = await client.base.talk.getMessage({ id: msgId });
// React with the predefined 👍 (LIKE) reaction
await msg.react(MessageReactionType.LIKE);
}
According to the evex-dev/linejs source code, this method (lines 101-110 in packages/linejs/client/features/message/talk.ts) forwards to client.base.talk.react() after converting the message ID to a BigInt.
Direct Talk Service Implementation
For batch operations or when working with raw IDs, use TalkService.react() directly. This method builds a Thrift request using LINEStruct.react_args (defined at lines 706-712 in packages/linejs/base/thrift/readwrite/struct.ts).
import { MessageReactionType } from "@evex/linejs-types";
async function lowLevelReact(client: LineClient) {
// React to a message without a Message wrapper
await client.base.talk.react({
id: 1234567890n, // message ID as bigint
reaction: MessageReactionType.HEART,
});
}
The implementation in packages/linejs/base/service/talk/mod.ts (lines 701-719) constructs the payload with reqSeq: 0, the target messageId, and the predefinedReactionType enum before dispatching via client.request.request().
How to Send Read Receipts in LINEJS
Read receipts (chat checked notifications) inform senders that you've viewed their messages. LINEJS provides both automated and manual methods for sending these receipts.
Marking Messages as Read via Message Instance
The Message.read() method automatically handles MID resolution and request sequencing. It determines the correct chat MID based on whether the message is incoming or outgoing (using this.isMyMessage to choose between this.to.id and this.from.id).
async function markAsRead(client: LineClient, msgId: string) {
const msg = await client.base.talk.getMessage({ id: msgId });
// Sends the read receipt (chat checked) to LINE
await msg.read();
}
This wrapper calls client.base.talk.sendChatChecked() with the chat MID, last message ID, and a fresh sequence number from client.base.getReqseq() (lines 115-122 in packages/linejs/client/features/message/talk.ts).
Manual Read Receipt Delivery
Use sendChatChecked() directly when you need precise control over the chat MID and message ID, or when processing messages outside the standard Message instance context.
async function manualReadReceipt(client: LineClient) {
await client.base.talk.sendChatChecked({
chatMid: "c1234567890", // chat MID
lastMessageId: "1234567890", // message ID as string
seq: await client.base.getReqseq(),
});
}
The service implementation in packages/linejs/base/service/talk/mod.ts (lines 989-1012) uses LINEStruct.sendChatChecked_args (defined at lines 8438-8442 in packages/linejs/base/thrift/readwrite/struct.ts) to build the Thrift payload for the sendChatChecked RPC.
Handling Square (Group/Room) Chats
For Square chats (groups and rooms), LINEJS provides analogous methods in the SquareService with similar signatures but different underlying RPCs.
Reactions and Read Receipts in Square Chats
Use client.base.square.reactToMessage() and client.base.square.markAsRead() for Square-specific operations. These are implemented in packages/linejs/base/service/square/mod.ts at lines 73-80 and 61-66 respectively.
import { MessageReactionType } from "@evex/linejs-types";
async function squareDemo(client: LineClient, messageId: string, roomMid: string) {
// React to a Square message
await client.base.square.reactToMessage({
messageId,
reaction: MessageReactionType.LIKE,
});
// Mark the Square chat as read up to the latest message
await client.base.square.markAsRead({
chatMid: roomMid,
lastReadMessageId: messageId,
seq: await client.base.getReqseq(),
});
}
Both Square methods follow the same fire-and-forget pattern as their Talk counterparts, with the server pushing downstream events like MessageReactionsUpdated or ReadReceiptUpdated to other clients.
Summary
- Message.react() provides a high-level interface for adding reactions, automatically converting string IDs to BigInt and handling the
MessageReactionTypeenum mapping. - Message.read() simplifies read receipts by resolving chat MIDs based on message direction and managing request sequences via
getReqseq(). - Direct service calls (
client.base.talk.react()andclient.base.talk.sendChatChecked()) offer flexibility for batch operations or custom workflows requiring raw ID access. - Square chats use separate service methods (
reactToMessageandmarkAsRead) implemented inpackages/linejs/base/service/square/mod.ts. - All operations generate Thrift RPCs via
LINEStructbuilders and transmit over protocol 4 to the/S4endpoint according to the LINE protocol specification.
Frequently Asked Questions
What is the difference between Message.react() and client.base.talk.react()?
Message.react() is a convenience wrapper that accepts a MessageReactionType enum and handles BigInt conversion for the message ID before calling client.base.talk.react(). The direct service method requires you to pass the message ID as a BigInt and the reaction type explicitly. Both ultimately generate the same react_args Thrift payload sent to the /S4 endpoint.
How does LINEJS handle request sequencing for read receipts?
LINEJS manages request sequences through client.base.getReqseq(), which generates a monotonic sequence number for each operation. When you call Message.read() or client.base.talk.sendChatChecked(), the library includes this seq value in the Thrift payload. The LINE servers use this sequence to track operation ordering and prevent duplicate receipts across reconnections.
Can I use custom emoji reactions with LINEJS?
The current implementation in packages/linejs/base/service/talk/mod.ts uses predefinedReactionType, which maps to the MessageReactionType enum (LIKE, LOVE, HAHA, etc.). Custom emoji reactions are not supported through the react() method; you must use the predefined enum values provided by the LINE protocol as defined in packages/types/line_types.ts.
What protocol endpoint does LINEJS use for reaction RPCs?
LINEJS sends reaction and read receipt RPCs to the /S4 endpoint using protocol type 4 (the Talk protocol). This is consistent across both TalkService.react() (lines 701-719) and TalkService.sendChatChecked() (lines 989-1012) in packages/linejs/base/service/talk/mod.ts.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →