JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 567
  • Score
    100M100P100Q85376F
  • License MIT

Node.js client for Max Messenger with QR code and token authentication

Package Exports

  • webmaxsocket
  • webmaxsocket/index.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (webmaxsocket) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

WebMaxSocket - Node.js Client for Max Messenger

📖 Описание / Description

WebMaxSocket — async Node.js библиотека для работы с внутренним API мессенджера Max. Поддерживает QR-код авторизацию, Token авторизацию, и работу через WebSocket (WEB) или TCP Socket (IOS/ANDROID).

✨ Особенности / Features

  • QR-код авторизация / QR code authentication
  • QR для привязки устройства (showLinkDeviceQR) после входа по SMS/TCP — тот же сценарий, что «Профиль → Устройства → Подключить устройство» в приложении
  • Token авторизация / Token authentication
  • Два транспорта: WebSocket (WEB) и TCP Socket (IOS/ANDROID)
  • Автоматическое сохранение сессий / Automatic session storage
  • Автовыбор транспорта после QR-авторизации (переход на TCP)
  • Отправка и получение сообщений / Send and receive messages
  • Скачивание вложений по URL (baseUrl из attaches) во временный файл — downloadUrlToTempFile, message.downloadAttachment()
  • Редактирование и удаление сообщений / Edit and delete messages
  • Event-driven архитектура / Event-driven architecture
  • Обработка входящих уведомлений / Handle incoming notifications
  • Встроенный лог входящих (logIncoming, WEBMAX_DEBUG, WEBMAX_SILENT) — JSON в консоль без ручных обработчиков
  • TypeScript-ready структура / TypeScript-ready structure

📦 Установка / Installation

npm install webmaxsocket

Зависимости для Socket транспорта (IOS/ANDROID)

Для работы с TCP Socket транспортом требуется библиотека lz4. Если при установке возникают проблемы с node-gyp:

npm install lz4 --ignore-scripts

Примечание: Для обычной QR-авторизации (WEB) дополнительные зависимости не нужны. Socket транспорт используется только после сохранения сессии или при явном указании deviceType: 'IOS'/'ANDROID'.

🚀 Быстрый старт / Quick Start

Базовый пример / Basic Example

const { WebMaxClient } = require('webmaxsocket');

async function main() {
  // Инициализация клиента / Initialize client
  const client = new WebMaxClient({
    name: 'my_session'  // Имя сессии / Session name
  });

  // Обработчик запуска / Start handler
  client.onStart(async () => {
    console.log('✅ Бот запущен!');
    console.log(`👤 Вы вошли как: ${client.me.fullname}`);
  });

  // Обработчик сообщений / Message handler
  client.onMessage(async (message) => {
    // Не отвечаем на свои сообщения / Don't reply to own messages
    if (message.senderId === client.me.id) return;
    
    console.log(`💬 ${message.getSenderName()}: ${message.text}`);
    
    // Автоответ / Auto-reply
    await message.reply({
      text: `Привет! Я получил: "${message.text}"`
    });
  });

  // Запуск / Start
  await client.start();
}

main().catch(console.error);

Авторизация / Authentication

Способ 1: QR-код (рекомендуется для первого запуска)

При первом запуске вы увидите QR-код в консоли:

🔐 АВТОРИЗАЦИЯ ЧЕРЕЗ QR-КОД
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

📱 На телефоне: Профиль → Устройства / Безопасность → Подключить устройство
📸 Отсканируйте QR-код

█████████████████████████████
...

После сканирования:

  • Токен и clientSessionId сохраняются автоматически
  • При следующем запуске клиент автоматически переключится на TCP Socket для стабильности
  • Повторная авторизация не требуется

Способ 2: SMS авторизация (IOS/ANDROID)

Авторизация по номеру телефона с кодом из SMS:

const client = new WebMaxClient({
  name: 'my_session',
  deviceType: 'IOS'  // Обязательно для SMS авторизации
});

await client.connect();

// Запрос кода
const authSession = await client.authorizeBySMS('+79001234567');

// Получаем код из SMS и отправляем
const code = '123456';  // Код из SMS
await authSession.sendCode(code);

// Завершаем запуск
await client.triggerHandlers(client.handlers.START);

Или запустите готовый пример:

node example-sms.js
node example-sms.js +79001234567  # с номером в аргументе

QR после входа: привязка второго устройства (IOS/ANDROID)

