August 4, 2022

🎉 grammY 1.10

На днях вышло большое обновление для grammY — современной typescript-библиотеки для создания телеграм-ботов.

Главная тема обновления — первый стабильный релиз @grammyjs/conversations. Это библиотека, позволяющая строить сложные диалоговые взаимодействия с пользователем, почти об этом не задумываясь.

Наверное, каждый, кто пробовал писать телеграм-ботов, хотя бы раз думал «как круто было бы, если бы можно было написать "подожди следующего сообщения от пользователя и продолжи функцию"». Так вот, conversations позволяют делать именно так! Например:

async function greeting(conversation: MyConversation, ctx: MyContext) {
  await ctx.reply("Hi there! What is your name?");
  const { message } = await conversation.wait();
  await ctx.reply(`Welcome to the chat, ${message.text}!`);
}

Причём, в отличие от наивных реализаций через промисы, все данные тут хранятся в сессии, и бот получается полностью устойчив к перезагрузкам.

И хотя я всё ещё придерживаюсь классического подхода со сценами (grammy-views), conversations — это интересная новая абстракция, которая (наверное) будет более интуитивно понятна для начинающих разработчиков. Подробнее »


Кроме этого добавили ctx.has — набор методов у контекста, позволяющих выполнять проверки. Раньше это было доступно только со стороны Composer'а. Например:

composer.command('start', (ctx) => ctx.reply(ctx.match.toString()))

Эквивалент этого с помощью ctx.has будет выглядеть примерно так:

composer.use((ctx, next) => {
  if (ctx.hasCommand('start')) {
    return ctx.reply(ctx.match.toString())
  }
  return next()
})

В обычных ситуациях ctx.has пригодится нечасто, но главное его применение — в conversations. Из-за более императивного подхода в них недоступны привычные методы Composer'а, их и заменит ctx.has. Подробнее »


Ещё обновили сессии. Добавили мульти-сессии, позволяющие хранить разные части данных в разных хранилищах; добавили «улучшатель» хранилищ, добавляющий TTL для сессий и инструмент для миграций. Первые два кажутся мне не такими важными, а вот миграции — это правда полезно.

По мере развития бота формат данных в сессии может меняться. При этом у старых пользователей могут оставаться данные в старом формате, с которыми бот может работать неправильно. Раньше с этим приходилось бороться обходными путями: добавлять проверки на отсутствующие поля, мигрировать из одного формата в другой.

Новый плагин упрощает эти действия. Он позволяет создавать функции, которые мигрируют данные из одной версии формата в следующую. При этом плагин сам следит за версией данных у каждого пользователя и запускает миграции при необходимости. Подробнее »


Ну и напоследок — обновили плагин для создания клавиатур. Наконец-то добавили поддержку resize_keyboard, one_time_keyboard и других полей для обычных клавиатур, без них было очень неудобно (хотя я и не пользуюсь обычными клавиатурами). А самое главное, добавили фичу, за которую я топил больше двух месяцев — конструкторы для клавиатур.

Встроенный в grammY плагин для построения клавиатур написан в императивном стиле. Например:

const keyboard = new InlineKeyboard()
  .text('1', 'a').text('2', 'b').row()
  .text('3', 'c')

И это не всегда может быть удобно (например, если нужно создать клавиатуру из динамического массива)

Поэтому я предпочитаю декларативный подход на базе обычных двумерных массивов. Я сделал плагин grammy-markup, который предоставляет функции-помощники для создания кнопок Button и IButton. Но вот незадача: в Keyboard и InlineKeyboard нельзя передать сырые данные о клавиатуре в виде двумерного массива! Было нельзя, до этого обновления. Теперь клавиатуры можно строить так (с помощью плагина grammy-markup):

const keyboard = new InlineKeyboard([
  [IButton.text('1', 'a'), IButton.text('2', 'b')],
  [IButton.text('3', 'c'),
])

Плагин grammy-markup в связи с этим получает версию 1.0! Репо »