npm package: @rurimeiko/zalo-channel
Description: Zalo messaging integration for OpenClaw - Multi-account support with QR/cookie login, message sending, and event handling (TypeScript)
Latest version: 1.0.17

# OpenClaw Zalo Channel Plugin (TypeScript)

Zalo messaging integration for OpenClaw Gateway. Based on MultiZlogin architecture with support for multiple accounts, proxy rotation, and comprehensive event handling. Written in TypeScript for better type safety and maintainability.

## Features

- **Multi-account support**: Login and manage multiple Zalo accounts simultaneously
- **QR & Cookie login**: Login via QR code or reuse saved cookies
- **Message handling**: Send/receive text messages, images, stickers, reactions
- **Group support**: Full support for group chats
- **Proxy support**: Automatic proxy rotation and health checks
- **Webhook forwarding**: Forward all events to external webhooks
- **Auto-relogin**: Automatic reconnection when connection drops
- **Bot message filtering**: Prevent echo loops using Redis caching
- **Health monitoring**: Connection health checks and retry logic
- **TypeScript**: Full type safety and IntelliSense support

## Project Structure

```
openclaw-zalo-channel/
├── src/
│   ├── config/
│   │   ├── types.ts          # TypeScript interfaces and types
│   │   ├── constants.ts      # Constants and enums
│   │   └── env.ts            # Environment configuration
│   ├── services/
│   │   ├── zaloService.ts    # Core Zalo API (login, logout, messaging)
│   │   ├── eventService.ts   # Event handling and webhooks
│   │   ├── redisService.ts   # Redis caching for bot messages
│   │   └── proxyService.ts   # Proxy management
│   ├── controllers/
│   │   ├── channelController.ts   # Channel registration
│   │   ├── commandController.ts   # CLI commands
│   │   ├── toolController.ts      # Agent tools
│   │   └── serviceController.ts   # Background service
│   ├── utils/
│   │   └── helpers.ts        # Utility functions
│   └── index.ts              # Plugin entry point
├── dist/                     # Compiled JavaScript (after build)
├── openclaw.plugin.json      # Plugin manifest
├── package.json              # NPM configuration
├── tsconfig.json             # TypeScript configuration
└── README.md                 # This file
```

## Installation

### Prerequisites

- Node.js 18+
- TypeScript 5.3+
- Redis server (optional, for bot message caching)

### Build from Source

```bash
# Install dependencies
npm install

# Build TypeScript
npm run build

# Or watch for changes during development
npm run build:watch
```

### Install to OpenClaw

```bash
# Copy plugin to OpenClaw extensions directory
cp -r openclaw-zalo-channel /path/to/openclaw/extensions/

# Or use OpenClaw CLI
openclaw plugin install ./openclaw-zalo-channel
```

## Configuration

Add to your `openclaw.json`:

```json
{
  "plugins": {
    "entries": {
      "openclaw-zalo-channel": {
        "enabled": true,
        "config": {
          "dataPath": "./data/zalo",
          "webhookUrl": "https://your-webhook-endpoint.com/webhook",
          "redisUrl": "redis://localhost:6379",
          "maxAccountsPerProxy": 3,
          "proxies": [
            "http://proxy1.example.com:8080",
            "http://proxy2.example.com:8080"
          ]
        }
      }
    }
  }
}
```

### Configuration Options

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `dataPath` | string | `./data/zalo` | Directory for storing cookies and credentials |
| `webhookUrl` | string | - | URL to forward Zalo events (messages, reactions, group events) |
| `redisUrl` | string | `redis://localhost:6379` | Redis connection URL for bot message caching |
| `maxAccountsPerProxy` | number | 3 | Maximum accounts per proxy |
| `proxies` | array | [] | List of proxy URLs for rotation |

## CLI Commands

### `/zalo:login [proxy_url]`
Login to Zalo account via QR code or saved cookie.

```
/zalo:login
/zalo:login http://proxy.example.com:8080
```

### `/zalo:logout <ownId>`
Logout from a specific Zalo account.

```
/zalo:logout 123456789
```

### `/zalo:accounts`
List all logged in Zalo accounts with their connection status.

```
/zalo:accounts
```

### `/zalo:send <ownId> <threadId> <user|group> <message>`
Send a message via a specific account.

```
/zalo:send 123456789 987654321 user Hello World!
/zalo:send 123456789 987654321 group Hello Group!
```

### `/zalo:status`
Show plugin status (total accounts, online/offline count).

```
/zalo:status
```

## Agent Tools

### `zalo_send_message`
Send a text message to a Zalo user or group.

```typescript
{
  accountId: string;    // Zalo account ID (ownId)
  threadId: string;     // Target user or group ID
  threadType: "user" | "group";
  message: string;      // Message content
}
```

### `zalo_send_image`
Send an image to a conversation.

