max_api_client 0.1.2 → 0.2.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9a7a9568ed92bf227e962ff1e08005f0d08a1a54c159f771ce30eb18c46665a8
4
- data.tar.gz: 4507132c766e8e3f26f967b95516646e601b71ea83057428490c0992528300a3
3
+ metadata.gz: 7d6578ded53eb4717c32d40728c217f163db0e8149bc813b084c6920692201dd
4
+ data.tar.gz: 338a01c773c1be6502cd37161bf1b11011a08717fd006055db99e9ff7466716c
5
5
  SHA512:
6
- metadata.gz: 619624bec359f829957a21b9177794256e68138b94479caa5690c728f728333ad1d39e538ffd0d8dab78a1178f4cf5244770423c1e2f50ac66494ce927a232e0
7
- data.tar.gz: e8e107a33f368aee7eab0782659222d5ca3764325a98fe50d8df099250da0c3faf588b4ba62abdf8286e7d212c5cdad144a12968864f318b04db32ca22bd0cf9
6
+ metadata.gz: a656768c33a27bf0c4d6a61b8eb8c6ef807b2177472c19c99c70ed29ec4f4d9a4ee9dfaec2a8db4d330582040d79b8500d511bcb3dd8e55fd178f98058f8fb09
7
+ data.tar.gz: 99f540522f43226232847ee792d1950643c7ff56464b693813b60d7a3da6cd07fa155c62978c95630cf8f7da78385ffbe5c6eb48b79392b5ca7e395362901751
data/CHANGELOG.md CHANGED
@@ -1,7 +1,35 @@
1
1
  ## [Unreleased]
2
2
 
3
- - Rewrote `README.md` with installation instructions, project status, TS vs Ruby comparison, and Max Bot API reference sections.
4
- - Filled gem metadata in `max_api_client.gemspec`.
3
+ ## [0.2.0] - 2026-10-03
4
+
5
+ Synced with Max Bot API schema 0.0.33.
6
+
7
+ - Added `edit_my_commands` (`PATCH /me/commands`); `set_my_commands` and `delete_my_commands` now use it instead of `PATCH /me`.
8
+ - Added `add_chat_admins` and `remove_chat_admin`.
9
+ - Added comment methods: `get_comments`, `get_comment`, `send_comment`, `edit_comment`, `delete_comment` (`api.raw.comments`).
10
+ - Added `get_video_info` (`GET /videos/{videoToken}`).
11
+ - Added `ContactAttachment`, `InlineKeyboardAttachment` and `Button` builders; attachment objects now serialize to JSON without an explicit `to_h`.
12
+ - Added `limit` to `poll_updates`; an empty `types` list is no longer sent.
13
+ - Fixed `remove_chat_member`: `user_id` and `block` are sent as query parameters, as the schema requires.
14
+ - Fixed `get_message`, which raised `ArgumentError`.
15
+ - Fixed `answer_on_callback`: `disable_link_preview` is sent as a query parameter.
16
+ - `false` query values are now sent as `false` instead of being dropped.
17
+ - Sending a message is retried at most 3 times on `attachment.not.ready`, with exponential backoff.
18
+ - `delete_message` no longer accepts extra options (they raised `ArgumentError`).
19
+ - Deprecated `edit_my_info`, `get_all_chats`, `get_chat_by_link` and `add_chat_members`: their endpoints are removed from the API or absent from the schema.
20
+
21
+ ## [0.1.3] - 2026-07-16
22
+
23
+ - Switched the default API endpoint to `https://platform-api2.max.ru`.
24
+ - Added the Russian Trusted Root CA to the TLS trust store, with optional `ca_file` override.
25
+ - Added an explicit `verify_ssl: false` option for environments that must temporarily ignore certificate errors.
26
+ - Documented the new endpoint and TLS configuration options.
27
+ - Updated the TypeScript reference client link.
28
+
29
+ ## [0.1.2] - 2026-03-27
30
+
31
+ - Configured RubyGems trusted publishing through GitHub Actions.
32
+ - Added release tag validation and updated the Ruby CI matrix.
5
33
 
6
34
  ## [0.1.0] - 2026-02-12
7
35
 
data/README.md CHANGED
@@ -24,19 +24,95 @@ gem "max_api_client", git: "git@github.com:Ziaw/max_api_client.git"
24
24
  bundle install
25
25
  ```
26
26
 
27
+ ## Адрес API и сертификат Минцифры
28
+
29
+ По умолчанию клиент использует актуальный адрес `https://platform-api2.max.ru`.
30
+ В gem включён корневой сертификат `Russian Trusted Root CA`, поэтому TLS-цепочка
31
+ MAX проверяется вместе с обычным системным хранилищем доверенных сертификатов.
32
+ По умолчанию проверка TLS включена.
33
+
34
+ Актуальные сертификаты и инструкции по их системной установке опубликованы
35
+ на Госуслугах: <https://www.gosuslugi.ru/crt>.
36
+
37
+ Обычное подключение не требует дополнительных настроек:
38
+
39
+ ```ruby
40
+ api = MaxApiClient::Api.new(
41
+ token: ENV.fetch("MAX_BOT_TOKEN")
42
+ )
43
+ ```
44
+
45
+ Доступные параметры подключения:
46
+
47
+ - `base_url` — адрес MAX API, по умолчанию `https://platform-api2.max.ru`;
48
+ - `ca_file` — путь к дополнительному доверенному CA-файлу;
49
+ - `verify_ssl` — проверять сертификат сервера, по умолчанию `true`;
50
+ - `open_timeout` — таймаут установления соединения;
51
+ - `read_timeout` — таймаут чтения ответа.
52
+
53
+ Эти параметры поддерживают как `MaxApiClient::Api`, так и
54
+ `MaxApiClient::Client`.
55
+
56
+ ### Подключение собственного сертификата
57
+
58
+ Передайте путь к актуальному сертификату Минцифры в формате PEM:
59
+
60
+ ```ruby
61
+ api = MaxApiClient::Api.new(
62
+ token: ENV.fetch("MAX_BOT_TOKEN"),
63
+ ca_file: "/etc/ssl/certs/russian_trusted_root_ca.pem"
64
+ )
65
+ ```
66
+
67
+ Чтобы использовать только системное хранилище сертификатов, передайте
68
+ `ca_file: nil`.
69
+
70
+ ### Игнорирование неверного сертификата
71
+
72
+ Если окружение временно не может проверить сертификат, отключите проверку
73
+ параметром `verify_ssl: false`:
74
+
75
+ ```ruby
76
+ api = MaxApiClient::Api.new(
77
+ token: ENV.fetch("MAX_BOT_TOKEN"),
78
+ verify_ssl: false
79
+ )
80
+ ```
81
+
82
+ `verify_ssl: false` принимает любой серверный сертификат и делает соединение
83
+ уязвимым для перехвата. Используйте эту настройку только как временный обходной
84
+ вариант. Для постоянной настройки передайте актуальный сертификат через
85
+ `ca_file` или установите его в системное хранилище.
86
+
87
+ Полный пример настройки:
88
+
89
+ ```ruby
90
+ api = MaxApiClient::Api.new(
91
+ token: ENV.fetch("MAX_BOT_TOKEN"),
92
+ base_url: "https://platform-api2.max.ru",
93
+ ca_file: MaxApiClient::Client::DEFAULT_CA_FILE,
94
+ verify_ssl: true,
95
+ open_timeout: 10,
96
+ read_timeout: 30
97
+ )
98
+ ```
99
+
27
100
  ## Справочник API
