# How to Handle Talk Events versus Square (OpenChat) Events in LINEJS

> Master LINEJS Talk and Square events with Client.listen(). Learn how to enable separate streams for personal chats and OpenChat to build robust LINE bots.

- Repository: [Evex  Developers/linejs](https://github.com/evex-dev/linejs)
- Tags: how-to-guide
- Published: 2026-03-01

---

**LINEJS exposes two independent event streams—Talk (personal chats) and Square (OpenChat)—through a unified `Client.listen()` API that accepts boolean flags to enable each stream separately.**

The LINEJS library abstracts the complexity of LINE's messaging protocols by providing distinct handlers for personal chat operations and OpenChat square events. Understanding how to differentiate and process these streams is essential for building responsive bots that handle both private conversations and community group interactions.

## Understanding the Two Event Streams

LINEJS processes messages from two distinct backend services, each with its own data structures and connection handling.

### Talk Events (Operations)

Talk events represent actions in personal chats, group chats, and official account conversations. Internally, these are modeled as `Operation` objects from the `TalkService`.

- **Underlying type**: `LINETypes.Operation`
- **Source service**: `TalkService` polled through the legacy push connection
- **Emitted events**: `"event"` (raw operation), `"message"` (decrypted `TalkMessage`)

In [`packages/linejs/client/client.ts`](https://github.com/evex-dev/linejs/blob/main/packages/linejs/client/client.ts) (lines 61-75), the client decrypts end-to-end encrypted messages when operation types are `"SEND_MESSAGE"` or `"RECEIVE_MESSAGE"`, emitting a `TalkMessage` instance.

### Square Events (OpenChat)

Square events handle OpenChat communities (formerly known as Square), including message notifications, member joins, and chat room updates.

- **Underlying type**: `LINETypes.SquareEvent`
- **Source service**: `SquareService` polled through the legacy push connection
- **Emitted events**: `"square:event"` (raw event), `"square:message"` (extracted `SquareMessage`)

According to [`packages/linejs/client/client.ts`](https://github.com/evex-dev/linejs/blob/main/packages/linejs/client/client.ts) (lines 84-95), when a square event type equals `"NOTIFICATION_MESSAGE"`, the client extracts the inner message and emits it as a `SquareMessage` via the `"square:message"` event.

## Listening to Events with Client.listen()

The `Client` class provides a unified entry point for both streams through the `listen()` method, defined in [`packages/linejs/client/client.ts`](https://github.com/evex-dev/linejs/blob/main/packages/linejs/client/client.ts) (lines 56-80).

The method accepts a configuration object to selectively enable streams:

```typescript
client.listen({
  talk: true,      // Enable personal/group chat events
  square: true,    // Enable OpenChat events
  signal: abortSignal // Optional AbortSignal for cleanup
});

```

Internally, `listen()` creates a `Polling` instance via `this.base.createPolling()` and initiates asynchronous loops for each enabled stream. The polling mechanism is implemented in [`packages/linejs/base/polling/mod.ts`](https://github.com/evex-dev/linejs/blob/main/packages/linejs/base/polling/mod.ts).

## Event Handling Architecture

### Talk Event Processing

When `talk: true` is specified, the client iterates over `polling.listenTalkEvents()`, which returns a `ReadableStream<Operation>`.

As shown in [`packages/linejs/base/polling/mod.ts`](https://github.com/evex-dev/linejs/blob/main/packages/linejs/base/polling/mod.ts) (lines 80-84), the method initializes the legacy pusher and returns the operation stream:

```typescript
listenTalkEvents(): ReadableStream<Operation> {
    this.client.push.opStream.renew();
    this.initLegyPusher();
    return this.client.push.opStream.stream;
}

```

The client then processes each operation, emitting raw events as `"event"` and decrypted messages as `"message"` when applicable.

### Square Event Processing

Similarly, `listenSquareEvents()` in [`packages/linejs/base/polling/mod.ts`](https://github.com/evex-dev/linejs/blob/main/packages/linejs/base/polling/mod.ts) manages the OpenChat stream:

```typescript
listenSquareEvents(): ReadableStream<SquareEvent> {
    this.client.push.sqStream.renew();
    this.initLegyPusher();
    return this.client.push.sqStream.stream;
}

```

The client handles these events by emitting `"square:event"` for all events and `"square:message"` specifically for `NOTIFICATION_MESSAGE` types.

### Abort Signal Handling

To gracefully stop listening, pass an `AbortSignal` in the options. The client automatically closes both push streams when the signal aborts, as implemented in [`packages/linejs/client/client.ts`](https://github.com/evex-dev/linejs/blob/main/packages/linejs/client/client.ts) (lines 51-55):

```typescript
signal && signal.addEventListener("abort", () => {
    this.base.push.opStream.close();
    this.base.push.sqStream.close();
});

```

## Practical Implementation Examples

The following example demonstrates handling both event types simultaneously:

```typescript
import { Client } from "@evex/linejs/client/mod.ts";

// Assume `base` is a logged-in BaseClient instance
const client = new Client(base);

// Enable both streams
client.listen({ talk: true, square: true });

// Handle Talk messages (personal/group chats)
client.on("message", (msg) => {
  console.log("[Talk] From:", msg.raw.senderMid, "Text:", msg.raw.text);
});

// Handle raw Talk operations (system events, read receipts, etc.)
client.on("event", (op) => {
  console.log("[Talk Event] Type:", op.type);
});

// Handle Square (OpenChat) messages
client.on("square:message", (msg) => {
  console.log("[Square] Chat:", msg.raw.chatMid, "Text:", msg.raw.text);
});

// Handle raw Square events (member joins, chat updates, etc.)
client.on("square:event", (ev) => {
  console.log("[Square Event] Type:", ev.type);
});

// Graceful shutdown example
const controller = new AbortController();
client.listen({ talk: true, square: false, signal: controller.signal });

// Later, to stop listening:
controller.abort(); // Closes opStream and sqStream

```

## Summary

- **Talk events** use `Operation` objects from `TalkService`, exposed via the `"event"` and `"message"` emitters in [`packages/linejs/client/client.ts`](https://github.com/evex-dev/linejs/blob/main/packages/linejs/client/client.ts).
- **Square events** use `SquareEvent` objects from `SquareService`, exposed via `"square:event"` and `"square:message"` emitters.
- Both streams are managed by the `Polling` class in [`packages/linejs/base/polling/mod.ts`](https://github.com/evex-dev/linejs/blob/main/packages/linejs/base/polling/mod.ts), which interfaces with the legacy push connection.
- Enable streams independently using `Client.listen({ talk: boolean, square: boolean })` and handle cleanup with an optional `AbortSignal`.

## Frequently Asked Questions

### What is the difference between Talk and Square events in LINEJS?

Talk events represent actions in personal chats, group conversations, and official account messages, modeled as `Operation` types from the `TalkService`. Square events represent OpenChat community interactions, modeled as `SquareEvent` types from the `SquareService`. The two streams use separate underlying connections but are exposed through the same `Client.listen()` API.

### How do I enable only Square (OpenChat) events in LINEJS?

Pass `talk: false` and `square: true` to the `listen()` method:

```typescript
client.listen({ talk: false, square: true });
client.on("square:message", (msg) => {
  console.log("OpenChat message:", msg.raw.text);
});

```

This configuration prevents the client from initializing the Talk operation stream and only processes Square events.

### Can I listen to both Talk and Square events simultaneously?

Yes, the `Client` class supports concurrent processing of both streams. Set both options to `true` in `Client.listen()` and attach listeners for both `"message"`/`"event"` (Talk) and `"square:message"`/`"square:event"` (Square). The underlying `Polling` class manages both streams through separate `ReadableStream` instances.

### Where are the event streams implemented in the LINEJS source code?

The high-level event handling is implemented in [`packages/linejs/client/client.ts`](https://github.com/evex-dev/linejs/blob/main/packages/linejs/client/client.ts), which emits events and manages the `listen()` lifecycle. The underlying stream polling logic resides in [`packages/linejs/base/polling/mod.ts`](https://github.com/evex-dev/linejs/blob/main/packages/linejs/base/polling/mod.ts), which interfaces with the legacy push connection (`LegyPusher`) and provides `listenTalkEvents()` and `listenSquareEvents()` methods. The service-level APIs are defined in [`packages/linejs/base/service/talk/mod.ts`](https://github.com/evex-dev/linejs/blob/main/packages/linejs/base/service/talk/mod.ts) (TalkService) and [`packages/linejs/base/service/square/mod.ts`](https://github.com/evex-dev/linejs/blob/main/packages/linejs/base/service/square/mod.ts) (SquareService).