Когда вы уже авторизованы по TCP (SMS и сохранённая сессия), запрос GET_QR на том же соединении недоступен (ответ сервера: недопустимое состояние сессии). Для сценария как в приложении — показать QR, телефон сканирует — используйте метод showLinkDeviceQR(): библиотека открывает отдельное краткоживущее WebSocket-подключение (как у web.max.ru), запрашивает QR, печатает его в консоль и при необходимости ждёт сканирования.

Требования: активное соединение и isAuthorized (обычно после await client.start()).

await client.start();

// Показать QR и ждать, пока отсканируют в приложении Max на телефоне
await client.showLinkDeviceQR();

// Только показать QR и вернуть данные (без ожидания скана)
const data = await client.showLinkDeviceQR({ waitForScan: false });
// data: { qrLink, trackId, pollingInterval, expiresAt }

Опции: waitForScan (по умолчанию true), small — компактный QR в терминале.

Версия клиента: для выдачи QR сервер ожидает актуальный appVersion в User-Agent (не ниже 25.12.13). В конструкторе по умолчанию используется 25.12.14; при необходимости передайте appVersion: '25.21.3' или новее.

Если сервер отвечает qr_login.disabled, проверьте версию приложения в опциях, откройте web.max.ru в браузере или войдите на втором устройстве по номеру телефона.

Способ 3: Token авторизация

Если у вас уже есть токен (от другого сервиса/приложения):

const client = new WebMaxClient({
  name: 'my_session',
  token: 'An_Sx6HQ9HDiftNkVBNf6Q5PG5D8Oyj...',  // Ваш токен
  configPath: 'config/myconfig.json',  // Или из файла
  saveToken: true
});

await client.start();

Формат конфига (config/default.json):

{
  "token": "An_Sx6HQ9HDiftNk...",
  "ua": "Mozilla/5.0 (iPhone...)",
  "device_type": 2,
  "deviceType": "IOS"
}

Транспорты

  • WEB (deviceType: 'WEB' или device_type: 1) → WebSocket (ws-api.oneme.ru)
  • IOS (deviceType: 'IOS' или device_type: 2) → TCP Socket (api.oneme.ru)
  • ANDROID (deviceType: 'ANDROID' или device_type: 3) → TCP Socket (api.oneme.ru)

Клиент автоматически выбирает правильный транспорт на основе сохраненного deviceType.

API

WebMaxClient

Основной класс для работы с API Max.

Конструктор

const client = new WebMaxClient({
  name: 'session',        // Имя сессии (для сохранения авторизации)
  token: 'An_Sx6H...',    // Токен авторизации (опционально)
  configPath: 'myconfig', // Путь к config файлу (опционально)
  deviceType: 'WEB',      // Тип устройства: 'WEB', 'IOS', 'ANDROID', 'DESKTOP' (опционально)
  saveToken: true,        // Сохранять токен в сессию (по умолчанию true)
  debug: false,           // TCP/WebSocket: краткий лог opcode; также учитывается WEBMAX_DEBUG=1, DEBUG=1
  // Лог входящих (JSON в консоль), см. ниже:
  logIncoming: undefined, // false | 'messages' | 'verbose' — по умолчанию см. таблицу
  logIncomingVerbose: false, // явно включить verbose (как logIncoming: 'verbose')
  apiUrl: 'wss://...',    // URL WebSocket API (опционально)
  maxReconnectAttempts: 5,// Максимальное количество попыток переподключения
  reconnectDelay: 3000,   // Задержка между попытками переподключения (мс)
  // User-Agent / клиент (важно для GET_QR, см. showLinkDeviceQR):
  appVersion: '25.12.14', // Рекомендуется ≥ 25.12.13 для запроса QR
  ua: 'Mozilla/5.0 ...', // или headerUserAgent
  osVersion: 'Windows 11',
  screen: '1920x1080 1.0x',
  timezone: 'Europe/Moscow',
  locale: 'ru',
  buildNumber: 0x97cb,    // опционально
  clientSessionId: 1      // опционально
});

Лог входящих (logIncoming): печать блоков 📥 [incoming:…] с JSON.

Значение / условие Поведение
logIncoming: false Выкл.
logIncoming: 'messages' Только входящие сообщения (message.rawData).
logIncoming: 'verbose' или logIncomingVerbose: true Сообщения + connected, raw_message, message_removed, chat_action, error.
не указано По умолчанию: как 'messages'; если WEBMAX_DEBUG=1 — как 'verbose'. Явное logIncoming: 'messages' отключает расширенный режим даже при WEBMAX_DEBUG.
WEBMAX_SILENT=1 Выкл. всех дампов.

