chore: re-thought method arguments

also dropped support for registration
This commit is contained in:
alina 🌸 2023-10-07 00:22:08 +03:00 committed by Alina Tumanova
parent a6726ccb40
commit 280a98f52a
81 changed files with 1559 additions and 1454 deletions

View file

@ -147,10 +147,7 @@ module.exports = {
},
],
'space-in-parens': 2,
'key-spacing': [
2,
{ beforeColon: false, afterColon: true, mode: 'strict' },
],
'key-spacing': [2, { beforeColon: false, afterColon: true, mode: 'strict' }],
'space-infix-ops': 2,
'padding-line-between-statements': [
'error',
@ -176,10 +173,7 @@ module.exports = {
{
files: ['**/*.ts', '**/*.tsx'],
env: { browser: true, es6: true, node: true },
extends: [
'plugin:@typescript-eslint/strict',
'plugin:import/typescript',
],
extends: ['plugin:@typescript-eslint/strict', 'plugin:import/typescript'],
globals: { Atomics: 'readonly', SharedArrayBuffer: 'readonly' },
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
@ -234,6 +228,13 @@ module.exports = {
'no-console': 'off',
},
},
{
files: ['packages/client/src/methods/**/*.ts'],
rules: {
// this + max 3 more
'max-params': ['error', 4],
},
},
],
settings: {
'import/resolver': {

File diff suppressed because it is too large Load diff

View file

@ -78,7 +78,6 @@ import {
StoryViewer,
StoryViewersList,
TakeoutSession,
TermsOfService,
TypingStatus,
UploadedFile,
UploadFileLike,

View file

@ -1,5 +1,9 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { MtUnsupportedError, tl } from '@mtcute/core'
import { assertTypeIs } from '@mtcute/core/utils'
import { TelegramClient } from '../../client'
import { User } from '../../types'
// @extension
interface AuthState {
@ -20,3 +24,35 @@ function _initializeAuthState(this: TelegramClient) {
this._selfUsername = null
this.log.prefix = '[USER N/A] '
}
/** @internal */
export async function _onAuthorization(
this: TelegramClient,
auth: tl.auth.TypeAuthorization,
bot = false,
): Promise<User> {
if (auth._ === 'auth.authorizationSignUpRequired') {
throw new MtUnsupportedError(
'Signup is no longer supported by Telegram for non-official clients. Please use your mobile device to sign up.',
)
}
assertTypeIs('_onAuthorization (@ auth.authorization -> user)', auth.user, 'user')
this._userId = auth.user.id
this.log.prefix = `[USER ${this._userId}] `
this._isBot = bot
this._selfUsername = auth.user.username!
this._selfChanged = true
await this.network.notifyLoggedIn(auth)
await this._fetchUpdatesState()
await this._saveStorage()
// telegram ignores invokeWithoutUpdates for auth methods
if (this.network.params.disableUpdates) this.network.resetSessions()
else this.startUpdatesLoop()
return new User(this, auth.user)
}

View file

@ -1,25 +0,0 @@
import { MtTypeAssertionError } from '@mtcute/core'
import { TelegramClient } from '../../client'
/**
* Accept the given TOS
*
* @param tosId TOS id
* @internal
*/
export async function acceptTos(this: TelegramClient, tosId: string): Promise<boolean> {
const res = await this.call({
_: 'help.acceptTermsOfService',
id: {
_: 'dataJSON',
data: tosId,
},
})
if (!res) {
throw new MtTypeAssertionError('help.acceptTermsOfService', 'true', 'false')
}
return true
}

View file

@ -1,4 +1,4 @@
import { assertTypeIs, computeSrpParams } from '@mtcute/core/utils'
import { computeSrpParams } from '@mtcute/core/utils'
import { TelegramClient } from '../../client'
import { User } from '../../types'
@ -23,22 +23,5 @@ export async function checkPassword(this: TelegramClient, password: string): Pro
),
})
assertTypeIs('checkPassword (@ auth.checkPassword)', res, 'auth.authorization')
assertTypeIs('checkPassword (@ auth.checkPassword -> user)', res.user, 'user')
this._userId = res.user.id
this.log.prefix = `[USER ${this._userId}] `
this._isBot = false
this._selfChanged = true
this._selfUsername = res.user.username ?? null
await this.network.notifyLoggedIn(res)
await this._fetchUpdatesState()
await this._saveStorage()
// telegram ignores invokeWithoutUpdates for auth methods
if (this.network.params.disableUpdates) this.network.resetSessions()
else this.startUpdatesLoop()
return new User(this, res.user)
return this._onAuthorization(res)
}

View file

@ -1,29 +1,26 @@
import { assertTypeIs } from '@mtcute/core/utils'
import { TelegramClient } from '../../client'
import { User } from '../../types'
/**
* Recover your password with a recovery code and log in.
*
* @param recoveryCode The recovery code sent via email
* @returns The authorized user
* @throws BadRequestError In case the code is invalid
* @internal
*/
export async function recoverPassword(this: TelegramClient, recoveryCode: string): Promise<User> {
export async function recoverPassword(
this: TelegramClient,
params: {
/** The recovery code sent via email */
recoveryCode: string
},
): Promise<User> {
const { recoveryCode } = params
const res = await this.call({
_: 'auth.recoverPassword',
code: recoveryCode,
})
assertTypeIs('recoverPassword (@ auth.recoverPassword)', res, 'auth.authorization')
assertTypeIs('recoverPassword (@ auth.recoverPassword -> user)', res.user, 'user')
this._userId = res.user.id
this._isBot = false
this._selfChanged = true
await this._saveStorage()
return new User(this, res.user)
return this._onAuthorization(res)
}

View file

@ -10,16 +10,23 @@ import { normalizePhoneNumber } from '../../utils/misc-utils'
* The type of the code to be re-sent is specified in the `nextType` attribute of
* {@link SentCode} object returned by {@link sendCode}
*
* @param phone Phone number in international format
* @param phoneCodeHash Confirmation code identifier from {@link SentCode}
* @internal
*/
export async function resendCode(this: TelegramClient, phone: string, phoneCodeHash: string): Promise<SentCode> {
phone = normalizePhoneNumber(phone)
export async function resendCode(
this: TelegramClient,
params: {
/** Phone number in international format */
phone: string
/** Confirmation code identifier from {@link SentCode} */
phoneCodeHash: string
},
): Promise<SentCode> {
const { phone, phoneCodeHash } = params
const res = await this.call({
_: 'auth.resendCode',
phoneNumber: phone,
phoneNumber: normalizePhoneNumber(phone),
phoneCodeHash,
})

View file

@ -7,12 +7,17 @@ import { normalizePhoneNumber } from '../../utils/misc-utils'
/**
* Send the confirmation code to the given phone number
*
* @param phone Phone number in international format.
* @returns An object containing information about the sent confirmation code
* @internal
*/
export async function sendCode(this: TelegramClient, phone: string): Promise<SentCode> {
phone = normalizePhoneNumber(phone)
export async function sendCode(
this: TelegramClient,
params: {
/** Phone number in international format */
phone: string
},
): Promise<SentCode> {
const phone = normalizePhoneNumber(params.phone)
const res = await this.call({
_: 'auth.sendCode',

View file

@ -1,5 +1,3 @@
import { assertTypeIs } from '@mtcute/core/utils'
import { TelegramClient } from '../../client'
import { User } from '../../types'
@ -20,23 +18,5 @@ export async function signInBot(this: TelegramClient, token: string): Promise<Us
botAuthToken: token,
})
assertTypeIs('signInBot (@ auth.importBotAuthorization)', res, 'auth.authorization')
assertTypeIs('signInBot (@ auth.importBotAuthorization -> user)', res.user, 'user')
this._userId = res.user.id
this.log.prefix = `[USER ${this._userId}] `
this._isBot = true
this._selfUsername = res.user.username!
this._selfChanged = true
await this.network.notifyLoggedIn(res)
await this._fetchUpdatesState()
await this._saveStorage()
// telegram ignores invokeWithoutUpdates for auth methods
if (this.network.params.disableUpdates) this.network.resetSessions()
else this.startUpdatesLoop()
return new User(this, res.user)
return this._onAuthorization(res, true)
}

View file

@ -1,60 +1,34 @@
import { assertTypeIs } from '@mtcute/core/utils'
import { TelegramClient } from '../../client'
import { TermsOfService, User } from '../../types'
import { User } from '../../types'
import { normalizePhoneNumber } from '../../utils/misc-utils'
/**
* Authorize a user in Telegram with a valid confirmation code.
*
* @param phone Phone number in international format
* @param phoneCodeHash Code identifier from {@link TelegramClient.sendCode}
* @param phoneCode The confirmation code that was received
* @returns
* - If the code was valid and authorization succeeded, the {@link User} is returned.
* - If the given phone number needs to be registered AND the ToS must be accepted,
* an object containing them is returned.
* - If the given phone number needs to be registered, `false` is returned.
* @throws BadRequestError In case the arguments are invalid
* @throws SessionPasswordNeededError In case a password is needed to sign in
* @returns If the code was valid and authorization succeeded, the {@link User} is returned.
* @throws BadRequestError In case the arguments are invalid
* @throws SessionPasswordNeededError In case a password is needed to sign in
* @internal
*/
export async function signIn(
this: TelegramClient,
phone: string,
phoneCodeHash: string,
phoneCode: string,
): Promise<User | TermsOfService | false> {
phone = normalizePhoneNumber(phone)
params: {
/** Phone number in international format */
phone: string
/** Code identifier from {@link sendCode} */
phoneCodeHash: string
/** The confirmation code that was received */
phoneCode: string
},
): Promise<User> {
const { phone, phoneCodeHash, phoneCode } = params
const res = await this.call({
_: 'auth.signIn',
phoneNumber: phone,
phoneNumber: normalizePhoneNumber(phone),
phoneCodeHash,
phoneCode,
})
if (res._ === 'auth.authorizationSignUpRequired') {
if (res.termsOfService) return new TermsOfService(res.termsOfService)
return false
}
assertTypeIs('signIn (@ auth.signIn -> user)', res.user, 'user')
this._userId = res.user.id
this.log.prefix = `[USER ${this._userId}] `
this._isBot = false
this._selfChanged = true
this._selfUsername = res.user.username ?? null
await this.network.notifyLoggedIn(res)
await this._fetchUpdatesState()
await this._saveStorage()
// telegram ignores invokeWithoutUpdates for auth methods
if (this.network.params.disableUpdates) this.network.resetSessions()
else this.startUpdatesLoop()
return new User(this, res.user)
return this._onAuthorization(res)
}

View file

@ -1,51 +0,0 @@
import { assertTypeIs } from '@mtcute/core/utils'
import { TelegramClient } from '../../client'
import { User } from '../../types'
import { normalizePhoneNumber } from '../../utils/misc-utils'
/**
* Register a new user in Telegram.
*
* @param phone Phone number in international format
* @param phoneCodeHash Code identifier from {@link TelegramClient.sendCode}
* @param firstName New user's first name
* @param lastName New user's last name
* @internal
*/
export async function signUp(
this: TelegramClient,
phone: string,
phoneCodeHash: string,
firstName: string,
lastName = '',
): Promise<User> {
phone = normalizePhoneNumber(phone)
const res = await this.call({
_: 'auth.signUp',
phoneNumber: phone,
phoneCodeHash,
firstName,
lastName,
})
assertTypeIs('signUp (@ auth.signUp)', res, 'auth.authorization')
assertTypeIs('signUp (@ auth.signUp -> user)', res.user, 'user')
this._userId = res.user.id
this.log.prefix = `[USER ${this._userId}] `
this._isBot = false
this._selfChanged = true
await this.network.notifyLoggedIn(res)
await this._fetchUpdatesState()
await this._saveStorage()
// telegram ignores invokeWithoutUpdates for auth methods
if (this.network.params.disableUpdates) this.network.resetSessions()
else this.startUpdatesLoop()
return new User(this, res.user)
}

View file

@ -1,7 +1,7 @@
import { MtArgumentError } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { MaybeDynamic, User } from '../../types'
import { User } from '../../types'
/**
* Utility function to quickly authorize on test DC
@ -35,25 +35,6 @@ export async function startTest(
* Override user's DC. Must be a valid test DC.
*/
dcId?: number
/**
* First name of the user (used only for sign-up, defaults to 'User')
*/
firstName?: MaybeDynamic<string>
/**
* Last name of the user (used only for sign-up, defaults to empty)
*/
lastName?: MaybeDynamic<string>
/**
* By using this method to sign up an account, you are agreeing to Telegram
* ToS. This is required and your account will be banned otherwise.
* See https://telegram.org/tos and https://core.telegram.org/api/terms.
*
* If true, TOS will not be displayed and `tosCallback` will not be called.
*/
acceptTos?: boolean
},
): Promise<User> {
if (!params) params = {}
@ -100,9 +81,6 @@ export async function startTest(
return this.start({
phone,
code: () => code,
firstName: params.firstName,
lastName: params.lastName,
acceptTos: params.acceptTos,
codeSentCallback: (sent) => {
for (let i = 0; i < sent.length; i++) {
code += phone![5]

View file

@ -2,7 +2,7 @@
import { MaybeAsync, MtArgumentError, tl } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { MaybeDynamic, SentCode, TermsOfService, User } from '../../types'
import { MaybeDynamic, SentCode, User } from '../../types'
import { normalizePhoneNumber, resolveMaybeDynamic } from '../../utils/misc-utils'
// @available=both
@ -75,31 +75,6 @@ export async function start(
*/
forceSms?: boolean
/**
* First name of the user (used only for sign-up, defaults to 'User')
*/
firstName?: MaybeDynamic<string>
/**
* Last name of the user (used only for sign-up, defaults to empty)
*/
lastName?: MaybeDynamic<string>
/**
* By using this method to sign up an account, you are agreeing to Telegram
* ToS. This is required and your account will be banned otherwise.
* See https://telegram.org/tos and https://core.telegram.org/api/terms.
*
* If true, TOS will not be displayed and `tosCallback` will not be called.
*/
acceptTos?: boolean
/**
* Custom method to display ToS. Can be used to show a GUI alert of some kind.
* Defaults to `console.log`
*/
tosCallback?: (tos: TermsOfService) => MaybeAsync<void>
/**
* Custom method that is called when a code is sent. Can be used
* to show a GUI alert of some kind.
@ -185,10 +160,10 @@ export async function start(
return await this.signInBot(botToken)
}
let sentCode = await this.sendCode(phone)
let sentCode = await this.sendCode({ phone })
if (params.forceSms && sentCode.type === 'app') {
sentCode = await this.resendCode(phone, sentCode.phoneCodeHash)
sentCode = await this.resendCode({ phone, phoneCodeHash: sentCode.phoneCodeHash })
}
if (params.codeSentCallback) {
@ -199,14 +174,12 @@ export async function start(
let has2fa = false
let result: User | TermsOfService | false
for (;;) {
const code = await resolveMaybeDynamic(params.code)
if (!code) throw new tl.RpcError(400, 'PHONE_CODE_EMPTY')
try {
result = await this.signIn(phone, sentCode.phoneCodeHash, code)
return await this.signIn({ phone, phoneCodeHash: sentCode.phoneCodeHash, phoneCode: code })
} catch (e) {
if (!tl.RpcError.is(e)) throw e
@ -246,7 +219,7 @@ export async function start(
const password = await resolveMaybeDynamic(params.password)
try {
result = await this.checkPassword(password)
return await this.checkPassword(password)
} catch (e) {
if (typeof params.password !== 'function') {
throw new MtArgumentError('Provided password was invalid')
@ -261,41 +234,8 @@ export async function start(
continue
} else throw e
}
break
}
}
// to make ts happy
result = result!
if (result instanceof User) {
return result
}
let tosId: string | null = null
if (result instanceof TermsOfService && !params.acceptTos) {
if (params.tosCallback) {
await params.tosCallback(result)
} else {
console.log(result.text)
}
tosId = result.id
}
// signup
result = await this.signUp(
phone,
sentCode.phoneCodeHash,
await resolveMaybeDynamic(params.firstName ?? 'User'),
await resolveMaybeDynamic(params.lastName),
)
if (tosId) {
await this.acceptTos(tosId)
}
return result
throw new MtArgumentError('Failed to log in with provided credentials')
}

View file

@ -2,7 +2,6 @@ import { Long } from '@mtcute/core'
import { TelegramClient } from '../../client'
// @available=bot
/**
* Send an answer to a callback query.
*
@ -18,7 +17,7 @@ export async function answerCallbackQuery(
* Maximum amount of time in seconds for which
* this result can be cached by the client (not server!).
*
* Defaults to `0`
* @default 0
*/
cacheTime?: number
@ -33,7 +32,7 @@ export async function answerCallbackQuery(
* Whether to show an alert in the middle of the screen
* instead of a notification at the top of the screen.
*
* Defaults to `false`.
* @default false
*/
alert?: boolean
@ -49,14 +48,14 @@ export async function answerCallbackQuery(
url?: string
},
): Promise<void> {
if (!params) params = {}
const { cacheTime = 0, text, alert, url } = params ?? {}
await this.call({
_: 'messages.setBotCallbackAnswer',
queryId,
cacheTime: params.cacheTime ?? 0,
alert: params.alert,
message: params.text,
url: params.url,
cacheTime,
alert,
message: text,
url,
})
}

View file

@ -20,7 +20,7 @@ export async function answerInlineQuery(
* Maximum number of time in seconds that the results of the
* query may be cached on the server for.
*
* Defaults to `300`
* @default 300
*/
cacheTime?: number
@ -39,7 +39,7 @@ export async function answerInlineQuery(
* Whether the results should only be cached on the server
* for the user who sent the query.
*
* Defaults to `false`
* @default false
*/
private?: boolean
@ -47,7 +47,7 @@ export async function answerInlineQuery(
* Next pagination offset (up to 64 bytes).
*
* When user has reached the end of the current results,
* it will re-send the inline query with the same text, but
* the client will re-send the inline query with the same text, but
* with `offset` set to this value.
*
* If omitted or empty string is provided, it is assumed that
@ -95,23 +95,23 @@ export async function answerInlineQuery(
parseMode?: string | null
},
): Promise<void> {
if (!params) params = {}
const { cacheTime = 300, gallery, private: priv, nextOffset, switchPm, parseMode } = params ?? {}
const [gallery, tlResults] = await BotInline._convertToTl(this, results, params.parseMode)
const [defaultGallery, tlResults] = await BotInline._convertToTl(this, results, parseMode)
await this.call({
_: 'messages.setInlineBotResults',
queryId,
results: tlResults,
cacheTime: params.cacheTime ?? 300,
gallery: params.gallery ?? gallery,
private: params.private,
nextOffset: params.nextOffset,
switchPm: params.switchPm ?
cacheTime,
gallery: gallery ?? defaultGallery,
private: priv,
nextOffset,
switchPm: switchPm ?
{
_: 'inlineBotSwitchPM',
text: params.switchPm.text,
startParam: params.switchPm.parameter,
text: switchPm.text,
startParam: switchPm.parameter,
} :
undefined,
})

View file

@ -6,10 +6,18 @@ import { TelegramClient } from '../../client'
* Answer a pre-checkout query.
*
* @param queryId Pre-checkout query ID
* @param error If pre-checkout is rejected, error message to show to the user
* @internal
*/
export async function answerPreCheckoutQuery(this: TelegramClient, queryId: tl.Long, error?: string): Promise<void> {
export async function answerPreCheckoutQuery(
this: TelegramClient,
queryId: tl.Long,
params?: {
/** If pre-checkout is rejected, error message to show to the user */
error?: string
},
): Promise<void> {
const { error } = params ?? {}
await this.call({
_: 'messages.setBotPrecheckoutResults',
queryId,

View file

@ -8,18 +8,21 @@ import { InputPeerLike } from '../../types'
* Request a callback answer from a bot,
* i.e. click an inline button that contains data.
*
* @param chatId Chat ID where the message was found
* @param message ID of the message containing the button
* @param data Data contained in the button
* @param params
* @internal
*/
export async function getCallbackAnswer(
this: TelegramClient,
chatId: InputPeerLike,
message: number,
data: string | Buffer,
params?: {
params: {
/** Chat ID where the message was found */
chatId: InputPeerLike
/** ID of the message containing the button */
message: number
/** Data contained in the button */
data: string | Buffer
/**
* Timeout for the query in ms.
*
@ -33,15 +36,16 @@ export async function getCallbackAnswer(
game?: boolean
/**
* If the button requires password entry,
* your 2FA password.
* If the button requires password entry, your 2FA password.
*
* Your password is never exposed to the
* bot, it is checked by Telegram.
* Your password is never exposed to the bot,
* it is checked by Telegram.
*/
password?: string
},
): Promise<tl.messages.TypeBotCallbackAnswer> {
const { chatId, message, data, game, timeout = 10000 } = params
let password: tl.TypeInputCheckPasswordSRP | undefined = undefined
if (params?.password) {
@ -56,8 +60,8 @@ export async function getCallbackAnswer(
msgId: message,
data: typeof data === 'string' ? Buffer.from(data) : data,
password,
game: params?.game,
game: game,
},
{ timeout: params?.timeout ?? 10000 },
{ timeout },
)
}

View file

@ -8,17 +8,23 @@ import { normalizeToInputUser } from '../../utils/peer-utils'
/**
* Get high scores of a game
*
* @param chatId ID of the chat where the game was found
* @param message ID of the message containing the game
* @param userId ID of the user to find high scores for
* @internal
*/
export async function getGameHighScores(
this: TelegramClient,
chatId: InputPeerLike,
message: number,
userId?: InputPeerLike,
params: {
/** ID of the chat where the game was found */
chatId: InputPeerLike
/** ID of the message containing the game */
message: number
/** ID of the user to find high scores for */
userId?: InputPeerLike
},
): Promise<GameHighScore[]> {
const { chatId, message, userId } = params
const chat = await this.resolvePeer(chatId)
let user: tl.TypeInputUser

View file

@ -17,12 +17,16 @@ export async function setGameScore(
params: {
/** Chat where the game was found */
chatId: InputPeerLike
/** ID of the message where the game was found */
message: number
/** ID of the user who has scored */
userId: InputPeerLike
/** The new score (must be >0) */
score: number
/**
* When `true`, the game message will not be modified
* to include the new score

View file

@ -5,15 +5,19 @@ import { TelegramClient } from '../../client'
/**
* Sets the default chat permissions for the bot in the supergroup or channel.
*
* @param target Whether to target groups or channels.
* @param rights The default chat permissions.
* @internal
*/
export async function setMyDefaultRights(
this: TelegramClient,
target: 'channel' | 'group',
rights: Omit<tl.RawChatAdminRights, '_'>,
params: {
/** Whether to target groups or channels. */
target: 'channel' | 'group'
/** The default chat permissions. */
rights: Omit<tl.RawChatAdminRights, '_'>
},
): Promise<void> {
const { target, rights } = params
await this.call({
_: target === 'group' ? 'bots.setBotGroupDefaultAdminRights' : 'bots.setBotBroadcastDefaultAdminRights',
adminRights: {

View file

@ -10,21 +10,28 @@ import {
} from '../../utils/peer-utils'
/**
* Add new members to a group, supergroup or channel.
* Add one or more new members to a group, supergroup or channel.
*
* @param chatId ID of the chat or its username
* @param users ID(s) of the users, their username(s) or phone(s).
* @param forwardCount
* Number of old messages to be forwarded (0-100).
* Only applicable to legacy groups, ignored for supergroups and channels
* @param users ID(s) of the user(s) to add
* @internal
*/
export async function addChatMembers(
this: TelegramClient,
chatId: InputPeerLike,
users: MaybeArray<InputPeerLike>,
forwardCount = 100,
params: {
/**
* Number of old messages to be forwarded (0-100).
* Only applicable to legacy groups, ignored for supergroups and channels
*
* @default 100
*/
forwardCount?: number
},
): Promise<void> {
const { forwardCount = 100 } = params
const chat = await this.resolvePeer(chatId)
if (!Array.isArray(users)) users = [users]

View file

@ -1,4 +1,4 @@
import { MaybeArray, tl } from '@mtcute/core'
import { MaybeArray } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { InputPeerLike } from '../../types'
@ -12,19 +12,15 @@ import { InputPeerLike } from '../../types'
export async function archiveChats(this: TelegramClient, chats: MaybeArray<InputPeerLike>): Promise<void> {
if (!Array.isArray(chats)) chats = [chats]
const folderPeers: tl.TypeInputFolderPeer[] = []
for (const chat of chats) {
folderPeers.push({
_: 'inputFolderPeer',
peer: await this.resolvePeer(chat),
folderId: 1,
})
}
const resolvedPeers = await this.resolvePeerMany(chats)
const updates = await this.call({
_: 'folders.editPeerFolders',
folderPeers,
folderPeers: resolvedPeers.map((peer) => ({
_: 'inputFolderPeer',
peer,
folderId: 1,
})),
})
this._handleUpdate(updates)
}

View file

@ -17,18 +17,20 @@ import {
* When banning a channel, the user won't be able to use
* any of their channels to post until the ban is lifted.
*
* @param chatId Chat ID
* @param peerId User/Channel ID
* @returns Service message about removed user, if one was generated.
* @internal
*/
export async function banChatMember(
this: TelegramClient,
chatId: InputPeerLike,
peerId: InputPeerLike,
params: {
/** Chat ID */
chatId: InputPeerLike
/** ID of the user/channel to ban */
participantId: InputPeerLike
},
): Promise<Message | null> {
const chat = await this.resolvePeer(chatId)
const peer = await this.resolvePeer(peerId)
const chat = await this.resolvePeer(params.chatId)
const peer = await this.resolvePeer(params.participantId)
let res
if (isInputPeerChannel(chat)) {
@ -49,7 +51,7 @@ export async function banChatMember(
chatId: chat.chatId,
userId: normalizeToInputUser(peer),
})
} else throw new MtInvalidPeerTypeError(chatId, 'chat or channel')
} else throw new MtInvalidPeerTypeError(params.chatId, 'chat or channel')
try {
return this._findMessageInUpdate(res)

View file

@ -7,23 +7,34 @@ import { createDummyUpdate } from '../../utils/updates-utils'
* Delete communication history (for private chats
* and legacy groups)
*
* @param chat Chat or user ID, username, phone number, `"me"` or `"self"`
* @param mode
* Deletion mode. Can be:
* - `delete`: delete messages (only for yourself)
* - `clear`: delete messages (only for yourself)
* - `revoke`: delete messages for all users
* - I'm not sure what's the difference between `delete` and `clear`,
* but they are in fact different flags in TL object.
* @param maxId Maximum ID of message to delete. Defaults to 0 (remove all messages)
* @internal
*/
export async function deleteHistory(
this: TelegramClient,
chat: InputPeerLike,
mode: 'delete' | 'clear' | 'revoke' = 'delete',
maxId = 0,
params?: {
/**
* Deletion mode. Can be:
* - `delete`: delete messages (only for yourself)
* - `clear`: delete messages (only for yourself)
* - `revoke`: delete messages for all users
* - I'm not sure what's the difference between `delete` and `clear`,
* but they are in fact different flags in TL object.
*
* @default 'delete'
*/
mode: 'delete' | 'clear' | 'revoke'
/**
* Maximum ID of message to delete.
*
* @default 0, i.e. remove all messages
*/
maxId?: number
},
): Promise<void> {
const { mode = 'delete', maxId = 0 } = params ?? {}
const peer = await this.resolvePeer(chat)
const res = await this.call({

View file

@ -8,15 +8,19 @@ import { createDummyUpdate } from '../../utils/updates-utils'
/**
* Delete all messages of a user (or channel) in a supergroup
*
* @param chatId Chat ID
* @param participantId User/channel ID
* @internal
*/
export async function deleteUserHistory(
this: TelegramClient,
chatId: InputPeerLike,
participantId: InputPeerLike,
params: {
/** Chat ID */
chatId: InputPeerLike
/** User/channel ID whose messages to delete */
participantId: InputPeerLike
},
): Promise<void> {
const { chatId, participantId } = params
const channel = normalizeToInputChannel(await this.resolvePeer(chatId), chatId)
const peer = await this.resolvePeer(participantId)

View file

@ -7,19 +7,23 @@ import { normalizeToInputChannel, normalizeToInputUser } from '../../utils/peer-
/**
* Edit supergroup/channel admin rights of a user.
*
* @param chatId Chat ID
* @param userId User ID
* @param rights New admin rights
* @param rank Custom admin rank
* @internal
*/
export async function editAdminRights(
this: TelegramClient,
chatId: InputPeerLike,
userId: InputPeerLike,
rights: Omit<tl.RawChatAdminRights, '_'>,
rank = '',
params: {
/** Chat ID */
chatId: InputPeerLike
/** User ID */
userId: InputPeerLike
/** New admin rights */
rights: Omit<tl.RawChatAdminRights, '_'>
/** Custom admin rank */
rank?: string
},
): Promise<void> {
const { chatId, userId, rights, rank = '' } = params
const chat = normalizeToInputChannel(await this.resolvePeer(chatId), chatId)
const user = normalizeToInputUser(await this.resolvePeer(userId), userId)

View file

@ -16,7 +16,6 @@ import { normalizeToInputChannel, normalizeToInputUser } from '../../utils/peer-
* in direct chronological order (i.e. newer
* events have bigger event ID)
*
* @param chatId Chat ID
* @param params
* @internal
*/
@ -73,12 +72,10 @@ export async function getChatEventLog(
limit?: number
},
): Promise<ChatEvent[]> {
if (!params) params = {}
const { maxId = Long.ZERO, minId = Long.ZERO, query = '', limit = 100, users, filters } = params ?? {}
const channel = normalizeToInputChannel(await this.resolvePeer(chatId), chatId)
const { maxId = Long.ZERO, minId = Long.ZERO, query = '', limit = 100, users, filters } = params
const admins: tl.TypeInputUser[] | undefined = users ?
await this.resolvePeerMany(users, normalizeToInputUser) :
undefined

View file

@ -15,9 +15,15 @@ import { isInputPeerChannel, isInputPeerChat, isInputPeerUser, normalizeToInputC
*/
export async function getChatMember(
this: TelegramClient,
chatId: InputPeerLike,
userId: InputPeerLike,
params: {
/** Chat ID or username */
chatId: InputPeerLike
/** User ID, username, phone number, `"me"` or `"self"` */
userId: InputPeerLike
},
): Promise<ChatMember> {
const { chatId, userId } = params
const user = await this.resolvePeer(userId)
const chat = await this.resolvePeer(chatId)

View file

@ -60,7 +60,7 @@ export async function getChatMembers(
type?: 'all' | 'banned' | 'restricted' | 'bots' | 'recent' | 'admins' | 'contacts' | 'mention'
},
): Promise<ArrayWithTotal<ChatMember>> {
if (!params) params = {}
const { query = '', offset = 0, limit = 200, type = 'recent' } = params ?? {}
const chat = await this.resolvePeer(chatId)
@ -75,21 +75,18 @@ export async function getChatMembers(
let members =
res.fullChat.participants._ === 'chatParticipantsForbidden' ? [] : res.fullChat.participants.participants
if (params.offset) members = members.slice(params.offset)
if (params.limit) members = members.slice(0, params.limit)
if (offset) members = members.slice(offset)
if (limit) members = members.slice(0, limit)
const peers = PeersIndex.from(res)
const ret = members.map((m) => new ChatMember(this, m, peers)) as ArrayWithTotal<ChatMember>
const ret = members.map((m) => new ChatMember(this, m, peers))
ret.total = ret.length
return ret
return makeArrayWithTotal(ret, ret.length)
}
if (isInputPeerChannel(chat)) {
const q = params.query?.toLowerCase() ?? ''
const type = params.type ?? 'recent'
const q = query
let filter: tl.TypeChannelParticipantsFilter
@ -126,8 +123,8 @@ export async function getChatMembers(
_: 'channels.getParticipants',
channel: normalizeToInputChannel(chat),
filter,
offset: params.offset ?? 0,
limit: params.limit ?? 200,
offset,
limit,
hash: Long.ZERO,
})

View file

@ -9,7 +9,7 @@ import { INVITE_LINK_REGEX } from '../../utils/peer-utils'
*
* @param inviteLink Invite link
* @throws MtArgumentError In case invite link has invalid format
* @throws MtNotFoundError
* @throws MtPeerNotFoundError
* In case you are trying to get info about private chat that you have already joined.
* Use {@link getChat} or {@link getFullChat} instead.
* @internal

View file

@ -9,24 +9,28 @@ import { isInputPeerChannel } from '../../utils/peer-utils'
*
* This effectively bans a user and immediately unbans them.
*
* @param chatId Chat ID
* @param userId User ID
* @internal
*/
export async function kickChatMember(
this: TelegramClient,
chatId: InputPeerLike,
userId: InputPeerLike,
params: {
/** Chat ID */
chatId: InputPeerLike
/** User ID */
userId: InputPeerLike
},
): Promise<void> {
const { chatId, userId } = params
const chat = await this.resolvePeer(chatId)
const user = await this.resolvePeer(userId)
await this.banChatMember(chat, user)
await this.banChatMember({ chatId: chat, participantId: user })
// not needed in case this is a legacy group
if (isInputPeerChannel(chat)) {
// i fucking love telegram serverside race conditions
await sleep(1000)
await this.unbanChatMember(chat, user)
await this.unbanChatMember({ chatId: chat, participantId: user })
}
}

View file

@ -6,10 +6,18 @@ import { isInputPeerChannel, isInputPeerChat, normalizeToInputChannel } from '..
* Leave a group chat, supergroup or channel
*
* @param chatId Chat ID or username
* @param clear Whether to clear history after leaving (only for legacy group chats)
* @internal
*/
export async function leaveChat(this: TelegramClient, chatId: InputPeerLike, clear = false): Promise<void> {
export async function leaveChat(
this: TelegramClient,
chatId: InputPeerLike,
params?: {
/**
* Whether to clear history after leaving (only for legacy group chats)
*/
clear?: boolean
},
): Promise<void> {
const chat = await this.resolvePeer(chatId)
if (isInputPeerChannel(chat)) {
@ -26,7 +34,7 @@ export async function leaveChat(this: TelegramClient, chatId: InputPeerLike, cle
})
this._handleUpdate(res)
if (clear) {
if (params?.clear) {
await this.deleteHistory(chat)
}
} else throw new MtInvalidPeerTypeError(chatId, 'chat or channel')

View file

@ -8,27 +8,38 @@ import { isInputPeerChannel, normalizeToInputChannel } from '../../utils/peer-ut
/**
* Restrict a user in a supergroup.
*
* @param chatId Chat ID
* @param userId User ID
* @param restrictions
* Restrictions for the user. Note that unlike Bot API, this object contains
* the restrictions, and not the permissions, i.e. to
* passing `sendMessages=true` will disallow the user to send messages,
* and passing `{}` (empty object) will lift any restrictions
* @param until
* Date when the user will be unrestricted.
* When `number` is passed, UNIX time in ms is expected.
* If this value is less than 30 seconds or more than 366 days in
* the future, user will be restricted forever. Defaults to `0` (forever)
* @internal
*/
export async function restrictChatMember(
this: TelegramClient,
chatId: InputPeerLike,
userId: InputPeerLike,
restrictions: Omit<tl.RawChatBannedRights, '_' | 'untilDate'>,
until?: number | Date,
params: {
/** Chat ID */
chatId: InputPeerLike
/** User ID */
userId: InputPeerLike
/**
* Restrictions for the user. Note that unlike Bot API, this object contains
* the restrictions, and not the permissions, i.e.
* passing `sendMessages=true` will disallow the user to send messages,
* and passing `{}` (empty object) will lift any restrictions
*/
restrictions: Omit<tl.RawChatBannedRights, '_' | 'untilDate'>
/**
* Date when the user will be unrestricted.
* When `number` is passed, UNIX time in ms is expected.
* If this value is less than 30 seconds or more than 366 days in
* the future, user will be restricted forever.
*
* @default `0`, i.e. forever
*/
until?: number | Date
},
): Promise<void> {
const { chatId, userId, restrictions, until = 0 } = params
const chat = await this.resolvePeer(chatId)
if (!isInputPeerChannel(chat)) {

View file

@ -12,7 +12,7 @@ import { assertIsUpdatesGroup } from '../../utils/updates-utils'
* @param chatId Chat ID or username
* @param restrictions
* Restrictions for the chat. Note that unlike Bot API, this object contains
* the restrictions, and not the permissions, i.e. to
* the restrictions, and not the permissions, i.e.
* passing `sendMessages=true` will disallow the users to send messages,
* and passing `{}` (empty object) will lift any restrictions
* @internal

View file

@ -10,21 +10,29 @@ import { isInputPeerChannel, isInputPeerChat, normalizeToInputChannel } from '..
*
* You must be an administrator and have the appropriate permissions.
*
* @param chatId Chat ID or username
* @param type Media type (photo or video)
* @param media Input media file
* @param previewSec
* When `type = video`, timestamp in seconds which will be shown
* as a static preview.
* @internal
*/
export async function setChatPhoto(
this: TelegramClient,
chatId: InputPeerLike,
type: 'photo' | 'video',
media: InputFileLike,
previewSec?: number,
params: {
/** Chat ID or username */
chatId: InputPeerLike
/** Media type (photo or video) */
type: 'photo' | 'video'
/** Input media file */
media: InputFileLike
/**
* When `type = video`, timestamp in seconds which will be shown
* as a static preview.
*/
previewSec?: number
},
): Promise<void> {
const { chatId, type, media, previewSec } = params
const chat = await this.resolvePeer(chatId)
if (!(isInputPeerChannel(chat) || isInputPeerChat(chat))) {

View file

@ -8,13 +8,14 @@ import { isInputPeerChannel, isInputPeerUser, normalizeToInputChannel, normalize
* > **Note**: non-collectible usernames must still be changed
* > using {@link setUsername}/{@link setChatUsername}
*
* @param peerId Bot, channel or "me"/"self"
* @internal
*/
export async function toggleFragmentUsername(
this: TelegramClient,
peerId: InputPeerLike,
params: {
/** Peer ID whose username to toggle */
peerId: InputPeerLike
/**
* Username to toggle
*/
@ -26,7 +27,7 @@ export async function toggleFragmentUsername(
active: boolean
},
): Promise<void> {
const { username, active } = params
const { peerId, username, active } = params
const peer = await this.resolvePeer(peerId)

View file

@ -11,17 +11,21 @@ import { isInputPeerChannel, isInputPeerChat, normalizeToInputChannel } from '..
*
* This method acts as a no-op in case a legacy group is passed.
*
* @param chatId Chat ID
* @param peerId User/channel ID
* @internal
*/
export async function unbanChatMember(
this: TelegramClient,
chatId: InputPeerLike,
peerId: InputPeerLike,
params: {
/** Chat ID */
chatId: InputPeerLike
/** User/channel ID who should be unbanned */
participantId: InputPeerLike
},
): Promise<void> {
const { chatId, participantId } = params
const chat = await this.resolvePeer(chatId)
const peer = await this.resolvePeer(peerId)
const peer = await this.resolvePeer(participantId)
if (isInputPeerChannel(chat)) {
const res = await this.call({

View file

@ -6,14 +6,14 @@ import { assertIsUpdatesGroup } from '../../utils/updates-utils'
/**
* Add an existing Telegram user as a contact
*
* @param userId User ID, username or phone number
* @param params Contact details
* @internal
*/
export async function addContact(
this: TelegramClient,
userId: InputPeerLike,
params: {
/** User ID, username or phone number */
userId: InputPeerLike
/**
* First name of the contact
*/
@ -36,15 +36,16 @@ export async function addContact(
sharePhone?: boolean
},
): Promise<User> {
const { userId, firstName, lastName = '', phone = '', sharePhone = false } = params
const peer = normalizeToInputUser(await this.resolvePeer(userId), userId)
const res = await this.call({
_: 'contacts.addContact',
id: peer,
firstName: params.firstName,
lastName: params.lastName ?? '',
phone: params.phone ?? '',
addPhonePrivacyException: Boolean(params.sharePhone),
firstName,
lastName,
phone,
addPhonePrivacyException: sharePhone,
})
assertIsUpdatesGroup('contacts.addContact', res)

View file

@ -5,20 +5,27 @@ import { TelegramClient } from '../../client'
/**
* Edit a folder with given modification
*
* @param folder
* Folder, folder ID or name.
* Note that passing an ID or name will require re-fetching all folders,
* and passing name might affect not the right folder if you have multiple
* with the same name.
* @param modification Modification that will be applied to this folder
* @returns Modified folder
* @internal
*/
export async function editFolder(
this: TelegramClient,
folder: tl.RawDialogFilter | number | string,
modification: Partial<Omit<tl.RawDialogFilter, 'id' | '_'>>,
params: {
/**
* Folder, folder ID or name.
* Note that passing an ID or name will require re-fetching all folders,
* and passing name might affect not the right folder if you have multiple
* with the same name.
*/
folder: tl.RawDialogFilter | number | string
/** Modification to be applied to this folder */
modification: Partial<Omit<tl.RawDialogFilter, 'id' | '_'>>
},
): Promise<tl.RawDialogFilter> {
const { modification } = params
let { folder } = params
if (folder === 0) {
throw new MtArgumentError('Cannot modify default folder')
}

View file

@ -15,8 +15,11 @@ import { TelegramClient } from '../../client'
export async function findFolder(
this: TelegramClient,
params: {
/** Folder title */
title?: string
/** Folder emoji */
emoji?: string
/** Folder ID */
id?: number
},
): Promise<tl.RawDialogFilter | null> {

View file

@ -3,8 +3,7 @@ import { TelegramClient } from '../../client'
/**
* Reorder folders
*
* Order is folder's ID (0 = default folder)
*
* @param order New order of folders (folder IDs, where default = 0)
* @internal
*/
export async function setFoldersOrder(this: TelegramClient, order: number[]): Promise<void> {

View file

@ -10,14 +10,15 @@ import { normalizeToInputChannel } from '../../utils/peer-utils'
*
* Only admins with `manageTopics` permission can do this.
*
* @param chatId Chat ID or username
* @returns Service message for the created topic
* @internal
*/
export async function createForumTopic(
this: TelegramClient,
chatId: InputPeerLike,
params: {
/** Chat ID or username */
chatId: InputPeerLike
/**
* Topic title
*/
@ -39,7 +40,7 @@ export async function createForumTopic(
sendAs?: InputPeerLike
},
): Promise<Message> {
const { title, icon, sendAs } = params
const { chatId, title, icon, sendAs } = params
const res = await this.call({
_: 'channels.createForumTopic',

View file

@ -16,9 +16,12 @@ import { normalizeToInputChannel } from '../../utils/peer-utils'
*/
export async function editForumTopic(
this: TelegramClient,
chatId: InputPeerLike,
topicId: number,
params: {
/** Chat ID or username */
chatId: InputPeerLike
/** ID of the topic (i.e. its top message ID) */
topicId: number
/**
* New topic title
*/
@ -33,7 +36,7 @@ export async function editForumTopic(
icon?: tl.Long | null
},
): Promise<Message> {
const { title, icon } = params
const { chatId, topicId, title, icon } = params
const res = await this.call({
_: 'channels.editForumTopic',

View file

@ -7,14 +7,14 @@ import { normalizeToInputChannel } from '../../utils/peer-utils'
*
* Only admins with `manageTopics` permission can do this.
*
* @param chatId Chat ID or username
* @param topicId ID of the topic (i.e. its top message ID)
* @internal
*/
export async function reorderPinnedForumTopics(
this: TelegramClient,
chatId: InputPeerLike,
params: {
/** Chat ID or username */
chatId: InputPeerLike
/**
* Order of the pinned topics
*/
@ -26,7 +26,7 @@ export async function reorderPinnedForumTopics(
force?: boolean
},
): Promise<void> {
const { order, force } = params
const { chatId, order, force } = params
await this.call({
_: 'channels.reorderPinnedForumTopics',
channel: normalizeToInputChannel(await this.resolvePeer(chatId), chatId),

View file

@ -7,18 +7,24 @@ import { normalizeToInputChannel } from '../../utils/peer-utils'
*
* Only admins with `manageTopics` permission can do this.
*
* @param chatId Chat ID or username
* @param topicId ID of the topic (i.e. its top message ID)
* @param closed Whether the topic should be closed
* @returns Service message about the modification
* @internal
*/
export async function toggleForumTopicClosed(
this: TelegramClient,
chatId: InputPeerLike,
topicId: number,
closed: boolean,
parmas: {
/** Chat ID or username */
chatId: InputPeerLike
/** ID of the topic (i.e. its top message ID) */
topicId: number
/** Whether the topic should be closed */
closed: boolean
},
): Promise<Message> {
const { chatId, topicId, closed } = parmas
const res = await this.call({
_: 'channels.editForumTopic',
channel: normalizeToInputChannel(await this.resolvePeer(chatId), chatId),

View file

@ -7,17 +7,21 @@ import { normalizeToInputChannel } from '../../utils/peer-utils'
*
* Only admins with `manageTopics` permission can do this.
*
* @param chatId Chat ID or username
* @param topicId ID of the topic (i.e. its top message ID)
* @param pinned Whether the topic should be pinned
* @internal
*/
export async function toggleForumTopicPinned(
this: TelegramClient,
chatId: InputPeerLike,
topicId: number,
pinned: boolean,
params: {
/** Chat ID or username */
chatId: InputPeerLike
/** ID of the topic (i.e. its top message ID) */
topicId: number
/** Whether the topic should be pinned */
pinned: boolean
},
): Promise<void> {
const { chatId, topicId, pinned } = params
await this.call({
_: 'channels.updatePinnedForumTopic',
channel: normalizeToInputChannel(await this.resolvePeer(chatId), chatId),

View file

@ -16,9 +16,11 @@ import { normalizeDate } from '../../utils/misc-utils'
*/
export async function editInviteLink(
this: TelegramClient,
chatId: InputPeerLike,
link: string,
params: {
/** Chat ID */
chatId: InputPeerLike
/** Invite link to edit */
link: string
/**
* Date when this link will expire.
* If `number` is passed, UNIX time in ms is expected.
@ -40,13 +42,15 @@ export async function editInviteLink(
withApproval?: boolean
},
): Promise<ChatInviteLink> {
const { chatId, link, expires, usageLimit, withApproval } = params
const res = await this.call({
_: 'messages.editExportedChatInvite',
peer: await this.resolvePeer(chatId),
link,
expireDate: normalizeDate(params.expires),
usageLimit: params.usageLimit,
requestNeeded: params.withApproval,
expireDate: normalizeDate(expires),
usageLimit,
requestNeeded: withApproval,
})
const peers = PeersIndex.from(res)

View file

@ -15,7 +15,7 @@ import { makeArrayPaginated, normalizeDate, normalizeToInputUser } from '../../u
export async function getInviteLinkMembers(
this: TelegramClient,
chatId: InputPeerLike,
params: {
params?: {
/**
* Invite link for which to get members
*/
@ -54,6 +54,7 @@ export async function getInviteLinkMembers(
},
): Promise<ArrayPaginated<ChatInviteLinkMember, { date: number; user: tl.TypeInputUser }>> {
const peer = await this.resolvePeer(chatId)
if (!params) params = {}
const { limit = 100, link, requestedSearch, requested = Boolean(requestedSearch) } = params

View file

@ -4,21 +4,27 @@ import { InputPeerLike } from '../../types'
/**
* Approve or deny multiple join requests to a chat.
*
* @param peer Chat/channel ID
* @param action Whether to approve or deny the join requests
* @param link Invite link to target
* @internal
*/
export async function hideAllJoinRequests(
this: TelegramClient,
peer: InputPeerLike,
action: 'approve' | 'deny',
link?: string,
params: {
/** Chat/channel ID */
chatId: InputPeerLike
/** Whether to approve or deny the join requests */
action: 'approve' | 'deny'
/** Invite link to target */
link?: string
},
): Promise<void> {
const { chatId, action, link } = params
await this.call({
_: 'messages.hideAllChatJoinRequests',
approved: action === 'approve',
peer: await this.resolvePeer(peer),
peer: await this.resolvePeer(chatId),
link,
})
}

View file

@ -5,23 +5,27 @@ import { normalizeToInputUser } from '../../utils/peer-utils'
/**
* Approve or deny join request to a chat.
*
* @param peer Chat/channel ID
* @param user User ID
* @param action Whether to approve or deny the join request
* @internal
*/
export async function hideJoinRequest(
this: TelegramClient,
peer: InputPeerLike,
user: InputPeerLike,
action: 'approve' | 'deny',
params: {
/** Chat/channel ID */
chatId: InputPeerLike
/** User ID */
user: InputPeerLike
/** Whether to approve or deny the join request */
action: 'approve' | 'deny'
},
): Promise<void> {
const { chatId, user, action } = params
const userId = normalizeToInputUser(await this.resolvePeer(user), user)
await this.call({
_: 'messages.hideChatJoinRequest',
approved: action === 'approve',
peer: await this.resolvePeer(peer),
peer: await this.resolvePeer(chatId),
userId,
})
}

View file

@ -12,7 +12,7 @@ import { ChatInviteLinkMember, InputPeerLike } from '../../types'
export async function* iterInviteLinkMembers(
this: TelegramClient,
chatId: InputPeerLike,
params: Parameters<TelegramClient['getInviteLinkMembers']>[1] & {
params?: Parameters<TelegramClient['getInviteLinkMembers']>[1] & {
/**
* Maximum number of users to return
*
@ -30,6 +30,7 @@ export async function* iterInviteLinkMembers(
},
): AsyncIterableIterator<ChatInviteLinkMember> {
const peer = await this.resolvePeer(chatId)
if (!params) params = {}
const { limit = Infinity, chunkSize = 100, link, requestedSearch, requested = Boolean(requestedSearch) } = params

View file

@ -11,11 +11,19 @@ import { assertIsUpdatesGroup } from '../../utils/updates-utils'
* Once closed, poll can't be re-opened, and nobody
* will be able to vote in it
*
* @param chatId Chat ID where this poll was found
* @param message Message ID where this poll was found
* @internal
*/
export async function closePoll(this: TelegramClient, chatId: InputPeerLike, message: number): Promise<Poll> {
export async function closePoll(
this: TelegramClient,
params: {
/** Chat ID where this poll was found */
chatId: InputPeerLike
/** Message ID where this poll was found */
message: number
},
): Promise<Poll> {
const { chatId, message } = params
const res = await this.call({
_: 'messages.editMessage',
peer: await this.resolvePeer(chatId),

View file

@ -10,16 +10,24 @@ import { createDummyUpdate } from '../../utils/updates-utils'
*
* @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<number>,
revoke = true,
params?: {
/**
* Whether to "revoke" (i.e. delete for both sides).
* Only used for chats and private chats.
*
* @default true
*/
revoke?: boolean
},
): Promise<void> {
const { revoke = true } = params ?? {}
if (!Array.isArray(ids)) ids = [ids]
const peer = await this.resolvePeer(chatId)

View file

@ -15,8 +15,13 @@ import { normalizeInlineId } from '../../utils/inline-utils'
*/
export async function editInlineMessage(
this: TelegramClient,
messageId: tl.TypeInputBotInlineMessageID | string,
params: {
/**
* Inline message ID, either as a TL object, or as a
* TDLib and Bot API compatible string
*/
messageId: tl.TypeInputBotInlineMessageID | string
/**
* New message text
*
@ -71,7 +76,7 @@ export async function editInlineMessage(
let entities: tl.TypeMessageEntity[] | undefined
let media: tl.TypeInputMedia | undefined = undefined
const id = normalizeInlineId(messageId)
const id = normalizeInlineId(params.messageId)
if (params.media) {
media = await this._normalizeInputMedia(params.media, params, true)

View file

@ -13,9 +13,12 @@ import { BotKeyboard, FormattedString, InputMediaLike, InputPeerLike, Message, R
*/
export async function editMessage(
this: TelegramClient,
chatId: InputPeerLike,
message: number | Message,
params: {
/** Chat ID */
chatId: InputPeerLike
/** Message to edit */
message: number | Message
/**
* New message text
*
@ -72,6 +75,7 @@ export async function editMessage(
progressCallback?: (uploaded: number, total: number) => void
},
): Promise<Message> {
const { chatId, message } = params
let content: string | undefined = undefined
let entities: tl.TypeMessageEntity[] | undefined
let media: tl.TypeInputMedia | undefined = undefined

View file

@ -11,8 +11,6 @@ import { assertIsUpdatesGroup } from '../../utils/updates-utils'
*
* To forward with a caption, use another overload that takes an array of IDs.
*
* @param toChatId Destination chat ID, username, phone, `"me"` or `"self"`
* @param fromChatId Source chat ID, username, phone, `"me"` or `"self"`
* @param message Message ID
* @param params Additional sending parameters
* @returns Newly sent, forwarded messages in the destination chat
@ -20,10 +18,14 @@ import { assertIsUpdatesGroup } from '../../utils/updates-utils'
*/
export async function forwardMessages(
this: TelegramClient,
toChatId: InputPeerLike,
fromChatId: InputPeerLike,
message: number,
params?: {
params: {
/** Source chat ID, username, phone, `"me"` or `"self"` */
fromChatId: InputPeerLike
/** Destination chat ID, username, phone, `"me"` or `"self"` */
toChatId: InputPeerLike
/** Message ID */
messages: number
/**
* Optionally, a caption for your forwarded message(s).
* It will be sent as a separate message before the forwarded messages.
@ -117,10 +119,14 @@ export async function forwardMessages(
*/
export async function forwardMessages(
this: TelegramClient,
toChatId: InputPeerLike,
fromChatId: InputPeerLike,
messages: number[],
params?: {
params: {
/** Source chat ID, username, phone, `"me"` or `"self"` */
fromChatId: InputPeerLike
/** Destination chat ID, username, phone, `"me"` or `"self"` */
toChatId: InputPeerLike
/** Message IDs */
messages: number[]
/**
* Optionally, a caption for your forwarded message(s).
* It will be sent as a separate message before the forwarded messages.
@ -200,10 +206,11 @@ export async function forwardMessages(
/** @internal */
export async function forwardMessages(
this: TelegramClient,
toChatId: InputPeerLike,
fromChatId: InputPeerLike,
messages: MaybeArray<number>,
params?: {
params: {
toChatId: InputPeerLike
fromChatId: InputPeerLike
messages: MaybeArray<number>
/**
* Optionally, a caption for your forwarded message(s).
* It will be sent as a separate message before the forwarded messages.
@ -283,7 +290,20 @@ export async function forwardMessages(
sendAs?: InputPeerLike
},
): Promise<MaybeArray<Message>> {
if (!params) params = {}
const {
toChatId,
fromChatId,
parseMode,
entities,
silent,
schedule,
clearDraft,
forbidForwards,
sendAs,
noAuthor,
noCaption,
} = params
let { messages } = params
let isSingle = false
@ -309,22 +329,22 @@ export async function forwardMessages(
}
captionMessage = await this.sendText(toPeer, params.caption, {
parseMode: params.parseMode,
entities: params.entities,
silent: params.silent,
schedule: params.schedule,
clearDraft: params.clearDraft,
forbidForwards: params.forbidForwards,
sendAs: params.sendAs,
parseMode,
entities,
silent,
schedule,
clearDraft,
forbidForwards,
sendAs,
})
} else if (params.captionMedia) {
captionMessage = await this.sendMedia(toPeer, params.captionMedia, {
parseMode: params.parseMode,
silent: params.silent,
schedule: params.schedule,
clearDraft: params.clearDraft,
forbidForwards: params.forbidForwards,
sendAs: params.sendAs,
parseMode,
silent,
schedule,
clearDraft,
forbidForwards,
sendAs,
})
}
@ -333,13 +353,13 @@ export async function forwardMessages(
toPeer,
fromPeer: await this.resolvePeer(fromChatId),
id: messages,
silent: params.silent,
scheduleDate: normalizeDate(params.schedule),
silent,
scheduleDate: normalizeDate(schedule),
randomId: Array.from({ length: messages.length }, () => randomLong()),
dropAuthor: params.noAuthor,
dropMediaCaptions: params.noCaption,
noforwards: params.forbidForwards,
sendAs: params.sendAs ? await this.resolvePeer(params.sendAs) : undefined,
dropAuthor: noAuthor,
dropMediaCaptions: noCaption,
noforwards: forbidForwards,
sendAs: sendAs ? await this.resolvePeer(sendAs) : undefined,
})
assertIsUpdatesGroup('messages.forwardMessages', res)

View file

@ -9,17 +9,21 @@ import { InputPeerLike } from '../../types'
*
* @param chatId Chat ID, username, phone number, `"self"` or `"me"`
* @param messageId Message ID
* @param notify Whether to send a notification (only for legacy groups and supergroups)
* @param bothSides Whether to pin for both sides (only for private chats)
* @internal
*/
export async function pinMessage(
this: TelegramClient,
chatId: InputPeerLike,
messageId: number,
notify = false,
bothSides = false,
params?: {
/** Whether to send a notification (only for legacy groups and supergroups) */
notify?: boolean
/** Whether to pin for both sides (only for private chats) */
bothSides?: boolean
},
): Promise<void> {
const { notify, bothSides } = params ?? {}
const res = await this.call({
_: 'messages.updatePinnedMessage',
peer: await this.resolvePeer(chatId),

View file

@ -7,16 +7,27 @@ import { createDummyUpdate } from '../../utils/updates-utils'
* Mark chat history as read.
*
* @param chatId Chat ID
* @param message Message up until which to read history (by default everything is read)
* @param clearMentions Whether to also clear all mentions in the chat
* @internal
*/
export async function readHistory(
this: TelegramClient,
chatId: InputPeerLike,
message = 0,
clearMentions = false,
params?: {
/**
* Message up until which to read history
*
* @default 0, i.e. read everything
*/
maxId?: number
/**
* Whether to also clear all mentions in the chat
*/
clearMentions?: boolean
},
): Promise<void> {
const { maxId = 0, clearMentions } = params ?? {}
const peer = await this.resolvePeer(chatId)
if (clearMentions) {
@ -36,13 +47,13 @@ export async function readHistory(
await this.call({
_: 'channels.readHistory',
channel: normalizeToInputChannel(peer),
maxId: message,
maxId,
})
} else {
const res = await this.call({
_: 'messages.readHistory',
peer,
maxId: message,
maxId,
})
this._handleUpdate(createDummyUpdate(res.pts, res.ptsCount))
}

View file

@ -16,18 +16,18 @@ import { FormattedString, InputPeerLike, Message, MtMessageNotFoundError, ReplyM
* > use {@link Message.sendCopy} instead, since that is
* > much more efficient, and that is what this method wraps.
*
* @param toChatId Source chat ID
* @param fromChatId Target chat ID
* @param message Message ID to forward
* @param params
* @internal
*/
export async function sendCopy(
this: TelegramClient,
toChatId: InputPeerLike,
fromChatId: InputPeerLike,
message: number,
params?: {
params: {
/** Source chat ID */
fromChatId: InputPeerLike
/** Target chat ID */
toChatId: InputPeerLike
/** Message ID to forward */
message: number
/**
* Whether to send this message silently.
*/
@ -97,6 +97,8 @@ export async function sendCopy(
clearDraft?: boolean
},
): Promise<Message> {
const { fromChatId, toChatId, message, ...rest } = params
const fromPeer = await this.resolvePeer(fromChatId)
const msg = await this.getMessages(fromPeer, message)
@ -105,5 +107,5 @@ export async function sendCopy(
throw new MtMessageNotFoundError(getMarkedPeerId(fromPeer), message, 'to copy')
}
return msg.sendCopy(toChatId, params)
return msg.sendCopy(toChatId, rest)
}

View file

@ -5,20 +5,24 @@ import { assertIsUpdatesGroup } from '../../utils/updates-utils'
/**
* Send or remove a reaction.
*
* @param chatId Chat ID with the message to react to
* @param message Message ID to react to
* @param emoji Reaction emoji (or `null` to remove reaction)
* @param big Whether to use a big reaction
* @returns Message to which the reaction was sent
* @internal
*/
export async function sendReaction(
this: TelegramClient,
chatId: InputPeerLike,
message: number,
emoji?: InputReaction | null,
big = false,
params: {
/** Chat ID with the message to react to */
chatId: InputPeerLike
/** Message ID to react to */
message: number
/** Reaction emoji (or `null` to remove reaction) */
emoji?: InputReaction | null
/** Whether to use a big reaction */
big?: boolean
},
): Promise<Message> {
const { chatId, message, emoji, big } = params
const reaction = normalizeInputReaction(emoji)
const res = await this.call({

View file

@ -8,21 +8,27 @@ import { assertIsUpdatesGroup } from '../../utils/updates-utils'
/**
* Send or retract a vote in a poll.
*
* @param chatId Chat ID where this poll was found
* @param message Message ID where this poll was found
* @param options
* Selected options, or `null` to retract.
* You can pass indexes of the answers or the `Buffer`s
* representing them. In case of indexes, the poll will first
* be requested from the server.
* @internal
*/
export async function sendVote(
this: TelegramClient,
chatId: InputPeerLike,
message: number,
options: null | MaybeArray<number | Buffer>,
params: {
/** Chat ID where this poll was found */
chatId: InputPeerLike
/** Message ID where this poll was found */
message: number
/**
* Selected options, or `null` to retract.
* You can pass indexes of the answers or the `Buffer`s
* representing them. In case of indexes, the poll will first
* be requested from the server.
*/
options: null | MaybeArray<number | Buffer>
},
): Promise<Poll> {
const { chatId, message } = params
let { options } = params
if (options === null) options = []
if (!Array.isArray(options)) options = [options]

View file

@ -6,19 +6,21 @@ import { InputPeerLike, MessageEntity } from '../../types'
*
* Returns `null` if it could not translate the message.
*
* > **Note**: For now doesn't seem to work, returns null for all messages.
*
* @param chatId Chat or user ID
* @param messageId Identifier of the message to translate
* @param toLanguage Target language (two-letter ISO 639-1 language code)
* @internal
*/
export async function translateMessage(
this: TelegramClient,
chatId: InputPeerLike,
messageId: number,
toLanguage: string,
params: {
/** Chat or user ID */
chatId: InputPeerLike
/** Identifier of the message to translate */
messageId: number
/** Target language (two-letter ISO 639-1 language code) */
toLanguage: string
},
): Promise<[string, MessageEntity[]] | null> {
const { chatId, messageId, toLanguage } = params
const res = await this.call({
_: 'messages.translateText',
peer: await this.resolvePeer(chatId),

View file

@ -6,17 +6,21 @@ import { TelegramClient } from '../../client'
/**
* Change your 2FA password
*
* @param currentPassword Current password as plaintext
* @param newPassword New password as plaintext
* @param hint Hint for the new password
* @internal
*/
export async function changeCloudPassword(
this: TelegramClient,
currentPassword: string,
newPassword: string,
hint?: string,
params: {
/** Current password as plaintext */
currentPassword: string
/** New password as plaintext */
newPassword: string
/** Hint for the new password */
hint?: string
},
): Promise<void> {
const { currentPassword, newPassword, hint } = params
const pwd = await this.call({ _: 'account.getPassword' })
if (!pwd.hasPassword) {

View file

@ -11,17 +11,21 @@ import { TelegramClient } from '../../client'
* {@link resendPasswordEmail} or {@link cancelPasswordEmail},
* and the call this method again
*
* @param password 2FA password as plaintext
* @param hint Hint for the new password
* @param email Recovery email
* @internal
*/
export async function enableCloudPassword(
this: TelegramClient,
password: string,
hint?: string,
email?: string,
params: {
/** 2FA password as plaintext */
password: string
/** Hint for the new password */
hint?: string
/** Recovery email */
email?: string
},
): Promise<void> {
const { password, hint, email } = params
const pwd = await this.call({ _: 'account.getPassword' })
if (pwd.hasPassword) {

View file

@ -13,7 +13,7 @@ import {
* Only for bots, and the sticker set must
* have been created by this bot.
*
* @param id 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 params
* @returns Modfiied sticker set
@ -21,7 +21,7 @@ import {
*/
export async function addStickerToSet(
this: TelegramClient,
id: InputStickerSet,
setId: InputStickerSet,
sticker: InputStickerSetItem,
params?: {
/**
@ -35,7 +35,7 @@ export async function addStickerToSet(
): Promise<StickerSet> {
const res = await this.call({
_: 'stickers.addStickerToSet',
stickerset: normalizeInputStickerSet(id),
stickerset: normalizeInputStickerSet(setId),
sticker: {
_: 'inputStickerSetItem',
document: await this._normalizeFileToDocument(sticker.file, params ?? {}),

View file

@ -4,13 +4,13 @@ import { InputStickerSet, normalizeInputStickerSet, StickerSet } from '../../typ
/**
* Get a sticker pack and stickers inside of it.
*
* @param id Sticker pack short name, dice emoji, `"emoji"` for animated emojis or input ID
* @param setId Sticker pack short name, dice emoji, `"emoji"` for animated emojis or input ID
* @internal
*/
export async function getStickerSet(this: TelegramClient, id: InputStickerSet): Promise<StickerSet> {
export async function getStickerSet(this: TelegramClient, setId: InputStickerSet): Promise<StickerSet> {
const res = await this.call({
_: 'messages.getStickerSet',
stickerset: normalizeInputStickerSet(id),
stickerset: normalizeInputStickerSet(setId),
hash: 0,
})

View file

@ -5,7 +5,7 @@ import { normalizeToInputChannel } from '../../utils'
/**
* Set group sticker set for a supergroup
*
* @param id Sticker set short name or a TL object with input sticker set
* @param setId Sticker set short name or a TL object with input sticker set
* @param thumb Sticker set thumbnail
* @param params
* @returns Modified sticker set
@ -14,11 +14,11 @@ import { normalizeToInputChannel } from '../../utils'
export async function setChatStickerSet(
this: TelegramClient,
chatId: InputPeerLike,
id: InputStickerSet,
setId: InputStickerSet,
): Promise<void> {
await this.call({
_: 'channels.setStickers',
channel: normalizeToInputChannel(await this.resolvePeer(chatId), chatId),
stickerset: normalizeInputStickerSet(id),
stickerset: normalizeInputStickerSet(setId),
})
}

View file

@ -1,4 +1,4 @@
/* eslint-disable max-depth */
/* eslint-disable max-depth,max-params */
import { assertNever, MtArgumentError, tl } from '@mtcute/core'
import {
AsyncLock,

View file

@ -8,7 +8,7 @@ import { normalizeToInputPeer } from '../../utils/peer-utils'
// @available=both
/**
* Get the `InputPeer` of a known peer id.
* Useful when an `InputPeer` is needed.
* Useful when an `InputPeer` is needed in Raw API.
*
* @param peerId The peer identifier that you want to extract the `InputPeer` from.
* @param force Whether to force re-fetch the peer from the server

View file

@ -9,19 +9,22 @@ import { InputFileLike, Photo } from '../../types'
*
* You can also pass a file ID or an InputPhoto to re-use existing photo.
*
* @param type Media type (photo or video)
* @param media Input media file
* @param previewSec
* When `type = video`, timestamp in seconds which will be shown
* as a static preview.
* @internal
*/
export async function setProfilePhoto(
this: TelegramClient,
type: 'photo' | 'video',
media: InputFileLike | tl.TypeInputPhoto,
previewSec?: number,
params: {
/** Media type (photo or video) */
type: 'photo' | 'video'
/** Input media file */
media: InputFileLike | tl.TypeInputPhoto
/** When `type = video`, timestamp in seconds which will be shown as a static preview. */
previewSec?: number
},
): Promise<Photo> {
const { type, previewSec } = params
let { media } = params
// try parsing media as file id or input photo
if (tdFileId.isFileIdLike(media) || (typeof media === 'object' && tl.isAnyInputPhoto(media))) {
if (typeof media === 'string' && media.match(/^https?:\/\//)) {

View file

@ -1,2 +1 @@
export * from './sent-code'
export * from './terms-of-service'

View file

@ -1,43 +0,0 @@
import { tl } from '@mtcute/core'
import { makeInspectable } from '../../utils'
import { MessageEntity } from '../messages'
/**
* Telegram's Terms of Service returned by {@link TelegramClient.signIn}
*/
export class TermsOfService {
/**
* Underlying raw TL object
*/
readonly tos: tl.help.TypeTermsOfService
constructor(obj: tl.help.TypeTermsOfService) {
this.tos = obj
}
/**
* Terms of Service identifier
*/
get id(): string {
return this.tos.id.data
}
/**
* Terms of Service text
*/
get text(): string {
return this.tos.text
}
private _entities?: MessageEntity[]
/**
* Terms of Service entities text
*/
get entities(): ReadonlyArray<MessageEntity> {
return (this._entities ??= this.tos.entities.map((it) => new MessageEntity(it, this.tos.text)))
}
}
makeInspectable(TermsOfService)

View file

@ -182,17 +182,17 @@ export class CallbackQuery {
return this.client.answerCallbackQuery(this.raw.queryId, params)
}
/**
* Edit the message that originated this callback query
*/
async editMessage(params: Parameters<TelegramClient['editInlineMessage']>[1]): Promise<void> {
// we can use editInlineMessage as a parameter since they share most of the parameters,
// except the ones that won't apply to already sent message anyways.
if (this.raw._ === 'updateInlineBotCallbackQuery') {
return this.client.editInlineMessage(this.raw.msgId, params)
}
await this.client.editMessage(getMarkedPeerId(this.raw.peer), this.raw.msgId, params)
}
// /**
// * Edit the message that originated this callback query
// */
// async editMessage(params: Parameters<TelegramClient['editInlineMessage']>[1]): Promise<void> {
// // we can use editInlineMessage as a parameter since they share most of the parameters,
// // except the ones that won't apply to already sent message anyways.
// if (this.raw._ === 'updateInlineBotCallbackQuery') {
// return this.client.editInlineMessage(this.raw.msgId, params)
// }
// await this.client.editMessage(getMarkedPeerId(this.raw.peer), this.raw.msgId, params)
// }
}
makeInspectable(CallbackQuery)

View file

@ -218,7 +218,7 @@ export class Conversation {
message = this._lastMessage ?? 0
}
return this.client.readHistory(this._inputPeer, message, clearMentions)
return this.client.readHistory(this._inputPeer, { maxId: message, clearMentions })
}
/**

View file

@ -786,17 +786,14 @@ export class Message {
* @param revoke Whether to "revoke" (i.e. delete for both sides). Only used for chats and private chats.
*/
delete(revoke = false): Promise<void> {
return this.client.deleteMessages(this.chat.inputPeer, this.id, revoke)
return this.client.deleteMessages(this.chat.inputPeer, this.id, { revoke })
}
/**
* Pin this message.
*
* @param notify Whether to send a notification (only for legacy groups and supergroups)
* @param bothSides Whether to pin for both sides (only for private chats)
*/
pin(notify = false, bothSides = false): Promise<void> {
return this.client.pinMessage(this.chat.inputPeer, this.id, notify, bothSides)
pin(params?: Parameters<TelegramClient['pinMessage']>[2]): Promise<void> {
return this.client.pinMessage(this.chat.inputPeer, this.id, params)
}
/**
@ -806,34 +803,34 @@ export class Message {
return this.client.pinMessage(this.chat.inputPeer, this.id)
}
/**
* Edit this message's text and/or reply markup
*
* @link TelegramClient.editMessage
*/
edit(params: Parameters<TelegramClient['editMessage']>[2]): Promise<Message> {
return this.client.editMessage(this.chat.inputPeer, this.id, params)
}
// /**
// * Edit this message's text and/or reply markup
// *
// * @link TelegramClient.editMessage
// */
// edit(params: Parameters<TelegramClient['editMessage']>[2]): Promise<Message> {
// return this.client.editMessage(this.chat.inputPeer, this.id, params)
// }
/**
* Edit message text and optionally reply markup.
*
* Convenience method that just wraps {@link edit},
* passing positional `text` as object field.
*
* @param text New message text
* @param params? Additional parameters
* @link TelegramClient.editMessage
*/
editText(
text: string | FormattedString<string>,
params?: Omit<Parameters<TelegramClient['editMessage']>[2], 'text'>,
): Promise<Message> {
return this.edit({
text,
...(params || {}),
})
}
// /**
// * Edit message text and optionally reply markup.
// *
// * Convenience method that just wraps {@link edit},
// * passing positional `text` as object field.
// *
// * @param text New message text
// * @param params? Additional parameters
// * @link TelegramClient.editMessage
// */
// editText(
// text: string | FormattedString<string>,
// params?: Omit<Parameters<TelegramClient['editMessage']>[2], 'text'>,
// ): Promise<Message> {
// return this.edit({
// text,
// ...(params || {}),
// })
// }
/**
* Forward this message to some chat
@ -842,13 +839,20 @@ export class Message {
* @param params
* @returns Forwarded message
*/
forwardTo(peer: InputPeerLike, params?: Parameters<TelegramClient['forwardMessages']>[3]): Promise<Message> {
return this.client.forwardMessages(peer, this.chat.inputPeer, this.id, params)
forwardTo(
peer: InputPeerLike,
params?: Omit<Parameters<TelegramClient['forwardMessages']>[0], 'messages' | 'toChatId' | 'fromChatId'>,
): Promise<Message> {
return this.client.forwardMessages({
toChatId: peer,
fromChatId: this.chat.inputPeer,
messages: this.id,
...params,
})
}
/**
* Send this message as a copy (i.e. send the same message,
* but do not forward it).
* Send this message as a copy (i.e. send the same message, but do not forward it).
*
* Note that if the message contains a webpage,
* it will be copied simply as a text message,
@ -858,7 +862,10 @@ export class Message {
* @param toChatId Target chat ID
* @param params Copy parameters
*/
sendCopy(toChatId: InputPeerLike, params?: Parameters<TelegramClient['sendCopy']>[3]): Promise<Message> {
sendCopy(
toChatId: InputPeerLike,
params?: Omit<Parameters<TelegramClient['sendCopy']>[0], 'fromChatId' | 'message' | 'toChatId'>,
): Promise<Message> {
if (!params) params = {}
if (this.raw._ === 'messageService') {
@ -912,7 +919,7 @@ export class Message {
* @param clearMentions Whether to also clear mentions
*/
async read(clearMentions = false): Promise<void> {
return this.client.readHistory(this.chat.inputPeer, this.raw.id, clearMentions)
return this.client.readHistory(this.chat.inputPeer, { maxId: this.raw.id, clearMentions })
}
/**
@ -922,7 +929,12 @@ export class Message {
* @param big Whether to use a big reaction
*/
async react(emoji: string | null, big?: boolean): Promise<Message> {
return this.client.sendReaction(this.chat.inputPeer, this.raw.id, emoji, big)
return this.client.sendReaction({
chatId: this.chat.inputPeer,
message: this.raw.id,
emoji,
big,
})
}
async getCustomEmojis(): Promise<Sticker[]> {

View file

@ -614,7 +614,7 @@ export class Chat {
* Only applicable to legacy groups, ignored for supergroups and channels
*/
async addMembers(users: MaybeArray<InputPeerLike>, forwardCount?: number): Promise<void> {
return this.client.addChatMembers(this.inputPeer, users, forwardCount)
return this.client.addChatMembers(this.inputPeer, users, { forwardCount })
}
/**
@ -638,7 +638,7 @@ export class Chat {
* @param clearMentions Whether to also clear all mentions in the chat
*/
async readHistory(message = 0, clearMentions = false): Promise<void> {
return this.client.readHistory(this.inputPeer, message, clearMentions)
return this.client.readHistory(this.inputPeer, { maxId: message, clearMentions })
}
/**

View file

@ -74,9 +74,9 @@ export class BotChatJoinRequestUpdate {
/**
* Approve or deny the request.
*/
hide(action: Parameters<TelegramClient['hideJoinRequest']>[2]): Promise<void> {
return this.client.hideJoinRequest(this.chat.inputPeer, this.user.inputPeer, action)
}
// hide(action: Parameters<TelegramClient['hideJoinRequest']>[1]['action']): Promise<void> {
// return this.client.hideJoinRequest(this.chat.inputPeer, { action, user: this.user.inputPeer })
// }
}
makeInspectable(BotChatJoinRequestUpdate)

View file

@ -55,19 +55,19 @@ export class ChatJoinRequestUpdate {
/**
* Approve or deny the last requested user
*/
hideLast(action: Parameters<TelegramClient['hideJoinRequest']>[2]): Promise<void> {
return this.client.hideJoinRequest(this.chatId, this.raw.recentRequesters[0], action)
}
// hideLast(action: Parameters<TelegramClient['hideJoinRequest']>[1]['action']): Promise<void> {
// return this.client.hideJoinRequest(this.chatId, { user: this.raw.recentRequesters[0], action })
// }
/**
* Approve or deny all recent requests
* (the ones available in {@link recentRequesters})
*/
async hideAllRecent(action: Parameters<TelegramClient['hideJoinRequest']>[2]): Promise<void> {
for (const id of this.raw.recentRequesters) {
await this.client.hideJoinRequest(this.chatId, id, action)
}
}
// async hideAllRecent(action: Parameters<TelegramClient['hideJoinRequest']>[1]['action']): Promise<void> {
// for (const id of this.raw.recentRequesters) {
// await this.client.hideJoinRequest(this.chatId, { user: id, action })
// }
// }
}
makeInspectable(ChatJoinRequestUpdate)

View file

@ -1,4 +1,4 @@
import { MtArgumentError, tl } from '@mtcute/core'
import { tl } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { makeInspectable } from '../../utils'
@ -78,13 +78,13 @@ export class ChosenInlineResult {
return encodeInlineMessageId(this.raw.msgId)
}
async editMessage(params: Parameters<TelegramClient['editInlineMessage']>[1]): Promise<void> {
if (!this.raw.msgId) {
throw new MtArgumentError('No message ID, make sure you have included reply markup!')
}
// async editMessage(params: Parameters<TelegramClient['editInlineMessage']>[1]): Promise<void> {
// if (!this.raw.msgId) {
// throw new MtArgumentError('No message ID, make sure you have included reply markup!')
// }
return this.client.editInlineMessage(this.raw.msgId, params)
}
// return this.client.editInlineMessage(this.raw.msgId, params)
// }
}
makeInspectable(ChosenInlineResult)

View file

@ -75,7 +75,7 @@ export class PreCheckoutQuery {
* Reject the query
*/
reject(error = ''): Promise<void> {
return this.client.answerPreCheckoutQuery(this.queryId, error)
return this.client.answerPreCheckoutQuery(this.queryId, { error })
}
}