# 🐳 changli-baileys

A Changli-focused fork of [WhiskeySockets/Baileys](https://github.com/WhiskeySockets/Baileys) v7 with additional modifications from the [Ourin-Baileys](https://github.com/LuckyArch/ourin-baileys) lineage. This repo includes deliberate changes for Changli bot use, such as safer newsletter action handling, removed hidden auto-follow behavior, and custom socket utilities.

This package is published to npm for installation convenience and aliasing, but the source repository contains the active customization work.

[![npm version](https://img.shields.io/npm/v/changli-baileys?color=CB3837&logo=npm&logoColor=white&style=for-the-badge)](https://www.npmjs.com/package/changli-baileys)
[![npm downloads](https://img.shields.io/npm/dm/changli-baileys?color=CB3837&logo=npm&logoColor=white&style=for-the-badge)](https://www.npmjs.com/package/changli-baileys)
[![GitHub](https://img.shields.io/github/stars/kyleee-max/changli-baileys?color=181717&logo=github&logoColor=white&style=for-the-badge)](https://github.com/kyleee-max/changli-baileys)
[![License](https://img.shields.io/badge/license-MIT-blue?style=for-the-badge)](LICENSE)
[![Node](https://img.shields.io/badge/node-%3E%3D20.0.0-339933?logo=node.js&logoColor=white&style=for-the-badge)](https://nodejs.org)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.8-3178C6?logo=typescript&logoColor=white&style=for-the-badge)](https://typescriptlang.org)
[![ESM](https://img.shields.io/badge/ESM-only-F7DF1E?logo=javascript&logoColor=black&style=for-the-badge)](#)

---

## What is this fork?

| Item | Description |
| --- | --- |
| `changli-baileys` | Personal fork for Changli bot features and newsletter utilities |
| `changli` | npm alias for easier import in bot projects |
| `baileys` | Original WhatsApp multi-device library from WhiskeySockets |

This repository is intended for private Changli development. It is not a plain mirror or redistribution — the code includes custom changes for newsletter safety, socket behavior, and interactive message handling.

**Copyright notice:** Baileys and its underlying protocol code remain the property of their original authors. This fork is licensed under MIT and includes modifications from the Ourin-Baileys lineage.

---

🌾 Donation / support link: [Saweria](https://saweria.co/ChangliMD)

---

## ✨ Features

| Feature | Description | Status |
|---------|-------------|--------|
| 🎛️ **Interactive Messages** | Native flow buttons, lists, menus | ✅ |
| 🖼️ **Album Messages** | Multi-image/video album support | ✅ |
| 🤖 **AI Rich Response** | Table, code block, rich text (Meta AI style) [ **NEW** ] | ✅ |
| 💻 **Code Block** | Syntax-highlighted code with tokenizer | ✅ |
| 💳 **Payment Messages** | Request payment with sticker/note | ✅ |
| 🛍️ **Product Messages** | Product catalog with buttons | ✅ |
| 📅 **Event Messages** | Event creation with RSVP | ✅ |
| 📊 **Poll Results** | Poll result snapshot messages | ✅ |
| 📢 **Newsletter** | bulk follow, cekIDSaluran | ✅ |
| 🔒 **Biz Node Injection** | Automatic business node for non-BA | ✅ |
| ⚡ **ESM Native** | Pure ES Module output | ✅ |
| 📖 **TypeScript** | Full type definitions included | ✅ |

---

## 📦 Installation

This package is published to npm for convenience and easier installation, not as a vanilla copy. The source repo contains the actual forked development and unique Changli bot adaptations.

### Install from npm

```bash
npm install changli-baileys
```

### Install with alias

In `package.json`:

```json
{
  "dependencies": {
    "changli": "npm:changli-baileys@latest"
  }
}
```

Then run:

```bash
npm install
```

> Tip: Use the alias `changli` so you can import with `import changli from 'changli'` without changing existing bot code.

---

## 🛠️ Setup Awal (Dari Nol)

### 1️⃣ Persiapan Project

```bash
mkdir my-bot
cd my-bot
npm init -y
```

Pastikan `package.json` punya `"type": "module"`:

```json
{
  "name": "my-bot",
  "type": "module",
  "dependencies": {
    "changli": "npm:changli-baileys@latest"
  }
}
```

> [!IMPORTANT]
> **Wajib** pakai `"type": "module"` karena changli-baileys adalah ESM-only package. Tanpa ini, import akan error.

### 2️⃣ Install Dependencies

```bash
npm install changli-baileys pino
```

### 3️⃣ Buat File `index.js`

```js
import makeWASocket, {
  useMultiFileAuthState,
  DisconnectReason,
  Browsers
} from 'changli-baileys'
import pino from 'pino'

const logger = pino({ level: 'silent' })

async function startBot() {
  const { state, saveCreds } = await useMultiFileAuthState('./session')

  const sock = makeWASocket({
    auth: state,
    logger,
    printQRInTerminal: true,
    browser: Browsers.ubuntu('Chrome')
  })

  sock.ev.on('creds.update', saveCreds)

  sock.ev.on('connection.update', ({ connection, lastDisconnect }) => {
    if (connection === 'close') {
      const shouldReconnect =
        lastDisconnect?.error?.output?.statusCode !== DisconnectReason.loggedOut
      if (shouldReconnect) startBot()
    }

    if (connection === 'open') {
      console.log('✅ Bot connected!')
    }
  })

  sock.ev.on('messages.upsert', async ({ messages }) => {
    const msg = messages[0]
    if (!msg?.message || msg.key.fromMe) return

    const text =
      msg.message.conversation ||
      msg.message.extendedTextMessage?.text ||
      ''

    if (text === '.ping') {
      await sock.sendMessage(msg.key.remoteJid, { text: '🏓 Pong!' })
    }

    if (text === '.menu') {
      await sock.sendMessage(msg.key.remoteJid, {
        interactiveMessage: {
          title: '📋 Bot Menu',
          footer: '⚡ Powered by changli-baileys',
          buttons: [
            {
              name: 'quick_reply',
              buttonParamsJson: JSON.stringify({
                display_text: '🏓 Ping',
                id: '.ping'
              })
            },
            {
              name: 'quick_reply',
              buttonParamsJson: JSON.stringify({
                display_text: 'ℹ️ Info',
                id: '.info'
              })
            }
          ],
          header: 'Main Menu'
        }
      })
    }
  })
}

startBot()
```

### 4️⃣ Jalankan Bot

```bash
node index.js
```

> Scan QR code yang muncul di terminal, lalu kirim `.ping` atau `.menu` untuk test! 🎉

---

## 🎛️ Interactive Messages

### Native Flow Buttons

```js
await sock.sendMessage(jid, {
  interactiveMessage: {
    title: '🎉 Welcome!',
    footer: 'Powered by Changli-MD',
    buttons: [
      {
        name: 'quick_reply',
        buttonParamsJson: JSON.stringify({
          display_text: '📋 Menu',
          id: 'menu'
        })
      },
      {
        name: 'cta_url',
        buttonParamsJson: JSON.stringify({
          display_text: '🌐 Website',
          url: 'https://example.com'
        })
      },
      {
        name: 'cta_copy',
        buttonParamsJson: JSON.stringify({
          display_text: '📋 Copy Code',
          copy_code: 'CHANGLI2026'
        })
      }
    ],
    header: 'Choose an option',
    image: { url: 'https://example.com/banner.jpg' }
  }
})
```

### Interactive Buttons (viewOnce wrapper)

```js
await sock.sendMessage(jid, {
  text: 'Hello World!',
  title: 'Welcome',
  footer: 'Choose below',
  interactiveButtons: [
    {
      name: 'quick_reply',
      buttonParamsJson: JSON.stringify({
        display_text: '✅ Confirm',
        id: 'confirm'
      })
    },
    {
      name: 'quick_reply',
      buttonParamsJson: JSON.stringify({
        display_text: '❌ Cancel',
        id: 'cancel'
      })
    }
  ]
})
```

### List Menu

```js
await sock.sendMessage(jid, {
  interactiveMessage: {
    title: '📋 Pilih Kategori',
    footer: 'Powered by Changli',
    buttons: [
      {
        name: 'single_select',
        buttonParamsJson: JSON.stringify({
          title: 'Menu List',
          sections: [
            {
              title: '🎮 Games',
              rows: [
                { title: 'Tebak Gambar', id: '.tebakgambar' },
                { title: 'Quiz', id: '.quiz' }
              ]
            },
            {
              title: '🔧 Tools',
              rows: [
                { title: 'Sticker', id: '.sticker' },
                { title: 'TTS', id: '.tts' }
              ]
            }
          ]
        })
      }
    ],
    header: 'Bot Menu'
  }
})
```

---

## 🖼️ Album Messages

```js
await sock.sendMessage(jid, {
  albumMessage: [
    { image: { url: './photo1.jpg' }, caption: 'First 📸' },
    { image: { url: './photo2.jpg' }, caption: 'Second 📸' },
    { video: { url: './clip.mp4' }, caption: 'Video 🎥' }
  ]
})
```

> [!NOTE]
> Albums otomatis set `expectedImageCount` dan `expectedVideoCount` berdasarkan isi array.

---

## 📢 Newsletter Methods

```js

// 🔍 Resolve channel URL ke metadata
const info = await sock.cekIDSaluran('https://whatsapp.com/channel/xxxxx')
console.log(info.name, info.subscribers)

// 📥 Bulk follow multiple channels
await sock.newsletterMultipleFollow('id1@newsletter id2@newsletter')

// 📋 Fetch semua subscribed channels
const channels = await sock.newsletterFetchAllSubscribe()

// ⚡ Generic action (follow/unfollow/mute)
await sock.newsletterAction('id@newsletter', 'follow')
```

---

## 📊 Other Message Types

### 💳 Payment Request

```js
await sock.sendMessage(jid, {
  requestPaymentMessage: {
    amount: 50000,
    currency: 'IDR',
    note: 'Payment for order #123',
    from: '628xxx@s.whatsapp.net'
  }
})
```

### 📅 Event

```js
await sock.sendMessage(jid, {
  eventMessage: {
    name: '🎉 Community Meetup',
    description: 'Join us for the monthly meetup!',
    startTime: Date.now() + 86400000,
    endTime: Date.now() + 90000000,
    location: {
      name: 'Jakarta',
      degreesLatitude: -6.2,
      degreesLongitude: 106.8
    }
  }
})
```

### 📊 Poll Result

```js
await sock.sendMessage(jid, {
  pollResultMessage: {
    name: 'Favorite Color?',
    pollVotes: [
      { optionName: '🔴 Red', optionVoteCount: 42 },
      { optionName: '🔵 Blue', optionVoteCount: 38 },
      { optionName: '🟢 Green', optionVoteCount: 25 }
    ]
  }
})
```

### 📢 Status with Mentions

```js
await sock.sendStatusMention(
  { text: '🔥 Big update coming!' },
  ['628xxx@s.whatsapp.net', 'groupid@g.us']
)
```

### 🛍️ Product Message

```js
await sock.sendMessage(jid, {
  productMessage: {
    title: '🎧 Wireless Headphones',
    description: 'High quality bluetooth headphones',
    productId: 'WH-001',
    retailerId: 'changli-shop',
    url: 'https://example.com/product',
    priceAmount1000: 299000,
    currencyCode: 'IDR',
    thumbnail: { url: 'https://example.com/product.jpg' },
    body: 'Check out this product!',
    footer: 'Changli Shop',
    buttons: [
      {
        name: 'quick_reply',
        buttonParamsJson: JSON.stringify({
          display_text: '🛒 Buy Now',
          id: 'buy_wh001'
        })
      }
    ]
  }
})
```

---


> [!IMPORTANT]
> Package ini output **ESM only**. Project kamu harus punya `"type": "module"` di `package.json` atau pakai file `.mjs`.

---

## 🤖 AI Rich Response Messages

Kirim pesan bergaya Meta AI — tabel, code block dengan syntax highlighting, dan rich text. Semua dirender via `botForwardedMessage` > `richResponseMessage`.

### 📊 Table (dengan heading)

```js
await sock.sendTable(jid, 'Java vs JavaScript',
  ['Feature', 'Java', 'JavaScript'],
  [
    ['Type', 'Compiled', 'Interpreted'],
    ['Typing', 'Static', 'Dynamic'],
    ['Main Use', 'Enterprise, Android', 'Web, Full-stack']
  ],
  quoted, // optional, pass message object for quoting
  {
    headerText: 'Here is a comparison:',  // text before table
    footer: 'Hope this helps!'            // text after table
  }
)
```

### 📋 List (tanpa heading)

```js
await sock.sendList(jid, 'Bot Info',
  [
    ['Nama', 'Changli AI'],
    ['Versi', '2.4.0'],
    ['Developer', 'Zann']
  ],
  quoted,
  { footer: '© Changli AI' }
)
```

### 💻 Code Block (dengan syntax highlighting)

```js
await sock.sendCodeBlock(jid,
  `const greeting = "Hello World"
function sayHello(name) {
    return greeting + " " + name
}
sayHello("Changli") // output: Hello World Changli`,
  quoted,
  {
    language: 'javascript',  // default: 'javascript'
    title: '📝 Example Code',
    footer: 'Powered by Changli'
  }
)
```

**Supported languages:** `javascript`, `typescript`, `python` (auto keyword detection)

### 🔀 Mixed Rich Message (custom submessages)

```js
await sock.sendRichMessage(jid, [
  { messageType: 2, messageText: 'Here is some info:' },
  {
    messageType: 4,
    tableMetadata: {
      title: 'Stats',
      rows: [
        { items: ['Metric', 'Value'], isHeading: true },
        { items: ['Users', '1000'] },
        { items: ['Uptime', '99.9%'] }
      ]
    }
  },
  { messageType: 2, messageText: 'And some code:' },
  {
    messageType: 5,
    codeMetadata: {
      codeLanguage: 'javascript',
      codeBlocks: [{ highlightType: 0, codeContent: 'console.log("OK")' }]
    }
  }
], quoted)
```

### SubMessage Types

| messageType | Name | Payload Field |
|---|---|---|
| 0 | UNKNOWN | — |
| 1 | GRID_IMAGE | `gridImageMetadata` |
| 2 | TEXT | `messageText` |
| 3 | INLINE_IMAGE | `imageMetadata` |
| 4 | TABLE | `tableMetadata` |
| 5 | CODE | `codeMetadata` |
| 6 | DYNAMIC | `dynamicMetadata` |
| 7 | MAP | `mapMetadata` |
| 8 | LATEX | `latexMetadata` |
| 9 | CONTENT_ITEMS | `contentItemsMetadata` |

### Code Highlight Types

| highlightType | Name | Color |
|---|---|---|
| 0 | DEFAULT | Normal text |
| 1 | KEYWORD | `import`, `const`, `function` |
| 2 | METHOD | Function/method calls |
| 3 | STRING | String literals |
| 4 | NUMBER | Numeric values |
| 5 | COMMENT | Comments (`//`, `#`) |

### Utility Functions (Advanced)

```js
import {
  tokenizeCode,
  generateTableContent,
  generateListContent,
  generateCodeBlockContent,
  generateRichMessageContent,
  buildRichContextInfo,
  buildBotForwardedMessage,
  CodeHighlightType,
  RichSubMessageType,
} from 'changli-baileys'
```

---

## 🔀 Perbedaan dengan Official Baileys

| Area | Official Baileys v7 | changli-baileys |
|------|---------------------|---------------|
| Interactive messages | ❌ Tidak ada native support | ✅ Full support via Dugong |
| Album messages | ❌ Tidak support | ✅ Multi-media albums |
| AI Rich Response | ❌ Tidak ada | ✅ Table, code block, rich text |
| Code Block | ❌ Tidak ada | ✅ Syntax highlighting (JS/TS/Python) |
| Business nodes | ❌ Inject manual | ✅ Auto-inject di relay |
| Newsletter extras | ❌ Basic saja | ✅ Auto-follow, bulk, resolve |
| Button detection | ❌ Tidak ada | ✅ `getButtonType()` auto-detect |
| Payment messages | ❌ Tidak support | ✅ Full support |
| Event messages | ❌ Basic | ✅ Enhanced semua field |
| Status mentions | ❌ Tidak ada | ✅ `sendStatusMention()` |
| Product messages | ❌ Tidak support | ✅ Catalog + buttons |

---

## 🔧 Development (Building from Source)

```bash
git clone https://github.com/LuckyArch/changli-baileys.git
cd changli-baileys
npm install
npm run build
```

> [!WARNING]
> Butuh **Node.js ≥ 20.0.0** dan **TypeScript ≥ 5.8** untuk build dari source.

---

## 🤝 Contributing

1. Fork repo ini
2. Buat branch baru (`git checkout -b feature/nama-fitur`)
3. Commit changes (`git commit -m 'feat: tambah fitur baru'`)
4. Push ke branch (`git push origin feature/nama-fitur`)
5. Buat Pull Request

---

## 📄 License

MIT © [LuckyArch](https://github.com/LuckyArch)

> [!CAUTION]
> Library ini untuk **keperluan edukasi**. Pastikan kamu mematuhi Terms of Service WhatsApp.

---

<div align="center">

**Made with 💚 by the Zann**

[⭐ Star this repo](https://github.com/LuckyArch/changli-baileys) · [🐛 Report Bug](https://github.com/LuckyArch/changli-baileys/issues) · [💡 Request Feature](https://github.com/LuckyArch/changli-baileys/issues)

</div>
