refactor: move errors to core

This commit is contained in:
alina 🌸 2023-09-22 15:32:28 +03:00
parent 6e8351ac01
commit 976c25141c
Signed by: teidesu
SSH key fingerprint: SHA256:uNeCpw6aTSU4aIObXLvHfLkDa82HWH9EiOj9AXOIRpI
113 changed files with 523 additions and 399 deletions

View file

@ -1,5 +1,6 @@
import { MtTypeAssertionError } from '@mtcute/core'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { MtTypeAssertionError } from '../../types'
/** /**
* Accept the given TOS * Accept the given TOS

View file

@ -1,8 +1,7 @@
import { computeSrpParams } from '@mtcute/core/utils' import { assertTypeIs, computeSrpParams } from '@mtcute/core/utils'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { User } from '../../types' import { User } from '../../types'
import { assertTypeIs } from '../../utils/type-assertion'
/** /**
* Check your Two-Step verification password and log in * Check your Two-Step verification password and log in

View file

@ -1,6 +1,7 @@
import { assertTypeIs } from '@mtcute/core/utils'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { User } from '../../types' import { User } from '../../types'
import { assertTypeIs } from '../../utils/type-assertion'
/** /**
* Recover your password with a recovery code and log in. * Recover your password with a recovery code and log in.

View file

@ -1,7 +1,8 @@
import { assertTypeIs } from '@mtcute/core/utils'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { SentCode } from '../../types' import { SentCode } from '../../types'
import { normalizePhoneNumber } from '../../utils/misc-utils' import { normalizePhoneNumber } from '../../utils/misc-utils'
import { assertTypeIs } from '../../utils/type-assertion'
/** /**
* Re-send the confirmation code using a different type. * Re-send the confirmation code using a different type.

View file

@ -1,7 +1,8 @@
import { assertTypeIs } from '@mtcute/core/utils'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { SentCode } from '../../types' import { SentCode } from '../../types'
import { normalizePhoneNumber } from '../../utils/misc-utils' import { normalizePhoneNumber } from '../../utils/misc-utils'
import { assertTypeIs } from '../../utils/type-assertion'
/** /**
* Send the confirmation code to the given phone number * Send the confirmation code to the given phone number

View file

@ -1,6 +1,7 @@
import { assertTypeIs } from '@mtcute/core/utils'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { User } from '../../types' import { User } from '../../types'
import { assertTypeIs } from '../../utils/type-assertion'
/** /**
* Authorize a bot using its token issued by [@BotFather](//t.me/BotFather) * Authorize a bot using its token issued by [@BotFather](//t.me/BotFather)

View file

@ -1,7 +1,8 @@
import { assertTypeIs } from '@mtcute/core/utils'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { TermsOfService, User } from '../../types' import { TermsOfService, User } from '../../types'
import { normalizePhoneNumber } from '../../utils/misc-utils' import { normalizePhoneNumber } from '../../utils/misc-utils'
import { assertTypeIs } from '../../utils/type-assertion'
/** /**
* Authorize a user in Telegram with a valid confirmation code. * Authorize a user in Telegram with a valid confirmation code.

View file

@ -1,7 +1,8 @@
import { assertTypeIs } from '@mtcute/core/utils'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { User } from '../../types' import { User } from '../../types'
import { normalizePhoneNumber } from '../../utils/misc-utils' import { normalizePhoneNumber } from '../../utils/misc-utils'
import { assertTypeIs } from '../../utils/type-assertion'
/** /**
* Register a new user in Telegram. * Register a new user in Telegram.

View file

@ -1,5 +1,7 @@
import { MtArgumentError } from '@mtcute/core'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { MaybeDynamic, MtArgumentError, User } from '../../types' import { MaybeDynamic, User } from '../../types'
/** /**
* Utility function to quickly authorize on test DC * Utility function to quickly authorize on test DC

View file

@ -1,11 +1,11 @@
/* eslint-disable no-console */ /* eslint-disable no-console */
import { MtArgumentError } from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { import {
MaybeAsync, MaybeAsync,
MaybeDynamic, MaybeDynamic,
MtArgumentError,
SentCode, SentCode,
TermsOfService, TermsOfService,
User, User,

View file

@ -1,10 +1,7 @@
import { MtTypeAssertionError } from '@mtcute/core'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { import { InputPeerLike, Message, MtInvalidPeerTypeError } from '../../types'
InputPeerLike,
Message,
MtInvalidPeerTypeError,
MtTypeAssertionError,
} from '../../types'
import { import {
isInputPeerChannel, isInputPeerChannel,
isInputPeerChat, isInputPeerChat,

View file

@ -1,3 +1,4 @@
import { assertTypeIs } from '@mtcute/core/utils'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
@ -13,7 +14,6 @@ import {
isInputPeerUser, isInputPeerUser,
normalizeToInputChannel, normalizeToInputChannel,
} from '../../utils/peer-utils' } from '../../utils/peer-utils'
import { assertTypeIs } from '../../utils/type-assertion'
/** /**
* Get information about a single chat member * Get information about a single chat member

View file

@ -1,20 +1,22 @@
import Long from 'long' import Long from 'long'
import { assertNever } from '@mtcute/core' import { assertNever } from '@mtcute/core'
import { assertTypeIs } from '@mtcute/core/utils'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { import {
ArrayWithTotal, ChatMember, ArrayWithTotal,
ChatMember,
InputPeerLike, InputPeerLike,
MtInvalidPeerTypeError, MtInvalidPeerTypeError,
PeersIndex } from '../../types' PeersIndex,
} from '../../types'
import { import {
isInputPeerChannel, isInputPeerChannel,
isInputPeerChat, isInputPeerChat,
normalizeToInputChannel, normalizeToInputChannel,
} from '../../utils/peer-utils' } from '../../utils/peer-utils'
import { assertTypeIs } from '../../utils/type-assertion'
/** /**
* Get a chunk of members of some chat. * Get a chunk of members of some chat.

View file

@ -1,5 +1,7 @@
import { MtArgumentError } from '@mtcute/core'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { ChatPreview, MtArgumentError, MtPeerNotFoundError } from '../../types' import { ChatPreview, MtPeerNotFoundError } from '../../types'
import { INVITE_LINK_REGEX } from '../../utils/peer-utils' import { INVITE_LINK_REGEX } from '../../utils/peer-utils'
/** /**

View file

@ -1,7 +1,8 @@
import { MtArgumentError } from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { Chat, InputPeerLike, MtArgumentError } from '../../types' import { Chat, InputPeerLike } from '../../types'
import { import {
INVITE_LINK_REGEX, INVITE_LINK_REGEX,
isInputPeerChannel, isInputPeerChannel,

View file

@ -1,7 +1,8 @@
import { MtArgumentError } from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { Chat, InputPeerLike, MtArgumentError } from '../../types' import { Chat, InputPeerLike } from '../../types'
import { import {
INVITE_LINK_REGEX, INVITE_LINK_REGEX,
isInputPeerChannel, isInputPeerChannel,

View file

@ -1,9 +1,9 @@
import { getMarkedPeerId } from '@mtcute/core' import { getMarkedPeerId } from '@mtcute/core'
import { assertTypeIs } from '@mtcute/core/utils'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { Chat } from '../../types' import { Chat } from '../../types'
import { assertTypeIs } from '../../utils/type-assertion'
import { assertIsUpdatesGroup } from '../../utils/updates-utils' import { assertIsUpdatesGroup } from '../../utils/updates-utils'
/** /**

View file

@ -1,3 +1,4 @@
import { MtArgumentError } from '@mtcute/core'
import { fileIdToInputPhoto, tdFileId } from '@mtcute/file-id' import { fileIdToInputPhoto, tdFileId } from '@mtcute/file-id'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
@ -6,7 +7,6 @@ import {
InputFileLike, InputFileLike,
InputPeerLike, InputPeerLike,
isUploadedFile, isUploadedFile,
MtArgumentError,
MtInvalidPeerTypeError, MtInvalidPeerTypeError,
} from '../../types' } from '../../types'
import { import {
@ -37,14 +37,18 @@ export async function setChatPhoto(
): Promise<void> { ): Promise<void> {
const chat = await this.resolvePeer(chatId) const chat = await this.resolvePeer(chatId)
if (!(isInputPeerChannel(chat) || isInputPeerChat(chat))) { throw new MtInvalidPeerTypeError(chatId, 'chat or channel') } if (!(isInputPeerChannel(chat) || isInputPeerChat(chat))) {
throw new MtInvalidPeerTypeError(chatId, 'chat or channel')
}
let photo: tl.TypeInputChatPhoto | undefined = undefined let photo: tl.TypeInputChatPhoto | undefined = undefined
let inputFile: tl.TypeInputFile let inputFile: tl.TypeInputFile
if (tdFileId.isFileIdLike(media)) { if (tdFileId.isFileIdLike(media)) {
if (typeof media === 'string' && media.match(/^https?:\/\//)) { throw new MtArgumentError("Chat photo can't be external") } if (typeof media === 'string' && media.match(/^https?:\/\//)) {
throw new MtArgumentError("Chat photo can't be external")
}
if (typeof media === 'string' && media.match(/^file:/)) { if (typeof media === 'string' && media.match(/^file:/)) {
const uploaded = await this.uploadFile({ const uploaded = await this.uploadFile({
file: media.substring(5), file: media.substring(5),

View file

@ -1,8 +1,9 @@
import Long from 'long' import Long from 'long'
import { assertTypeIs } from '@mtcute/core/utils'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { User } from '../../types' import { User } from '../../types'
import { assertTypeIs } from '../../utils/type-assertion'
/** /**
* Get list of contacts from your Telegram contacts list. * Get list of contacts from your Telegram contacts list.

View file

@ -1,7 +1,7 @@
import { MtArgumentError } from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { MtArgumentError } from '../../types'
/** /**
* Edit a folder with given modification * Edit a folder with given modification
@ -31,7 +31,9 @@ export async function editFolder(
(it.id === folder || it.title === folder), (it.id === folder || it.title === folder),
) )
if (!found) { throw new MtArgumentError(`Could not find a folder ${folder}`) } if (!found) {
throw new MtArgumentError(`Could not find a folder ${folder}`)
}
folder = found as tl.RawDialogFilter folder = found as tl.RawDialogFilter
} }

View file

@ -1,7 +1,7 @@
import { MtArgumentError } from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { MtArgumentError } from '../../types'
/** /**
* Find a folder by its parameter. * Find a folder by its parameter.
@ -21,7 +21,9 @@ export async function findFolder(
id?: number id?: number
}, },
): Promise<tl.RawDialogFilter | null> { ): Promise<tl.RawDialogFilter | null> {
if (!params.title && !params.emoji && !params.id) { throw new MtArgumentError('One of search parameters must be passed') } if (!params.title && !params.emoji && !params.id) {
throw new MtArgumentError('One of search parameters must be passed')
}
const folders = await this.getFolders() const folders = await this.getFolders()

View file

@ -1,9 +1,10 @@
import Long from 'long' import Long from 'long'
import { MtArgumentError } from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { Dialog, MtArgumentError } from '../../types' import { Dialog } from '../../types'
import { normalizeDate } from '../../utils/misc-utils' import { normalizeDate } from '../../utils/misc-utils'
/** /**
@ -233,10 +234,11 @@ export async function* getDialogs(
} }
} }
const filterFolder = filters ? // if pinned is `only`, this wouldn't be reached // if pinned is `only`, this wouldn't be reached
// if pinned is `exclude`, we want to exclude them // if pinned is `exclude`, we want to exclude them
// if pinned is `include`, we already yielded them, so we also want to exclude them // if pinned is `include`, we already yielded them, so we also want to exclude them
// if pinned is `keep`, we want to keep them // if pinned is `keep`, we want to keep them
const filterFolder = filters ?
Dialog.filterFolder(filters, pinned !== 'keep') : Dialog.filterFolder(filters, pinned !== 'keep') :
undefined undefined

View file

@ -1,8 +1,8 @@
import { getMarkedPeerId } from '@mtcute/core' import { getMarkedPeerId, MtTypeAssertionError } from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { Dialog, MtTypeAssertionError, PeersIndex } from '../../types' import { Dialog, PeersIndex } from '../../types'
/** @internal */ /** @internal */
export function _parseDialogs( export function _parseDialogs(

View file

@ -1,10 +1,7 @@
import { TelegramClient } from '../../client' import { MtUnsupportedError } from '@mtcute/core'
import {
FileDownloadParameters,
FileLocation,
MtUnsupportedError,
} from '../../types'
import { TelegramClient } from '../../client'
import { FileDownloadParameters, FileLocation } from '../../types'
let fs: typeof import('fs') | null = null let fs: typeof import('fs') | null = null
try { try {

View file

@ -1,4 +1,8 @@
import { ConnectionKind } from '@mtcute/core' import {
ConnectionKind,
MtArgumentError,
MtUnsupportedError,
} from '@mtcute/core'
import { ConditionVariable } from '@mtcute/core/utils' import { ConditionVariable } from '@mtcute/core/utils'
import { import {
fileIdToInputFileLocation, fileIdToInputFileLocation,
@ -8,12 +12,7 @@ import {
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { import { FileDownloadParameters, FileLocation } from '../../types'
FileDownloadParameters,
FileLocation,
MtArgumentError,
MtUnsupportedError,
} from '../../types'
import { determinePartSize } from '../../utils/file-utils' import { determinePartSize } from '../../utils/file-utils'
// small files (less than 128 kb) are downloaded using the "downloadSmall" pool // small files (less than 128 kb) are downloaded using the "downloadSmall" pool

View file

@ -1,8 +1,8 @@
import { assertTypeIs } from '@mtcute/core/utils'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { InputFileLike } from '../../types' import { InputFileLike } from '../../types'
import { assertTypeIs } from '../../utils/type-assertion'
/** /**
* @internal * @internal

View file

@ -1,8 +1,9 @@
import { MtArgumentError } from '@mtcute/core'
import { tdFileId } from '@mtcute/file-id' import { tdFileId } from '@mtcute/file-id'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { InputFileLike, isUploadedFile, MtArgumentError } from '../../types' import { InputFileLike, isUploadedFile } from '../../types'
/** /**
* Normalize a {@link InputFileLike} to `InputFile`, * Normalize a {@link InputFileLike} to `InputFile`,

View file

@ -1,5 +1,6 @@
import Long from 'long' import Long from 'long'
import { assertTypeIs } from '@mtcute/core/utils'
import { import {
fileIdToInputDocument, fileIdToInputDocument,
fileIdToInputPhoto, fileIdToInputPhoto,
@ -12,7 +13,6 @@ import { TelegramClient } from '../../client'
import { InputMediaLike, isUploadedFile, UploadFileLike } from '../../types' import { InputMediaLike, isUploadedFile, UploadFileLike } from '../../types'
import { extractFileName } from '../../utils/file-utils' import { extractFileName } from '../../utils/file-utils'
import { normalizeDate } from '../../utils/misc-utils' import { normalizeDate } from '../../utils/misc-utils'
import { assertTypeIs } from '../../utils/type-assertion'
import { encodeWaveform } from '../../utils/voice-utils' import { encodeWaveform } from '../../utils/voice-utils'
/** /**
@ -267,8 +267,8 @@ export async function _normalizeInputMedia(
) )
assertTypeIs( assertTypeIs(
'normalizeInputMedia (@ messages.uploadMedia)', 'normalizeInputMedia (@ messages.uploadMedia)',
res.document!, res.document!,
'document', 'document',
) )
return { return {
@ -377,7 +377,9 @@ export async function _normalizeInputMedia(
roundMessage: media.isRound, roundMessage: media.isRound,
}) })
if (media.isAnimated) { attributes.push({ _: 'documentAttributeAnimated' }) } if (media.isAnimated) {
attributes.push({ _: 'documentAttributeAnimated' })
}
} }
if (media.type === 'audio' || media.type === 'voice') { if (media.type === 'audio' || media.type === 'voice') {

View file

@ -2,11 +2,12 @@ import { fromBuffer as fileTypeFromBuffer } from 'file-type'
import type { ReadStream } from 'fs' import type { ReadStream } from 'fs'
import { Readable } from 'stream' import { Readable } from 'stream'
import { MtArgumentError } from '@mtcute/core'
import { AsyncLock, randomLong } from '@mtcute/core/utils' import { AsyncLock, randomLong } from '@mtcute/core/utils'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { MtArgumentError, UploadedFile, UploadFileLike } from '../../types' import { UploadedFile, UploadFileLike } from '../../types'
import { determinePartSize, isProbablyPlainText } from '../../utils/file-utils' import { determinePartSize, isProbablyPlainText } from '../../utils/file-utils'
import { import {
bufferToStream, bufferToStream,

View file

@ -1,17 +1,19 @@
import { assertNever } from '@mtcute/core' import {
assertNever,
MtArgumentError,
MtTypeAssertionError,
} from '@mtcute/core'
import { assertTypeIs } from '@mtcute/core/utils'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { import {
InputMediaLike, InputMediaLike,
InputPeerLike, InputPeerLike,
MessageMedia, MessageMedia,
MtArgumentError,
MtTypeAssertionError,
Photo, Photo,
RawDocument, RawDocument,
} from '../../types' } from '../../types'
import { parseDocument } from '../../types/media/document-utils' import { parseDocument } from '../../types/media/document-utils'
import { assertTypeIs } from '../../utils/type-assertion'
/** /**
* Upload a media to Telegram servers, without actually * Upload a media to Telegram servers, without actually

View file

@ -1,13 +1,8 @@
import { MtTypeAssertionError } from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { import { ChatInviteLink, InputPeerLike, PeersIndex } from '../../types'
ChatInviteLink,
InputPeerLike,
MtInvalidPeerTypeError,
MtTypeAssertionError,
PeersIndex,
} from '../../types'
import { normalizeToInputUser } from '../../utils/peer-utils' import { normalizeToInputUser } from '../../utils/peer-utils'
/** /**

View file

@ -1,10 +1,7 @@
import { MtTypeAssertionError } from '@mtcute/core'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { import { ChatInviteLink, InputPeerLike, PeersIndex } from '../../types'
ChatInviteLink,
InputPeerLike,
MtTypeAssertionError,
PeersIndex,
} from '../../types'
/** /**
* Get primary invite link of a chat * Get primary invite link of a chat

View file

@ -1,13 +1,10 @@
import Long from 'long' import Long from 'long'
import { MtTypeAssertionError } from '@mtcute/core'
import { assertTypeIs } from '@mtcute/core/utils'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { import { InputPeerLike, PeersIndex, Poll } from '../../types'
InputPeerLike,
MtTypeAssertionError,
PeersIndex,
Poll,
} from '../../types'
import { assertTypeIs } from '../../utils/type-assertion'
import { assertIsUpdatesGroup } from '../../utils/updates-utils' import { assertIsUpdatesGroup } from '../../utils/updates-utils'
/** /**

View file

@ -1,7 +1,8 @@
import { MtTypeAssertionError } from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { Message, MtTypeAssertionError, PeersIndex } from '../../types' import { Message, PeersIndex } from '../../types'
import { assertIsUpdatesGroup } from '../../utils/updates-utils' import { assertIsUpdatesGroup } from '../../utils/updates-utils'
/** @internal */ /** @internal */

View file

@ -1,4 +1,4 @@
import { MaybeArray } from '@mtcute/core' import { MaybeArray, MtArgumentError } from '@mtcute/core'
import { randomLong } from '@mtcute/core/utils' import { randomLong } from '@mtcute/core/utils'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
@ -8,7 +8,6 @@ import {
InputMediaLike, InputMediaLike,
InputPeerLike, InputPeerLike,
Message, Message,
MtArgumentError,
PeersIndex, PeersIndex,
} from '../../types' } from '../../types'
import { normalizeDate } from '../../utils/misc-utils' import { normalizeDate } from '../../utils/misc-utils'

View file

@ -1,12 +1,9 @@
import Long from 'long' import Long from 'long'
import { MtTypeAssertionError } from '@mtcute/core'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { import { InputPeerLike, Message, PeersIndex } from '../../types'
InputPeerLike,
Message,
MtTypeAssertionError,
PeersIndex,
} from '../../types'
import { normalizeDate } from '../../utils/misc-utils' import { normalizeDate } from '../../utils/misc-utils'
/** /**

View file

@ -1,5 +1,7 @@
import { MtArgumentError } from '@mtcute/core'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { InputPeerLike, Message, MtArgumentError } from '../../types' import { InputPeerLike, Message } from '../../types'
import { isInputPeerChannel } from '../../utils/peer-utils' import { isInputPeerChannel } from '../../utils/peer-utils'
/** /**

View file

@ -1,8 +1,8 @@
import { getMarkedPeerId, MaybeArray } from '@mtcute/core' import { getMarkedPeerId, MaybeArray } from '@mtcute/core'
import { assertTypeIs } from '@mtcute/core/utils'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { InputPeerLike, MessageReactions, PeersIndex } from '../../types' import { InputPeerLike, MessageReactions, PeersIndex } from '../../types'
import { assertTypeIs } from '../../utils/type-assertion'
import { assertIsUpdatesGroup } from '../../utils/updates-utils' import { assertIsUpdatesGroup } from '../../utils/updates-utils'
/** /**

View file

@ -1,8 +1,8 @@
import { MaybeArray } from '@mtcute/core' import { MaybeArray, MtTypeAssertionError } from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { Message, MtTypeAssertionError, PeersIndex } from '../../types' import { Message, PeersIndex } from '../../types'
/** /**
* Get a single message from PM or legacy group by its ID. * Get a single message from PM or legacy group by its ID.

View file

@ -1,13 +1,8 @@
import { MaybeArray } from '@mtcute/core' import { MaybeArray, MtTypeAssertionError } from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { import { InputPeerLike, Message, PeersIndex } from '../../types'
InputPeerLike,
Message,
MtTypeAssertionError,
PeersIndex,
} from '../../types'
import { import {
isInputPeerChannel, isInputPeerChannel,
normalizeToInputChannel, normalizeToInputChannel,
@ -105,7 +100,9 @@ export async function getMessages(
msg.peerId._ === 'peerUser' && msg.peerId._ === 'peerUser' &&
msg.peerId.userId === this._userId msg.peerId.userId === this._userId
) )
) { return null } ) {
return null
}
break break
case 'inputPeerUser': case 'inputPeerUser':
case 'inputPeerUserFromMessage': case 'inputPeerUserFromMessage':
@ -114,7 +111,9 @@ export async function getMessages(
msg.peerId._ === 'peerUser' && msg.peerId._ === 'peerUser' &&
msg.peerId.userId === peer.userId msg.peerId.userId === peer.userId
) )
) { return null } ) {
return null
}
break break
case 'inputPeerChat': case 'inputPeerChat':
if ( if (
@ -122,7 +121,9 @@ export async function getMessages(
msg.peerId._ === 'peerChat' && msg.peerId._ === 'peerChat' &&
msg.peerId.chatId === peer.chatId msg.peerId.chatId === peer.chatId
) )
) { return null } ) {
return null
}
break break
} }
} }

View file

@ -1,12 +1,7 @@
import { MaybeArray } from '@mtcute/core' import { MaybeArray, MtTypeAssertionError } from '@mtcute/core'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { import { InputPeerLike, Message, PeersIndex } from '../../types'
InputPeerLike,
Message,
MtTypeAssertionError,
PeersIndex,
} from '../../types'
/** /**
* Get a single scheduled message in chat by its ID * Get a single scheduled message in chat by its ID

View file

@ -1,8 +1,9 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import { MtArgumentError } from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { FormattedString, MtClientError } from '../../types' import { FormattedString } from '../../types'
import { normalizeToInputUser } from '../../utils/peer-utils' import { normalizeToInputUser } from '../../utils/peer-utils'
const empty: [string, undefined] = ['', undefined] const empty: [string, undefined] = ['', undefined]
@ -33,7 +34,7 @@ export async function _parseEntities(
const modeImpl = this._parseModes.get(mode) const modeImpl = this._parseModes.get(mode)
if (!modeImpl) { if (!modeImpl) {
throw new MtClientError(`Parse mode ${mode} is not registered.`) throw new MtArgumentError(`Parse mode ${mode} is not registered.`)
} }
[text, entities] = modeImpl.parse(text) [text, entities] = modeImpl.parse(text)

View file

@ -1,7 +1,8 @@
import { MtTypeAssertionError } from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { Message, MtTypeAssertionError, PeersIndex, SearchFilters } from '../../types' import { Message, PeersIndex, SearchFilters } from '../../types'
/** /**
* Search for messages globally from all of your chats * Search for messages globally from all of your chats

View file

@ -1,14 +1,10 @@
import Long from 'long' import Long from 'long'
import { MtTypeAssertionError } from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { import { InputPeerLike, Message, PeersIndex, SearchFilters } from '../../types'
InputPeerLike,
Message,
MtTypeAssertionError,
PeersIndex,
SearchFilters } from '../../types'
import { normalizeDate } from '../../utils/misc-utils' import { normalizeDate } from '../../utils/misc-utils'
/** /**

View file

@ -1,4 +1,4 @@
import { getMarkedPeerId } from '@mtcute/core' import { getMarkedPeerId, MtArgumentError } from '@mtcute/core'
import { randomLong } from '@mtcute/core/utils' import { randomLong } from '@mtcute/core/utils'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
@ -8,7 +8,6 @@ import {
InputMediaLike, InputMediaLike,
InputPeerLike, InputPeerLike,
Message, Message,
MtArgumentError,
MtMessageNotFoundError, MtMessageNotFoundError,
PeersIndex, PeersIndex,
ReplyMarkup, ReplyMarkup,

View file

@ -1,4 +1,4 @@
import { getMarkedPeerId } from '@mtcute/core' import { getMarkedPeerId, MtArgumentError } from '@mtcute/core'
import { randomLong } from '@mtcute/core/utils' import { randomLong } from '@mtcute/core/utils'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
@ -9,7 +9,6 @@ import {
InputMediaLike, InputMediaLike,
InputPeerLike, InputPeerLike,
Message, Message,
MtArgumentError,
MtMessageNotFoundError, MtMessageNotFoundError,
ReplyMarkup, ReplyMarkup,
} from '../../types' } from '../../types'

View file

@ -1,14 +1,10 @@
import Long from 'long' import Long from 'long'
import { MtTypeAssertionError } from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { import { InputPeerLike, Message, PeersIndex } from '../../types'
InputPeerLike,
Message,
MtTypeAssertionError,
PeersIndex,
} from '../../types'
import { assertIsUpdatesGroup } from '../../utils/updates-utils' import { assertIsUpdatesGroup } from '../../utils/updates-utils'
/** /**

View file

@ -1,4 +1,8 @@
import { getMarkedPeerId } from '@mtcute/core' import {
getMarkedPeerId,
MtArgumentError,
MtTypeAssertionError,
} from '@mtcute/core'
import { randomLong } from '@mtcute/core/utils' import { randomLong } from '@mtcute/core/utils'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
@ -8,9 +12,7 @@ import {
FormattedString, FormattedString,
InputPeerLike, InputPeerLike,
Message, Message,
MtArgumentError,
MtMessageNotFoundError, MtMessageNotFoundError,
MtTypeAssertionError,
PeersIndex, PeersIndex,
ReplyMarkup, ReplyMarkup,
} from '../../types' } from '../../types'

View file

@ -1,16 +1,19 @@
import { getMarkedPeerId, MaybeArray } from '@mtcute/core' import {
getMarkedPeerId,
MaybeArray,
MtArgumentError,
MtTypeAssertionError,
} from '@mtcute/core'
import { assertTypeIs } from '@mtcute/core/utils'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { import {
InputPeerLike, InputPeerLike,
MtArgumentError,
MtMessageNotFoundError, MtMessageNotFoundError,
MtTypeAssertionError,
PeersIndex, PeersIndex,
Poll, Poll,
} from '../../types' } from '../../types'
import { assertTypeIs } from '../../utils/type-assertion'
import { assertIsUpdatesGroup } from '../../utils/updates-utils' import { assertIsUpdatesGroup } from '../../utils/updates-utils'
/** /**

View file

@ -1,5 +1,7 @@
import { MtArgumentError } from '@mtcute/core'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { IMessageEntityParser, MtClientError } from '../../types' import { IMessageEntityParser } from '../../types'
/** /**
* Register a given {@link IMessageEntityParser} as a parse mode * Register a given {@link IMessageEntityParser} as a parse mode
@ -17,7 +19,7 @@ export function registerParseMode(
const name = parseMode.name const name = parseMode.name
if (this._parseModes.has(name)) { if (this._parseModes.has(name)) {
throw new MtClientError( throw new MtArgumentError(
`Parse mode ${name} is already registered. Unregister it first!`, `Parse mode ${name} is already registered. Unregister it first!`,
) )
} }
@ -60,7 +62,7 @@ export function getParseMode(
): IMessageEntityParser { ): IMessageEntityParser {
if (!name) { if (!name) {
if (!this._defaultParseMode) { if (!this._defaultParseMode) {
throw new MtClientError('There is no default parse mode') throw new MtArgumentError('There is no default parse mode')
} }
name = this._defaultParseMode name = this._defaultParseMode
@ -69,7 +71,7 @@ export function getParseMode(
const mode = this._parseModes.get(name) const mode = this._parseModes.get(name)
if (!mode) { if (!mode) {
throw new MtClientError(`Parse mode ${name} is not registered.`) throw new MtArgumentError(`Parse mode ${name} is not registered.`)
} }
return mode return mode
@ -84,7 +86,7 @@ export function getParseMode(
*/ */
export function setDefaultParseMode(this: TelegramClient, name: string): void { export function setDefaultParseMode(this: TelegramClient, name: string): void {
if (!this._parseModes.has(name)) { if (!this._parseModes.has(name)) {
throw new MtClientError(`Parse mode ${name} is not registered.`) throw new MtArgumentError(`Parse mode ${name} is not registered.`)
} }
this._defaultParseMode = name this._defaultParseMode = name

View file

@ -1,8 +1,11 @@
import { computeNewPasswordHash, computeSrpParams } from '@mtcute/core/utils' import { MtArgumentError } from '@mtcute/core'
import {
assertTypeIs,
computeNewPasswordHash,
computeSrpParams,
} from '@mtcute/core/utils'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { MtArgumentError } from '../../types'
import { assertTypeIs } from '../../utils/type-assertion'
/** /**
* Change your 2FA password * Change your 2FA password

View file

@ -1,8 +1,7 @@
import { computeNewPasswordHash } from '@mtcute/core/utils' import { MtArgumentError } from '@mtcute/core'
import { assertTypeIs, computeNewPasswordHash } from '@mtcute/core/utils'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { MtArgumentError } from '../../types'
import { assertTypeIs } from '../../utils/type-assertion'
/** /**
* Enable 2FA password on your account * Enable 2FA password on your account

View file

@ -1,7 +1,7 @@
import { MtArgumentError } from '@mtcute/core'
import { computeSrpParams } from '@mtcute/core/utils' import { computeSrpParams } from '@mtcute/core/utils'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { MtArgumentError } from '../../types'
/** /**
* Remove 2FA password from your account * Remove 2FA password from your account

View file

@ -1,3 +1,4 @@
import { MtArgumentError } from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
@ -5,7 +6,6 @@ import {
InputFileLike, InputFileLike,
InputPeerLike, InputPeerLike,
InputStickerSetItem, InputStickerSetItem,
MtArgumentError,
StickerSet, StickerSet,
StickerSourceType, StickerSourceType,
StickerType, StickerType,

View file

@ -1,9 +1,10 @@
import { MtTypeAssertionError } from '@mtcute/core'
import { assertTypeIs } from '@mtcute/core/utils'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { MtTypeAssertionError, Sticker } from '../../types' import { Sticker } from '../../types'
import { parseDocument } from '../../types/media/document-utils' import { parseDocument } from '../../types/media/document-utils'
import { assertTypeIs } from '../../utils/type-assertion'
/** /**
* Get custom emoji stickers by their IDs * Get custom emoji stickers by their IDs

View file

@ -1,8 +1,9 @@
import Long from 'long' import Long from 'long'
import { assertTypeIs } from '@mtcute/core/utils'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { StickerSet } from '../../types' import { StickerSet } from '../../types'
import { assertTypeIs } from '../../utils/type-assertion'
/** /**
* Get a list of all installed sticker packs * Get a list of all installed sticker packs

View file

@ -1,5 +1,5 @@
/* eslint-disable max-depth */ /* eslint-disable max-depth */
import { assertNever } from '@mtcute/core' import { assertNever, MtArgumentError } from '@mtcute/core'
import { import {
AsyncLock, AsyncLock,
ConditionVariable, ConditionVariable,
@ -14,7 +14,7 @@ import {
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../client' import { TelegramClient } from '../client'
import { MtArgumentError, PeersIndex } from '../types' import { PeersIndex } from '../types'
import { _parseUpdate } from '../types/updates/parse-update' import { _parseUpdate } from '../types/updates/parse-update'
import { extractChannelIdFromUpdate } from '../utils/misc-utils' import { extractChannelIdFromUpdate } from '../utils/misc-utils'
import { normalizeToInputChannel } from '../utils/peer-utils' import { normalizeToInputChannel } from '../utils/peer-utils'

View file

@ -1,6 +1,7 @@
import { assertTypeIs } from '@mtcute/core/utils'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { User } from '../../types' import { User } from '../../types'
import { assertTypeIs } from '../../utils/type-assertion'
/** /**
* Get currently authorized user's full information * Get currently authorized user's full information

View file

@ -3,18 +3,15 @@ import Long from 'long'
import { import {
getBasicPeerType, getBasicPeerType,
getMarkedPeerId, getMarkedPeerId,
MtTypeAssertionError,
toggleChannelIdMark, toggleChannelIdMark,
} from '@mtcute/core' } from '@mtcute/core'
import { assertTypeIs } from '@mtcute/core/utils'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { import { InputPeerLike, MtPeerNotFoundError } from '../../types'
InputPeerLike,
MtPeerNotFoundError,
MtTypeAssertionError,
} from '../../types'
import { normalizeToInputPeer } from '../../utils/peer-utils' import { normalizeToInputPeer } from '../../utils/peer-utils'
import { assertTypeIs } from '../../utils/type-assertion'
/** /**
* Get the `InputPeer` of a known peer id. * Get the `InputPeer` of a known peer id.

View file

@ -1,8 +1,9 @@
import { MtArgumentError } from '@mtcute/core'
import { fileIdToInputPhoto, tdFileId } from '@mtcute/file-id' import { fileIdToInputPhoto, tdFileId } from '@mtcute/file-id'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { InputFileLike, MtArgumentError, Photo } from '../../types' import { InputFileLike, Photo } from '../../types'
/** /**
* Set a new profile photo or video. * Set a new profile photo or video.

View file

@ -1,9 +1,14 @@
import { BasicPeerType, getBasicPeerType, getMarkedPeerId } from '@mtcute/core' import {
BasicPeerType,
getBasicPeerType,
getMarkedPeerId,
MtArgumentError,
} from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { encodeInlineMessageId } from '../../utils/inline-utils' import { encodeInlineMessageId } from '../../utils/inline-utils'
import { MtArgumentError, MtMessageNotFoundError } from '../errors' import { MtMessageNotFoundError } from '../errors'
import { Message } from '../messages' import { Message } from '../messages'
import { PeersIndex, User } from '../peers' import { PeersIndex, User } from '../peers'
import { makeInspectable } from '../utils' import { makeInspectable } from '../utils'

View file

@ -1,9 +1,9 @@
import { MtArgumentError } from '@mtcute/core'
import { fileIdToInputDocument, fileIdToInputPhoto } from '@mtcute/file-id' import { fileIdToInputDocument, fileIdToInputPhoto } from '@mtcute/file-id'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../../client' import { TelegramClient } from '../../../client'
import { extractFileName } from '../../../utils/file-utils' import { extractFileName } from '../../../utils/file-utils'
import { MtArgumentError } from '../../errors'
import { BotInlineMessage, InputInlineMessage } from './input-inline-message' import { BotInlineMessage, InputInlineMessage } from './input-inline-message'
export interface BaseInputInlineResult { export interface BaseInputInlineResult {
@ -903,8 +903,8 @@ export namespace BotInline {
} }
} else if ( } else if (
obj.type === 'video' && obj.type === 'video' &&
obj.isEmbed && obj.isEmbed &&
typeof obj.media === 'string' typeof obj.media === 'string'
) { ) {
sendMessage = { sendMessage = {
_: 'inputBotInlineMessageText', _: 'inputBotInlineMessageText',
@ -956,8 +956,9 @@ export namespace BotInline {
let mime: string let mime: string
if (obj.type === 'video') mime = 'video/mp4' if (obj.type === 'video') mime = 'video/mp4'
else if (obj.type === 'audio') { mime = obj.mime ?? 'audio/mpeg' } else if (obj.type === 'gif') mime = obj.mime ?? 'video/mp4' else if (obj.type === 'audio') {
else if (obj.type === 'voice') mime = 'audio/ogg' mime = obj.mime ?? 'audio/mpeg'
} else if (obj.type === 'gif') { mime = obj.mime ?? 'video/mp4' } else if (obj.type === 'voice') mime = 'audio/ogg'
else if (obj.type === 'file') { else if (obj.type === 'file') {
if (!obj.mime) { if (!obj.mime) {
throw new MtArgumentError( throw new MtArgumentError(
@ -991,7 +992,10 @@ export namespace BotInline {
h: obj.height, h: obj.height,
}) })
} }
} else if (obj.type === 'audio' || obj.type === 'voice') { } else if (
obj.type === 'audio' ||
obj.type === 'voice'
) {
attributes.push({ attributes.push({
_: 'documentAttributeAudio', _: 'documentAttributeAudio',
voice: obj.type === 'voice', voice: obj.type === 'voice',

View file

@ -1,5 +1,10 @@
/* eslint-disable dot-notation */ /* eslint-disable dot-notation */
import { getMarkedPeerId, MaybeAsync } from '@mtcute/core' import {
getMarkedPeerId,
MaybeAsync,
MtArgumentError,
MtTimeoutError,
} from '@mtcute/core'
import { import {
AsyncLock, AsyncLock,
ControllablePromise, ControllablePromise,
@ -9,7 +14,6 @@ import {
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../client' import { TelegramClient } from '../client'
import { MtArgumentError, MtTimeoutError } from './errors'
import { InputMediaLike } from './media' import { InputMediaLike } from './media'
import { Message } from './messages' import { Message } from './messages'
import { FormattedString } from './parser' import { FormattedString } from './parser'

View file

@ -1,25 +1,16 @@
/** import { MtcuteError } from '@mtcute/core'
* Base class for all `@mtcute/client` errors
*/
import { InputPeerLike } from './peers' import { InputPeerLike } from './peers'
export class MtClientError extends Error {}
/**
* Method invocation was invalid because some argument
* passed was invalid.
*/
export class MtArgumentError extends MtClientError {}
/** /**
* Could not find a peer by the provided information * Could not find a peer by the provided information
*/ */
export class MtPeerNotFoundError extends MtClientError {} export class MtPeerNotFoundError extends MtcuteError {}
/** /**
* Could not find a message by the provided information * Could not find a message by the provided information
*/ */
export class MtMessageNotFoundError extends MtClientError { export class MtMessageNotFoundError extends MtcuteError {
constructor( constructor(
readonly peerId: number, readonly peerId: number,
readonly messageId: number, readonly messageId: number,
@ -33,46 +24,6 @@ export class MtMessageNotFoundError extends MtClientError {
} }
} }
/**
* Either you requested or the server returned something
* that is not (yet) supported.
*
* Stay tuned for future updates!
*/
export class MtUnsupportedError extends MtClientError {}
/**
* Server returned something of an unexpected type.
*
* This is usually a problem on library side.
* Feel free to open an issue about this!
*/
export class MtTypeAssertionError extends MtClientError {
/**
* Context at which the error occurred.
* Usually a user-friendly string containing name
* of the high-level API method, name of the TL
* RPC method, and path of the entity,
* like this: `signIn (@ auth.signIn -> user)`
*/
context: string
/** Expected TL type */
expected: string
/** Actual TL type */
actual: string
constructor(context: string, expected: string, actual: string) {
super(
`Type assertion error at ${context}: expected ${expected}, but got ${actual}`,
)
this.context = context
this.expected = expected
this.actual = actual
}
}
/** /**
* Some method that requires a particular type of peer * Some method that requires a particular type of peer
* is called, but the resolved peer type is invalid. * is called, but the resolved peer type is invalid.
@ -80,7 +31,7 @@ export class MtTypeAssertionError extends MtClientError {
* For example, when trying to get common chats * For example, when trying to get common chats
* while providing another chat as `userId` * while providing another chat as `userId`
*/ */
export class MtInvalidPeerTypeError extends MtClientError { export class MtInvalidPeerTypeError extends MtcuteError {
constructor(peer: InputPeerLike, expected: string) { constructor(peer: InputPeerLike, expected: string) {
super( super(
`Provided identifier ${JSON.stringify(peer)} is not a ${expected}`, `Provided identifier ${JSON.stringify(peer)} is not a ${expected}`,
@ -92,14 +43,8 @@ export class MtInvalidPeerTypeError extends MtClientError {
* Trying to access to some property on an object that does not * Trying to access to some property on an object that does not
* contain that information. * contain that information.
*/ */
export class MtEmptyError extends MtClientError { export class MtEmptyError extends MtcuteError {
constructor() { constructor() {
super('Property is not available on an empty object') super('Property is not available on an empty object')
} }
} }
export class MtTimeoutError extends MtClientError {
constructor(readonly timeout?: number) {
super(`Request timed out${timeout ? ` after ${timeout}ms` : ''}`)
}
}

View file

@ -1,7 +1,7 @@
import { MtArgumentError } from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { MtArgumentError } from '../errors'
import { makeInspectable } from '../utils' import { makeInspectable } from '../utils'
import { FileLocation } from './file-location' import { FileLocation } from './file-location'

View file

@ -1,7 +1,7 @@
import { MtArgumentError } from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { MtArgumentError } from '../errors'
import { WebDocument } from '../files/web-document' import { WebDocument } from '../files/web-document'
import { _messageMediaFromTl, MessageMedia } from '../messages' import { _messageMediaFromTl, MessageMedia } from '../messages'
import { makeInspectable } from '../utils' import { makeInspectable } from '../utils'
@ -146,7 +146,9 @@ export class Invoice {
get extendedMediaState(): InvoiceExtendedMediaState { get extendedMediaState(): InvoiceExtendedMediaState {
if (!this.raw.extendedMedia) return 'none' if (!this.raw.extendedMedia) return 'none'
if (this.raw.extendedMedia._ === 'messageExtendedMediaPreview') { return 'preview' } if (this.raw.extendedMedia._ === 'messageExtendedMediaPreview') {
return 'preview'
}
return 'full' return 'full'
} }
@ -158,7 +160,9 @@ export class Invoice {
* Otherwise, throws an error. * Otherwise, throws an error.
*/ */
get extendedMediaPreview(): InvoiceExtendedMediaPreview { get extendedMediaPreview(): InvoiceExtendedMediaPreview {
if (this.raw.extendedMedia?._ !== 'messageExtendedMediaPreview') { throw new MtArgumentError('No extended media preview available') } if (this.raw.extendedMedia?._ !== 'messageExtendedMediaPreview') {
throw new MtArgumentError('No extended media preview available')
}
return (this._extendedMediaPreview ??= new InvoiceExtendedMediaPreview( return (this._extendedMediaPreview ??= new InvoiceExtendedMediaPreview(
this.client, this.client,

View file

@ -1,7 +1,7 @@
import { MtArgumentError } from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { MtArgumentError } from '../errors'
import { FileLocation } from '../files' import { FileLocation } from '../files'
import { makeInspectable } from '../utils' import { makeInspectable } from '../utils'
import { Thumbnail } from './thumbnail' import { Thumbnail } from './thumbnail'

View file

@ -1,8 +1,8 @@
import { MtArgumentError } from '@mtcute/core'
import { tdFileId } from '@mtcute/file-id' import { tdFileId } from '@mtcute/file-id'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { MtArgumentError } from '../errors'
import { StickerSet } from '../misc' import { StickerSet } from '../misc'
import { makeInspectable } from '../utils' import { makeInspectable } from '../utils'
import { RawDocument } from './document' import { RawDocument } from './document'

View file

@ -1,5 +1,7 @@
import Long from 'long' import Long from 'long'
import { MtArgumentError, MtTypeAssertionError } from '@mtcute/core'
import { assertTypeIs } from '@mtcute/core/utils'
import { tdFileId as td, toFileId, toUniqueFileId } from '@mtcute/file-id' import { tdFileId as td, toFileId, toUniqueFileId } from '@mtcute/file-id'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
@ -9,8 +11,6 @@ import {
strippedPhotoToJpg, strippedPhotoToJpg,
svgPathToFile, svgPathToFile,
} from '../../utils/file-utils' } from '../../utils/file-utils'
import { assertTypeIs } from '../../utils/type-assertion'
import { MtArgumentError, MtTypeAssertionError } from '../errors'
import { FileLocation } from '../files' import { FileLocation } from '../files'
import { makeInspectable } from '../utils' import { makeInspectable } from '../utils'
@ -182,8 +182,12 @@ export class Thumbnail extends FileLocation {
* Thumbnail type * Thumbnail type
*/ */
get type(): string { get type(): string {
if (this.raw._ === 'videoSizeEmojiMarkup') { return Thumbnail.THUMB_EMOJI_MARKUP } if (this.raw._ === 'videoSizeEmojiMarkup') {
if (this.raw._ === 'videoSizeStickerMarkup') { return Thumbnail.THUMB_STICKER_MARKUP } return Thumbnail.THUMB_EMOJI_MARKUP
}
if (this.raw._ === 'videoSizeStickerMarkup') {
return Thumbnail.THUMB_STICKER_MARKUP
}
return this.raw.type return this.raw.type
} }

View file

@ -1,7 +1,7 @@
import { assertTypeIs } from '@mtcute/core/utils'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { assertTypeIs } from '../../utils/type-assertion'
import { makeInspectable } from '../utils' import { makeInspectable } from '../utils'
import { Location } from './location' import { Location } from './location'

View file

@ -1,7 +1,7 @@
import { MtArgumentError } from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { MtArgumentError } from '../errors'
import { makeInspectable } from '../utils' import { makeInspectable } from '../utils'
import { RawDocument } from './document' import { RawDocument } from './document'
import { parseDocument } from './document-utils' import { parseDocument } from './document-utils'

View file

@ -1,7 +1,7 @@
import { MtTypeAssertionError } from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { MtTypeAssertionError } from '../errors'
import { import {
Audio, Audio,
Contact, Contact,

View file

@ -1,9 +1,14 @@
import { assertNever, getMarkedPeerId, toggleChannelIdMark } from '@mtcute/core' import {
assertNever,
getMarkedPeerId,
MtArgumentError,
MtTypeAssertionError,
toggleChannelIdMark,
} from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { BotKeyboard, ReplyMarkup } from '../bots' import { BotKeyboard, ReplyMarkup } from '../bots'
import { MtArgumentError, MtTypeAssertionError } from '../errors'
import { InputMediaLike, Sticker, WebPage } from '../media' import { InputMediaLike, Sticker, WebPage } from '../media'
import { FormattedString } from '../parser' import { FormattedString } from '../parser'
import { Chat, InputPeerLike, PeersIndex, User } from '../peers' import { Chat, InputPeerLike, PeersIndex, User } from '../peers'

View file

@ -1,8 +1,8 @@
import { getMarkedPeerId } from '@mtcute/core' import { getMarkedPeerId } from '@mtcute/core'
import { assertTypeIs } from '@mtcute/core/utils'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { assertTypeIs } from '../../utils/type-assertion'
import { PeersIndex, User } from '../peers' import { PeersIndex, User } from '../peers'
import { makeInspectable } from '../utils' import { makeInspectable } from '../utils'

View file

@ -1,8 +1,9 @@
import { MtTypeAssertionError } from '@mtcute/core'
import { LongMap } from '@mtcute/core/utils' import { LongMap } from '@mtcute/core/utils'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { MtEmptyError, MtTypeAssertionError } from '../errors' import { MtEmptyError } from '../errors'
import { InputFileLike } from '../files' import { InputFileLike } from '../files'
import { import {
MaskPosition, MaskPosition,

View file

@ -1,7 +1,7 @@
import { MtTypeAssertionError } from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { MtTypeAssertionError } from '../errors'
import { makeInspectable } from '../utils' import { makeInspectable } from '../utils'
import { PeersIndex } from './index' import { PeersIndex } from './index'
import { User } from './user' import { User } from './user'

View file

@ -1,7 +1,7 @@
import { assertTypeIs } from '@mtcute/core/utils'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { assertTypeIs } from '../../utils/type-assertion'
import { makeInspectable } from '../utils' import { makeInspectable } from '../utils'
import { ChatPermissions } from './chat-permissions' import { ChatPermissions } from './chat-permissions'
import { PeersIndex } from './index' import { PeersIndex } from './index'

View file

@ -1,12 +1,11 @@
import Long from 'long' import Long from 'long'
import { toggleChannelIdMark } from '@mtcute/core' import { MtArgumentError, toggleChannelIdMark } from '@mtcute/core'
import { tdFileId, toFileId, toUniqueFileId } from '@mtcute/file-id' import { tdFileId, toFileId, toUniqueFileId } from '@mtcute/file-id'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { strippedPhotoToJpg } from '../../utils/file-utils' import { strippedPhotoToJpg } from '../../utils/file-utils'
import { MtArgumentError } from '../errors'
import { FileLocation } from '../files' import { FileLocation } from '../files'
import { makeInspectable } from '../utils' import { makeInspectable } from '../utils'

View file

@ -1,8 +1,12 @@
import { getMarkedPeerId, MaybeArray } from '@mtcute/core' import {
getMarkedPeerId,
MaybeArray,
MtArgumentError,
MtTypeAssertionError,
} from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { MtArgumentError, MtTypeAssertionError } from '../errors'
import { InputMediaLike } from '../media' import { InputMediaLike } from '../media'
import { FormattedString } from '../parser' import { FormattedString } from '../parser'
import { makeInspectable } from '../utils' import { makeInspectable } from '../utils'

View file

@ -1,7 +1,6 @@
import { MtArgumentError } from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { MtArgumentError } from '../errors'
const ERROR_MSG = const ERROR_MSG =
'Given peer is not available in this index. This is most likely an internal library error.' 'Given peer is not available in this index. This is most likely an internal library error.'

View file

@ -1,8 +1,8 @@
import { MtArgumentError } from '@mtcute/core'
import { assertTypeIs } from '@mtcute/core/utils'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { assertTypeIs } from '../../utils/type-assertion'
import { MtArgumentError } from '../errors'
import { InputMediaLike } from '../media' import { InputMediaLike } from '../media'
import { FormattedString } from '../parser' import { FormattedString } from '../parser'
import { makeInspectable } from '../utils' import { makeInspectable } from '../utils'

View file

@ -1,8 +1,9 @@
import { MtArgumentError } from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { encodeInlineMessageId } from '../../utils/inline-utils' import { encodeInlineMessageId } from '../../utils/inline-utils'
import { Location, MtArgumentError, PeersIndex, User } from '../' import { Location, PeersIndex, User } from '../'
import { makeInspectable } from '../utils' import { makeInspectable } from '../utils'
/** /**

View file

@ -1,8 +1,9 @@
import { MtUnsupportedError } from '@mtcute/core'
import { assertTypeIs } from '@mtcute/core/utils'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { assertTypeIs } from '../../utils/type-assertion' import { Chat, PeersIndex, User } from '../'
import { Chat, MtUnsupportedError, PeersIndex, User } from '../'
import { makeInspectable } from '../utils' import { makeInspectable } from '../utils'
/** /**

View file

@ -1,14 +1,12 @@
import { getBarePeerId, toggleChannelIdMark } from '@mtcute/core' import {
getBarePeerId,
MtUnsupportedError,
toggleChannelIdMark,
} from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { import { BasicPeerType, Chat, TypingStatus, User } from '../'
BasicPeerType,
Chat,
MtUnsupportedError,
TypingStatus,
User,
} from '../'
import { makeInspectable } from '../utils' import { makeInspectable } from '../utils'
/** /**

View file

@ -1,4 +1,4 @@
import { MtArgumentError } from '../types' import { MtArgumentError } from '@mtcute/core'
/** /**
* Given file size, determine the appropriate chunk size (in KB) * Given file size, determine the appropriate chunk size (in KB)

View file

@ -1,6 +1,7 @@
import { MtArgumentError } from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { MaybeDynamic, Message, MtClientError } from '../types' import { MaybeDynamic, Message } from '../types'
/** /**
* Normalize phone number by stripping formatting * Normalize phone number by stripping formatting
@ -8,7 +9,7 @@ import { MaybeDynamic, Message, MtClientError } from '../types'
*/ */
export function normalizePhoneNumber(phone: string): string { export function normalizePhoneNumber(phone: string): string {
phone = phone.trim().replace(/[+()\s-]/g, '') phone = phone.trim().replace(/[+()\s-]/g, '')
if (!phone.match(/^\d+$/)) throw new MtClientError('Invalid phone number') if (!phone.match(/^\d+$/)) throw new MtArgumentError('Invalid phone number')
return phone return phone
} }
@ -25,7 +26,13 @@ export function extractChannelIdFromUpdate(
if ('channelId' in upd) { if ('channelId' in upd) {
res = upd.channelId res = upd.channelId
} else if ('message' in upd && typeof upd.message !== 'string' && 'peerId' in upd.message && upd.message.peerId && 'channelId' in upd.message.peerId) { } else if (
'message' in upd &&
typeof upd.message !== 'string' &&
'peerId' in upd.message &&
upd.message.peerId &&
'channelId' in upd.message.peerId
) {
res = upd.message.peerId.channelId res = upd.message.peerId.channelId
} }

View file

@ -1,13 +0,0 @@
import { tl } from '@mtcute/tl'
import { MtTypeAssertionError } from '../types'
export function assertTypeIs<T extends tl.TlObject, K extends T['_']>(
context: string,
obj: T,
expected: K,
): asserts obj is tl.FindByName<T, K> {
if (obj._ !== expected) {
throw new MtTypeAssertionError(context, expected, obj._)
}
}

View file

@ -1,7 +1,6 @@
import { MtTypeAssertionError } from '@mtcute/core'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { MtTypeAssertionError } from '../types'
// dummy updates which are used for methods that return messages.affectedHistory. // dummy updates which are used for methods that return messages.affectedHistory.
// that is not an update, but it carries info about pts, and we need to handle it // that is not an update, but it carries info about pts, and we need to handle it

View file

@ -3,6 +3,7 @@ import Long from 'long'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { TlBinaryReader, TlReaderMap } from '@mtcute/tl-runtime' import { TlBinaryReader, TlReaderMap } from '@mtcute/tl-runtime'
import { MtcuteError } from '../types'
import { buffersEqual, ICryptoProvider, Logger, randomBytes } from '../utils' import { buffersEqual, ICryptoProvider, Logger, randomBytes } from '../utils'
import { createAesIgeForMessage } from '../utils/crypto/mtproto' import { createAesIgeForMessage } from '../utils/crypto/mtproto'
@ -41,7 +42,7 @@ export class AuthKey {
serverSalt: Long, serverSalt: Long,
sessionId: Long, sessionId: Long,
): Promise<Buffer> { ): Promise<Buffer> {
if (!this.ready) throw new Error('Keys are not set up!') if (!this.ready) throw new MtcuteError('Keys are not set up!')
let padding = let padding =
(16 /* header size */ + message.length + 12) /* min padding */ % 16 (16 /* header size */ + message.length + 12) /* min padding */ % 16

View file

@ -9,6 +9,11 @@ import {
TlSerializationCounter, TlSerializationCounter,
} from '@mtcute/tl-runtime' } from '@mtcute/tl-runtime'
import {
MtArgumentError,
MtSecurityError,
MtTypeAssertionError,
} from '../types'
import { import {
bigIntToBuffer, bigIntToBuffer,
bufferToBigInt, bufferToBigInt,
@ -24,6 +29,7 @@ import {
import { findKeyByFingerprints } from '../utils/crypto/keys' import { findKeyByFingerprints } from '../utils/crypto/keys'
import { millerRabin } from '../utils/crypto/miller-rabin' import { millerRabin } from '../utils/crypto/miller-rabin'
import { generateKeyAndIvFromNonce } from '../utils/crypto/mtproto' import { generateKeyAndIvFromNonce } from '../utils/crypto/mtproto'
import { mtpAssertTypeIs } from '../utils/type-assertions'
import { SessionConnection } from './session-connection' import { SessionConnection } from './session-connection'
// Heavily based on code from https://github.com/LonamiWebs/Telethon/blob/master/telethon/network/authenticator.py // Heavily based on code from https://github.com/LonamiWebs/Telethon/blob/master/telethon/network/authenticator.py
@ -57,14 +63,16 @@ function checkDhPrime(log: Logger, dhPrime: bigInt.BigInteger, g: number) {
dhPrime.lesserOrEquals(TWO_POW_2047) || dhPrime.lesserOrEquals(TWO_POW_2047) ||
dhPrime.greaterOrEquals(TWO_POW_2048) dhPrime.greaterOrEquals(TWO_POW_2048)
) { ) {
throw new Error('Step 3: dh_prime is not in the 2048-bit range') throw new MtSecurityError(
'Step 3: dh_prime is not in the 2048-bit range',
)
} }
if (!millerRabin(dhPrime)) { if (!millerRabin(dhPrime)) {
throw new Error('Step 3: dh_prime is not prime') throw new MtSecurityError('Step 3: dh_prime is not prime')
} }
if (!millerRabin(dhPrime.minus(1).divide(2))) { if (!millerRabin(dhPrime.minus(1).divide(2))) {
throw new Error( throw new MtSecurityError(
'Step 3: dh_prime is not a safe prime - (dh_prime-1)/2 is not prime', 'Step 3: dh_prime is not a safe prime - (dh_prime-1)/2 is not prime',
) )
} }
@ -91,12 +99,16 @@ function checkDhPrime(log: Logger, dhPrime: bigInt.BigInteger, g: number) {
switch (g) { switch (g) {
case 2: case 2:
if (dhPrime.mod(8).notEquals(7)) { if (dhPrime.mod(8).notEquals(7)) {
throw new Error('Step 3: ivalid g - dh_prime mod 8 != 7') throw new MtSecurityError(
'Step 3: ivalid g - dh_prime mod 8 != 7',
)
} }
break break
case 3: case 3:
if (dhPrime.mod(3).notEquals(2)) { if (dhPrime.mod(3).notEquals(2)) {
throw new Error('Step 3: ivalid g - dh_prime mod 3 != 2') throw new MtSecurityError(
'Step 3: ivalid g - dh_prime mod 3 != 2',
)
} }
break break
case 4: case 4:
@ -105,7 +117,7 @@ function checkDhPrime(log: Logger, dhPrime: bigInt.BigInteger, g: number) {
const mod = dhPrime.mod(5) const mod = dhPrime.mod(5)
if (mod.notEquals(1) && mod.notEquals(4)) { if (mod.notEquals(1) && mod.notEquals(4)) {
throw new Error( throw new MtSecurityError(
'Step 3: ivalid g - dh_prime mod 5 != 1 && dh_prime mod 5 != 4', 'Step 3: ivalid g - dh_prime mod 5 != 1 && dh_prime mod 5 != 4',
) )
} }
@ -115,7 +127,7 @@ function checkDhPrime(log: Logger, dhPrime: bigInt.BigInteger, g: number) {
const mod = dhPrime.mod(24) const mod = dhPrime.mod(24)
if (mod.notEquals(19) && mod.notEquals(23)) { if (mod.notEquals(19) && mod.notEquals(23)) {
throw new Error( throw new MtSecurityError(
'Step 3: ivalid g - dh_prime mod 24 != 19 && dh_prime mod 24 != 23', 'Step 3: ivalid g - dh_prime mod 24 != 19 && dh_prime mod 24 != 23',
) )
} }
@ -125,14 +137,14 @@ function checkDhPrime(log: Logger, dhPrime: bigInt.BigInteger, g: number) {
const mod = dhPrime.mod(7) const mod = dhPrime.mod(7)
if (mod.notEquals(3) && mod.notEquals(5) && mod.notEquals(6)) { if (mod.notEquals(3) && mod.notEquals(5) && mod.notEquals(6)) {
throw new Error( throw new MtSecurityError(
'Step 3: ivalid g - dh_prime mod 7 != 3 && dh_prime mod 7 != 5 && dh_prime mod 7 != 6', 'Step 3: ivalid g - dh_prime mod 7 != 3 && dh_prime mod 7 != 5 && dh_prime mod 7 != 6',
) )
} }
break break
} }
default: default:
throw new Error(`Step 3: ivalid g - unknown g = ${g}`) throw new MtSecurityError(`Step 3: ivalid g - unknown g = ${g}`)
} }
checkedPrime.generators.push(g) checkedPrime.generators.push(g)
@ -151,7 +163,7 @@ async function rsaPad(
const keyExponent = bigInt(key.exponent, 16) const keyExponent = bigInt(key.exponent, 16)
if (data.length > 144) { if (data.length > 144) {
throw new Error('Failed to pad: too big data') throw new MtArgumentError('Failed to pad: too big data')
} }
data = Buffer.concat([data, randomBytes(192 - data.length)]) data = Buffer.concat([data, randomBytes(192 - data.length)])
@ -265,10 +277,10 @@ export async function doAuthorization(
await sendPlainMessage({ _: 'mt_req_pq_multi', nonce }) await sendPlainMessage({ _: 'mt_req_pq_multi', nonce })
const resPq = await readNext() const resPq = await readNext()
if (resPq._ !== 'mt_resPQ') throw new Error('Step 1: answer was ' + resPq._) mtpAssertTypeIs('auth step 1', resPq, 'mt_resPQ')
if (!buffersEqual(resPq.nonce, nonce)) { if (!buffersEqual(resPq.nonce, nonce)) {
throw new Error('Step 1: invalid nonce from server') throw new MtSecurityError('Step 1: invalid nonce from server')
} }
const serverKeys = resPq.serverPublicKeyFingerprints.map((it) => const serverKeys = resPq.serverPublicKeyFingerprints.map((it) =>
@ -280,7 +292,7 @@ export async function doAuthorization(
const publicKey = findKeyByFingerprints(serverKeys) const publicKey = findKeyByFingerprints(serverKeys)
if (!publicKey) { if (!publicKey) {
throw new Error( throw new MtSecurityError(
'Step 2: Could not find server public key with any of these fingerprints: ' + 'Step 2: Could not find server public key with any of these fingerprints: ' +
serverKeys.join(', '), serverKeys.join(', '),
) )
@ -330,19 +342,13 @@ export async function doAuthorization(
}) })
const serverDhParams = await readNext() const serverDhParams = await readNext()
if (!mtp.isAnyServer_DH_Params(serverDhParams)) { mtpAssertTypeIs('auth step 2', serverDhParams, 'mt_server_DH_params_ok')
throw new Error('Step 2.1: answer was ' + serverDhParams._)
}
if (serverDhParams._ !== 'mt_server_DH_params_ok') {
throw new Error('Step 2.1: answer was ' + serverDhParams._)
}
if (!buffersEqual(serverDhParams.nonce, nonce)) { if (!buffersEqual(serverDhParams.nonce, nonce)) {
throw Error('Step 2: invalid nonce from server') throw new MtSecurityError('Step 2: invalid nonce from server')
} }
if (!buffersEqual(serverDhParams.serverNonce, resPq.serverNonce)) { if (!buffersEqual(serverDhParams.serverNonce, resPq.serverNonce)) {
throw Error('Step 2: invalid server nonce from server') throw new MtSecurityError('Step 2: invalid server nonce from server')
} }
// type was removed from schema in July 2021 // type was removed from schema in July 2021
@ -350,14 +356,14 @@ export async function doAuthorization(
// // why would i want to do that? we are gonna fail anyways. // // why would i want to do that? we are gonna fail anyways.
// // let expectedNnh = (await crypto.sha1(newNonce)).slice(4, 20) // // let expectedNnh = (await crypto.sha1(newNonce)).slice(4, 20)
// // if (!buffersEqual(serverDhParams.newNonceHash, expectedNnh)) // // if (!buffersEqual(serverDhParams.newNonceHash, expectedNnh))
// // throw new Error('Step 2: invalid DH fail nonce from server') // // throw new MtSecurityError('Step 2: invalid DH fail nonce from server')
// throw new Error('Step 2: server DH failed') // throw new MtSecurityError('Step 2: server DH failed')
// } // }
log.debug('server DH ok') log.debug('server DH ok')
if (serverDhParams.encryptedAnswer.length % 16 !== 0) { if (serverDhParams.encryptedAnswer.length % 16 !== 0) {
throw new Error('Step 2: AES block size is invalid') throw new MtSecurityError('Step 2: AES block size is invalid')
} }
// Step 3: complete DH exchange // Step 3: complete DH exchange
@ -385,12 +391,11 @@ export async function doAuthorization(
), ),
) )
) { ) {
throw new Error('Step 3: invalid inner data hash') throw new MtSecurityError('Step 3: invalid inner data hash')
} }
if (serverDhInner._ !== 'mt_server_DH_inner_data') { mtpAssertTypeIs('auth step 3', serverDhInner, 'mt_server_DH_inner_data')
throw Error('Step 3: inner data was ' + serverDhInner._)
}
if (!buffersEqual(serverDhInner.nonce, nonce)) { if (!buffersEqual(serverDhInner.nonce, nonce)) {
throw Error('Step 3: invalid nonce from server') throw Error('Step 3: invalid nonce from server')
} }
@ -424,28 +429,28 @@ export async function doAuthorization(
g.lesserOrEquals(1) || g.lesserOrEquals(1) ||
g.greaterOrEquals(dhPrime.minus(bigInt.one)) g.greaterOrEquals(dhPrime.minus(bigInt.one))
) { ) {
throw new Error('g is not within (1, dh_prime - 1)') throw new MtSecurityError('g is not within (1, dh_prime - 1)')
} }
if ( if (
gA.lesserOrEquals(1) || gA.lesserOrEquals(1) ||
gA.greaterOrEquals(dhPrime.minus(bigInt.one)) gA.greaterOrEquals(dhPrime.minus(bigInt.one))
) { ) {
throw new Error('g_a is not within (1, dh_prime - 1)') throw new MtSecurityError('g_a is not within (1, dh_prime - 1)')
} }
if ( if (
gB.lesserOrEquals(1) || gB.lesserOrEquals(1) ||
gB.greaterOrEquals(dhPrime.minus(bigInt.one)) gB.greaterOrEquals(dhPrime.minus(bigInt.one))
) { ) {
throw new Error('g_b is not within (1, dh_prime - 1)') throw new MtSecurityError('g_b is not within (1, dh_prime - 1)')
} }
if (gA.lt(DH_SAFETY_RANGE) || gA.gt(dhPrime.minus(DH_SAFETY_RANGE))) { if (gA.lt(DH_SAFETY_RANGE) || gA.gt(dhPrime.minus(DH_SAFETY_RANGE))) {
throw new Error( throw new MtSecurityError(
'g_a is not within (2^{2048-64}, dh_prime - 2^{2048-64})', 'g_a is not within (2^{2048-64}, dh_prime - 2^{2048-64})',
) )
} }
if (gB.lt(DH_SAFETY_RANGE) || gB.gt(dhPrime.minus(DH_SAFETY_RANGE))) { if (gB.lt(DH_SAFETY_RANGE) || gB.gt(dhPrime.minus(DH_SAFETY_RANGE))) {
throw new Error( throw new MtSecurityError(
'g_b is not within (2^{2048-64}, dh_prime - 2^{2048-64})', 'g_b is not within (2^{2048-64}, dh_prime - 2^{2048-64})',
) )
} }
@ -488,7 +493,11 @@ export async function doAuthorization(
const dhGen = await readNext() const dhGen = await readNext()
if (!mtp.isAnySet_client_DH_params_answer(dhGen)) { if (!mtp.isAnySet_client_DH_params_answer(dhGen)) {
throw new Error('Step 4: answer was ' + dhGen._) throw new MtTypeAssertionError(
'auth step 4',
'set_client_DH_params_answer',
dhGen._,
)
} }
if (!buffersEqual(dhGen.nonce, nonce)) { if (!buffersEqual(dhGen.nonce, nonce)) {
@ -502,7 +511,11 @@ export async function doAuthorization(
if (dhGen._ === 'mt_dh_gen_fail') { if (dhGen._ === 'mt_dh_gen_fail') {
// in theory i would be supposed to calculate newNonceHash, but why, we are failing anyway // in theory i would be supposed to calculate newNonceHash, but why, we are failing anyway
throw new Error('Step 4: server DH returned failure') throw new MtTypeAssertionError(
'auth step 4',
'!mt_dh_gen_fail',
dhGen._,
)
} }
if (dhGen._ === 'mt_dh_gen_retry') { if (dhGen._ === 'mt_dh_gen_retry') {

View file

@ -8,6 +8,7 @@ import {
TlWriterMap, TlWriterMap,
} from '@mtcute/tl-runtime' } from '@mtcute/tl-runtime'
import { MtcuteError } from '../types'
import { import {
ControllablePromise, ControllablePromise,
Deque, Deque,
@ -183,7 +184,7 @@ export class MtprotoSession {
if (!keepPending) { if (!keepPending) {
for (const info of this.pendingMessages.values()) { for (const info of this.pendingMessages.values()) {
if (info._ === 'rpc') { if (info._ === 'rpc') {
info.rpc.promise.reject(new Error('Session is reset')) info.rpc.promise.reject(new MtcuteError('Session is reset'))
} }
} }
this.pendingMessages.clear() this.pendingMessages.clear()
@ -197,7 +198,7 @@ export class MtprotoSession {
const rpc = this.queuedRpc.popFront()! const rpc = this.queuedRpc.popFront()!
if (rpc.sent === false) { if (rpc.sent === false) {
rpc.promise.reject(new Error('Session is reset')) rpc.promise.reject(new MtcuteError('Session is reset'))
} }
} }
} }
@ -264,7 +265,7 @@ export class MtprotoSession {
data: Buffer, data: Buffer,
callback: Parameters<AuthKey['decryptMessage']>[2], callback: Parameters<AuthKey['decryptMessage']>[2],
): Promise<void> { ): Promise<void> {
if (!this._authKey.ready) throw new Error('Keys are not set up!') if (!this._authKey.ready) throw new MtcuteError('Keys are not set up!')
const authKeyId = data.slice(0, 8) const authKeyId = data.slice(0, 8)

View file

@ -2,12 +2,14 @@ import { tl } from '@mtcute/tl'
import { TlReaderMap, TlWriterMap } from '@mtcute/tl-runtime' import { TlReaderMap, TlWriterMap } from '@mtcute/tl-runtime'
import { ITelegramStorage } from '../storage' import { ITelegramStorage } from '../storage'
import { MtArgumentError, MtcuteError } from '../types'
import { import {
createControllablePromise, createControllablePromise,
ICryptoProvider, ICryptoProvider,
Logger, Logger,
sleep, sleep,
} from '../utils' } from '../utils'
import { assertTypeIs } from '../utils/type-assertions'
import { ConfigManager } from './config-manager' import { ConfigManager } from './config-manager'
import { MultiSessionConnection } from './multi-session-connection' import { MultiSessionConnection } from './multi-session-connection'
import { PersistentConnectionParams } from './persistent-connection' import { PersistentConnectionParams } from './persistent-connection'
@ -500,7 +502,7 @@ export class NetworkManager {
}) })
if (!main || !media) { if (!main || !media) {
throw new Error(`Could not find DC ${dcId}`) throw new MtArgumentError(`Could not find DC ${dcId}`)
} }
return { main, media } return { main, media }
@ -586,12 +588,12 @@ export class NetworkManager {
*/ */
async connect(defaultDcs: ITelegramStorage.DcOptions): Promise<void> { async connect(defaultDcs: ITelegramStorage.DcOptions): Promise<void> {
if (defaultDcs.main.id !== defaultDcs.media.id) { if (defaultDcs.main.id !== defaultDcs.media.id) {
throw new Error('Default DCs must be the same') throw new MtArgumentError('Default DCs must be the same')
} }
if (this._dcConnections.has(defaultDcs.main.id)) { if (this._dcConnections.has(defaultDcs.main.id)) {
// shouldn't happen // shouldn't happen
throw new Error('DC manager already exists') throw new MtArgumentError('DC manager already exists')
} }
const dc = new DcConnectionManager(this, defaultDcs.main.id, defaultDcs) const dc = new DcConnectionManager(this, defaultDcs.main.id, defaultDcs)
@ -626,11 +628,7 @@ export class NetworkManager {
{ manager }, { manager },
) )
if (res._ !== 'auth.authorization') { assertTypeIs('auth.importAuthorization', res, 'auth.authorization')
throw new Error(
`Unexpected response from auth.importAuthorization: ${res._}`,
)
}
promise.resolve() promise.resolve()
delete this._pendingExports[manager.dcId] delete this._pendingExports[manager.dcId]
@ -713,7 +711,7 @@ export class NetworkManager {
stack?: string, stack?: string,
): Promise<tl.RpcCallReturn[T['_']]> { ): Promise<tl.RpcCallReturn[T['_']]> {
if (!this._primaryDc) { if (!this._primaryDc) {
throw new Error('Not connected to any DC') throw new MtcuteError('Not connected to any DC')
} }
const floodSleepThreshold = const floodSleepThreshold =
@ -860,7 +858,7 @@ export class NetworkManager {
if (!dc) { if (!dc) {
if (!this._primaryDc) { if (!this._primaryDc) {
throw new Error('Not connected to any DC') throw new MtcuteError('Not connected to any DC')
} }
// guess based on the provided delegate. it is most likely correct, // guess based on the provided delegate. it is most likely correct,
@ -876,7 +874,7 @@ export class NetworkManager {
} }
getPrimaryDcId() { getPrimaryDcId() {
if (!this._primaryDc) throw new Error('Not connected to any DC') if (!this._primaryDc) throw new MtcuteError('Not connected to any DC')
return this._primaryDc.dcId return this._primaryDc.dcId
} }

View file

@ -2,6 +2,7 @@ import EventEmitter from 'events'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { MtcuteError } from '../types'
import { ICryptoProvider, Logger } from '../utils' import { ICryptoProvider, Logger } from '../utils'
import { ReconnectionStrategy } from './reconnection' import { ReconnectionStrategy } from './reconnection'
import { import {
@ -166,9 +167,9 @@ export abstract class PersistentConnection extends EventEmitter {
connect(): void { connect(): void {
if (this.isConnected) { if (this.isConnected) {
throw new Error('Connection is already opened!') throw new MtcuteError('Connection is already opened!')
} }
if (this._destroyed) throw new Error('Connection is already destroyed!') if (this._destroyed) { throw new MtcuteError('Connection is already destroyed!') }
if (this._reconnectionTimeout != null) { if (this._reconnectionTimeout != null) {
clearTimeout(this._reconnectionTimeout) clearTimeout(this._reconnectionTimeout)

View file

@ -12,6 +12,7 @@ import {
} from '@mtcute/tl-runtime' } from '@mtcute/tl-runtime'
import { gzipDeflate, gzipInflate } from '@mtcute/tl-runtime/src/platform/gzip' import { gzipDeflate, gzipInflate } from '@mtcute/tl-runtime/src/platform/gzip'
import { MtArgumentError, MtcuteError, MtTimeoutError } from '../types'
import { import {
ControllablePromise, ControllablePromise,
createCancellablePromise, createCancellablePromise,
@ -123,7 +124,7 @@ export class SessionConnection extends PersistentConnection {
Object.values(this._pendingWaitForUnencrypted).forEach( Object.values(this._pendingWaitForUnencrypted).forEach(
([prom, timeout]) => { ([prom, timeout]) => {
prom.reject(new Error('Connection closed')) prom.reject(new MtcuteError('Connection closed'))
clearTimeout(timeout) clearTimeout(timeout)
}, },
) )
@ -456,7 +457,7 @@ export class SessionConnection extends PersistentConnection {
res.errorCode, res.errorCode,
res.errorMessage, res.errorMessage,
) )
throw new Error('Failed to bind temporary key') throw new MtcuteError('Failed to bind temporary key')
} }
// now we can swap the keys (secondary becomes primary, // now we can swap the keys (secondary becomes primary,
@ -506,7 +507,7 @@ export class SessionConnection extends PersistentConnection {
waitForUnencryptedMessage(timeout = 5000): Promise<Buffer> { waitForUnencryptedMessage(timeout = 5000): Promise<Buffer> {
const promise = createControllablePromise<Buffer>() const promise = createControllablePromise<Buffer>()
const timeoutId = setTimeout(() => { const timeoutId = setTimeout(() => {
promise.reject(new Error('Timeout')) promise.reject(new MtTimeoutError(timeout))
this._pendingWaitForUnencrypted = this._pendingWaitForUnencrypted =
this._pendingWaitForUnencrypted.filter( this._pendingWaitForUnencrypted.filter(
(it) => it[0] !== promise, (it) => it[0] !== promise,
@ -1453,7 +1454,9 @@ export class SessionConnection extends PersistentConnection {
// and since we resend them, it will get resent after reconnection and // and since we resend them, it will get resent after reconnection and
// that will be an endless loop of reconnections. we don't want that, // that will be an endless loop of reconnections. we don't want that,
// and payloads this large are usually a sign of an error in the code. // and payloads this large are usually a sign of an error in the code.
throw new Error(`Payload is too big (${content.length} > 1044404)`) throw new MtArgumentError(
`Payload is too big (${content.length} > 1044404)`,
)
} }
// gzip // gzip
@ -1533,7 +1536,7 @@ export class SessionConnection extends PersistentConnection {
private _cancelRpc(rpc: PendingRpc, onTimeout = false): void { private _cancelRpc(rpc: PendingRpc, onTimeout = false): void {
if (rpc.cancelled && !onTimeout) { if (rpc.cancelled && !onTimeout) {
throw new Error('RPC was already cancelled') throw new MtcuteError('RPC was already cancelled')
} }
if (!onTimeout && rpc.timeout) { if (!onTimeout && rpc.timeout) {

View file

@ -3,6 +3,7 @@ import { connect, Socket } from 'net'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { MtcuteError } from '../../types'
import { ICryptoProvider, Logger } from '../../utils' import { ICryptoProvider, Logger } from '../../utils'
import { IPacketCodec, ITelegramTransport, TransportState } from './abstract' import { IPacketCodec, ITelegramTransport, TransportState } from './abstract'
import { IntermediatePacketCodec } from './intermediate' import { IntermediatePacketCodec } from './intermediate'
@ -49,7 +50,7 @@ export abstract class BaseTcpTransport
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
connect(dc: tl.RawDcOption, testMode: boolean): void { connect(dc: tl.RawDcOption, testMode: boolean): void {
if (this._state !== TransportState.Idle) { if (this._state !== TransportState.Idle) {
throw new Error('Transport is not IDLE') throw new MtcuteError('Transport is not IDLE')
} }
if (!this.packetCodecInitialized) { if (!this.packetCodecInitialized) {
@ -125,7 +126,7 @@ export abstract class BaseTcpTransport
async send(bytes: Buffer): Promise<void> { async send(bytes: Buffer): Promise<void> {
if (this._state !== TransportState.Ready) { if (this._state !== TransportState.Ready) {
throw new Error('Transport is not READY') throw new MtcuteError('Transport is not READY')
} }
const framed = await this._packetCodec.encode(bytes) const framed = await this._packetCodec.encode(bytes)

View file

@ -2,6 +2,7 @@ import EventEmitter from 'events'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { MtcuteError, MtUnsupportedError } from '../../types'
import { ICryptoProvider, Logger, typedArrayToBuffer } from '../../utils' import { ICryptoProvider, Logger, typedArrayToBuffer } from '../../utils'
import { IPacketCodec, ITelegramTransport, TransportState } from './abstract' import { IPacketCodec, ITelegramTransport, TransportState } from './abstract'
import { IntermediatePacketCodec } from './intermediate' import { IntermediatePacketCodec } from './intermediate'
@ -57,7 +58,7 @@ export abstract class BaseWebSocketTransport
super() super()
if (!ws) { if (!ws) {
throw new Error( throw new MtUnsupportedError(
'To use WebSocket transport with NodeJS, install `ws` package.', 'To use WebSocket transport with NodeJS, install `ws` package.',
) )
} }
@ -93,7 +94,7 @@ export abstract class BaseWebSocketTransport
connect(dc: tl.RawDcOption, testMode: boolean): void { connect(dc: tl.RawDcOption, testMode: boolean): void {
if (this._state !== TransportState.Idle) { if (this._state !== TransportState.Idle) {
throw new Error('Transport is not IDLE') throw new MtcuteError('Transport is not IDLE')
} }
if (!this.packetCodecInitialized) { if (!this.packetCodecInitialized) {
@ -164,7 +165,7 @@ export abstract class BaseWebSocketTransport
async send(bytes: Buffer): Promise<void> { async send(bytes: Buffer): Promise<void> {
if (this._state !== TransportState.Ready) { if (this._state !== TransportState.Ready) {
throw new Error('Transport is not READY') throw new MtcuteError('Transport is not READY')
} }
const framed = await this._packetCodec.encode(bytes) const framed = await this._packetCodec.encode(bytes)

View file

@ -1,6 +1,7 @@
import type * as exitHookNs from 'exit-hook' import type * as exitHookNs from 'exit-hook'
import type * as fsNs from 'fs' import type * as fsNs from 'fs'
import { MtUnsupportedError } from '../types'
import { JsonMemoryStorage } from './json' import { JsonMemoryStorage } from './json'
type fs = typeof fsNs type fs = typeof fsNs
@ -52,7 +53,7 @@ export class JsonFileStorage extends JsonMemoryStorage {
super() super()
if (!fs || !fs.readFile) { if (!fs || !fs.readFile) {
throw new Error('Node fs module is not available!') throw new MtUnsupportedError('Node fs module is not available!')
} }
this._filename = filename this._filename = filename
@ -60,7 +61,7 @@ export class JsonFileStorage extends JsonMemoryStorage {
this._cleanup = params?.cleanup ?? Boolean(exitHook) this._cleanup = params?.cleanup ?? Boolean(exitHook)
if (this._cleanup && !exitHook) { if (this._cleanup && !exitHook) {
throw new Error( throw new MtUnsupportedError(
'Cleanup on exit is supported through `exit-hook` library, install it first!', 'Cleanup on exit is supported through `exit-hook` library, install it first!',
) )
} }

View file

@ -1,3 +1,4 @@
import { MtUnsupportedError } from '../types'
import { JsonMemoryStorage } from './json' import { JsonMemoryStorage } from './json'
export class LocalstorageStorage extends JsonMemoryStorage { export class LocalstorageStorage extends JsonMemoryStorage {
@ -7,7 +8,7 @@ export class LocalstorageStorage extends JsonMemoryStorage {
super() super()
if (typeof localStorage === 'undefined') { if (typeof localStorage === 'undefined') {
throw new Error('localStorage is not available!') throw new MtUnsupportedError('localStorage is not available!')
} }
this._key = key this._key = key

View file

@ -151,7 +151,9 @@ export class MemoryStorage implements ITelegramStorage, IStateStorage {
(ent: ITelegramStorage.PeerInfo) => { (ent: ITelegramStorage.PeerInfo) => {
if (ent.phone) obj.phoneIndex.set(ent.phone, ent.id) if (ent.phone) obj.phoneIndex.set(ent.phone, ent.id)
if (ent.username) { obj.usernameIndex.set(ent.username, ent.id) } if (ent.username) {
obj.usernameIndex.set(ent.username, ent.id)
}
}, },
) )
} }
@ -291,8 +293,6 @@ export class MemoryStorage implements ITelegramStorage, IStateStorage {
accessHash: peerInfo.accessHash, accessHash: peerInfo.accessHash,
} }
} }
throw new Error(`Invalid peer type: ${peerInfo.type}`)
} }
getPeerById(peerId: number): tl.TypeInputPeer | null { getPeerById(peerId: number): tl.TypeInputPeer | null {

View file

@ -0,0 +1,65 @@
/**
* Base class for all mtcute errors
*/
export class MtcuteError extends Error {}
/**
* Method invocation was invalid because some argument
* passed was invalid.
*/
export class MtArgumentError extends MtcuteError {}
/**
* Something isn't right with security of the connection.
*/
export class MtSecurityError extends MtcuteError {}
/**
* Either you requested or the server returned something
* that is not (yet) supported.
*
* Stay tuned for future updates!
*
* In some cases, this error may mean that you are missing some
* optional peer dependencies, or that the feature is not supported
* in the current environment.
*/
export class MtUnsupportedError extends MtcuteError {}
/**
* Server returned something of an unexpected type.
*
* This is usually a problem on library side.
* Feel free to open an issue about this!
*/
export class MtTypeAssertionError extends MtcuteError {
/**
* Context at which the error occurred.
* Usually a user-friendly string containing name
* of the high-level API method, name of the TL
* RPC method, and path of the entity,
* like this: `signIn (@ auth.signIn -> user)`
*/
context: string
/** Expected TL type */
expected: string
/** Actual TL type */
actual: string
constructor(context: string, expected: string, actual: string) {
super(
`Type assertion error at ${context}: expected ${expected}, but got ${actual}`,
)
this.context = context
this.expected = expected
this.actual = actual
}
}
export class MtTimeoutError extends MtcuteError {
constructor(readonly timeout?: number) {
super(`Request timed out${timeout ? ` after ${timeout}ms` : ''}`)
}
}

Some files were not shown because too many files have changed in this diff Show more