```typescript
{
  accountId: string;
  threadId: string;
  threadType: "user" | "group";
  imageUrl: string;     // URL of the image
}
```

### `zalo_get_user_info`
Get information about a Zalo user by phone number or user ID.

```typescript
{
  accountId: string;
  phoneNumber?: string;  // Optional if userId provided
  userId?: string;       // Optional if phoneNumber provided
}
```

### `zalo_find_user`
Find a Zalo user by phone number.

```typescript
{
  accountId: string;
  phoneNumber: string;
}
```

### `zalo_send_typing`
Send typing indicator to a conversation.

```typescript
{
  accountId: string;
  threadId: string;
  threadType: "user" | "group";
}
```

### `zalo_add_reaction`
Add a reaction (emoji) to a message.

```typescript
{
  accountId: string;
  msgId: string;
  threadId: string;
  threadType: "user" | "group";
  icon: string;         // Emoji like ❤️, 👍, 😂
}
```

### `zalo_send_sticker`
Send a sticker to a conversation.

```typescript
{
  accountId: string;
  threadId: string;
  threadType: "user" | "group";
  sticker: object;      // Sticker object with id, type, etc.
}
```

### `zalo_get_group_info`
Get information about a Zalo group.

```typescript
{
  accountId: string;
  groupId: string;
}
```

## Channel Integration

As a channel plugin, it integrates with OpenClaw's channel system:

```typescript
// Send via OpenClaw Gateway
api.gateway.send({
  channel: "zalo",
  accountId: "<ownId>",
  target: { threadId: "<user_or_group_id>" },
  content: { text: "Hello from OpenClaw!" },
  metadata: { threadType: "user" }
});
```

## Webhook Events

Events are sent to the configured `webhookUrl`:

### Message Event
```json
{
  "event": "message",
  "timestamp": 1234567890,
  "data": {
    "accountId": "123456789",
    "messageType": "user",
    "isGroup": false,
    "chatType": "personal",
    "bot": false,
    "raw": { /* raw message data */ }
  }
}
```

### Login Success Event
```json
{
  "event": "login_success",
  "timestamp": 1234567890,
  "data": {
    "ownId": "123456789",
    "displayName": "User Name",
    "phoneNumber": "+84123456789",
    "proxy": "http://proxy.example.com:8080"
  }
}
```

### Group Event
```json
{
  "event": "group_event",
  "timestamp": 1234567890,
  "data": {
    "accountId": "123456789",
    "raw": { /* group event data */ }
  }
}
```

### Reaction Event
```json
{
  "event": "reaction",
  "timestamp": 1234567890,
  "data": {
    "accountId": "123456789",
    "raw": { /* reaction data */ }
  }
}
```

## Data Directory Structure

```
data/zalo/
├── cookies/
│   ├── cred_<ownId1>.json    # Saved credentials for account 1
│   └── cred_<ownId2>.json    # Saved credentials for account 2
└── proxies.json               # Proxy configuration (auto-generated)
```

## Architecture

### Services

- **zaloService.ts**: Core Zalo functionality - login/logout, messaging, account management
- **eventService.ts**: Event handling - message, group, reaction events and webhook forwarding
- **redisService.ts**: Redis caching - bot message deduplication
- **proxyService.ts**: Proxy management - rotation, health checks

### Controllers

- **channelController.ts**: Channel registration with OpenClaw
- **commandController.ts**: CLI command handlers
- **toolController.ts**: Agent tool registration
- **serviceController.ts**: Background service (health checks, cleanup)

### Utilities

- **helpers.ts**: Common utilities - image download, file operations, validators

## Auto-Relogin

The plugin automatically handles connection drops:
- Detects disconnection via listener events and health checks
- Attempts re-login using saved cookies
- Exponential backoff retry (max 5 attempts)
- Resets retry counter after 30 minutes
- Lock mechanism prevents concurrent relogin attempts

## Bot Message Caching

Uses Redis to prevent echo loops:
- All sent messages are cached with TTL (24 hours)
- Incoming messages are checked against cache
- Marked with `bot: true` if from self
- Prevents the bot from responding to its own messages

## Dependencies

### Runtime
- `zca-js`: Zalo unofficial API SDK
- `https-proxy-agent`: Proxy support
- `ioredis`: Redis client
- `axios`: HTTP requests

### Development
- `typescript`: TypeScript compiler
- `@types/node`: Node.js type definitions

## API Types

The plugin exports TypeScript interfaces for external use:

```typescript
import {
  OpenClawApi,
  ZaloAccount,
  ZaloMessage,
  ZaloCredentials,
  SendTextParams,
  // ... and more
} from 'openclaw-zalo-channel';
```

## Development

```bash
# Install dependencies
npm install

# Build
npm run build

# Watch mode
npm run build:watch

# Clean build artifacts
npm run clean
```

## License

MIT