telegem 3.3.1 → 3.5.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.
data/lib/api/types.rb CHANGED
@@ -5,70 +5,70 @@ module Telegem
5
5
  @_raw_data = data || {}
6
6
  @_accessors_defined = {}
7
7
  end
8
-
8
+
9
9
  def method_missing(name, *args)
10
10
  return super if args.any? || block_given?
11
-
11
+
12
12
  define_accessor(name)
13
-
13
+
14
14
  if respond_to?(name)
15
15
  send(name)
16
16
  else
17
17
  super
18
18
  end
19
19
  end
20
-
20
+
21
21
  def respond_to_missing?(name, include_private = false)
22
22
  key = name.to_s
23
23
  camel_key = snake_to_camel(key)
24
24
  @_raw_data.key?(key) || @_raw_data.key?(camel_key) || super
25
25
  end
26
-
26
+
27
27
  def to_h
28
28
  @_raw_data.dup
29
29
  end
30
-
30
+
31
31
  alias_method :to_hash, :to_h
32
-
32
+
33
33
  def inspect
34
34
  "#<#{self.class.name} #{@_raw_data.inspect}>"
35
35
  end
36
-
36
+
37
37
  def to_s
38
38
  inspect
39
39
  end
40
-
40
+
41
41
  attr_reader :_raw_data
42
-
42
+
43
43
  private
44
-
44
+
45
45
  def define_accessor(name)
46
46
  return if @_accessors_defined[name]
47
-
47
+
48
48
  key = name.to_s
49
49
  camel_key = snake_to_camel(key)
50
-
50
+
51
51
  if @_raw_data.key?(key)
52
52
  define_singleton_method(name) { @_raw_data[key] }
53
53
  elsif @_raw_data.key?(camel_key)
54
54
  define_singleton_method(name) { @_raw_data[camel_key] }
55
55
  else
56
56
  define_singleton_method(name) do
57
- raise NoMethodError,
57
+ raise NoMethodError,
58
58
  "undefined method `#{name}' for #{self.class} with keys: #{@_raw_data.keys}"
59
59
  end
60
60
  end
61
-
61
+
62
62
  @_accessors_defined[name] = true
63
63
  end
64
-
64
+
65
65
  # helpers for converting nested objects
66
66
  def wrap(key, klass)
67
67
  if @_raw_data[key] && !@_raw_data[key].is_a?(klass)
68
68
  @_raw_data[key] = klass.new(@_raw_data[key])
69
69
  end
70
70
  end
71
-
71
+
72
72
  def wrap_array(key, klass)
73
73
  if @_raw_data[key] && @_raw_data[key].is_a?(Array)
74
74
  @_raw_data[key] = @_raw_data[key].map do |v|
@@ -76,35 +76,36 @@ module Telegem
76
76
  end
77
77
  end
78
78
  end
79
-
79
+
80
80
  def snake_to_camel(str)
81
81
  str.gsub(/_([a-z])/) { $1.upcase }
82
82
  end
83
-
83
+
84
84
  def camel_to_snake(str)
85
85
  str.gsub(/([A-Z])/) { "_#{$1.downcase}" }.sub(/^_/, '')
86
86
  end
87
87
  end
88
-
88
+
89
89
  class User < BaseType
90
90
  COMMON_FIELDS = %w[id is_bot first_name last_name username
91
- can_join_groups can_read_all_group_messages
92
- supports_inline_queries language_code
93
- is_premium added_to_attachment_menu
94
- can_connect_to_business].freeze
95
-
91
+ can_join_groups can_read_all_group_messages
92
+ supports_inline_queries language_code
93
+ is_premium added_to_attachment_menu
94
+ can_connect_to_business can_manage_bots
95
+ supports_guest_queries].freeze
96
+
96
97
  def initialize(data)
97
98
  super(data)
98
-
99
+
99
100
  COMMON_FIELDS.each do |field|
100
101
  define_accessor(field.to_sym)
101
102
  end
102
103
  end
103
-
104
+
104
105
  def full_name
105
106
  [first_name, last_name].compact.join(' ')
106
107
  end
107
-
108
+
108
109
  def mention
109
110
  if username
110
111
  "@#{username}"
@@ -114,127 +115,129 @@ module Telegem
114
115
  "User ##{id}"
115
116
  end
116
117
  end
117
-
118
+
118
119
  def to_s
119
120
  full_name
120
121
  end
121
122
  end
122
-
123
+
123
124
  class Chat < BaseType
