Виджеты в сообщениях Telegram получили обратный канал к боту. В бета-сборках Telegram для macOS 13.1.0 от 26 октября у скрипта виджета появился вызов request(): по нажатию он отправляет боту до 64 байт и ждёт ответ до 1 024 байт. Без нажатия запрос уходит только в личном чате с ботом, если бот разрешил такие запросы, пока виджет на экране и не чаще раза в пять секунд. Там же виджет теперь знает, кто его открыл, — id, имя, юзернейм и наличие Premium, — и в каком типе чата он лежит. Сами виджеты замечены в бетах iOS, macOS и Android, но эту механику пока видно только в сборке для macOS; в публичной схеме API и в Bot API виджетов нет.
Что изменилось между 25 и 26 октября
Бета macOS раздаётся через фид обновлений, каждая сборка — zip с приложением. Для сравнения взяты 13.1.0.283381 от 25 октября и 13.1.0.283391 от 26 октября.
Скрипт виджета общается с клиентом через глобальный объект TelegramWidget. Его код лежит в пакете WidgetSandbox внутри приложения, в файле sandbox-bundle.js. В 283381 объект умел немного: отдать тему оформления, подписаться на события, открыть ссылку и включить вибрацию. В 283391 к этому добавились:
| Что | Что делает |
|---|---|
request(data) | отправляет боту строку от 1 до 64 байт и возвращает его ответ |
viewer | id, имя, фамилия, юзернейм и признак Premium того, кто смотрит |
chatType | тип чата: личный, группа, супергруппа или канал |
chatData | данные, привязанные к сообщению в этом чате, до 1 024 байт |
publicData | данные самого сообщения, до 1 024 байт |
watchPublicData() | подписка на изменения publicData |
isForward и isPreview | пересланная ли это копия и не превью ли это ещё не отправленного инлайн-результата |
copyText(text) | кладёт в буфер обмена до 256 знаков |
setResizeAnchor | край, от которого виджет растёт при смене высоты, — верхний или нижний |
К трём прежним событиям — смена темы, активация и деактивация — добавились chatDataChanged и publicDataChanged.
Одновременно из пакета HTMLBubbles убрали всё демонстрационное: тринадцать демо-переписок, о которых шла речь в материале от 13 октября, папку ported с перенесёнными карточками, многопользовательскую игру voxel-clash и папку widget-sandbox с примерами. В пакете осталась одна библиотека three.js.
Когда виджет может написать боту
Правила записаны в той же песочнице, текстом ошибок, которые получает скрипт, и в строках приложения:
- запрос уходит из обработчика нажатия на виджет, один вызов на одно нажатие;
- без нажатия — только в личном чате с ботом, только если сообщению разрешены фоновые запросы (флаг
background_query), только пока виджет на экране и не чаще раза в пять секунд; - пока ждёт ответа прошлый запрос, новый не отправляется;
- превью инлайн-результата, которое ещё не отправлено в чат, бота не спрашивает;
- запросы выключены, если бот не разрешил их этому сообщению, — у пересланной копии отдельное разрешение;
- ответ бота — только текст и не длиннее 1 024 байт, иначе скрипт получает ошибку
INVALID_ANSWER; не ответил вовремя —TIMEOUT.
У пересланной копии chatData пуст, а publicData остаётся.
В строках приложения рядом с кодом HTML-пузыря появилась фраза «A tap may send data to the bot» — «нажатие может отправить данные боту». Где именно клиент её показывает, по сборке не видно.
Что делать
- Виджеты пока живут только в бетах, и от ботов их не прислать: в Bot API нет метода, который отправлял бы виджет.
- Нажимая на виджет, учитывайте, что каждое нажатие может стать запросом к боту. Скрипт видит ваш id, имя, юзернейм и Premium, а id занимает до 16 цифр — в запрос в 64 байта он помещается.
- Сам по себе, без нажатия, виджет пишет боту только в личном чате с этим ботом. Для групп и каналов песочница фоновых запросов не предусматривает.
- Сети у виджета нет:
fetch,XMLHttpRequest,WebSocketи воркеры в песочнице заменены заглушками, которые возвращают ошибку. Наружу данные уходят через бота или через ссылку, которую виджет открывает (openLinkпринимает только https и не длиннее 256 знаков), — так было и в сборке 25 октября.
Как сервер доставит виджет
В бинарнике 283391 появились имена типов схемы, которых не было в 283381. В публичной схеме слоя 232 — ни у Telegram Desktop, ни у Telegram Web A — их нет, нет виджетов и в документации Bot API. Устройство читается по именам, поэтому дальше — прочтение, а не описание:
botInlineMessageWidget,inputBotInlineMessageWidgetиinputBotInlineMessageWidgetId— бот, судя по всему, отдаёт виджет как инлайн-результат, целиком или по id;inputMediaWidgetId— виджет как вложение сообщения по id;updateBotWidgetQuery,updateInlineBotWidgetQueryиupdateBotWidgetCopyQuery— запросы к боту от виджета в обычном сообщении, в отправленном через инлайн-режим и, судя по имени, в пересланной копии; ответ —botWidgetQueryAnswer;updateMessageWidgetDataиwidgetPublicData— сервер присылает новые данные уже отправленного виджета, а в песочнице на это есть событиеpublicDataChanged;- ошибки сервера
WIDGET_QUERY_NOT_ALLOWEDиWIDGET_RESPONSE_TIMEOUTвыглядят парой к ошибкам скриптаNOT_ALLOWEDиTIMEOUT.
Строки клиента называют и флаги разрешений: allow_queries у сообщения, fwd_allow_queries у его пересланных копий и background_query для запросов без нажатия. Что именно бот получает вместе с запросом — id нажавшего, как у кнопок под сообщением, или нет, — по сборке не видно.
Что проверяют стенды в открытом коде
В открытом репозитории клиента движок виджетов подключён подмодулем twidget; по ссылке подмодуля GitHub отвечает 404 — репозиторий закрыт или удалён. Рядом лежат стенды для замеров, а в папке tools/perflab/TwidgetLab/widgets/attack — 28 виджетов, которые пытаются действовать без настоящего нажатия. Шестнадцать из них шлют боту данные: по таймеру раз в 50 мс, синтетическим кликом, отложенным вызовом после клика, через подпись к полю формы (label), перетаскиванием. Двенадцать пробуют без нажатия открыть ссылку или уйти со страницы — ссылкой поверх кнопки, отправкой формы, автообновлением страницы. Папка появилась в репозитории с коммитом 23 октября, за три дня до сборки с request().
В этих стендах отправка ещё называется TelegramWidget.sendMessage. В сборке 283391 такого вызова нет — есть request(), а вызов вне нажатия скрипт получает как ошибку с причиной no-activation.
Что ещё было в убранных примерах
В папке widget-sandbox сборки 283381 лежали два набора по 20 виджетов — with-profile и without-profile. Имена файлов — это просьбы: «show me a mortgage calculator», «make a bar chart of the top 6 programming…», «create a pomodoro timer», «create a flashcard widget for 8 Spanish…». Объект TelegramWidget упоминают 12 файлов первого набора и ни одного из второго. Похоже на виджеты, собранные моделью по одним и тем же просьбам с описанием возможностей песочницы и без него, — это вывод по содержимому, сама сборка этого не говорит. Слово profile есть и в объекте TelegramWidget: свойство profile равно 1, а isProfileAtLeast() проверяет уровень.
Остальное в папке — проверки совместимости (Chart.js, D3, three.js, WebGL, формы, перетаскивание, localStorage), карточки для витрины по темам «покупки», «работа», «жизнь», «путешествия» и стресс-тесты.
Где ещё виджеты
Виджеты в сообщениях как формат следующего обновления 13.2 описывали 25 октября. Как виджет обращается к боту, что он видит о зрителе и где проходят границы запросов, в этом описании не было.