Ручной вывод в том же формате: client.logIncoming('my_label', data). Текущий режим: client.incomingLogMode ('off' \| 'messages' \| 'verbose'). Низкоуровнево: resolveIncomingLogMode(options), printIncomingLog(label, payload) из пакета.

Методы

start()

Запускает клиент и устанавливает соединение.

await client.start();
authorizeBySMS(phone)

Авторизация по номеру телефона через SMS (только для IOS/ANDROID).

// Подключаемся
await client.connect();

// Запрашиваем код
const authSession = await client.authorizeBySMS('+79001234567');

// Вводим код из SMS
await authSession.sendCode('123456');
showLinkDeviceQR(options)

Показать в консоли QR-код для привязки устройства (как в приложении Max: телефон сканирует QR). Нужна уже выполненная авторизация (start() или connect + sync).

  • Для WEB запрос выполняется по текущему WebSocket.
  • Для IOS/ANDROID после входа по TCP используется второе WebSocket-подключение без повторного LOGIN на той сессии (иначе GET_QR на том же TCP недоступен).
await client.showLinkDeviceQR();
await client.showLinkDeviceQR({ waitForScan: false, small: false });

Возвращает Promise<{ qrLink, trackId, pollingInterval, expiresAt }>.

requestQR(), checkQRStatus(trackId), loginByQR(trackId), authorizeByQR()

Низкоуровневые шаги QR-авторизации для WEB (первый вход без SMS). Обычно достаточно start() без токена или authorizeByQR().

sendMessage(options)

Отправляет сообщение в чат с уведомлением (notify: true).

const message = await client.sendMessage({
  chatId: 123,
  text: 'Привет!',
  // cid опционально; на TCP не используйте Date.now() (нужен int32)
  replyTo: null,        // ID сообщения для ответа (опционально)
  attachments: []       // Вложения (опционально)
});
sendMessageChannel(options)

Отправляет сообщение в канал без уведомления (notify: false).

const message = await client.sendMessageChannel({
  chatId: 123,
  text: 'Сообщение в канал',
  replyTo: null,        // ID сообщения для ответа (опционально)
  attachments: []       // Вложения (опционально)
});
editMessage(options)

Редактирует сообщение.

await client.editMessage({
  messageId: 456,
  chatId: 123,
  text: 'Исправленный текст'
});
deleteMessage(options)

Удаляет сообщение.

await client.deleteMessage({
  messageId: 456,
  chatId: 123
});
forwardMessage(options)

Пересылает сообщение.

await client.forwardMessage({
  messageId: 456,
  fromChatId: 123,
  toChatId: 789
});
sendChatAction(chatId, action)

Отправляет действие в чате (печатает, выбирает стикер и т.д.).

await client.sendChatAction(123, ChatActions.TYPING);
getUser(userId)

Получает информацию о пользователе.

const user = await client.getUser(123);
getChats(limit, offset)

Получает список чатов.

const chats = await client.getChats(50, 0);
getHistory(chatId, limit, offset)

Получает историю сообщений.

const messages = await client.getHistory(123, 50, 0);
stop()

Останавливает клиент.

await client.stop();
logout()

Выполняет выход из аккаунта и удаляет сессию.

await client.logout();

Обработчики событий

onStart(handler)

Регистрирует обработчик запуска клиента.

client.onStart(async () => {
  console.log('Клиент запущен!');
});
onMessage(handler)

Регистрирует обработчик новых сообщений.

client.onMessage(async (message) => {
  console.log('Новое сообщение:', message.text);
});
onMessageRemoved(handler)

Регистрирует обработчик удаленных сообщений.

client.onMessageRemoved(async (message) => {
  console.log('Сообщение удалено:', message.text);
});
onChatAction(handler)

Регистрирует обработчик действий в чате.

client.onChatAction(async (action) => {
  console.log('Действие в чате:', action.type);
});
onError(handler)

Регистрирует обработчик ошибок.

client.onError(async (error) => {
  console.error('Ошибка:', error.message);
});

Message

Класс, представляющий сообщение.

