Скрипти
Скрипт рахує і змінює змінні. Його виконує крок «Скрипт».

Під полем скрипта є «Тестовий запуск»: він показує, що зміниться, і нічого не зберігає.
Синтаксис
Кожен рядок присвоює значення: змінна = вираз. Рядок, що починається з #, — коментар.
# Без префікса змінна живе, поки триває розмова
options = filter(app.slots, item.status == "free")
labels = map(options, item.time)
# user.* зберігається за відвідувачем назавжди
user.score = default(user.score, 0) + 10
user.level = user.score > 100 ? 2 : 1
# app.* — спільні дані бота
app.total_plays = default(app.total_plays, 0) + 1
- Значення бувають такі: числа, рядки в лапках
"…",true,false,null, списки[a, b]і об'єкти{ключ: значення}. - Рядок у зворотних лапках підставляє значення:
`${item.name} ×${item.qty}`даєКеди ×2. Усередині${…}будь-який вираз. Порожнє значення підставляється як нічого. - Вираз може тривати на кількох рядках, поки не закрито дужку.
- Коментар займає цілий рядок. Коментар у кінці рядка з кодом не працює.
- Елемент списку —
items[0]абоitems.0. Розмір списку чи об'єкта —list.size. - Змінна, якій ще нічого не присвоїли, дорівнює
null. Запасне значення даєdefault(x, запасне). -
==порівнює строго:1 == "1"хибне.
Простори імен
Префікс перед назвою змінної каже, де вона живе і скільки.
| Змінна | Що це |
|---|---|
name або session.name
|
Змінні розмови. Ім'я без префікса пише й читає сюди. Зникають, коли діалог завершується. |
user.name |
Стан окремого відвідувача, назавжди. Читання й запис. Сюди кроки зберігають відповіді: ввід, вибір, опитування. |
app.name |
Спільні дані для всіх відвідувачів. Читання й запис. Лічильники, каталог, розклад. |
temp.name |
Змінні одного скрипта. Живуть, поки він виконується, і ніде не зберігаються. |
platform.* |
Дані Telegram про людину й повідомлення, яке зараз обробляється. Лише читання. Див. нижче. |
initiator.* |
Хто запустив цю ланку через «Сповіщення» чи «Анонс»: user_id, name, username. Лише читання. У звичайній ланці порожньо. |
secret.* |
Секрети бота з «Налаштування бота → Секрети»: ключі API, паролі. Лише читання і лише всередині запитів: fetch, page_meta, save_image. |
- Змінити поле всередині об'єкта напряму не можна:
user.cart.qty = 1не спрацює. Зберіть об'єкт заново або змініть елемент списку черезupdate_where. - Два чати можуть змінювати
app.*одночасно. Зміни обох не загубляться. - Імена, що починаються з
_, зарезервовані. - Порада: те, що людина ввела, зберігайте в
user.*, а те, що порахував скрипт, — у змінних розмови.
Оператори
| Що | Оператори |
|---|---|
| Арифметика | + - * / % |
| Порівняння | > < >= <= == != |
| Логіка | && || ! |
| Умова в одному виразі | user.x > 5 ? "high" : "low" |
| Склеювання рядків | "Привіт, " + platform.first_name |
+ склеює, якщо хоч один бік — рядок. Інакше обидва боки мають бути числами.
Функції
Математика
| Функція | Що робить |
|---|---|
min(a, b, ...) max(a, b, ...)
|
Мінімум і максимум |
abs(x) |
Модуль числа |
floor(x) ceil(x) round(x, decimals?)
|
Округлення вниз, вгору і до найближчого, з потрібною кількістю знаків |
sqrt(x) pow(x, y)
|
Корінь і степінь |
clamp(val, min, max) |
Обмежити число діапазоном |
Рядки
| Функція | Що робить |
|---|---|
len(s) |
Довжина рядка або списку |
upper(s) lower(s) trim(s)
|
Великі літери, малі літери, без пробілів на краях |
contains(s, sub) |
Чи містить рядок підрядок |
starts_with(s, prefix) ends_with(s, suffix)
|
Чи починається або закінчується рядок цим текстом |
substr(s, start, len?) |
Вирізати підрядок |
replace(s, from, to) |
Замінити всі входження |
split(s, sep) |
Розбити рядок на список за роздільником |
Списки
| Функція | Що робить |
|---|---|
count(list) |
Кількість елементів |
sort(list) unique(list)
|
Відсортований список і список без повторів |
join(list, ", ") |
Список → рядок |
append(list, item) |
Додати елемент у кінець списку |
sort_by(list, "key", "desc") |
Відсортувати за полем; "asc" за зростанням, "desc" за спаданням |
take(list, n) |
Перші n елементів |
slice(list, start, count) |
Відрізок списку від позиції start (рахунок з 0) |
last(list, n) |
Останні n елементів, у тому ж порядку |
sum(list) |
Сума чисел |
nth(list, i) |
Елемент за номером; за межами списку — null
|
Списки з item
У цих функціях другий аргумент — вираз, у якому item означає поточний елемент.
| Функція | Що робить |
|---|---|
filter(list, item.status == "free") |
Лишити елементи, для яких вираз правдивий |
map(list, item.time) |
Зібрати значення з кожного елемента |
flat_map(list, item.slots) |
Як map, але списки з кожного елемента зливаються в один |
find(list, item.id == 5) |
Перший елемент, що підходить, або null
|
update_where(list, item.id == 5, "status", "busy") |
Змінити поле в елементах, що підходять |
Ці виклики не можна вкладати в умову один одного.
Дати
Дати — це рядки ISO, що починаються з YYYY-MM-DD.
| Функція | Що робить |
|---|---|
add_days(date, n) |
Зсунути дату на n днів; результат має вигляд "yyyy-MM-dd"
|
get_iso_day(date) |
Номер дня тижня: 1 — понеділок … 7 — неділя |
format(date, "dd.MM") |
Форматування токенами date-fns: dd, MM, yyyy, HH:mm
|
Перетворення й перевірки
| Функція | Що робить |
|---|---|
num(x) str(x) bool(x)
|
У число, рядок чи булеве значення; num дає помилку, якщо x — не число |
to_num(x, fallback) |
Число, або fallback, якщо x — не число |
is_num(x) is_str(x) is_bool(x) is_null(x)
|
Повертають true або false; is_null правдиве й для змінної, якої ще немає |
default(x, fallback) |
fallback, якщо x — null; 0 і "" лишаються як є |
Запити до інших сервісів
fetch звертається до іншого сервісу через інтернет.
temp.resp = fetch("https://api.example.com/items", {method: "POST", body: {q: 1}, cache: 60, timeout: 10})
user.saved = temp.resp.status == 200 ? temp.resp.body.id : null
-
fetchзаймає весь правий бік рядка. Результат треба записати вtemp.x(зникне після скрипта) або вsession.x(лишиться на розмову). -
method,headersіbody— як у звичайному HTTP-запиті. Об'єкт уbodyнадсилається як JSON, рядок — як є. -
timeout— скільки секунд чекати відповідь: 5, якщо не задано, щонайбільше 30. -
cache— скільки секунд зберігати успішну відповідь, щонайбільше година. Кеш спільний для всіх, хто робить такий самий запит. Він годиться для розкладу чи каталогу, але не для бронювання. - Результат —
{status, body, error}.body— розібраний JSON або текст. Якщо запит не дійшов,statusдорівнюєnull, аerrorпояснює чому. - Невдалий запит не вважається помилкою скрипта і не веде в гілку «+ Крок помилки». Перевірте
temp.resp.status == 200і розведіть гілки кроком «Умова». - Поки запит виконується, людина бачить «друкує…». Сусідні запити, що не залежать один від одного, виконуються паралельно, до 6 на скрипт.
Секрети
Ключ API не пишіть у скрипт відкритим текстом: збережіть його як секрет і беріть у запиті як secret.API_KEY. Докладно — на сторінці Секрети.
Дані сторінки і картинки
page_meta і save_image працюють за тими самими правилами, що й fetch.
temp.page = page_meta(link)
temp.photo = save_image(temp.page.image)
app.catalog = append(app.catalog, {id: "p1", name: temp.page.title, image: temp.photo.url})
-
page_meta(url)читає, що сторінка каже про себе:{status, title, description, image, images, url, site, type, extra, error}. Уimages— до 10 картинок сторінки, головна перша. -
save_image(url)копіює картинку до медіа бота:{url, urls, error}. Можна передати список, до 10 картинок, і до 20 МБ кожна. Тестовий запуск картинку не зберігає.
Змінні платформи
Лише для читання.
| Змінна | Що це |
|---|---|
platform.user_id |
Telegram ID людини (число) |
platform.first_name |
Ім'я |
platform.last_name |
Прізвище |
platform.full_name |
Ім'я й прізвище; будь-яке з них може бути відсутнє |
platform.username |
@username |
platform.language_code |
Код мови (uk, en, …) |
platform.is_premium |
Чи має людина Telegram Premium (true / false) |
platform.first_seen |
Коли людина вперше написала боту (ISO 8601) |
platform.last_seen |
Коли людина востаннє щось робила в боті (ISO 8601) |
platform.message_text |
Текст повідомлення, яке зараз обробляється |
platform.start_param |
Дані з посилання на ланку після дефіса; є лише у відповідь на /start, а розмова, яку воно відкрило, зберігає їх у session.start_param
|
platform.now |
Поточний момент у форматі ISO 8601 |
Ліміти
| Що | Скільки |
|---|---|
| Довжина виразу | 1024 символи |
Кількість інструкцій (fetch на кількох рядках — одна) |
50 |
| Довжина скрипта | 4096 символів |
| Довжина списку | 500 |
Елементів в одному {…} чи […]
|
50 |
Очікування fetch
|
5 с, якщо не задано; щонайбільше 30 с |
Відповідь fetch
|
1 МіБ |
Кеш fetch
|
1 година |