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 { MtTypeAssertionError } from '../../types'
/**
* 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 { User } from '../../types'
import { assertTypeIs } from '../../utils/type-assertion'
/**
* 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 { User } from '../../types'
import { assertTypeIs } from '../../utils/type-assertion'
/**
* 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 { SentCode } from '../../types'
import { normalizePhoneNumber } from '../../utils/misc-utils'
import { assertTypeIs } from '../../utils/type-assertion'
/**
* 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 { SentCode } from '../../types'
import { normalizePhoneNumber } from '../../utils/misc-utils'
import { assertTypeIs } from '../../utils/type-assertion'
/**
* 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 { User } from '../../types'
import { assertTypeIs } from '../../utils/type-assertion'
/**
* 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 { TermsOfService, User } from '../../types'
import { normalizePhoneNumber } from '../../utils/misc-utils'
import { assertTypeIs } from '../../utils/type-assertion'
/**
* 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 { User } from '../../types'
import { normalizePhoneNumber } from '../../utils/misc-utils'
import { assertTypeIs } from '../../utils/type-assertion'
/**
* Register a new user in Telegram.

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +1,7 @@
import { MtArgumentError } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { ChatPreview, MtArgumentError, MtPeerNotFoundError } from '../../types'
import { ChatPreview, MtPeerNotFoundError } from '../../types'
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 { TelegramClient } from '../../client'
import { Chat, InputPeerLike, MtArgumentError } from '../../types'
import { Chat, InputPeerLike } from '../../types'
import {
INVITE_LINK_REGEX,
isInputPeerChannel,

View file

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

View file

@ -1,9 +1,9 @@
import { getMarkedPeerId } from '@mtcute/core'
import { assertTypeIs } from '@mtcute/core/utils'
import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client'
import { Chat } from '../../types'
import { assertTypeIs } from '../../utils/type-assertion'
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 { tl } from '@mtcute/tl'
@ -6,7 +7,6 @@ import {
InputFileLike,
InputPeerLike,
isUploadedFile,
MtArgumentError,
MtInvalidPeerTypeError,
} from '../../types'
import {
@ -37,14 +37,18 @@ export async function setChatPhoto(
): Promise<void> {
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 inputFile: tl.TypeInputFile
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:/)) {
const uploaded = await this.uploadFile({
file: media.substring(5),

View file

@ -1,8 +1,9 @@
import Long from 'long'
import { assertTypeIs } from '@mtcute/core/utils'
import { TelegramClient } from '../../client'
import { User } from '../../types'
import { assertTypeIs } from '../../utils/type-assertion'
/**
* 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 { TelegramClient } from '../../client'
import { MtArgumentError } from '../../types'
/**
* Edit a folder with given modification
@ -31,7 +31,9 @@ export async function editFolder(
(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
}

View file

@ -1,7 +1,7 @@
import { MtArgumentError } from '@mtcute/core'
import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client'
import { MtArgumentError } from '../../types'
/**
* Find a folder by its parameter.
@ -21,7 +21,9 @@ export async function findFolder(
id?: number
},
): 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()

View file

@ -1,9 +1,10 @@
import Long from 'long'
import { MtArgumentError } from '@mtcute/core'
import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client'
import { Dialog, MtArgumentError } from '../../types'
import { Dialog } from '../../types'
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 `include`, we already yielded them, so we also want to exclude them
// if pinned is `keep`, we want to keep them
const filterFolder = filters ?
Dialog.filterFolder(filters, pinned !== 'keep') :
undefined

View file

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

View file

@ -1,10 +1,7 @@
import { TelegramClient } from '../../client'
import {
FileDownloadParameters,
FileLocation,
MtUnsupportedError,
} from '../../types'
import { MtUnsupportedError } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { FileDownloadParameters, FileLocation } from '../../types'
let fs: typeof import('fs') | null = null
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 {
fileIdToInputFileLocation,
@ -8,12 +12,7 @@ import {
import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client'
import {
FileDownloadParameters,
FileLocation,
MtArgumentError,
MtUnsupportedError,
} from '../../types'
import { FileDownloadParameters, FileLocation } from '../../types'
import { determinePartSize } from '../../utils/file-utils'
// 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 { TelegramClient } from '../../client'
import { InputFileLike } from '../../types'
import { assertTypeIs } from '../../utils/type-assertion'
/**
* @internal

View file

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

View file

@ -1,5 +1,6 @@
import Long from 'long'
import { assertTypeIs } from '@mtcute/core/utils'
import {
fileIdToInputDocument,
fileIdToInputPhoto,
@ -12,7 +13,6 @@ import { TelegramClient } from '../../client'
import { InputMediaLike, isUploadedFile, UploadFileLike } from '../../types'
import { extractFileName } from '../../utils/file-utils'
import { normalizeDate } from '../../utils/misc-utils'
import { assertTypeIs } from '../../utils/type-assertion'
import { encodeWaveform } from '../../utils/voice-utils'
/**
@ -267,8 +267,8 @@ export async function _normalizeInputMedia(
)
assertTypeIs(
'normalizeInputMedia (@ messages.uploadMedia)',
res.document!,
'document',
res.document!,
'document',
)
return {
@ -377,7 +377,9 @@ export async function _normalizeInputMedia(
roundMessage: media.isRound,
})
if (media.isAnimated) { attributes.push({ _: 'documentAttributeAnimated' }) }
if (media.isAnimated) {
attributes.push({ _: 'documentAttributeAnimated' })
}
}
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 { Readable } from 'stream'
import { MtArgumentError } from '@mtcute/core'
import { AsyncLock, randomLong } from '@mtcute/core/utils'
import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client'
import { MtArgumentError, UploadedFile, UploadFileLike } from '../../types'
import { UploadedFile, UploadFileLike } from '../../types'
import { determinePartSize, isProbablyPlainText } from '../../utils/file-utils'
import {
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 {
InputMediaLike,
InputPeerLike,
MessageMedia,
MtArgumentError,
MtTypeAssertionError,
Photo,
RawDocument,
} from '../../types'
import { parseDocument } from '../../types/media/document-utils'
import { assertTypeIs } from '../../utils/type-assertion'
/**
* 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 { TelegramClient } from '../../client'
import {
ChatInviteLink,
InputPeerLike,
MtInvalidPeerTypeError,
MtTypeAssertionError,
PeersIndex,
} from '../../types'
import { ChatInviteLink, InputPeerLike, PeersIndex } from '../../types'
import { normalizeToInputUser } from '../../utils/peer-utils'
/**

View file

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

View file

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

View file

@ -1,7 +1,8 @@
import { MtTypeAssertionError } from '@mtcute/core'
import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client'
import { Message, MtTypeAssertionError, PeersIndex } from '../../types'
import { Message, PeersIndex } from '../../types'
import { assertIsUpdatesGroup } from '../../utils/updates-utils'
/** @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 { tl } from '@mtcute/tl'
@ -8,7 +8,6 @@ import {
InputMediaLike,
InputPeerLike,
Message,
MtArgumentError,
PeersIndex,
} from '../../types'
import { normalizeDate } from '../../utils/misc-utils'

View file

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

View file

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

View file

@ -1,8 +1,8 @@
import { getMarkedPeerId, MaybeArray } from '@mtcute/core'
import { assertTypeIs } from '@mtcute/core/utils'
import { TelegramClient } from '../../client'
import { InputPeerLike, MessageReactions, PeersIndex } from '../../types'
import { assertTypeIs } from '../../utils/type-assertion'
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 { 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.

View file

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

View file

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

View file

@ -1,8 +1,9 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { MtArgumentError } from '@mtcute/core'
import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client'
import { FormattedString, MtClientError } from '../../types'
import { FormattedString } from '../../types'
import { normalizeToInputUser } from '../../utils/peer-utils'
const empty: [string, undefined] = ['', undefined]
@ -33,7 +34,7 @@ export async function _parseEntities(
const modeImpl = this._parseModes.get(mode)
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)

View file

@ -1,7 +1,8 @@
import { MtTypeAssertionError } from '@mtcute/core'
import { tl } from '@mtcute/tl'
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

View file

@ -1,14 +1,10 @@
import Long from 'long'
import { MtTypeAssertionError } from '@mtcute/core'
import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client'
import {
InputPeerLike,
Message,
MtTypeAssertionError,
PeersIndex,
SearchFilters } from '../../types'
import { InputPeerLike, Message, PeersIndex, SearchFilters } from '../../types'
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 { tl } from '@mtcute/tl'
@ -8,7 +8,6 @@ import {
InputMediaLike,
InputPeerLike,
Message,
MtArgumentError,
MtMessageNotFoundError,
PeersIndex,
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 { tl } from '@mtcute/tl'
@ -9,7 +9,6 @@ import {
InputMediaLike,
InputPeerLike,
Message,
MtArgumentError,
MtMessageNotFoundError,
ReplyMarkup,
} from '../../types'

View file

@ -1,14 +1,10 @@
import Long from 'long'
import { MtTypeAssertionError } from '@mtcute/core'
import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client'
import {
InputPeerLike,
Message,
MtTypeAssertionError,
PeersIndex,
} from '../../types'
import { InputPeerLike, Message, PeersIndex } from '../../types'
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 { tl } from '@mtcute/tl'
@ -8,9 +12,7 @@ import {
FormattedString,
InputPeerLike,
Message,
MtArgumentError,
MtMessageNotFoundError,
MtTypeAssertionError,
PeersIndex,
ReplyMarkup,
} 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 { TelegramClient } from '../../client'
import {
InputPeerLike,
MtArgumentError,
MtMessageNotFoundError,
MtTypeAssertionError,
PeersIndex,
Poll,
} from '../../types'
import { assertTypeIs } from '../../utils/type-assertion'
import { assertIsUpdatesGroup } from '../../utils/updates-utils'
/**

View file

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

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 { MtArgumentError } from '../../types'
import { assertTypeIs } from '../../utils/type-assertion'
/**
* 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 { MtArgumentError } from '../../types'
import { assertTypeIs } from '../../utils/type-assertion'
/**
* Enable 2FA password on your account

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -3,18 +3,15 @@ import Long from 'long'
import {
getBasicPeerType,
getMarkedPeerId,
MtTypeAssertionError,
toggleChannelIdMark,
} from '@mtcute/core'
import { assertTypeIs } from '@mtcute/core/utils'
import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client'
import {
InputPeerLike,
MtPeerNotFoundError,
MtTypeAssertionError,
} from '../../types'
import { InputPeerLike, MtPeerNotFoundError } from '../../types'
import { normalizeToInputPeer } from '../../utils/peer-utils'
import { assertTypeIs } from '../../utils/type-assertion'
/**
* 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 { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client'
import { InputFileLike, MtArgumentError, Photo } from '../../types'
import { InputFileLike, Photo } from '../../types'
/**
* 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 { TelegramClient } from '../../client'
import { encodeInlineMessageId } from '../../utils/inline-utils'
import { MtArgumentError, MtMessageNotFoundError } from '../errors'
import { MtMessageNotFoundError } from '../errors'
import { Message } from '../messages'
import { PeersIndex, User } from '../peers'
import { makeInspectable } from '../utils'

View file

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

View file

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

View file

@ -1,25 +1,16 @@
/**
* Base class for all `@mtcute/client` errors
*/
import { MtcuteError } from '@mtcute/core'
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
*/
export class MtPeerNotFoundError extends MtClientError {}
export class MtPeerNotFoundError extends MtcuteError {}
/**
* Could not find a message by the provided information
*/
export class MtMessageNotFoundError extends MtClientError {
export class MtMessageNotFoundError extends MtcuteError {
constructor(
readonly peerId: 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
* 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
* while providing another chat as `userId`
*/
export class MtInvalidPeerTypeError extends MtClientError {
export class MtInvalidPeerTypeError extends MtcuteError {
constructor(peer: InputPeerLike, expected: string) {
super(
`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
* contain that information.
*/
export class MtEmptyError extends MtClientError {
export class MtEmptyError extends MtcuteError {
constructor() {
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 { TelegramClient } from '../../client'
import { MtArgumentError } from '../errors'
import { makeInspectable } from '../utils'
import { FileLocation } from './file-location'

View file

@ -1,7 +1,7 @@
import { MtArgumentError } from '@mtcute/core'
import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client'
import { MtArgumentError } from '../errors'
import { WebDocument } from '../files/web-document'
import { _messageMediaFromTl, MessageMedia } from '../messages'
import { makeInspectable } from '../utils'
@ -146,7 +146,9 @@ export class Invoice {
get extendedMediaState(): InvoiceExtendedMediaState {
if (!this.raw.extendedMedia) return 'none'
if (this.raw.extendedMedia._ === 'messageExtendedMediaPreview') { return 'preview' }
if (this.raw.extendedMedia._ === 'messageExtendedMediaPreview') {
return 'preview'
}
return 'full'
}
@ -158,7 +160,9 @@ export class Invoice {
* Otherwise, throws an error.
*/
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(
this.client,

View file

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

View file

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

View file

@ -1,5 +1,7 @@
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 { tl } from '@mtcute/tl'
@ -9,8 +11,6 @@ import {
strippedPhotoToJpg,
svgPathToFile,
} from '../../utils/file-utils'
import { assertTypeIs } from '../../utils/type-assertion'
import { MtArgumentError, MtTypeAssertionError } from '../errors'
import { FileLocation } from '../files'
import { makeInspectable } from '../utils'
@ -182,8 +182,12 @@ export class Thumbnail extends FileLocation {
* Thumbnail type
*/
get type(): string {
if (this.raw._ === 'videoSizeEmojiMarkup') { return Thumbnail.THUMB_EMOJI_MARKUP }
if (this.raw._ === 'videoSizeStickerMarkup') { return Thumbnail.THUMB_STICKER_MARKUP }
if (this.raw._ === 'videoSizeEmojiMarkup') {
return Thumbnail.THUMB_EMOJI_MARKUP
}
if (this.raw._ === 'videoSizeStickerMarkup') {
return Thumbnail.THUMB_STICKER_MARKUP
}
return this.raw.type
}

View file

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

View file

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

View file

@ -1,7 +1,7 @@
import { MtTypeAssertionError } from '@mtcute/core'
import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client'
import { MtTypeAssertionError } from '../errors'
import {
Audio,
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 { TelegramClient } from '../../client'
import { BotKeyboard, ReplyMarkup } from '../bots'
import { MtArgumentError, MtTypeAssertionError } from '../errors'
import { InputMediaLike, Sticker, WebPage } from '../media'
import { FormattedString } from '../parser'
import { Chat, InputPeerLike, PeersIndex, User } from '../peers'

View file

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

View file

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

View file

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

View file

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

View file

@ -1,12 +1,11 @@
import Long from 'long'
import { toggleChannelIdMark } from '@mtcute/core'
import { MtArgumentError, toggleChannelIdMark } from '@mtcute/core'
import { tdFileId, toFileId, toUniqueFileId } from '@mtcute/file-id'
import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client'
import { strippedPhotoToJpg } from '../../utils/file-utils'
import { MtArgumentError } from '../errors'
import { FileLocation } from '../files'
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 { TelegramClient } from '../../client'
import { MtArgumentError, MtTypeAssertionError } from '../errors'
import { InputMediaLike } from '../media'
import { FormattedString } from '../parser'
import { makeInspectable } from '../utils'

View file

@ -1,7 +1,6 @@
import { MtArgumentError } from '@mtcute/core'
import { tl } from '@mtcute/tl'
import { MtArgumentError } from '../errors'
const ERROR_MSG =
'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 { TelegramClient } from '../../client'
import { assertTypeIs } from '../../utils/type-assertion'
import { MtArgumentError } from '../errors'
import { InputMediaLike } from '../media'
import { FormattedString } from '../parser'
import { makeInspectable } from '../utils'

View file

@ -1,8 +1,9 @@
import { MtArgumentError } from '@mtcute/core'
import { tl } from '@mtcute/tl'
import { TelegramClient } from '../../client'
import { encodeInlineMessageId } from '../../utils/inline-utils'
import { Location, MtArgumentError, PeersIndex, User } from '../'
import { Location, PeersIndex, User } from '../'
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 { TelegramClient } from '../../client'
import { assertTypeIs } from '../../utils/type-assertion'
import { Chat, MtUnsupportedError, PeersIndex, User } from '../'
import { Chat, PeersIndex, User } from '../'
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 { TelegramClient } from '../../client'
import {
BasicPeerType,
Chat,
MtUnsupportedError,
TypingStatus,
User,
} from '../'
import { BasicPeerType, Chat, TypingStatus, User } from '../'
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)

View file

@ -1,6 +1,7 @@
import { MtArgumentError } from '@mtcute/core'
import { tl } from '@mtcute/tl'
import { MaybeDynamic, Message, MtClientError } from '../types'
import { MaybeDynamic, Message } from '../types'
/**
* Normalize phone number by stripping formatting
@ -8,7 +9,7 @@ import { MaybeDynamic, Message, MtClientError } from '../types'
*/
export function normalizePhoneNumber(phone: string): string {
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
}
@ -25,7 +26,13 @@ export function extractChannelIdFromUpdate(
if ('channelId' in upd) {
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
}

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 { MtTypeAssertionError } from '../types'
// 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

View file

@ -3,6 +3,7 @@ import Long from 'long'
import { tl } from '@mtcute/tl'
import { TlBinaryReader, TlReaderMap } from '@mtcute/tl-runtime'
import { MtcuteError } from '../types'
import { buffersEqual, ICryptoProvider, Logger, randomBytes } from '../utils'
import { createAesIgeForMessage } from '../utils/crypto/mtproto'
@ -41,7 +42,7 @@ export class AuthKey {
serverSalt: Long,
sessionId: Long,
): 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 =
(16 /* header size */ + message.length + 12) /* min padding */ % 16

View file

@ -9,6 +9,11 @@ import {
TlSerializationCounter,
} from '@mtcute/tl-runtime'
import {
MtArgumentError,
MtSecurityError,
MtTypeAssertionError,
} from '../types'
import {
bigIntToBuffer,
bufferToBigInt,
@ -24,6 +29,7 @@ import {
import { findKeyByFingerprints } from '../utils/crypto/keys'
import { millerRabin } from '../utils/crypto/miller-rabin'
import { generateKeyAndIvFromNonce } from '../utils/crypto/mtproto'
import { mtpAssertTypeIs } from '../utils/type-assertions'
import { SessionConnection } from './session-connection'
// 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.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)) {
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))) {
throw new Error(
throw new MtSecurityError(
'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) {
case 2:
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
case 3:
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
case 4:
@ -105,7 +117,7 @@ function checkDhPrime(log: Logger, dhPrime: bigInt.BigInteger, g: number) {
const mod = dhPrime.mod(5)
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',
)
}
@ -115,7 +127,7 @@ function checkDhPrime(log: Logger, dhPrime: bigInt.BigInteger, g: number) {
const mod = dhPrime.mod(24)
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',
)
}
@ -125,14 +137,14 @@ function checkDhPrime(log: Logger, dhPrime: bigInt.BigInteger, g: number) {
const mod = dhPrime.mod(7)
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',
)
}
break
}
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)
@ -151,7 +163,7 @@ async function rsaPad(
const keyExponent = bigInt(key.exponent, 16)
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)])
@ -265,10 +277,10 @@ export async function doAuthorization(
await sendPlainMessage({ _: 'mt_req_pq_multi', nonce })
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)) {
throw new Error('Step 1: invalid nonce from server')
throw new MtSecurityError('Step 1: invalid nonce from server')
}
const serverKeys = resPq.serverPublicKeyFingerprints.map((it) =>
@ -280,7 +292,7 @@ export async function doAuthorization(
const publicKey = findKeyByFingerprints(serverKeys)
if (!publicKey) {
throw new Error(
throw new MtSecurityError(
'Step 2: Could not find server public key with any of these fingerprints: ' +
serverKeys.join(', '),
)
@ -330,19 +342,13 @@ export async function doAuthorization(
})
const serverDhParams = await readNext()
if (!mtp.isAnyServer_DH_Params(serverDhParams)) {
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._)
}
mtpAssertTypeIs('auth step 2', serverDhParams, 'mt_server_DH_params_ok')
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)) {
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
@ -350,14 +356,14 @@ export async function doAuthorization(
// // why would i want to do that? we are gonna fail anyways.
// // let expectedNnh = (await crypto.sha1(newNonce)).slice(4, 20)
// // if (!buffersEqual(serverDhParams.newNonceHash, expectedNnh))
// // throw new Error('Step 2: invalid DH fail nonce from server')
// throw new Error('Step 2: server DH failed')
// // throw new MtSecurityError('Step 2: invalid DH fail nonce from server')
// throw new MtSecurityError('Step 2: server DH failed')
// }
log.debug('server DH ok')
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
@ -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') {
throw Error('Step 3: inner data was ' + serverDhInner._)
}
mtpAssertTypeIs('auth step 3', serverDhInner, 'mt_server_DH_inner_data')
if (!buffersEqual(serverDhInner.nonce, nonce)) {
throw Error('Step 3: invalid nonce from server')
}
@ -424,28 +429,28 @@ export async function doAuthorization(
g.lesserOrEquals(1) ||
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 (
gA.lesserOrEquals(1) ||
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 (
gB.lesserOrEquals(1) ||
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))) {
throw new Error(
throw new MtSecurityError(
'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))) {
throw new Error(
throw new MtSecurityError(
'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()
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)) {
@ -502,7 +511,11 @@ export async function doAuthorization(
if (dhGen._ === 'mt_dh_gen_fail') {
// 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') {

View file

@ -8,6 +8,7 @@ import {
TlWriterMap,
} from '@mtcute/tl-runtime'
import { MtcuteError } from '../types'
import {
ControllablePromise,
Deque,
@ -183,7 +184,7 @@ export class MtprotoSession {
if (!keepPending) {
for (const info of this.pendingMessages.values()) {
if (info._ === 'rpc') {
info.rpc.promise.reject(new Error('Session is reset'))
info.rpc.promise.reject(new MtcuteError('Session is reset'))
}
}
this.pendingMessages.clear()
@ -197,7 +198,7 @@ export class MtprotoSession {
const rpc = this.queuedRpc.popFront()!
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,
callback: Parameters<AuthKey['decryptMessage']>[2],
): 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)

View file

@ -2,12 +2,14 @@ import { tl } from '@mtcute/tl'
import { TlReaderMap, TlWriterMap } from '@mtcute/tl-runtime'
import { ITelegramStorage } from '../storage'
import { MtArgumentError, MtcuteError } from '../types'
import {
createControllablePromise,
ICryptoProvider,
Logger,
sleep,
} from '../utils'
import { assertTypeIs } from '../utils/type-assertions'
import { ConfigManager } from './config-manager'
import { MultiSessionConnection } from './multi-session-connection'
import { PersistentConnectionParams } from './persistent-connection'
@ -500,7 +502,7 @@ export class NetworkManager {
})
if (!main || !media) {
throw new Error(`Could not find DC ${dcId}`)
throw new MtArgumentError(`Could not find DC ${dcId}`)
}
return { main, media }
@ -586,12 +588,12 @@ export class NetworkManager {
*/
async connect(defaultDcs: ITelegramStorage.DcOptions): Promise<void> {
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)) {
// 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)
@ -626,11 +628,7 @@ export class NetworkManager {
{ manager },
)
if (res._ !== 'auth.authorization') {
throw new Error(
`Unexpected response from auth.importAuthorization: ${res._}`,
)
}
assertTypeIs('auth.importAuthorization', res, 'auth.authorization')
promise.resolve()
delete this._pendingExports[manager.dcId]
@ -713,7 +711,7 @@ export class NetworkManager {
stack?: string,
): Promise<tl.RpcCallReturn[T['_']]> {
if (!this._primaryDc) {
throw new Error('Not connected to any DC')
throw new MtcuteError('Not connected to any DC')
}
const floodSleepThreshold =
@ -860,7 +858,7 @@ export class NetworkManager {
if (!dc) {
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,
@ -876,7 +874,7 @@ export class NetworkManager {
}
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
}

View file

@ -2,6 +2,7 @@ import EventEmitter from 'events'
import { tl } from '@mtcute/tl'
import { MtcuteError } from '../types'
import { ICryptoProvider, Logger } from '../utils'
import { ReconnectionStrategy } from './reconnection'
import {
@ -166,9 +167,9 @@ export abstract class PersistentConnection extends EventEmitter {
connect(): void {
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) {
clearTimeout(this._reconnectionTimeout)

View file

@ -12,6 +12,7 @@ import {
} from '@mtcute/tl-runtime'
import { gzipDeflate, gzipInflate } from '@mtcute/tl-runtime/src/platform/gzip'
import { MtArgumentError, MtcuteError, MtTimeoutError } from '../types'
import {
ControllablePromise,
createCancellablePromise,
@ -123,7 +124,7 @@ export class SessionConnection extends PersistentConnection {
Object.values(this._pendingWaitForUnencrypted).forEach(
([prom, timeout]) => {
prom.reject(new Error('Connection closed'))
prom.reject(new MtcuteError('Connection closed'))
clearTimeout(timeout)
},
)
@ -456,7 +457,7 @@ export class SessionConnection extends PersistentConnection {
res.errorCode,
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,
@ -506,7 +507,7 @@ export class SessionConnection extends PersistentConnection {
waitForUnencryptedMessage(timeout = 5000): Promise<Buffer> {
const promise = createControllablePromise<Buffer>()
const timeoutId = setTimeout(() => {
promise.reject(new Error('Timeout'))
promise.reject(new MtTimeoutError(timeout))
this._pendingWaitForUnencrypted =
this._pendingWaitForUnencrypted.filter(
(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
// 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.
throw new Error(`Payload is too big (${content.length} > 1044404)`)
throw new MtArgumentError(
`Payload is too big (${content.length} > 1044404)`,
)
}
// gzip
@ -1533,7 +1536,7 @@ export class SessionConnection extends PersistentConnection {
private _cancelRpc(rpc: PendingRpc, onTimeout = false): void {
if (rpc.cancelled && !onTimeout) {
throw new Error('RPC was already cancelled')
throw new MtcuteError('RPC was already cancelled')
}
if (!onTimeout && rpc.timeout) {

View file

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

View file

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

View file

@ -1,6 +1,7 @@
import type * as exitHookNs from 'exit-hook'
import type * as fsNs from 'fs'
import { MtUnsupportedError } from '../types'
import { JsonMemoryStorage } from './json'
type fs = typeof fsNs
@ -52,7 +53,7 @@ export class JsonFileStorage extends JsonMemoryStorage {
super()
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
@ -60,7 +61,7 @@ export class JsonFileStorage extends JsonMemoryStorage {
this._cleanup = params?.cleanup ?? Boolean(exitHook)
if (this._cleanup && !exitHook) {
throw new Error(
throw new MtUnsupportedError(
'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'
export class LocalstorageStorage extends JsonMemoryStorage {
@ -7,7 +8,7 @@ export class LocalstorageStorage extends JsonMemoryStorage {
super()
if (typeof localStorage === 'undefined') {
throw new Error('localStorage is not available!')
throw new MtUnsupportedError('localStorage is not available!')
}
this._key = key

View file

@ -151,7 +151,9 @@ export class MemoryStorage implements ITelegramStorage, IStateStorage {
(ent: ITelegramStorage.PeerInfo) => {
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,
}
}
throw new Error(`Invalid peer type: ${peerInfo.type}`)
}
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