124
125
  COMMON_FIELDS = %w[id type username title first_name last_name
125
- photo bio has_private_forwards
126
+ photo bio has_private_forwards
126
127
  has_restricted_voice_and_video_messages
127
- description invite_link pinned_message
128
+ description invite_link pinned_message
128
129
  permissions slow_mode_delay message_auto_delete_time
129
- has_protected_content sticker_set_name
130
+ has_protected_content sticker_set_name
130
131
  can_set_sticker_set linked_chat_id location].freeze
131
-
132
+
132
133
  def initialize(data)
133
134
  super(data)
134
-
135
+
135
136
  COMMON_FIELDS.each do |field|
136
137
  define_accessor(field.to_sym)
137
138
  end
138
139
  end
139
-
140
+
140
141
  def private?
141
142
  type == 'private'
142
143
  end
143
-
144
+
144
145
  def group?
145
146
  type == 'group'
146
147
  end
147
-
148
+
148
149
  def supergroup?
149
150
  type == 'supergroup'
150
151
  end
151
-
152
+
152
153
  def channel?
153
154
  type == 'channel'
154
155
  end
155
-
156
+
156
157
  def to_s
157
158
  title || username || "Chat ##{id}"
158
159
  end
159
160
  end
160
-
161
+
161
162
  class MessageEntity < BaseType
162
163
  COMMON_FIELDS = %w[type offset length url user language
163
164
  custom_emoji_id].freeze
164
-
165
+
165
166
  def initialize(data)
166
167
  super(data)
167
-
168
+
168
169
  COMMON_FIELDS.each do |field|
169
170
  define_accessor(field.to_sym)
170
171
  end
171
-
172
+
172
173
  if @_raw_data['user'] && !@_raw_data['user'].is_a?(User)
173
174
  @_raw_data['user'] = User.new(@_raw_data['user'])
174
175
  end
175
176
  end
176
177
  end
177
-
178
+
178
179
  class Message < BaseType
179
- COMMON_FIELDS = %w[message_id from chat date edit_date
180
- text caption entities caption_entities
181
- audio document photo sticker video voice
182
- video_note contact location venue
183
- new_chat_members left_chat_member
184
- new_chat_title new_chat_photo
185
- delete_chat_photo group_chat_created
186
- supergroup_chat_created channel_chat_created
187
- migrate_to_chat_id migrate_from_chat_id
188
- pinned_message invoice successful_payment
189
- connected_website reply_markup via_bot
190
- forward_from forward_from_chat
191
- forward_from_message_id forward_signature
192
- forward_sender_name forward_date reply_to_message
193
- media_group_id author_signature
194
- has_protected_content].freeze
195
-
180
+ COMMON_FIELDS = %w[message_id from chat date edit_date
181
+ text caption entities caption_entities
182
+ audio document photo sticker video voice
183
+ video_note contact location venue
184
+ new_chat_members left_chat_member
185
+ new_chat_title new_chat_photo
186
+ delete_chat_photo group_chat_created
187
+ supergroup_chat_created channel_chat_created
188
+ migrate_to_chat_id migrate_from_chat_id
189
+ pinned_message invoice successful_payment
190
+ connected_website reply_markup via_bot
191
+ forward_from forward_from_chat
192
+ forward_from_message_id forward_signature
193
+ forward_sender_name forward_date reply_to_message
194
+ media_group_id author_signature
195
+ has_protected_content managed_bot_created managed_bot
196
+ guest_bot_caller_user guest_bot_caller_chat
197
+ guest_query_id live_photo].freeze
198
+
196
199
  def initialize(data)
197
200
  super(data)
198
-
201
+
199
202
  COMMON_FIELDS.each do |field|
200
203
  define_accessor(field.to_sym)
201
204
  end
202
-
205
+
203
206
  convert_complex_fields
204
207
  end
205
-
208
+
206
209
  def command?
207
210
  return false unless text && entities