Свойства

  • id - ID сообщения
  • cid - Client ID сообщения
  • chatId - ID чата
  • text - Текст сообщения
  • senderId - ID отправителя
  • sender - Объект отправителя (User)
  • timestamp - Время отправки
  • type - Тип сообщения
  • isEdited - Флаг редактирования
  • replyTo - ID сообщения, на которое это является ответом
  • attachments - Вложения

Методы

reply(options)

Отправляет текст в тот же чат. По умолчанию без цитаты исходного сообщения (link REPLY), т.к. на TCP-сокете сервер часто возвращает «Ошибка валидации» для ответа-цитаты. Чтобы попробовать ответ с цитатой: { text: '...', quote: true }.

await message.reply({ text: 'Ответ на сообщение' });
await message.reply({ text: '...', quote: true });
edit(options)

Редактирует сообщение.

await message.edit({
  text: 'Новый текст'
});
delete()

Удаляет сообщение.

await message.delete();
forward(chatId)

Пересылает сообщение.

await message.forward(789);
downloadAttachment(index, options?)

Скачивает вложение по полю baseUrl (или url) из message.attachments[index] в временный файл. По умолчанию каталог — os.tmpdir() (на Windows обычно %TEMP%). Имя файла генерируется автоматически; расширение берётся из заголовка Content-Type, при необходимости — из типа вложения (_type, например PHOTO).

Возвращает { path, contentType }.

if (message.attachments.length) {
  const { path, contentType } = await message.downloadAttachment(0);
  console.log('Сохранено:', path, contentType);
  // после обработки можно удалить: fs.unlinkSync(path)
}

// Свой каталог или имя файла:
await message.downloadAttachment(0, {
  dir: './downloads',
  filename: 'photo.webp'
});

Утилиты скачивания медиа / Media download helpers

Экспортируются из пакета наряду с WebMaxClient:

const {
  downloadUrlToTempFile,
  extFromContentType,
  extFromAttachType
} = require('webmaxsocket');
downloadUrlToTempFile(url, options?)

HTTP(S)-запрос с следованием редиректам, запись тела ответа в файл.

Опция Описание
dir Каталог (по умолчанию os.tmpdir())
filename Имя файла (только basename); если не задано — max-media-<time>-<random>.<ext>
extFallback Расширение, если по Content-Type определить не удалось (например '.jpg')
const { path, contentType } = await downloadUrlToTempFile(
  'https://i.oneme.ru/i?r=...',
  { extFallback: '.jpg' }
);
extFromContentType(contentType) / extFromAttachType(attachType)

Вспомогательные функции для подбора расширения по MIME или по _type вложения (PHOTO, VIDEO, …).

User

Класс, представляющий пользователя.

Свойства

  • id - ID пользователя
  • firstname - Имя
  • lastname - Фамилия
  • username - Имя пользователя
  • phone - Номер телефона
  • avatar - URL аватара
  • status - Статус
  • bio - Биография
  • fullname - Полное имя (getter)

ChatAction

Класс, представляющий действие в чате.

Свойства

  • type - Тип действия
  • chatId - ID чата
  • userId - ID пользователя
  • user - Объект пользователя (User)
  • timestamp - Время действия

Константы

ChatActions

const { ChatActions } = require('webmaxsocket');

ChatActions.TYPING          // Печатает
ChatActions.STICKER         // Выбирает стикер
ChatActions.FILE            // Отправляет файл
ChatActions.RECORDING_VOICE // Записывает голосовое
ChatActions.RECORDING_VIDEO // Записывает видео

MaxSocketTransport

Низкоуровневый TCP Socket транспорт для IOS/ANDROID (api.oneme.ru).

Прямое использование (advanced)

const { MaxSocketTransport } = require('webmaxsocket');

const transport = new MaxSocketTransport({
  deviceType: 'IOS',
  ua: 'Mozilla/5.0 (iPhone...)',
  deviceId: 'your-device-id',
  debug: true
});

await transport.connect();
await transport.handshake(userAgentPayload);
const syncData = await transport.sync(token, userAgent);

Примечание: В большинстве случаев используйте WebMaxClient, который автоматически выбирает нужный транспорт.

📚 Примеры

Пример 1: QR-авторизация (example.js)

node example.js

Первый запуск - QR-авторизация, повторные запуски - автоматический вход через TCP Socket.

Пример 2: Token авторизация (example-token.js)

# Через config файл
node example-token.js
node example-token.js myconfig  # config/myconfig.json

