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💡 Важные замечания
TCP Socket после QR-авторизации: После первой успешной QR-авторизации клиент автоматически сохраняет
clientSessionIdи переключается на TCP Socket транспорт при следующем запуске для повышения стабильности.QR для нового устройства после входа по SMS/TCP: Используйте
showLinkDeviceQR(). Это не отдельный опкод в протоколе, а тот жеGET_QR, что и у веб-клиента; для уже залогиненного TCP-сокета запрос выполняется через эфемерное WebSocket-подключение (временный файл сессии_link_qr_*удаляется после завершения).Версия
appVersionи QR: Слишком старая версия в User-Agent может привести к ответуqr_login.disabledнаGET_QR. Задайте в конструкторе актуальную строку (по умолчанию 25.12.14).Разница между sendMessage и sendMessageChannel:
sendMessage()- отправка с уведомлением (notify: true) для обычных чатовsendMessageChannel()- отправка без уведомления (notify: false) для каналов
Автоматический выбор транспорта: Клиент автоматически определяет какой транспорт использовать на основе
deviceTypeв сессии или config файле.cidпри отправке сообщений (TCP/Socket): сервер проверяет signed int32. Не передавайтеDate.now()(миллисекунды ~1e12) — будет «Ошибка валидации». Либо не указывайтеcid(клиент подставит свой), либо передайте целое в диапазоне −2³¹ … 2³¹−1.TCP и keep-alive (PING): сервер периодически шлёт
PING. На WebSocket клиент отвечаетsendPong; на TCP раньше ответ не отправлялся — соединение могло обрываться через несколько минут, после чего процесс Node завершался (нечем держать event loop). Сейчас на TCP автоматически шлётся тот же ответ, что и у WebSocket (PINGс пустым payload).
🔗 Ссылки / Links
📄 Лицензия / License
MIT License - see LICENSE file for details
👤 Автор / Author
Tellarion - tellarion.dev
💝 Поддержка / Support
Если вам нравится эта библиотека и вы хотите поддержать разработку:
USDT (TRC20): TXfs1iVbp2aLd3rbc4cenVzMoTevP5RbBE
Спасибо за вашу поддержку!