@grom.js/effect-tg 0.10.0 → 0.12.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.
Files changed (46) hide show
  1. package/README.md +386 -25
  2. package/dist/BotApiError.js +1 -1
  3. package/dist/BotApiError.js.map +1 -1
  4. package/dist/Dialog.d.ts +24 -23
  5. package/dist/Dialog.d.ts.map +1 -1
  6. package/dist/Dialog.js +15 -17
  7. package/dist/Dialog.js.map +1 -1
  8. package/dist/Markup.d.ts +200 -11
  9. package/dist/Markup.d.ts.map +1 -1
  10. package/dist/Markup.js +39 -0
  11. package/dist/Markup.js.map +1 -1
  12. package/dist/Reply.d.ts +22 -0
  13. package/dist/Reply.d.ts.map +1 -0
  14. package/dist/Reply.js +18 -0
  15. package/dist/Reply.js.map +1 -0
  16. package/dist/Send.d.ts +16 -1
  17. package/dist/Send.d.ts.map +1 -1
  18. package/dist/Send.js +28 -5
  19. package/dist/Send.js.map +1 -1
  20. package/dist/Text.d.ts +1 -1
  21. package/dist/Text.d.ts.map +1 -1
  22. package/dist/index.d.ts +1 -0
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +1 -0
  25. package/dist/index.js.map +1 -1
  26. package/dist/internal/botApi.gen.d.ts +263 -191
  27. package/dist/internal/botApi.gen.d.ts.map +1 -1
  28. package/dist/internal/dialog.d.ts +4 -4
  29. package/dist/internal/dialog.d.ts.map +1 -1
  30. package/dist/internal/dialog.js +12 -13
  31. package/dist/internal/dialog.js.map +1 -1
  32. package/dist/internal/send.d.ts +4 -1
  33. package/dist/internal/send.d.ts.map +1 -1
  34. package/dist/internal/send.js +151 -7
  35. package/dist/internal/send.js.map +1 -1
  36. package/package.json +12 -11
  37. package/src/BotApiError.ts +1 -1
  38. package/src/Dialog.ts +31 -30
  39. package/src/Markup.ts +251 -11
  40. package/src/Reply.ts +36 -0
  41. package/src/Send.ts +51 -17
  42. package/src/Text.ts +1 -1
  43. package/src/index.ts +1 -0
  44. package/src/internal/botApi.gen.ts +267 -191
  45. package/src/internal/dialog.ts +16 -17
  46. package/src/internal/send.ts +171 -7
@@ -9,7 +9,7 @@ import * as Dialog from '../Dialog.ts'
9
9
  export const decodeDialogId = (dialogId: number): Option.Option<
10
10
  | { peer: 'user', id: Dialog.UserId }
11
11
  | { peer: 'group', id: Dialog.GroupId }
12
- | { peer: 'supergroup', id: Dialog.SupergroupId }
12
+ | { peer: 'channel', id: Dialog.ChannelId }
13
13
  | { peer: 'monoforum', id: number }
14
14
  | { peer: 'secret-chat', id: number }
15
15
  > => {
@@ -21,7 +21,7 @@ export const decodeDialogId = (dialogId: number): Option.Option<
21
21
  return Option.some({ peer: 'group', id: -dialogId as Dialog.GroupId })
22
22
  }
23
23
  if (-1997852516352 <= dialogId && dialogId <= -1000000000001) {
24
- return Option.some({ peer: 'supergroup', id: -(dialogId + 1000000000000) as Dialog.SupergroupId })
24
+ return Option.some({ peer: 'channel', id: -(dialogId + 1000000000000) as Dialog.ChannelId })
25
25
  }
