Yurst

Limitations

What Yurst does not do yet and what to watch out for

Limitations

This list describes functionality that is absent in the current version of Yurst.

Implementation boundaries

These are not bugs but deliberate limitations. If you need such behavior, implement it in your own code.

Missing features

Commands

LimitationSolution
scope is not checked locallyCheck the chat type in the handler
No built-in cooldownImplement cooldown yourself
No middleware for commandsHandle common logic at the start of the handler

Messages

LimitationSolution
ctx.reply() does not split long textsSplit messages yourself
No method for deleting messagesUse api('DELETE', ...)

Keyboards

LimitationSolution
Only one markup at a timeSend two messages
The reply keyboard is always Once: trueIt cannot be changed

Callback buttons

LimitationSolution
Routing: only an exact match and a prefix up to :Parse ctx.data yourself
No validation of button actionsSpecify one action (data/url/copy/command)

Inline

LimitationSolution
No result formatting (markdown)—
No photos/files in results—

Architecture

LimitationSolution
bot.start() is not protected against a repeated callCall it once
No dependency injection—
No plugins—

Behavior nuances

Unknown commands

bot.command('ping', 'Ping', (ctx) => ...);

bot.on('message', (ctx) => {
  // Сюди НЕ потрапить /ping
  // Сюди НЕ потрапить /unknown
});

An unknown command:

  • Is ignored
  • Does not reach bot.on('message')
  • Is logged in debug mode

Errors in handlers

bot.on('message', async (ctx) => {
  throw new Error('Помилка!');
  // Наступний handler не викликається
});

bot.on('message', async (ctx) => {
  // Цей код не виконається
});

On error:

  • Processing of this update stops
  • Subsequent listeners are not called
  • The error is logged
  • The process keeps running

Concurrency

let counter = 0;

bot.on('message', async (ctx) => {
  const c = counter++;
  await new Promise(r => setTimeout(r, 1000));
  // counter вже змінився іншим обробником!
});

Different updates are processed simultaneously. If synchronization is needed:

  • Use queues
  • Use mutexes
  • Store state in a database with transactions

WebSocket

SituationBehavior
Node.js < 22 without the ws packageAutomatic switch to polling
Authentication error (code 3000)The process terminates
WS_MAX_FAILS failed attemptsAutomatic switch to polling

401 error

With an invalid token:

  • GET /bot/me → 401 → the process terminates
  • WebSocket → code 3000 → the process terminates

Internal modules

The public API is only the exports from index.js. The rest of the files under src/ are internal implementation and may change without notice.

Tests

The package contains unit tests for ButtonsBuilder, command name normalization, and markup generation:

npm test

There are no integration tests that contact the real Yurba API — to verify the transport and delivery, run the bot in dev mode.

Tips

Error handling

bot.on('message', async (ctx) => {
  try {
    // Ваш код
  } catch (err) {
    L.error('handler', err);
    await ctx.reply('Сталася помилка. Спробуйте пізніше.');
  }
});

Checking scope

The library does not provide a ready-made "private chat" flag. If you need a local check, take the raw dialog object from ctx.message.Dialog and look at its Type field in a real update (for example, by enabling YURST=dev). The set of values is determined by Yurba, so do not rely on a guessed dialog ID format.

Cooldown

const cooldowns = new Map();

bot.on('message', (ctx) => {
  const userId = ctx.user?.ID;
  const now = Date.now();
  const last = cooldowns.get(userId) ?? 0;

  if (now - last < 1000) {  // 1 секунда
    return;  // Ігноруємо
  }

  cooldowns.set(userId, now);
  // Обробка
});

Next

Examples

Ready-made scenarios for copying

On this page