28
101
 
29
102
  ### Методы бота
30
103
 
31
- Методы Ruby, доступные через `MaxApiClient::Api`:
104
+ Методы доступные через `MaxApiClient::Api`, порт официального клиента <https://github.com/max-messenger/max-bot-api-client-ts>, названия сохранены, poller собственный:
32
105
 
33
106
  - `get_my_info`
34
- - `edit_my_info(**extra)`
107
+ - `edit_my_commands(commands)`
35
108
  - `set_my_commands(commands)`
36
109
  - `delete_my_commands`
37
110
 
38
- `set_my_commands(commands)` это короткий хелпер над `edit_my_info(commands: ...)`.
39
- Он принимает массив команд и отправляет его в поле `commands` профиля бота.
111
+ Клиент соответствует схеме Bot API MAX версии 0.0.33
112
+ (<https://github.com/max-messenger/api-schema>).
113
+
114
+ `set_my_commands(commands)` это синоним `edit_my_commands(commands)`.
115
+ Он принимает массив команд и отправляет его в поле `commands`.
40
116
 
41
117
  Ожидается массив хэшей с данными команды, например:
42
118
 
@@ -52,27 +128,28 @@ api.set_my_commands([
52
128
  Соответствующие HTTP-маршруты:
53
129
 
54
130
  - `GET /me`
55
- - `PATCH /me`
131
+ - `PATCH /me/commands`
56
132
 
57
133
  Типовые сценарии:
58
134
 
59
135
  - получить текущий профиль бота;
60
- - обновить имя, описание, аватар и команды бота;
61
136
  - опубликовать или очистить подсказки команд для пользователей.
62
137
 
138
+ Устаревший метод `edit_my_info(**extra)` (`PATCH /me`) оставлен для совместимости
139
+ и выводит предупреждение: этого маршрута нет в актуальной схеме API.
140
+
63
141
  ### Методы чатов
64
142
 
65
143
  Методы Ruby, доступные через `MaxApiClient::Api`:
66
144
 
67
- - `get_all_chats(**extra)`
68
145
  - `get_chat(chat_id)`
69
- - `get_chat_by_link(chat_link)`
70
146
  - `edit_chat_info(chat_id, **extra)`
71
147
  - `get_chat_membership(chat_id)`
72
148
  - `get_chat_admins(chat_id)`
73
- - `add_chat_members(chat_id, user_ids)`
149
+ - `add_chat_admins(chat_id, admins)`
150
+ - `remove_chat_admin(chat_id, user_id)`
74
151
  - `get_chat_members(chat_id, **extra)`
75
- - `remove_chat_member(chat_id, user_id)`
152
+ - `remove_chat_member(chat_id, user_id, block: nil)`
76
153
  - `get_pinned_message(chat_id)`
77
154
  - `pin_message(chat_id, message_id, **extra)`
78
155
  - `unpin_message(chat_id)`
@@ -81,13 +158,12 @@ api.set_my_commands([
81
158
 
82
159
  Соответствующие HTTP-маршруты:
83
160
 
84
- - `GET /chats`
85
161
  - `GET /chats/{chat_id}`
86
- - `GET /chats/{chat_link}`
87
162
  - `PATCH /chats/{chat_id}`
88
163
  - `GET /chats/{chat_id}/members/me`
89
164
  - `GET /chats/{chat_id}/members/admins`
90
- - `POST /chats/{chat_id}/members`
165
+ - `POST /chats/{chat_id}/members/admins`
166
+ - `DELETE /chats/{chat_id}/members/admins/{user_id}`
91
167
  - `GET /chats/{chat_id}/members`
92
168
  - `DELETE /chats/{chat_id}/members`
93
169
  - `GET /chats/{chat_id}/pin`
@@ -98,14 +174,29 @@ api.set_my_commands([
98
174
 
99
175
  Типовые сценарии:
100
176
 
101
- - получить список чатов, доступных боту;
102
- - найти чат по идентификатору или публичной ссылке;
177
+ - получить чат по идентификатору;
103
178
  - изменить заголовок, иконку и метаданные чата;
104
179
  - управлять участниками и администраторами;
105
180
  - читать, устанавливать и снимать закреплённые сообщения;
106
181
  - отправлять статус набора текста и другие действия отправителя;
107
182
  - выходить из чата.
108
183
 
184
+ Пример назначения администратора:
185
+
186
+ ```ruby
187
+ api.add_chat_admins(chat_id, [
188
+ { user_id: 42, permissions: %w[write pin_message] }
189
+ ])
190
+ ```
191
+
192
+ Устаревшие методы оставлены для совместимости и выводят предупреждение:
193
+
194
+ - `get_all_chats(**extra)` — `GET /chats` не поддерживается с июня 2026;
195
+ список чатов нужно вести самостоятельно по событиям `bot_added` и `bot_started`;
196
+ - `get_chat_by_link(chat_link)` — поиска по ссылке нет в актуальной схеме;
197
+ - `add_chat_members(chat_id, user_ids)` — `POST /chats/{chat_id}/members`
198
+ удалён из API 30 сентября 2026.
199
+
109
200
  ### Методы сообщений
110
201
 
111
202
  Методы Ruby, доступные через `MaxApiClient::Api`:
@@ -115,7 +206,8 @@ api.set_my_commands([
115
206
  - `get_messages(chat_id, **extra)`
116
207
  - `get_message(message_id)`
117
208
  - `edit_message(message_id, **extra)`
118
- - `delete_message(message_id, **extra)`
209
+ - `delete_message(message_id)`
210
+ - `get_video_info(video_token)`
119
211
  - `answer_on_callback(callback_id, **extra)`
120
212
 
121
213
  Соответствующие HTTP-маршруты:
@@ -125,6 +217,7 @@ api.set_my_commands([
125
217
  - `GET /messages/{message_id}`
126
218
  - `PUT /messages`
127
219
  - `DELETE /messages`
220
+ - `GET /videos/{video_token}`
128
221
  - `POST /answers`
129
222
 
130
223
  Поддерживаемые возможности:
@@ -133,7 +226,25 @@ api.set_my_commands([
133
226
  - дополнительный payload для форматирования, reply-ссылок и вложений;
134
227
  - редактирование и удаление сообщений;
135
228
  - ответы на callback-кнопки;
136
- - автоматический повтор запроса, если вложение после загрузки ещё не готово.
229
+ - автоматический повтор запроса (до 3 попыток), если вложение после загрузки ещё не готово.
230
+
231
+ ### Методы комментариев
232
+
233
+ Методы Ruby, доступные через `MaxApiClient::Api`:
234
+
235
+ - `get_comments(message_id, **extra)`
236
+ - `get_comment(message_id, comment_id)`
237
+ - `send_comment(message_id, text, **extra)`
238
+ - `edit_comment(message_id, comment_id, **extra)`
239
+ - `delete_comment(message_id, comment_id)`
240
+
241
+ Соответствующие HTTP-маршруты:
242
+
243
+ - `GET /messages/{message_id}/comments`
244
+ - `GET /messages/{message_id}/comments/{comment_id}`
245
+ - `POST /messages/{message_id}/comments`
246
+ - `PUT /messages/{message_id}/comments`
247
+ - `DELETE /messages/{message_id}/comments`
137
248
 
138
249
  ### Методы подписок
139
250
 
@@ -142,7 +253,7 @@ api.set_my_commands([
142
253
  - `get_subscriptions`
143
254
  - `subscribe(url, update_types: nil, secret: nil)`
144
255
  - `unsubscribe(url)`
145
- - `poll_updates(types = [], marker: nil, timeout: 20, retry_interval: 5, read_timeout: nil, &block)`
256
+ - `poll_updates(types = [], marker: nil, limit: nil, timeout: 20, retry_interval: 5, read_timeout: nil, &block)`
146
257
 
147
258
  Соответствующие HTTP-маршруты:
148
259
 
@@ -197,6 +308,25 @@ end
197
308
  - `StickerAttachment`
198
309
  - `LocationAttachment`
199
310
  - `ShareAttachment`
311
+ - `ContactAttachment`
312
+ - `InlineKeyboardAttachment`
313
+
314
+ Объекты вложений можно передавать в `attachments:` напрямую. Кнопки клавиатуры
315
+ собираются через `MaxApiClient::Button`:
316
+
317
+ ```ruby
318
+ keyboard = MaxApiClient::InlineKeyboardAttachment.new(
319
+ buttons: [[
320
+ MaxApiClient::Button.callback("Да", "yes"),
321
+ MaxApiClient::Button.link("Сайт", "https://max.ru")
322
+ ]]
323
+ )
324
+
325
+ api.send_message_to_chat(chat_id, "Выберите", attachments: [keyboard])
326
+ ```
327
+
328
+ Доступные кнопки: `callback`, `link`, `message`, `request_contact`,
329
+ `request_geo_location`, `open_app`, `clipboard`.
200
330
 
201
331
  ### Доступ к Raw API
202
332
 
@@ -265,6 +395,7 @@ bin/console
265
395
  ## Источники
266
396
 
267
397
  - Официальная документация Max Bot API: <https://dev.max.ru/>
398
+ - OpenAPI-схема Max Bot API: <https://github.com/max-messenger/api-schema>
268
399
  - TypeScript reference client: <https://github.com/max-messenger/max-bot-api-client-ts>
269
400
 
270
401
  ## Лицензия
@@ -0,0 +1,33 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIFwjCCA6qgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwcDELMAkGA1UEBhMCUlUx
3
+ PzA9BgNVBAoMNlRoZSBNaW5pc3RyeSBvZiBEaWdpdGFsIERldmVsb3BtZW50IGFu
4
+ ZCBDb21tdW5pY2F0aW9uczEgMB4GA1UEAwwXUnVzc2lhbiBUcnVzdGVkIFJvb3Qg
5
+ Q0EwHhcNMjIwMzAxMjEwNDE1WhcNMzIwMjI3MjEwNDE1WjBwMQswCQYDVQQGEwJS
6
+ VTE/MD0GA1UECgw2VGhlIE1pbmlzdHJ5IG9mIERpZ2l0YWwgRGV2ZWxvcG1lbnQg
7
+ YW5kIENvbW11bmljYXRpb25zMSAwHgYDVQQDDBdSdXNzaWFuIFRydXN0ZWQgUm9v
8
+ dCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMfFOZ8pUAL3+r2n
9
+ qqE0Zp52selXsKGFYoG0GM5bwz1bSFtCt+AZQMhkWQheI3poZAToYJu69pHLKS6Q
10
+ XBiwBC1cvzYmUYKMYZC7jE5YhEU2bSL0mX7NaMxMDmH2/NwuOVRj8OImVa5s1F4U
11
+ zn4Kv3PFlDBjjSjXKVY9kmjUBsXQrIHeaqmUIsPIlNWUnimXS0I0abExqkbdrXbX
12
+ YwCOXhOO2pDUx3ckmJlCMUGacUTnylyQW2VsJIyIGA8V0xzdaeUXg0VZ6ZmNUr5Y
13
+ Ber/EAOLPb8NYpsAhJe2mXjMB/J9HNsoFMBFJ0lLOT/+dQvjbdRZoOT8eqJpWnVD
14
+ U+QL/qEZnz57N88OWM3rabJkRNdU/Z7x5SFIM9FrqtN8xewsiBWBI0K6XFuOBOTD
15
+ 4V08o4TzJ8+Ccq5XlCUW2L48pZNCYuBDfBh7FxkB7qDgGDiaftEkZZfApRg2E+M9
16
+ G8wkNKTPLDc4wH0FDTijhgxR3Y4PiS1HL2Zhw7bD3CbslmEGgfnnZojNkJtcLeBH
17
+ BLa52/dSwNU4WWLubaYSiAmA9IUMX1/RpfpxOxd4Ykmhz97oFbUaDJFipIggx5sX
18
+ ePAlkTdWnv+RWBxlJwMQ25oEHmRguNYf4Zr/Rxr9cS93Y+mdXIZaBEE0KS2iLRqa
19
+ OiWBki9IMQU4phqPOBAaG7A+eP8PAgMBAAGjZjBkMB0GA1UdDgQWBBTh0YHlzlpf
20
+ BKrS6badZrHF+qwshzAfBgNVHSMEGDAWgBTh0YHlzlpfBKrS6badZrHF+qwshzAS
21
+ BgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsF
22
+ AAOCAgEAALIY1wkilt/urfEVM5vKzr6utOeDWCUczmWX/RX4ljpRdgF+5fAIS4vH
23
+ tmXkqpSCOVeWUrJV9QvZn6L227ZwuE15cWi8DCDal3Ue90WgAJJZMfTshN4OI8cq
24
+ W9E4EG9wglbEtMnObHlms8F3CHmrw3k6KmUkWGoa+/ENmcVl68u/cMRl1JbW2bM+
25
+ /3A+SAg2c6iPDlehczKx2oa95QW0SkPPWGuNA/CE8CpyANIhu9XFrj3RQ3EqeRcS
26
+ AQQod1RNuHpfETLU/A2gMmvn/w/sx7TB3W5BPs6rprOA37tutPq9u6FTZOcG1Oqj
27
+ C/B7yTqgI7rbyvox7DEXoX7rIiEqyNNUguTk/u3SZ4VXE2kmxdmSh3TQvybfbnXV
28
+ 4JbCZVaqiZraqc7oZMnRoWrXRG3ztbnbes/9qhRGI7PqXqeKJBztxRTEVj8ONs1d
29
+ WN5szTwaPIvhkhO3CO5ErU2rVdUr89wKpNXbBODFKRtgxUT70YpmJ46VVaqdAhOZ
30
+ D9EUUn4YaeLaS8AjSF/h7UkjOibNc4qVDiPP+rkehFWM66PVnP1Msh93tc+taIfC
31
+ EYVMxjh8zNbFuoc7fzvvrFILLe7ifvEIUqSVIC/AzplM/Jxw7buXFeGP1qVCBEHq
32
+ 391d/9RAfaZ12zkwFsl+IKwE/OZxW8AHa9i1p4GO0YSNuczzEm4=
33
+ -----END CERTIFICATE-----
@@ -2,18 +2,21 @@
2
2
 
3
3
  module MaxApiClient
4
4
  # High-level convenience wrapper over grouped Max Bot API endpoints.
5
+ # rubocop:disable Metrics/ClassLength
5
6
  class Api
6
7
  attr_reader :raw, :upload, :client
7
8
 
8
9
  # rubocop:disable Metrics/ParameterLists
9
10
  def initialize(token:, base_url: Client::DEFAULT_BASE_URL, adapter: nil, open_timeout: nil, read_timeout: nil,
10
- logger: nil)
11
+ ca_file: Client::DEFAULT_CA_FILE, verify_ssl: true, logger: nil)
11
12
  @client = Client.new(
12
13
  token:,
13
14
  base_url:,
14
15
  adapter:,
15
16
  open_timeout:,
16
17
  read_timeout:,
18
+ ca_file:,
19
+ verify_ssl:,
17
20
  logger:
18
21
  )
19
22
  @raw = RawApi.new(client)
@@ -28,20 +31,26 @@ module MaxApiClient
28
31
  # rubocop:enable Naming/AccessorMethodName
29
32
 
30
33
  def edit_my_info(**extra)
34
+ warn_deprecated(:edit_my_info, "PATCH /me is absent from the current API schema, use edit_my_commands")
31
35
  raw.bots.edit_my_info(**extra)
32
36
  end
33
37
 
38
+ def edit_my_commands(commands)
39
+ raw.bots.edit_my_commands(commands:)
40
+ end
41
+
34
42
  # rubocop:disable Naming/AccessorMethodName
35
43
  def set_my_commands(commands)
36
- edit_my_info(commands:)
44
+ edit_my_commands(commands)
37
45
  end
38
46
  # rubocop:enable Naming/AccessorMethodName
39
47
 
40
48
  def delete_my_commands
41
- edit_my_info(commands: [])
49
+ edit_my_commands([])
42
50
  end
43
51
 
44
52
  def get_all_chats(**extra)
53
+ warn_deprecated(:get_all_chats, "GET /chats is not supported by the API since June 2026")
45
54
  raw.chats.get_all(**extra)
46
55
  end
47
56
 
@@ -50,6 +59,7 @@ module MaxApiClient
50
59
  end
51
60
 
52
61
  def get_chat_by_link(chat_link)
62
+ warn_deprecated(:get_chat_by_link, "lookup by link is absent from the current API schema")
53
63
  raw.chats.get_by_link(chat_link:)
54
64
  end
55
65
 
@@ -65,7 +75,16 @@ module MaxApiClient
65
75
  raw.chats.get_chat_admins(chat_id:)
66
76
  end
67
77
 
78
+ def add_chat_admins(chat_id, admins)
79
+ raw.chats.add_chat_admins(chat_id:, admins:)
80
+ end
81
+
82
+ def remove_chat_admin(chat_id, user_id)
83
+ raw.chats.remove_chat_admin(chat_id:, user_id:)
84
+ end
85
+
68
86
  def add_chat_members(chat_id, user_ids)
87
+ warn_deprecated(:add_chat_members, "POST /chats/{chat_id}/members was removed from the API on 2026-09-30")
69
88
  raw.chats.add_chat_members(chat_id:, user_ids:)
70
89
  end
71
90
 
@@ -117,14 +136,38 @@ module MaxApiClient
117
136
  raw.messages.edit(message_id:, **extra)
118
137
  end
119
138
 
120
- def delete_message(message_id, **extra)
121
- raw.messages.delete(message_id:, **extra)
139
+ def delete_message(message_id)
140
+ raw.messages.delete(message_id:)
141
+ end
142
+
143
+ def get_video_info(video_token)
144
+ raw.messages.get_video_info(video_token:)
122
145
  end
123
146
 
124
147
  def answer_on_callback(callback_id, **extra)
125
148
  raw.messages.answer_on_callback(callback_id:, **extra)
126
149
  end
127
150
 
151
+ def get_comments(message_id, **extra)
152
+ raw.comments.get(message_id:, **csv_query(extra, :comment_ids))
153
+ end
154
+
155
+ def get_comment(message_id, comment_id)
156
+ raw.comments.get_by_id(message_id:, comment_id:)
157
+ end
158
+
159
+ def send_comment(message_id, text, **extra)
160
+ message_from(raw.comments.send(message_id:, text:, **extra))
161
+ end
162
+
163
+ def edit_comment(message_id, comment_id, **extra)
164
+ raw.comments.edit(message_id:, comment_id:, **extra)
165
+ end
166
+
167
+ def delete_comment(message_id, comment_id)
168
+ raw.comments.delete(message_id:, comment_id:)
169
+ end
170
+
128
171
  # rubocop:disable Naming/AccessorMethodName
129
172
  def get_subscriptions
130
173
  raw.subscriptions.get_subscriptions
@@ -139,12 +182,14 @@ module MaxApiClient
139
182
  raw.subscriptions.unsubscribe(url:)
140
183
  end
141
184
 
142
- def poll_updates(types = [], marker: nil, timeout: Polling::DEFAULT_TIMEOUT,
185
+ # rubocop:disable Metrics/ParameterLists
186
+ def poll_updates(types = [], marker: nil, limit: nil, timeout: Polling::DEFAULT_TIMEOUT,
143
187
  retry_interval: Polling::DEFAULT_RETRY_INTERVAL, read_timeout: nil, &block)
144
188
  poller = Polling.new(
145
189
  self,
146
190
  types:,
147
191
  marker:,
192
+ limit:,
148
193
  timeout:,
149
194
  retry_interval:,
150
195
  read_timeout:
@@ -154,6 +199,7 @@ module MaxApiClient
154
199
 
155
200
  poller.each(&block)
156
201
  end
202
+ # rubocop:enable Metrics/ParameterLists
157
203
 
158
204
  def upload_image(options)
159
205
  data = upload.image(**options)
@@ -187,8 +233,13 @@ module MaxApiClient
187
233
  query.merge(key => normalize_types(query[key]))
188
234
  end
189
235
 
236
+ def warn_deprecated(method_name, reason)
237
+ warn("[max_api_client] #{method_name} is deprecated: #{reason}", uplevel: 2)
238
+ end
239
+
190
240
  def message_from(response)
191
241
  response.fetch("message") { response.fetch(:message) }
192
242
  end
193
243
  end
244
+ # rubocop:enable Metrics/ClassLength
194
245
  end
@@ -6,6 +6,10 @@ module MaxApiClient
6
6
  def to_h
7
7
  raise NotImplementedError, "#{self.class} must implement #to_h"
8
8
  end
9
+
10
+ def to_json(*args)
11
+ to_h.to_json(*args)
12
+ end
9
13
  end
10
14
 
11
15
  # Shared attachment implementation for upload-backed media objects.
@@ -105,7 +109,71 @@ module MaxApiClient
105
109
  end
106
110
 
107
111
  def to_h
108
- { type: "share", payload: { url:, token: } }
112
+ { type: "share", payload: { url:, token: }.compact }
113
+ end
114
+ end
115
+
116
+ # Attachment wrapper for contact cards.
117
+ class ContactAttachment < Attachment
118
+ attr_reader :name, :contact_id, :vcf_info, :vcf_phone
119
+
120
+ def initialize(name: nil, contact_id: nil, vcf_info: nil, vcf_phone: nil)
121
+ super()
122
+ @name = name
123
+ @contact_id = contact_id
124
+ @vcf_info = vcf_info
125
+ @vcf_phone = vcf_phone
126
+ end
127
+
128
+ def to_h
129
+ { type: "contact", payload: { name:, contact_id:, vcf_info:, vcf_phone: }.compact }
130
+ end
131
+ end
132
+
133
+ # Attachment wrapper for an inline keyboard: an array of button rows.
134
+ class InlineKeyboardAttachment < Attachment
135
+ attr_reader :buttons
136
+
137
+ def initialize(buttons:)
138
+ super()
139
+ @buttons = buttons
140
+ end
141
+
142
+ def to_h
143
+ { type: "inline_keyboard", payload: { buttons: } }
144
+ end
145
+ end
146
+
147
+ # Builders for inline keyboard buttons.
148
+ module Button
149
+ module_function
150
+
151
+ def callback(text, payload)
152
+ { type: "callback", text:, payload: }
153
+ end
154
+
155
+ def link(text, url)
156
+ { type: "link", text:, url: }
157
+ end
158
+
159
+ def message(text)
160
+ { type: "message", text: }
161
+ end
162
+
163
+ def request_contact(text)
164
+ { type: "request_contact", text: }
165
+ end
166
+
167
+ def request_geo_location(text, quick: nil)
168
+ { type: "request_geo_location", text:, quick: }.compact
169
+ end
170
+
171
+ def open_app(text, web_app, payload: nil, contact_id: nil)
172
+ { type: "open_app", text:, web_app:, payload:, contact_id: }.compact
173
+ end
174
+
175
+ def clipboard(text, payload)
176
+ { type: "clipboard", text:, payload: }
109
177
  end
110
178
  end
111
179
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MaxApiClient
4
+ # Builds a TLS trust store from the system defaults and an optional CA file.
5
+ class CertificateStore
6
+ def self.configure(http, ca_file:, verify_ssl:)
7
+ http.use_ssl = true
8
+ http.verify_mode = verify_ssl ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
9
+ http.cert_store = build(ca_file:) if verify_ssl
10
+ end
11
+
12
+ def self.build(ca_file:)
13
+ OpenSSL::X509::Store.new.tap do |store|
14
+ store.set_default_paths
15
+ store.add_file(ca_file) if ca_file
16
+ end
17
+ end
18
+ end
19
+ end
@@ -3,7 +3,8 @@
3
3
  module MaxApiClient
4
4
  # HTTP transport client responsible for authenticated API requests.
5
5
  class Client
6
- DEFAULT_BASE_URL = "https://platform-api.max.ru"
6
+ DEFAULT_BASE_URL = "https://platform-api2.max.ru"
7
+ DEFAULT_CA_FILE = File.expand_path("../../certs/russian_trusted_root_ca.pem", __dir__)
7
8
  REQUEST_CLASSES = {
8
9
  get: Net::HTTP::Get,
9
10
  post: Net::HTTP::Post,
@@ -12,15 +13,18 @@ module MaxApiClient
12
13
  delete: Net::HTTP::Delete
13
14
  }.freeze
14
15
 
15
- attr_reader :token, :base_url
16
+ attr_reader :token, :base_url, :ca_file, :verify_ssl
16
17
 
17
18
  # rubocop:disable Metrics/ParameterLists
18
- def initialize(token:, base_url: DEFAULT_BASE_URL, adapter: nil, open_timeout: nil, read_timeout: nil, logger: nil)
19
+ def initialize(token:, base_url: DEFAULT_BASE_URL, adapter: nil, open_timeout: nil, read_timeout: nil,
20
+ ca_file: DEFAULT_CA_FILE, verify_ssl: true, logger: nil)
19
21
  @token = token
20
22
  @base_url = base_url
21
23
  @adapter = adapter
22
24
  @open_timeout = open_timeout
23
25
  @read_timeout = read_timeout
26
+ @ca_file = ca_file
27
+ @verify_ssl = verify_ssl
24
28
  @logger = logger || MaxApiClient.logger
25
29
  end
26
30
  # rubocop:enable Metrics/ParameterLists
@@ -82,7 +86,7 @@ module MaxApiClient
82
86
 
83
87
  params = URI.decode_www_form(String(uri.query))
84
88
  query.to_h.each do |key, value|
85
- next if value.nil? || value == false
89
+ next if value.nil?
86
90
 
87
91
  params << [key.to_s, value.to_s]
88
92
  end
@@ -122,10 +126,13 @@ module MaxApiClient
122
126
  end
123
127
 
124
128
  def configured_http(uri, open_timeout:, read_timeout:)
129
+ open_timeout ||= @open_timeout
130
+ read_timeout ||= @read_timeout
131
+
125
132
  Net::HTTP.new(uri.host, uri.port).tap do |http|
126
- http.use_ssl = uri.scheme == "https"
127
- http.open_timeout = open_timeout || @open_timeout if open_timeout || @open_timeout
128
- http.read_timeout = read_timeout || @read_timeout if read_timeout || @read_timeout
133
+ CertificateStore.configure(http, ca_file:, verify_ssl:) if uri.scheme == "https"
134
+ http.open_timeout = open_timeout if open_timeout
135
+ http.read_timeout = read_timeout if read_timeout
129
136
  end
130
137
  end
131
138
 
@@ -16,11 +16,12 @@ module MaxApiClient
16
16
  ].freeze
17
17
 
18
18
  # rubocop:disable Metrics/ParameterLists
19
- def initialize(api, types: [], marker: nil, timeout: DEFAULT_TIMEOUT, retry_interval: DEFAULT_RETRY_INTERVAL,
20
- read_timeout: nil)
19
+ def initialize(api, types: [], marker: nil, limit: nil, timeout: DEFAULT_TIMEOUT,
20
+ retry_interval: DEFAULT_RETRY_INTERVAL, read_timeout: nil)
21
21
  @api = api
22
22
  @types = types
23
23
  @marker = marker
24
+ @limit = limit
24
25
  @timeout = timeout
25
26
  @retry_interval = retry_interval
26
27
  @read_timeout = read_timeout || (timeout.to_i + READ_TIMEOUT_PADDING)
@@ -63,12 +64,13 @@ module MaxApiClient
63
64
 
64
65
  private
65
66
 
66
- attr_reader :api, :types, :marker, :timeout, :retry_interval, :read_timeout
67
+ attr_reader :api, :types, :marker, :limit, :timeout, :retry_interval, :read_timeout
67
68
 
68
69
  def fetch_updates
69
70
  api.raw.subscriptions.get_updates(
70
71
  types: normalize_types(types),
71
72
  marker:,
73
+ limit:,
72
74
  timeout:,
73
75
  read_timeout:
74
76
  )
@@ -87,9 +89,9 @@ module MaxApiClient
87
89
  end
88
90
 
89
91
  def normalize_types(value)
90
- return value.join(",") if value.is_a?(Array)
92
+ value = value.join(",") if value.is_a?(Array)
91
93
 
92
- value
94
+ value unless value.to_s.empty?
93
95
  end
94
96
  end
95
97
  end
@@ -17,6 +17,10 @@ module MaxApiClient
17
17
  @messages ||= build_api(MessagesApi)
18
18
  end
19
19
 
20
+ def comments
21
+ @comments ||= build_api(CommentsApi)
22
+ end
23
+
20
24
  def subscriptions
21
25
  @subscriptions ||= build_api(SubscriptionsApi)
22
26
  end
@@ -40,13 +44,19 @@ module MaxApiClient
40
44
  end
41
45
  # rubocop:enable Naming/AccessorMethodName
42
46
 
47
+ # PATCH /me is absent from the current API schema; prefer #edit_my_commands.
43
48
  def edit_my_info(**extra)
44
49
  patch("me", body: extra)
45
50
  end
51
+
52
+ def edit_my_commands(commands:)
53
+ patch("me/commands", body: { commands: })
54
+ end
46
55
  end
47
56
 
48
57
  # Raw chat management endpoints.
49
58
  class ChatsApi < BaseApi
59
+ # GET /chats is no longer supported by the API since June 2026.
50
60
  def get_all(**extra)
51
61
  get("chats", query: extra)
52
62
  end
@@ -55,6 +65,7 @@ module MaxApiClient
55
65
  get("chats/{chat_id}", path_params: { chat_id: })
56
66
  end
57
67
 
68
+ # Lookup by public link is absent from the current API schema.
58
69
  def get_by_link(chat_link:)
59
70
  get("chats/{chat_link}", path_params: { chat_link: })
60
71
  end
@@ -71,6 +82,15 @@ module MaxApiClient
71
82
  get("chats/{chat_id}/members/admins", path_params: { chat_id: })
72
83
  end
73
84
 
85
+ def add_chat_admins(chat_id:, admins:)
86
+ post("chats/{chat_id}/members/admins", path_params: { chat_id: }, body: { admins: })
87
+ end
88
+
89
+ def remove_chat_admin(chat_id:, user_id:)
90
+ delete("chats/{chat_id}/members/admins/{user_id}", path_params: { chat_id:, user_id: })
91
+ end
92
+
93
+ # POST /chats/{chat_id}/members was removed from the API on 2026-09-30.
74
94
  def add_chat_members(chat_id:, user_ids:)
75
95
  post("chats/{chat_id}/members", path_params: { chat_id: }, body: { user_ids: })
76
96
  end
@@ -80,7 +100,7 @@ module MaxApiClient
80
100
  end
81
101
 
82
102
  def remove_chat_member(chat_id:, user_id:, block: nil)
83
- delete("chats/{chat_id}/members", path_params: { chat_id: }, body: compact_nil(user_id:, block:))
103
+ delete("chats/{chat_id}/members", path_params: { chat_id: }, query: compact_nil(user_id:, block:))
84
104
  end
85
105
 
86
106
  def get_pinned_message(chat_id:)
@@ -108,22 +128,30 @@ module MaxApiClient
108
128
  class MessagesApi < BaseApi
109
129
  ATTACHMENT_NOT_READY_CODE = "attachment.not.ready"
110
130
  ATTACHMENT_NOT_READY_DELAY = 1
131
+ ATTACHMENT_NOT_READY_RETRIES = 3
111
132
 
112
133
  def get(**query)
113
134
  super("messages", query:)
114
135
  end
115
136
 
116
137
  def get_by_id(message_id:)
117
- get("messages/{message_id}", path_params: { message_id: })
138
+ call_api(:get, "messages/{message_id}", path_params: { message_id: })
118
139
  end
119
140
 
120
141
  def send(chat_id: nil, user_id: nil, disable_link_preview: nil, **body)
121
- post("messages", query: compact_nil(chat_id:, user_id:, disable_link_preview:), body:)
122
- rescue ApiError => e
123
- raise unless e.code == ATTACHMENT_NOT_READY_CODE
142
+ attempt = 0
143
+
144
+ begin
145
+ post("messages", query: compact_nil(chat_id:, user_id:, disable_link_preview:), body:)
146
+ rescue ApiError => e
147
+ raise unless e.code == ATTACHMENT_NOT_READY_CODE
124
148
 
125
- sleep(ATTACHMENT_NOT_READY_DELAY)
126
- send(chat_id:, user_id:, disable_link_preview:, **body)
149
+ attempt += 1
150
+ raise if attempt >= ATTACHMENT_NOT_READY_RETRIES
151
+
152
+ sleep(ATTACHMENT_NOT_READY_DELAY * (2**(attempt - 1)))
153
+ retry
154
+ end
127
155
  end
128
156
 
129
157
  def edit(message_id:, **body)
@@ -134,8 +162,36 @@ module MaxApiClient
134
162
  super("messages", query: { message_id: })
135
163
  end
136
164
 
137
- def answer_on_callback(callback_id:, **body)
138
- post("answers", query: { callback_id: }, body:)
165
+ def get_video_info(video_token:)
166
+ call_api(:get, "videos/{video_token}", path_params: { video_token: })
167
+ end
168
+
169
+ def answer_on_callback(callback_id:, disable_link_preview: nil, **body)
170
+ post("answers", query: compact_nil(callback_id:, disable_link_preview:), body:)
171
+ end
172
+ end
173
+
174
+ # Raw endpoints for comments under channel posts.
175
+ class CommentsApi < BaseApi
176
+ def get(message_id:, **query)
177
+ super("messages/{message_id}/comments", path_params: { message_id: }, query:)
178
+ end
179
+
180
+ def get_by_id(message_id:, comment_id:)
181
+ call_api(:get, "messages/{message_id}/comments/{comment_id}", path_params: { message_id:, comment_id: })
182
+ end
183
+
184
+ def send(message_id:, disable_link_preview: nil, **body)
185
+ post("messages/{message_id}/comments", path_params: { message_id: },
186
+ query: compact_nil(disable_link_preview:), body:)
187
+ end
188
+
189
+ def edit(message_id:, comment_id:, **body)
190
+ put("messages/{message_id}/comments", path_params: { message_id: }, query: { comment_id: }, body:)
191
+ end
192
+
193
+ def delete(message_id:, comment_id:)
194
+ super("messages/{message_id}/comments", path_params: { message_id: }, query: { comment_id: })
139
195
  end
140
196
  end
141
197
 
@@ -2,5 +2,5 @@
2
2
 
3
3
  # Root namespace for gem version information.
4
4
  module MaxApiClient
5
- VERSION = "0.1.2"
5
+ VERSION = "0.2.0"
6
6
  end
@@ -2,11 +2,13 @@
2
2
 
3
3
  require "json"
4
4
  require "net/http"
5
+ require "openssl"
5
6
  require "uri"
6
7
  require "securerandom"
7
8
 
8
9
  require_relative "max_api_client/version"
9
10
  require_relative "max_api_client/error"
11
+ require_relative "max_api_client/certificate_store"
10
12
  require_relative "max_api_client/client"
11
13
  require_relative "max_api_client/base_api"
12
14
  require_relative "max_api_client/raw_api"
@@ -17,9 +17,12 @@ module MaxApiClient
17
17
 
18
18
  class Client
19
19
  DEFAULT_BASE_URL: String
20
+ DEFAULT_CA_FILE: String
20
21
  attr_reader token: String
21
22
  attr_reader base_url: String
22
- def initialize: (token: String, ?base_url: String, ?adapter: untyped, ?open_timeout: Numeric?, ?read_timeout: Numeric?, ?logger: untyped) -> void
23
+ attr_reader ca_file: String?
24
+ attr_reader verify_ssl: bool
25
+ def initialize: (token: String, ?base_url: String, ?adapter: untyped, ?open_timeout: Numeric?, ?read_timeout: Numeric?, ?ca_file: String?, ?verify_ssl: bool, ?logger: untyped) -> void
23
26
  def call: (method: Symbol | String, ?path: String?, ?query: untyped, ?body: untyped, ?path_params: untyped, ?headers: untyped, ?url: String?, ?raw_body: untyped, ?parse_json: bool) -> Hash[Symbol, untyped]
24
27
  end
25
28
 
@@ -33,6 +36,7 @@ module MaxApiClient
33
36
  def bots: () -> BotsApi
34
37
  def chats: () -> ChatsApi
35
38
  def messages: () -> MessagesApi
39
+ def comments: () -> CommentsApi
36
40
  def subscriptions: () -> SubscriptionsApi
37
41
  def uploads: () -> UploadsApi
38
42
  end
@@ -40,6 +44,7 @@ module MaxApiClient
40
44
  class BotsApi
41
45
  def get_my_info: () -> untyped
42
46
  def edit_my_info: (untyped extra) -> untyped
47
+ def edit_my_commands: (commands: Array[bot_command]) -> untyped
43
48
  end
44
49
 
45
50
  class ChatsApi
@@ -49,6 +54,8 @@ module MaxApiClient
49
54
  def edit: (chat_id: Integer, **untyped extra) -> untyped
50
55
  def get_chat_membership: (chat_id: Integer) -> untyped
51
56
  def get_chat_admins: (chat_id: Integer) -> untyped
57
+ def add_chat_admins: (chat_id: Integer, admins: Array[Hash[Symbol | String, untyped]]) -> untyped
58
+ def remove_chat_admin: (chat_id: Integer, user_id: Integer) -> untyped
52
59
  def add_chat_members: (chat_id: Integer, user_ids: Array[Integer]) -> untyped
53
60
  def get_chat_members: (chat_id: Integer, **untyped query) -> untyped
54
61
  def remove_chat_member: (chat_id: Integer, user_id: Integer, ?block: bool?) -> untyped
@@ -65,7 +72,16 @@ module MaxApiClient
65
72
  def send: (?chat_id: Integer?, ?user_id: Integer?, ?disable_link_preview: bool?, **untyped body) -> untyped
66
73
  def edit: (message_id: String, **untyped body) -> untyped
67
74
  def delete: (message_id: String) -> untyped
68
- def answer_on_callback: (callback_id: String, **untyped body) -> untyped
75
+ def get_video_info: (video_token: String) -> untyped
76
+ def answer_on_callback: (callback_id: String, ?disable_link_preview: bool?, **untyped body) -> untyped
77
+ end
78
+
79
+ class CommentsApi
80
+ def get: (message_id: String, **untyped query) -> untyped
81
+ def get_by_id: (message_id: String, comment_id: String) -> untyped
82
+ def send: (message_id: String, ?disable_link_preview: bool?, **untyped body) -> untyped
83
+ def edit: (message_id: String, comment_id: String, **untyped body) -> untyped
84
+ def delete: (message_id: String, comment_id: String) -> untyped
69
85
  end
70
86
 
71
87
  class SubscriptionsApi
@@ -81,6 +97,7 @@ module MaxApiClient
81
97
 
82
98
  class Attachment
83
99
  def to_h: () -> Hash[Symbol, untyped]
100
+ def to_json: (*untyped args) -> String
84
101
  end
85
102
 
86
103
  class ImageAttachment < Attachment
@@ -104,6 +121,22 @@ module MaxApiClient
104
121
  class ShareAttachment < Attachment
105
122
  end
106
123
 
124
+ class ContactAttachment < Attachment
125
+ end
126
+
127
+ class InlineKeyboardAttachment < Attachment
128
+ end
129
+
130
+ module Button
131
+ def self.callback: (String text, String payload) -> Hash[Symbol, untyped]
132
+ def self.link: (String text, String url) -> Hash[Symbol, untyped]
133
+ def self.message: (String text) -> Hash[Symbol, untyped]
134
+ def self.request_contact: (String text) -> Hash[Symbol, untyped]
135
+ def self.request_geo_location: (String text, ?quick: bool?) -> Hash[Symbol, untyped]
136
+ def self.open_app: (String text, String web_app, ?payload: String?, ?contact_id: Integer?) -> Hash[Symbol, untyped]
137
+ def self.clipboard: (String text, String payload) -> Hash[Symbol, untyped]
138
+ end
139
+
107
140
  class Upload
108
141
  def initialize: (Api) -> void
109
142
  end
@@ -112,7 +145,7 @@ module MaxApiClient
112
145
  DEFAULT_TIMEOUT: Integer
113
146
  DEFAULT_RETRY_INTERVAL: Integer
114
147
  READ_TIMEOUT_PADDING: Integer
115
- def initialize: (Api api, ?types: Array[String] | String, ?marker: Integer?, ?timeout: Integer, ?retry_interval: Integer, ?read_timeout: Numeric?) -> void
148
+ def initialize: (Api api, ?types: Array[String] | String, ?marker: Integer?, ?limit: Integer?, ?timeout: Integer, ?retry_interval: Integer, ?read_timeout: Numeric?) -> void
116
149
  def each: () { (untyped update) -> void } -> self
117
150
  def each: () -> Enumerator[untyped, self]
118
151
  def stop: () -> bool
@@ -123,9 +156,10 @@ module MaxApiClient
123
156
  attr_reader raw: RawApi
124
157
  attr_reader upload: Upload
125
158
  attr_reader client: Client
126
- def initialize: (token: String, ?base_url: String, ?adapter: untyped, ?open_timeout: Numeric?, ?read_timeout: Numeric?, ?logger: untyped) -> void
159
+ def initialize: (token: String, ?base_url: String, ?adapter: untyped, ?open_timeout: Numeric?, ?read_timeout: Numeric?, ?ca_file: String?, ?verify_ssl: bool, ?logger: untyped) -> void
127
160
  def get_my_info: () -> untyped
128
161
  def edit_my_info: (untyped extra) -> untyped
162
+ def edit_my_commands: (Array[bot_command] commands) -> untyped
129
163
  def set_my_commands: (Array[bot_command] commands) -> untyped
130
164
  def delete_my_commands: () -> untyped
131
165
  def get_all_chats: (?untyped extra) -> untyped
@@ -134,6 +168,8 @@ module MaxApiClient
134
168
  def edit_chat_info: (Integer chat_id, untyped extra) -> untyped
135
169
  def get_chat_membership: (Integer chat_id) -> untyped
136
170
  def get_chat_admins: (Integer chat_id) -> untyped
171
+ def add_chat_admins: (Integer chat_id, Array[Hash[Symbol | String, untyped]] admins) -> untyped
172
+ def remove_chat_admin: (Integer chat_id, Integer user_id) -> untyped
137
173
  def add_chat_members: (Integer chat_id, Array[Integer] user_ids) -> untyped
138
174
  def get_chat_members: (Integer chat_id, ?untyped extra) -> untyped
139
175
  def remove_chat_member: (Integer chat_id, Integer user_id, ?block: bool?) -> untyped
@@ -147,13 +183,19 @@ module MaxApiClient
147
183
  def get_messages: (Integer chat_id, ?untyped extra) -> untyped
148
184
  def get_message: (String message_id) -> untyped
149
185
  def edit_message: (String message_id, ?untyped extra) -> untyped
150
- def delete_message: (String message_id, ?untyped extra) -> untyped
186
+ def delete_message: (String message_id) -> untyped
187
+ def get_video_info: (String video_token) -> untyped
188
+ def get_comments: (String message_id, ?untyped extra) -> untyped
189
+ def get_comment: (String message_id, String comment_id) -> untyped
190
+ def send_comment: (String message_id, String text, ?untyped extra) -> untyped
191
+ def edit_comment: (String message_id, String comment_id, ?untyped extra) -> untyped
192
+ def delete_comment: (String message_id, String comment_id) -> untyped
151
193
  def answer_on_callback: (String callback_id, ?untyped extra) -> untyped
152
194
  def get_subscriptions: () -> untyped
153
195
  def subscribe: (String url, ?update_types: Array[String] | String?, ?secret: String?) -> untyped
154
196
  def unsubscribe: (String url) -> untyped
155
- def poll_updates: (?Array[String] | String types, ?marker: Integer?, ?timeout: Integer, ?retry_interval: Integer, ?read_timeout: Numeric?) { (untyped update) -> void } -> Polling
156
- def poll_updates: (?Array[String] | String types, ?marker: Integer?, ?timeout: Integer, ?retry_interval: Integer, ?read_timeout: Numeric?) -> Enumerator[untyped, Polling]
197
+ def poll_updates: (?Array[String] | String types, ?marker: Integer?, ?limit: Integer?, ?timeout: Integer, ?retry_interval: Integer, ?read_timeout: Numeric?) { (untyped update) -> void } -> Polling
198
+ def poll_updates: (?Array[String] | String types, ?marker: Integer?, ?limit: Integer?, ?timeout: Integer, ?retry_interval: Integer, ?read_timeout: Numeric?) -> Enumerator[untyped, Polling]
157
199
  def upload_image: (Hash[Symbol, untyped] options) -> ImageAttachment
158
200
  def upload_video: (Hash[Symbol, untyped] options) -> VideoAttachment
159
201
  def upload_audio: (Hash[Symbol, untyped] options) -> AudioAttachment
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: max_api_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexandr Zimin
@@ -23,10 +23,12 @@ files:
23
23
  - LICENSE.txt
24
24
  - README.md
25
25
  - Rakefile
26
+ - certs/russian_trusted_root_ca.pem
26
27
  - lib/max_api_client.rb
27
28
  - lib/max_api_client/api.rb
28
29
  - lib/max_api_client/attachments.rb
29
30
  - lib/max_api_client/base_api.rb
31
+ - lib/max_api_client/certificate_store.rb
30
32
  - lib/max_api_client/client.rb
31
33
  - lib/max_api_client/error.rb
32
34
  - lib/max_api_client/polling.rb