26
26
  if (-4000000000000 <= dialogId && dialogId <= -2002147483649) {
27
27
  return Option.some({ peer: 'monoforum', id: -(dialogId + 1000000000000) })
@@ -36,7 +36,7 @@ export const decodeDialogId = (dialogId: number): Option.Option<
36
36
  export const decodePeerId: {
37
37
  (peer: 'user', dialogId: number): Option.Option<Dialog.UserId>
38
38
  (peer: 'group', dialogId: number): Option.Option<Dialog.GroupId>
39
- (peer: 'supergroup', dialogId: number): Option.Option<Dialog.SupergroupId>
39
+ (peer: 'channel', dialogId: number): Option.Option<Dialog.ChannelId>
40
40
  (peer: 'monoforum', dialogId: number): Option.Option<number>
41
41
  (peer: 'secret-chat', dialogId: number): Option.Option<number>
42
42
  } = (peer, dialogId) => {
@@ -48,7 +48,7 @@ export const decodePeerId: {
48
48
  }
49
49
 
50
50
  export const encodePeerId = (
51
- peer: 'user' | 'group' | 'supergroup' | 'monoforum' | 'secret-chat',
51
+ peer: 'user' | 'group' | 'channel' | 'monoforum' | 'secret-chat',
52
52
  id: number,
53
53
  ): Option.Option<Dialog.DialogId> => {
54
54
  if (Number.isSafeInteger(id)) {
@@ -58,7 +58,7 @@ export const encodePeerId = (
58
58
  if (peer === 'group' && 1 <= id && id <= 999999999999) {
59
59
  return Option.some(-id as Dialog.DialogId)
60
60
  }
61
- if (peer === 'supergroup' && 1 <= id && id <= 997852516352) {
61
+ if (peer === 'channel' && 1 <= id && id <= 997852516352) {
62
62
  return Option.some(-(id + 1000000000000) as Dialog.DialogId)
63
63
  }
64
64
  if (peer === 'monoforum' && 1002147483649 <= id && id <= 3000000000000) {
@@ -78,8 +78,7 @@ export const encodePeerId = (
78
78
  export const ofMessage: (
79
79
  message: BotApi.Types.Message,
80
80
  ) => Dialog.Dialog = (m) => {
81
- // TODO: Remove type assertion when bot-api-spec updates types.
82
- switch (m.chat.type as 'private' | 'group' | 'supergroup' | 'channel') {
81
+ switch (m.chat.type) {
83
82
  case 'private': {
84
83
  const user = new Dialog.User({
85
84
  id: Option.getOrThrow(decodePeerId('user', m.chat.id)),
@@ -94,23 +93,23 @@ export const ofMessage: (
94
93
  id: Option.getOrThrow(decodePeerId('group', m.chat.id)),
95
94
  })
96
95
  }
97
- case 'supergroup': {
98
- const supergroup = new Dialog.Supergroup({
99
- id: Option.getOrThrow(decodePeerId('supergroup', m.chat.id)),
100
- })
101
- if (m.message_thread_id != null) {
102
- return supergroup.topic(m.message_thread_id)
103
- }
104
- return supergroup
105
- }
106
96
  case 'channel': {
107
97
  const channel = new Dialog.Channel({
108
- id: Option.getOrThrow(decodePeerId('supergroup', m.chat.id)),
98
+ id: Option.getOrThrow(decodePeerId('channel', m.chat.id)),
109
99
  })
110
100
  if (m.direct_messages_topic != null) {
111
101
  return channel.directMessages(m.direct_messages_topic.topic_id)
112
102
  }
113
103
  return channel
114
104
  }
105
+ case 'supergroup': {
106
+ const supergroup = new Dialog.Supergroup({
107
+ id: Option.getOrThrow(decodePeerId('channel', m.chat.id)),
108
+ })
109
+ if (m.message_thread_id != null) {
110
+ return supergroup.topic(m.message_thread_id)
111
+ }
112
+ return supergroup
113
+ }
115
114
  }
116
115
  }
@@ -1,8 +1,10 @@
1
1
  import type * as Content from '../Content.ts'
2
2
  import type * as Dialog from '../Dialog.ts'
3
3
  import type * as Markup from '../Markup.ts'
4
+ import type * as Reply from '../Reply.ts'
4
5
  import type * as Send from '../Send.ts'
5
6
  import type * as Text from '../Text.ts'
7
+ import type { Types } from './botApi.gen.ts'
6
8
  import * as Tgx from '@grom.js/tgx'
7
9
  import * as Duration from 'effect/Duration'
8
10
  import * as Effect from 'effect/Effect'
@@ -69,7 +71,7 @@ const paramsText: (
69
71
  Plain: ({ text, entities }) => ({ text, entities }),
70
72
  Html: ({ html }) => ({ text: html, parse_mode: 'HTML' }),
71
73
  Markdown: ({ markdown }) => ({ text: markdown, parse_mode: 'MarkdownV2' }),
72
- Tgx: ({ tgx }) => ({ text: Tgx.html(tgx), parse_mode: 'HTML' }),
74
+ Tgx: ({ tgx }) => ({ text: Tgx.renderHtml(tgx), parse_mode: 'HTML' }),
73
75
  }),
74
76
  )
75
77
 
@@ -248,12 +250,12 @@ const paramsDialog: (
248
250
  Group: group => ({
249
251
  chat_id: group.dialogId(),
250
252
  }),
251
- Supergroup: supergroup => ({
252
- chat_id: supergroup.dialogId(),
253
- }),
254
253
  Channel: channel => ({
255
254
  chat_id: channel.dialogId(),
256
255
  }),
256
+ Supergroup: supergroup => ({
257
+ chat_id: supergroup.dialogId(),
258
+ }),
257
259
  PrivateTopic: topic => ({
258
260
  chat_id: topic.user.dialogId(),
259
261
  message_thread_id: topic.topicId,
@@ -275,6 +277,146 @@ const paramsDialog: (
275
277
 
276
278
  type ParamsMarkup = PickMethodParams<SendMethod, 'reply_markup'>
277
279
 
280
+ const paramsInlineButton = (btn: Markup.InlineButton): Types.InlineKeyboardButton => {
281
+ const base = {
282
+ text: btn.text,
283
+ style: btn.style,
284
+ icon_custom_emoji_id: btn.iconEmojiId,
285
+ }
286
+ if ('url' in btn && btn.url !== undefined) {
287
+ return { ...base, url: btn.url }
288
+ }
289
+ if ('callbackData' in btn && btn.callbackData !== undefined) {
290
+ return { ...base, callback_data: btn.callbackData }
291
+ }
292
+ if ('webApp' in btn && btn.webApp !== undefined) {
293
+ return { ...base, web_app: { url: btn.webApp.url } }
294
+ }
295
+ if ('loginUrl' in btn && btn.loginUrl !== undefined) {
296
+ return {
297
+ ...base,
298
+ login_url: {
299
+ url: btn.loginUrl.url,
300
+ ...(btn.loginUrl.forwardText !== undefined && { forward_text: btn.loginUrl.forwardText }),
301
+ ...(btn.loginUrl.botUsername !== undefined && { bot_username: btn.loginUrl.botUsername }),
302
+ ...(btn.loginUrl.requestWriteAccess !== undefined && { request_write_access: btn.loginUrl.requestWriteAccess }),
303
+ },
304
+ }
305
+ }
306
+ if ('switchInlineQuery' in btn && btn.switchInlineQuery !== undefined) {
307
+ return { ...base, switch_inline_query: btn.switchInlineQuery }
308
+ }
309
+ if ('switchInlineQueryCurrentChat' in btn && btn.switchInlineQueryCurrentChat !== undefined) {
310
+ return { ...base, switch_inline_query_current_chat: btn.switchInlineQueryCurrentChat }
311
+ }
312
+ if ('switchInlineQueryChosenChat' in btn && btn.switchInlineQueryChosenChat !== undefined) {
313
+ return {
314
+ ...base,
315
+ switch_inline_query_chosen_chat: {
316
+ query: btn.switchInlineQueryChosenChat.query,
317
+ allow_user_chats: btn.switchInlineQueryChosenChat.allowUserChats,
318
+ allow_bot_chats: btn.switchInlineQueryChosenChat.allowBotChats,
319
+ allow_group_chats: btn.switchInlineQueryChosenChat.allowGroupChats,
320
+ allow_channel_chats: btn.switchInlineQueryChosenChat.allowChannelChats,
321
+ },
322
+ }
323
+ }
324
+ if ('copyText' in btn && btn.copyText !== undefined) {
325
+ return { ...base, copy_text: { text: btn.copyText } }
326
+ }
327
+ if ('callbackGame' in btn && btn.callbackGame !== undefined) {
328
+ return { ...base, callback_game: {} }
329
+ }
330
+ if ('pay' in btn && btn.pay !== undefined) {
331
+ return { ...base, pay: true }
332
+ }
333
+ return base
334
+ }
335
+
336
+ const paramsChatAdminRights = (
337
+ rights: Markup.ChatAdminRights,
338
+ ): Types.ChatAdministratorRights => ({
339
+ is_anonymous: rights.isAnonymous,
340
+ can_manage_chat: rights.canManageChat,
341
+ can_delete_messages: rights.canDeleteMessages,
342
+ can_manage_video_chats: rights.canManageVideoChats,
343
+ can_restrict_members: rights.canRestrictMembers,
344
+ can_promote_members: rights.canPromoteMembers,
345
+ can_change_info: rights.canChangeInfo,
346
+ can_invite_users: rights.canInviteUsers,
347
+ can_post_stories: rights.canPostStories,
348
+ can_edit_stories: rights.canEditStories,
349
+ can_delete_stories: rights.canDeleteStories,
350
+ can_post_messages: rights.canPostMessages,
351
+ can_edit_messages: rights.canEditMessages,
352
+ can_pin_messages: rights.canPinMessages,
353
+ can_manage_topics: rights.canManageTopics,
354
+ can_manage_direct_messages: rights.canManageDirectMessages,
355
+ })
356
+
357
+ const paramsReplyButton = (btn: Markup.ReplyButton): string | Types.KeyboardButton => {
358
+ if (typeof btn === 'string') {
359
+ return btn
360
+ }
361
+ const base = {
362
+ text: btn.text,
363
+ style: btn.style,
364
+ icon_custom_emoji_id: btn.iconEmojiId,
365
+ }
366
+ if ('requestUsers' in btn && btn.requestUsers !== undefined) {
367
+ return {
368
+ ...base,
369
+ request_users: {
370
+ request_id: btn.requestUsers.requestId,
371
+ user_is_bot: btn.requestUsers.userIsBot,
372
+ user_is_premium: btn.requestUsers.userIsPremium,
373
+ max_quantity: btn.requestUsers.maxQuantity,
374
+ request_name: btn.requestUsers.requestName,
375
+ request_username: btn.requestUsers.requestUsername,
376
+ request_photo: btn.requestUsers.requestPhoto,
377
+ },
378
+ }
379
+ }
380
+ if ('requestChat' in btn && btn.requestChat !== undefined) {
381
+ return {
382
+ ...base,
383
+ request_chat: {
384
+ request_id: btn.requestChat.requestId,
385
+ chat_is_channel: btn.requestChat.chatIsChannel,
386
+ chat_is_forum: btn.requestChat.chatIsForum,
387
+ chat_has_username: btn.requestChat.chatHasUsername,
388
+ chat_is_created: btn.requestChat.chatIsCreated,
389
+ user_administrator_rights: btn.requestChat.userAdministratorRights
390
+ ? paramsChatAdminRights(btn.requestChat.userAdministratorRights)
391
+ : undefined,
392
+ bot_administrator_rights: btn.requestChat.botAdministratorRights
393
+ ? paramsChatAdminRights(btn.requestChat.botAdministratorRights)
394
+ : undefined,
395
+ bot_is_member: btn.requestChat.botIsMember,
396
+ request_title: btn.requestChat.requestTitle,
397
+ request_username: btn.requestChat.requestUsername,
398
+ request_photo: btn.requestChat.requestPhoto,
399
+ },
400
+ }
401
+ }
402
+ if ('requestContact' in btn && btn.requestContact !== undefined) {
403
+ return { ...base, request_contact: btn.requestContact }
404
+ }
405
+ if ('requestLocation' in btn && btn.requestLocation !== undefined) {
406
+ return { ...base, request_location: btn.requestLocation }
407
+ }
408
+ if ('requestPoll' in btn && btn.requestPoll !== undefined) {
409
+ return {
410
+ ...base,
411
+ request_poll: btn.requestPoll === true ? {} : { type: btn.requestPoll },
412
+ }
413
+ }
414
+ if ('webApp' in btn && btn.webApp !== undefined) {
415
+ return { ...base, web_app: { url: btn.webApp.url } }
416
+ }
417
+ return base
418
+ }
419
+
278
420
  const paramsMarkup: (
279
421
  markup: Markup.Markup,
280
422
  ) => ParamsMarkup = Match.type<Markup.Markup>().pipe(
@@ -282,12 +424,12 @@ const paramsMarkup: (
282
424
  Match.tagsExhaustive({
283
425
  InlineKeyboard: markup => ({
284
426
  reply_markup: {
285
- inline_keyboard: markup.rows, // TODO
427
+ inline_keyboard: markup.rows.map(row => row.map(paramsInlineButton)),
286
428
  },
287
429
  }),
288
430
  ReplyKeyboard: markup => ({
289
431
  reply_markup: {
290
- keyboard: markup.rows, // TODO
432
+ keyboard: markup.rows.map(row => row.map(paramsReplyButton)),
291
433
  is_persistent: markup.persistent,
292
434
  resize_keyboard: markup.resizable,
293
435
  one_time_keyboard: markup.oneTime,
@@ -311,6 +453,26 @@ const paramsMarkup: (
311
453
  }),
312
454
  )
313
455
 
456
+ // =============================================================================
457
+ // Parameters (Reply Options)
458
+ // =============================================================================
459
+
460
+ type ParamsReply = PickMethodParams<SendMethod, 'reply_parameters'>
461
+
462
+ const paramsReply = (
463
+ reply: Reply.Reply,
464
+ ): ParamsReply => ({
465
+ reply_parameters: {
466
+ chat_id: Match.value(reply.dialog).pipe(
467
+ Match.when(Match.number, id => id),
468
+ Match.orElse(peer => peer.dialogId()),
469
+ ),
470
+ message_id: reply.messageId,
471
+ checklist_task_id: Option.getOrUndefined(reply.taskId),
472
+ allow_sending_without_reply: reply.optional,
473
+ },
474
+ })
475
+
314
476
  // =============================================================================
315
477
  // Parameters (Send Options)
316
478
  // =============================================================================
@@ -333,6 +495,7 @@ export const sendMessage = Effect.fnUntraced(function* (params: {
333
495
  content: Content.Content
334
496
  dialog: Dialog.Dialog | Dialog.DialogId
335
497
  markup?: Markup.Markup
498
+ reply?: Reply.Reply
336
499
  options?: Send.Options
337
500
  }) {
338
501
  return yield* BotApi.callMethod(
@@ -340,8 +503,9 @@ export const sendMessage = Effect.fnUntraced(function* (params: {
340
503
  {
341
504
  ...paramsContent(params.content),
342
505
  ...paramsDialog(params.dialog),
343
- ...(params.options ? paramsOptions(params.options) : {}),
344
506
  ...(params.markup ? paramsMarkup(params.markup) : {}),
507
+ ...(params.reply ? paramsReply(params.reply) : {}),
508
+ ...(params.options ? paramsOptions(params.options) : {}),
345
509
  },
346
510
  )
347
511
  })