diff --git a/package.json b/package.json index 0cc0f2f..7f2c64c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "telegram-shop-bot", - "version": "1.0.0", + "version": "1.0.1", "type": "module", "scripts": { "test": "vitest run", diff --git a/src/context/bot.js b/src/context/bot.js index 86e2ccd..ae1de07 100644 --- a/src/context/bot.js +++ b/src/context/bot.js @@ -15,7 +15,53 @@ const initBot = async () => { } for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) { try { - const instance = new TelegramBot(config.BOT_TOKEN, {polling: true}); + const instance = new TelegramBot(config.BOT_TOKEN, {polling: false}); + // ── Проверка на ДУБЛИКАТ токена ───────────────────────────── + // Перед запуском polling делаем разовый getUpdates. Если токен уже + // используется другой нодой/процессом — Telegram возвращает 409 + // "Conflict: terminated by other getUpdates request" (или webhook). + // Такой бот НЕ должен стартовать: он будет конфликтовать, терять + // обновления и «прыгать» между серверами (issue: дубликат BotFather + // токена на нескольких нодах). + const dupCheck = await new Promise((resolve, reject) => { + const timeout = setTimeout(() => resolve(null), 10000); + instance + .getUpdates({ timeout: 0, allowed_updates: [] }) + .then((updates) => { + clearTimeout(timeout); + // допустимые значения — любой успешный ответ ([] или список) + resolve({ ok: true, updates }); + }) + .catch((error) => { + clearTimeout(timeout); + const status = error?.response?.statusCode ?? error?.response?.status; + const description = error?.response?.body?.description ?? error?.message ?? String(error); + const is409 = status === 409 || /conflict/i.test(description); + resolve({ ok: false, status, description, is409 }); + }); + }); + if (!dupCheck?.ok) { + if (dupCheck?.is409) { + console.error( + '\n====================================================\n' + + '🚫 ОБНАРУЖЕН ДУБЛИКАТ ТОКЕНА ДЛЯ ЗАПУСКА\n' + + ' Telegram вернул 409 Conflict — этот BOT_TOKEN уже\n' + + ' используется другим экземпляром/нодой.\n' + + ` (${dupCheck.description})\n` + + ' Запуск бота остановлен. Создайте новый бот в @BotFather\n' + + ' или замените BOT_TOKEN в настройках сервиса.\n' + + '====================================================\n' + ); + process.exit(1); + } + if (dupCheck?.status === 404 || (dupCheck?.description || '').includes('Not Found')) { + // неверный токен — пробуем дальше; ниже полноценная валидация + logger.warn('validate: getUpdates 404 (invalid token?)'); + } + } + + // Реальная инициализация: включаем polling и проверяем getMe + await instance.startPolling(); await new Promise((resolve, reject) => { const timeout = setTimeout(() => { instance.stopPolling();