updated to 179 layer (#56)
This commit is contained in:
commit
73d880c8ac
84 changed files with 2795 additions and 397 deletions
|
@ -1,6 +1,6 @@
|
||||||
import { assertEquals } from 'https://deno.land/std@0.223.0/assert/mod.ts'
|
import { assertEquals } from 'https://deno.land/std@0.223.0/assert/mod.ts'
|
||||||
|
|
||||||
import { MtcuteError } from '@mtcute/core'
|
import { MtcuteError, tl } from '@mtcute/core'
|
||||||
import { BaseTelegramClient, TelegramClient } from '@mtcute/core/client.js'
|
import { BaseTelegramClient, TelegramClient } from '@mtcute/core/client.js'
|
||||||
|
|
||||||
import { getApiParams } from '../utils.ts'
|
import { getApiParams } from '../utils.ts'
|
||||||
|
@ -29,7 +29,10 @@ Deno.test('1. authorization', { sanitizeResources: false }, async (t) => {
|
||||||
code: () => '22222',
|
code: () => '22222',
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof MtcuteError && e.message.match(/Signup is no longer supported|2FA is enabled/)) {
|
if (
|
||||||
|
(e instanceof MtcuteError && e.message.match(/Signup is no longer supported|2FA is enabled/)) ||
|
||||||
|
tl.RpcError.is(e, 'SESSION_PASSWORD_NEEDED')
|
||||||
|
) {
|
||||||
// retry with another number
|
// retry with another number
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
|
@ -64,7 +67,10 @@ Deno.test('1. authorization', { sanitizeResources: false }, async (t) => {
|
||||||
code: () => '11111',
|
code: () => '11111',
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof MtcuteError && e.message.match(/Signup is no longer supported|2FA is enabled/)) {
|
if (
|
||||||
|
(e instanceof MtcuteError && e.message.match(/Signup is no longer supported|2FA is enabled/)) ||
|
||||||
|
tl.RpcError.is(e, 'SESSION_PASSWORD_NEEDED')
|
||||||
|
) {
|
||||||
// retry with another number
|
// retry with another number
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { expect } from 'chai'
|
import { expect } from 'chai'
|
||||||
import { describe, it } from 'mocha'
|
import { describe, it } from 'mocha'
|
||||||
|
|
||||||
import { MtcuteError } from '@mtcute/core'
|
import { MtcuteError, tl } from '@mtcute/core'
|
||||||
import { BaseTelegramClient, TelegramClient } from '@mtcute/core/client.js'
|
import { BaseTelegramClient, TelegramClient } from '@mtcute/core/client.js'
|
||||||
|
|
||||||
import { getApiParams } from '../utils.js'
|
import { getApiParams } from '../utils.js'
|
||||||
|
@ -32,7 +32,10 @@ describe('1. authorization', function () {
|
||||||
code: () => '22222',
|
code: () => '22222',
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof MtcuteError && e.message.match(/Signup is no longer supported|2FA is enabled/)) {
|
if (
|
||||||
|
(e instanceof MtcuteError && e.message.match(/Signup is no longer supported|2FA is enabled/)) ||
|
||||||
|
tl.RpcError.is(e, 'SESSION_PASSWORD_NEEDED')
|
||||||
|
) {
|
||||||
// retry with another number
|
// retry with another number
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
|
@ -67,7 +70,10 @@ describe('1. authorization', function () {
|
||||||
code: () => '11111',
|
code: () => '11111',
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof MtcuteError && e.message.match(/Signup is no longer supported|2FA is enabled/)) {
|
if (
|
||||||
|
(e instanceof MtcuteError && e.message.match(/Signup is no longer supported|2FA is enabled/)) ||
|
||||||
|
tl.RpcError.is(e, 'SESSION_PASSWORD_NEEDED')
|
||||||
|
) {
|
||||||
// retry with another number
|
// retry with another number
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -21,3 +21,8 @@ story: StoryUpdate = StoryUpdate
|
||||||
delete_story = DeleteStoryUpdate
|
delete_story = DeleteStoryUpdate
|
||||||
bot_reaction: BotReactionUpdate = BotReactionUpdate
|
bot_reaction: BotReactionUpdate = BotReactionUpdate
|
||||||
bot_reaction_count: BotReactionCountUpdate = BotReactionCountUpdate
|
bot_reaction_count: BotReactionCountUpdate = BotReactionCountUpdate
|
||||||
|
business_connection: BusinessConnectionUpdate = BusinessConnection
|
||||||
|
new_business_message = BusinessMessage + State in BusinessMessageContext
|
||||||
|
edit_business_message = BusinessMessage + State in BusinessMessageContext
|
||||||
|
business_message_group = BusinessMessage[] + State in BusinessMessageContext
|
||||||
|
delete_business_message = DeleteBusinessMessageUpdate
|
|
@ -130,6 +130,7 @@ import { deleteScheduledMessages } from './methods/messages/delete-scheduled-mes
|
||||||
import { editInlineMessage } from './methods/messages/edit-inline-message.js'
|
import { editInlineMessage } from './methods/messages/edit-inline-message.js'
|
||||||
import { editMessage } from './methods/messages/edit-message.js'
|
import { editMessage } from './methods/messages/edit-message.js'
|
||||||
import { ForwardMessageOptions, forwardMessages, forwardMessagesById } from './methods/messages/forward-messages.js'
|
import { ForwardMessageOptions, forwardMessages, forwardMessagesById } from './methods/messages/forward-messages.js'
|
||||||
|
import { getAllScheduledMessages } from './methods/messages/get-all-scheduled-messages.js'
|
||||||
import { getCallbackQueryMessage } from './methods/messages/get-callback-query-message.js'
|
import { getCallbackQueryMessage } from './methods/messages/get-callback-query-message.js'
|
||||||
import { getDiscussionMessage } from './methods/messages/get-discussion-message.js'
|
import { getDiscussionMessage } from './methods/messages/get-discussion-message.js'
|
||||||
import { getHistory, GetHistoryOffset } from './methods/messages/get-history.js'
|
import { getHistory, GetHistoryOffset } from './methods/messages/get-history.js'
|
||||||
|
@ -168,6 +169,7 @@ import { translateMessage } from './methods/messages/translate-message.js'
|
||||||
import { translateText } from './methods/messages/translate-text.js'
|
import { translateText } from './methods/messages/translate-text.js'
|
||||||
import { unpinAllMessages } from './methods/messages/unpin-all-messages.js'
|
import { unpinAllMessages } from './methods/messages/unpin-all-messages.js'
|
||||||
import { unpinMessage } from './methods/messages/unpin-message.js'
|
import { unpinMessage } from './methods/messages/unpin-message.js'
|
||||||
|
import { getCollectibleInfo } from './methods/misc/get-collectible-info.js'
|
||||||
import { initTakeoutSession } from './methods/misc/init-takeout-session.js'
|
import { initTakeoutSession } from './methods/misc/init-takeout-session.js'
|
||||||
import { _normalizePrivacyRules } from './methods/misc/normalize-privacy-rules.js'
|
import { _normalizePrivacyRules } from './methods/misc/normalize-privacy-rules.js'
|
||||||
import { withParams } from './methods/misc/with-params.js'
|
import { withParams } from './methods/misc/with-params.js'
|
||||||
|
@ -177,17 +179,25 @@ import { cancelPasswordEmail, resendPasswordEmail, verifyPasswordEmail } from '.
|
||||||
import { removeCloudPassword } from './methods/password/remove-cloud-password.js'
|
import { removeCloudPassword } from './methods/password/remove-cloud-password.js'
|
||||||
import { applyBoost } from './methods/premium/apply-boost.js'
|
import { applyBoost } from './methods/premium/apply-boost.js'
|
||||||
import { canApplyBoost, CanApplyBoostResult } from './methods/premium/can-apply-boost.js'
|
import { canApplyBoost, CanApplyBoostResult } from './methods/premium/can-apply-boost.js'
|
||||||
|
import { createBusinessChatLink } from './methods/premium/create-business-chat-link.js'
|
||||||
|
import { deleteBusinessChatLink, editBusinessChatLink } from './methods/premium/edit-business-chat-link.js'
|
||||||
import { getBoostStats } from './methods/premium/get-boost-stats.js'
|
import { getBoostStats } from './methods/premium/get-boost-stats.js'
|
||||||
import { getBoosts } from './methods/premium/get-boosts.js'
|
import { getBoosts } from './methods/premium/get-boosts.js'
|
||||||
|
import { getBusinessChatLinks } from './methods/premium/get-business-chat-links.js'
|
||||||
|
import { getBusinessConnection } from './methods/premium/get-business-connection.js'
|
||||||
import { getMyBoostSlots } from './methods/premium/get-my-boost-slots.js'
|
import { getMyBoostSlots } from './methods/premium/get-my-boost-slots.js'
|
||||||
import { iterBoosters } from './methods/premium/iter-boosters.js'
|
import { iterBoosters } from './methods/premium/iter-boosters.js'
|
||||||
|
import { setBusinessIntro } from './methods/premium/set-business-intro.js'
|
||||||
|
import { setBusinessWorkHours } from './methods/premium/set-business-work-hours.js'
|
||||||
import { addStickerToSet } from './methods/stickers/add-sticker-to-set.js'
|
import { addStickerToSet } from './methods/stickers/add-sticker-to-set.js'
|
||||||
import { createStickerSet } from './methods/stickers/create-sticker-set.js'
|
import { createStickerSet } from './methods/stickers/create-sticker-set.js'
|
||||||
import { deleteStickerFromSet } from './methods/stickers/delete-sticker-from-set.js'
|
import { deleteStickerFromSet } from './methods/stickers/delete-sticker-from-set.js'
|
||||||
import { getCustomEmojis, getCustomEmojisFromMessages } from './methods/stickers/get-custom-emojis.js'
|
import { getCustomEmojis, getCustomEmojisFromMessages } from './methods/stickers/get-custom-emojis.js'
|
||||||
import { getInstalledStickers } from './methods/stickers/get-installed-stickers.js'
|
import { getInstalledStickers } from './methods/stickers/get-installed-stickers.js'
|
||||||
|
import { getMyStickerSets } from './methods/stickers/get-my-sticker-sets.js'
|
||||||
import { getStickerSet } from './methods/stickers/get-sticker-set.js'
|
import { getStickerSet } from './methods/stickers/get-sticker-set.js'
|
||||||
import { moveStickerInSet } from './methods/stickers/move-sticker-in-set.js'
|
import { moveStickerInSet } from './methods/stickers/move-sticker-in-set.js'
|
||||||
|
import { replaceStickerInSet } from './methods/stickers/replace-sticker-in-set.js'
|
||||||
import { setChatStickerSet } from './methods/stickers/set-chat-sticker-set.js'
|
import { setChatStickerSet } from './methods/stickers/set-chat-sticker-set.js'
|
||||||
import { setStickerSetThumb } from './methods/stickers/set-sticker-set-thumb.js'
|
import { setStickerSetThumb } from './methods/stickers/set-sticker-set-thumb.js'
|
||||||
import { canSendStory, CanSendStoryResult } from './methods/stories/can-send-story.js'
|
import { canSendStory, CanSendStoryResult } from './methods/stories/can-send-story.js'
|
||||||
|
@ -225,6 +235,7 @@ import { iterProfilePhotos } from './methods/users/iter-profile-photos.js'
|
||||||
import { resolveChannel, resolvePeer, resolveUser } from './methods/users/resolve-peer.js'
|
import { resolveChannel, resolvePeer, resolveUser } from './methods/users/resolve-peer.js'
|
||||||
import { resolvePeerMany } from './methods/users/resolve-peer-many.js'
|
import { resolvePeerMany } from './methods/users/resolve-peer-many.js'
|
||||||
import { setGlobalTtl } from './methods/users/set-global-ttl.js'
|
import { setGlobalTtl } from './methods/users/set-global-ttl.js'
|
||||||
|
import { setMyBirthday } from './methods/users/set-my-birthday.js'
|
||||||
import { setMyEmojiStatus } from './methods/users/set-my-emoji-status.js'
|
import { setMyEmojiStatus } from './methods/users/set-my-emoji-status.js'
|
||||||
import { setMyProfilePhoto } from './methods/users/set-my-profile-photo.js'
|
import { setMyProfilePhoto } from './methods/users/set-my-profile-photo.js'
|
||||||
import { setMyUsername } from './methods/users/set-my-username.js'
|
import { setMyUsername } from './methods/users/set-my-username.js'
|
||||||
|
@ -245,6 +256,10 @@ import {
|
||||||
BotReactionCountUpdate,
|
BotReactionCountUpdate,
|
||||||
BotReactionUpdate,
|
BotReactionUpdate,
|
||||||
BotStoppedUpdate,
|
BotStoppedUpdate,
|
||||||
|
BusinessChatLink,
|
||||||
|
BusinessConnection,
|
||||||
|
BusinessMessage,
|
||||||
|
BusinessWorkHoursDay,
|
||||||
CallbackQuery,
|
CallbackQuery,
|
||||||
Chat,
|
Chat,
|
||||||
ChatEvent,
|
ChatEvent,
|
||||||
|
@ -255,12 +270,15 @@ import {
|
||||||
ChatMemberUpdate,
|
ChatMemberUpdate,
|
||||||
ChatPreview,
|
ChatPreview,
|
||||||
ChosenInlineResult,
|
ChosenInlineResult,
|
||||||
|
CollectibleInfo,
|
||||||
|
DeleteBusinessMessageUpdate,
|
||||||
DeleteMessageUpdate,
|
DeleteMessageUpdate,
|
||||||
DeleteStoryUpdate,
|
DeleteStoryUpdate,
|
||||||
Dialog,
|
Dialog,
|
||||||
FileDownloadLocation,
|
FileDownloadLocation,
|
||||||
FileDownloadParameters,
|
FileDownloadParameters,
|
||||||
ForumTopic,
|
ForumTopic,
|
||||||
|
FullChat,
|
||||||
GameHighScore,
|
GameHighScore,
|
||||||
HistoryReadUpdate,
|
HistoryReadUpdate,
|
||||||
InlineCallbackQuery,
|
InlineCallbackQuery,
|
||||||
|
@ -270,6 +288,7 @@ import {
|
||||||
InputFileLike,
|
InputFileLike,
|
||||||
InputInlineResult,
|
InputInlineResult,
|
||||||
InputMediaLike,
|
InputMediaLike,
|
||||||
|
InputMediaSticker,
|
||||||
InputMessageId,
|
InputMessageId,
|
||||||
InputPeerLike,
|
InputPeerLike,
|
||||||
InputPrivacyRule,
|
InputPrivacyRule,
|
||||||
|
@ -510,6 +529,41 @@ export interface TelegramClient extends ITelegramClient {
|
||||||
* @param handler Bot reaction count update handler
|
* @param handler Bot reaction count update handler
|
||||||
*/
|
*/
|
||||||
on(name: 'bot_reaction_count', handler: (upd: BotReactionCountUpdate) => void): this
|
on(name: 'bot_reaction_count', handler: (upd: BotReactionCountUpdate) => void): this
|
||||||
|
/**
|
||||||
|
* Register a business connection update handler
|
||||||
|
*
|
||||||
|
* @param name Event name
|
||||||
|
* @param handler Business connection update handler
|
||||||
|
*/
|
||||||
|
on(name: 'business_connection', handler: (upd: BusinessConnection) => void): this
|
||||||
|
/**
|
||||||
|
* Register a new business message handler
|
||||||
|
*
|
||||||
|
* @param name Event name
|
||||||
|
* @param handler New business message handler
|
||||||
|
*/
|
||||||
|
on(name: 'new_business_message', handler: (upd: BusinessMessage) => void): this
|
||||||
|
/**
|
||||||
|
* Register an edit business message handler
|
||||||
|
*
|
||||||
|
* @param name Event name
|
||||||
|
* @param handler Edit business message handler
|
||||||
|
*/
|
||||||
|
on(name: 'edit_business_message', handler: (upd: BusinessMessage) => void): this
|
||||||
|
/**
|
||||||
|
* Register a business message group handler
|
||||||
|
*
|
||||||
|
* @param name Event name
|
||||||
|
* @param handler Business message group handler
|
||||||
|
*/
|
||||||
|
on(name: 'business_message_group', handler: (upd: BusinessMessage[]) => void): this
|
||||||
|
/**
|
||||||
|
* Register a delete business message handler
|
||||||
|
*
|
||||||
|
* @param name Event name
|
||||||
|
* @param handler Delete business message handler
|
||||||
|
*/
|
||||||
|
on(name: 'delete_business_message', handler: (upd: DeleteBusinessMessageUpdate) => void): this
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
on(name: string, handler: (...args: any[]) => void): this
|
on(name: string, handler: (...args: any[]) => void): this
|
||||||
|
@ -1562,7 +1616,7 @@ export interface TelegramClient extends ITelegramClient {
|
||||||
* In case you are trying to get info about private chat that you haven't joined.
|
* In case you are trying to get info about private chat that you haven't joined.
|
||||||
* Use {@link getChatPreview} instead.
|
* Use {@link getChatPreview} instead.
|
||||||
*/
|
*/
|
||||||
getFullChat(chatId: InputPeerLike): Promise<Chat>
|
getFullChat(chatId: InputPeerLike): Promise<FullChat>
|
||||||
/**
|
/**
|
||||||
* Get nearby chats
|
* Get nearby chats
|
||||||
*
|
*
|
||||||
|
@ -2324,6 +2378,7 @@ export interface TelegramClient extends ITelegramClient {
|
||||||
params?: {
|
params?: {
|
||||||
progressCallback?: (uploaded: number, total: number) => void
|
progressCallback?: (uploaded: number, total: number) => void
|
||||||
uploadPeer?: tl.TypeInputPeer
|
uploadPeer?: tl.TypeInputPeer
|
||||||
|
businessConnectionId?: string
|
||||||
},
|
},
|
||||||
uploadMedia?: boolean,
|
uploadMedia?: boolean,
|
||||||
): Promise<tl.TypeInputMedia>
|
): Promise<tl.TypeInputMedia>
|
||||||
|
@ -3109,6 +3164,8 @@ export interface TelegramClient extends ITelegramClient {
|
||||||
* client render the preview above the caption and not below.
|
* client render the preview above the caption and not below.
|
||||||
*/
|
*/
|
||||||
invertMedia?: boolean
|
invertMedia?: boolean
|
||||||
|
|
||||||
|
businessConnectionId?: string
|
||||||
},
|
},
|
||||||
): Promise<Message>
|
): Promise<Message>
|
||||||
/**
|
/**
|
||||||
|
@ -3143,6 +3200,14 @@ export interface TelegramClient extends ITelegramClient {
|
||||||
messages: Message[]
|
messages: Message[]
|
||||||
},
|
},
|
||||||
): Promise<Message[]>
|
): Promise<Message[]>
|
||||||
|
/**
|
||||||
|
* Get all scheduled messages in chat
|
||||||
|
*
|
||||||
|
* **Available**: 👤 users only
|
||||||
|
*
|
||||||
|
* @param chatId Chat's marked ID, its username, phone or `"me"` or `"self"`
|
||||||
|
*/
|
||||||
|
getAllScheduledMessages(chatId: InputPeerLike): Promise<Message[]>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the message containing the button being clicked
|
* Get the message containing the button being clicked
|
||||||
|
@ -3583,6 +3648,11 @@ export interface TelegramClient extends ITelegramClient {
|
||||||
* Only return messages older than this date
|
* Only return messages older than this date
|
||||||
*/
|
*/
|
||||||
maxDate?: Date | number
|
maxDate?: Date | number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to only search across broadcast channels
|
||||||
|
*/
|
||||||
|
onlyChannels?: boolean
|
||||||
}): Promise<ArrayPaginated<Message, SearchGlobalOffset>>
|
}): Promise<ArrayPaginated<Message, SearchGlobalOffset>>
|
||||||
/**
|
/**
|
||||||
* Search for messages inside a specific chat
|
* Search for messages inside a specific chat
|
||||||
|
@ -3990,6 +4060,11 @@ export interface TelegramClient extends ITelegramClient {
|
||||||
*/
|
*/
|
||||||
progress?: number
|
progress?: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unique identifier of the business connection on behalf of which the action will be sent
|
||||||
|
*/
|
||||||
|
businessConnectionId?: string
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For comment threads, ID of the thread (i.e. top message)
|
* For comment threads, ID of the thread (i.e. top message)
|
||||||
*/
|
*/
|
||||||
|
@ -4062,6 +4137,13 @@ export interface TelegramClient extends ITelegramClient {
|
||||||
* @param messageId Message ID
|
* @param messageId Message ID
|
||||||
*/
|
*/
|
||||||
unpinMessage(params: InputMessageId): Promise<void>
|
unpinMessage(params: InputMessageId): Promise<void>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get information about a fragment collectible
|
||||||
|
* **Available**: 👤 users only
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
getCollectibleInfo(kind: 'phone' | 'username', item: string): Promise<CollectibleInfo>
|
||||||
/**
|
/**
|
||||||
* Create a new takeout session
|
* Create a new takeout session
|
||||||
*
|
*
|
||||||
|
@ -4160,6 +4242,47 @@ export interface TelegramClient extends ITelegramClient {
|
||||||
*/
|
*/
|
||||||
canApplyBoost(): Promise<CanApplyBoostResult>
|
canApplyBoost(): Promise<CanApplyBoostResult>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new business chat link
|
||||||
|
*
|
||||||
|
* **Available**: 👤 users only
|
||||||
|
*
|
||||||
|
* @param text Text to be inserted into the message input
|
||||||
|
*/
|
||||||
|
createBusinessChatLink(
|
||||||
|
text: InputText,
|
||||||
|
params?: {
|
||||||
|
/** Custom title for the link */
|
||||||
|
title?: string
|
||||||
|
},
|
||||||
|
): Promise<BusinessChatLink>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edit an existing business chat link
|
||||||
|
*
|
||||||
|
* **Available**: 👤 users only
|
||||||
|
*
|
||||||
|
* @param link The link to edit
|
||||||
|
*/
|
||||||
|
editBusinessChatLink(
|
||||||
|
link: string | BusinessChatLink,
|
||||||
|
params: {
|
||||||
|
/** Text to be inserted in the message input */
|
||||||
|
text: InputText
|
||||||
|
/** Custom title for the link */
|
||||||
|
title?: string
|
||||||
|
},
|
||||||
|
): Promise<BusinessChatLink>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a business chat link
|
||||||
|
*
|
||||||
|
* **Available**: 👤 users only
|
||||||
|
*
|
||||||
|
* @param link The link to delete
|
||||||
|
*/
|
||||||
|
deleteBusinessChatLink(link: string | BusinessChatLink): Promise<void>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get information about boosts in a channel
|
* Get information about boosts in a channel
|
||||||
*
|
*
|
||||||
|
@ -4189,6 +4312,22 @@ export interface TelegramClient extends ITelegramClient {
|
||||||
limit?: number
|
limit?: number
|
||||||
},
|
},
|
||||||
): Promise<ArrayPaginated<Boost, string>>
|
): Promise<ArrayPaginated<Boost, string>>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current user's business chat links
|
||||||
|
* **Available**: 👤 users only
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
getBusinessChatLinks(): Promise<BusinessChatLink[]>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get information about the connection of the bot with a business account
|
||||||
|
*
|
||||||
|
* **Available**: 🤖 bots only
|
||||||
|
*
|
||||||
|
* @param connectionId ID of the business connection
|
||||||
|
*/
|
||||||
|
getBusinessConnection(connectionId: string): Promise<BusinessConnection>
|
||||||
/**
|
/**
|
||||||
* Get boost slots information of the current user.
|
* Get boost slots information of the current user.
|
||||||
*
|
*
|
||||||
|
@ -4226,11 +4365,61 @@ export interface TelegramClient extends ITelegramClient {
|
||||||
chunkSize?: number
|
chunkSize?: number
|
||||||
},
|
},
|
||||||
): AsyncIterableIterator<Boost>
|
): AsyncIterableIterator<Boost>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set current user's business introduction.
|
||||||
|
*
|
||||||
|
* **Available**: 👤 users only
|
||||||
|
*
|
||||||
|
* @param intro Introduction parameters, or `null` to remove
|
||||||
|
*/
|
||||||
|
setBusinessIntro(
|
||||||
|
intro: {
|
||||||
|
/**
|
||||||
|
* Title of the introduction
|
||||||
|
*/
|
||||||
|
title?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description of the introduction
|
||||||
|
*/
|
||||||
|
description?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sticker to show beneath the introduction
|
||||||
|
*/
|
||||||
|
sticker?: InputMediaSticker | InputFileLike | tl.TypeInputDocument
|
||||||
|
} | null,
|
||||||
|
): Promise<void>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set current user's business work hours.
|
||||||
|
* **Available**: 👤 users only
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
setBusinessWorkHours(
|
||||||
|
params:
|
||||||
|
| ({
|
||||||
|
/** Timezone in which the hours are defined */
|
||||||
|
timezone: string
|
||||||
|
} & (
|
||||||
|
| {
|
||||||
|
/**
|
||||||
|
* Business work intervals, per-day (like available in {@link BusinessWorkHours.days})
|
||||||
|
*/
|
||||||
|
hours: ReadonlyArray<BusinessWorkHoursDay>
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
/** Business work intervals, raw intervals */
|
||||||
|
intervals: tl.TypeBusinessWeeklyOpen[]
|
||||||
|
}
|
||||||
|
))
|
||||||
|
| null,
|
||||||
|
): Promise<void>
|
||||||
/**
|
/**
|
||||||
* Add a sticker to a sticker set.
|
* Add a sticker to a sticker set.
|
||||||
*
|
*
|
||||||
* Only for bots, and the sticker set must
|
* For bots the sticker set must have been created by this bot.
|
||||||
* have been created by this bot.
|
|
||||||
*
|
*
|
||||||
* **Available**: ✅ both users and bots
|
* **Available**: ✅ both users and bots
|
||||||
*
|
*
|
||||||
|
@ -4255,9 +4444,6 @@ export interface TelegramClient extends ITelegramClient {
|
||||||
/**
|
/**
|
||||||
* Create a new sticker set.
|
* Create a new sticker set.
|
||||||
*
|
*
|
||||||
* This is the only sticker-related method that
|
|
||||||
* users can use (they allowed it with the "import stickers" update)
|
|
||||||
*
|
|
||||||
* **Available**: ✅ both users and bots
|
* **Available**: ✅ both users and bots
|
||||||
*
|
*
|
||||||
* @param params
|
* @param params
|
||||||
|
@ -4338,8 +4524,7 @@ export interface TelegramClient extends ITelegramClient {
|
||||||
/**
|
/**
|
||||||
* Delete a sticker from a sticker set
|
* Delete a sticker from a sticker set
|
||||||
*
|
*
|
||||||
* Only for bots, and the sticker set must
|
* For bots the sticker set must have been created by this bot.
|
||||||
* have been created by this bot.
|
|
||||||
*
|
*
|
||||||
* **Available**: ✅ both users and bots
|
* **Available**: ✅ both users and bots
|
||||||
*
|
*
|
||||||
|
@ -4370,26 +4555,36 @@ export interface TelegramClient extends ITelegramClient {
|
||||||
*
|
*
|
||||||
* > **Note**: This method returns *brief* meta information about
|
* > **Note**: This method returns *brief* meta information about
|
||||||
* > the packs, that does not include the stickers themselves.
|
* > the packs, that does not include the stickers themselves.
|
||||||
* > Use {@link StickerSet.getFull} or {@link getStickerSet}
|
* > Use {@link getStickerSet} to get a stickerset that will include the stickers
|
||||||
* > to get a stickerset that will include the stickers
|
|
||||||
* **Available**: 👤 users only
|
* **Available**: 👤 users only
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
getInstalledStickers(): Promise<StickerSet[]>
|
getInstalledStickers(): Promise<StickerSet[]>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a sticker pack and stickers inside of it.
|
* Get the list of sticker sets that were created by the current user
|
||||||
|
* **Available**: 👤 users only
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
getMyStickerSets(params?: {
|
||||||
|
/** Offset for pagination */
|
||||||
|
offset?: Long
|
||||||
|
/** Limit for pagination */
|
||||||
|
limit?: number
|
||||||
|
}): Promise<ArrayPaginated<StickerSet, Long>>
|
||||||
|
/**
|
||||||
|
* Get a sticker set and stickers inside of it.
|
||||||
*
|
*
|
||||||
* **Available**: ✅ both users and bots
|
* **Available**: ✅ both users and bots
|
||||||
*
|
*
|
||||||
* @param setId Sticker pack short name, dice emoji, `"emoji"` for animated emojis or input ID
|
* @param setId Sticker set identifier
|
||||||
*/
|
*/
|
||||||
getStickerSet(setId: InputStickerSet): Promise<StickerSet>
|
getStickerSet(setId: InputStickerSet): Promise<StickerSet>
|
||||||
/**
|
/**
|
||||||
* Move a sticker in a sticker set
|
* Move a sticker in a sticker set
|
||||||
* to another position
|
* to another position
|
||||||
*
|
*
|
||||||
* Only for bots, and the sticker set must
|
* For bots the sticker set must have been created by this bot.
|
||||||
* have been created by this bot.
|
|
||||||
*
|
*
|
||||||
* **Available**: ✅ both users and bots
|
* **Available**: ✅ both users and bots
|
||||||
*
|
*
|
||||||
|
@ -4397,12 +4592,39 @@ export interface TelegramClient extends ITelegramClient {
|
||||||
* TDLib and Bot API compatible File ID, or a
|
* TDLib and Bot API compatible File ID, or a
|
||||||
* TL object representing a sticker to be removed
|
* TL object representing a sticker to be removed
|
||||||
* @param position New sticker position (starting from 0)
|
* @param position New sticker position (starting from 0)
|
||||||
* @returns Modfiied sticker set
|
* @returns Modified sticker set
|
||||||
*/
|
*/
|
||||||
moveStickerInSet(
|
moveStickerInSet(
|
||||||
sticker: string | tdFileId.RawFullRemoteFileLocation | tl.TypeInputDocument,
|
sticker: string | tdFileId.RawFullRemoteFileLocation | tl.TypeInputDocument,
|
||||||
position: number,
|
position: number,
|
||||||
): Promise<StickerSet>
|
): Promise<StickerSet>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace a sticker in a sticker set with another sticker
|
||||||
|
*
|
||||||
|
* For bots the sticker set must have been created by this bot.
|
||||||
|
*
|
||||||
|
* **Available**: ✅ both users and bots
|
||||||
|
*
|
||||||
|
* @param sticker
|
||||||
|
* TDLib and Bot API compatible File ID, or a
|
||||||
|
* TL object representing a sticker to be removed
|
||||||
|
* @param newSticker New sticker to replace the old one with
|
||||||
|
* @returns Modfiied sticker set
|
||||||
|
*/
|
||||||
|
replaceStickerInSet(
|
||||||
|
sticker: string | tdFileId.RawFullRemoteFileLocation | tl.TypeInputDocument,
|
||||||
|
newSticker: InputStickerSetItem,
|
||||||
|
params?: {
|
||||||
|
/**
|
||||||
|
* Upload progress callback
|
||||||
|
*
|
||||||
|
* @param uploaded Number of bytes uploaded
|
||||||
|
* @param total Total file size
|
||||||
|
*/
|
||||||
|
progressCallback?: (uploaded: number, total: number) => void
|
||||||
|
},
|
||||||
|
): Promise<StickerSet>
|
||||||
/**
|
/**
|
||||||
* Set group sticker set for a supergroup
|
* Set group sticker set for a supergroup
|
||||||
*
|
*
|
||||||
|
@ -5061,6 +5283,22 @@ export interface TelegramClient extends ITelegramClient {
|
||||||
* @param period New TTL period, in seconds (or 0 to disable)
|
* @param period New TTL period, in seconds (or 0 to disable)
|
||||||
*/
|
*/
|
||||||
setGlobalTtl(period: number): Promise<void>
|
setGlobalTtl(period: number): Promise<void>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set or remove current user's birthday.
|
||||||
|
* **Available**: 👤 users only
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
setMyBirthday(
|
||||||
|
birthday: {
|
||||||
|
/** Birthday day */
|
||||||
|
day: number
|
||||||
|
/** Birthday month */
|
||||||
|
month: number
|
||||||
|
/** Birthday year (optional) */
|
||||||
|
year?: number
|
||||||
|
} | null,
|
||||||
|
): Promise<void>
|
||||||
/**
|
/**
|
||||||
* Set an emoji status for the current user
|
* Set an emoji status for the current user
|
||||||
*
|
*
|
||||||
|
@ -5573,6 +5811,9 @@ TelegramClient.prototype.forwardMessagesById = function (...args) {
|
||||||
TelegramClient.prototype.forwardMessages = function (...args) {
|
TelegramClient.prototype.forwardMessages = function (...args) {
|
||||||
return forwardMessages(this._client, ...args)
|
return forwardMessages(this._client, ...args)
|
||||||
}
|
}
|
||||||
|
TelegramClient.prototype.getAllScheduledMessages = function (...args) {
|
||||||
|
return getAllScheduledMessages(this._client, ...args)
|
||||||
|
}
|
||||||
TelegramClient.prototype.getCallbackQueryMessage = function (...args) {
|
TelegramClient.prototype.getCallbackQueryMessage = function (...args) {
|
||||||
return getCallbackQueryMessage(this._client, ...args)
|
return getCallbackQueryMessage(this._client, ...args)
|
||||||
}
|
}
|
||||||
|
@ -5711,6 +5952,9 @@ TelegramClient.prototype.unpinAllMessages = function (...args) {
|
||||||
TelegramClient.prototype.unpinMessage = function (...args) {
|
TelegramClient.prototype.unpinMessage = function (...args) {
|
||||||
return unpinMessage(this._client, ...args)
|
return unpinMessage(this._client, ...args)
|
||||||
}
|
}
|
||||||
|
TelegramClient.prototype.getCollectibleInfo = function (...args) {
|
||||||
|
return getCollectibleInfo(this._client, ...args)
|
||||||
|
}
|
||||||
TelegramClient.prototype.initTakeoutSession = function (...args) {
|
TelegramClient.prototype.initTakeoutSession = function (...args) {
|
||||||
return initTakeoutSession(this._client, ...args)
|
return initTakeoutSession(this._client, ...args)
|
||||||
}
|
}
|
||||||
|
@ -5741,18 +5985,39 @@ TelegramClient.prototype.applyBoost = function (...args) {
|
||||||
TelegramClient.prototype.canApplyBoost = function (...args) {
|
TelegramClient.prototype.canApplyBoost = function (...args) {
|
||||||
return canApplyBoost(this._client, ...args)
|
return canApplyBoost(this._client, ...args)
|
||||||
}
|
}
|
||||||
|
TelegramClient.prototype.createBusinessChatLink = function (...args) {
|
||||||
|
return createBusinessChatLink(this._client, ...args)
|
||||||
|
}
|
||||||
|
TelegramClient.prototype.editBusinessChatLink = function (...args) {
|
||||||
|
return editBusinessChatLink(this._client, ...args)
|
||||||
|
}
|
||||||
|
TelegramClient.prototype.deleteBusinessChatLink = function (...args) {
|
||||||
|
return deleteBusinessChatLink(this._client, ...args)
|
||||||
|
}
|
||||||
TelegramClient.prototype.getBoostStats = function (...args) {
|
TelegramClient.prototype.getBoostStats = function (...args) {
|
||||||
return getBoostStats(this._client, ...args)
|
return getBoostStats(this._client, ...args)
|
||||||
}
|
}
|
||||||
TelegramClient.prototype.getBoosts = function (...args) {
|
TelegramClient.prototype.getBoosts = function (...args) {
|
||||||
return getBoosts(this._client, ...args)
|
return getBoosts(this._client, ...args)
|
||||||
}
|
}
|
||||||
|
TelegramClient.prototype.getBusinessChatLinks = function (...args) {
|
||||||
|
return getBusinessChatLinks(this._client, ...args)
|
||||||
|
}
|
||||||
|
TelegramClient.prototype.getBusinessConnection = function (...args) {
|
||||||
|
return getBusinessConnection(this._client, ...args)
|
||||||
|
}
|
||||||
TelegramClient.prototype.getMyBoostSlots = function (...args) {
|
TelegramClient.prototype.getMyBoostSlots = function (...args) {
|
||||||
return getMyBoostSlots(this._client, ...args)
|
return getMyBoostSlots(this._client, ...args)
|
||||||
}
|
}
|
||||||
TelegramClient.prototype.iterBoosters = function (...args) {
|
TelegramClient.prototype.iterBoosters = function (...args) {
|
||||||
return iterBoosters(this._client, ...args)
|
return iterBoosters(this._client, ...args)
|
||||||
}
|
}
|
||||||
|
TelegramClient.prototype.setBusinessIntro = function (...args) {
|
||||||
|
return setBusinessIntro(this._client, ...args)
|
||||||
|
}
|
||||||
|
TelegramClient.prototype.setBusinessWorkHours = function (...args) {
|
||||||
|
return setBusinessWorkHours(this._client, ...args)
|
||||||
|
}
|
||||||
TelegramClient.prototype.addStickerToSet = function (...args) {
|
TelegramClient.prototype.addStickerToSet = function (...args) {
|
||||||
return addStickerToSet(this._client, ...args)
|
return addStickerToSet(this._client, ...args)
|
||||||
}
|
}
|
||||||
|
@ -5771,12 +6036,18 @@ TelegramClient.prototype.getCustomEmojisFromMessages = function (...args) {
|
||||||
TelegramClient.prototype.getInstalledStickers = function (...args) {
|
TelegramClient.prototype.getInstalledStickers = function (...args) {
|
||||||
return getInstalledStickers(this._client, ...args)
|
return getInstalledStickers(this._client, ...args)
|
||||||
}
|
}
|
||||||
|
TelegramClient.prototype.getMyStickerSets = function (...args) {
|
||||||
|
return getMyStickerSets(this._client, ...args)
|
||||||
|
}
|
||||||
TelegramClient.prototype.getStickerSet = function (...args) {
|
TelegramClient.prototype.getStickerSet = function (...args) {
|
||||||
return getStickerSet(this._client, ...args)
|
return getStickerSet(this._client, ...args)
|
||||||
}
|
}
|
||||||
TelegramClient.prototype.moveStickerInSet = function (...args) {
|
TelegramClient.prototype.moveStickerInSet = function (...args) {
|
||||||
return moveStickerInSet(this._client, ...args)
|
return moveStickerInSet(this._client, ...args)
|
||||||
}
|
}
|
||||||
|
TelegramClient.prototype.replaceStickerInSet = function (...args) {
|
||||||
|
return replaceStickerInSet(this._client, ...args)
|
||||||
|
}
|
||||||
TelegramClient.prototype.setChatStickerSet = function (...args) {
|
TelegramClient.prototype.setChatStickerSet = function (...args) {
|
||||||
return setChatStickerSet(this._client, ...args)
|
return setChatStickerSet(this._client, ...args)
|
||||||
}
|
}
|
||||||
|
@ -5899,6 +6170,9 @@ TelegramClient.prototype.resolveChannel = function (...args) {
|
||||||
TelegramClient.prototype.setGlobalTtl = function (...args) {
|
TelegramClient.prototype.setGlobalTtl = function (...args) {
|
||||||
return setGlobalTtl(this._client, ...args)
|
return setGlobalTtl(this._client, ...args)
|
||||||
}
|
}
|
||||||
|
TelegramClient.prototype.setMyBirthday = function (...args) {
|
||||||
|
return setMyBirthday(this._client, ...args)
|
||||||
|
}
|
||||||
TelegramClient.prototype.setMyEmojiStatus = function (...args) {
|
TelegramClient.prototype.setMyEmojiStatus = function (...args) {
|
||||||
return setMyEmojiStatus(this._client, ...args)
|
return setMyEmojiStatus(this._client, ...args)
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,6 +128,7 @@ export { editMessage } from './methods/messages/edit-message.js'
|
||||||
export type { ForwardMessageOptions } from './methods/messages/forward-messages.js'
|
export type { ForwardMessageOptions } from './methods/messages/forward-messages.js'
|
||||||
export { forwardMessagesById } from './methods/messages/forward-messages.js'
|
export { forwardMessagesById } from './methods/messages/forward-messages.js'
|
||||||
export { forwardMessages } from './methods/messages/forward-messages.js'
|
export { forwardMessages } from './methods/messages/forward-messages.js'
|
||||||
|
export { getAllScheduledMessages } from './methods/messages/get-all-scheduled-messages.js'
|
||||||
export { getCallbackQueryMessage } from './methods/messages/get-callback-query-message.js'
|
export { getCallbackQueryMessage } from './methods/messages/get-callback-query-message.js'
|
||||||
export { getDiscussionMessage } from './methods/messages/get-discussion-message.js'
|
export { getDiscussionMessage } from './methods/messages/get-discussion-message.js'
|
||||||
export type { GetHistoryOffset } from './methods/messages/get-history.js'
|
export type { GetHistoryOffset } from './methods/messages/get-history.js'
|
||||||
|
@ -181,6 +182,7 @@ export { translateMessage } from './methods/messages/translate-message.js'
|
||||||
export { translateText } from './methods/messages/translate-text.js'
|
export { translateText } from './methods/messages/translate-text.js'
|
||||||
export { unpinAllMessages } from './methods/messages/unpin-all-messages.js'
|
export { unpinAllMessages } from './methods/messages/unpin-all-messages.js'
|
||||||
export { unpinMessage } from './methods/messages/unpin-message.js'
|
export { unpinMessage } from './methods/messages/unpin-message.js'
|
||||||
|
export { getCollectibleInfo } from './methods/misc/get-collectible-info.js'
|
||||||
export { initTakeoutSession } from './methods/misc/init-takeout-session.js'
|
export { initTakeoutSession } from './methods/misc/init-takeout-session.js'
|
||||||
export { _normalizePrivacyRules } from './methods/misc/normalize-privacy-rules.js'
|
export { _normalizePrivacyRules } from './methods/misc/normalize-privacy-rules.js'
|
||||||
export { changeCloudPassword } from './methods/password/change-cloud-password.js'
|
export { changeCloudPassword } from './methods/password/change-cloud-password.js'
|
||||||
|
@ -192,18 +194,27 @@ export { removeCloudPassword } from './methods/password/remove-cloud-password.js
|
||||||
export { applyBoost } from './methods/premium/apply-boost.js'
|
export { applyBoost } from './methods/premium/apply-boost.js'
|
||||||
export type { CanApplyBoostResult } from './methods/premium/can-apply-boost.js'
|
export type { CanApplyBoostResult } from './methods/premium/can-apply-boost.js'
|
||||||
export { canApplyBoost } from './methods/premium/can-apply-boost.js'
|
export { canApplyBoost } from './methods/premium/can-apply-boost.js'
|
||||||
|
export { createBusinessChatLink } from './methods/premium/create-business-chat-link.js'
|
||||||
|
export { editBusinessChatLink } from './methods/premium/edit-business-chat-link.js'
|
||||||
|
export { deleteBusinessChatLink } from './methods/premium/edit-business-chat-link.js'
|
||||||
export { getBoostStats } from './methods/premium/get-boost-stats.js'
|
export { getBoostStats } from './methods/premium/get-boost-stats.js'
|
||||||
export { getBoosts } from './methods/premium/get-boosts.js'
|
export { getBoosts } from './methods/premium/get-boosts.js'
|
||||||
|
export { getBusinessChatLinks } from './methods/premium/get-business-chat-links.js'
|
||||||
|
export { getBusinessConnection } from './methods/premium/get-business-connection.js'
|
||||||
export { getMyBoostSlots } from './methods/premium/get-my-boost-slots.js'
|
export { getMyBoostSlots } from './methods/premium/get-my-boost-slots.js'
|
||||||
export { iterBoosters } from './methods/premium/iter-boosters.js'
|
export { iterBoosters } from './methods/premium/iter-boosters.js'
|
||||||
|
export { setBusinessIntro } from './methods/premium/set-business-intro.js'
|
||||||
|
export { setBusinessWorkHours } from './methods/premium/set-business-work-hours.js'
|
||||||
export { addStickerToSet } from './methods/stickers/add-sticker-to-set.js'
|
export { addStickerToSet } from './methods/stickers/add-sticker-to-set.js'
|
||||||
export { createStickerSet } from './methods/stickers/create-sticker-set.js'
|
export { createStickerSet } from './methods/stickers/create-sticker-set.js'
|
||||||
export { deleteStickerFromSet } from './methods/stickers/delete-sticker-from-set.js'
|
export { deleteStickerFromSet } from './methods/stickers/delete-sticker-from-set.js'
|
||||||
export { getCustomEmojis } from './methods/stickers/get-custom-emojis.js'
|
export { getCustomEmojis } from './methods/stickers/get-custom-emojis.js'
|
||||||
export { getCustomEmojisFromMessages } from './methods/stickers/get-custom-emojis.js'
|
export { getCustomEmojisFromMessages } from './methods/stickers/get-custom-emojis.js'
|
||||||
export { getInstalledStickers } from './methods/stickers/get-installed-stickers.js'
|
export { getInstalledStickers } from './methods/stickers/get-installed-stickers.js'
|
||||||
|
export { getMyStickerSets } from './methods/stickers/get-my-sticker-sets.js'
|
||||||
export { getStickerSet } from './methods/stickers/get-sticker-set.js'
|
export { getStickerSet } from './methods/stickers/get-sticker-set.js'
|
||||||
export { moveStickerInSet } from './methods/stickers/move-sticker-in-set.js'
|
export { moveStickerInSet } from './methods/stickers/move-sticker-in-set.js'
|
||||||
|
export { replaceStickerInSet } from './methods/stickers/replace-sticker-in-set.js'
|
||||||
export { setChatStickerSet } from './methods/stickers/set-chat-sticker-set.js'
|
export { setChatStickerSet } from './methods/stickers/set-chat-sticker-set.js'
|
||||||
export { setStickerSetThumb } from './methods/stickers/set-sticker-set-thumb.js'
|
export { setStickerSetThumb } from './methods/stickers/set-sticker-set-thumb.js'
|
||||||
export type { CanSendStoryResult } from './methods/stories/can-send-story.js'
|
export type { CanSendStoryResult } from './methods/stories/can-send-story.js'
|
||||||
|
@ -245,6 +256,7 @@ export { resolveUser } from './methods/users/resolve-peer.js'
|
||||||
export { resolveChannel } from './methods/users/resolve-peer.js'
|
export { resolveChannel } from './methods/users/resolve-peer.js'
|
||||||
export { resolvePeerMany } from './methods/users/resolve-peer-many.js'
|
export { resolvePeerMany } from './methods/users/resolve-peer-many.js'
|
||||||
export { setGlobalTtl } from './methods/users/set-global-ttl.js'
|
export { setGlobalTtl } from './methods/users/set-global-ttl.js'
|
||||||
|
export { setMyBirthday } from './methods/users/set-my-birthday.js'
|
||||||
export { setMyEmojiStatus } from './methods/users/set-my-emoji-status.js'
|
export { setMyEmojiStatus } from './methods/users/set-my-emoji-status.js'
|
||||||
export { setMyProfilePhoto } from './methods/users/set-my-profile-photo.js'
|
export { setMyProfilePhoto } from './methods/users/set-my-profile-photo.js'
|
||||||
export { setMyUsername } from './methods/users/set-my-username.js'
|
export { setMyUsername } from './methods/users/set-my-username.js'
|
||||||
|
|
|
@ -26,6 +26,10 @@ import {
|
||||||
BotReactionCountUpdate,
|
BotReactionCountUpdate,
|
||||||
BotReactionUpdate,
|
BotReactionUpdate,
|
||||||
BotStoppedUpdate,
|
BotStoppedUpdate,
|
||||||
|
BusinessChatLink,
|
||||||
|
BusinessConnection,
|
||||||
|
BusinessMessage,
|
||||||
|
BusinessWorkHoursDay,
|
||||||
CallbackQuery,
|
CallbackQuery,
|
||||||
Chat,
|
Chat,
|
||||||
ChatEvent,
|
ChatEvent,
|
||||||
|
@ -36,12 +40,15 @@ import {
|
||||||
ChatMemberUpdate,
|
ChatMemberUpdate,
|
||||||
ChatPreview,
|
ChatPreview,
|
||||||
ChosenInlineResult,
|
ChosenInlineResult,
|
||||||
|
CollectibleInfo,
|
||||||
|
DeleteBusinessMessageUpdate,
|
||||||
DeleteMessageUpdate,
|
DeleteMessageUpdate,
|
||||||
DeleteStoryUpdate,
|
DeleteStoryUpdate,
|
||||||
Dialog,
|
Dialog,
|
||||||
FileDownloadLocation,
|
FileDownloadLocation,
|
||||||
FileDownloadParameters,
|
FileDownloadParameters,
|
||||||
ForumTopic,
|
ForumTopic,
|
||||||
|
FullChat,
|
||||||
GameHighScore,
|
GameHighScore,
|
||||||
HistoryReadUpdate,
|
HistoryReadUpdate,
|
||||||
InlineCallbackQuery,
|
InlineCallbackQuery,
|
||||||
|
@ -51,6 +58,7 @@ import {
|
||||||
InputFileLike,
|
InputFileLike,
|
||||||
InputInlineResult,
|
InputInlineResult,
|
||||||
InputMediaLike,
|
InputMediaLike,
|
||||||
|
InputMediaSticker,
|
||||||
InputMessageId,
|
InputMessageId,
|
||||||
InputPeerLike,
|
InputPeerLike,
|
||||||
InputPrivacyRule,
|
InputPrivacyRule,
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
import { MtArgumentError } from '../../../types/errors.js'
|
import { MtArgumentError } from '../../../types/errors.js'
|
||||||
import { ITelegramClient } from '../../client.types.js'
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { Chat, InputPeerLike } from '../../types/index.js'
|
import { FullChat, InputPeerLike } from '../../types/index.js'
|
||||||
import {
|
import {
|
||||||
INVITE_LINK_REGEX,
|
INVITE_LINK_REGEX,
|
||||||
isInputPeerChannel,
|
isInputPeerChannel,
|
||||||
|
@ -22,7 +22,7 @@ import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
* In case you are trying to get info about private chat that you haven't joined.
|
* In case you are trying to get info about private chat that you haven't joined.
|
||||||
* Use {@link getChatPreview} instead.
|
* Use {@link getChatPreview} instead.
|
||||||
*/
|
*/
|
||||||
export async function getFullChat(client: ITelegramClient, chatId: InputPeerLike): Promise<Chat> {
|
export async function getFullChat(client: ITelegramClient, chatId: InputPeerLike): Promise<FullChat> {
|
||||||
if (typeof chatId === 'string') {
|
if (typeof chatId === 'string') {
|
||||||
const m = chatId.match(INVITE_LINK_REGEX)
|
const m = chatId.match(INVITE_LINK_REGEX)
|
||||||
|
|
||||||
|
@ -61,5 +61,5 @@ export async function getFullChat(client: ITelegramClient, chatId: InputPeerLike
|
||||||
})
|
})
|
||||||
} else throw new Error('should not happen')
|
} else throw new Error('should not happen')
|
||||||
|
|
||||||
return Chat._parseFull(res)
|
return FullChat._parse(res)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { ITelegramClient } from '../../client.types.js'
|
||||||
import { isUploadedFile } from '../../types/files/uploaded-file.js'
|
import { isUploadedFile } from '../../types/files/uploaded-file.js'
|
||||||
import { UploadFileLike } from '../../types/files/utils.js'
|
import { UploadFileLike } from '../../types/files/utils.js'
|
||||||
import { InputMediaLike } from '../../types/media/input-media/types.js'
|
import { InputMediaLike } from '../../types/media/input-media/types.js'
|
||||||
|
import { inputTextToTl } from '../../types/misc/entities.js'
|
||||||
import { fileIdToInputDocument, fileIdToInputPhoto } from '../../utils/convert-file-id.js'
|
import { fileIdToInputDocument, fileIdToInputPhoto } from '../../utils/convert-file-id.js'
|
||||||
import { normalizeDate } from '../../utils/misc-utils.js'
|
import { normalizeDate } from '../../utils/misc-utils.js'
|
||||||
import { encodeWaveform } from '../../utils/voice-utils.js'
|
import { encodeWaveform } from '../../utils/voice-utils.js'
|
||||||
|
@ -27,6 +28,7 @@ export async function _normalizeInputMedia(
|
||||||
params: {
|
params: {
|
||||||
progressCallback?: (uploaded: number, total: number) => void
|
progressCallback?: (uploaded: number, total: number) => void
|
||||||
uploadPeer?: tl.TypeInputPeer
|
uploadPeer?: tl.TypeInputPeer
|
||||||
|
businessConnectionId?: string
|
||||||
} = {},
|
} = {},
|
||||||
uploadMedia = false,
|
uploadMedia = false,
|
||||||
): Promise<tl.TypeInputMedia> {
|
): Promise<tl.TypeInputMedia> {
|
||||||
|
@ -151,16 +153,14 @@ export async function _normalizeInputMedia(
|
||||||
|
|
||||||
if (media.type === 'poll' || media.type === 'quiz') {
|
if (media.type === 'poll' || media.type === 'quiz') {
|
||||||
const answers: tl.TypePollAnswer[] = media.answers.map((ans, idx) => {
|
const answers: tl.TypePollAnswer[] = media.answers.map((ans, idx) => {
|
||||||
if (typeof ans === 'string') {
|
if (typeof ans === 'object' && tl.isAnyPollAnswer(ans)) return ans
|
||||||
|
|
||||||
return {
|
return {
|
||||||
_: 'pollAnswer',
|
_: 'pollAnswer',
|
||||||
text: ans,
|
text: inputTextToTl(ans),
|
||||||
// emulate the behaviour of most implementations
|
// emulate the behaviour of most implementations
|
||||||
option: new Uint8Array([48 /* '0' */ + idx]),
|
option: new Uint8Array([48 /* '0' */ + idx]),
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return ans
|
|
||||||
})
|
})
|
||||||
|
|
||||||
let correct: Uint8Array[] | undefined = undefined
|
let correct: Uint8Array[] | undefined = undefined
|
||||||
|
@ -192,7 +192,7 @@ export async function _normalizeInputMedia(
|
||||||
publicVoters: media.public,
|
publicVoters: media.public,
|
||||||
multipleChoice: media.multiple,
|
multipleChoice: media.multiple,
|
||||||
quiz: media.type === 'quiz',
|
quiz: media.type === 'quiz',
|
||||||
question: media.question,
|
question: inputTextToTl(media.question),
|
||||||
answers,
|
answers,
|
||||||
closePeriod: media.closePeriod,
|
closePeriod: media.closePeriod,
|
||||||
closeDate: normalizeDate(media.closeDate),
|
closeDate: normalizeDate(media.closeDate),
|
||||||
|
@ -255,6 +255,7 @@ export async function _normalizeInputMedia(
|
||||||
_: 'messages.uploadMedia',
|
_: 'messages.uploadMedia',
|
||||||
peer: uploadPeer,
|
peer: uploadPeer,
|
||||||
media: inputMedia,
|
media: inputMedia,
|
||||||
|
businessConnectionId: params.businessConnectionId,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (photo) {
|
if (photo) {
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { RpcCallOptions } from '../../../network/network-manager.js'
|
||||||
|
import { LruMap } from '../../../utils/lru-map.js'
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
import { getBusinessConnection } from '../premium/get-business-connection.js'
|
||||||
|
|
||||||
|
// temporary solution
|
||||||
|
// todo – rework once we have either a more generic caching solution
|
||||||
|
const DC_MAP_SYMBOL = Symbol('dcMap')
|
||||||
|
|
||||||
|
const getDcMap = (client: ITelegramClient): LruMap<string, number> => {
|
||||||
|
const client_ = client as typeof client & { [DC_MAP_SYMBOL]?: LruMap<string, number> }
|
||||||
|
|
||||||
|
if (!client_[DC_MAP_SYMBOL]) {
|
||||||
|
client_[DC_MAP_SYMBOL] = new LruMap(50)
|
||||||
|
}
|
||||||
|
|
||||||
|
return client_[DC_MAP_SYMBOL]
|
||||||
|
}
|
||||||
|
|
||||||
|
// @available=both
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export async function _maybeInvokeWithBusinessConnection<T extends tl.RpcMethod>(
|
||||||
|
client: ITelegramClient,
|
||||||
|
businessConnectionId: string | undefined,
|
||||||
|
request: T,
|
||||||
|
params?: RpcCallOptions,
|
||||||
|
): Promise<tl.RpcCallReturn[T['_']]> {
|
||||||
|
if (!businessConnectionId) {
|
||||||
|
return client.call(request, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
const dcMap = getDcMap(client)
|
||||||
|
|
||||||
|
if (!dcMap.has(businessConnectionId)) {
|
||||||
|
const res = await getBusinessConnection(client, businessConnectionId)
|
||||||
|
|
||||||
|
dcMap.set(businessConnectionId, res.dcId)
|
||||||
|
}
|
||||||
|
|
||||||
|
const dcId = dcMap.get(businessConnectionId)!
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||||
|
return client.call(
|
||||||
|
{
|
||||||
|
_: 'invokeWithBusinessConnection',
|
||||||
|
connectionId: businessConnectionId,
|
||||||
|
query: request,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...params,
|
||||||
|
localMigrate: true, // just in case
|
||||||
|
dcId,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
|
@ -35,7 +35,7 @@ export async function closePoll(
|
||||||
_: 'poll',
|
_: 'poll',
|
||||||
id: Long.ZERO,
|
id: Long.ZERO,
|
||||||
closed: true,
|
closed: true,
|
||||||
question: '',
|
question: { _: 'textWithEntities', text: '', entities: [] },
|
||||||
answers: [],
|
answers: [],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -13,6 +13,7 @@ import {
|
||||||
import { _normalizeInputMedia } from '../files/normalize-input-media.js'
|
import { _normalizeInputMedia } from '../files/normalize-input-media.js'
|
||||||
import { _normalizeInputText } from '../misc/normalize-text.js'
|
import { _normalizeInputText } from '../misc/normalize-text.js'
|
||||||
import { resolvePeer } from '../users/resolve-peer.js'
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
import { _maybeInvokeWithBusinessConnection } from './_business-connection.js'
|
||||||
import { _findMessageInUpdate } from './find-in-update.js'
|
import { _findMessageInUpdate } from './find-in-update.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -75,6 +76,8 @@ export async function editMessage(
|
||||||
* client render the preview above the caption and not below.
|
* client render the preview above the caption and not below.
|
||||||
*/
|
*/
|
||||||
invertMedia?: boolean
|
invertMedia?: boolean
|
||||||
|
|
||||||
|
businessConnectionId?: string
|
||||||
},
|
},
|
||||||
): Promise<Message> {
|
): Promise<Message> {
|
||||||
const { chatId, message } = normalizeInputMessageId(params)
|
const { chatId, message } = normalizeInputMessageId(params)
|
||||||
|
@ -96,7 +99,7 @@ export async function editMessage(
|
||||||
[content, entities] = await _normalizeInputText(client, params.text)
|
[content, entities] = await _normalizeInputText(client, params.text)
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await client.call({
|
const res = await _maybeInvokeWithBusinessConnection(client, params.businessConnectionId, {
|
||||||
_: 'messages.editMessage',
|
_: 'messages.editMessage',
|
||||||
id: message,
|
id: message,
|
||||||
peer: await resolvePeer(client, chatId),
|
peer: await resolvePeer(client, chatId),
|
||||||
|
|
|
@ -57,15 +57,27 @@ export function _findMessageInUpdate(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isEdit) {
|
if (isEdit) {
|
||||||
if (!(u._ === 'updateEditMessage' || u._ === 'updateEditChannelMessage')) continue
|
if (
|
||||||
|
!(
|
||||||
|
u._ === 'updateEditMessage' ||
|
||||||
|
u._ === 'updateEditChannelMessage' ||
|
||||||
|
u._ === 'updateBotEditBusinessMessage'
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (
|
if (
|
||||||
!(
|
!(
|
||||||
u._ === 'updateNewMessage' ||
|
u._ === 'updateNewMessage' ||
|
||||||
u._ === 'updateNewChannelMessage' ||
|
u._ === 'updateNewChannelMessage' ||
|
||||||
u._ === 'updateNewScheduledMessage'
|
u._ === 'updateNewScheduledMessage' ||
|
||||||
|
u._ === 'updateQuickReplyMessage' ||
|
||||||
|
u._ === 'updateBotNewBusinessMessage'
|
||||||
)
|
)
|
||||||
) { continue }
|
) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// this *may* break if updateMessageID comes after the message update
|
// this *may* break if updateMessageID comes after the message update
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { InputPeerLike, Message, PeersIndex } from '../../types/index.js'
|
||||||
import { assertIsUpdatesGroup } from '../../updates/utils.js'
|
import { assertIsUpdatesGroup } from '../../updates/utils.js'
|
||||||
import { normalizeDate } from '../../utils/misc-utils.js'
|
import { normalizeDate } from '../../utils/misc-utils.js'
|
||||||
import { resolvePeer } from '../users/resolve-peer.js'
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
import { _normalizeQuickReplyShortcut } from './send-common.js'
|
||||||
|
|
||||||
// @exported
|
// @exported
|
||||||
export interface ForwardMessageOptions {
|
export interface ForwardMessageOptions {
|
||||||
|
@ -56,6 +57,12 @@ export interface ForwardMessageOptions {
|
||||||
*/
|
*/
|
||||||
sendAs?: InputPeerLike
|
sendAs?: InputPeerLike
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If passed, instead of sending the message, it will be saved into the
|
||||||
|
* given quick reply shortcut (either its ID or its shortcut string).
|
||||||
|
*/
|
||||||
|
quickReply?: number | string
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to dispatch the forwarded messages
|
* Whether to dispatch the forwarded messages
|
||||||
* to the client's update handler.
|
* to the client's update handler.
|
||||||
|
@ -105,6 +112,7 @@ export async function forwardMessagesById(
|
||||||
dropMediaCaptions: noCaption,
|
dropMediaCaptions: noCaption,
|
||||||
noforwards: forbidForwards,
|
noforwards: forbidForwards,
|
||||||
sendAs: sendAs ? await resolvePeer(client, sendAs) : undefined,
|
sendAs: sendAs ? await resolvePeer(client, sendAs) : undefined,
|
||||||
|
quickReplyShortcut: _normalizeQuickReplyShortcut(params.quickReply),
|
||||||
})
|
})
|
||||||
|
|
||||||
assertIsUpdatesGroup('messages.forwardMessages', res)
|
assertIsUpdatesGroup('messages.forwardMessages', res)
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
import Long from 'long'
|
||||||
|
|
||||||
|
import { assertTypeIsNot } from '../../../utils/type-assertions.js'
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
import { InputPeerLike, Message, PeersIndex } from '../../types/index.js'
|
||||||
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all scheduled messages in chat
|
||||||
|
*
|
||||||
|
* @param chatId Chat's marked ID, its username, phone or `"me"` or `"self"`
|
||||||
|
*/
|
||||||
|
export async function getAllScheduledMessages(client: ITelegramClient, chatId: InputPeerLike): Promise<Message[]> {
|
||||||
|
const peer = await resolvePeer(client, chatId)
|
||||||
|
|
||||||
|
const res = await client.call({
|
||||||
|
_: 'messages.getScheduledHistory',
|
||||||
|
peer,
|
||||||
|
hash: Long.ZERO,
|
||||||
|
})
|
||||||
|
|
||||||
|
assertTypeIsNot('getScheduledMessages', res, 'messages.messagesNotModified')
|
||||||
|
|
||||||
|
const peers = PeersIndex.from(res)
|
||||||
|
|
||||||
|
const ret = res.messages.map((msg) => {
|
||||||
|
assertTypeIsNot('getScheduledMessages', msg, 'messageEmpty')
|
||||||
|
|
||||||
|
return new Message(msg, peers, true)
|
||||||
|
})
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
|
@ -33,7 +33,7 @@ export async function* iterSearchGlobal(
|
||||||
): AsyncIterableIterator<Message> {
|
): AsyncIterableIterator<Message> {
|
||||||
if (!params) params = {}
|
if (!params) params = {}
|
||||||
|
|
||||||
const { query = '', filter = SearchFilters.Empty, limit = Infinity, chunkSize = 100 } = params
|
const { query = '', filter = SearchFilters.Empty, limit = Infinity, chunkSize = 100, onlyChannels } = params
|
||||||
|
|
||||||
const minDate = normalizeDate(params.minDate) ?? 0
|
const minDate = normalizeDate(params.minDate) ?? 0
|
||||||
const maxDate = normalizeDate(params.maxDate) ?? 0
|
const maxDate = normalizeDate(params.maxDate) ?? 0
|
||||||
|
@ -49,6 +49,7 @@ export async function* iterSearchGlobal(
|
||||||
minDate,
|
minDate,
|
||||||
maxDate,
|
maxDate,
|
||||||
offset,
|
offset,
|
||||||
|
onlyChannels,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!res.length) return
|
if (!res.length) return
|
||||||
|
|
|
@ -63,6 +63,11 @@ export async function searchGlobal(
|
||||||
* Only return messages older than this date
|
* Only return messages older than this date
|
||||||
*/
|
*/
|
||||||
maxDate?: Date | number
|
maxDate?: Date | number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to only search across broadcast channels
|
||||||
|
*/
|
||||||
|
onlyChannels?: boolean
|
||||||
},
|
},
|
||||||
): Promise<ArrayPaginated<Message, SearchGlobalOffset>> {
|
): Promise<ArrayPaginated<Message, SearchGlobalOffset>> {
|
||||||
if (!params) params = {}
|
if (!params) params = {}
|
||||||
|
@ -72,6 +77,7 @@ export async function searchGlobal(
|
||||||
filter = SearchFilters.Empty,
|
filter = SearchFilters.Empty,
|
||||||
limit = 100,
|
limit = 100,
|
||||||
offset: { rate: offsetRate, peer: offsetPeer, id: offsetId } = defaultOffset,
|
offset: { rate: offsetRate, peer: offsetPeer, id: offsetId } = defaultOffset,
|
||||||
|
onlyChannels,
|
||||||
} = params
|
} = params
|
||||||
|
|
||||||
const minDate = normalizeDate(params.minDate) ?? 0
|
const minDate = normalizeDate(params.minDate) ?? 0
|
||||||
|
@ -87,6 +93,7 @@ export async function searchGlobal(
|
||||||
offsetRate,
|
offsetRate,
|
||||||
offsetPeer,
|
offsetPeer,
|
||||||
limit,
|
limit,
|
||||||
|
broadcastsOnly: onlyChannels,
|
||||||
})
|
})
|
||||||
|
|
||||||
assertTypeIsNot('searchGlobal', res, 'messages.messagesNotModified')
|
assertTypeIsNot('searchGlobal', res, 'messages.messagesNotModified')
|
||||||
|
|
|
@ -100,11 +100,45 @@ export interface CommonSendParams {
|
||||||
*/
|
*/
|
||||||
sendAs?: InputPeerLike
|
sendAs?: InputPeerLike
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If passed, instead of sending the message, it will be saved into the
|
||||||
|
* given quick reply shortcut (either its ID or its shortcut string).
|
||||||
|
*/
|
||||||
|
quickReply?: number | string
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to dispatch the returned message
|
* Whether to dispatch the returned message
|
||||||
* to the client's update handler.
|
* to the client's update handler.
|
||||||
*/
|
*/
|
||||||
shouldDispatch?: true
|
shouldDispatch?: true
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unique identifier of the business connection on behalf of which
|
||||||
|
* the message will be sent
|
||||||
|
*/
|
||||||
|
businessConnectionId?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* @noemit
|
||||||
|
*/
|
||||||
|
export function _normalizeQuickReplyShortcut(
|
||||||
|
shortcut: number | string | undefined,
|
||||||
|
): tl.TypeInputQuickReplyShortcut | undefined {
|
||||||
|
if (!shortcut) return undefined
|
||||||
|
|
||||||
|
if (typeof shortcut === 'number') {
|
||||||
|
return {
|
||||||
|
_: 'inputQuickReplyShortcutId',
|
||||||
|
shortcutId: shortcut,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
_: 'inputQuickReplyShortcut',
|
||||||
|
shortcut,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -172,6 +206,7 @@ export async function _processCommonSendParameters(
|
||||||
peer,
|
peer,
|
||||||
replyTo: tlReplyTo,
|
replyTo: tlReplyTo,
|
||||||
scheduleDate,
|
scheduleDate,
|
||||||
|
quickReplyShortcut: _normalizeQuickReplyShortcut(params.quickReply),
|
||||||
chainId: _getPeerChainId(client, peer, 'send'),
|
chainId: _getPeerChainId(client, peer, 'send'),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { assertIsUpdatesGroup } from '../../updates/utils.js'
|
||||||
import { _normalizeInputMedia } from '../files/normalize-input-media.js'
|
import { _normalizeInputMedia } from '../files/normalize-input-media.js'
|
||||||
import { _normalizeInputText } from '../misc/normalize-text.js'
|
import { _normalizeInputText } from '../misc/normalize-text.js'
|
||||||
import { resolvePeer } from '../users/resolve-peer.js'
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
import { _maybeInvokeWithBusinessConnection } from './_business-connection.js'
|
||||||
import { _getDiscussionMessage } from './get-discussion-message.js'
|
import { _getDiscussionMessage } from './get-discussion-message.js'
|
||||||
import { _processCommonSendParameters, CommonSendParams } from './send-common.js'
|
import { _processCommonSendParameters, CommonSendParams } from './send-common.js'
|
||||||
|
|
||||||
|
@ -50,7 +51,11 @@ export async function sendMediaGroup(
|
||||||
): Promise<Message[]> {
|
): Promise<Message[]> {
|
||||||
if (!params) params = {}
|
if (!params) params = {}
|
||||||
|
|
||||||
const { peer, replyTo, scheduleDate, chainId } = await _processCommonSendParameters(client, chatId, params)
|
const { peer, replyTo, scheduleDate, chainId, quickReplyShortcut } = await _processCommonSendParameters(
|
||||||
|
client,
|
||||||
|
chatId,
|
||||||
|
params,
|
||||||
|
)
|
||||||
|
|
||||||
const multiMedia: tl.RawInputSingleMedia[] = []
|
const multiMedia: tl.RawInputSingleMedia[] = []
|
||||||
|
|
||||||
|
@ -73,6 +78,7 @@ export async function sendMediaGroup(
|
||||||
// but otherwise Telegram throws MEDIA_INVALID
|
// but otherwise Telegram throws MEDIA_INVALID
|
||||||
// fuck my life
|
// fuck my life
|
||||||
uploadPeer: peer,
|
uploadPeer: peer,
|
||||||
|
businessConnectionId: params.businessConnectionId,
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
|
@ -93,7 +99,9 @@ export async function sendMediaGroup(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await client.call(
|
const res = await _maybeInvokeWithBusinessConnection(
|
||||||
|
client,
|
||||||
|
params.businessConnectionId,
|
||||||
{
|
{
|
||||||
_: 'messages.sendMultiMedia',
|
_: 'messages.sendMultiMedia',
|
||||||
peer,
|
peer,
|
||||||
|
@ -105,6 +113,7 @@ export async function sendMediaGroup(
|
||||||
noforwards: params.forbidForwards,
|
noforwards: params.forbidForwards,
|
||||||
sendAs: params.sendAs ? await resolvePeer(client, params.sendAs) : undefined,
|
sendAs: params.sendAs ? await resolvePeer(client, params.sendAs) : undefined,
|
||||||
invertMedia: params.invertMedia,
|
invertMedia: params.invertMedia,
|
||||||
|
quickReplyShortcut,
|
||||||
},
|
},
|
||||||
{ chainId },
|
{ chainId },
|
||||||
)
|
)
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { InputPeerLike } from '../../types/peers/index.js'
|
||||||
import { _normalizeInputMedia } from '../files/normalize-input-media.js'
|
import { _normalizeInputMedia } from '../files/normalize-input-media.js'
|
||||||
import { _normalizeInputText } from '../misc/normalize-text.js'
|
import { _normalizeInputText } from '../misc/normalize-text.js'
|
||||||
import { resolvePeer } from '../users/resolve-peer.js'
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
import { _maybeInvokeWithBusinessConnection } from './_business-connection.js'
|
||||||
import { _findMessageInUpdate } from './find-in-update.js'
|
import { _findMessageInUpdate } from './find-in-update.js'
|
||||||
import { _getDiscussionMessage } from './get-discussion-message.js'
|
import { _getDiscussionMessage } from './get-discussion-message.js'
|
||||||
import { _processCommonSendParameters, CommonSendParams } from './send-common.js'
|
import { _processCommonSendParameters, CommonSendParams } from './send-common.js'
|
||||||
|
@ -80,10 +81,16 @@ export async function sendMedia(
|
||||||
)
|
)
|
||||||
|
|
||||||
const replyMarkup = BotKeyboard._convertToTl(params.replyMarkup)
|
const replyMarkup = BotKeyboard._convertToTl(params.replyMarkup)
|
||||||
const { peer, replyTo, scheduleDate, chainId } = await _processCommonSendParameters(client, chatId, params)
|
const { peer, replyTo, scheduleDate, chainId, quickReplyShortcut } = await _processCommonSendParameters(
|
||||||
|
client,
|
||||||
|
chatId,
|
||||||
|
params,
|
||||||
|
)
|
||||||
|
|
||||||
const randomId = randomLong()
|
const randomId = randomLong()
|
||||||
const res = await client.call(
|
const res = await _maybeInvokeWithBusinessConnection(
|
||||||
|
client,
|
||||||
|
params.businessConnectionId,
|
||||||
{
|
{
|
||||||
_: 'messages.sendMedia',
|
_: 'messages.sendMedia',
|
||||||
peer,
|
peer,
|
||||||
|
@ -99,6 +106,7 @@ export async function sendMedia(
|
||||||
noforwards: params.forbidForwards,
|
noforwards: params.forbidForwards,
|
||||||
sendAs: params.sendAs ? await resolvePeer(client, params.sendAs) : undefined,
|
sendAs: params.sendAs ? await resolvePeer(client, params.sendAs) : undefined,
|
||||||
invertMedia: params.invert,
|
invertMedia: params.invert,
|
||||||
|
quickReplyShortcut,
|
||||||
},
|
},
|
||||||
{ chainId },
|
{ chainId },
|
||||||
)
|
)
|
||||||
|
|
|
@ -13,6 +13,7 @@ import { inputPeerToPeer } from '../../utils/peer-utils.js'
|
||||||
import { _getRawPeerBatched } from '../chats/batched-queries.js'
|
import { _getRawPeerBatched } from '../chats/batched-queries.js'
|
||||||
import { _normalizeInputText } from '../misc/normalize-text.js'
|
import { _normalizeInputText } from '../misc/normalize-text.js'
|
||||||
import { resolvePeer } from '../users/resolve-peer.js'
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
import { _maybeInvokeWithBusinessConnection } from './_business-connection.js'
|
||||||
import { _findMessageInUpdate } from './find-in-update.js'
|
import { _findMessageInUpdate } from './find-in-update.js'
|
||||||
import { _getDiscussionMessage } from './get-discussion-message.js'
|
import { _getDiscussionMessage } from './get-discussion-message.js'
|
||||||
import { _processCommonSendParameters, CommonSendParams } from './send-common.js'
|
import { _processCommonSendParameters, CommonSendParams } from './send-common.js'
|
||||||
|
@ -54,10 +55,16 @@ export async function sendText(
|
||||||
const [message, entities] = await _normalizeInputText(client, text)
|
const [message, entities] = await _normalizeInputText(client, text)
|
||||||
|
|
||||||
const replyMarkup = BotKeyboard._convertToTl(params.replyMarkup)
|
const replyMarkup = BotKeyboard._convertToTl(params.replyMarkup)
|
||||||
const { peer, replyTo, scheduleDate, chainId } = await _processCommonSendParameters(client, chatId, params)
|
const { peer, replyTo, scheduleDate, chainId, quickReplyShortcut } = await _processCommonSendParameters(
|
||||||
|
client,
|
||||||
|
chatId,
|
||||||
|
params,
|
||||||
|
)
|
||||||
|
|
||||||
const randomId = randomLong()
|
const randomId = randomLong()
|
||||||
const res = await client.call(
|
const res = await _maybeInvokeWithBusinessConnection(
|
||||||
|
client,
|
||||||
|
params.businessConnectionId,
|
||||||
{
|
{
|
||||||
_: 'messages.sendMessage',
|
_: 'messages.sendMessage',
|
||||||
peer,
|
peer,
|
||||||
|
@ -73,6 +80,7 @@ export async function sendText(
|
||||||
noforwards: params.forbidForwards,
|
noforwards: params.forbidForwards,
|
||||||
sendAs: params.sendAs ? await resolvePeer(client, params.sendAs) : undefined,
|
sendAs: params.sendAs ? await resolvePeer(client, params.sendAs) : undefined,
|
||||||
invertMedia: params.invertMedia,
|
invertMedia: params.invertMedia,
|
||||||
|
quickReplyShortcut,
|
||||||
},
|
},
|
||||||
{ chainId },
|
{ chainId },
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { assertTrue } from '../../../utils/type-assertions.js'
|
||||||
import { ITelegramClient } from '../../client.types.js'
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { InputPeerLike, TypingStatus } from '../../types/index.js'
|
import { InputPeerLike, TypingStatus } from '../../types/index.js'
|
||||||
import { resolvePeer } from '../users/resolve-peer.js'
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
import { _maybeInvokeWithBusinessConnection } from './_business-connection.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a current user/bot typing event
|
* Sends a current user/bot typing event
|
||||||
|
@ -28,6 +29,11 @@ export async function sendTyping(
|
||||||
*/
|
*/
|
||||||
progress?: number
|
progress?: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unique identifier of the business connection on behalf of which the action will be sent
|
||||||
|
*/
|
||||||
|
businessConnectionId?: string
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For comment threads, ID of the thread (i.e. top message)
|
* For comment threads, ID of the thread (i.e. top message)
|
||||||
*/
|
*/
|
||||||
|
@ -91,7 +97,7 @@ export async function sendTyping(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const r = await client.call({
|
const r = await _maybeInvokeWithBusinessConnection(client, params?.businessConnectionId, {
|
||||||
_: 'messages.setTyping',
|
_: 'messages.setTyping',
|
||||||
peer: await resolvePeer(client, chatId),
|
peer: await resolvePeer(client, chatId),
|
||||||
action: status,
|
action: status,
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
import { CollectibleInfo } from '../../types/misc/collectible-info.js'
|
||||||
|
import { normalizePhoneNumber } from '../../utils/misc-utils.js'
|
||||||
|
|
||||||
|
// @available=user
|
||||||
|
/**
|
||||||
|
* Get information about a fragment collectible
|
||||||
|
*/
|
||||||
|
export async function getCollectibleInfo(
|
||||||
|
client: ITelegramClient,
|
||||||
|
kind: 'phone' | 'username',
|
||||||
|
item: string,
|
||||||
|
): Promise<CollectibleInfo> {
|
||||||
|
const res = await client.call({
|
||||||
|
_: 'fragment.getCollectibleInfo',
|
||||||
|
collectible:
|
||||||
|
kind === 'phone' ?
|
||||||
|
{
|
||||||
|
_: 'inputCollectiblePhone',
|
||||||
|
phone: normalizePhoneNumber(item),
|
||||||
|
} :
|
||||||
|
{
|
||||||
|
_: 'inputCollectibleUsername',
|
||||||
|
username: item,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return new CollectibleInfo(res)
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
import { InputText } from '../../types/index.js'
|
||||||
|
import { BusinessChatLink } from '../../types/premium/business-chat-link.js'
|
||||||
|
import { _normalizeInputText } from '../misc/normalize-text.js'
|
||||||
|
|
||||||
|
// @available=user
|
||||||
|
/**
|
||||||
|
* Create a new business chat link
|
||||||
|
*
|
||||||
|
* @param text Text to be inserted into the message input
|
||||||
|
*/
|
||||||
|
export async function createBusinessChatLink(
|
||||||
|
client: ITelegramClient,
|
||||||
|
text: InputText,
|
||||||
|
params?: {
|
||||||
|
/** Custom title for the link */
|
||||||
|
title?: string
|
||||||
|
},
|
||||||
|
): Promise<BusinessChatLink> {
|
||||||
|
const [message, entities] = await _normalizeInputText(client, text)
|
||||||
|
const res = await client.call({
|
||||||
|
_: 'account.createBusinessChatLink',
|
||||||
|
link: {
|
||||||
|
_: 'inputBusinessChatLink',
|
||||||
|
message,
|
||||||
|
entities,
|
||||||
|
title: params?.title,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return new BusinessChatLink(res)
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
import { assertTrue } from '../../../utils/type-assertions.js'
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
import { InputText } from '../../types/index.js'
|
||||||
|
import { BusinessChatLink } from '../../types/premium/business-chat-link.js'
|
||||||
|
import { _normalizeInputText } from '../misc/normalize-text.js'
|
||||||
|
|
||||||
|
// @available=user
|
||||||
|
/**
|
||||||
|
* Edit an existing business chat link
|
||||||
|
*
|
||||||
|
* @param link The link to edit
|
||||||
|
*/
|
||||||
|
export async function editBusinessChatLink(
|
||||||
|
client: ITelegramClient,
|
||||||
|
link: string | BusinessChatLink,
|
||||||
|
params: {
|
||||||
|
/** Text to be inserted in the message input */
|
||||||
|
text: InputText
|
||||||
|
/** Custom title for the link */
|
||||||
|
title?: string
|
||||||
|
},
|
||||||
|
): Promise<BusinessChatLink> {
|
||||||
|
const [message, entities] = await _normalizeInputText(client, params.text)
|
||||||
|
const res = await client.call({
|
||||||
|
_: 'account.editBusinessChatLink',
|
||||||
|
slug: link instanceof BusinessChatLink ? link.link : link,
|
||||||
|
link: {
|
||||||
|
_: 'inputBusinessChatLink',
|
||||||
|
message,
|
||||||
|
entities,
|
||||||
|
title: params?.title,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return new BusinessChatLink(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @available=user
|
||||||
|
/**
|
||||||
|
* Delete a business chat link
|
||||||
|
*
|
||||||
|
* @param link The link to delete
|
||||||
|
*/
|
||||||
|
export async function deleteBusinessChatLink(client: ITelegramClient, link: string | BusinessChatLink): Promise<void> {
|
||||||
|
const res = await client.call({
|
||||||
|
_: 'account.deleteBusinessChatLink',
|
||||||
|
slug: typeof link === 'string' ? link : link.link,
|
||||||
|
})
|
||||||
|
|
||||||
|
assertTrue('account.deleteBusinessChatLink', res)
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
import { BusinessChatLink } from '../../types/premium/business-chat-link.js'
|
||||||
|
|
||||||
|
// @available=user
|
||||||
|
/**
|
||||||
|
* Get current user's business chat links
|
||||||
|
*/
|
||||||
|
export async function getBusinessChatLinks(client: ITelegramClient): Promise<BusinessChatLink[]> {
|
||||||
|
const res = await client.call({ _: 'account.getBusinessChatLinks' })
|
||||||
|
|
||||||
|
return res.links.map((x) => new BusinessChatLink(x))
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { assertTypeIs } from '../../../utils/type-assertions.js'
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
import { PeersIndex } from '../../types/peers/peers-index.js'
|
||||||
|
import { BusinessConnection } from '../../types/premium/business-connection.js'
|
||||||
|
import { assertIsUpdatesGroup } from '../../updates/utils.js'
|
||||||
|
|
||||||
|
// @available=bot
|
||||||
|
/**
|
||||||
|
* Get information about the connection of the bot with a business account
|
||||||
|
*
|
||||||
|
* @param connectionId ID of the business connection
|
||||||
|
*/
|
||||||
|
export async function getBusinessConnection(
|
||||||
|
client: ITelegramClient,
|
||||||
|
connectionId: string,
|
||||||
|
): Promise<BusinessConnection> {
|
||||||
|
const res = await client.call({
|
||||||
|
_: 'account.getBotBusinessConnection',
|
||||||
|
connectionId,
|
||||||
|
})
|
||||||
|
|
||||||
|
assertIsUpdatesGroup('account.getBotBusinessConnection', res)
|
||||||
|
assertTypeIs('account.getBotBusinessConnection', res.updates[0], 'updateBotBusinessConnect')
|
||||||
|
|
||||||
|
const peers = PeersIndex.from(res)
|
||||||
|
|
||||||
|
return new BusinessConnection(res.updates[0].connection, peers)
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { assertTrue, assertTypeIs } from '../../../utils/type-assertions.js'
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
import { InputFileLike, InputMediaSticker } from '../../types/index.js'
|
||||||
|
import { _normalizeFileToDocument } from '../files/normalize-file-to-document.js'
|
||||||
|
import { _normalizeInputMedia } from '../files/normalize-input-media.js'
|
||||||
|
|
||||||
|
const isInputMediaSticker = (media: unknown): media is InputMediaSticker =>
|
||||||
|
typeof media === 'object' && media !== null && 'type' in media && media.type === 'sticker'
|
||||||
|
|
||||||
|
// @available=user
|
||||||
|
/**
|
||||||
|
* Set current user's business introduction.
|
||||||
|
*
|
||||||
|
* @param intro Introduction parameters, or `null` to remove
|
||||||
|
*/
|
||||||
|
export async function setBusinessIntro(
|
||||||
|
client: ITelegramClient,
|
||||||
|
intro: {
|
||||||
|
/**
|
||||||
|
* Title of the introduction
|
||||||
|
*/
|
||||||
|
title?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description of the introduction
|
||||||
|
*/
|
||||||
|
description?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sticker to show beneath the introduction
|
||||||
|
*/
|
||||||
|
sticker?: InputMediaSticker | InputFileLike | tl.TypeInputDocument
|
||||||
|
} | null,
|
||||||
|
): Promise<void> {
|
||||||
|
let tlIntro: tl.TypeInputBusinessIntro | undefined = undefined
|
||||||
|
|
||||||
|
if (intro) {
|
||||||
|
let sticker: tl.TypeInputDocument | undefined
|
||||||
|
|
||||||
|
if (intro.sticker) {
|
||||||
|
if (isInputMediaSticker(intro.sticker)) {
|
||||||
|
const media = await _normalizeInputMedia(client, intro.sticker, undefined, true)
|
||||||
|
|
||||||
|
assertTypeIs('_normalizeInputMedia', media, 'inputMediaDocument')
|
||||||
|
sticker = media.id
|
||||||
|
} else {
|
||||||
|
sticker = await _normalizeFileToDocument(client, intro.sticker, {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tlIntro = {
|
||||||
|
_: 'inputBusinessIntro',
|
||||||
|
title: intro.title ?? '',
|
||||||
|
description: intro.description ?? '',
|
||||||
|
sticker,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await client.call({
|
||||||
|
_: 'account.updateBusinessIntro',
|
||||||
|
intro: tlIntro,
|
||||||
|
})
|
||||||
|
|
||||||
|
assertTrue('account.updateBusinessIntro', res)
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { assertTrue } from '../../../utils/type-assertions.js'
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
import { BusinessWorkHoursDay, businessWorkHoursDaysToRaw } from '../../types/premium/business-work-hours.js'
|
||||||
|
|
||||||
|
// @available=user
|
||||||
|
/**
|
||||||
|
* Set current user's business work hours.
|
||||||
|
*/
|
||||||
|
export async function setBusinessWorkHours(
|
||||||
|
client: ITelegramClient,
|
||||||
|
params:
|
||||||
|
| ({
|
||||||
|
/** Timezone in which the hours are defined */
|
||||||
|
timezone: string
|
||||||
|
} & (
|
||||||
|
| {
|
||||||
|
/**
|
||||||
|
* Business work intervals, per-day (like available in {@link BusinessWorkHours.days})
|
||||||
|
*/
|
||||||
|
hours: ReadonlyArray<BusinessWorkHoursDay>
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
/** Business work intervals, raw intervals */
|
||||||
|
intervals: tl.TypeBusinessWeeklyOpen[]
|
||||||
|
}
|
||||||
|
))
|
||||||
|
| null,
|
||||||
|
): Promise<void> {
|
||||||
|
let businessWorkHours: tl.TypeBusinessWorkHours | undefined = undefined
|
||||||
|
|
||||||
|
if (params) {
|
||||||
|
let weeklyOpen: tl.TypeBusinessWeeklyOpen[]
|
||||||
|
|
||||||
|
if ('hours' in params) {
|
||||||
|
weeklyOpen = businessWorkHoursDaysToRaw(params.hours)
|
||||||
|
} else {
|
||||||
|
weeklyOpen = params.intervals
|
||||||
|
}
|
||||||
|
|
||||||
|
businessWorkHours = {
|
||||||
|
_: 'businessWorkHours',
|
||||||
|
timezoneId: params.timezone,
|
||||||
|
weeklyOpen,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await client.call({
|
||||||
|
_: 'account.updateBusinessWorkHours',
|
||||||
|
businessWorkHours,
|
||||||
|
})
|
||||||
|
|
||||||
|
assertTrue('account.updateBusinessWorkHours', res)
|
||||||
|
}
|
32
packages/core/src/highlevel/methods/stickers/_utils.ts
Normal file
32
packages/core/src/highlevel/methods/stickers/_utils.ts
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
import { InputStickerSetItem, MASK_POSITION_POINT_TO_TL } from '../../types/index.js'
|
||||||
|
import { _normalizeFileToDocument } from '../files/normalize-file-to-document.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* @noemit
|
||||||
|
*/
|
||||||
|
export async function _normalizeInputStickerSetItem(
|
||||||
|
client: ITelegramClient,
|
||||||
|
sticker: InputStickerSetItem,
|
||||||
|
params?: {
|
||||||
|
progressCallback?: (uploaded: number, total: number) => void
|
||||||
|
},
|
||||||
|
): Promise<tl.TypeInputStickerSetItem> {
|
||||||
|
return {
|
||||||
|
_: 'inputStickerSetItem',
|
||||||
|
document: await _normalizeFileToDocument(client, sticker.file, params ?? {}),
|
||||||
|
emoji: sticker.emojis,
|
||||||
|
maskCoords: sticker.maskPosition ?
|
||||||
|
{
|
||||||
|
_: 'maskCoords',
|
||||||
|
n: MASK_POSITION_POINT_TO_TL[sticker.maskPosition.point],
|
||||||
|
x: sticker.maskPosition.x,
|
||||||
|
y: sticker.maskPosition.y,
|
||||||
|
zoom: sticker.maskPosition.scale,
|
||||||
|
} :
|
||||||
|
undefined,
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,17 +2,16 @@ import { ITelegramClient } from '../../client.types.js'
|
||||||
import {
|
import {
|
||||||
InputStickerSet,
|
InputStickerSet,
|
||||||
InputStickerSetItem,
|
InputStickerSetItem,
|
||||||
MASK_POSITION_POINT_TO_TL,
|
|
||||||
normalizeInputStickerSet,
|
normalizeInputStickerSet,
|
||||||
StickerSet,
|
StickerSet,
|
||||||
} from '../../types/index.js'
|
} from '../../types/index.js'
|
||||||
import { _normalizeFileToDocument } from '../files/normalize-file-to-document.js'
|
import { _normalizeFileToDocument } from '../files/normalize-file-to-document.js'
|
||||||
|
import { _normalizeInputStickerSetItem } from './_utils.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a sticker to a sticker set.
|
* Add a sticker to a sticker set.
|
||||||
*
|
*
|
||||||
* Only for bots, and the sticker set must
|
* For bots the sticker set must have been created by this bot.
|
||||||
* have been created by this bot.
|
|
||||||
*
|
*
|
||||||
* @param setId Sticker set short name or TL object with input sticker set
|
* @param setId Sticker set short name or TL object with input sticker set
|
||||||
* @param sticker Sticker to be added
|
* @param sticker Sticker to be added
|
||||||
|
@ -36,20 +35,7 @@ export async function addStickerToSet(
|
||||||
const res = await client.call({
|
const res = await client.call({
|
||||||
_: 'stickers.addStickerToSet',
|
_: 'stickers.addStickerToSet',
|
||||||
stickerset: normalizeInputStickerSet(setId),
|
stickerset: normalizeInputStickerSet(setId),
|
||||||
sticker: {
|
sticker: await _normalizeInputStickerSetItem(client, sticker, params),
|
||||||
_: 'inputStickerSetItem',
|
|
||||||
document: await _normalizeFileToDocument(client, sticker.file, params ?? {}),
|
|
||||||
emoji: sticker.emojis,
|
|
||||||
maskCoords: sticker.maskPosition ?
|
|
||||||
{
|
|
||||||
_: 'maskCoords',
|
|
||||||
n: MASK_POSITION_POINT_TO_TL[sticker.maskPosition.point],
|
|
||||||
x: sticker.maskPosition.x,
|
|
||||||
y: sticker.maskPosition.y,
|
|
||||||
zoom: sticker.maskPosition.scale,
|
|
||||||
} :
|
|
||||||
undefined,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return new StickerSet(res)
|
return new StickerSet(res)
|
||||||
|
|
|
@ -5,20 +5,17 @@ import {
|
||||||
InputFileLike,
|
InputFileLike,
|
||||||
InputPeerLike,
|
InputPeerLike,
|
||||||
InputStickerSetItem,
|
InputStickerSetItem,
|
||||||
MASK_POSITION_POINT_TO_TL,
|
|
||||||
StickerSet,
|
StickerSet,
|
||||||
StickerSourceType,
|
StickerSourceType,
|
||||||
StickerType,
|
StickerType,
|
||||||
} from '../../types/index.js'
|
} from '../../types/index.js'
|
||||||
import { _normalizeFileToDocument } from '../files/normalize-file-to-document.js'
|
import { _normalizeFileToDocument } from '../files/normalize-file-to-document.js'
|
||||||
import { resolveUser } from '../users/resolve-peer.js'
|
import { resolveUser } from '../users/resolve-peer.js'
|
||||||
|
import { _normalizeInputStickerSetItem } from './_utils.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new sticker set.
|
* Create a new sticker set.
|
||||||
*
|
*
|
||||||
* This is the only sticker-related method that
|
|
||||||
* users can use (they allowed it with the "import stickers" update)
|
|
||||||
*
|
|
||||||
* @param params
|
* @param params
|
||||||
* @returns Newly created sticker set
|
* @returns Newly created sticker set
|
||||||
*/
|
*/
|
||||||
|
@ -106,22 +103,7 @@ export async function createStickerSet(
|
||||||
for (const sticker of params.stickers) {
|
for (const sticker of params.stickers) {
|
||||||
const progressCallback = params.progressCallback?.bind(null, i)
|
const progressCallback = params.progressCallback?.bind(null, i)
|
||||||
|
|
||||||
inputStickers.push({
|
inputStickers.push(await _normalizeInputStickerSetItem(client, sticker, { progressCallback }))
|
||||||
_: 'inputStickerSetItem',
|
|
||||||
document: await _normalizeFileToDocument(client, sticker.file, {
|
|
||||||
progressCallback,
|
|
||||||
}),
|
|
||||||
emoji: sticker.emojis,
|
|
||||||
maskCoords: sticker.maskPosition ?
|
|
||||||
{
|
|
||||||
_: 'maskCoords',
|
|
||||||
n: MASK_POSITION_POINT_TO_TL[sticker.maskPosition.point],
|
|
||||||
x: sticker.maskPosition.x,
|
|
||||||
y: sticker.maskPosition.y,
|
|
||||||
zoom: sticker.maskPosition.scale,
|
|
||||||
} :
|
|
||||||
undefined,
|
|
||||||
})
|
|
||||||
|
|
||||||
i += 1
|
i += 1
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,7 @@ import { fileIdToInputDocument } from '../../utils/convert-file-id.js'
|
||||||
/**
|
/**
|
||||||
* Delete a sticker from a sticker set
|
* Delete a sticker from a sticker set
|
||||||
*
|
*
|
||||||
* Only for bots, and the sticker set must
|
* For bots the sticker set must have been created by this bot.
|
||||||
* have been created by this bot.
|
|
||||||
*
|
*
|
||||||
* @param sticker
|
* @param sticker
|
||||||
* TDLib and Bot API compatible File ID, or a
|
* TDLib and Bot API compatible File ID, or a
|
||||||
|
|
|
@ -9,8 +9,7 @@ import { StickerSet } from '../../types/index.js'
|
||||||
*
|
*
|
||||||
* > **Note**: This method returns *brief* meta information about
|
* > **Note**: This method returns *brief* meta information about
|
||||||
* > the packs, that does not include the stickers themselves.
|
* > the packs, that does not include the stickers themselves.
|
||||||
* > Use {@link StickerSet.getFull} or {@link getStickerSet}
|
* > Use {@link getStickerSet} to get a stickerset that will include the stickers
|
||||||
* > to get a stickerset that will include the stickers
|
|
||||||
*/
|
*/
|
||||||
export async function getInstalledStickers(client: ITelegramClient): Promise<StickerSet[]> {
|
export async function getInstalledStickers(client: ITelegramClient): Promise<StickerSet[]> {
|
||||||
const res = await client.call({
|
const res = await client.call({
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
import Long from 'long'
|
||||||
|
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
import { StickerSet } from '../../types/misc/sticker-set.js'
|
||||||
|
import { ArrayPaginated } from '../../types/utils.js'
|
||||||
|
import { makeArrayPaginated } from '../../utils/misc-utils.js'
|
||||||
|
|
||||||
|
// @available=user
|
||||||
|
/**
|
||||||
|
* Get the list of sticker sets that were created by the current user
|
||||||
|
*/
|
||||||
|
export async function getMyStickerSets(
|
||||||
|
client: ITelegramClient,
|
||||||
|
params?: {
|
||||||
|
/** Offset for pagination */
|
||||||
|
offset?: Long
|
||||||
|
/** Limit for pagination */
|
||||||
|
limit?: number
|
||||||
|
},
|
||||||
|
): Promise<ArrayPaginated<StickerSet, Long>> {
|
||||||
|
const res = await client.call({
|
||||||
|
_: 'messages.getMyStickers',
|
||||||
|
offsetId: params?.offset ?? Long.ZERO,
|
||||||
|
limit: params?.limit ?? 100,
|
||||||
|
})
|
||||||
|
|
||||||
|
const items = res.sets.map((x) => new StickerSet(x))
|
||||||
|
|
||||||
|
return makeArrayPaginated(items, res.count, items[items.length - 1]?.brief.id)
|
||||||
|
}
|
|
@ -2,9 +2,9 @@ import { ITelegramClient } from '../../client.types.js'
|
||||||
import { InputStickerSet, normalizeInputStickerSet, StickerSet } from '../../types/index.js'
|
import { InputStickerSet, normalizeInputStickerSet, StickerSet } from '../../types/index.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a sticker pack and stickers inside of it.
|
* Get a sticker set and stickers inside of it.
|
||||||
*
|
*
|
||||||
* @param setId Sticker pack short name, dice emoji, `"emoji"` for animated emojis or input ID
|
* @param setId Sticker set identifier
|
||||||
*/
|
*/
|
||||||
export async function getStickerSet(client: ITelegramClient, setId: InputStickerSet): Promise<StickerSet> {
|
export async function getStickerSet(client: ITelegramClient, setId: InputStickerSet): Promise<StickerSet> {
|
||||||
const res = await client.call({
|
const res = await client.call({
|
||||||
|
|
|
@ -9,16 +9,14 @@ import { fileIdToInputDocument } from '../../utils/convert-file-id.js'
|
||||||
* Move a sticker in a sticker set
|
* Move a sticker in a sticker set
|
||||||
* to another position
|
* to another position
|
||||||
*
|
*
|
||||||
* Only for bots, and the sticker set must
|
* For bots the sticker set must have been created by this bot.
|
||||||
* have been created by this bot.
|
|
||||||
*
|
*
|
||||||
* @param sticker
|
* @param sticker
|
||||||
* TDLib and Bot API compatible File ID, or a
|
* TDLib and Bot API compatible File ID, or a
|
||||||
* TL object representing a sticker to be removed
|
* TL object representing a sticker to be removed
|
||||||
* @param position New sticker position (starting from 0)
|
* @param position New sticker position (starting from 0)
|
||||||
* @returns Modfiied sticker set
|
* @returns Modified sticker set
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export async function moveStickerInSet(
|
export async function moveStickerInSet(
|
||||||
client: ITelegramClient,
|
client: ITelegramClient,
|
||||||
sticker: string | tdFileId.RawFullRemoteFileLocation | tl.TypeInputDocument,
|
sticker: string | tdFileId.RawFullRemoteFileLocation | tl.TypeInputDocument,
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
import { tdFileId } from '@mtcute/file-id'
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
import { InputStickerSetItem, StickerSet } from '../../types/index.js'
|
||||||
|
import { fileIdToInputDocument } from '../../utils/convert-file-id.js'
|
||||||
|
import { _normalizeInputStickerSetItem } from './_utils.js'
|
||||||
|
|
||||||
|
// @available=both
|
||||||
|
/**
|
||||||
|
* Replace a sticker in a sticker set with another sticker
|
||||||
|
*
|
||||||
|
* For bots the sticker set must have been created by this bot.
|
||||||
|
*
|
||||||
|
* @param sticker
|
||||||
|
* TDLib and Bot API compatible File ID, or a
|
||||||
|
* TL object representing a sticker to be removed
|
||||||
|
* @param newSticker New sticker to replace the old one with
|
||||||
|
* @returns Modfiied sticker set
|
||||||
|
*/
|
||||||
|
export async function replaceStickerInSet(
|
||||||
|
client: ITelegramClient,
|
||||||
|
sticker: string | tdFileId.RawFullRemoteFileLocation | tl.TypeInputDocument,
|
||||||
|
newSticker: InputStickerSetItem,
|
||||||
|
params?: {
|
||||||
|
/**
|
||||||
|
* Upload progress callback
|
||||||
|
*
|
||||||
|
* @param uploaded Number of bytes uploaded
|
||||||
|
* @param total Total file size
|
||||||
|
*/
|
||||||
|
progressCallback?: (uploaded: number, total: number) => void
|
||||||
|
},
|
||||||
|
): Promise<StickerSet> {
|
||||||
|
if (tdFileId.isFileIdLike(sticker)) {
|
||||||
|
sticker = fileIdToInputDocument(sticker)
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await client.call({
|
||||||
|
_: 'stickers.replaceSticker',
|
||||||
|
sticker,
|
||||||
|
newSticker: await _normalizeInputStickerSetItem(client, newSticker, params),
|
||||||
|
})
|
||||||
|
|
||||||
|
return new StickerSet(res)
|
||||||
|
}
|
30
packages/core/src/highlevel/methods/users/set-my-birthday.ts
Normal file
30
packages/core/src/highlevel/methods/users/set-my-birthday.ts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import { assertTrue } from '../../../utils/type-assertions.js'
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
|
||||||
|
// @available=user
|
||||||
|
/**
|
||||||
|
* Set or remove current user's birthday.
|
||||||
|
*/
|
||||||
|
export async function setMyBirthday(
|
||||||
|
client: ITelegramClient,
|
||||||
|
birthday: {
|
||||||
|
/** Birthday day */
|
||||||
|
day: number
|
||||||
|
/** Birthday month */
|
||||||
|
month: number
|
||||||
|
/** Birthday year (optional) */
|
||||||
|
year?: number
|
||||||
|
} | null,
|
||||||
|
): Promise<void> {
|
||||||
|
const res = await client.call({
|
||||||
|
_: 'account.updateBirthday',
|
||||||
|
birthday: birthday ?
|
||||||
|
{
|
||||||
|
_: 'birthday',
|
||||||
|
...birthday,
|
||||||
|
} :
|
||||||
|
undefined,
|
||||||
|
})
|
||||||
|
|
||||||
|
assertTrue('account.updateBirthday', res)
|
||||||
|
}
|
|
@ -12,6 +12,8 @@ const sentCodeMap: Record<tl.auth.TypeSentCodeType['_'], SentCodeDeliveryType> =
|
||||||
'auth.sentCodeTypeSetUpEmailRequired': 'email_required',
|
'auth.sentCodeTypeSetUpEmailRequired': 'email_required',
|
||||||
'auth.sentCodeTypeFragmentSms': 'fragment',
|
'auth.sentCodeTypeFragmentSms': 'fragment',
|
||||||
'auth.sentCodeTypeFirebaseSms': 'firebase',
|
'auth.sentCodeTypeFirebaseSms': 'firebase',
|
||||||
|
'auth.sentCodeTypeSmsWord': 'sms_word',
|
||||||
|
'auth.sentCodeTypeSmsPhrase': 'sms_phrase',
|
||||||
}
|
}
|
||||||
|
|
||||||
const nextCodeMap: Record<tl.auth.TypeCodeType['_'], NextCodeDeliveryType> = {
|
const nextCodeMap: Record<tl.auth.TypeCodeType['_'], NextCodeDeliveryType> = {
|
||||||
|
@ -33,7 +35,8 @@ const nextCodeMap: Record<tl.auth.TypeCodeType['_'], NextCodeDeliveryType> = {
|
||||||
* - `email_required`: Code sending via email setup is required
|
* - `email_required`: Code sending via email setup is required
|
||||||
* - `fragment`: Code is sent via Fragment anonymous numbers
|
* - `fragment`: Code is sent via Fragment anonymous numbers
|
||||||
* - `firebase`: Code is sent via Firebase
|
* - `firebase`: Code is sent via Firebase
|
||||||
* - `Success`: Code is not needed, you're already logged in (only for future auth tokens)
|
* - `sms_word`, `sms_phrase`: Code is sent via SMS with a word/phrase (see {@link SentCode#beginning})
|
||||||
|
* - `success`: Code is not needed, you're already logged in (only for future auth tokens)
|
||||||
*/
|
*/
|
||||||
export type SentCodeDeliveryType =
|
export type SentCodeDeliveryType =
|
||||||
| 'app'
|
| 'app'
|
||||||
|
@ -45,6 +48,8 @@ export type SentCodeDeliveryType =
|
||||||
| 'email_required'
|
| 'email_required'
|
||||||
| 'fragment'
|
| 'fragment'
|
||||||
| 'firebase'
|
| 'firebase'
|
||||||
|
| 'sms_word'
|
||||||
|
| 'sms_phrase'
|
||||||
| 'success'
|
| 'success'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -91,6 +96,19 @@ export class SentCode {
|
||||||
return this.raw.timeout ?? 0
|
return this.raw.timeout ?? 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the code is sent via SMS with a word/phrase, this field *may* contain the beginning of the message
|
||||||
|
*/
|
||||||
|
get beginning(): string | undefined {
|
||||||
|
switch (this.raw.type._) {
|
||||||
|
case 'auth.sentCodeTypeSmsPhrase':
|
||||||
|
case 'auth.sentCodeTypeSmsWord':
|
||||||
|
return this.raw.type.beginning
|
||||||
|
default:
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Length of the code (0 for flash calls)
|
* Length of the code (0 for flash calls)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { Voice } from './voice.js'
|
||||||
export type ParsedDocument = Sticker | Voice | Audio | Video | Document
|
export type ParsedDocument = Sticker | Voice | Audio | Video | Document
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
export function parseDocument(doc: tl.RawDocument, media?: tl.RawMessageMediaDocument): ParsedDocument {
|
export function parseSticker(doc: tl.RawDocument) {
|
||||||
const stickerAttr = doc.attributes.find(
|
const stickerAttr = doc.attributes.find(
|
||||||
(a) => a._ === 'documentAttributeSticker' || a._ === 'documentAttributeCustomEmoji',
|
(a) => a._ === 'documentAttributeSticker' || a._ === 'documentAttributeCustomEmoji',
|
||||||
)
|
)
|
||||||
|
@ -21,6 +21,12 @@ export function parseDocument(doc: tl.RawDocument, media?: tl.RawMessageMediaDoc
|
||||||
|
|
||||||
return new Sticker(doc, stickerAttr as tl.RawDocumentAttributeSticker | tl.RawDocumentAttributeCustomEmoji, sz)
|
return new Sticker(doc, stickerAttr as tl.RawDocumentAttributeSticker | tl.RawDocumentAttributeCustomEmoji, sz)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
export function parseDocument(doc: tl.RawDocument, media?: tl.RawMessageMediaDocument): ParsedDocument {
|
||||||
|
const sticker = parseSticker(doc)
|
||||||
|
if (sticker) return sticker
|
||||||
|
|
||||||
for (const attr of doc.attributes) {
|
for (const attr of doc.attributes) {
|
||||||
switch (attr._) {
|
switch (attr._) {
|
||||||
|
|
|
@ -460,7 +460,7 @@ export interface InputMediaPoll extends CaptionMixin {
|
||||||
/**
|
/**
|
||||||
* Question of the poll (1-255 chars for users, 1-300 chars for bots)
|
* Question of the poll (1-255 chars for users, 1-300 chars for bots)
|
||||||
*/
|
*/
|
||||||
question: string
|
question: InputText
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Answers of the poll.
|
* Answers of the poll.
|
||||||
|
@ -471,7 +471,7 @@ export interface InputMediaPoll extends CaptionMixin {
|
||||||
* objects, with a single=byte incrementing
|
* objects, with a single=byte incrementing
|
||||||
* `option` value.
|
* `option` value.
|
||||||
*/
|
*/
|
||||||
answers: (string | tl.TypePollAnswer)[]
|
answers: (InputText | tl.TypePollAnswer)[]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this is poll is closed
|
* Whether this is poll is closed
|
||||||
|
|
|
@ -7,17 +7,32 @@ import { memoizeGetters } from '../../utils/memoize.js'
|
||||||
import { MessageEntity } from '../messages/message-entity.js'
|
import { MessageEntity } from '../messages/message-entity.js'
|
||||||
import { PeersIndex } from '../peers/peers-index.js'
|
import { PeersIndex } from '../peers/peers-index.js'
|
||||||
|
|
||||||
export interface PollAnswer {
|
export class PollAnswer {
|
||||||
|
constructor(
|
||||||
|
readonly raw: tl.TypePollAnswer,
|
||||||
|
readonly result?: tl.TypePollAnswerVoters,
|
||||||
|
) {}
|
||||||
/**
|
/**
|
||||||
* Answer text
|
* Answer text
|
||||||
*/
|
*/
|
||||||
text: string
|
get text(): string {
|
||||||
|
return this.raw.text.text
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format entities for {@link text}, currently may only contain custom emojis
|
||||||
|
*/
|
||||||
|
get textEntities(): ReadonlyArray<MessageEntity> {
|
||||||
|
return this.raw.text.entities.map((ent) => new MessageEntity(ent, this.raw.text.text))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Answer data, to be passed to
|
* Answer data, to be passed to
|
||||||
* {@link TelegramClient.sendVote}
|
* {@link TelegramClient.sendVote}
|
||||||
*/
|
*/
|
||||||
data: Uint8Array
|
get data(): Uint8Array {
|
||||||
|
return this.raw.option
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number of people who has chosen this result.
|
* Number of people who has chosen this result.
|
||||||
|
@ -25,12 +40,16 @@ export interface PollAnswer {
|
||||||
*
|
*
|
||||||
* @default `0`
|
* @default `0`
|
||||||
*/
|
*/
|
||||||
voters: number
|
get voters(): number {
|
||||||
|
return this.result?.voters ?? 0
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this answer was chosen by the current user
|
* Whether this answer was chosen by the current user
|
||||||
*/
|
*/
|
||||||
chosen: boolean
|
get chosen(): boolean {
|
||||||
|
return Boolean(this.result?.chosen)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this answer is correct (for quizzes).
|
* Whether this answer is correct (for quizzes).
|
||||||
|
@ -38,9 +57,14 @@ export interface PollAnswer {
|
||||||
*
|
*
|
||||||
* @default `false`
|
* @default `false`
|
||||||
*/
|
*/
|
||||||
correct: boolean
|
get correct(): boolean {
|
||||||
|
return Boolean(this.result?.correct)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memoizeGetters(PollAnswer, ['textEntities'])
|
||||||
|
makeInspectable(PollAnswer)
|
||||||
|
|
||||||
export class Poll {
|
export class Poll {
|
||||||
readonly type = 'poll' as const
|
readonly type = 'poll' as const
|
||||||
|
|
||||||
|
@ -61,7 +85,14 @@ export class Poll {
|
||||||
* Poll question
|
* Poll question
|
||||||
*/
|
*/
|
||||||
get question(): string {
|
get question(): string {
|
||||||
return this.raw.question
|
return this.raw.question.text
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format entities for {@link question} (currently may only contain custom emojis)
|
||||||
|
*/
|
||||||
|
get questionEntities(): ReadonlyArray<MessageEntity> {
|
||||||
|
return this.raw.question.entities.map((ent) => new MessageEntity(ent, this.raw.question.text))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -72,24 +103,10 @@ export class Poll {
|
||||||
|
|
||||||
return this.raw.answers.map((ans, idx) => {
|
return this.raw.answers.map((ans, idx) => {
|
||||||
if (results) {
|
if (results) {
|
||||||
const res = results[idx]
|
return new PollAnswer(ans, results[idx])
|
||||||
|
|
||||||
return {
|
|
||||||
text: ans.text,
|
|
||||||
data: ans.option,
|
|
||||||
voters: res.voters,
|
|
||||||
chosen: Boolean(res.chosen),
|
|
||||||
correct: Boolean(res.correct),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return new PollAnswer(ans)
|
||||||
text: ans.text,
|
|
||||||
data: ans.option,
|
|
||||||
voters: 0,
|
|
||||||
chosen: false,
|
|
||||||
correct: false,
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,5 +206,5 @@ export class Poll {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memoizeGetters(Poll, ['answers', 'solutionEntities'])
|
memoizeGetters(Poll, ['answers', 'solutionEntities', 'questionEntities'])
|
||||||
makeInspectable(Poll, undefined, ['inputMedia'])
|
makeInspectable(Poll, undefined, ['inputMedia'])
|
||||||
|
|
|
@ -194,21 +194,7 @@ export class Dialog {
|
||||||
* Chat that this dialog represents
|
* Chat that this dialog represents
|
||||||
*/
|
*/
|
||||||
get chat(): Chat {
|
get chat(): Chat {
|
||||||
const peer = this.raw.peer
|
return Chat._parseFromPeer(this.raw.peer, this._peers)
|
||||||
|
|
||||||
let chat
|
|
||||||
|
|
||||||
switch (peer._) {
|
|
||||||
case 'peerChannel':
|
|
||||||
case 'peerChat':
|
|
||||||
chat = this._peers.chat(peer._ === 'peerChannel' ? peer.channelId : peer.chatId)
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
chat = this._peers.user(peer.userId)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Chat(chat)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -372,7 +372,24 @@ export interface ActionPhotoSuggested {
|
||||||
photo: Photo
|
photo: Photo
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A peer was chosen by the user after clicking on a RequestPeer button */
|
/**
|
||||||
|
* A peer was chosen by the user after clicking on a RequestPeer button.
|
||||||
|
* The user-side version of {@link ActionPeerChosen}
|
||||||
|
*/
|
||||||
|
export interface ActionPeerSent {
|
||||||
|
readonly type: 'peer_sent'
|
||||||
|
|
||||||
|
/** ID of the button passed earlier by the bot */
|
||||||
|
buttonId: number
|
||||||
|
|
||||||
|
/** Brief information about the chosen peers */
|
||||||
|
peers: tl.TypeRequestedPeer[]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A peer was chosen by the user after clicking on a RequestPeer button
|
||||||
|
* The bot-side version of {@link ActionPeerSent}
|
||||||
|
*/
|
||||||
export interface ActionPeerChosen {
|
export interface ActionPeerChosen {
|
||||||
readonly type: 'peer_chosen'
|
readonly type: 'peer_chosen'
|
||||||
|
|
||||||
|
@ -472,6 +489,7 @@ export type MessageAction =
|
||||||
| ActionWebviewDataReceived
|
| ActionWebviewDataReceived
|
||||||
| ActionPremiumGifted
|
| ActionPremiumGifted
|
||||||
| ActionPhotoSuggested
|
| ActionPhotoSuggested
|
||||||
|
| ActionPeerSent
|
||||||
| ActionPeerChosen
|
| ActionPeerChosen
|
||||||
| ActionWallpaperChanged
|
| ActionWallpaperChanged
|
||||||
| ActionGiftCode
|
| ActionGiftCode
|
||||||
|
@ -696,6 +714,12 @@ export function _messageActionFromTl(this: Message, act: tl.TypeMessageAction):
|
||||||
type: 'photo_suggested',
|
type: 'photo_suggested',
|
||||||
photo: new Photo(act.photo as tl.RawPhoto),
|
photo: new Photo(act.photo as tl.RawPhoto),
|
||||||
}
|
}
|
||||||
|
case 'messageActionRequestedPeerSentMe':
|
||||||
|
return {
|
||||||
|
type: 'peer_sent',
|
||||||
|
buttonId: act.buttonId,
|
||||||
|
peers: act.peers,
|
||||||
|
}
|
||||||
case 'messageActionRequestedPeer':
|
case 'messageActionRequestedPeer':
|
||||||
return {
|
return {
|
||||||
type: 'peer_chosen',
|
type: 'peer_chosen',
|
||||||
|
|
|
@ -57,6 +57,23 @@ export class Message {
|
||||||
return this.raw._ === 'message' ? this.raw.views ?? null : null
|
return this.raw._ === 'message' ? this.raw.views ?? null : null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For channel posts, number of forwards
|
||||||
|
*
|
||||||
|
* `null` for service messages and non-post messages, or
|
||||||
|
* if the current user is not an admin in the channel
|
||||||
|
*/
|
||||||
|
get forwards(): number | null {
|
||||||
|
return this.raw._ === 'message' ? this.raw.forwards ?? null : null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For channel posts with signatures enabled, name of the post author
|
||||||
|
*/
|
||||||
|
get signature(): string | null {
|
||||||
|
return this.raw._ === 'message' ? this.raw.postAuthor ?? null : null
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the message is incoming or outgoing:
|
* Whether the message is incoming or outgoing:
|
||||||
* - Messages received from other chats are incoming (`outgoing = false`)
|
* - Messages received from other chats are incoming (`outgoing = false`)
|
||||||
|
@ -79,6 +96,56 @@ export class Message {
|
||||||
return this.raw._ === 'message' && this.raw.noforwards!
|
return this.raw._ === 'message' && this.raw.noforwards!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the message was sent by an implicit action, for example,
|
||||||
|
* as an away or a greeting business message, or as a scheduled message
|
||||||
|
*/
|
||||||
|
get isFromOffline(): boolean {
|
||||||
|
return this.raw._ === 'message' && this.raw.offline!
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether this is a silent message (no notification triggered) */
|
||||||
|
get isSilent(): boolean {
|
||||||
|
return this.raw.silent!
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether there are unread media attachments in this message */
|
||||||
|
get hasUnreadMedia(): boolean {
|
||||||
|
return this.raw.mediaUnread!
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether this is a broadcast channel post */
|
||||||
|
get isChannelPost(): boolean {
|
||||||
|
return this.raw._ === 'message' && this.raw.post!
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this message was automatically sent from a scheduled message.
|
||||||
|
*
|
||||||
|
* **Note**: for messages sent by other users, this is always `false`.
|
||||||
|
*/
|
||||||
|
get isFromScheduled(): boolean {
|
||||||
|
return this.raw._ === 'message' && this.raw.fromScheduled!
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the message is pinned in the current chat */
|
||||||
|
get isPinned(): boolean {
|
||||||
|
return this.raw._ === 'message' && this.raw.pinned!
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the message should be considered unedited, even if {@link editDate} ≠ null */
|
||||||
|
get hideEditMark(): boolean {
|
||||||
|
return this.raw._ === 'message' && this.raw.editHide!
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set, any eventual webpage preview should be shown on top of
|
||||||
|
* the message instead of at the bottom.
|
||||||
|
*/
|
||||||
|
get invertMedia(): boolean {
|
||||||
|
return this.raw._ === 'message' && this.raw.invertMedia!
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Multiple media messages with the same grouped ID
|
* Multiple media messages with the same grouped ID
|
||||||
* indicate an album or media group
|
* indicate an album or media group
|
||||||
|
@ -126,6 +193,15 @@ export class Message {
|
||||||
return parsePeer(from, this._peers)
|
return parsePeer(from, this._peers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of boosts applied to this {@link chat} by the sender
|
||||||
|
*/
|
||||||
|
get senderBoostCount(): number {
|
||||||
|
if (this.raw._ !== 'message') return 0
|
||||||
|
|
||||||
|
return this.raw.fromBoostsApplied ?? 0
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Conversation the message belongs to
|
* Conversation the message belongs to
|
||||||
*/
|
*/
|
||||||
|
@ -134,12 +210,21 @@ export class Message {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Date the message was sent
|
* Date when the message was sent
|
||||||
*/
|
*/
|
||||||
get date(): Date {
|
get date(): Date {
|
||||||
return new Date(this.raw.date * 1000)
|
return new Date(this.raw.date * 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date when the message was last edited
|
||||||
|
*/
|
||||||
|
get editDate(): Date | null {
|
||||||
|
if (this.raw._ === 'messageService') return null
|
||||||
|
|
||||||
|
return this.raw.editDate ? new Date(this.raw.editDate * 1000) : null
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If this message is a forward, contains info about it.
|
* If this message is a forward, contains info about it.
|
||||||
*/
|
*/
|
||||||
|
@ -213,6 +298,17 @@ export class Message {
|
||||||
return this.raw.mentioned!
|
return this.raw.mentioned!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If non-null, this message is not actually sent, and is
|
||||||
|
* instead inside a group of "quick reply" messages
|
||||||
|
* under the given shortcut ID
|
||||||
|
*/
|
||||||
|
get quickReplyShortcutId(): number | null {
|
||||||
|
if (this.raw._ === 'messageService') return null
|
||||||
|
|
||||||
|
return this.raw.quickReplyShortcutId ?? null
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If this message is generated from an inline query,
|
* If this message is generated from an inline query,
|
||||||
* information about the bot which generated it
|
* information about the bot which generated it
|
||||||
|
@ -225,6 +321,20 @@ export class Message {
|
||||||
return new User(this._peers.user(this.raw.viaBotId))
|
return new User(this._peers.user(this.raw.viaBotId))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this message was sent by a business bot on behalf of {@link sender},
|
||||||
|
* information about the business bot.
|
||||||
|
*
|
||||||
|
* **Note**: only available to the business account and the bot itself.
|
||||||
|
*/
|
||||||
|
get viaBusinessBot(): User | null {
|
||||||
|
if (this.raw._ === 'messageService' || !this.raw.viaBusinessBotId) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return new User(this._peers.user(this.raw.viaBusinessBotId))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Message text or media caption.
|
* Message text or media caption.
|
||||||
*
|
*
|
||||||
|
|
50
packages/core/src/highlevel/types/misc/collectible-info.ts
Normal file
50
packages/core/src/highlevel/types/misc/collectible-info.ts
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
import Long from 'long'
|
||||||
|
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { makeInspectable } from '../../utils/inspectable.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about a Fragment collectible
|
||||||
|
*/
|
||||||
|
export class CollectibleInfo {
|
||||||
|
constructor(readonly raw: tl.fragment.RawCollectibleInfo) {}
|
||||||
|
|
||||||
|
/** Date when the item was purchased */
|
||||||
|
get purchaseDate(): Date {
|
||||||
|
return new Date(this.raw.purchaseDate * 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Crypto currency used to purchase the item */
|
||||||
|
get cryptoCurrency(): string {
|
||||||
|
return this.raw.cryptoCurrency
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Amount of crypto currency used to purchase the item,
|
||||||
|
* in the smallest units
|
||||||
|
*/
|
||||||
|
get cryptoAmount(): Long {
|
||||||
|
return this.raw.cryptoAmount
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Fiat currency to which the crypto currency was converted */
|
||||||
|
get currency(): string {
|
||||||
|
return this.raw.currency
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converted amount in fiat currency,
|
||||||
|
* in the smallest units (e.g. cents)
|
||||||
|
*/
|
||||||
|
get amount(): Long {
|
||||||
|
return this.raw.amount
|
||||||
|
}
|
||||||
|
|
||||||
|
/** URL to the collectible on Fragment */
|
||||||
|
get url(): string {
|
||||||
|
return this.raw.url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
makeInspectable(CollectibleInfo)
|
|
@ -15,3 +15,17 @@ export interface TextWithEntities {
|
||||||
* Can be either a plain string or an object with `text` and `entities` fields.
|
* Can be either a plain string or an object with `text` and `entities` fields.
|
||||||
*/
|
*/
|
||||||
export type InputText = string | TextWithEntities
|
export type InputText = string | TextWithEntities
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert {@link InputText} to a {@link tl.RawTextWithEntities} object
|
||||||
|
*
|
||||||
|
* @param text Input text
|
||||||
|
* @returns TL object
|
||||||
|
*/
|
||||||
|
export function inputTextToTl(text: InputText): tl.RawTextWithEntities {
|
||||||
|
return {
|
||||||
|
_: 'textWithEntities',
|
||||||
|
text: typeof text === 'string' ? text : text.text,
|
||||||
|
entities: typeof text === 'string' ? [] : text.entities ?? [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
export * from './app-config.js'
|
export * from './app-config.js'
|
||||||
|
export * from './collectible-info.js'
|
||||||
export * from './entities.js'
|
export * from './entities.js'
|
||||||
export * from './input-privacy-rule/index.js'
|
export * from './input-privacy-rule/index.js'
|
||||||
export * from './sticker-set.js'
|
export * from './sticker-set.js'
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { makeInspectable } from '../../utils/index.js'
|
||||||
import { memoizeGetters } from '../../utils/memoize.js'
|
import { memoizeGetters } from '../../utils/memoize.js'
|
||||||
import { MtEmptyError } from '../errors.js'
|
import { MtEmptyError } from '../errors.js'
|
||||||
import { InputFileLike } from '../files/index.js'
|
import { InputFileLike } from '../files/index.js'
|
||||||
import { parseDocument } from '../media/document-utils.js'
|
import { parseSticker } from '../media/document-utils.js'
|
||||||
import { MaskPosition, Sticker, StickerSourceType, StickerType, Thumbnail } from '../media/index.js'
|
import { MaskPosition, Sticker, StickerSourceType, StickerType, Thumbnail } from '../media/index.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -98,24 +98,38 @@ export interface StickerInfo {
|
||||||
readonly sticker: Sticker
|
readonly sticker: Sticker
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parseStickerOrThrow(doc: tl.RawDocument): Sticker {
|
||||||
|
const sticker = parseSticker(doc)
|
||||||
|
|
||||||
|
if (!sticker) {
|
||||||
|
throw new MtTypeAssertionError('full.documents', 'sticker', 'not a sticker')
|
||||||
|
}
|
||||||
|
|
||||||
|
return sticker
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A sticker set (aka sticker pack)
|
* A sticker set (aka sticker pack)
|
||||||
*/
|
*/
|
||||||
export class StickerSet {
|
export class StickerSet {
|
||||||
readonly brief: tl.RawStickerSet
|
readonly brief: tl.RawStickerSet
|
||||||
readonly full?: tl.messages.RawStickerSet
|
readonly full?: tl.messages.RawStickerSet
|
||||||
|
readonly cover?: tl.TypeStickerSetCovered
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this object contains information about stickers inside the set
|
* Whether this object contains information about stickers inside the set
|
||||||
*/
|
*/
|
||||||
readonly isFull: boolean
|
readonly isFull: boolean
|
||||||
|
|
||||||
constructor(raw: tl.TypeStickerSet | tl.messages.TypeStickerSet) {
|
constructor(raw: tl.TypeStickerSet | tl.messages.TypeStickerSet | tl.TypeStickerSetCovered) {
|
||||||
if (raw._ === 'messages.stickerSet') {
|
if (raw._ === 'messages.stickerSet') {
|
||||||
this.full = raw
|
this.full = raw
|
||||||
this.brief = raw.set
|
this.brief = raw.set
|
||||||
} else if (raw._ === 'stickerSet') {
|
} else if (raw._ === 'stickerSet') {
|
||||||
this.brief = raw
|
this.brief = raw
|
||||||
|
} else if (tl.isAnyStickerSetCovered(raw)) {
|
||||||
|
this.cover = raw
|
||||||
|
this.brief = raw.set
|
||||||
} else {
|
} else {
|
||||||
throw new MtTypeAssertionError('StickerSet', 'messages.stickerSet | stickerSet', raw._)
|
throw new MtTypeAssertionError('StickerSet', 'messages.stickerSet | stickerSet', raw._)
|
||||||
}
|
}
|
||||||
|
@ -138,6 +152,13 @@ export class StickerSet {
|
||||||
return this.brief.official!
|
return this.brief.official!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this sticker set was created by the current user
|
||||||
|
*/
|
||||||
|
get isCreator(): boolean {
|
||||||
|
return this.brief.creator!
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type of the stickers in this set
|
* Type of the stickers in this set
|
||||||
*/
|
*/
|
||||||
|
@ -215,17 +236,13 @@ export class StickerSet {
|
||||||
* In case this object does not contain info about stickers (i.e. {@link isFull} = false)
|
* In case this object does not contain info about stickers (i.e. {@link isFull} = false)
|
||||||
*/
|
*/
|
||||||
get stickers(): ReadonlyArray<StickerInfo> {
|
get stickers(): ReadonlyArray<StickerInfo> {
|
||||||
if (!this.isFull) throw new MtEmptyError()
|
if (!this.full) throw new MtEmptyError()
|
||||||
|
|
||||||
const stickers: StickerInfo[] = []
|
const stickers: StickerInfo[] = []
|
||||||
const index = new LongMap<tl.Mutable<StickerInfo>>()
|
const index = new LongMap<tl.Mutable<StickerInfo>>()
|
||||||
|
|
||||||
this.full!.documents.forEach((doc) => {
|
this.full.documents.forEach((doc) => {
|
||||||
const sticker = parseDocument(doc as tl.RawDocument)
|
const sticker = parseStickerOrThrow(doc as tl.RawDocument)
|
||||||
|
|
||||||
if (!(sticker instanceof Sticker)) {
|
|
||||||
throw new MtTypeAssertionError('full.documents', 'Sticker', sticker.mimeType)
|
|
||||||
}
|
|
||||||
|
|
||||||
const info: tl.Mutable<StickerInfo> = {
|
const info: tl.Mutable<StickerInfo> = {
|
||||||
alt: sticker.emoji,
|
alt: sticker.emoji,
|
||||||
|
@ -236,7 +253,7 @@ export class StickerSet {
|
||||||
index.set(doc.id, info)
|
index.set(doc.id, info)
|
||||||
})
|
})
|
||||||
|
|
||||||
this.full!.packs.forEach((pack) => {
|
this.full.packs.forEach((pack) => {
|
||||||
pack.documents.forEach((id) => {
|
pack.documents.forEach((id) => {
|
||||||
const item = index.get(id)
|
const item = index.get(id)
|
||||||
|
|
||||||
|
@ -249,6 +266,22 @@ export class StickerSet {
|
||||||
return stickers
|
return stickers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Cover stickers of the sticker set. Not the same as {@link thumbnails} */
|
||||||
|
get covers(): ReadonlyArray<Sticker> {
|
||||||
|
if (!this.cover) return []
|
||||||
|
|
||||||
|
switch (this.cover._) {
|
||||||
|
case 'stickerSetCovered':
|
||||||
|
return [parseStickerOrThrow(this.cover.cover as tl.RawDocument)]
|
||||||
|
case 'stickerSetMultiCovered':
|
||||||
|
return this.cover.covers.map((it) => parseStickerOrThrow(it as tl.RawDocument))
|
||||||
|
case 'stickerSetFullCovered':
|
||||||
|
return this.cover.documents.map((it) => parseStickerOrThrow(it as tl.RawDocument))
|
||||||
|
case 'stickerSetNoCovered':
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Available sticker set thumbnails.
|
* Available sticker set thumbnails.
|
||||||
*
|
*
|
||||||
|
|
|
@ -4,11 +4,9 @@ import { MtArgumentError, MtTypeAssertionError } from '../../../types/errors.js'
|
||||||
import { getMarkedPeerId } from '../../../utils/peer-utils.js'
|
import { getMarkedPeerId } from '../../../utils/peer-utils.js'
|
||||||
import { makeInspectable } from '../../utils/index.js'
|
import { makeInspectable } from '../../utils/index.js'
|
||||||
import { memoizeGetters } from '../../utils/memoize.js'
|
import { memoizeGetters } from '../../utils/memoize.js'
|
||||||
import { Photo } from '../media/photo.js'
|
|
||||||
import { MessageEntity } from '../messages/message-entity.js'
|
import { MessageEntity } from '../messages/message-entity.js'
|
||||||
import { EmojiStatus } from '../reactions/emoji-status.js'
|
import { EmojiStatus } from '../reactions/emoji-status.js'
|
||||||
import { ChatColors } from './chat-colors.js'
|
import { ChatColors } from './chat-colors.js'
|
||||||
import { ChatLocation } from './chat-location.js'
|
|
||||||
import { ChatPermissions } from './chat-permissions.js'
|
import { ChatPermissions } from './chat-permissions.js'
|
||||||
import { ChatPhoto } from './chat-photo.js'
|
import { ChatPhoto } from './chat-photo.js'
|
||||||
import { PeersIndex } from './peers-index.js'
|
import { PeersIndex } from './peers-index.js'
|
||||||
|
@ -36,10 +34,7 @@ export class Chat {
|
||||||
*/
|
*/
|
||||||
readonly peer: tl.RawUser | tl.RawChat | tl.RawChannel | tl.RawChatForbidden | tl.RawChannelForbidden
|
readonly peer: tl.RawUser | tl.RawChat | tl.RawChannel | tl.RawChatForbidden | tl.RawChannelForbidden
|
||||||
|
|
||||||
constructor(
|
constructor(peer: tl.TypeUser | tl.TypeChat) {
|
||||||
peer: tl.TypeUser | tl.TypeChat,
|
|
||||||
readonly fullPeer?: tl.TypeUserFull | tl.TypeChatFull,
|
|
||||||
) {
|
|
||||||
if (!peer) throw new MtArgumentError('peer is not available')
|
if (!peer) throw new MtArgumentError('peer is not available')
|
||||||
|
|
||||||
switch (peer._) {
|
switch (peer._) {
|
||||||
|
@ -283,15 +278,6 @@ export class Chat {
|
||||||
return (this.peer._ === 'channel' || this.peer._ === 'chat') && this.peer.noforwards!
|
return (this.peer._ === 'channel' || this.peer._ === 'chat') && this.peer.noforwards!
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether this chat (user) has restricted sending them voice/video messages.
|
|
||||||
*
|
|
||||||
* Returned only in {@link TelegramClient.getFullChat}
|
|
||||||
*/
|
|
||||||
get hasBlockedVoices(): boolean {
|
|
||||||
return this.fullPeer?._ === 'userFull' && this.fullPeer.voiceMessagesForbidden!
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Title, for supergroups, channels and groups
|
* Title, for supergroups, channels and groups
|
||||||
*/
|
*/
|
||||||
|
@ -357,7 +343,7 @@ export class Chat {
|
||||||
* Chat photo, if any.
|
* Chat photo, if any.
|
||||||
* Suitable for downloads only.
|
* Suitable for downloads only.
|
||||||
*
|
*
|
||||||
* If full chat information is available, prefer {@link fullPhoto} instead.
|
* If full chat information is available, prefer {@link FullChat#fullPhoto} instead.
|
||||||
*/
|
*/
|
||||||
get photo(): ChatPhoto | null {
|
get photo(): ChatPhoto | null {
|
||||||
if (
|
if (
|
||||||
|
@ -371,89 +357,6 @@ export class Chat {
|
||||||
return new ChatPhoto(this.inputPeer, this.peer.photo)
|
return new ChatPhoto(this.inputPeer, this.peer.photo)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Full information about this chat's photo, if any.
|
|
||||||
*
|
|
||||||
* Unlike {@link Chat.photo}, this field contains additional information
|
|
||||||
* about the photo, such as its date, more sizes, and is the only
|
|
||||||
* way to get the animated profile photo.
|
|
||||||
*
|
|
||||||
* This field takes into account any personal/fallback photo
|
|
||||||
* that the user may have set
|
|
||||||
*
|
|
||||||
* Only available in {@link TelegramClient.getFullChat}
|
|
||||||
*/
|
|
||||||
get fullPhoto(): Photo | null {
|
|
||||||
if (!this.fullPeer) return null
|
|
||||||
|
|
||||||
let photo: tl.TypePhoto | undefined = undefined
|
|
||||||
|
|
||||||
switch (this.fullPeer._) {
|
|
||||||
case 'userFull':
|
|
||||||
photo = this.fullPeer.personalPhoto ?? this.fullPeer.profilePhoto ?? this.fullPeer.fallbackPhoto
|
|
||||||
break
|
|
||||||
case 'chatFull':
|
|
||||||
case 'channelFull':
|
|
||||||
photo = this.fullPeer.chatPhoto
|
|
||||||
}
|
|
||||||
|
|
||||||
if (photo?._ !== 'photo') return null
|
|
||||||
|
|
||||||
return new Photo(photo)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A custom photo (set by the current user) that should be displayed
|
|
||||||
* instead of the actual chat photo.
|
|
||||||
*
|
|
||||||
* Currently only available for users.
|
|
||||||
* Returned only in {@link TelegramClient.getFullChat}
|
|
||||||
*/
|
|
||||||
get personalPhoto(): Photo | null {
|
|
||||||
if (!this.fullPeer || this.fullPeer._ !== 'userFull') return null
|
|
||||||
if (this.fullPeer.personalPhoto?._ !== 'photo') return null
|
|
||||||
|
|
||||||
return new Photo(this.fullPeer.personalPhoto)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Actual profile photo of the user, bypassing the custom one.
|
|
||||||
*
|
|
||||||
* Returned only in {@link TelegramClient.getFullChat}
|
|
||||||
*/
|
|
||||||
get realPhoto(): Photo | null {
|
|
||||||
if (!this.fullPeer) return null
|
|
||||||
if (this.fullPeer._ !== 'userFull') return this.fullPhoto
|
|
||||||
if (this.fullPeer.personalPhoto?._ !== 'photo') return null
|
|
||||||
|
|
||||||
return new Photo(this.fullPeer.personalPhoto)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A photo that the user has set to be shown
|
|
||||||
* in case their actual profile photo is not available
|
|
||||||
* due to privacy settings.
|
|
||||||
*
|
|
||||||
* Currently only available for users.
|
|
||||||
* Returned only in {@link TelegramClient.getFullChat}
|
|
||||||
*/
|
|
||||||
get publicPhoto(): Photo | null {
|
|
||||||
if (!this.fullPeer || this.fullPeer._ !== 'userFull') return null
|
|
||||||
if (this.fullPeer.fallbackPhoto?._ !== 'photo') return null
|
|
||||||
|
|
||||||
return new Photo(this.fullPeer.fallbackPhoto)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bio of the other party in a private chat, or description of a
|
|
||||||
* group, supergroup or channel.
|
|
||||||
*
|
|
||||||
* Returned only in {@link TelegramClient.getFullChat}
|
|
||||||
*/
|
|
||||||
get bio(): string | null {
|
|
||||||
return this.fullPeer?.about ?? null
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User's or bot's assigned DC (data center).
|
* User's or bot's assigned DC (data center).
|
||||||
* Available only in case the user has set a public profile photo.
|
* Available only in case the user has set a public profile photo.
|
||||||
|
@ -472,55 +375,6 @@ export class Chat {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Chat's permanent invite link, for groups, supergroups and channels.
|
|
||||||
* Returned only in {@link TelegramClient.getFullChat}
|
|
||||||
*/
|
|
||||||
get inviteLink(): string | null {
|
|
||||||
if (this.fullPeer && this.fullPeer._ !== 'userFull') {
|
|
||||||
switch (this.fullPeer.exportedInvite?._) {
|
|
||||||
case 'chatInvitePublicJoinRequests':
|
|
||||||
return null
|
|
||||||
case 'chatInviteExported':
|
|
||||||
return this.fullPeer.exportedInvite.link
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For supergroups, name of the group sticker set.
|
|
||||||
* Returned only in {@link TelegramClient.getFullChat}
|
|
||||||
*/
|
|
||||||
get stickerSetName(): string | null {
|
|
||||||
return this.fullPeer && this.fullPeer._ === 'channelFull' ? this.fullPeer.stickerset?.shortName ?? null : null
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the group sticker set can be changed by you.
|
|
||||||
* Returned only in {@link TelegramClient.getFullChat}
|
|
||||||
*/
|
|
||||||
get canSetStickerSet(): boolean | null {
|
|
||||||
return this.fullPeer && this.fullPeer._ === 'channelFull' ? this.fullPeer.canSetStickers ?? null : null
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Chat members count, for groups, supergroups and channels only.
|
|
||||||
* Returned only in {@link TelegramClient.getFullChat}
|
|
||||||
*/
|
|
||||||
get membersCount(): number | null {
|
|
||||||
if (this.fullPeer && this.fullPeer._ !== 'userFull') {
|
|
||||||
if (this.fullPeer._ === 'chatFull' && this.fullPeer.participants._ === 'chatParticipants') {
|
|
||||||
return this.fullPeer.participants.participants.length
|
|
||||||
} else if (this.fullPeer._ === 'channelFull') {
|
|
||||||
return this.fullPeer.participantsCount ?? null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The list of reasons why this chat might be unavailable to some users.
|
* The list of reasons why this chat might be unavailable to some users.
|
||||||
* This field is available only in case {@link isRestricted} is `true`
|
* This field is available only in case {@link isRestricted} is `true`
|
||||||
|
@ -565,38 +419,6 @@ export class Chat {
|
||||||
*/
|
*/
|
||||||
readonly distance?: number
|
readonly distance?: number
|
||||||
|
|
||||||
/**
|
|
||||||
* Location of the chat.
|
|
||||||
* Returned only in {@link TelegramClient.getFullChat}
|
|
||||||
*/
|
|
||||||
get location(): ChatLocation | null {
|
|
||||||
if (!this.fullPeer || this.fullPeer._ !== 'channelFull' || this.fullPeer.location?._ !== 'channelLocation') {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ChatLocation(this.fullPeer.location)
|
|
||||||
}
|
|
||||||
|
|
||||||
private _linkedChat?: Chat
|
|
||||||
/**
|
|
||||||
* The linked discussion group (in case of channels)
|
|
||||||
* or the linked channel (in case of supergroups).
|
|
||||||
*
|
|
||||||
* Returned only in {@link TelegramClient.getFullChat}
|
|
||||||
*/
|
|
||||||
get linkedChat(): Chat | null {
|
|
||||||
return this._linkedChat ?? null
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TTL of all messages in this chat, in seconds
|
|
||||||
*
|
|
||||||
* Returned only in {@link TelegramClient.getFullChat}
|
|
||||||
*/
|
|
||||||
get ttlPeriod(): number | null {
|
|
||||||
return this.fullPeer?.ttlPeriod ?? null
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum ID of stories this chat has (or 0 if none)
|
* Maximum ID of stories this chat has (or 0 if none)
|
||||||
*/
|
*/
|
||||||
|
@ -676,37 +498,6 @@ export class Chat {
|
||||||
return new Chat(peers.chat(peer.channelId))
|
return new Chat(peers.chat(peer.channelId))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
static _parseFull(full: tl.messages.RawChatFull | tl.users.TypeUserFull): Chat {
|
|
||||||
if (full._ === 'users.userFull') {
|
|
||||||
const user = full.users.find((it) => it.id === full.fullUser.id)
|
|
||||||
|
|
||||||
if (!user || user._ === 'userEmpty') {
|
|
||||||
throw new MtTypeAssertionError('Chat._parseFull', 'user', user?._ ?? 'undefined')
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Chat(user, full.fullUser)
|
|
||||||
}
|
|
||||||
|
|
||||||
const fullChat = full.fullChat
|
|
||||||
let chat: tl.TypeChat | undefined = undefined
|
|
||||||
let linked: tl.TypeChat | undefined = undefined
|
|
||||||
|
|
||||||
for (const c of full.chats) {
|
|
||||||
if (fullChat.id === c.id) {
|
|
||||||
chat = c
|
|
||||||
}
|
|
||||||
if (fullChat._ === 'channelFull' && fullChat.linkedChatId === c.id) {
|
|
||||||
linked = c
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const ret = new Chat(chat!, fullChat)
|
|
||||||
ret._linkedChat = linked ? new Chat(linked) : undefined
|
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a mention for the chat.
|
* Create a mention for the chat.
|
||||||
*
|
*
|
||||||
|
@ -758,13 +549,8 @@ memoizeGetters(Chat, [
|
||||||
'chatType',
|
'chatType',
|
||||||
'usernames',
|
'usernames',
|
||||||
'photo',
|
'photo',
|
||||||
'fullPhoto',
|
|
||||||
'personalPhoto',
|
|
||||||
'realPhoto',
|
|
||||||
'publicPhoto',
|
|
||||||
'permissions',
|
'permissions',
|
||||||
'defaultPermissions',
|
'defaultPermissions',
|
||||||
'location',
|
|
||||||
'user',
|
'user',
|
||||||
'color',
|
'color',
|
||||||
])
|
])
|
||||||
|
|
265
packages/core/src/highlevel/types/peers/full-chat.ts
Normal file
265
packages/core/src/highlevel/types/peers/full-chat.ts
Normal file
|
@ -0,0 +1,265 @@
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { MtTypeAssertionError } from '../../../types/errors.js'
|
||||||
|
import { makeInspectable } from '../../utils/inspectable.js'
|
||||||
|
import { memoizeGetters } from '../../utils/memoize.js'
|
||||||
|
import { Photo } from '../media/photo.js'
|
||||||
|
import { StickerSet } from '../misc/sticker-set.js'
|
||||||
|
import { BusinessAccount } from '../premium/business-account.js'
|
||||||
|
import { Chat } from './chat.js'
|
||||||
|
import { ChatInviteLink } from './chat-invite-link.js'
|
||||||
|
import { ChatLocation } from './chat-location.js'
|
||||||
|
import { PeersIndex } from './peers-index.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Complete information about a particular chat.
|
||||||
|
*/
|
||||||
|
export class FullChat extends Chat {
|
||||||
|
constructor(
|
||||||
|
peer: tl.TypeUser | tl.TypeChat,
|
||||||
|
readonly fullPeer: tl.TypeUserFull | tl.TypeChatFull,
|
||||||
|
) {
|
||||||
|
super(peer)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
static _parse(full: tl.messages.RawChatFull | tl.users.TypeUserFull): FullChat {
|
||||||
|
const peers = PeersIndex.from(full)
|
||||||
|
|
||||||
|
if (full._ === 'users.userFull') {
|
||||||
|
const { fullUser } = full
|
||||||
|
const user = peers.user(full.fullUser.id)
|
||||||
|
|
||||||
|
if (!user || user._ === 'userEmpty') {
|
||||||
|
throw new MtTypeAssertionError('Chat._parseFull', 'user', user?._ ?? 'undefined')
|
||||||
|
}
|
||||||
|
|
||||||
|
const ret = new FullChat(user, fullUser)
|
||||||
|
|
||||||
|
if (fullUser.personalChannelId) {
|
||||||
|
ret._linkedChat = new Chat(peers.chat(fullUser.personalChannelId))
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
const { fullChat } = full
|
||||||
|
|
||||||
|
const ret = new FullChat(peers.chat(fullChat.id), fullChat)
|
||||||
|
|
||||||
|
if (fullChat._ === 'channelFull' && fullChat.linkedChatId) {
|
||||||
|
ret._linkedChat = new Chat(peers.chat(fullChat.linkedChatId))
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this chat (user) has restricted sending them voice/video messages.
|
||||||
|
*/
|
||||||
|
get hasBlockedVoices(): boolean {
|
||||||
|
return this.fullPeer?._ === 'userFull' && this.fullPeer.voiceMessagesForbidden!
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Full information about this chat's photo, if any.
|
||||||
|
*
|
||||||
|
* Unlike {@link Chat.photo}, this field contains additional information
|
||||||
|
* about the photo, such as its date, more sizes, and is the only
|
||||||
|
* way to get the animated profile photo.
|
||||||
|
*
|
||||||
|
* This field takes into account any personal/fallback photo
|
||||||
|
* that the user may have set
|
||||||
|
*/
|
||||||
|
get fullPhoto(): Photo | null {
|
||||||
|
if (!this.fullPeer) return null
|
||||||
|
|
||||||
|
let photo: tl.TypePhoto | undefined = undefined
|
||||||
|
|
||||||
|
switch (this.fullPeer._) {
|
||||||
|
case 'userFull':
|
||||||
|
photo = this.fullPeer.personalPhoto ?? this.fullPeer.profilePhoto ?? this.fullPeer.fallbackPhoto
|
||||||
|
break
|
||||||
|
case 'chatFull':
|
||||||
|
case 'channelFull':
|
||||||
|
photo = this.fullPeer.chatPhoto
|
||||||
|
}
|
||||||
|
|
||||||
|
if (photo?._ !== 'photo') return null
|
||||||
|
|
||||||
|
return new Photo(photo)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A custom photo (set by the current user) that should be displayed
|
||||||
|
* instead of the actual chat photo.
|
||||||
|
*
|
||||||
|
* Currently only available for users.
|
||||||
|
*/
|
||||||
|
get personalPhoto(): Photo | null {
|
||||||
|
if (!this.fullPeer || this.fullPeer._ !== 'userFull') return null
|
||||||
|
if (this.fullPeer.personalPhoto?._ !== 'photo') return null
|
||||||
|
|
||||||
|
return new Photo(this.fullPeer.personalPhoto)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actual profile photo of the user, bypassing the custom one.
|
||||||
|
*/
|
||||||
|
get realPhoto(): Photo | null {
|
||||||
|
if (!this.fullPeer) return null
|
||||||
|
if (this.fullPeer._ !== 'userFull') return this.fullPhoto
|
||||||
|
if (this.fullPeer.personalPhoto?._ !== 'photo') return null
|
||||||
|
|
||||||
|
return new Photo(this.fullPeer.personalPhoto)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A photo that the user has set to be shown
|
||||||
|
* in case their actual profile photo is not available
|
||||||
|
* due to privacy settings.
|
||||||
|
*
|
||||||
|
* Currently only available for users.
|
||||||
|
*/
|
||||||
|
get publicPhoto(): Photo | null {
|
||||||
|
if (!this.fullPeer || this.fullPeer._ !== 'userFull') return null
|
||||||
|
if (this.fullPeer.fallbackPhoto?._ !== 'photo') return null
|
||||||
|
|
||||||
|
return new Photo(this.fullPeer.fallbackPhoto)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bio of the other party in a private chat, or description of a
|
||||||
|
* group, supergroup or channel.
|
||||||
|
*/
|
||||||
|
get bio(): string | null {
|
||||||
|
return this.fullPeer?.about ?? null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chat's primary invite link, for groups, supergroups and channels.
|
||||||
|
*/
|
||||||
|
get inviteLink(): ChatInviteLink | null {
|
||||||
|
if (this.fullPeer && this.fullPeer._ !== 'userFull') {
|
||||||
|
switch (this.fullPeer.exportedInvite?._) {
|
||||||
|
case 'chatInvitePublicJoinRequests':
|
||||||
|
return null
|
||||||
|
case 'chatInviteExported':
|
||||||
|
return new ChatInviteLink(this.fullPeer.exportedInvite)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For supergroups, information about the group sticker set.
|
||||||
|
*/
|
||||||
|
get stickerSet(): StickerSet | null {
|
||||||
|
if (this.fullPeer?._ !== 'channelFull' || !this.fullPeer.stickerset) return null
|
||||||
|
|
||||||
|
return new StickerSet(this.fullPeer.stickerset)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For supergroups, information about the group emoji set.
|
||||||
|
*/
|
||||||
|
get emojiSet(): StickerSet | null {
|
||||||
|
if (this.fullPeer?._ !== 'channelFull' || !this.fullPeer.emojiset) return null
|
||||||
|
|
||||||
|
return new StickerSet(this.fullPeer.emojiset)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the group sticker set can be changed by you.
|
||||||
|
*/
|
||||||
|
get canSetStickerSet(): boolean | null {
|
||||||
|
return this.fullPeer && this.fullPeer._ === 'channelFull' ? this.fullPeer.canSetStickers ?? null : null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of boosts applied by the current user to this chat.
|
||||||
|
*/
|
||||||
|
get boostsApplied(): number {
|
||||||
|
if (!this.fullPeer || this.fullPeer._ !== 'channelFull') return 0
|
||||||
|
|
||||||
|
return this.fullPeer?.boostsApplied ?? 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of boosts required for the user to be unrestricted in this chat.
|
||||||
|
*/
|
||||||
|
get boostsForUnrestrict(): number {
|
||||||
|
if (!this.fullPeer || this.fullPeer._ !== 'channelFull') return 0
|
||||||
|
|
||||||
|
return this.fullPeer?.boostsUnrestrict ?? 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chat members count, for groups, supergroups and channels only.
|
||||||
|
*/
|
||||||
|
get membersCount(): number | null {
|
||||||
|
switch (this.fullPeer._) {
|
||||||
|
case 'userFull':
|
||||||
|
return null
|
||||||
|
case 'chatFull':
|
||||||
|
if (this.fullPeer.participants._ !== 'chatParticipants') {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.fullPeer.participants.participants.length
|
||||||
|
case 'channelFull':
|
||||||
|
return this.fullPeer.participantsCount ?? null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Location of the chat.
|
||||||
|
*/
|
||||||
|
get location(): ChatLocation | null {
|
||||||
|
if (!this.fullPeer || this.fullPeer._ !== 'channelFull' || this.fullPeer.location?._ !== 'channelLocation') {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ChatLocation(this.fullPeer.location)
|
||||||
|
}
|
||||||
|
|
||||||
|
private _linkedChat?: Chat
|
||||||
|
/**
|
||||||
|
* Information about a linked chat:
|
||||||
|
* - for channels: the discussion group
|
||||||
|
* - for supergroups: the linked channel
|
||||||
|
* - for users: the personal channel
|
||||||
|
*/
|
||||||
|
get linkedChat(): Chat | null {
|
||||||
|
return this._linkedChat ?? null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TTL of all messages in this chat, in seconds
|
||||||
|
*/
|
||||||
|
get ttlPeriod(): number | null {
|
||||||
|
return this.fullPeer?.ttlPeriod ?? null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this is a business account, information about the business.
|
||||||
|
*/
|
||||||
|
get business(): BusinessAccount | null {
|
||||||
|
if (!this.fullPeer || this.fullPeer._ !== 'userFull') return null
|
||||||
|
|
||||||
|
return new BusinessAccount(this.fullPeer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memoizeGetters(FullChat, [
|
||||||
|
'fullPhoto',
|
||||||
|
'personalPhoto',
|
||||||
|
'realPhoto',
|
||||||
|
'publicPhoto',
|
||||||
|
'location',
|
||||||
|
'stickerSet',
|
||||||
|
'emojiSet',
|
||||||
|
'business',
|
||||||
|
])
|
||||||
|
makeInspectable(FullChat)
|
|
@ -8,6 +8,7 @@ export * from './chat-permissions.js'
|
||||||
export * from './chat-photo.js'
|
export * from './chat-photo.js'
|
||||||
export * from './chat-preview.js'
|
export * from './chat-preview.js'
|
||||||
export * from './forum-topic.js'
|
export * from './forum-topic.js'
|
||||||
|
export * from './full-chat.js'
|
||||||
export * from './peer.js'
|
export * from './peer.js'
|
||||||
export * from './peers-index.js'
|
export * from './peers-index.js'
|
||||||
export * from './typing-status.js'
|
export * from './typing-status.js'
|
||||||
|
|
|
@ -108,6 +108,14 @@ export class User {
|
||||||
return this.raw.bot!
|
return this.raw.bot!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this user is a bot that can be connected to a
|
||||||
|
* Telegram Business account to receive its messages
|
||||||
|
*/
|
||||||
|
get isBusinessBot(): boolean {
|
||||||
|
return this.raw.botBusiness!
|
||||||
|
}
|
||||||
|
|
||||||
/** Whether this user is a bot that has access to all messages */
|
/** Whether this user is a bot that has access to all messages */
|
||||||
get isBotWithHistory(): boolean {
|
get isBotWithHistory(): boolean {
|
||||||
return this.raw.botChatHistory!
|
return this.raw.botChatHistory!
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { makeInspectable } from '../../utils/inspectable.js'
|
||||||
|
import { memoizeGetters } from '../../utils/memoize.js'
|
||||||
|
import { BusinessIntro } from './business-intro.js'
|
||||||
|
import { BusinessLocation } from './business-location.js'
|
||||||
|
import { BusinessWorkHours } from './business-work-hours.js'
|
||||||
|
|
||||||
|
/** Information about a business account */
|
||||||
|
export class BusinessAccount {
|
||||||
|
constructor(readonly info: tl.RawUserFull) {}
|
||||||
|
|
||||||
|
/** Introduction of the business account */
|
||||||
|
get intro(): BusinessIntro | null {
|
||||||
|
if (!this.info.businessIntro) return null
|
||||||
|
|
||||||
|
return new BusinessIntro(this.info.businessIntro)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Work hours of the business */
|
||||||
|
get workHours(): BusinessWorkHours | null {
|
||||||
|
if (!this.info.businessWorkHours) return null
|
||||||
|
|
||||||
|
return new BusinessWorkHours(this.info.businessWorkHours)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Location of the business */
|
||||||
|
get location(): BusinessLocation | null {
|
||||||
|
if (!this.info.businessLocation) return null
|
||||||
|
|
||||||
|
return new BusinessLocation(this.info.businessLocation)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Information about a greeting message */
|
||||||
|
get greetingMessage(): tl.TypeBusinessGreetingMessage | null {
|
||||||
|
return this.info.businessGreetingMessage ?? null
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Information about an "away" message */
|
||||||
|
get awayMessage(): tl.TypeBusinessAwayMessage | null {
|
||||||
|
return this.info.businessAwayMessage ?? null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memoizeGetters(BusinessAccount, ['intro', 'workHours', 'location'])
|
||||||
|
makeInspectable(BusinessAccount)
|
|
@ -0,0 +1,40 @@
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { makeInspectable } from '../../utils/inspectable.js'
|
||||||
|
import { memoizeGetters } from '../../utils/memoize.js'
|
||||||
|
import { MessageEntity } from '../messages/message-entity.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A business chat link, i.e. a link to start a chat with a pre-filled message.
|
||||||
|
*/
|
||||||
|
export class BusinessChatLink {
|
||||||
|
constructor(readonly raw: tl.RawBusinessChatLink) {}
|
||||||
|
|
||||||
|
/** The link itself */
|
||||||
|
get link(): string {
|
||||||
|
return this.raw.link
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Text to be inserted into the message input */
|
||||||
|
get text(): string {
|
||||||
|
return this.raw.message
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Entities for the text */
|
||||||
|
get entities(): MessageEntity[] {
|
||||||
|
return this.raw.entities?.map((x) => new MessageEntity(x)) ?? []
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Custom title for the link */
|
||||||
|
get title(): string | null {
|
||||||
|
return this.raw.title ?? null
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Number of clicks on the link */
|
||||||
|
get clicks(): number {
|
||||||
|
return this.raw.views
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
makeInspectable(BusinessChatLink)
|
||||||
|
memoizeGetters(BusinessChatLink, ['entities'])
|
|
@ -0,0 +1,49 @@
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { makeInspectable } from '../../utils/inspectable.js'
|
||||||
|
import { memoizeGetters } from '../../utils/memoize.js'
|
||||||
|
import { PeersIndex } from '../peers/peers-index.js'
|
||||||
|
import { User } from '../peers/user.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the connection of the bot with a business account.
|
||||||
|
*/
|
||||||
|
export class BusinessConnection {
|
||||||
|
constructor(
|
||||||
|
readonly raw: tl.TypeBotBusinessConnection,
|
||||||
|
readonly _peers: PeersIndex,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/** Whether the connection was removed by the user */
|
||||||
|
get isRemoved(): boolean {
|
||||||
|
return this.raw.disabled!
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ID of the connection */
|
||||||
|
get id(): string {
|
||||||
|
return this.raw.connectionId
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Datacenter ID of the connected user */
|
||||||
|
get dcId(): number {
|
||||||
|
return this.raw.dcId
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Date when the connection was created */
|
||||||
|
get date(): Date {
|
||||||
|
return new Date(this.raw.date * 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the bot can reply on behalf of the user */
|
||||||
|
get canReply(): boolean {
|
||||||
|
return this.raw.canReply!
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Business account user that created the business connection */
|
||||||
|
get user(): User {
|
||||||
|
return new User(this._peers.user(this.raw.userId))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
makeInspectable(BusinessConnection)
|
||||||
|
memoizeGetters(BusinessConnection, ['user'])
|
43
packages/core/src/highlevel/types/premium/business-intro.ts
Normal file
43
packages/core/src/highlevel/types/premium/business-intro.ts
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { makeInspectable } from '../../utils/inspectable.js'
|
||||||
|
import { memoizeGetters } from '../../utils/memoize.js'
|
||||||
|
import { parseDocument } from '../media/document-utils.js'
|
||||||
|
import { Sticker } from '../media/sticker.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about a "business intro" – text that is displayed
|
||||||
|
* when a user opens a chat with a business account for the first time.
|
||||||
|
*/
|
||||||
|
export class BusinessIntro {
|
||||||
|
constructor(readonly raw: tl.RawBusinessIntro) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Title of the intro.
|
||||||
|
*/
|
||||||
|
get title(): string {
|
||||||
|
return this.raw.title
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description of the intro.
|
||||||
|
*/
|
||||||
|
get description(): string {
|
||||||
|
return this.raw.description
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sticker of the intro.
|
||||||
|
*/
|
||||||
|
get sticker(): Sticker | null {
|
||||||
|
if (!this.raw.sticker || this.raw.sticker._ === 'documentEmpty') return null
|
||||||
|
|
||||||
|
const doc = parseDocument(this.raw.sticker)
|
||||||
|
if (doc.type !== 'sticker') return null
|
||||||
|
|
||||||
|
return doc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
makeInspectable(BusinessIntro)
|
||||||
|
memoizeGetters(BusinessIntro, ['sticker'])
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { makeInspectable } from '../../utils/inspectable.js'
|
||||||
|
import { memoizeGetters } from '../../utils/memoize.js'
|
||||||
|
import { Location } from '../media/location.js'
|
||||||
|
|
||||||
|
/** Location of a business */
|
||||||
|
export class BusinessLocation {
|
||||||
|
constructor(readonly raw: tl.RawBusinessLocation) {}
|
||||||
|
|
||||||
|
/** Address of the business */
|
||||||
|
get address(): string {
|
||||||
|
return this.raw.address
|
||||||
|
}
|
||||||
|
|
||||||
|
get location(): Location | null {
|
||||||
|
if (!this.raw.geoPoint || this.raw.geoPoint._ === 'geoPointEmpty') return null
|
||||||
|
|
||||||
|
return new Location(this.raw.geoPoint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
makeInspectable(BusinessLocation)
|
||||||
|
memoizeGetters(BusinessLocation, ['location'])
|
|
@ -0,0 +1,228 @@
|
||||||
|
import { describe, expect, it } from 'vitest'
|
||||||
|
|
||||||
|
import { createStub } from '@mtcute/test'
|
||||||
|
|
||||||
|
import { BusinessWorkHours, businessWorkHoursDaysToRaw } from './business-work-hours.js'
|
||||||
|
|
||||||
|
describe('BusinessWorkHours', () => {
|
||||||
|
describe('days', () => {
|
||||||
|
const mkHours = (intervals: [number, number][]) =>
|
||||||
|
createStub('businessWorkHours', {
|
||||||
|
weeklyOpen: intervals.map(([start, end]) =>
|
||||||
|
createStub('businessWeeklyOpen', {
|
||||||
|
startMinute: start,
|
||||||
|
endMinute: end,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle a single interval on Monday', () => {
|
||||||
|
const it = new BusinessWorkHours(mkHours([[0, 60]]))
|
||||||
|
|
||||||
|
expect(it.days).toEqual([
|
||||||
|
{ day: 0, is24h: false, intervals: [{ startHour: 0, startMinute: 0, endHour: 1, endMinute: 0 }] },
|
||||||
|
{ day: 1, is24h: false, intervals: [] },
|
||||||
|
{ day: 2, is24h: false, intervals: [] },
|
||||||
|
{ day: 3, is24h: false, intervals: [] },
|
||||||
|
{ day: 4, is24h: false, intervals: [] },
|
||||||
|
{ day: 5, is24h: false, intervals: [] },
|
||||||
|
{ day: 6, is24h: false, intervals: [] },
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle a single interval on Tuesday', () => {
|
||||||
|
const it = new BusinessWorkHours(mkHours([[1440, 1500]]))
|
||||||
|
|
||||||
|
expect(it.days).toEqual([
|
||||||
|
{ day: 0, is24h: false, intervals: [] },
|
||||||
|
{ day: 1, is24h: false, intervals: [{ startHour: 0, startMinute: 0, endHour: 1, endMinute: 0 }] },
|
||||||
|
{ day: 2, is24h: false, intervals: [] },
|
||||||
|
{ day: 3, is24h: false, intervals: [] },
|
||||||
|
{ day: 4, is24h: false, intervals: [] },
|
||||||
|
{ day: 5, is24h: false, intervals: [] },
|
||||||
|
{ day: 6, is24h: false, intervals: [] },
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle multiple intervals within a day', () => {
|
||||||
|
const it = new BusinessWorkHours(
|
||||||
|
mkHours([
|
||||||
|
[0, 60],
|
||||||
|
[120, 180],
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(it.days).toEqual([
|
||||||
|
{
|
||||||
|
day: 0,
|
||||||
|
is24h: false,
|
||||||
|
intervals: [
|
||||||
|
{ startHour: 0, startMinute: 0, endHour: 1, endMinute: 0 },
|
||||||
|
{ startHour: 2, startMinute: 0, endHour: 3, endMinute: 0 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ day: 1, is24h: false, intervals: [] },
|
||||||
|
{ day: 2, is24h: false, intervals: [] },
|
||||||
|
{ day: 3, is24h: false, intervals: [] },
|
||||||
|
{ day: 4, is24h: false, intervals: [] },
|
||||||
|
{ day: 5, is24h: false, intervals: [] },
|
||||||
|
{ day: 6, is24h: false, intervals: [] },
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle multiple intervals across different days', () => {
|
||||||
|
const it = new BusinessWorkHours(
|
||||||
|
mkHours([
|
||||||
|
[0, 60],
|
||||||
|
[25 * 60 + 30, 26 * 60 + 30],
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(it.days).toEqual([
|
||||||
|
{ day: 0, is24h: false, intervals: [{ startHour: 0, startMinute: 0, endHour: 1, endMinute: 0 }] },
|
||||||
|
{ day: 1, is24h: false, intervals: [{ startHour: 1, startMinute: 30, endHour: 2, endMinute: 30 }] },
|
||||||
|
{ day: 2, is24h: false, intervals: [] },
|
||||||
|
{ day: 3, is24h: false, intervals: [] },
|
||||||
|
{ day: 4, is24h: false, intervals: [] },
|
||||||
|
{ day: 5, is24h: false, intervals: [] },
|
||||||
|
{ day: 6, is24h: false, intervals: [] },
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle a single interval spanning multiple days', () => {
|
||||||
|
const it = new BusinessWorkHours(mkHours([[0, 1500]]))
|
||||||
|
|
||||||
|
expect(it.days).toEqual([
|
||||||
|
{ day: 0, is24h: true, intervals: [{ startHour: 0, startMinute: 0, endHour: 24, endMinute: 0 }] },
|
||||||
|
{ day: 1, is24h: false, intervals: [{ startHour: 0, startMinute: 0, endHour: 1, endMinute: 0 }] },
|
||||||
|
{ day: 2, is24h: false, intervals: [] },
|
||||||
|
{ day: 3, is24h: false, intervals: [] },
|
||||||
|
{ day: 4, is24h: false, intervals: [] },
|
||||||
|
{ day: 5, is24h: false, intervals: [] },
|
||||||
|
{ day: 6, is24h: false, intervals: [] },
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle a single 7-day interval', () => {
|
||||||
|
const it = new BusinessWorkHours(mkHours([[0, 7 * 24 * 60]]))
|
||||||
|
|
||||||
|
expect(it.days).toEqual([
|
||||||
|
{ day: 0, is24h: true, intervals: [{ startHour: 0, startMinute: 0, endHour: 24, endMinute: 0 }] },
|
||||||
|
{ day: 1, is24h: true, intervals: [{ startHour: 0, startMinute: 0, endHour: 24, endMinute: 0 }] },
|
||||||
|
{ day: 2, is24h: true, intervals: [{ startHour: 0, startMinute: 0, endHour: 24, endMinute: 0 }] },
|
||||||
|
{ day: 3, is24h: true, intervals: [{ startHour: 0, startMinute: 0, endHour: 24, endMinute: 0 }] },
|
||||||
|
{ day: 4, is24h: true, intervals: [{ startHour: 0, startMinute: 0, endHour: 24, endMinute: 0 }] },
|
||||||
|
{ day: 5, is24h: true, intervals: [{ startHour: 0, startMinute: 0, endHour: 24, endMinute: 0 }] },
|
||||||
|
{ day: 6, is24h: true, intervals: [{ startHour: 0, startMinute: 0, endHour: 24, endMinute: 0 }] },
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle multiple intervals each spanning multiple days', () => {
|
||||||
|
const it = new BusinessWorkHours(
|
||||||
|
mkHours([
|
||||||
|
[0, 2 * 24 * 60],
|
||||||
|
[4 * 24 * 60, 6 * 24 * 60],
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(it.days).toEqual([
|
||||||
|
{ day: 0, is24h: true, intervals: [{ startHour: 0, startMinute: 0, endHour: 24, endMinute: 0 }] },
|
||||||
|
{ day: 1, is24h: true, intervals: [{ startHour: 0, startMinute: 0, endHour: 24, endMinute: 0 }] },
|
||||||
|
{ day: 2, is24h: false, intervals: [] },
|
||||||
|
{ day: 3, is24h: false, intervals: [] },
|
||||||
|
{ day: 4, is24h: true, intervals: [{ startHour: 0, startMinute: 0, endHour: 24, endMinute: 0 }] },
|
||||||
|
{ day: 5, is24h: true, intervals: [{ startHour: 0, startMinute: 0, endHour: 24, endMinute: 0 }] },
|
||||||
|
{ day: 6, is24h: false, intervals: [] },
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle overlapping intervals', () => {
|
||||||
|
const it = new BusinessWorkHours(
|
||||||
|
mkHours([
|
||||||
|
[0, 60],
|
||||||
|
[30, 90],
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(it.days).toEqual([
|
||||||
|
{ day: 0, is24h: false, intervals: [{ startHour: 0, startMinute: 0, endHour: 1, endMinute: 30 }] },
|
||||||
|
{ day: 1, is24h: false, intervals: [] },
|
||||||
|
{ day: 2, is24h: false, intervals: [] },
|
||||||
|
{ day: 3, is24h: false, intervals: [] },
|
||||||
|
{ day: 4, is24h: false, intervals: [] },
|
||||||
|
{ day: 5, is24h: false, intervals: [] },
|
||||||
|
{ day: 6, is24h: false, intervals: [] },
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle adjascent intervals', () => {
|
||||||
|
const it = new BusinessWorkHours(
|
||||||
|
mkHours([
|
||||||
|
[0, 60],
|
||||||
|
[60, 90],
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(it.days).toEqual([
|
||||||
|
{ day: 0, is24h: false, intervals: [{ startHour: 0, startMinute: 0, endHour: 1, endMinute: 30 }] },
|
||||||
|
{ day: 1, is24h: false, intervals: [] },
|
||||||
|
{ day: 2, is24h: false, intervals: [] },
|
||||||
|
{ day: 3, is24h: false, intervals: [] },
|
||||||
|
{ day: 4, is24h: false, intervals: [] },
|
||||||
|
{ day: 5, is24h: false, intervals: [] },
|
||||||
|
{ day: 6, is24h: false, intervals: [] },
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle magic 8th day', () => {
|
||||||
|
const it = new BusinessWorkHours(
|
||||||
|
mkHours([
|
||||||
|
// Mon 12:00 - 14:00
|
||||||
|
[12 * 60, 14 * 60],
|
||||||
|
// Sun 0:00 - Mon (next week) 2:00
|
||||||
|
[6 * 24 * 60 + 20 * 60, 7 * 24 * 60 + 2 * 60],
|
||||||
|
// Mon (next week) 3:00 - Mon (next week) 4:00
|
||||||
|
[7 * 24 * 60 + 3 * 60, 7 * 24 * 60 + 4 * 60],
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(it.days).toEqual([
|
||||||
|
{
|
||||||
|
day: 0,
|
||||||
|
is24h: false,
|
||||||
|
intervals: [
|
||||||
|
{ startHour: 0, startMinute: 0, endHour: 2, endMinute: 0 },
|
||||||
|
{ startHour: 3, startMinute: 0, endHour: 4, endMinute: 0 },
|
||||||
|
{ startHour: 12, startMinute: 0, endHour: 14, endMinute: 0 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ day: 1, is24h: false, intervals: [] },
|
||||||
|
{ day: 2, is24h: false, intervals: [] },
|
||||||
|
{ day: 3, is24h: false, intervals: [] },
|
||||||
|
{ day: 4, is24h: false, intervals: [] },
|
||||||
|
{ day: 5, is24h: false, intervals: [] },
|
||||||
|
{ day: 6, is24h: false, intervals: [{ startHour: 20, startMinute: 0, endHour: 24, endMinute: 0 }] },
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('businessWorkHoursDaysToRaw', () => {
|
||||||
|
it('should handle 24-hour days', () => {
|
||||||
|
expect(businessWorkHoursDaysToRaw([{ day: 0, is24h: true, intervals: [] }])).toEqual([
|
||||||
|
{ _: 'businessWeeklyOpen', startMinute: 0, endMinute: 1440 },
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle intervals', () => {
|
||||||
|
expect(
|
||||||
|
businessWorkHoursDaysToRaw([
|
||||||
|
{ day: 0, is24h: false, intervals: [{ startHour: 0, startMinute: 0, endHour: 1, endMinute: 0 }] },
|
||||||
|
{ day: 3, is24h: false, intervals: [{ startHour: 12, startMinute: 0, endHour: 14, endMinute: 0 }] },
|
||||||
|
]),
|
||||||
|
).toEqual([
|
||||||
|
{ _: 'businessWeeklyOpen', startMinute: 0, endMinute: 60 },
|
||||||
|
{ _: 'businessWeeklyOpen', startMinute: 3 * 24 * 60 + 12 * 60, endMinute: 3 * 24 * 60 + 14 * 60 },
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
191
packages/core/src/highlevel/types/premium/business-work-hours.ts
Normal file
191
packages/core/src/highlevel/types/premium/business-work-hours.ts
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { MtArgumentError } from '../../../types/errors.js'
|
||||||
|
import { makeInspectable } from '../../utils/inspectable.js'
|
||||||
|
import { memoizeGetters } from '../../utils/memoize.js'
|
||||||
|
|
||||||
|
export interface BusinessWorkHoursInterval {
|
||||||
|
/** Start hour of the interval (0-23) */
|
||||||
|
readonly startHour: number
|
||||||
|
/** Start minute of the interval (0-59) */
|
||||||
|
readonly startMinute: number
|
||||||
|
|
||||||
|
/** End hour of the interval (0-23) */
|
||||||
|
readonly endHour: number
|
||||||
|
/** End minute of the interval (0-59) */
|
||||||
|
readonly endMinute: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BusinessWorkHoursDay {
|
||||||
|
/** Day of the week, 0-6, where 0 is Monday and 6 is Sunday */
|
||||||
|
readonly day: number
|
||||||
|
|
||||||
|
/** Whether this day is open 24 hours */
|
||||||
|
readonly is24h: boolean
|
||||||
|
|
||||||
|
/** Open intervals for this day */
|
||||||
|
readonly intervals: BusinessWorkHoursInterval[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const DAYS_IN_WEEK = 7
|
||||||
|
const MINUTES_IN_DAY = 24 * 60
|
||||||
|
|
||||||
|
export function businessWorkHoursDaysToRaw(day: ReadonlyArray<BusinessWorkHoursDay>): tl.TypeBusinessWeeklyOpen[] {
|
||||||
|
const res: tl.TypeBusinessWeeklyOpen[] = []
|
||||||
|
|
||||||
|
for (const d of day) {
|
||||||
|
const dayStart = d.day * MINUTES_IN_DAY
|
||||||
|
|
||||||
|
if (d.is24h) {
|
||||||
|
res.push({
|
||||||
|
_: 'businessWeeklyOpen',
|
||||||
|
startMinute: dayStart,
|
||||||
|
endMinute: dayStart + MINUTES_IN_DAY,
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const interval of d.intervals) {
|
||||||
|
const start = dayStart + interval.startHour * 60 + interval.startMinute
|
||||||
|
const end = dayStart + interval.endHour * 60 + interval.endMinute
|
||||||
|
|
||||||
|
if (start >= end) {
|
||||||
|
throw new MtArgumentError('startMinute >= endMinute')
|
||||||
|
}
|
||||||
|
|
||||||
|
res.push({
|
||||||
|
_: 'businessWeeklyOpen',
|
||||||
|
startMinute: start,
|
||||||
|
endMinute: end,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about business work hours.
|
||||||
|
*/
|
||||||
|
export class BusinessWorkHours {
|
||||||
|
constructor(readonly raw: tl.RawBusinessWorkHours) {}
|
||||||
|
|
||||||
|
/** Whether the business is open right now */
|
||||||
|
get isOpenNow(): boolean {
|
||||||
|
return this.raw.openNow!
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifier of the time zone in which the {@link hours} are defined,
|
||||||
|
* in the IANA format.
|
||||||
|
*/
|
||||||
|
get timezoneId(): string {
|
||||||
|
return this.raw.timezoneId
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Raw "open" intervals */
|
||||||
|
get intervals(): tl.TypeBusinessWeeklyOpen[] {
|
||||||
|
return this.raw.weeklyOpen
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parsed business hours intervals per week day.
|
||||||
|
*
|
||||||
|
* @returns Array of 7 elements, each representing a day of the week (starting from Monday = 0)
|
||||||
|
*/
|
||||||
|
get days(): ReadonlyArray<BusinessWorkHoursDay> {
|
||||||
|
const days: BusinessWorkHoursDay[] = Array.from({ length: DAYS_IN_WEEK }, (_, i) => ({
|
||||||
|
day: i,
|
||||||
|
is24h: false,
|
||||||
|
intervals: [],
|
||||||
|
}))
|
||||||
|
|
||||||
|
// sort intervals by start time
|
||||||
|
const sorted = [...this.raw.weeklyOpen].sort((a, b) => a.startMinute - b.startMinute)
|
||||||
|
|
||||||
|
// merge overlapping/consecutive intervals
|
||||||
|
for (let i = 1; i < sorted.length; i++) {
|
||||||
|
const prev = sorted[i - 1]
|
||||||
|
const cur = sorted[i]
|
||||||
|
|
||||||
|
if (prev.endMinute >= cur.startMinute) {
|
||||||
|
prev.endMinute = cur.endMinute
|
||||||
|
sorted.splice(i, 1)
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mondayPrepend: BusinessWorkHoursInterval[] = []
|
||||||
|
|
||||||
|
// process intervals
|
||||||
|
for (const interval of sorted) {
|
||||||
|
if (interval.startMinute > interval.endMinute) {
|
||||||
|
throw new MtArgumentError('startMinute is greater than endMinute')
|
||||||
|
}
|
||||||
|
|
||||||
|
const startDay = Math.floor(interval.startMinute / MINUTES_IN_DAY)
|
||||||
|
const endDay = Math.floor(interval.endMinute / MINUTES_IN_DAY)
|
||||||
|
|
||||||
|
if (endDay > DAYS_IN_WEEK + 1) {
|
||||||
|
throw new MtArgumentError('interval spans more than a week')
|
||||||
|
}
|
||||||
|
|
||||||
|
for (
|
||||||
|
let day = startDay, dayStart = startDay * MINUTES_IN_DAY;
|
||||||
|
day <= endDay;
|
||||||
|
day++, dayStart += MINUTES_IN_DAY
|
||||||
|
) {
|
||||||
|
const startWithin = Math.max(interval.startMinute, dayStart) - dayStart
|
||||||
|
const endWithin = Math.min(interval.endMinute, dayStart + MINUTES_IN_DAY) - dayStart
|
||||||
|
|
||||||
|
const startHour = Math.floor(startWithin / 60)
|
||||||
|
const startMinute = startWithin % 60
|
||||||
|
const endHour = Math.floor(endWithin / 60)
|
||||||
|
const endMinute = endWithin % 60
|
||||||
|
|
||||||
|
if (startHour === 0 && startMinute === 0 && endHour === 0 && endMinute === 0) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const obj: BusinessWorkHoursInterval = {
|
||||||
|
startHour,
|
||||||
|
startMinute,
|
||||||
|
endHour,
|
||||||
|
endMinute,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (day === DAYS_IN_WEEK) {
|
||||||
|
// prepend to Monday
|
||||||
|
mondayPrepend.push(obj)
|
||||||
|
} else {
|
||||||
|
days[day].intervals.push(obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mondayPrepend.length > 0) {
|
||||||
|
// we do this like this to keep everything sorted
|
||||||
|
days[0].intervals.unshift(...mondayPrepend)
|
||||||
|
}
|
||||||
|
|
||||||
|
// set up 24h days
|
||||||
|
for (const day of days) {
|
||||||
|
if (day.intervals.length !== 1) continue
|
||||||
|
const interval = day.intervals[0]
|
||||||
|
|
||||||
|
if (
|
||||||
|
interval.startHour === 0 &&
|
||||||
|
interval.startMinute === 0 &&
|
||||||
|
((interval.endHour === 24 && interval.endMinute === 0) ||
|
||||||
|
(interval.endHour === 23 && interval.endMinute === 59))
|
||||||
|
) {
|
||||||
|
(day as tl.Mutable<BusinessWorkHoursDay>).is24h = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return days
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
makeInspectable(BusinessWorkHours, undefined, ['intervals'])
|
||||||
|
memoizeGetters(BusinessWorkHours, ['days'])
|
|
@ -1,3 +1,8 @@
|
||||||
export * from './boost.js'
|
export * from './boost.js'
|
||||||
export * from './boost-slot.js'
|
export * from './boost-slot.js'
|
||||||
export * from './boost-stats.js'
|
export * from './boost-stats.js'
|
||||||
|
export * from './business-account.js'
|
||||||
|
export * from './business-chat-link.js'
|
||||||
|
export * from './business-connection.js'
|
||||||
|
export * from './business-intro.js'
|
||||||
|
export * from './business-work-hours.js'
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { Message } from '../messages/message.js'
|
||||||
|
import { PeersIndex } from '../peers/peers-index.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update about a new or edited business message.
|
||||||
|
*/
|
||||||
|
export class BusinessMessage extends Message {
|
||||||
|
constructor(
|
||||||
|
readonly update: tl.RawUpdateBotNewBusinessMessage | tl.RawUpdateBotEditBusinessMessage,
|
||||||
|
readonly _peers: PeersIndex,
|
||||||
|
) {
|
||||||
|
super(update.message, _peers)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unique identifier of the business connection from which the message was received.
|
||||||
|
*/
|
||||||
|
get connectionId(): string {
|
||||||
|
return this.update.connectionId
|
||||||
|
}
|
||||||
|
|
||||||
|
get groupedIdUnique(): string {
|
||||||
|
return `${super.groupedIdUnique}|${this.update.connectionId}`
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The replied message (if any) */
|
||||||
|
get replyTo(): Message | null {
|
||||||
|
return this.update.replyToMessage ? new Message(this.update.replyToMessage, this._peers) : null
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { makeInspectable } from '../../utils/index.js'
|
||||||
|
import { memoizeGetters } from '../../utils/memoize.js'
|
||||||
|
import { Chat } from '../peers/chat.js'
|
||||||
|
import { PeersIndex } from '../peers/peers-index.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* One or more messages were deleted from a connected business account
|
||||||
|
*/
|
||||||
|
export class DeleteBusinessMessageUpdate {
|
||||||
|
constructor(
|
||||||
|
readonly raw: tl.RawUpdateBotDeleteBusinessMessage,
|
||||||
|
readonly _peers: PeersIndex,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/** Unique identifier of the business connection */
|
||||||
|
get connectionId(): string {
|
||||||
|
return this.raw.connectionId
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IDs of the messages which were deleted
|
||||||
|
*/
|
||||||
|
get messageIds(): number[] {
|
||||||
|
return this.raw.messages
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chat where the messages were deleted
|
||||||
|
*/
|
||||||
|
get chat(): Chat {
|
||||||
|
return Chat._parseFromPeer(this.raw.peer, this._peers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
makeInspectable(DeleteBusinessMessageUpdate)
|
||||||
|
memoizeGetters(DeleteBusinessMessageUpdate, ['chat'])
|
|
@ -1,4 +1,4 @@
|
||||||
import type { Message } from '../../types/index.js'
|
import type { BusinessConnection, Message } from '../../types/index.js'
|
||||||
import { BotChatJoinRequestUpdate } from './bot-chat-join-request.js'
|
import { BotChatJoinRequestUpdate } from './bot-chat-join-request.js'
|
||||||
import { BotStoppedUpdate } from './bot-stopped.js'
|
import { BotStoppedUpdate } from './bot-stopped.js'
|
||||||
import { CallbackQuery, InlineCallbackQuery } from './callback-query.js'
|
import { CallbackQuery, InlineCallbackQuery } from './callback-query.js'
|
||||||
|
@ -7,7 +7,9 @@ import { ChatMemberUpdate } from './chat-member-update.js'
|
||||||
import { InlineQuery } from './inline-query.js'
|
import { InlineQuery } from './inline-query.js'
|
||||||
export type { ChatMemberUpdateType } from './chat-member-update.js'
|
export type { ChatMemberUpdateType } from './chat-member-update.js'
|
||||||
import { BotReactionCountUpdate, BotReactionUpdate } from './bot-reaction.js'
|
import { BotReactionCountUpdate, BotReactionUpdate } from './bot-reaction.js'
|
||||||
|
import { BusinessMessage } from './business-message.js'
|
||||||
import { ChosenInlineResult } from './chosen-inline-result.js'
|
import { ChosenInlineResult } from './chosen-inline-result.js'
|
||||||
|
import { DeleteBusinessMessageUpdate } from './delete-business-message-update.js'
|
||||||
import { DeleteMessageUpdate } from './delete-message-update.js'
|
import { DeleteMessageUpdate } from './delete-message-update.js'
|
||||||
import { DeleteStoryUpdate } from './delete-story-update.js'
|
import { DeleteStoryUpdate } from './delete-story-update.js'
|
||||||
import { HistoryReadUpdate } from './history-read-update.js'
|
import { HistoryReadUpdate } from './history-read-update.js'
|
||||||
|
@ -23,10 +25,12 @@ export {
|
||||||
BotReactionCountUpdate,
|
BotReactionCountUpdate,
|
||||||
BotReactionUpdate,
|
BotReactionUpdate,
|
||||||
BotStoppedUpdate,
|
BotStoppedUpdate,
|
||||||
|
BusinessMessage,
|
||||||
CallbackQuery,
|
CallbackQuery,
|
||||||
ChatJoinRequestUpdate,
|
ChatJoinRequestUpdate,
|
||||||
ChatMemberUpdate,
|
ChatMemberUpdate,
|
||||||
ChosenInlineResult,
|
ChosenInlineResult,
|
||||||
|
DeleteBusinessMessageUpdate,
|
||||||
DeleteMessageUpdate,
|
DeleteMessageUpdate,
|
||||||
DeleteStoryUpdate,
|
DeleteStoryUpdate,
|
||||||
HistoryReadUpdate,
|
HistoryReadUpdate,
|
||||||
|
@ -64,5 +68,10 @@ export type ParsedUpdate =
|
||||||
| { name: 'delete_story'; data: DeleteStoryUpdate }
|
| { name: 'delete_story'; data: DeleteStoryUpdate }
|
||||||
| { name: 'bot_reaction'; data: BotReactionUpdate }
|
| { name: 'bot_reaction'; data: BotReactionUpdate }
|
||||||
| { name: 'bot_reaction_count'; data: BotReactionCountUpdate }
|
| { name: 'bot_reaction_count'; data: BotReactionCountUpdate }
|
||||||
|
| { name: 'business_connection'; data: BusinessConnection }
|
||||||
|
| { name: 'new_business_message'; data: BusinessMessage }
|
||||||
|
| { name: 'edit_business_message'; data: BusinessMessage }
|
||||||
|
| { name: 'business_message_group'; data: BusinessMessage[] }
|
||||||
|
| { name: 'delete_business_message'; data: DeleteBusinessMessageUpdate }
|
||||||
|
|
||||||
// end-codegen
|
// end-codegen
|
||||||
|
|
|
@ -6,10 +6,13 @@ import {
|
||||||
BotReactionCountUpdate,
|
BotReactionCountUpdate,
|
||||||
BotReactionUpdate,
|
BotReactionUpdate,
|
||||||
BotStoppedUpdate,
|
BotStoppedUpdate,
|
||||||
|
BusinessConnection,
|
||||||
|
BusinessMessage,
|
||||||
CallbackQuery,
|
CallbackQuery,
|
||||||
ChatJoinRequestUpdate,
|
ChatJoinRequestUpdate,
|
||||||
ChatMemberUpdate,
|
ChatMemberUpdate,
|
||||||
ChosenInlineResult,
|
ChosenInlineResult,
|
||||||
|
DeleteBusinessMessageUpdate,
|
||||||
DeleteMessageUpdate,
|
DeleteMessageUpdate,
|
||||||
DeleteStoryUpdate,
|
DeleteStoryUpdate,
|
||||||
HistoryReadUpdate,
|
HistoryReadUpdate,
|
||||||
|
@ -94,6 +97,14 @@ export function _parseUpdate(update: tl.TypeUpdate, peers: PeersIndex): ParsedUp
|
||||||
return { name: 'bot_reaction', data: new BotReactionUpdate(update, peers) }
|
return { name: 'bot_reaction', data: new BotReactionUpdate(update, peers) }
|
||||||
case 'updateBotMessageReactions':
|
case 'updateBotMessageReactions':
|
||||||
return { name: 'bot_reaction_count', data: new BotReactionCountUpdate(update, peers) }
|
return { name: 'bot_reaction_count', data: new BotReactionCountUpdate(update, peers) }
|
||||||
|
case 'updateBotBusinessConnect':
|
||||||
|
return { name: 'business_connection', data: new BusinessConnection(update.connection, peers) }
|
||||||
|
case 'updateBotNewBusinessMessage':
|
||||||
|
return { name: 'new_business_message', data: new BusinessMessage(update, peers) }
|
||||||
|
case 'updateBotEditBusinessMessage':
|
||||||
|
return { name: 'edit_business_message', data: new BusinessMessage(update, peers) }
|
||||||
|
case 'updateBotDeleteBusinessMessage':
|
||||||
|
return { name: 'delete_business_message', data: new DeleteBusinessMessageUpdate(update, peers) }
|
||||||
default:
|
default:
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,11 +55,11 @@ export class PollUpdate {
|
||||||
poll = {
|
poll = {
|
||||||
_: 'poll',
|
_: 'poll',
|
||||||
id: this.raw.pollId,
|
id: this.raw.pollId,
|
||||||
question: '',
|
question: { _: 'textWithEntities', text: '', entities: [] },
|
||||||
answers:
|
answers:
|
||||||
this.raw.results.results?.map((res) => ({
|
this.raw.results.results?.map((res) => ({
|
||||||
_: 'pollAnswer',
|
_: 'pollAnswer',
|
||||||
text: '',
|
text: { _: 'textWithEntities', text: '', entities: [] },
|
||||||
option: res.option,
|
option: res.option,
|
||||||
})) ?? [],
|
})) ?? [],
|
||||||
}
|
}
|
||||||
|
|
|
@ -523,7 +523,8 @@ export class UpdatesManager {
|
||||||
|
|
||||||
switch (upd._) {
|
switch (upd._) {
|
||||||
case 'updateNewMessage':
|
case 'updateNewMessage':
|
||||||
case 'updateNewChannelMessage': {
|
case 'updateNewChannelMessage':
|
||||||
|
case 'updateBotNewBusinessMessage': {
|
||||||
const channelId = upd.message.peerId?._ === 'peerChannel' ? upd.message.peerId.channelId : 0
|
const channelId = upd.message.peerId?._ === 'peerChannel' ? upd.message.peerId.channelId : 0
|
||||||
|
|
||||||
const set = noDispatchMsg.get(channelId)
|
const set = noDispatchMsg.get(channelId)
|
||||||
|
@ -1260,7 +1261,11 @@ export class UpdatesManager {
|
||||||
if (this.noDispatchEnabled) {
|
if (this.noDispatchEnabled) {
|
||||||
const channelId = pending.channelId ?? 0
|
const channelId = pending.channelId ?? 0
|
||||||
const msgId =
|
const msgId =
|
||||||
upd._ === 'updateNewMessage' || upd._ === 'updateNewChannelMessage' ? upd.message.id : undefined
|
upd._ === 'updateNewMessage' ||
|
||||||
|
upd._ === 'updateNewChannelMessage' ||
|
||||||
|
upd._ === 'updateBotNewBusinessMessage' ?
|
||||||
|
upd.message.id :
|
||||||
|
undefined
|
||||||
|
|
||||||
// we first need to remove it from each index, and then check if it was there
|
// we first need to remove it from each index, and then check if it was there
|
||||||
const foundByMsgId = msgId && this.noDispatchMsg.get(channelId)?.delete(msgId)
|
const foundByMsgId = msgId && this.noDispatchMsg.get(channelId)?.delete(msgId)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Message } from '../types/messages/index.js'
|
import { Message } from '../types/messages/index.js'
|
||||||
import { ParsedUpdate } from '../types/updates/index.js'
|
import { BusinessMessage, ParsedUpdate } from '../types/updates/index.js'
|
||||||
import { _parseUpdate } from '../types/updates/parse-update.js'
|
import { _parseUpdate } from '../types/updates/parse-update.js'
|
||||||
import { RawUpdateHandler } from './types.js'
|
import { RawUpdateHandler } from './types.js'
|
||||||
|
|
||||||
|
@ -54,10 +54,11 @@ export function makeParsedUpdateHandler(params: ParsedUpdateHandlerParams): RawU
|
||||||
onRawUpdate(update, peers)
|
onRawUpdate(update, peers)
|
||||||
|
|
||||||
if (parsed) {
|
if (parsed) {
|
||||||
if (parsed.name === 'new_message') {
|
if (parsed.name === 'new_message' || parsed.name === 'new_business_message') {
|
||||||
const group = parsed.data.groupedIdUnique
|
const group = parsed.data.groupedIdUnique
|
||||||
|
|
||||||
if (group) {
|
if (group) {
|
||||||
|
const isBusiness = parsed.name === 'new_business_message'
|
||||||
const pendingGroup = pending.get(group)
|
const pendingGroup = pending.get(group)
|
||||||
|
|
||||||
if (pendingGroup) {
|
if (pendingGroup) {
|
||||||
|
@ -66,7 +67,12 @@ export function makeParsedUpdateHandler(params: ParsedUpdateHandlerParams): RawU
|
||||||
const messages = [parsed.data]
|
const messages = [parsed.data]
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
pending.delete(group)
|
pending.delete(group)
|
||||||
|
|
||||||
|
if (isBusiness) {
|
||||||
|
onUpdate({ name: 'business_message_group', data: messages as BusinessMessage[] })
|
||||||
|
} else {
|
||||||
onUpdate({ name: 'message_group', data: messages })
|
onUpdate({ name: 'message_group', data: messages })
|
||||||
|
}
|
||||||
}, messageGroupingInterval)
|
}, messageGroupingInterval)
|
||||||
|
|
||||||
pending.set(group, [messages, timeout])
|
pending.set(group, [messages, timeout])
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
/* eslint-disable @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-assignment */
|
/* eslint-disable @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-assignment */
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-argument */
|
/* eslint-disable @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-argument */
|
||||||
|
|
||||||
|
import Long from 'long'
|
||||||
|
|
||||||
import { getPlatform } from '../../platform.js'
|
import { getPlatform } from '../../platform.js'
|
||||||
|
|
||||||
const customInspectSymbol = Symbol.for('nodejs.util.inspect.custom')
|
const customInspectSymbol = Symbol.for('nodejs.util.inspect.custom')
|
||||||
|
@ -57,6 +59,8 @@ export function makeInspectable<T>(
|
||||||
if (val && typeof val === 'object') {
|
if (val && typeof val === 'object') {
|
||||||
if (val instanceof Uint8Array) {
|
if (val instanceof Uint8Array) {
|
||||||
val = getPlatform().base64Encode(val)
|
val = getPlatform().base64Encode(val)
|
||||||
|
} else if (Long.isLong(val)) {
|
||||||
|
val = val.toString()
|
||||||
} else if (typeof val.toJSON === 'function') {
|
} else if (typeof val.toJSON === 'function') {
|
||||||
val = val.toJSON(true)
|
val = val.toJSON(true)
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,6 +173,15 @@ export interface RpcCallOptions {
|
||||||
*/
|
*/
|
||||||
throw503?: boolean
|
throw503?: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the `X_MIGRATE_%d` errors should be handled locally on request level
|
||||||
|
* instead of changing the default datacenter for the entire client.
|
||||||
|
*
|
||||||
|
* Useful for `invokeWithBusinessConnection`, as it returns a `USER_MIGRATE_%d` error
|
||||||
|
* that is in fact not related to the user, but to the specific request.
|
||||||
|
*/
|
||||||
|
localMigrate?: boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Some requests should be processed consecutively, and not in parallel.
|
* Some requests should be processed consecutively, and not in parallel.
|
||||||
* Using the same `chainId` for multiple requests will ensure that they are processed in the order
|
* Using the same `chainId` for multiple requests will ensure that they are processed in the order
|
||||||
|
@ -807,10 +816,15 @@ export class NetworkManager {
|
||||||
|
|
||||||
if (manager === this._primaryDc) {
|
if (manager === this._primaryDc) {
|
||||||
if (e.is('PHONE_MIGRATE_%d') || e.is('NETWORK_MIGRATE_%d') || e.is('USER_MIGRATE_%d')) {
|
if (e.is('PHONE_MIGRATE_%d') || e.is('NETWORK_MIGRATE_%d') || e.is('USER_MIGRATE_%d')) {
|
||||||
|
if (params?.localMigrate) {
|
||||||
|
manager = await this._getOtherDc(e.newDc)
|
||||||
|
} else {
|
||||||
this._log.info('Migrate error, new dc = %d', e.newDc)
|
this._log.info('Migrate error, new dc = %d', e.newDc)
|
||||||
|
|
||||||
await this.changePrimaryDc(e.newDc)
|
await this.changePrimaryDc(e.newDc)
|
||||||
manager = this._primaryDc!
|
manager = this._primaryDc!
|
||||||
|
}
|
||||||
|
|
||||||
multi = manager[kind]
|
multi = manager[kind]
|
||||||
|
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
const { types, toSentence, replaceSections, formatFile } = require('../../mtcute/scripts/generate-updates.cjs')
|
const { types, toSentence, replaceSections, formatFile } = require('../../core/scripts/generate-updates.cjs')
|
||||||
|
|
||||||
function generateHandler() {
|
function generateHandler() {
|
||||||
const lines = []
|
const lines = []
|
||||||
|
|
187
packages/dispatcher/src/context/business-message.ts
Normal file
187
packages/dispatcher/src/context/business-message.ts
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
import { BusinessMessage, OmitInputMessageId, ParametersSkip1 } from '@mtcute/core'
|
||||||
|
import { TelegramClient } from '@mtcute/core/client.js'
|
||||||
|
import {
|
||||||
|
DeleteMessagesParams,
|
||||||
|
ForwardMessageOptions,
|
||||||
|
SendCopyGroupParams,
|
||||||
|
SendCopyParams,
|
||||||
|
} from '@mtcute/core/methods.js'
|
||||||
|
|
||||||
|
import { UpdateContext } from './base.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Context of a business message related update.
|
||||||
|
*
|
||||||
|
* This is a subclass of {@link BusinessMessage}, so all fields
|
||||||
|
* of the message are available.
|
||||||
|
*
|
||||||
|
* For message groups, own fields are related to the last message
|
||||||
|
* in the group. To access all messages, use {@link BusinessMessageContext#messages}.
|
||||||
|
*/
|
||||||
|
export class BusinessMessageContext extends BusinessMessage implements UpdateContext<BusinessMessage> {
|
||||||
|
// this is primarily for proper types in filters, so don't bother much with actual value
|
||||||
|
readonly _name = 'new_business_message'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of messages in the message group.
|
||||||
|
*
|
||||||
|
* For other updates, this is a list with a single element (`this`).
|
||||||
|
*/
|
||||||
|
readonly messages: BusinessMessageContext[]
|
||||||
|
|
||||||
|
/** Whether this update is about a message group */
|
||||||
|
readonly isMessageGroup: boolean
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
readonly client: TelegramClient,
|
||||||
|
message: BusinessMessage | BusinessMessage[],
|
||||||
|
) {
|
||||||
|
const msg = Array.isArray(message) ? message[message.length - 1] : message
|
||||||
|
super(msg.update, msg._peers)
|
||||||
|
|
||||||
|
this.messages = Array.isArray(message) ? message.map((it) => new BusinessMessageContext(client, it)) : [this]
|
||||||
|
this.isMessageGroup = Array.isArray(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get all custom emojis contained in this message (message group), if any */
|
||||||
|
getCustomEmojis() {
|
||||||
|
return this.client.getCustomEmojisFromMessages(this.messages)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Send a text message to the same chat (and topic, if applicable) as a given message */
|
||||||
|
answerText(...params: ParametersSkip1<TelegramClient['answerText']>) {
|
||||||
|
const [send, params_ = {}] = params
|
||||||
|
params_.businessConnectionId = this.update.connectionId
|
||||||
|
|
||||||
|
return this.client.answerText(this, send, params_)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Send a media to the same chat (and topic, if applicable) as a given message */
|
||||||
|
answerMedia(...params: ParametersSkip1<TelegramClient['answerMedia']>) {
|
||||||
|
const [send, params_ = {}] = params
|
||||||
|
params_.businessConnectionId = this.update.connectionId
|
||||||
|
|
||||||
|
return this.client.answerMedia(this, send, params_)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Send a media group to the same chat (and topic, if applicable) as a given message */
|
||||||
|
answerMediaGroup(...params: ParametersSkip1<TelegramClient['answerMediaGroup']>) {
|
||||||
|
const [send, params_ = {}] = params
|
||||||
|
params_.businessConnectionId = this.update.connectionId
|
||||||
|
|
||||||
|
return this.client.answerMediaGroup(this, send, params_)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Send a text message in reply to this message */
|
||||||
|
replyText(...params: ParametersSkip1<TelegramClient['replyText']>) {
|
||||||
|
const [send, params_ = {}] = params
|
||||||
|
params_.businessConnectionId = this.update.connectionId
|
||||||
|
|
||||||
|
return this.client.replyText(this, send, params_)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Send a media in reply to this message */
|
||||||
|
replyMedia(...params: ParametersSkip1<TelegramClient['replyMedia']>) {
|
||||||
|
const [send, params_ = {}] = params
|
||||||
|
params_.businessConnectionId = this.update.connectionId
|
||||||
|
|
||||||
|
return this.client.replyMedia(this, send, params_)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Send a media group in reply to this message */
|
||||||
|
replyMediaGroup(...params: ParametersSkip1<TelegramClient['replyMediaGroup']>) {
|
||||||
|
const [send, params_ = {}] = params
|
||||||
|
params_.businessConnectionId = this.update.connectionId
|
||||||
|
|
||||||
|
return this.client.replyMediaGroup(this, send, params_)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Send a text message in reply to this message */
|
||||||
|
quoteWithText(params: Parameters<TelegramClient['quoteWithText']>[1]) {
|
||||||
|
params.businessConnectionId = this.update.connectionId
|
||||||
|
|
||||||
|
return this.client.quoteWithText(this, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Send a media in reply to this message */
|
||||||
|
quoteWithMedia(params: Parameters<TelegramClient['quoteWithMedia']>[1]) {
|
||||||
|
params.businessConnectionId = this.update.connectionId
|
||||||
|
|
||||||
|
return this.client.quoteWithMedia(this, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Send a media group in reply to this message */
|
||||||
|
quoteWithMediaGroup(params: Parameters<TelegramClient['quoteWithMediaGroup']>[1]) {
|
||||||
|
params.businessConnectionId = this.update.connectionId
|
||||||
|
|
||||||
|
return this.client.quoteWithMediaGroup(this, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Delete this message (message group) */
|
||||||
|
delete(params?: DeleteMessagesParams) {
|
||||||
|
return this.client.deleteMessagesById(
|
||||||
|
this.chat.inputPeer,
|
||||||
|
this.messages.map((it) => it.id),
|
||||||
|
params,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Pin this message */
|
||||||
|
pin(params?: OmitInputMessageId<Parameters<TelegramClient['pinMessage']>[0]>) {
|
||||||
|
return this.client.pinMessage({
|
||||||
|
chatId: this.chat.inputPeer,
|
||||||
|
message: this.id,
|
||||||
|
...params,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Unpin this message */
|
||||||
|
unpin() {
|
||||||
|
return this.client.unpinMessage({
|
||||||
|
chatId: this.chat.inputPeer,
|
||||||
|
message: this.id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Edit this message */
|
||||||
|
edit(params: OmitInputMessageId<Parameters<TelegramClient['editMessage']>[0]>) {
|
||||||
|
return this.client.editMessage({
|
||||||
|
chatId: this.chat.inputPeer,
|
||||||
|
message: this.id,
|
||||||
|
...params,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Forward this message (message group) */
|
||||||
|
forwardTo(params: ForwardMessageOptions) {
|
||||||
|
return this.client.forwardMessagesById({
|
||||||
|
fromChatId: this.chat.inputPeer,
|
||||||
|
messages: this.messages.map((it) => it.id),
|
||||||
|
...params,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Send a copy of this message (message group) */
|
||||||
|
copy(params: SendCopyParams & SendCopyGroupParams) {
|
||||||
|
if (this.isMessageGroup) {
|
||||||
|
return this.client.sendCopyGroup({
|
||||||
|
messages: this.messages,
|
||||||
|
...params,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.client.sendCopy({
|
||||||
|
message: this,
|
||||||
|
...params,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** React to this message */
|
||||||
|
react(params: OmitInputMessageId<Parameters<TelegramClient['sendReaction']>[0]>) {
|
||||||
|
return this.client.sendReaction({
|
||||||
|
chatId: this.chat.inputPeer,
|
||||||
|
message: this.id,
|
||||||
|
...params,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ import { ParsedUpdate } from '@mtcute/core'
|
||||||
import { TelegramClient } from '@mtcute/core/client.js'
|
import { TelegramClient } from '@mtcute/core/client.js'
|
||||||
|
|
||||||
import { UpdateContextDistributed } from './base.js'
|
import { UpdateContextDistributed } from './base.js'
|
||||||
|
import { BusinessMessageContext } from './business-message.js'
|
||||||
import { CallbackQueryContext } from './callback-query.js'
|
import { CallbackQueryContext } from './callback-query.js'
|
||||||
import { ChatJoinRequestUpdateContext } from './chat-join-request.js'
|
import { ChatJoinRequestUpdateContext } from './chat-join-request.js'
|
||||||
import { ChosenInlineResultContext } from './chosen-inline-result.js'
|
import { ChosenInlineResultContext } from './chosen-inline-result.js'
|
||||||
|
@ -26,6 +27,10 @@ export function _parsedUpdateToContext(client: TelegramClient, update: ParsedUpd
|
||||||
return new ChatJoinRequestUpdateContext(client, update.data)
|
return new ChatJoinRequestUpdateContext(client, update.data)
|
||||||
case 'pre_checkout_query':
|
case 'pre_checkout_query':
|
||||||
return new PreCheckoutQueryContext(client, update.data)
|
return new PreCheckoutQueryContext(client, update.data)
|
||||||
|
case 'new_business_message':
|
||||||
|
case 'edit_business_message':
|
||||||
|
case 'business_message_group':
|
||||||
|
return new BusinessMessageContext(client, update.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
const _update = update.data as UpdateContextDistributed<typeof update.data>
|
const _update = update.data as UpdateContextDistributed<typeof update.data>
|
||||||
|
|
|
@ -7,8 +7,10 @@ import {
|
||||||
BotReactionCountUpdate,
|
BotReactionCountUpdate,
|
||||||
BotReactionUpdate,
|
BotReactionUpdate,
|
||||||
BotStoppedUpdate,
|
BotStoppedUpdate,
|
||||||
|
BusinessConnection,
|
||||||
ChatJoinRequestUpdate,
|
ChatJoinRequestUpdate,
|
||||||
ChatMemberUpdate,
|
ChatMemberUpdate,
|
||||||
|
DeleteBusinessMessageUpdate,
|
||||||
DeleteMessageUpdate,
|
DeleteMessageUpdate,
|
||||||
DeleteStoryUpdate,
|
DeleteStoryUpdate,
|
||||||
HistoryReadUpdate,
|
HistoryReadUpdate,
|
||||||
|
@ -26,6 +28,7 @@ import {
|
||||||
import { TelegramClient } from '@mtcute/core/client.js'
|
import { TelegramClient } from '@mtcute/core/client.js'
|
||||||
|
|
||||||
import { UpdateContext } from './context/base.js'
|
import { UpdateContext } from './context/base.js'
|
||||||
|
import { BusinessMessageContext } from './context/business-message.js'
|
||||||
import {
|
import {
|
||||||
CallbackQueryContext,
|
CallbackQueryContext,
|
||||||
ChatJoinRequestUpdateContext,
|
ChatJoinRequestUpdateContext,
|
||||||
|
@ -43,17 +46,22 @@ import {
|
||||||
BotReactionCountUpdateHandler,
|
BotReactionCountUpdateHandler,
|
||||||
BotReactionUpdateHandler,
|
BotReactionUpdateHandler,
|
||||||
BotStoppedHandler,
|
BotStoppedHandler,
|
||||||
|
BusinessConnectionUpdateHandler,
|
||||||
|
BusinessMessageGroupHandler,
|
||||||
CallbackQueryHandler,
|
CallbackQueryHandler,
|
||||||
ChatJoinRequestHandler,
|
ChatJoinRequestHandler,
|
||||||
ChatMemberUpdateHandler,
|
ChatMemberUpdateHandler,
|
||||||
ChosenInlineResultHandler,
|
ChosenInlineResultHandler,
|
||||||
|
DeleteBusinessMessageHandler,
|
||||||
DeleteMessageHandler,
|
DeleteMessageHandler,
|
||||||
DeleteStoryHandler,
|
DeleteStoryHandler,
|
||||||
|
EditBusinessMessageHandler,
|
||||||
EditMessageHandler,
|
EditMessageHandler,
|
||||||
HistoryReadHandler,
|
HistoryReadHandler,
|
||||||
InlineCallbackQueryHandler,
|
InlineCallbackQueryHandler,
|
||||||
InlineQueryHandler,
|
InlineQueryHandler,
|
||||||
MessageGroupHandler,
|
MessageGroupHandler,
|
||||||
|
NewBusinessMessageHandler,
|
||||||
NewMessageHandler,
|
NewMessageHandler,
|
||||||
PollUpdateHandler,
|
PollUpdateHandler,
|
||||||
PollVoteHandler,
|
PollVoteHandler,
|
||||||
|
@ -1014,9 +1022,9 @@ export class Dispatcher<State extends object = never> {
|
||||||
if (typeof handler === 'number' || typeof handler === 'undefined') {
|
if (typeof handler === 'number' || typeof handler === 'undefined') {
|
||||||
this.addUpdateHandler(
|
this.addUpdateHandler(
|
||||||
{
|
{
|
||||||
name,
|
name: name,
|
||||||
callback: filter,
|
callback: filter,
|
||||||
},
|
} as UpdateHandler,
|
||||||
handler,
|
handler,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1025,7 +1033,7 @@ export class Dispatcher<State extends object = never> {
|
||||||
name,
|
name,
|
||||||
callback: handler,
|
callback: handler,
|
||||||
check: filter,
|
check: filter,
|
||||||
},
|
} as UpdateHandler,
|
||||||
group,
|
group,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1743,5 +1751,212 @@ export class Dispatcher<State extends object = never> {
|
||||||
this._addKnownHandler('bot_reaction_count', filter, handler, group)
|
this._addKnownHandler('bot_reaction_count', filter, handler, group)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a business connection update handler without any filters
|
||||||
|
*
|
||||||
|
* @param handler Business connection update handler
|
||||||
|
* @param group Handler group index
|
||||||
|
*/
|
||||||
|
onBusinessConnectionUpdate(handler: BusinessConnectionUpdateHandler['callback'], group?: number): void
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a business connection update handler with a filter
|
||||||
|
*
|
||||||
|
* @param filter Update filter
|
||||||
|
* @param handler Business connection update handler
|
||||||
|
* @param group Handler group index
|
||||||
|
*/
|
||||||
|
onBusinessConnectionUpdate<Mod>(
|
||||||
|
filter: UpdateFilter<UpdateContext<BusinessConnection>, Mod>,
|
||||||
|
handler: BusinessConnectionUpdateHandler<filters.Modify<UpdateContext<BusinessConnection>, Mod>>['callback'],
|
||||||
|
group?: number,
|
||||||
|
): void
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
onBusinessConnectionUpdate(filter: any, handler?: any, group?: number): void {
|
||||||
|
this._addKnownHandler('business_connection', filter, handler, group)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a new business message handler without any filters
|
||||||
|
*
|
||||||
|
* @param handler New business message handler
|
||||||
|
* @param group Handler group index
|
||||||
|
*/
|
||||||
|
onNewBusinessMessage(
|
||||||
|
handler: NewBusinessMessageHandler<
|
||||||
|
BusinessMessageContext,
|
||||||
|
State extends never ? never : UpdateState<State>
|
||||||
|
>['callback'],
|
||||||
|
group?: number,
|
||||||
|
): void
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a new business message handler with a filter
|
||||||
|
*
|
||||||
|
* @param filter Update filter
|
||||||
|
* @param handler New business message handler
|
||||||
|
* @param group Handler group index
|
||||||
|
*/
|
||||||
|
onNewBusinessMessage<Mod>(
|
||||||
|
filter: UpdateFilter<BusinessMessageContext, Mod, State>,
|
||||||
|
handler: NewBusinessMessageHandler<
|
||||||
|
filters.Modify<BusinessMessageContext, Mod>,
|
||||||
|
State extends never ? never : UpdateState<State>
|
||||||
|
>['callback'],
|
||||||
|
group?: number,
|
||||||
|
): void
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a new business message handler with a filter
|
||||||
|
*
|
||||||
|
* @param filter Update filter
|
||||||
|
* @param handler New business message handler
|
||||||
|
* @param group Handler group index
|
||||||
|
*/
|
||||||
|
onNewBusinessMessage<Mod>(
|
||||||
|
filter: UpdateFilter<BusinessMessageContext, Mod>,
|
||||||
|
handler: NewBusinessMessageHandler<
|
||||||
|
filters.Modify<BusinessMessageContext, Mod>,
|
||||||
|
State extends never ? never : UpdateState<State>
|
||||||
|
>['callback'],
|
||||||
|
group?: number,
|
||||||
|
): void
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
onNewBusinessMessage(filter: any, handler?: any, group?: number): void {
|
||||||
|
this._addKnownHandler('new_business_message', filter, handler, group)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register an edit business message handler without any filters
|
||||||
|
*
|
||||||
|
* @param handler Edit business message handler
|
||||||
|
* @param group Handler group index
|
||||||
|
*/
|
||||||
|
onEditBusinessMessage(
|
||||||
|
handler: EditBusinessMessageHandler<
|
||||||
|
BusinessMessageContext,
|
||||||
|
State extends never ? never : UpdateState<State>
|
||||||
|
>['callback'],
|
||||||
|
group?: number,
|
||||||
|
): void
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register an edit business message handler with a filter
|
||||||
|
*
|
||||||
|
* @param filter Update filter
|
||||||
|
* @param handler Edit business message handler
|
||||||
|
* @param group Handler group index
|
||||||
|
*/
|
||||||
|
onEditBusinessMessage<Mod>(
|
||||||
|
filter: UpdateFilter<BusinessMessageContext, Mod, State>,
|
||||||
|
handler: EditBusinessMessageHandler<
|
||||||
|
filters.Modify<BusinessMessageContext, Mod>,
|
||||||
|
State extends never ? never : UpdateState<State>
|
||||||
|
>['callback'],
|
||||||
|
group?: number,
|
||||||
|
): void
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register an edit business message handler with a filter
|
||||||
|
*
|
||||||
|
* @param filter Update filter
|
||||||
|
* @param handler Edit business message handler
|
||||||
|
* @param group Handler group index
|
||||||
|
*/
|
||||||
|
onEditBusinessMessage<Mod>(
|
||||||
|
filter: UpdateFilter<BusinessMessageContext, Mod>,
|
||||||
|
handler: EditBusinessMessageHandler<
|
||||||
|
filters.Modify<BusinessMessageContext, Mod>,
|
||||||
|
State extends never ? never : UpdateState<State>
|
||||||
|
>['callback'],
|
||||||
|
group?: number,
|
||||||
|
): void
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
onEditBusinessMessage(filter: any, handler?: any, group?: number): void {
|
||||||
|
this._addKnownHandler('edit_business_message', filter, handler, group)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a business message group handler without any filters
|
||||||
|
*
|
||||||
|
* @param handler Business message group handler
|
||||||
|
* @param group Handler group index
|
||||||
|
*/
|
||||||
|
onBusinessMessageGroup(
|
||||||
|
handler: BusinessMessageGroupHandler<
|
||||||
|
BusinessMessageContext,
|
||||||
|
State extends never ? never : UpdateState<State>
|
||||||
|
>['callback'],
|
||||||
|
group?: number,
|
||||||
|
): void
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a business message group handler with a filter
|
||||||
|
*
|
||||||
|
* @param filter Update filter
|
||||||
|
* @param handler Business message group handler
|
||||||
|
* @param group Handler group index
|
||||||
|
*/
|
||||||
|
onBusinessMessageGroup<Mod>(
|
||||||
|
filter: UpdateFilter<BusinessMessageContext, Mod, State>,
|
||||||
|
handler: BusinessMessageGroupHandler<
|
||||||
|
filters.Modify<BusinessMessageContext, Mod>,
|
||||||
|
State extends never ? never : UpdateState<State>
|
||||||
|
>['callback'],
|
||||||
|
group?: number,
|
||||||
|
): void
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a business message group handler with a filter
|
||||||
|
*
|
||||||
|
* @param filter Update filter
|
||||||
|
* @param handler Business message group handler
|
||||||
|
* @param group Handler group index
|
||||||
|
*/
|
||||||
|
onBusinessMessageGroup<Mod>(
|
||||||
|
filter: UpdateFilter<BusinessMessageContext, Mod>,
|
||||||
|
handler: BusinessMessageGroupHandler<
|
||||||
|
filters.Modify<BusinessMessageContext, Mod>,
|
||||||
|
State extends never ? never : UpdateState<State>
|
||||||
|
>['callback'],
|
||||||
|
group?: number,
|
||||||
|
): void
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
onBusinessMessageGroup(filter: any, handler?: any, group?: number): void {
|
||||||
|
this._addKnownHandler('business_message_group', filter, handler, group)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a delete business message handler without any filters
|
||||||
|
*
|
||||||
|
* @param handler Delete business message handler
|
||||||
|
* @param group Handler group index
|
||||||
|
*/
|
||||||
|
onDeleteBusinessMessage(handler: DeleteBusinessMessageHandler['callback'], group?: number): void
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a delete business message handler with a filter
|
||||||
|
*
|
||||||
|
* @param filter Update filter
|
||||||
|
* @param handler Delete business message handler
|
||||||
|
* @param group Handler group index
|
||||||
|
*/
|
||||||
|
onDeleteBusinessMessage<Mod>(
|
||||||
|
filter: UpdateFilter<UpdateContext<DeleteBusinessMessageUpdate>, Mod>,
|
||||||
|
handler: DeleteBusinessMessageHandler<
|
||||||
|
filters.Modify<UpdateContext<DeleteBusinessMessageUpdate>, Mod>
|
||||||
|
>['callback'],
|
||||||
|
group?: number,
|
||||||
|
): void
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
onDeleteBusinessMessage(filter: any, handler?: any, group?: number): void {
|
||||||
|
this._addKnownHandler('delete_business_message', filter, handler, group)
|
||||||
|
}
|
||||||
|
|
||||||
// end-codegen
|
// end-codegen
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { MaybeArray, MaybePromise, Message } from '@mtcute/core'
|
import { MaybeArray, MaybePromise, Message } from '@mtcute/core'
|
||||||
|
|
||||||
|
import { BusinessMessageContext } from '../context/business-message.js'
|
||||||
import { MessageContext } from '../context/message.js'
|
import { MessageContext } from '../context/message.js'
|
||||||
import { chat } from './chat.js'
|
import { chat } from './chat.js'
|
||||||
import { and, or } from './logic.js'
|
import { and, or } from './logic.js'
|
||||||
|
@ -30,7 +31,7 @@ export const command = (
|
||||||
prefixes?: MaybeArray<string> | null
|
prefixes?: MaybeArray<string> | null
|
||||||
caseSensitive?: boolean
|
caseSensitive?: boolean
|
||||||
} = {},
|
} = {},
|
||||||
): UpdateFilter<MessageContext, { command: string[] }> => {
|
): UpdateFilter<MessageContext | BusinessMessageContext, { command: string[] }> => {
|
||||||
if (!Array.isArray(commands)) commands = [commands]
|
if (!Array.isArray(commands)) commands = [commands]
|
||||||
|
|
||||||
if (!caseSensitive) {
|
if (!caseSensitive) {
|
||||||
|
@ -51,7 +52,7 @@ export const command = (
|
||||||
|
|
||||||
const _prefixes = prefixes
|
const _prefixes = prefixes
|
||||||
|
|
||||||
const check = (msg: MessageContext): MaybePromise<boolean> => {
|
const check = (msg: MessageContext | BusinessMessageContext): MaybePromise<boolean> => {
|
||||||
if (msg.isMessageGroup) return check(msg.messages[0])
|
if (msg.isMessageGroup) return check(msg.messages[0])
|
||||||
|
|
||||||
for (const pref of _prefixes) {
|
for (const pref of _prefixes) {
|
||||||
|
@ -107,8 +108,10 @@ export const start = and(chat('private'), command('start'))
|
||||||
export const startGroup = and(or(chat('supergroup'), chat('group')), command('start'))
|
export const startGroup = and(or(chat('supergroup'), chat('group')), command('start'))
|
||||||
|
|
||||||
const deeplinkBase =
|
const deeplinkBase =
|
||||||
(base: UpdateFilter<MessageContext, { command: string[] }>) =>
|
(base: UpdateFilter<MessageContext | BusinessMessageContext, { command: string[] }>) =>
|
||||||
(params: MaybeArray<string | RegExp>): UpdateFilter<MessageContext, { command: string[] }> => {
|
(
|
||||||
|
params: MaybeArray<string | RegExp>,
|
||||||
|
): UpdateFilter<MessageContext | BusinessMessageContext, { command: string[] }> => {
|
||||||
if (!Array.isArray(params)) {
|
if (!Array.isArray(params)) {
|
||||||
return and(start, (_msg: Message) => {
|
return and(start, (_msg: Message) => {
|
||||||
const msg = _msg as Message & { command: string[] }
|
const msg = _msg as Message & { command: string[] }
|
||||||
|
|
|
@ -3,6 +3,7 @@ import {
|
||||||
Chat,
|
Chat,
|
||||||
ChatMemberUpdate,
|
ChatMemberUpdate,
|
||||||
ChatType,
|
ChatType,
|
||||||
|
DeleteBusinessMessageUpdate,
|
||||||
HistoryReadUpdate,
|
HistoryReadUpdate,
|
||||||
MaybeArray,
|
MaybeArray,
|
||||||
Message,
|
Message,
|
||||||
|
@ -58,6 +59,7 @@ export const chatId: {
|
||||||
| HistoryReadUpdate
|
| HistoryReadUpdate
|
||||||
| PollVoteUpdate
|
| PollVoteUpdate
|
||||||
| BotChatJoinRequestUpdate
|
| BotChatJoinRequestUpdate
|
||||||
|
| DeleteBusinessMessageUpdate
|
||||||
>>
|
>>
|
||||||
} = (id) => {
|
} = (id) => {
|
||||||
const indexId = new Set<number>()
|
const indexId = new Set<number>()
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { MaybePromise, Message } from '@mtcute/core'
|
import { MaybePromise, Message } from '@mtcute/core'
|
||||||
|
|
||||||
|
import { BusinessMessageContext } from '../context/business-message.js'
|
||||||
import { MessageContext } from '../context/message.js'
|
import { MessageContext } from '../context/message.js'
|
||||||
import { Modify, UpdateFilter } from './types.js'
|
import { Modify, UpdateFilter } from './types.js'
|
||||||
|
|
||||||
|
@ -15,9 +16,9 @@ import { Modify, UpdateFilter } from './types.js'
|
||||||
export function every<Mod, State extends object>(
|
export function every<Mod, State extends object>(
|
||||||
filter: UpdateFilter<Message, Mod, State>,
|
filter: UpdateFilter<Message, Mod, State>,
|
||||||
): UpdateFilter<
|
): UpdateFilter<
|
||||||
MessageContext,
|
MessageContext | BusinessMessageContext,
|
||||||
Mod & {
|
Mod & {
|
||||||
messages: Modify<MessageContext, Mod>[]
|
messages: Modify<MessageContext | BusinessMessageContext, Mod>[]
|
||||||
},
|
},
|
||||||
State
|
State
|
||||||
> {
|
> {
|
||||||
|
@ -61,7 +62,7 @@ export function some<State extends object>(
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
filter: UpdateFilter<Message, any, State>,
|
filter: UpdateFilter<Message, any, State>,
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
): UpdateFilter<MessageContext, {}, State> {
|
): UpdateFilter<MessageContext | BusinessMessageContext, {}, State> {
|
||||||
return (ctx, state) => {
|
return (ctx, state) => {
|
||||||
let i = 0
|
let i = 0
|
||||||
const upds = ctx.messages
|
const upds = ctx.messages
|
||||||
|
|
|
@ -18,6 +18,7 @@ import {
|
||||||
Video,
|
Video,
|
||||||
} from '@mtcute/core'
|
} from '@mtcute/core'
|
||||||
|
|
||||||
|
import { BusinessMessageContext } from '../context/business-message.js'
|
||||||
import { MessageContext } from '../index.js'
|
import { MessageContext } from '../index.js'
|
||||||
import { Modify, UpdateFilter } from './types.js'
|
import { Modify, UpdateFilter } from './types.js'
|
||||||
|
|
||||||
|
@ -35,6 +36,11 @@ export const incoming: UpdateFilter<Message, { isOutgoing: false }> = (msg) => !
|
||||||
*/
|
*/
|
||||||
export const outgoing: UpdateFilter<Message, { isOutgoing: true }> = (msg) => msg.isOutgoing
|
export const outgoing: UpdateFilter<Message, { isOutgoing: true }> = (msg) => msg.isOutgoing
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter for scheduled messages
|
||||||
|
*/
|
||||||
|
export const scheduled: UpdateFilter<Message, { isScheduled: true }> = (msg) => msg.isScheduled
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter messages that are replies to some other message
|
* Filter messages that are replies to some other message
|
||||||
*/
|
*/
|
||||||
|
@ -237,14 +243,16 @@ export const sender =
|
||||||
export const replyTo =
|
export const replyTo =
|
||||||
<Mod, State extends object>(
|
<Mod, State extends object>(
|
||||||
filter?: UpdateFilter<Message, Mod, State>,
|
filter?: UpdateFilter<Message, Mod, State>,
|
||||||
): UpdateFilter<MessageContext, { getReplyTo: () => Promise<Message & Mod> }, State> =>
|
): UpdateFilter<MessageContext | BusinessMessageContext, { getReplyTo: () => Promise<Message & Mod> }, State> =>
|
||||||
async (msg, state) => {
|
async (msg, state) => {
|
||||||
if (!msg.replyToMessage?.id) return false
|
if (!msg.replyToMessage?.id) return false
|
||||||
|
|
||||||
const reply = await msg.getReplyTo()
|
const reply = msg._name === 'new_message' ? await msg.getReplyTo() : msg.replyTo
|
||||||
if (!reply) return false
|
if (!reply) return false
|
||||||
|
|
||||||
|
if (msg._name === 'new_message') {
|
||||||
msg.getReplyTo = () => Promise.resolve(reply)
|
msg.getReplyTo = () => Promise.resolve(reply)
|
||||||
|
}
|
||||||
|
|
||||||
if (!filter) return true
|
if (!filter) return true
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,9 @@ export const userId: {
|
||||||
return (upd) => {
|
return (upd) => {
|
||||||
switch (upd._name) {
|
switch (upd._name) {
|
||||||
case 'new_message':
|
case 'new_message':
|
||||||
case 'edit_message': {
|
case 'edit_message':
|
||||||
|
case 'new_business_message':
|
||||||
|
case 'edit_business_message': {
|
||||||
const sender = upd.sender
|
const sender = upd.sender
|
||||||
|
|
||||||
return (matchSelf && sender.isSelf) ||
|
return (matchSelf && sender.isSelf) ||
|
||||||
|
|
|
@ -2,8 +2,10 @@ import {
|
||||||
BotReactionCountUpdate,
|
BotReactionCountUpdate,
|
||||||
BotReactionUpdate,
|
BotReactionUpdate,
|
||||||
BotStoppedUpdate,
|
BotStoppedUpdate,
|
||||||
|
BusinessConnection,
|
||||||
ChatJoinRequestUpdate,
|
ChatJoinRequestUpdate,
|
||||||
ChatMemberUpdate,
|
ChatMemberUpdate,
|
||||||
|
DeleteBusinessMessageUpdate,
|
||||||
DeleteMessageUpdate,
|
DeleteMessageUpdate,
|
||||||
DeleteStoryUpdate,
|
DeleteStoryUpdate,
|
||||||
HistoryReadUpdate,
|
HistoryReadUpdate,
|
||||||
|
@ -19,6 +21,7 @@ import {
|
||||||
import { TelegramClient } from '@mtcute/core/client.js'
|
import { TelegramClient } from '@mtcute/core/client.js'
|
||||||
|
|
||||||
import { UpdateContext } from './context/base.js'
|
import { UpdateContext } from './context/base.js'
|
||||||
|
import { BusinessMessageContext } from './context/business-message.js'
|
||||||
import {
|
import {
|
||||||
CallbackQueryContext,
|
CallbackQueryContext,
|
||||||
ChatJoinRequestUpdateContext,
|
ChatJoinRequestUpdateContext,
|
||||||
|
@ -89,6 +92,29 @@ export type BotReactionCountUpdateHandler<T = UpdateContext<BotReactionCountUpda
|
||||||
'bot_reaction_count',
|
'bot_reaction_count',
|
||||||
T
|
T
|
||||||
>
|
>
|
||||||
|
export type BusinessConnectionUpdateHandler<T = UpdateContext<BusinessConnection>> = ParsedUpdateHandler<
|
||||||
|
'business_connection',
|
||||||
|
T
|
||||||
|
>
|
||||||
|
export type NewBusinessMessageHandler<T = BusinessMessageContext, S = never> = ParsedUpdateHandler<
|
||||||
|
'new_business_message',
|
||||||
|
T,
|
||||||
|
S
|
||||||
|
>
|
||||||
|
export type EditBusinessMessageHandler<T = BusinessMessageContext, S = never> = ParsedUpdateHandler<
|
||||||
|
'edit_business_message',
|
||||||
|
T,
|
||||||
|
S
|
||||||
|
>
|
||||||
|
export type BusinessMessageGroupHandler<T = BusinessMessageContext, S = never> = ParsedUpdateHandler<
|
||||||
|
'business_message_group',
|
||||||
|
T,
|
||||||
|
S
|
||||||
|
>
|
||||||
|
export type DeleteBusinessMessageHandler<T = UpdateContext<DeleteBusinessMessageUpdate>> = ParsedUpdateHandler<
|
||||||
|
'delete_business_message',
|
||||||
|
T
|
||||||
|
>
|
||||||
|
|
||||||
export type UpdateHandler =
|
export type UpdateHandler =
|
||||||
| RawUpdateHandler
|
| RawUpdateHandler
|
||||||
|
@ -114,5 +140,10 @@ export type UpdateHandler =
|
||||||
| DeleteStoryHandler
|
| DeleteStoryHandler
|
||||||
| BotReactionUpdateHandler
|
| BotReactionUpdateHandler
|
||||||
| BotReactionCountUpdateHandler
|
| BotReactionCountUpdateHandler
|
||||||
|
| BusinessConnectionUpdateHandler
|
||||||
|
| NewBusinessMessageHandler
|
||||||
|
| EditBusinessMessageHandler
|
||||||
|
| BusinessMessageGroupHandler
|
||||||
|
| DeleteBusinessMessageHandler
|
||||||
|
|
||||||
// end-codegen
|
// end-codegen
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { assertNever, MaybePromise, Peer } from '@mtcute/core'
|
import { assertNever, MaybePromise, Peer } from '@mtcute/core'
|
||||||
|
|
||||||
|
import { BusinessMessageContext } from '../context/business-message.js'
|
||||||
import { CallbackQueryContext, MessageContext } from '../context/index.js'
|
import { CallbackQueryContext, MessageContext } from '../context/index.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -10,7 +11,9 @@ import { CallbackQueryContext, MessageContext } from '../context/index.js'
|
||||||
* @param msg Message or callback from which to derive the key
|
* @param msg Message or callback from which to derive the key
|
||||||
* @param scene Current scene UID, or `null` if none
|
* @param scene Current scene UID, or `null` if none
|
||||||
*/
|
*/
|
||||||
export type StateKeyDelegate = (upd: MessageContext | CallbackQueryContext | Peer) => MaybePromise<string | null>
|
export type StateKeyDelegate = (
|
||||||
|
upd: MessageContext | BusinessMessageContext | CallbackQueryContext | Peer,
|
||||||
|
) => MaybePromise<string | null>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default state key delegate.
|
* Default state key delegate.
|
||||||
|
@ -29,7 +32,7 @@ export const defaultStateKeyDelegate: StateKeyDelegate = (upd): string | null =>
|
||||||
return String(upd.id)
|
return String(upd.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (upd._name === 'new_message') {
|
if (upd._name === 'new_message' || upd._name === 'new_business_message') {
|
||||||
switch (upd.chat.chatType) {
|
switch (upd.chat.chatType) {
|
||||||
case 'private':
|
case 'private':
|
||||||
case 'bot':
|
case 'bot':
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
TL schema and related utils used for mtcute.
|
TL schema and related utils used for mtcute.
|
||||||
|
|
||||||
Generated from TL layer **177** (last updated on 01.04.2024).
|
Generated from TL layer **179** (last updated on 03.05.2024).
|
||||||
|
|
||||||
## About
|
## About
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@mtcute/tl",
|
"name": "@mtcute/tl",
|
||||||
"version": "177.0.0",
|
"version": "179.0.0",
|
||||||
"description": "TL schema used for mtcute",
|
"description": "TL schema used for mtcute",
|
||||||
"author": "alina sireneva <alina@tei.su>",
|
"author": "alina sireneva <alina@tei.su>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|
Loading…
Reference in a new issue