# Через переменную окружения
TOKEN="ваш_токен" node example-token.js

Пример 3: SMS авторизация (example-sms.js)

# Интерактивный ввод номера
node example-sms.js

# С номером в аргументе
node example-sms.js +79001234567

Пример 4: IOS/ANDROID Socket (example-ios.js)

# С готовым конфигом
node example-ios.js

# С отладкой
node example-ios.js --debug

Пример 5: QR для второго устройства после SMS

После успешного start() с сохранённой сессией IOS/Android вызовите showLinkDeviceQR() (см. раздел «QR после входа» выше).

Структура проекта

webmaxsocket/
├── lib/
│   ├── client.js           # Основной клиент
│   ├── socketTransport.js  # TCP Socket транспорт
│   ├── session.js          # Управление сессиями
│   ├── userAgent.js        # UserAgent генератор
│   ├── opcodes.js          # Протокол опкоды
│   ├── constants.js        # Константы
│   ├── downloadMedia.js    # Скачивание медиа по URL во временный файл
│   ├── incomingLog.js      # Режим logIncoming / печать входящих
│   └── entities/
│       ├── User.js         # Класс пользователя
│       ├── Message.js      # Класс сообщения
│       ├── ChatAction.js   # Класс действия в чате
│       └── index.js        # Экспорт сущностей
├── config/                 # Конфигурационные файлы
│   └── example.json        # Пример конфига
├── sessions/               # Директория с сохраненными сессиями
├── index.js                # Точка входа
├── example.js              # QR-авторизация
├── example-token.js        # Token авторизация
├── example-sms.js          # SMS авторизация
├── example-ios.js          # IOS/ANDROID Socket
├── package.json
└── README.md

Сессии

Библиотека автоматически сохраняет сессии в директории sessions/. При повторном запуске с тем же именем сессии авторизация не требуется.

// Создание новой сессии
const client1 = new WebMaxClient({ name: 'account1', phone: '+1234567890' });

// Использование существующей сессии
const client2 = new WebMaxClient({ name: 'account1' }); // phone не требуется

Обработка ошибок

Рекомендуется всегда оборачивать вызовы API в try-catch блоки:

try {
  const message = await client.sendMessage({
    chatId: 123,
    text: 'Привет!'
  });
} catch (error) {
  console.error('Ошибка:', error.message);
}

🔧 Отладка / Debug

Для включения отладочного вывода:

const client = new WebMaxClient({
  name: 'my_session',
  debug: true  // или process.env.DEBUG = '1'
});

Или через переменную окружения:

DEBUG=1 node example.js

💡 Важные замечания

  1. TCP Socket после QR-авторизации: После первой успешной QR-авторизации клиент автоматически сохраняет clientSessionId и переключается на TCP Socket транспорт при следующем запуске для повышения стабильности.

  2. QR для нового устройства после входа по SMS/TCP: Используйте showLinkDeviceQR(). Это не отдельный опкод в протоколе, а тот же GET_QR, что и у веб-клиента; для уже залогиненного TCP-сокета запрос выполняется через эфемерное WebSocket-подключение (временный файл сессии _link_qr_* удаляется после завершения).

  3. Версия appVersion и QR: Слишком старая версия в User-Agent может привести к ответу qr_login.disabled на GET_QR. Задайте в конструкторе актуальную строку (по умолчанию 25.12.14).

  4. Разница между sendMessage и sendMessageChannel:

    • sendMessage() - отправка с уведомлением (notify: true) для обычных чатов
    • sendMessageChannel() - отправка без уведомления (notify: false) для каналов
  5. Автоматический выбор транспорта: Клиент автоматически определяет какой транспорт использовать на основе deviceType в сессии или config файле.

  6. cid при отправке сообщений (TCP/Socket): сервер проверяет signed int32. Не передавайте Date.now() (миллисекунды ~1e12) — будет «Ошибка валидации». Либо не указывайте cid (клиент подставит свой), либо передайте целое в диапазоне −2³¹ … 2³¹−1.

📄 Лицензия / License

MIT License - see LICENSE file for details

👤 Автор / Author

Tellarion - tellarion.dev

💝 Поддержка / Support

Если вам нравится эта библиотека и вы хотите поддержать разработку:

USDT (TRC20): TXfs1iVbp2aLd3rbc4cenVzMoTevP5RbBE

Спасибо за вашу поддержку!