208
-
209
- entities.any? { |e| e.type == 'bot_command' &&
211
+
212
+ entities.any? { |e| e.type == 'bot_command' &&
210
213
  text[e.offset, e.length]&.start_with?('/') }
211
214
  end
212
-
215
+
213
216
  def command_name
214
217
  return nil unless command?
215
-
218
+
216
219
  command_entity = entities.find { |e| e.type == 'bot_command' }
217
220
  return nil unless command_entity
218
-
221
+
219
222
  cmd = text[command_entity.offset, command_entity.length]
220
223
  return nil if cmd.nil? || cmd.length <= 1
221
-
224
+
222
225
  cmd = cmd[1..-1]
223
226
  cmd.split('@').first.strip
224
227
  end
225
-
228
+
226
229
  def command_args
227
230
  return nil unless command?
228
-
231
+
229
232
  command_entity = entities.find { |e| e.type == 'bot_command' }
230
233
  return nil unless command_entity
231
-
234
+
232
235
  args_start = command_entity.offset + command_entity.length
233
236
  remaining = text[args_start..-1]
234
-
237
+
235
238
  next_entity = entities.select { |e| e.offset >= args_start }
236
239
  .min_by(&:offset)
237
-
240
+
238
241
  if next_entity
239
242
  args_end = next_entity.offset - 1
240
243
  text[args_start..args_end]&.strip
@@ -242,15 +245,15 @@ module Telegem
242
245
  remaining&.strip
243
246
  end
244
247
  end
245
-
248
+
246
249
  def reply?
247
250
  !!reply_to_message
248
251
  end
249
-
252
+
250
253
  def has_media?
251
254
  !!(audio || document || photo || video || voice || video_note || sticker)
252
255
  end
253
-
256
+
254
257
  def media_type
255
258
  return :audio if audio
256
259
  return :document if document
@@ -261,9 +264,9 @@ module Telegem
261
264
  return :sticker if sticker
262
265
  nil
263
266
  end
264
-
267
+
265
268
  private
266
-
269
+
267
270
  def convert_complex_fields
268
271
  # time conversions
269
272
  @_raw_data['date'] = Time.at(@_raw_data['date']) if @_raw_data['date'] && !@_raw_data['date'].is_a?(Time)
@@ -301,6 +304,10 @@ module Telegem
301
304
  wrap('voice', Voice)
302
305
  wrap('video_note', VideoNote)
303
306
  wrap('sticker', Sticker)
307
+ wrap('live_photo', LivePhoto)
308
+
309
+ wrap('guest_bot_caller_user', User)
310
+ wrap('guest_bot_caller_chat', Chat)
304
311
 
305
312
  wrap('invoice', Invoice)
306
313
  wrap('successful_payment', SuccessfulPayment)
@@ -324,6 +331,10 @@ module Telegem
324
331
  wrap('general_forum_topic_unhidden', GeneralForumTopicUnhidden)
325
332
  wrap('write_access_allowed', WriteAccessAllowed)
326
333
 
334
+ # Bot API 9.6 - Managed Bot Support
335
+ wrap('managed_bot_created', ManagedBotCreated)
336
+ wrap('managed_bot', ManagedBotUpdated)
337
+
327
338
  # arrays of sizes and photos
328
339
  wrap_array('photo', PhotoSize)
329
340
  wrap_array('new_chat_photo', PhotoSize)
@@ -331,7 +342,7 @@ module Telegem
331
342
  # fall back to original media wrapper for backward compatibility
332
343
  wrap_media_objects
333
344
  end
334
-
345
+
335
346
  def wrap_media_objects
336
347
  # Media files (fall‑back to generic types if no specific class defined)
337
348
  @_raw_data['document'] = Document.new(@_raw_data['document']) if @_raw_data['document'] && !@_raw_data['document'].is_a?(Document)
@@ -367,56 +378,57 @@ module Telegem
367
378
  end
368
379
  end
369
380
  end
370
-
381
+
371
382
  class CallbackQuery < BaseType
372
383
  COMMON_FIELDS = %w[id from message inline_message_id chat_instance data game_short_name].freeze
373
-
384
+
374
385
  def initialize(data)
375
386
  super(data)
376
-
387
+
377
388
  COMMON_FIELDS.each do |field|
378
389
  define_accessor(field.to_sym)
379
390
  end
380
-
391
+
381
392
  if @_raw_data['from'] && !@_raw_data['from'].is_a?(User)
382
393
  @_raw_data['from'] = User.new(@_raw_data['from'])
383
394
  end
384
-
395
+
385
396
  if @_raw_data['message'] && !@_raw_data['message'].is_a?(Message)
386
397
  @_raw_data['message'] = Message.new(@_raw_data['message'])
387
398
  end
388
399
  end
389
-
400
+
390
401
  def from_user?
391
402
  !!from
392
403
  end
393
-
404
+
394
405
  def message?
395
406
  !!message
396
407
  end
397
-
408
+
398
409
  def inline_message?
399
410
  !!inline_message_id
400
411
  end
401
412
  end
402
-
413
+
403
414
  class Update < BaseType
404
- COMMON_FIELDS = %w[update_id message edited_message channel_post
405
- edited_channel_post inline_query chosen_inline_result
406
- callback_query shipping_query pre_checkout_query
407
- poll poll_answer my_chat_member chat_member
408
- chat_join_request].freeze
409
-
415
+ COMMON_FIELDS = %w[update_id message edited_message channel_post
416
+ edited_channel_post inline_query chosen_inline_result
417
+ callback_query shipping_query pre_checkout_query
418
+ poll poll_answer my_chat_member chat_member
419
+ chat_join_request managed_bot_created managed_bot
420
+ guest_message].freeze
421
+
410
422
  def initialize(data)
411
423
  super(data)
412
-
424
+
413
425
  COMMON_FIELDS.each do |field|
414
426
  define_accessor(field.to_sym)
415
427
  end
416
-
428
+
417
429
  convert_update_objects
418
430
  end
419
-
431
+
420
432
  def type
421
433
  return :message if message
422
434
  return :edited_message if edited_message
@@ -432,9 +444,12 @@ module Telegem
432
444
  return :my_chat_member if my_chat_member
433
445
  return :chat_member if chat_member
434
446
  return :chat_join_request if chat_join_request
447
+ return :managed_bot_created if managed_bot_created
448
+ return :managed_bot if managed_bot
449
+ return :guest_message if guest_message
435
450
  :unknown
436
451
  end
437
-
452
+
438
453
  def from
439
454
  case type
440
455
  when :message, :edited_message
@@ -455,13 +470,17 @@ module Telegem
455
470
  my_chat_member&.from || chat_member&.from
456
471
  when :chat_join_request
457
472
  chat_join_request.from
473
+ when :managed_bot_created, :managed_bot
474
+ managed_bot_created&.from || managed_bot&.from
475
+ when :guest_message
476
+ guest_message.from
458
477
  else
459
478
  nil
460
479
  end
461
480
  end
462
-
481
+
463
482
  private
464
-
483
+
465
484
  def convert_update_objects
466
485
  wrap('message', Message)
467
486
  wrap('edited_message', Message)
@@ -485,6 +504,12 @@ module Telegem
485
504
  wrap('general_forum_topic_hidden', GeneralForumTopicHidden)
486
505
  wrap('general_forum_topic_unhidden', GeneralForumTopicUnhidden)
487
506
  wrap('write_access_allowed', WriteAccessAllowed)
507
+
508
+ # Bot API 9.6 - Managed Bot Support
509
+ wrap('managed_bot_created', ManagedBotCreated)
510
+ wrap('managed_bot', ManagedBotUpdated)
511
+ # Bot API 10.0 - Guest Message Support
512
+ wrap('guest_message', SentGuestMessage)
488
513
  end
489
514
  end
490
515
 
@@ -528,7 +553,17 @@ module Telegem
528
553
  end
529
554
  end
530
555
 
531
- class PollOption < BaseType; end
556
+ class PollOption < BaseType
557
+ def initialize(data)
558
+ super(data)
559
+ # Bot API 9.6 enhancements
560
+ wrap('added_by_user', User)
561
+ wrap('added_by_chat', Chat)
562
+ # Bot API 10.0 - media support
563
+ wrap('media', InputPollOptionMedia)
564
+ end
565
+ end
566
+
532
567
  class PollAnswer < BaseType; end
533
568
 
534
569
  class Poll < BaseType
@@ -536,10 +571,19 @@ module Telegem
536
571
  super(data)
537
572
  wrap_array('options', PollOption)
538
573
  wrap_array('explanation_entities', MessageEntity)
574
+ # Bot API 10.0 - poll media support
575
+ wrap('media', PollMedia)
576
+ wrap('explanation_media', PollMedia)
539
577
  end
540
578
  end
541
579
 
542
- class ChatPermissions < BaseType; end
580
+ class ChatPermissions < BaseType
581
+ def initialize(data)
582
+ super(data)
583
+ # Bot API 10.0 - reaction support
584
+ define_accessor(:can_react_to_messages)
585
+ end
586
+ end
543
587
  class ChatPhoto < BaseType; end
544
588
  class ChatInviteLink < BaseType; end
545
589
 
@@ -548,7 +592,13 @@ module Telegem
548
592
  class ChatMemberOwner < ChatMember; end
549
593
  class ChatMemberAdministrator < ChatMember; end
550
594
  class ChatMemberMember < ChatMember; end
551
- class ChatMemberRestricted < ChatMember; end
595
+ class ChatMemberRestricted < ChatMember
596
+ def initialize(data)
597
+ super(data)
598
+ # Bot API 10.0 - reaction support
599
+ define_accessor(:can_react_to_messages)
600
+ end
601
+ end
552
602
  class ChatMemberLeft < ChatMember; end
553
603
  class ChatMemberBanned < ChatMember; end
554
604
 
@@ -675,6 +725,33 @@ module Telegem
675
725
  class VideoChatEnded < BaseType; end
676
726
  class VideoChatParticipantsInvited < BaseType; end
677
727
  class VideoChatLocation < BaseType; end
728
+ # Bot API 9.6 - Managed Bot Support
729
+ class ManagedBotCreated < BaseType; end
730
+ class ManagedBotDeleted < BaseType; end
731
+ class ManagedBotUpdated < BaseType; end
732
+
733
+ # Bot API 10.0 - Guest Mode Support
734
+ class SentGuestMessage < BaseType; end
735
+
736
+ # Bot API 10.0 - Poll Media Support
737
+ class PollMedia < BaseType; end
738
+ class InputPollMedia < BaseType; end
739
+ class InputPollOptionMedia < BaseType; end
740
+
741
+ # Bot API 10.0 - Live Photo Support
742
+ class LivePhoto < BaseType
743
+ def initialize(data)
744
+ super(data)
745
+ wrap('photo', PhotoSize)
746
+ wrap('video', Video)
747
+ end
748
+ end
749
+
750
+ class InputMediaLivePhoto < BaseType; end
751
+ class PaidMediaLivePhoto < BaseType; end
752
+ class InputPaidMediaLivePhoto < BaseType; end
678
753
 
754
+ # Bot API 10.0 - Business Access Settings
755
+ class BotAccessSettings < BaseType; end
756
+ end
679
757
  end
680
- end
data/lib/core/composer.rb CHANGED
@@ -1,4 +1,4 @@
1
- # lib/core/composer.rb - HTTPX VERSION (NO ASYNC GEM)
1
+ # lib/core/composer.rb
2
2
  module Telegem
3
3
  module Core
4
4
  class Composer
@@ -40,7 +40,7 @@ module Telegem
40
40
  # Call the middleware with next in chain
41
41
  middleware_instance.call(context, next_middleware)
42
42
  else
43
- raise "Invalid middleware: #{middleware.class}"
43
+ raise "Invalid middleware: #{middleware.inspect} does not respond to :call"
44
44
  end
45
45
  end
46
46
  end
@@ -58,4 +58,4 @@ module Telegem
58
58
  end
59
59
  end
60
60
  end
61
- end
61
+ end
data/lib/core/context.rb CHANGED
@@ -436,16 +436,8 @@ module Telegem
436
436
  scene&.next_step(self, step_name)
437
437
  end
438
438
  def with_typing(&block)
439
- thread = Thread.new do
440
- while @typing_active
441
- typing
442
- sleep 5
443
- end
444
- end
445
- result = block.call
446
- @typing_active = false
447
- thread.join
448
- result
439
+ typing
440
+ block.call
449
441
  end
450
442
 
451
443
  def command?
@@ -463,6 +455,20 @@ module Telegem
463
455
  scene.enter(self, options[:step], options.except(:step))
464
456
  scene_name
465
457
  end
458
+
459
+ # Essential 9.6 methods for context.rb
460
+ def business_connection_id
461
+ message&.business_connection_id || @update.business_connection_id
462
+ end
463
+
464
+ def reply_draft(text, **options)
465
+ return unless chat
466
+ @bot.api.call('sendMessageDraft', { chat_id: chat.id, text: text }.merge(options))
467
+ end
468
+
469
+ def managed_bot
470
+ @update.managed_bot
471
+ end
466
472
 
467
473
  def logger
468
474
  @bot.logger
@@ -488,4 +494,4 @@ module Telegem
488
494
  end
489
495
  end
490
496
  end
491
- end
497
+ end
@@ -63,7 +63,6 @@ module Telegem
63
63
  end
64
64
 
65
65
  def increment_counters(ctx)
66
- now = Time.now.to_i
67
66
  if @options[:global]
68
67
  key = "global"
69
68
  @counters[:global].increment(key, 1, ttl: @options[:global][:per])
@@ -80,8 +79,12 @@ module Telegem
80
79
  end
81
80
  end
82
81
  def rate_limit_response(ctx)
83
- ctx.reply("⏳ Please wait a moment before sending another request.") rescue nil
82
+ begin
83
+ ctx.reply("⏳ Please wait a moment before sending another request.")
84
+ rescue StandardError => e
85
+ ctx.logger&.warn("Failed to send rate limit response: #{e.class}: #{e.message}")
86
+ end
84
87
  nil
85
88
  end
86
89
  end
87
- end
90
+ end
data/lib/plugins/cc ADDED
@@ -0,0 +1,3 @@
1
+ curl -H "Content-Type: application/json" \
2
+ -d '{"world": "hello world", "from": "es", "to": "fr"}' \
3
+ https://zen-drx-api.onrender.com