@andrey4emk/npm-app-back-b24
v3.3.1
Published
Bitrix24 OAuth helpers for Node.js projects
Readme
npm_appBackB24
Утилиты для работы с Bitrix24 OAuth на основе @bitrix24/b24jssdk.
Содержание
Установка
npm install @andrey4emk/npm-app-back-b24Использование
import {
$b24,
saveAuthB24Handler,
refreshAndSaveTokens,
reinitializeB24,
stopProactiveRefresh,
errorB24,
event,
Event,
ChatApp,
Smsgold,
Email,
Wappi,
logs,
fetchRetry,
isNetworkError,
} from "@andrey4emk/npm-app-back-b24";
// $b24 — готовый экземпляр B24OAuth (или null, если токены не настроены)
if ($b24) {
const result = await $b24.callMethod("crm.contact.list", { limit: 5 });
}
// HTTP-обработчик для сохранения токенов с фронта
app.post("/b24/auth", saveAuthB24Handler);
// Обновление токенов вручную
const refreshResult = await refreshAndSaveTokens();
// Создание служебной задачи при ошибке
await errorB24({
title: "Ошибка синхронизации",
description: "Детали ошибки здесь",
ufCrmTask: ["D_5"],
});
// Работа с событиями (готовый экземпляр, или null если $b24 не инициализирован)
if (event) {
const { error, data } = await event.get("ONCRMDYNAMICITEMUPDATE_149");
}
// ChatApp — создаёте экземпляр самостоятельно
const chatApp = new ChatApp(makeParam, authParam, typeParam);
await chatApp.sendMessageChatApp("whatsApp", {
phone: "+1234567890",
message: "Привет!",
});
// Smsgold — создаёте экземпляр самостоятельно
const smsClient = new Smsgold({ user: "login", pass: "password" });
await smsClient.sendSms({ phone: "+79990000000", message: "Привет!" });
// Email — создаёте экземпляр самостоятельно
const emailClient = new Email({ user: "[email protected]", pass: "app-password" });
await emailClient.send({ to: "[email protected]", subject: "Тема", text: "Текст" });
// Wappi — создаёте экземпляр самостоятельно
const wappi = new Wappi(maxAuth, telegaAuth, whatsAppAuth);
await wappi.sendMessageWappi("whatsApp", { phone: "+1234567890", message: "Привет!" });
// Логирование
logs.add("Сообщение", "info");
// fetch с повторными попытками при сетевых ошибках
const response = await fetchRetry("https://api.example.com/data", { method: "GET" });API
Bitrix24 OAuth
Модуль работает с токенами через файл authB24.json (используется библиотека conf). Модель БД не требуется.
$b24— готовый экземплярB24OAuth, создаётся автоматически при импорте на основе сохранённых токенов. Если данные авторизации отсутствуют —null.import { $b24 } from "@andrey4emk/npm-app-back-b24"; if ($b24) { const result = await $b24.callMethod("crm.contact.list", { limit: 5 }); }Особенности:
- При обновлении токенов SDK автоматически сохраняет их в файл через callback
setCallbackRefreshAuth. - Окружение (
DEV/PROD) определяется переменнойAPP_ENV— используется как ключ секции в конфиге авторизации.
Retry при сетевых ошибках:
Экземпляр
$b24обёрнут Proxy, который автоматически повторяет запросы при сетевых ошибках. Повторные попытки применяются к методамcallMethod,callListMethod,callBatchиfetchListMethod, а также к обновлению токена (refreshAuth).| Параметр | Значение | | -------------- | ----------------------------------------- | | Попыток | 5 | | Задержка | 500 мс (экспоненциально для refreshAuth) |
Retry срабатывает только при сетевых проблемах (
ECONNRESET,ETIMEDOUT,ERR_NETWORKи т.д.). HTTP-ошибки (400, 500) и ошибки бизнес-логики Bitrix24 не вызывают повторных попыток. Каждая неудачная попытка логируется черезlogs.add()с уровнемerror.Проактивное обновление токена:
Токен автоматически обновляется каждые 25 минут. Если обновление не удалось — повтор через 2 минуты (вместо ожидания следующих 25 минут), что предотвращает протухание токена.
- При обновлении токенов SDK автоматически сохраняет их в файл через callback
saveAuthB24Handler(req, res)— HTTP-обработчик для сохранения набора токенов изreq.body. После сохранения автоматически переинициализирует$b24— перезапуск сервера не требуется.- Параметры:
req(Express Request) — объект запроса с полемbody.res(Express Response) — объект ответа.
- Тело запроса (req.body):
{ "access_token": "string", "refresh_token": "string", "domain": "string", "expires_in": "number", "member_id": "string" } - Возвращает: HTTP-ответ с JSON
{ status, message }(код201при успехе,400/500при ошибках).
app.post("/b24/auth", saveAuthB24Handler);- Параметры:
refreshAndSaveTokens()— обновляет токены из текущего экземпляра$b24и сохраняет в файл.- Возвращает: промис с объектом
{ error: boolean, message: string }.
const result = await refreshAndSaveTokens(); if (!result.error) { console.log("Токены обновлены:", result.message); }- Возвращает: промис с объектом
saveTokens(authData)— низкоуровневая функция для прямого сохранения токенов в файл. Перед записью валидирует данные — еслиaccess_token,refresh_token,domainилиexpiresпустые/отсутствуют, операция отклоняется.- Параметры:
authData(AuthData) — объект с полямиaccess_token,refresh_token,domain,expires_in,member_id,expires.
- Возвращает: объект
{ error: boolean, message: string }.
- Параметры:
reinitializeB24()— пересоздаёт экземпляр$b24из актуальногоauthB24.jsonбез перезапуска сервера. Останавливает текущий проактивный таймер, создаёт новыйB24OAuth, настраивает колбэк автосохранения, обновляет токены и запускает таймер заново.- Возвращает: промис с объектом
{ error: boolean, message: string }.
import { reinitializeB24 } from "@andrey4emk/npm-app-back-b24"; const result = await reinitializeB24(); if (!result.error) { console.log("$b24 переинициализирован"); }- Возвращает: промис с объектом
stopProactiveRefresh()— останавливает проактивный таймер обновления токена. Используется при graceful shutdown.import { stopProactiveRefresh } from "@andrey4emk/npm-app-back-b24"; process.on("SIGTERM", () => { stopProactiveRefresh(); process.exit(0); });
Задачи ошибок
errorB24(dataTask)— создаёт служебную задачу в Bitrix24 при ошибках/событиях. Использует глобальный$b24.Алгоритм:
- Сначала проверяет, сколько задач с таким
TITLEуже создано (черезtasks.task.list). - Если их меньше чем
maxTasks, создаёт новую задачу (tasks.task.add).
- Сначала проверяет, сколько задач с таким
Параметры:
dataTask(ErrorTaskData) — объект с параметрами задачи (см. ниже).
Возвращает: промис с объектом:
{ error: false, message: "Задача создана в Битрикс24.", data: { /* API response */ } }или при превышении лимита:
{ error: false, message: "Превышено максимальное количество задач с таким названием (100). Новая задача не создана." }или при ошибке:
{ error: true, message: "Не удалось создать задачу в Битрикс24: <текст ошибки>" }или если
$b24не инициализирован:{ error: true, message: "$b24 не инициализирован" }
Параметры
dataTask(ErrorTaskData):| Параметр | Тип | По умолчанию | Описание | | ---------------- | ---------------- | ------------------------- | ---------------------------------------------- | |
title| string | обязательно | Заголовок задачи | |description| string |""| Описание задачи | |createdBy| number |138| ID создателя | |responsibleId| number |1| ID ответственного | |deadline| ISO string |DateTime.now() + 1 день| Дедлайн в ISO формате | |groupId| number|null |null| ID группы (опционально) | |accomplices| number[] |[]| Массив ID соисполнителей | |maxTasks| number |100| Максимум существующих задач с таким названием | |ufCrmTask| string|string[] |""| Значение дляUF_CRM_TASK(массив или строка) | |entityTypeAbbr| string |""| ~~Устаревший~~ ИспользуйтеufCrmTask|await errorB24({ title: "Ошибка синхронизации", description: "Не удалось подключиться к API", responsibleId: 42, deadline: new Date(Date.now() + 2 * 24 * 60 * 60 * 1000).toISOString(), maxTasks: 50, ufCrmTask: ["D_5", "C_10"], });checkB24Scope()— проверяет и логирует права (скоупы) приложения Bitrix24. Вызывается автоматически при старте, если$b24инициализирован.
События
event— готовый экземпляр классаEvent(илиnull, если$b24не инициализирован). Создаётся автоматически при импорте.import { event } from "@andrey4emk/npm-app-back-b24"; if (event) { const result = await event.get("ONCRMDYNAMICITEMUPDATE_149"); }Event— класс для работы с офлайн-событиями Bitrix24. Можно создать свой экземпляр, передавB24OAuth.import { Event } from "@andrey4emk/npm-app-back-b24"; const myEvent = new Event(b24Instance);Методы:
get(eventName)— получить офлайн-события по названию.Параметры:
eventName(string) — название события (например,'ONCRMDYNAMICITEMUPDATE_149'или'ONIMCONNECTORMESSAGEADD').
Возвращает: промис с объектом
{ error, message, data }.Для событий сущностей (сделки, смарт-процессы):
{ error: false, message: "События получены", data: { processId: "12345", entitysId: ["101", "102", "103"], arrMessageIdAndEntityId: [ { messageId: "msg_1", entityId: "101" }, { messageId: "msg_2", entityId: "102" } ] } }Для событий коннектора (
ONIMCONNECTORMESSAGEADD):{ error: false, message: "События коннектора получены", data: { processId: "12345", message: [ { connectorId: "...", lineId: "...", chatId: "...", text: "Текст сообщения", file: null, attachments: null, im: null } ] } }или при ошибке:
{ error: true, message: "Не удалось получить события. <текст ошибки>", data: null }Особенности:
- Автоматически фильтрует и удаляет события от системного пользователя (
user_id: '138'). - Для коннекторных событий конвертирует файлы в формат с типами
image,video,document. - Если событий нет, возвращает
dataс пустыми массивами.
- Автоматически фильтрует и удаляет события от системного пользователя (
const { error, data } = await event.get("ONCRMDYNAMICITEMUPDATE_149"); if (!error && data.entitysId.length > 0) { console.log("Обработанные ID сущностей:", data.entitysId); }clear(processId, messageId?)— очистить обработанные офлайн-события в Bitrix24.Параметры:
processId(string) — ID процесса (получен изget()).messageId(string|string[]) — опциональный ID или массив ID сообщений для очистки.
Возвращает: промис с объектом
{ error, message, data }.
const { data } = await event.get("ONCRMDYNAMICITEMUPDATE_149"); if (data.processId) { const messageIds = data.arrMessageIdAndEntityId.map((item) => item.messageId); await event.clear(data.processId, messageIds); }
ChatApp
ChatApp— класс для работы с мессенджерами через платформу ChatApp Online. Экземпляр нужно создать самостоятельно.import { ChatApp } from "@andrey4emk/npm-app-back-b24"; const chatApp = new ChatApp( // makeParam — данные для создания токена { email: "your-email", pass: "your-password", appId: "your-app-id" }, // authParam — текущие токены (можно пустой объект, заполнится после makeTokenChatApp) { accessToken: "", accessTokenEndTime: "", refreshToken: "", refreshTokenEndTime: "" }, // typeParam — конфигурация мессенджеров и лицензий { whatsApp: { licenseId: "12345", messenger: [{ type: "grWhatsApp" }] }, telegram: { licenseId: "67890", messenger: [{ type: "telegram" }] }, } );Методы:
makeTokenChatApp()— получить токены доступа для ChatApp API.- Возвращает: промис с объектом
{ error }или{ error, message, data }при ошибке. - Особенности: Сохраняет полученные токены в свойствах экземпляра.
const result = await chatApp.makeTokenChatApp(); if (!result.error) { console.log("Токены успешно получены"); }- Возвращает: промис с объектом
refreshTokenChatApp()— обновить токены доступа.- Возвращает: промис с объектом
{ error }или{ error, message, data }при ошибке. - Алгоритм: Пытается обновить токены через API. Если не удалось — автоматически вызывает
makeTokenChatApp().
- Возвращает: промис с объектом
checkTokenChatApp()— проверить валидность текущего токена.- Возвращает: промис с объектом
{ error, message }. - Особенности: Если токен невалидный, автоматически вызывает
refreshTokenChatApp().
- Возвращает: промис с объектом
getLicensesChatApp()— получить список лицензий для текущего аккаунта.- Возвращает: промис с объектом
{ error, message, data }, гдеdata— массив лицензий.
const result = await chatApp.getLicensesChatApp(); if (!result.error) { console.log("Доступные лицензии:", result.data); }- Возвращает: промис с объектом
sendMessageChatApp(messengerType, messageData)— отправить текстовое сообщение.- Параметры:
messengerType(string) —"whatsApp"или"telegram".messageData(object) —{ phone: string, message: string }.
- Возвращает: промис с объектом
{ error, message, data, auth }. Если в процессе обновился токен,authсодержит новые данные авторизации.
const result = await chatApp.sendMessageChatApp("whatsApp", { phone: "+1234567890", message: "Это тестовое сообщение", });- Параметры:
sendFileChatApp(messengerType, messageData)— отправить файл.- Параметры:
messengerType(string) —"whatsApp"или"telegram".messageData(object) —{ phone, message, fileUrl, fileName }.
- Параметры:
phoneCheckChatApp(messengerType, phone)— проверить, существует ли номер в мессенджере.- Параметры:
messengerType(string) —"whatsApp"или"telegram".phone(string) — номер телефона.
- Возвращает: промис с объектом
{ error, message, data }, гдеdata.check— результат проверки.
- Параметры:
Smsgold
Smsgold— класс для отправки SMS через сервис SMSGold. Экземпляр нужно создать самостоятельно.import { Smsgold } from "@andrey4emk/npm-app-back-b24"; const smsClient = new Smsgold( { user: "smsgold_login", pass: "smsgold_password" }, b24Instance // опционально — экземпляр B24OAuth для загрузки файлов на диск );Методы:
sendSms(messageData)— отправить SMS.- Параметры:
messageData(object):phone(string) — номер телефона.message(string) — текст сообщения.fileUrl(string) — опционально, ссылка на файл (будет загружен на диск Bitrix24 и публичная ссылка добавлена в SMS).fileName(string) — опционально, имя файла.
- Возвращает: промис с объектом
{ error, message, result }.
const result = await smsClient.sendSms({ phone: "+79990000000", message: "Готово!", }); if (!result.error) { console.log(result.message); }- Параметры:
Email— класс для отправки email через SMTP Яндекса. Экземпляр нужно создать самостоятельно.import { Email } from "@andrey4emk/npm-app-back-b24"; const emailClient = new Email({ user: "[email protected]", pass: "your-app-password", });Методы:
send(dataMail)— отправить письмо.- Параметры:
dataMail(object):to(string) — адрес получателя.subject(string) — тема письма.text(string) — текстовая версия.html(string) — опционально, HTML-версия.fileUrl(string) — опционально, ссылка на файл (будет скачан и прикреплён).fileName(string) — опционально, имя файла для вложения.
- Возвращает: промис с объектом
{ error, info }при успехе или{ error, message }при ошибке.
const result = await emailClient.send({ to: "[email protected]", subject: "Тема письма", text: "Текст письма", html: "<b>HTML текст</b>", });- Параметры:
Особенности:
- SMTP-сервер:
smtp.yandex.ru:465(SMTPS). - Копия письма автоматически отправляется на адрес отправителя.
- SMTP-сервер:
Wappi
Wappi— класс для отправки сообщений через Wappi API (WhatsApp, Telegram, Max). Экземпляр нужно создать самостоятельно.import { Wappi } from "@andrey4emk/npm-app-back-b24"; const wappi = new Wappi( { token: "max-token", profile_id: "max-profile" }, { token: "telegram-token", profile_id: "telegram-profile" }, { token: "whatsapp-token", profile_id: "whatsapp-profile" } );Методы:
sendMessageWappi(messengerType, messageData)— отправить текстовое сообщение.- Параметры:
messengerType(string) —"whatsApp","telegram"или"max".messageData(object):phone(string) — номер телефона.message(string) — текст сообщения.sendOpenLine(boolean) — опционально, отображать ли в открытой линии Битрикс24 (по умолчаниюtrue).
- Возвращает: промис с объектом
{ error, message, data }.
const result = await wappi.sendMessageWappi("whatsApp", { phone: "+1234567890", message: "Привет из Wappi!", });- Параметры:
sendFileWappi(messengerType, messageData)— отправить файл.- Параметры:
messengerType(string) —"whatsApp","telegram"или"max".messageData(object):phone(string) — номер телефона.message(string) — подпись к файлу.fileUrl(string) — ссылка на файл.fileName(string) — имя файла.sendOpenLine(boolean) — опционально.
- Особенности: Для WhatsApp и Telegram файл конвертируется в base64. Для Max отправляется по URL.
- Параметры:
phoneCheckWappi(messengerType, phone)— проверить, существует ли номер в мессенджере.- Параметры:
messengerType(string) —"whatsApp","telegram"или"max".phone(string) — номер телефона.
- Возвращает: промис с объектом
{ error, message, data }, гдеdata.check—true/false. - Особенности: Для Telegram сначала проверяет контакт, при отсутствии — пытается создать.
- Параметры:
Логирование
logs— экземпляр классаLogsAPIдля цветного логирования в консоль.import { logs } from "@andrey4emk/npm-app-back-b24"; logs.add("Информационное сообщение", "info"); logs.add("Отладочное сообщение", "debug"); logs.add("Ошибка!", "error"); logs.add({ key: "value" }); // объект будет JSON.stringify logs.add("С доп. данными", "info", { detail: 123 }); // jsonData выведется через console.dirУровни логирования:
| Уровень | Цвет | По умолчанию | | ------- | ------- | ------------ | |
debug| Серый | Выключен | |info| Зелёный | Включён | |error| Красный | Включён |- Конфигурация хранится в файле
log.json(черезconf). - Каждый уровень можно включить/выключить, изменить цвет.
- Конфигурация хранится в файле
fetchRetry
fetchRetry(url, options?, retries?, delay?)— обёртка надfetchс повторными попытками при сетевых ошибках. HTTP-ошибки (4xx, 5xx) не вызывают повторных попыток — повторяются только сетевые сбои (TypeError, ECONNRESET, ETIMEDOUT и т.д.).isNetworkError(error)— проверяет, является ли ошибка сетевой (стоит повторить запрос). Используется внутриfetchRetryи retry-обёртки$b24. Можно использовать в своём коде для аналогичных проверок.import { isNetworkError } from "@andrey4emk/npm-app-back-b24"; try { await someRequest(); } catch (error) { if (isNetworkError(error)) { // сетевая ошибка — можно повторить } }Параметры:
| Параметр | Тип | По умолчанию | Описание | | --------- | ---------------------------- | --------------- | ----------------------------------------------- | |
url| string | URL | Request | обязательно | Адрес запроса | |options| RequestInit |undefined| Параметры fetch (метод, заголовки, body и т.д.) | |retries| number |5| Количество попыток | |delay| number |500| Задержка между попытками (мс) |Возвращает:
Promise<Response>— ответ от fetch.Обрабатываемые сетевые ошибки:
ECONNRESET,ECONNREFUSED,ETIMEDOUT,ENOTFOUND,ENETUNREACH,EAI_AGAIN,UND_ERR_CONNECT_TIMEOUT,UND_ERR_SOCKET,TypeError, а также ошибки с сообщениямиfetch failed,network,socket.Логирование: при каждой неудачной попытке записывает сообщение через
logs.add()с уровнемerror.
import { fetchRetry } from "@andrey4emk/npm-app-back-b24"; // Простой GET-запрос с дефолтными параметрами (5 попыток, 500мс) const response = await fetchRetry("https://api.example.com/data"); const json = await response.json(); // POST-запрос с кастомными параметрами const res = await fetchRetry( "https://api.example.com/webhook", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ key: "value" }), }, 3, // 3 попытки 1000 // 1 секунда между попытками );
Переменные окружения
| Переменная | Назначение |
| --------------------------- | ------------------------------------------------------------- |
| APP_B24_DOMEN | Домен Bitrix24, для которого хранится запись авторизации в БД |
| APP_B24_CLIENT_ID | Client ID приложения Bitrix24 |
| APP_B24_CLIENT_SECRET | Client Secret приложения Bitrix24 |
| APP_ENV | Определяет окружение, используется как ключ секции авторизации |
| APP_NAME | Название приложения (используется в описании задач) |
| CONFIG_DIR | Путь к директории с конфигами (по умолчанию ../config) |
| CHATAPP_EMAIL | Email аккаунта ChatApp |
| CHATAPP_PASS | Пароль аккаунта ChatApp |
| CHATAPP_APP_ID | ID приложения в ChatApp |
Пример .env:
APP_B24_DOMEN=mycompany.bitrix24.ru
APP_ENV=DEV
APP_B24_CLIENT_ID=xxx
APP_B24_CLIENT_SECRET=yyy
APP_NAME=MyApp
CONFIG_DIR=../config
[email protected]
CHATAPP_PASS=your-password
CHATAPP_APP_ID=your-app-idСкрипты
npm run test— запуск тестов (заглушка).npm run pack:dry— предпросмотр содержимого пакета перед публикацией.
Лицензия
MIT © 2025 andrey4emk
