@pixelbyte-software/pixcode 1.53.9 → 1.53.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -27,6 +27,9 @@ const PAIRING_TTL_MS = 10 * 60 * 1000;
27
27
  let bot = null;
28
28
  let botInfo = null; // { id, username, first_name }
29
29
  let lastError = null;
30
+ let lastTransientPollingLogAt = 0;
31
+
32
+ const TRANSIENT_POLLING_LOG_INTERVAL_MS = 60 * 1000;
30
33
 
31
34
  export const setTelegramBotForTesting = (nextBot) => {
32
35
  bot = nextBot;
@@ -75,6 +78,29 @@ const parseMaybeCode = (text) => {
75
78
  return /^\d{6}$/.test(trimmed) ? trimmed : null;
76
79
  };
77
80
 
81
+ const isTransientTelegramNetworkError = (err, code = err?.response?.statusCode || err?.code) => {
82
+ if (code === 409) return true;
83
+ const message = String(err?.message || err || '').toLowerCase();
84
+ return message.includes('fetch failed')
85
+ || message.includes('network')
86
+ || message.includes('timeout')
87
+ || message.includes('timed out')
88
+ || message.includes('econnreset')
89
+ || message.includes('econnrefused')
90
+ || message.includes('enotfound')
91
+ || message.includes('etimedout')
92
+ || message.includes('socket hang up');
93
+ };
94
+
95
+ const logTransientPollingError = (nextError) => {
96
+ const timestamp = Date.now();
97
+ if (timestamp - lastTransientPollingLogAt < TRANSIENT_POLLING_LOG_INTERVAL_MS) {
98
+ return;
99
+ }
100
+ lastTransientPollingLogAt = timestamp;
101
+ console.log('[telegram] polling temporarily unavailable; retrying with backoff:', nextError);
102
+ };
103
+
78
104
  const safeSend = async (chatId, text, extra = {}) => {
79
105
  if (!bot) return;
80
106
  try {
@@ -216,8 +242,10 @@ const wirePollingErrors = () => {
216
242
  if (code === 401) {
217
243
  console.error('[telegram] fatal polling error, stopping:', lastError);
218
244
  stopBot().catch(() => {});
245
+ } else if (isTransientTelegramNetworkError(err, code)) {
246
+ logTransientPollingError(lastError);
219
247
  } else if (code === 409) {
220
- console.warn('[telegram] polling conflict:', lastError);
248
+ console.log('[telegram] polling conflict:', lastError);
221
249
  } else {
222
250
  console.warn('[telegram] polling error:', lastError);
223
251
  }
@@ -247,9 +275,17 @@ export const startBot = async ({ token, persist = true } = {}) => {
247
275
  } catch (err) {
248
276
  try { await instance.stopPolling(); } catch { /* ignore */ }
249
277
  const reason = err?.response?.body?.description || err?.message || String(err);
250
- lastError = { code: 'auth', message: reason };
251
- const error = new Error(`Invalid bot token: ${reason}`);
252
- error.code = 'INVALID_TOKEN';
278
+ const transientNetworkError = isTransientTelegramNetworkError(err);
279
+ lastError = {
280
+ code: transientNetworkError ? 'network' : 'auth',
281
+ message: reason,
282
+ };
283
+ const error = new Error(
284
+ transientNetworkError
285
+ ? `Telegram network unavailable: ${reason}`
286
+ : `Invalid bot token: ${reason}`,
287
+ );
288
+ error.code = transientNetworkError ? 'TELEGRAM_NETWORK_UNAVAILABLE' : 'INVALID_TOKEN';
253
289
  throw error;
254
290
  }
255
291
 
@@ -331,6 +367,10 @@ export const restoreBotFromConfig = async () => {
331
367
  try {
332
368
  await startBot({ token: config.bot_token, persist: false });
333
369
  } catch (err) {
334
- console.warn('[telegram] Failed to restore bot:', err?.message || err);
370
+ if (err?.code === 'TELEGRAM_NETWORK_UNAVAILABLE') {
371
+ console.log('[telegram] restore delayed; Telegram network unavailable:', err?.message || err);
372
+ } else {
373
+ console.warn('[telegram] Failed to restore bot:', err?.message || err);
374
+ }
335
375
  }
336
376
  };