diff --git a/packages/client/src/client.ts b/packages/client/src/client.ts index 423266d1..57aeb965 100644 --- a/packages/client/src/client.ts +++ b/packages/client/src/client.ts @@ -17,9 +17,10 @@ import { downloadAsBuffer } from './methods/files/download-buffer' import { downloadToFile } from './methods/files/download-file' import { downloadAsIterable } from './methods/files/download-iterable' import { downloadAsStream } from './methods/files/download-stream' -import { UploadedFile } from './types/files/uploaded-file' import { uploadFile } from './methods/files/upload-file' +import { deleteMessages } from './methods/messages/delete-messages' import { _findMessageInUpdate } from './methods/messages/find-in-update' +import { getHistory } from './methods/messages/get-history' import { getMessages } from './methods/messages/get-messages' import { _parseEntities } from './methods/messages/parse-entities' import { sendPhoto } from './methods/messages/send-photo' @@ -60,6 +61,7 @@ import { UpdateFilter, UpdateHandler, UploadFileLike, + UploadedFile, User, filters, handlers, @@ -99,7 +101,6 @@ export class TelegramClient extends BaseTelegramClient { acceptTos(tosId: string): Promise { return acceptTos.apply(this, arguments) } - /** * Check your Two-Step verification password and log in * @@ -110,7 +111,6 @@ export class TelegramClient extends BaseTelegramClient { checkPassword(password: string): Promise { return checkPassword.apply(this, arguments) } - /** * Get your Two-Step Verification password hint. * @@ -119,7 +119,6 @@ export class TelegramClient extends BaseTelegramClient { getPasswordHint(): Promise { return getPasswordHint.apply(this, arguments) } - /** * Log out from Telegram account and optionally reset the session storage. * @@ -132,7 +131,6 @@ export class TelegramClient extends BaseTelegramClient { logOut(resetSession = false): Promise { return logOut.apply(this, arguments) } - /** * Recover your password with a recovery code and log in. * @@ -143,7 +141,6 @@ export class TelegramClient extends BaseTelegramClient { recoverPassword(recoveryCode: string): Promise { return recoverPassword.apply(this, arguments) } - /** * Re-send the confirmation code using a different type. * @@ -156,7 +153,6 @@ export class TelegramClient extends BaseTelegramClient { resendCode(phone: string, phoneCodeHash: string): Promise { return resendCode.apply(this, arguments) } - /** * Send the confirmation code to the given phone number * @@ -166,7 +162,6 @@ export class TelegramClient extends BaseTelegramClient { sendCode(phone: string): Promise { return sendCode.apply(this, arguments) } - /** * Send a code to email needed to recover your password * @@ -175,7 +170,6 @@ export class TelegramClient extends BaseTelegramClient { sendRecoveryCode(): Promise { return sendRecoveryCode.apply(this, arguments) } - /** * Authorize a bot using its token issued by [@BotFather](//t.me/BotFather) * @@ -186,7 +180,6 @@ export class TelegramClient extends BaseTelegramClient { signInBot(token: string): Promise { return signInBot.apply(this, arguments) } - /** * Authorize a user in Telegram with a valid confirmation code. * @@ -208,7 +201,6 @@ export class TelegramClient extends BaseTelegramClient { ): Promise { return signIn.apply(this, arguments) } - /** * Register a new user in Telegram. * @@ -225,7 +217,6 @@ export class TelegramClient extends BaseTelegramClient { ): Promise { return signUp.apply(this, arguments) } - /** * Start the client in an interactive and declarative manner, * by providing callbacks for authorization details. @@ -312,14 +303,16 @@ export class TelegramClient extends BaseTelegramClient { codeSentCallback?: (code: SentCode) => MaybeAsync /** - * Whether to "catch up" (load missed updates) after authorization. + * Whether to "catch up" (load missed updates). + * Note: you should register your handlers + * before calling `start()` + * * Defaults to true. */ catchUp?: boolean }): Promise { return start.apply(this, arguments) } - /** * Download a file and return its contents as a Buffer. * @@ -331,7 +324,6 @@ export class TelegramClient extends BaseTelegramClient { downloadAsBuffer(params: FileDownloadParameters): Promise { return downloadAsBuffer.apply(this, arguments) } - /** * Download a remote file to a local file (only for NodeJS). * Promise will resolve once the download is complete. @@ -345,7 +337,6 @@ export class TelegramClient extends BaseTelegramClient { ): Promise { return downloadToFile.apply(this, arguments) } - /** * Download a file and return it as an iterable, which yields file contents * in chunks of a given size. Order of the chunks is guaranteed to be @@ -358,7 +349,6 @@ export class TelegramClient extends BaseTelegramClient { ): AsyncIterableIterator { return downloadAsIterable.apply(this, arguments) } - /** * Download a file and return it as a Node readable stream, * streaming file contents. @@ -368,7 +358,6 @@ export class TelegramClient extends BaseTelegramClient { downloadAsStream(params: FileDownloadParameters): Readable { return downloadAsStream.apply(this, arguments) } - /** * Upload a file to Telegram servers, without actually * sending a message anywhere. Useful when an `InputFile` is required. @@ -429,11 +418,72 @@ export class TelegramClient extends BaseTelegramClient { }): Promise { return uploadFile.apply(this, arguments) } + /** + * Delete messages, including service messages. + * + * @param chatId Chat's marked ID, its username, phone or `"me"` or `"self"`. + * @param ids Message(s) ID(s) to delete. + * @param revoke Whether to "revoke" (i.e. delete for both sides). Only used for chats and private chats. + */ + deleteMessages( + chatId: InputPeerLike, + ids: MaybeArray, + revoke = true + ): Promise { + return deleteMessages.apply(this, arguments) + } protected _findMessageInUpdate(res: tl.TypeUpdates): Message { return _findMessageInUpdate.apply(this, arguments) } + /** + * Retrieve a chunk of the chat history. + * + * You can get up to 100 messages with one call. + * For larger chunks, use {@link TelegramClient.iterHistory}. + * + * @param chatId Chat's marked ID, its username, phone or `"me"` or `"self"`. + * @param params Additional fetch parameters + */ + getHistory( + chatId: InputPeerLike, + params?: { + /** + * Limits the number of messages to be retrieved. + * + * Defaults to `100`. + */ + limit?: number + /** + * Sequential number of the first message to be returned. + * Defaults to 0 (most recent message). + * + * Negative values are also accepted and are useful + * in case you set `offsetId` or `offsetDate`. + */ + offset?: number + + /** + * Pass a message identifier as an offset to retrieve + * only older messages starting from that message + */ + offsetId?: number + + /** + * Pass a date (`Date` or Unix time in ms) as an offset to retrieve + * only older messages starting from that date. + */ + offsetDate?: number | Date + + /** + * Pass `true` to retrieve messages in reversed order (from older to recent) + */ + reverse?: boolean + } + ): Promise { + return getHistory.apply(this, arguments) + } /** * Get a single message in chat by its ID * @@ -482,7 +532,6 @@ export class TelegramClient extends BaseTelegramClient { ): Promise<[string, tl.TypeMessageEntity[] | undefined]> { return _parseEntities.apply(this, arguments) } - /** * Send a single photo * @@ -556,7 +605,6 @@ export class TelegramClient extends BaseTelegramClient { ): Promise> { return sendPhoto.apply(this, arguments) } - /** * Send a text message * @@ -614,7 +662,6 @@ export class TelegramClient extends BaseTelegramClient { ): Promise> { return sendText.apply(this, arguments) } - /** * Register a given {@link IMessageEntityParser} as a parse mode * for messages. When this method is first called, given parse @@ -630,7 +677,6 @@ export class TelegramClient extends BaseTelegramClient { ): void { return registerParseMode.apply(this, arguments) } - /** * Unregister a parse mode by its name. * Will silently fail if given parse mode does not exist. @@ -642,7 +688,6 @@ export class TelegramClient extends BaseTelegramClient { unregisterParseMode(name: string): void { return unregisterParseMode.apply(this, arguments) } - /** * Get a {@link IMessageEntityParser} registered under a given name (or a default one). * @@ -653,7 +698,6 @@ export class TelegramClient extends BaseTelegramClient { getParseMode(name?: string | null): IMessageEntityParser { return getParseMode.apply(this, arguments) } - /** * Set a given parse mode as a default one. * @@ -663,7 +707,6 @@ export class TelegramClient extends BaseTelegramClient { setDefaultParseMode(name: string): void { return setDefaultParseMode.apply(this, arguments) } - /** * Catch up with the server by loading missed updates. * @@ -671,7 +714,6 @@ export class TelegramClient extends BaseTelegramClient { catchUp(): Promise { return catchUp.apply(this, arguments) } - protected _dispatchUpdate( update: tl.TypeUpdate, users: Record, @@ -679,7 +721,6 @@ export class TelegramClient extends BaseTelegramClient { ): Promise { return _dispatchUpdate.apply(this, arguments) } - /** * Add an update handler to a given handlers group * @@ -689,7 +730,6 @@ export class TelegramClient extends BaseTelegramClient { addUpdateHandler(handler: UpdateHandler, group = 0): void { return addUpdateHandler.apply(this, arguments) } - /** * Remove an update handler (or handlers) from a given * handler group. @@ -703,11 +743,9 @@ export class TelegramClient extends BaseTelegramClient { ): void { return removeUpdateHandler.apply(this, arguments) } - protected _handleUpdate(update: tl.TypeUpdates): void { return _handleUpdate.apply(this, arguments) } - /** * Register a message handler without any filters. * @@ -739,7 +777,6 @@ export class TelegramClient extends BaseTelegramClient { ): void { return onNewMessage.apply(this, arguments) } - /** * Block a user * @@ -749,7 +786,6 @@ export class TelegramClient extends BaseTelegramClient { blockUser(id: InputPeerLike): Promise { return blockUser.apply(this, arguments) } - /** * Get a list of common chats you have with a given user * @@ -759,7 +795,6 @@ export class TelegramClient extends BaseTelegramClient { getCommonChats(userId: InputPeerLike): Promise { return getCommonChats.apply(this, arguments) } - /** * Get currently authorized user's full information * @@ -767,7 +802,6 @@ export class TelegramClient extends BaseTelegramClient { getMe(): Promise { return getMe.apply(this, arguments) } - /** * Get information about a single user. * @@ -785,7 +819,6 @@ export class TelegramClient extends BaseTelegramClient { getUsers(ids: MaybeArray): Promise> { return getUsers.apply(this, arguments) } - /** * Get the `InputPeer` of a known peer id. * Useful when an `InputPeer` is needed. diff --git a/packages/client/src/methods/messages/delete-messages.ts b/packages/client/src/methods/messages/delete-messages.ts new file mode 100644 index 00000000..66bdcc1b --- /dev/null +++ b/packages/client/src/methods/messages/delete-messages.ts @@ -0,0 +1,41 @@ +import { TelegramClient } from '../../client' +import { InputPeerLike } from '../../types' +import { MaybeArray } from '@mtcute/core' +import { normalizeToInputChannel, normalizeToInputPeer } from '../../utils/peer-utils' + +/** + * Delete messages, including service messages. + * + * @param chatId Chat's marked ID, its username, phone or `"me"` or `"self"`. + * @param ids Message(s) ID(s) to delete. + * @param revoke Whether to "revoke" (i.e. delete for both sides). Only used for chats and private chats. + * @internal + */ +export async function deleteMessages( + this: TelegramClient, + chatId: InputPeerLike, + ids: MaybeArray, + revoke = true +): Promise { + if (!Array.isArray(ids)) ids = [ids] + + const peer = await this.resolvePeer(chatId) + const inputPeer = normalizeToInputPeer(peer) + + let res + if (inputPeer._ === 'inputPeerChannel') { + res = await this.call({ + _: 'channels.deleteMessages', + channel: normalizeToInputChannel(peer)!, + id: ids + }) + } else { + res = await this.call({ + _: 'messages.deleteMessages', + id: ids, + revoke + }) + } + + return !!res.ptsCount +} diff --git a/packages/client/src/methods/messages/get-history.ts b/packages/client/src/methods/messages/get-history.ts new file mode 100644 index 00000000..3cce7b7b --- /dev/null +++ b/packages/client/src/methods/messages/get-history.ts @@ -0,0 +1,85 @@ +import { TelegramClient } from '../../client' +import { InputPeerLike, Message, MtCuteTypeAssertionError } from '../../types' +import { createUsersChatsIndex, normalizeToInputPeer } from '../../utils/peer-utils' +import { normalizeDate } from '../../utils/misc-utils' + +/** + * Retrieve a chunk of the chat history. + * + * You can get up to 100 messages with one call. + * For larger chunks, use {@link TelegramClient.iterHistory}. + * + * @param chatId Chat's marked ID, its username, phone or `"me"` or `"self"`. + * @param params Additional fetch parameters + * @internal + */ +export async function getHistory( + this: TelegramClient, + chatId: InputPeerLike, + params?: { + /** + * Limits the number of messages to be retrieved. + * + * Defaults to `100`. + */ + limit?: number + + /** + * Sequential number of the first message to be returned. + * Defaults to 0 (most recent message). + * + * Negative values are also accepted and are useful + * in case you set `offsetId` or `offsetDate`. + */ + offset?: number + + /** + * Pass a message identifier as an offset to retrieve + * only older messages starting from that message + */ + offsetId?: number + + /** + * Pass a date (`Date` or Unix time in ms) as an offset to retrieve + * only older messages starting from that date. + */ + offsetDate?: number | Date + + /** + * Pass `true` to retrieve messages in reversed order (from older to recent) + */ + reverse?: boolean + } +): Promise { + if (!params) params = {} + + const offsetId = params.offsetId || (params.reverse ? 1 : 0) + const limit = params.limit || 100 + + const peer = normalizeToInputPeer(await this.resolvePeer(chatId)) + + const res = await this.call({ + _: 'messages.getHistory', + peer, + offsetId, + offsetDate: normalizeDate(params.offsetDate) || 0, + addOffset: + (params.offset ? params.offset * (params.reverse ? -1 : 1) : 0) - + (params.reverse ? limit : 0), + limit, + maxId: 0, + minId: 0, + hash: 0, + }) + + if (res._ === 'messages.messagesNotModified') + throw new MtCuteTypeAssertionError( + 'getHistory', + '!messages.messagesNotModified', + res._ + ) + + const { users, chats } = createUsersChatsIndex(res) + + return res.messages.map((msg) => new Message(this, msg, users, chats)) +} diff --git a/packages/client/src/types/messages/message.ts b/packages/client/src/types/messages/message.ts index 372baa8e..0fd90ef2 100644 --- a/packages/client/src/types/messages/message.ts +++ b/packages/client/src/types/messages/message.ts @@ -793,6 +793,15 @@ export class Message { } return this.client.sendText(this.chat.inputPeer, text, params) } + + /** + * Delete this message. + * + * @param revoke Whether to "revoke" (i.e. delete for both sides). Only used for chats and private chats. + */ + delete(revoke = false): Promise { + return this.client.deleteMessages(this.chat.inputPeer, this.id, revoke) + } } makeInspectable(Message, ['empty', 'isScheduled'], ['link'])