chore: improved eslint config
closes MTQ-54
This commit is contained in:
parent
e7171e32c7
commit
81ce550604
97 changed files with 778 additions and 541 deletions
14
.eslintrc.js
14
.eslintrc.js
|
@ -176,7 +176,7 @@ module.exports = {
|
|||
files: ['**/*.ts', '**/*.tsx'],
|
||||
env: { browser: true, es6: true, node: true },
|
||||
extends: [
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:@typescript-eslint/strict-type-checked',
|
||||
'plugin:import/typescript',
|
||||
],
|
||||
globals: { Atomics: 'readonly', SharedArrayBuffer: 'readonly' },
|
||||
|
@ -213,6 +213,18 @@ module.exports = {
|
|||
],
|
||||
'@typescript-eslint/no-non-null-assertion': 'off', // todo MTQ-36
|
||||
'@typescript-eslint/no-empty-function': 'off',
|
||||
'@typescript-eslint/no-confusing-void-expression': 'off',
|
||||
'@typescript-eslint/no-unnecessary-condition': 'off',
|
||||
'@typescript-eslint/no-var-requires': 'off',
|
||||
'@typescript-eslint/restrict-template-expressions': [
|
||||
'error',
|
||||
{ allowNever: true },
|
||||
],
|
||||
'@typescript-eslint/no-unsafe-enum-comparison': 'off',
|
||||
'@typescript-eslint/no-invalid-void-type': 'off',
|
||||
'@typescript-eslint/unbound-method': 'off',
|
||||
'@typescript-eslint/no-dynamic-delete': 'off',
|
||||
'@typescript-eslint/no-unsafe-member-access': 'off',
|
||||
},
|
||||
settings: {
|
||||
'import/resolver': {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging, @typescript-eslint/unified-signatures */
|
||||
/* THIS FILE WAS AUTO-GENERATED */
|
||||
import { Readable } from 'stream'
|
||||
|
||||
|
|
|
@ -14,7 +14,8 @@ export async function logOut(this: TelegramClient): Promise<true> {
|
|||
|
||||
this._userId = null
|
||||
this._isBot = false
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
// some implicit magic in favor of performance
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment
|
||||
this._pts = this._seq = this._date = undefined as any
|
||||
this._selfUsername = null
|
||||
this._selfChanged = true
|
||||
|
|
|
@ -97,7 +97,11 @@ export async function answerInlineQuery(
|
|||
): Promise<void> {
|
||||
if (!params) params = {}
|
||||
|
||||
const [gallery, tlResults] = await BotInline._convertToTl(this, results, params!.parseMode)
|
||||
const [gallery, tlResults] = await BotInline._convertToTl(
|
||||
this,
|
||||
results,
|
||||
params.parseMode,
|
||||
)
|
||||
|
||||
await this.call({
|
||||
_: 'messages.setInlineBotResults',
|
||||
|
|
|
@ -53,7 +53,7 @@ export async function getInlineGameHighScores(
|
|||
messageId: string | tl.TypeInputBotInlineMessageID,
|
||||
userId?: InputPeerLike,
|
||||
): Promise<GameHighScore[]> {
|
||||
const id = await normalizeInlineId(messageId)
|
||||
const id = normalizeInlineId(messageId)
|
||||
|
||||
let user: tl.TypeInputUser
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@ export async function setInlineGameScore(
|
|||
|
||||
const user = normalizeToInputUser(await this.resolvePeer(userId), userId)
|
||||
|
||||
const id = await normalizeInlineId(messageId)
|
||||
const id = normalizeInlineId(messageId)
|
||||
|
||||
await this.call(
|
||||
{
|
||||
|
|
|
@ -45,10 +45,7 @@ export async function addChatMembers(
|
|||
const updates = await this.call({
|
||||
_: 'channels.inviteToChannel',
|
||||
channel: normalizeToInputChannel(chat),
|
||||
users: await this.resolvePeerMany(
|
||||
users as InputPeerLike[],
|
||||
normalizeToInputUser,
|
||||
),
|
||||
users: await this.resolvePeerMany(users, normalizeToInputUser),
|
||||
})
|
||||
this._handleUpdate(updates)
|
||||
} else throw new MtInvalidPeerTypeError(chatId, 'chat or channel')
|
||||
|
|
|
@ -24,10 +24,7 @@ export async function createGroup(
|
|||
): Promise<Chat> {
|
||||
if (!Array.isArray(users)) users = [users]
|
||||
|
||||
const peers = await this.resolvePeerMany(
|
||||
users as InputPeerLike[],
|
||||
normalizeToInputUser,
|
||||
)
|
||||
const peers = await this.resolvePeerMany(users, normalizeToInputUser)
|
||||
|
||||
const res = await this.call({
|
||||
_: 'messages.createChat',
|
||||
|
|
|
@ -28,7 +28,7 @@ export function _pushConversationMessage(
|
|||
const chatId = getMarkedPeerId(msg.raw.peerId)
|
||||
const msgId = msg.raw.id
|
||||
|
||||
this._pendingConversations[chatId]?.forEach((conv) => {
|
||||
this._pendingConversations[chatId].forEach((conv) => {
|
||||
conv['_lastMessage'] = msgId
|
||||
if (incoming) conv['_lastReceivedMessage'] = msgId
|
||||
})
|
||||
|
|
|
@ -5,11 +5,10 @@ import {
|
|||
MtUnsupportedError,
|
||||
} from '../../types'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
let fs: any = null
|
||||
let fs: typeof import('fs') | null = null
|
||||
|
||||
try {
|
||||
fs = require('fs')
|
||||
fs = require('fs') as typeof import('fs')
|
||||
} catch (e) {}
|
||||
|
||||
/**
|
||||
|
@ -39,7 +38,7 @@ export function downloadToFile(
|
|||
const buf = params.location.location
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.writeFile(filename, buf, (err?: Error) => {
|
||||
fs!.writeFile(filename, buf, (err) => {
|
||||
if (err) reject(err)
|
||||
else resolve()
|
||||
})
|
||||
|
|
|
@ -47,19 +47,20 @@ export async function* downloadAsIterable(
|
|||
const input = params.location
|
||||
let location: tl.TypeInputFileLocation | tl.TypeInputWebFileLocation
|
||||
if (input instanceof FileLocation) {
|
||||
if (typeof input.location === 'function') {
|
||||
(input as tl.Mutable<FileLocation>).location = input.location()
|
||||
let locationInner = input.location
|
||||
|
||||
if (typeof locationInner === 'function') {
|
||||
locationInner = locationInner()
|
||||
}
|
||||
|
||||
if (Buffer.isBuffer(input.location)) {
|
||||
yield input.location
|
||||
if (Buffer.isBuffer(locationInner)) {
|
||||
yield locationInner
|
||||
|
||||
return
|
||||
}
|
||||
if (!dcId) dcId = input.dcId
|
||||
if (!fileSize) fileSize = input.fileSize
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
location = input.location as any
|
||||
location = locationInner
|
||||
} else if (typeof input === 'string') {
|
||||
const parsed = parseFileId(input)
|
||||
|
||||
|
@ -129,7 +130,7 @@ export async function* downloadAsIterable(
|
|||
result = await this.call(
|
||||
{
|
||||
_: isWeb ? 'upload.getWebFile' : 'upload.getFile',
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
// eslint-disable-next-line
|
||||
location: location as any,
|
||||
offset: chunkSize * chunk,
|
||||
limit: chunkSize,
|
||||
|
@ -182,7 +183,7 @@ export async function* downloadAsIterable(
|
|||
}
|
||||
|
||||
let error: unknown = undefined
|
||||
Promise.all(
|
||||
void Promise.all(
|
||||
Array.from(
|
||||
{ length: Math.min(poolSize * REQUESTS_PER_CONNECTION, numChunks) },
|
||||
downloadChunk,
|
||||
|
@ -202,6 +203,7 @@ export async function* downloadAsIterable(
|
|||
while (position < limitBytes) {
|
||||
await nextChunkCv.wait()
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-throw-literal
|
||||
if (error) throw error
|
||||
|
||||
while (nextChunkIdx in buffer) {
|
||||
|
|
|
@ -26,6 +26,7 @@ export function downloadAsStream(
|
|||
async read() {},
|
||||
})
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
for await (const chunk of this.downloadAsIterable(params)) {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { fromBuffer as fileTypeFromBuffer } from 'file-type'
|
||||
import type { ReadStream } from 'fs'
|
||||
import { Readable } from 'stream'
|
||||
|
@ -15,12 +14,12 @@ import {
|
|||
readBytesFromStream,
|
||||
} from '../../utils/stream-utils'
|
||||
|
||||
let fs: any = null
|
||||
let path: any = null
|
||||
let fs: typeof import('fs') | null = null
|
||||
let path: typeof import('path') | null = null
|
||||
|
||||
try {
|
||||
fs = require('fs')
|
||||
path = require('path')
|
||||
fs = require('fs') as typeof import('fs')
|
||||
path = require('path') as typeof import('path')
|
||||
} catch (e) {}
|
||||
|
||||
const OVERRIDE_MIME: Record<string, string> = {
|
||||
|
@ -132,15 +131,12 @@ export async function uploadFile(
|
|||
}
|
||||
|
||||
if (fs && file instanceof fs.ReadStream) {
|
||||
fileName = path.basename((file as ReadStream).path.toString())
|
||||
fileName = path!.basename(file.path.toString())
|
||||
fileSize = await new Promise((res, rej) => {
|
||||
fs.stat(
|
||||
(file as ReadStream).path.toString(),
|
||||
(err?: any, stat?: any) => {
|
||||
if (err) rej(err)
|
||||
res(stat.size)
|
||||
},
|
||||
)
|
||||
fs!.stat((file as ReadStream).path.toString(), (err, stat) => {
|
||||
if (err) rej(err)
|
||||
res(stat.size)
|
||||
})
|
||||
})
|
||||
// fs.ReadStream is a subclass of Readable, no conversion needed
|
||||
}
|
||||
|
@ -171,7 +167,7 @@ export async function uploadFile(
|
|||
|
||||
if (idx > -1) {
|
||||
const raw = disposition.slice(idx + 9).split(';')[0]
|
||||
fileName = JSON.parse(raw)
|
||||
fileName = JSON.parse(raw) as string
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ export async function uploadMedia(
|
|||
assertTypeIs('uploadMedia', res, 'messageMediaDocument')
|
||||
assertTypeIs('uploadMedia', res.document!, 'document')
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
// eslint-disable-next-line
|
||||
return parseDocument(this, res.document) as any
|
||||
case 'inputMediaStory':
|
||||
throw new MtArgumentError("This media (story) can't be uploaded")
|
||||
|
|
|
@ -76,7 +76,7 @@ export async function editInlineMessage(
|
|||
let entities: tl.TypeMessageEntity[] | undefined
|
||||
let media: tl.TypeInputMedia | undefined = undefined
|
||||
|
||||
const id = await normalizeInlineId(messageId)
|
||||
const id = normalizeInlineId(messageId)
|
||||
|
||||
if (params.media) {
|
||||
media = await this._normalizeInputMedia(params.media, params, true)
|
||||
|
|
|
@ -114,6 +114,6 @@ export async function editMessage(
|
|||
media,
|
||||
})
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
// eslint-disable-next-line
|
||||
return this._findMessageInUpdate(res, true) as any
|
||||
}
|
||||
|
|
|
@ -291,13 +291,18 @@ export async function forwardMessages(
|
|||
},
|
||||
): Promise<MaybeArray<Message>> {
|
||||
if (!params) params = {}
|
||||
const isSingle = !Array.isArray(messages)
|
||||
if (isSingle) messages = [messages as number]
|
||||
|
||||
let isSingle = false
|
||||
|
||||
if (!Array.isArray(messages)) {
|
||||
isSingle = true
|
||||
messages = [messages]
|
||||
}
|
||||
|
||||
// sending more than 100 will not result in a server-sent
|
||||
// error, instead only first 100 IDs will be forwarded,
|
||||
// which is definitely not the best outcome.
|
||||
if ((messages as number[]).length > 100) {
|
||||
if (messages.length > 100) {
|
||||
throw new MtArgumentError(
|
||||
'You can forward no more than 100 messages at once',
|
||||
)
|
||||
|
@ -338,12 +343,10 @@ export async function forwardMessages(
|
|||
_: 'messages.forwardMessages',
|
||||
toPeer,
|
||||
fromPeer: await this.resolvePeer(fromChatId),
|
||||
id: messages as number[],
|
||||
id: messages,
|
||||
silent: params.silent,
|
||||
scheduleDate: normalizeDate(params.schedule),
|
||||
randomId: [...Array((messages as number[]).length)].map(() =>
|
||||
randomLong(),
|
||||
),
|
||||
randomId: Array.from({ length: messages.length }, () => randomLong()),
|
||||
dropAuthor: params.noAuthor,
|
||||
dropMediaCaptions: params.noCaption,
|
||||
noforwards: params.forbidForwards,
|
||||
|
|
|
@ -56,7 +56,7 @@ export async function addStickerToSet(
|
|||
maskCoords: sticker.maskPosition ?
|
||||
{
|
||||
_: 'maskCoords',
|
||||
n: MASK_POS[sticker.maskPosition.point as keyof typeof MASK_POS],
|
||||
n: MASK_POS[sticker.maskPosition.point],
|
||||
x: sticker.maskPosition.x,
|
||||
y: sticker.maskPosition.y,
|
||||
zoom: sticker.maskPosition.scale,
|
||||
|
|
|
@ -106,7 +106,10 @@ export async function createStickerSet(
|
|||
)
|
||||
}
|
||||
|
||||
const owner = normalizeToInputUser(await this.resolvePeer(params.owner), params.owner)
|
||||
const owner = normalizeToInputUser(
|
||||
await this.resolvePeer(params.owner),
|
||||
params.owner,
|
||||
)
|
||||
|
||||
const inputStickers: tl.TypeInputStickerSetItem[] = []
|
||||
|
||||
|
@ -124,7 +127,7 @@ export async function createStickerSet(
|
|||
maskCoords: sticker.maskPosition ?
|
||||
{
|
||||
_: 'maskCoords',
|
||||
n: MASK_POS[sticker.maskPosition.point as keyof typeof MASK_POS],
|
||||
n: MASK_POS[sticker.maskPosition.point],
|
||||
x: sticker.maskPosition.x,
|
||||
y: sticker.maskPosition.y,
|
||||
zoom: sticker.maskPosition.scale,
|
||||
|
|
|
@ -33,6 +33,6 @@ export async function getCustomEmojis(
|
|||
)
|
||||
}
|
||||
|
||||
return doc as Sticker
|
||||
return doc
|
||||
})
|
||||
}
|
||||
|
|
|
@ -940,7 +940,7 @@ function _fetchChannelDifferenceLater(
|
|||
fallbackPts?: number,
|
||||
force = false,
|
||||
): void {
|
||||
if (!requestedDiff[channelId]) {
|
||||
if (!(channelId in requestedDiff)) {
|
||||
requestedDiff[channelId] = _fetchChannelDifference
|
||||
.call(this, channelId, fallbackPts, force)
|
||||
.catch((err) => {
|
||||
|
@ -1074,7 +1074,7 @@ function _fetchDifferenceLater(
|
|||
this: TelegramClient,
|
||||
requestedDiff: Record<number, Promise<void>>,
|
||||
): void {
|
||||
if (!requestedDiff[0]) {
|
||||
if (!(0 in requestedDiff)) {
|
||||
requestedDiff[0] = _fetchDifference
|
||||
.call(this, requestedDiff)
|
||||
.catch((err) => {
|
||||
|
|
|
@ -8,7 +8,11 @@ import {
|
|||
import { tl } from '@mtcute/tl'
|
||||
|
||||
import { TelegramClient } from '../../client'
|
||||
import { InputPeerLike, MtNotFoundError, MtTypeAssertionError } from '../../types'
|
||||
import {
|
||||
InputPeerLike,
|
||||
MtNotFoundError,
|
||||
MtTypeAssertionError,
|
||||
} from '../../types'
|
||||
import { normalizeToInputPeer } from '../../utils/peer-utils'
|
||||
import { assertTypeIs } from '../../utils/type-assertion'
|
||||
|
||||
|
@ -109,7 +113,12 @@ export async function resolvePeer(
|
|||
const found = res.chats.find((it) => it.id === id)
|
||||
|
||||
if (found) {
|
||||
if (!(found._ === 'channel' || found._ === 'channelForbidden')) {
|
||||
if (
|
||||
!(
|
||||
found._ === 'channel' ||
|
||||
found._ === 'channelForbidden'
|
||||
)
|
||||
) {
|
||||
// chats can't have usernames
|
||||
// furthermore, our id is a channel id, so it must be a channel
|
||||
// this should never happen, unless Telegram goes crazy
|
||||
|
@ -205,7 +214,7 @@ export async function resolvePeer(
|
|||
// break
|
||||
}
|
||||
case 'channel': {
|
||||
const id = toggleChannelIdMark(peerId as number)
|
||||
const id = toggleChannelIdMark(peerId)
|
||||
|
||||
const res = await this.call({
|
||||
_: 'channels.getChannels',
|
||||
|
|
|
@ -251,6 +251,7 @@ export class Conversation {
|
|||
|
||||
this.stop()
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-throw-literal
|
||||
if (err) throw err
|
||||
|
||||
return res!
|
||||
|
@ -501,7 +502,7 @@ export class Conversation {
|
|||
const it = this._queuedNewMessage.peekFront()!
|
||||
|
||||
// order does matter for new messages
|
||||
this._lock.acquire().then(async () => {
|
||||
void this._lock.acquire().then(async () => {
|
||||
try {
|
||||
if (!it.check || (await it.check(msg))) {
|
||||
if (it.timeout) clearTimeout(it.timeout)
|
||||
|
|
|
@ -140,7 +140,7 @@ export class Sticker extends RawDocument {
|
|||
*/
|
||||
get customEmojiFree(): boolean {
|
||||
return this.attr._ === 'documentAttributeCustomEmoji' ?
|
||||
this.attr?.free ?? false :
|
||||
this.attr.free ?? false :
|
||||
false
|
||||
}
|
||||
|
||||
|
|
|
@ -329,7 +329,7 @@ export class Message {
|
|||
get replyToMessageId(): number | null {
|
||||
if (this.raw.replyTo?._ !== 'messageReplyHeader') return null
|
||||
|
||||
return this.raw.replyTo?.replyToMsgId ?? null
|
||||
return this.raw.replyTo.replyToMsgId ?? null
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -339,7 +339,7 @@ export class Message {
|
|||
get replyToThreadId(): number | null {
|
||||
if (this.raw.replyTo?._ !== 'messageReplyHeader') return null
|
||||
|
||||
return this.raw.replyTo?.replyToTopId ?? null
|
||||
return this.raw.replyTo.replyToTopId ?? null
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -239,7 +239,7 @@ export class StickerSet {
|
|||
*/
|
||||
getStickersByEmoji(emoji: string): StickerInfo[] {
|
||||
return this.stickers.filter(
|
||||
(it) => it.alt === emoji || it.emoji.indexOf(emoji) !== -1,
|
||||
(it) => it.alt === emoji || it.emoji.includes(emoji),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -271,8 +271,8 @@ export class StickerSet {
|
|||
private _getInputDocument(idx: number): tl.TypeInputDocument {
|
||||
if (!this.full) throw new MtEmptyError()
|
||||
|
||||
if (idx < 0) idx = this.full!.documents.length + idx
|
||||
const doc = this.full!.documents[idx] as tl.RawDocument
|
||||
if (idx < 0) idx = this.full.documents.length + idx
|
||||
const doc = this.full.documents[idx] as tl.RawDocument
|
||||
|
||||
if (!doc) {
|
||||
throw new RangeError(`Sticker set does not have sticker ${idx}`)
|
||||
|
|
|
@ -33,6 +33,7 @@ export class TakeoutSession {
|
|||
message: MustEqual<T, tl.RpcMethod>,
|
||||
params?: RpcCallOptions,
|
||||
): Promise<tl.RpcCallReturn[T['_']]> {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return this.client.call(
|
||||
{
|
||||
_: 'invokeWithTakeout',
|
||||
|
@ -76,6 +77,7 @@ export class TakeoutSession {
|
|||
get(target, prop, receiver) {
|
||||
if (prop === 'call') return boundCall
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return Reflect.get(target, prop, receiver)
|
||||
},
|
||||
})
|
||||
|
|
|
@ -98,6 +98,7 @@ export class ChatPhotoSize extends FileLocation {
|
|||
{
|
||||
_: 'photo',
|
||||
id: this.obj.photoId,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
source: {
|
||||
_: 'dialogPhoto',
|
||||
big: this.big,
|
||||
|
|
|
@ -120,7 +120,7 @@ export class Chat {
|
|||
}
|
||||
}
|
||||
|
||||
return this._inputPeer!
|
||||
return this._inputPeer
|
||||
}
|
||||
|
||||
private _chatType?: ChatType
|
||||
|
@ -148,7 +148,7 @@ export class Chat {
|
|||
}
|
||||
}
|
||||
|
||||
return this._chatType!
|
||||
return this._chatType
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -594,7 +594,7 @@ export class Chat {
|
|||
return new FormattedString(
|
||||
this.client.getParseMode(parseMode).unparse(text, [
|
||||
{
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
// eslint-disable-next-line
|
||||
raw: undefined as any,
|
||||
type: 'text_link',
|
||||
offset: 0,
|
||||
|
@ -602,7 +602,7 @@ export class Chat {
|
|||
url: `https://t.me/${this.username}`,
|
||||
},
|
||||
]),
|
||||
parseMode!,
|
||||
parseMode,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@ const ERROR_MSG =
|
|||
'Given peer is not available in this index. This is most likely an internal library error.'
|
||||
|
||||
export class PeersIndex {
|
||||
readonly users: Record<number, tl.TypeUser> = Object.create(null)
|
||||
readonly chats: Record<number, tl.TypeChat> = Object.create(null)
|
||||
readonly users: Record<number, tl.TypeUser> = {}
|
||||
readonly chats: Record<number, tl.TypeChat> = {}
|
||||
|
||||
hasMin = false
|
||||
|
||||
|
|
|
@ -324,7 +324,7 @@ export class User {
|
|||
return new FormattedString(
|
||||
this.client.getParseMode(parseMode).unparse(text, [
|
||||
{
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
// eslint-disable-next-line
|
||||
raw: undefined as any,
|
||||
type: 'text_mention',
|
||||
offset: 0,
|
||||
|
@ -332,7 +332,7 @@ export class User {
|
|||
userId: this.raw.id,
|
||||
},
|
||||
]),
|
||||
parseMode!,
|
||||
parseMode,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -383,7 +383,7 @@ export class User {
|
|||
return new FormattedString(
|
||||
this.client.getParseMode(parseMode).unparse(text, [
|
||||
{
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
// eslint-disable-next-line
|
||||
raw: undefined as any,
|
||||
type: 'text_link',
|
||||
offset: 0,
|
||||
|
@ -393,7 +393,7 @@ export class User {
|
|||
}&hash=${this.raw.accessHash.toString(16)}`,
|
||||
},
|
||||
]),
|
||||
parseMode!,
|
||||
parseMode,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
// ^^ will be looked into in MTQ-35
|
||||
|
||||
import { getMarkedPeerId } from '@mtcute/core'
|
||||
import { tl } from '@mtcute/tl'
|
||||
|
||||
import { TelegramClient } from '../../client'
|
||||
|
@ -37,6 +37,26 @@ export type ChatMemberUpdateType =
|
|||
| 'new_owner'
|
||||
| 'other'
|
||||
|
||||
function extractPeerId(
|
||||
raw?: tl.TypeChatParticipant | tl.TypeChannelParticipant,
|
||||
) {
|
||||
if (!raw) return 0
|
||||
|
||||
if (tl.isAnyChatParticipant(raw)) {
|
||||
return raw.userId
|
||||
}
|
||||
|
||||
switch (raw._) {
|
||||
case 'channelParticipant':
|
||||
case 'channelParticipantSelf':
|
||||
case 'channelParticipantCreator':
|
||||
case 'channelParticipantAdmin':
|
||||
return raw.userId
|
||||
default:
|
||||
return getMarkedPeerId(raw.peer)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update representing a change in the status
|
||||
* of a chat/channel member.
|
||||
|
@ -82,12 +102,8 @@ export class ChatMemberUpdate {
|
|||
const old = this.raw.prevParticipant
|
||||
const cur = this.raw.newParticipant
|
||||
|
||||
const oldId =
|
||||
(old && ((old as any).userId || (old as any).peer.userId)) ||
|
||||
null
|
||||
const curId =
|
||||
(cur && ((cur as any).userId || (cur as any).peer.userId)) ||
|
||||
null
|
||||
const oldId = extractPeerId(old)
|
||||
const curId = extractPeerId(cur)
|
||||
|
||||
const actorId = this.raw.actorId
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-argument */
|
||||
import { tl } from '@mtcute/tl'
|
||||
|
||||
import { TelegramClient } from '../../client'
|
||||
|
@ -19,13 +19,14 @@ import {
|
|||
PollVoteUpdate,
|
||||
PreCheckoutQuery,
|
||||
UserStatusUpdate,
|
||||
UserTypingUpdate } from '../index'
|
||||
UserTypingUpdate,
|
||||
} from '../index'
|
||||
|
||||
type ParserFunction = (
|
||||
client: TelegramClient,
|
||||
upd: tl.TypeUpdate | tl.TypeMessage,
|
||||
peers: PeersIndex
|
||||
) => any
|
||||
) => ParsedUpdate['data']
|
||||
type UpdateParser = [ParsedUpdate['name'], ParserFunction]
|
||||
|
||||
const baseMessageParser: ParserFunction = (
|
||||
|
@ -35,7 +36,9 @@ const baseMessageParser: ParserFunction = (
|
|||
) =>
|
||||
new Message(
|
||||
client,
|
||||
tl.isAnyMessage(upd) ? upd : (upd as any).message,
|
||||
tl.isAnyMessage(upd) ?
|
||||
upd :
|
||||
(upd as { message: tl.TypeMessage }).message,
|
||||
peers,
|
||||
upd._ === 'updateNewScheduledMessage',
|
||||
)
|
||||
|
@ -142,7 +145,7 @@ export function _parseUpdate(
|
|||
return {
|
||||
name: pair[0],
|
||||
data: pair[1](client, update, peers),
|
||||
}
|
||||
} as ParsedUpdate
|
||||
}
|
||||
|
||||
return null
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-argument */
|
||||
import { MaybeAsync } from '@mtcute/core'
|
||||
|
||||
export type MaybeDynamic<T> = MaybeAsync<T> | (() => MaybeAsync<T>)
|
||||
|
||||
export type ArrayWithTotal<T> = T[] & { total: number }
|
||||
|
||||
let util: any | null = null
|
||||
let util: typeof import('util') | null = null
|
||||
|
||||
try {
|
||||
util = require('util')
|
||||
util = require('util') as typeof import('util')
|
||||
} catch (e) {}
|
||||
|
||||
// get all property names. unlike Object.getOwnPropertyNames,
|
||||
|
@ -21,7 +22,7 @@ function getAllGettersNames(obj: object): string[] {
|
|||
if (
|
||||
prop !== '__proto__' &&
|
||||
Object.getOwnPropertyDescriptor(obj, prop)?.get &&
|
||||
getters.indexOf(prop) === -1
|
||||
!getters.includes(prop)
|
||||
) {
|
||||
getters.push(prop)
|
||||
}
|
||||
|
@ -53,10 +54,11 @@ export function makeInspectable(
|
|||
const getters: string[] = props ? props : []
|
||||
|
||||
for (const key of getAllGettersNames(obj.prototype)) {
|
||||
if (!hide || hide.indexOf(key) === -1) getters.push(key)
|
||||
if (!hide || !hide.includes(key)) getters.push(key)
|
||||
}
|
||||
|
||||
// dirty hack to set name for inspect result
|
||||
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
||||
const proto = new Function(`return function ${obj.name}(){}`)().prototype
|
||||
|
||||
obj.prototype.toJSON = function (nested = false) {
|
||||
|
@ -86,6 +88,7 @@ export function makeInspectable(
|
|||
Buffer.prototype.toJSON = bufferToJsonOriginal
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return ret
|
||||
}
|
||||
if (util) {
|
||||
|
|
|
@ -21,27 +21,30 @@ class NodeReadable extends Readable {
|
|||
this._reading = true
|
||||
|
||||
const doRead = () => {
|
||||
this._reader.read().then((res) => {
|
||||
if (this._doneReading) {
|
||||
this._reader
|
||||
.read()
|
||||
.then((res) => {
|
||||
if (this._doneReading) {
|
||||
this._reading = false
|
||||
this._reader.releaseLock()
|
||||
this._doneReading()
|
||||
}
|
||||
if (res.done) {
|
||||
this.push(null)
|
||||
this._reading = false
|
||||
this._reader.releaseLock()
|
||||
|
||||
return
|
||||
}
|
||||
if (this.push(res.value)) {
|
||||
doRead()
|
||||
|
||||
return
|
||||
}
|
||||
this._reading = false
|
||||
this._reader.releaseLock()
|
||||
this._doneReading()
|
||||
}
|
||||
if (res.done) {
|
||||
this.push(null)
|
||||
this._reading = false
|
||||
this._reader.releaseLock()
|
||||
|
||||
return
|
||||
}
|
||||
if (this.push(res.value)) {
|
||||
doRead()
|
||||
|
||||
return
|
||||
}
|
||||
this._reading = false
|
||||
this._reader.releaseLock()
|
||||
})
|
||||
})
|
||||
.catch((err) => this.emit('error', err))
|
||||
}
|
||||
doRead()
|
||||
}
|
||||
|
@ -51,9 +54,11 @@ class NodeReadable extends Readable {
|
|||
const promise = new Promise<void>((resolve) => {
|
||||
this._doneReading = resolve
|
||||
})
|
||||
promise.then(() => {
|
||||
this._handleDestroy(err, callback)
|
||||
})
|
||||
promise
|
||||
.then(() => {
|
||||
this._handleDestroy(err, callback)
|
||||
})
|
||||
.catch((err) => this.emit('error', err))
|
||||
} else {
|
||||
this._handleDestroy(err, callback)
|
||||
}
|
||||
|
@ -63,8 +68,10 @@ class NodeReadable extends Readable {
|
|||
err: Error | null,
|
||||
callback: (error?: Error | null) => void,
|
||||
) {
|
||||
this._webStream.cancel()
|
||||
super._destroy(err, callback)
|
||||
this._webStream
|
||||
.cancel()
|
||||
.then(() => super._destroy(err, callback))
|
||||
.catch((err: Error) => callback(err))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,12 +97,12 @@ export async function readBytesFromStream(
|
|||
): Promise<Buffer | null> {
|
||||
if (stream.readableEnded) return null
|
||||
|
||||
let res = stream.read(size)
|
||||
let res = stream.read(size) as Buffer
|
||||
|
||||
if (!res) {
|
||||
return new Promise((resolve, reject) => {
|
||||
stream.on('readable', function handler() {
|
||||
res = stream.read(size)
|
||||
res = stream.read(size) as Buffer
|
||||
|
||||
if (res) {
|
||||
stream.off('readable', handler)
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"outDir": "./dist",
|
||||
},
|
||||
"include": [
|
||||
"./src"
|
||||
"./src",
|
||||
"./tests"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -18,17 +18,18 @@
|
|||
"./storage/json-file.js": false
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": "18.16.0",
|
||||
"@types/events": "3.0.0",
|
||||
"@mtcute/tl": "workspace:^160.0.0",
|
||||
"@mtcute/tl-runtime": "workspace:^1.0.0",
|
||||
"@types/events": "3.0.0",
|
||||
"@types/node": "18.16.0",
|
||||
"big-integer": "1.6.51",
|
||||
"long": "5.2.3",
|
||||
"events": "3.2.0"
|
||||
"events": "3.2.0",
|
||||
"long": "5.2.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@mtcute/dispatcher": "workspace:^1.0.0",
|
||||
"@types/ws": "8.5.4",
|
||||
"exit-hook": "^4.0.0",
|
||||
"ws": "8.13.0"
|
||||
}
|
||||
}
|
|
@ -388,7 +388,7 @@ export class BaseTelegramClient extends EventEmitter {
|
|||
promise.resolve()
|
||||
this._connected = true
|
||||
})
|
||||
.catch((err) => this._emitError(err))
|
||||
.catch((err: Error) => this._emitError(err))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -401,7 +401,7 @@ export class BaseTelegramClient extends EventEmitter {
|
|||
* Close all connections and finalize the client.
|
||||
*/
|
||||
async close(): Promise<void> {
|
||||
await this._onClose()
|
||||
this._onClose()
|
||||
|
||||
this._config.destroy()
|
||||
this.network.destroy()
|
||||
|
@ -436,6 +436,7 @@ export class BaseTelegramClient extends EventEmitter {
|
|||
const res = await this.network.call(message, params, stack)
|
||||
await this._cachePeersFrom(res)
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return res
|
||||
}
|
||||
|
||||
|
@ -487,7 +488,7 @@ export class BaseTelegramClient extends EventEmitter {
|
|||
let hadMin = false
|
||||
let count = 0
|
||||
|
||||
for (const peer of getAllPeersFrom(obj as any)) {
|
||||
for (const peer of getAllPeersFrom(obj as tl.TlObject)) {
|
||||
if ((peer as any).min) {
|
||||
// absolutely incredible min peer handling, courtesy of levlam.
|
||||
// see this thread: https://t.me/tdlibchat/15084
|
||||
|
|
|
@ -178,6 +178,7 @@ async function rsaPad(
|
|||
const decryptedDataBigint = bufferToBigInt(decryptedData)
|
||||
|
||||
if (decryptedDataBigint.geq(keyModulus)) {
|
||||
console.log('retrying because decrypted data is too big')
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -224,6 +225,7 @@ export async function doAuthorization(
|
|||
const session = connection['_session']
|
||||
const readerMap = session._readerMap
|
||||
const writerMap = session._writerMap
|
||||
const log = connection.log.create('auth')
|
||||
|
||||
function sendPlainMessage(message: mtp.TlObject): Promise<void> {
|
||||
const length = TlSerializationCounter.countNeededBytes(
|
||||
|
@ -234,6 +236,7 @@ export async function doAuthorization(
|
|||
|
||||
const messageId = session.getMessageId()
|
||||
|
||||
log.verbose('[PLAIN] >>> %j', message)
|
||||
writer.long(Long.ZERO)
|
||||
writer.long(messageId)
|
||||
writer.uint(length)
|
||||
|
@ -243,14 +246,17 @@ export async function doAuthorization(
|
|||
}
|
||||
|
||||
async function readNext(): Promise<mtp.TlObject> {
|
||||
return TlBinaryReader.deserializeObject(
|
||||
const res = TlBinaryReader.deserializeObject<mtp.TlObject>(
|
||||
readerMap,
|
||||
await connection.waitForUnencryptedMessage(),
|
||||
20, // skip mtproto header
|
||||
)
|
||||
|
||||
log.verbose('[PLAIN] <<< %j', res)
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
const log = connection.log.create('auth')
|
||||
if (expiresIn) log.prefix = '[PFS] '
|
||||
|
||||
const nonce = randomBytes(16)
|
||||
|
@ -508,8 +514,7 @@ export async function doAuthorization(
|
|||
if (!buffersEqual(expectedHash.slice(4, 20), dhGen.newNonceHash2)) {
|
||||
throw Error('Step 4: invalid retry nonce hash from server')
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
retryId = Long.fromBytesLE(authKeyAuxHash as any)
|
||||
retryId = Long.fromBytesLE(authKeyAuxHash as unknown as number[])
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ export class ConfigManager {
|
|||
|
||||
if (this._updateTimeout) clearTimeout(this._updateTimeout)
|
||||
this._updateTimeout = setTimeout(
|
||||
() => this.update(),
|
||||
() => void this.update().catch(() => {}),
|
||||
(config.expires - Date.now() / 1000) * 1000,
|
||||
)
|
||||
|
||||
|
|
|
@ -250,7 +250,7 @@ export class DcConnectionManager {
|
|||
private _setupMulti(kind: ConnectionKind): void {
|
||||
const connection = this[kind]
|
||||
|
||||
connection.on('key-change', (idx, key) => {
|
||||
connection.on('key-change', (idx, key: Buffer | null) => {
|
||||
if (kind !== 'main') {
|
||||
// main connection is responsible for authorization,
|
||||
// and keys are then sent to other connections
|
||||
|
@ -266,51 +266,58 @@ export class DcConnectionManager {
|
|||
this.dcId,
|
||||
idx,
|
||||
)
|
||||
this.manager._storage.setAuthKeyFor(this.dcId, key)
|
||||
|
||||
// send key to other connections
|
||||
Promise.all([
|
||||
this.manager._storage.setAuthKeyFor(this.dcId, key),
|
||||
this.upload.setAuthKey(key),
|
||||
this.download.setAuthKey(key),
|
||||
this.downloadSmall.setAuthKey(key),
|
||||
]).then(() => {
|
||||
this.upload.notifyKeyChange()
|
||||
this.download.notifyKeyChange()
|
||||
this.downloadSmall.notifyKeyChange()
|
||||
})
|
||||
])
|
||||
.then(() => {
|
||||
this.upload.notifyKeyChange()
|
||||
this.download.notifyKeyChange()
|
||||
this.downloadSmall.notifyKeyChange()
|
||||
})
|
||||
.catch((e: Error) => this.manager.params._emitError(e))
|
||||
})
|
||||
connection.on('tmp-key-change', (idx, key, expires) => {
|
||||
if (kind !== 'main') {
|
||||
this.manager._log.warn(
|
||||
'got tmp-key-change from non-main connection, ignoring',
|
||||
connection.on(
|
||||
'tmp-key-change',
|
||||
(idx: number, key: Buffer | null, expires: number) => {
|
||||
if (kind !== 'main') {
|
||||
this.manager._log.warn(
|
||||
'got tmp-key-change from non-main connection, ignoring',
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
this.manager._log.debug(
|
||||
'temp key change for dc %d from connection %d',
|
||||
this.dcId,
|
||||
idx,
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
this.manager._log.debug(
|
||||
'temp key change for dc %d from connection %d',
|
||||
this.dcId,
|
||||
idx,
|
||||
)
|
||||
this.manager._storage.setTempAuthKeyFor(
|
||||
this.dcId,
|
||||
idx,
|
||||
key,
|
||||
expires * 1000,
|
||||
)
|
||||
|
||||
// send key to other connections
|
||||
Promise.all([
|
||||
this.upload.setAuthKey(key, true),
|
||||
this.download.setAuthKey(key, true),
|
||||
this.downloadSmall.setAuthKey(key, true),
|
||||
]).then(() => {
|
||||
this.upload.notifyKeyChange()
|
||||
this.download.notifyKeyChange()
|
||||
this.downloadSmall.notifyKeyChange()
|
||||
})
|
||||
})
|
||||
// send key to other connections
|
||||
Promise.all([
|
||||
this.manager._storage.setTempAuthKeyFor(
|
||||
this.dcId,
|
||||
idx,
|
||||
key,
|
||||
expires * 1000,
|
||||
),
|
||||
this.upload.setAuthKey(key, true),
|
||||
this.download.setAuthKey(key, true),
|
||||
this.downloadSmall.setAuthKey(key, true),
|
||||
])
|
||||
.then(() => {
|
||||
this.upload.notifyKeyChange()
|
||||
this.download.notifyKeyChange()
|
||||
this.downloadSmall.notifyKeyChange()
|
||||
})
|
||||
.catch((e: Error) => this.manager.params._emitError(e))
|
||||
},
|
||||
)
|
||||
|
||||
connection.on('auth-begin', () => {
|
||||
// we need to propagate auth-begin to all connections
|
||||
|
@ -334,7 +341,7 @@ export class DcConnectionManager {
|
|||
this.main.requestAuth()
|
||||
})
|
||||
|
||||
connection.on('error', (err, conn) => {
|
||||
connection.on('error', (err: Error, conn: SessionConnection) => {
|
||||
this.manager.params._emitError(err, conn)
|
||||
})
|
||||
}
|
||||
|
@ -429,19 +436,21 @@ export class NetworkManager {
|
|||
let deviceModel = 'mtcute on '
|
||||
let appVersion = 'unknown'
|
||||
if (typeof process !== 'undefined' && typeof require !== 'undefined') {
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const os = require('os')
|
||||
const os = require('os') as typeof import('os')
|
||||
deviceModel += `${os.type()} ${os.arch()} ${os.release()}`
|
||||
|
||||
try {
|
||||
// for production builds
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
appVersion = require('../package.json').version
|
||||
|
||||
appVersion = (require('../package.json') as { version: string })
|
||||
.version
|
||||
} catch (e) {
|
||||
try {
|
||||
// for development builds (additional /src/ in path)
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
appVersion = require('../../package.json').version
|
||||
|
||||
appVersion = (
|
||||
require('../../package.json') as { version: string }
|
||||
).version
|
||||
} catch (e) {}
|
||||
}
|
||||
} else if (typeof navigator !== 'undefined') {
|
||||
|
@ -458,7 +467,7 @@ export class NetworkManager {
|
|||
langCode: 'en',
|
||||
...(params.initConnectionOptions ?? {}),
|
||||
apiId: params.apiId,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
// eslint-disable-next-line
|
||||
query: null as any,
|
||||
}
|
||||
|
||||
|
@ -484,7 +493,7 @@ export class NetworkManager {
|
|||
this._lastUpdateTime = Date.now()
|
||||
|
||||
if (this._keepAliveInterval) clearInterval(this._keepAliveInterval)
|
||||
this._keepAliveInterval = setInterval(async () => {
|
||||
this._keepAliveInterval = setInterval(() => {
|
||||
if (Date.now() - this._lastUpdateTime > 900_000) {
|
||||
// telegram asks to fetch pending updates if there are no updates for 15 minutes.
|
||||
// it is up to the user to decide whether to do it or not
|
||||
|
@ -494,27 +503,21 @@ export class NetworkManager {
|
|||
}
|
||||
}, 60_000)
|
||||
|
||||
Promise.resolve(this._storage.getSelf()).then((self) => {
|
||||
if (self?.isBot) {
|
||||
// bots may receive tmpSessions, which we should respect
|
||||
this.config.update(true).catch((e) => {
|
||||
this.params._emitError(e)
|
||||
})
|
||||
}
|
||||
})
|
||||
Promise.resolve(this._storage.getSelf())
|
||||
.then((self) => {
|
||||
if (self?.isBot) {
|
||||
// bots may receive tmpSessions, which we should respect
|
||||
return this.config.update(true)
|
||||
}
|
||||
})
|
||||
.catch((e: Error) => this.params._emitError(e))
|
||||
})
|
||||
dc.main.on('update', (update) => {
|
||||
dc.main.on('update', (update: tl.TypeUpdates) => {
|
||||
this._lastUpdateTime = Date.now()
|
||||
this._updateHandler(update)
|
||||
})
|
||||
|
||||
dc.loadKeys()
|
||||
.catch((e) => {
|
||||
this.params._emitError(e)
|
||||
})
|
||||
.then(() => {
|
||||
dc.main.ensureConnected()
|
||||
})
|
||||
return dc.loadKeys().then(() => dc.main.ensureConnected())
|
||||
}
|
||||
|
||||
private _dcCreationPromise: Record<number, Promise<void>> = {}
|
||||
|
@ -574,7 +577,7 @@ export class NetworkManager {
|
|||
|
||||
const dc = new DcConnectionManager(this, defaultDc.id, defaultDc)
|
||||
this._dcConnections[defaultDc.id] = dc
|
||||
this._switchPrimaryDc(dc)
|
||||
await this._switchPrimaryDc(dc)
|
||||
}
|
||||
|
||||
private async _exportAuthTo(manager: DcConnectionManager): Promise<void> {
|
||||
|
@ -681,9 +684,9 @@ export class NetworkManager {
|
|||
)
|
||||
}
|
||||
|
||||
this._storage.setDefaultDc(option)
|
||||
await this._storage.setDefaultDc(option)
|
||||
|
||||
this._switchPrimaryDc(this._dcConnections[newDc])
|
||||
await this._switchPrimaryDc(this._dcConnections[newDc])
|
||||
}
|
||||
|
||||
private _floodWaitedRequests: Record<string, number> = {}
|
||||
|
@ -738,10 +741,11 @@ export class NetworkManager {
|
|||
this._lastUpdateTime = Date.now()
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return res
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (e: any) {
|
||||
lastError = e
|
||||
lastError = e as Error
|
||||
|
||||
if (e.code && !(e.code in CLIENT_ERRORS)) {
|
||||
this._log.warn(
|
||||
|
@ -811,7 +815,7 @@ export class NetworkManager {
|
|||
}
|
||||
}
|
||||
|
||||
throw lastError
|
||||
throw lastError!
|
||||
}
|
||||
|
||||
setUpdateHandler(handler: NetworkManager['_updateHandler']): void {
|
||||
|
|
|
@ -115,7 +115,7 @@ export class SessionConnection extends PersistentConnection {
|
|||
this._isPfsBindingPending = false
|
||||
this._isPfsBindingPendingInBackground = false
|
||||
this._session._authKeyTemp.reset()
|
||||
clearTimeout(this._pfsUpdateTimeout!)
|
||||
clearTimeout(this._pfsUpdateTimeout)
|
||||
}
|
||||
|
||||
this._resetSession()
|
||||
|
@ -296,7 +296,7 @@ export class SessionConnection extends PersistentConnection {
|
|||
}
|
||||
this.onConnectionUsable()
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch((err: Error) => {
|
||||
this._session.authorizationPending = false
|
||||
this.log.error('Authorization error: %s', err.message)
|
||||
this.onError(err)
|
||||
|
@ -338,7 +338,7 @@ export class SessionConnection extends PersistentConnection {
|
|||
return
|
||||
}
|
||||
|
||||
const tempKey = await this._session._authKeyTempSecondary
|
||||
const tempKey = this._session._authKeyTempSecondary
|
||||
await tempKey.setup(tempAuthKey)
|
||||
|
||||
const msgId = this._session.getMessageId()
|
||||
|
@ -490,7 +490,7 @@ export class SessionConnection extends PersistentConnection {
|
|||
this._authorizePfs(true)
|
||||
}, (TEMP_AUTH_KEY_EXPIRY - 60) * 1000)
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch((err: Error) => {
|
||||
this.log.error('PFS Authorization error: %s', err.message)
|
||||
|
||||
if (this._isPfsBindingPendingInBackground) {
|
||||
|
@ -699,6 +699,8 @@ export class SessionConnection extends PersistentConnection {
|
|||
this._rescheduleInactivity()
|
||||
}
|
||||
|
||||
this.log.verbose('<<< %j', message)
|
||||
|
||||
if (this.params.disableUpdates) {
|
||||
this.log.warn(
|
||||
'received updates, but updates are disabled',
|
||||
|
@ -727,6 +729,7 @@ export class SessionConnection extends PersistentConnection {
|
|||
let resultType
|
||||
|
||||
try {
|
||||
// eslint-disable-next-line
|
||||
resultType = (message.object() as any)._
|
||||
} catch (err) {
|
||||
resultType = message.peekUint()
|
||||
|
@ -745,6 +748,7 @@ export class SessionConnection extends PersistentConnection {
|
|||
let result
|
||||
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
result = message.object() as any
|
||||
} catch (err) {
|
||||
result = '[failed to parse]'
|
||||
|
@ -1490,6 +1494,7 @@ export class SessionConnection extends PersistentConnection {
|
|||
|
||||
const pending: PendingRpc = {
|
||||
method,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
promise: undefined as any, // because we need the object to make a promise
|
||||
data: content,
|
||||
stack,
|
||||
|
@ -1599,7 +1604,7 @@ export class SessionConnection extends PersistentConnection {
|
|||
try {
|
||||
this._doFlush()
|
||||
} catch (e: any) {
|
||||
this.log.error('flush error: %s', e.stack)
|
||||
this.log.error('flush error: %s', (e as Error).stack)
|
||||
// should not happen unless there's a bug in the code
|
||||
}
|
||||
|
||||
|
@ -1718,7 +1723,7 @@ export class SessionConnection extends PersistentConnection {
|
|||
}
|
||||
|
||||
const idx = this._session.getStateSchedule.index(
|
||||
{ getState: now } as any,
|
||||
{ getState: now } as PendingRpc,
|
||||
true,
|
||||
)
|
||||
|
||||
|
@ -2035,7 +2040,7 @@ export class SessionConnection extends PersistentConnection {
|
|||
this._session
|
||||
.encryptMessage(result)
|
||||
.then((enc) => this.send(enc))
|
||||
.catch((err) => {
|
||||
.catch((err: Error) => {
|
||||
this.log.error(
|
||||
'error while sending pending messages (root msg_id = %l): %s',
|
||||
rootMsgId,
|
||||
|
|
|
@ -98,8 +98,13 @@ export class ObfuscatedPacketCodec
|
|||
|
||||
feed(data: Buffer): void {
|
||||
const dec = this._decryptor!.decrypt(data)
|
||||
|
||||
if (Buffer.isBuffer(dec)) this._inner.feed(dec)
|
||||
else dec.then((dec) => this._inner.feed(dec))
|
||||
else {
|
||||
dec.then((dec) => this._inner.feed(dec)).catch((err) =>
|
||||
this.emit('error', err),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
|
|
|
@ -96,28 +96,31 @@ export abstract class BaseTcpTransport
|
|||
this.emit('error', error)
|
||||
}
|
||||
|
||||
async handleConnect(): Promise<void> {
|
||||
handleConnect(): void {
|
||||
this.log.info('connected')
|
||||
const initialMessage = await this._packetCodec.tag()
|
||||
|
||||
if (initialMessage.length) {
|
||||
this._socket!.write(initialMessage, (err) => {
|
||||
if (err) {
|
||||
this.log.error(
|
||||
'failed to write initial message: %s',
|
||||
err.stack,
|
||||
)
|
||||
this.emit('error')
|
||||
this.close()
|
||||
Promise.resolve(this._packetCodec.tag())
|
||||
.then((initialMessage) => {
|
||||
if (initialMessage.length) {
|
||||
this._socket!.write(initialMessage, (err) => {
|
||||
if (err) {
|
||||
this.log.error(
|
||||
'failed to write initial message: %s',
|
||||
err.stack,
|
||||
)
|
||||
this.emit('error')
|
||||
this.close()
|
||||
} else {
|
||||
this._state = TransportState.Ready
|
||||
this.emit('ready')
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this._state = TransportState.Ready
|
||||
this.emit('ready')
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this._state = TransportState.Ready
|
||||
this.emit('ready')
|
||||
}
|
||||
.catch((err) => this.emit('error', err))
|
||||
}
|
||||
|
||||
async send(bytes: Buffer): Promise<void> {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import EventEmitter from 'events'
|
||||
import type WebSocket from 'ws'
|
||||
|
||||
import { tl } from '@mtcute/tl'
|
||||
|
||||
|
@ -14,13 +13,13 @@ let ws: {
|
|||
|
||||
if (typeof window === 'undefined' || typeof window.WebSocket === 'undefined') {
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
ws = require('ws')
|
||||
} catch (e) {
|
||||
ws = null
|
||||
}
|
||||
} else {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
ws = window.WebSocket as any
|
||||
ws = window.WebSocket
|
||||
}
|
||||
|
||||
const subdomainsMap: Record<string, string> = {
|
||||
|
@ -93,7 +92,9 @@ export abstract class BaseWebSocketTransport
|
|||
}
|
||||
|
||||
connect(dc: tl.RawDcOption, testMode: boolean): void {
|
||||
if (this._state !== TransportState.Idle) { throw new Error('Transport is not IDLE') }
|
||||
if (this._state !== TransportState.Idle) {
|
||||
throw new Error('Transport is not IDLE')
|
||||
}
|
||||
|
||||
if (!this.packetCodecInitialized) {
|
||||
this._packetCodec.setup?.(this._crypto, this.log)
|
||||
|
@ -117,8 +118,9 @@ export abstract class BaseWebSocketTransport
|
|||
this._socket.binaryType = 'arraybuffer'
|
||||
|
||||
this._socket.addEventListener('message', (evt) =>
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
this._packetCodec.feed(typedArrayToBuffer(evt.data as any)),
|
||||
this._packetCodec.feed(
|
||||
typedArrayToBuffer(evt.data as NodeJS.TypedArray),
|
||||
),
|
||||
)
|
||||
this._socket.addEventListener('open', this.handleConnect.bind(this))
|
||||
this._socket.addEventListener('error', this.handleError.bind(this))
|
||||
|
@ -138,22 +140,32 @@ export abstract class BaseWebSocketTransport
|
|||
this._packetCodec.reset()
|
||||
}
|
||||
|
||||
async handleError({ error }: { error: Error }): Promise<void> {
|
||||
handleError(event: Event | { error: Error }): void {
|
||||
const error =
|
||||
'error' in event ?
|
||||
event.error :
|
||||
new Error('unknown WebSocket error')
|
||||
|
||||
this.log.error('error: %s', error.stack)
|
||||
this.emit('error', error)
|
||||
}
|
||||
|
||||
async handleConnect(): Promise<void> {
|
||||
handleConnect(): void {
|
||||
this.log.info('connected')
|
||||
const initialMessage = await this._packetCodec.tag()
|
||||
|
||||
this._socket!.send(initialMessage)
|
||||
this._state = TransportState.Ready
|
||||
this.emit('ready')
|
||||
Promise.resolve(this._packetCodec.tag())
|
||||
.then((initialMessage) => {
|
||||
this._socket!.send(initialMessage)
|
||||
this._state = TransportState.Ready
|
||||
this.emit('ready')
|
||||
})
|
||||
.catch((err) => this.emit('error', err))
|
||||
}
|
||||
|
||||
async send(bytes: Buffer): Promise<void> {
|
||||
if (this._state !== TransportState.Ready) { throw new Error('Transport is not READY') }
|
||||
if (this._state !== TransportState.Ready) {
|
||||
throw new Error('Transport is not READY')
|
||||
}
|
||||
|
||||
const framed = await this._packetCodec.encode(bytes)
|
||||
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import type * as exitHookNs from 'exit-hook'
|
||||
import type * as fsNs from 'fs'
|
||||
|
||||
import { JsonMemoryStorage } from './json'
|
||||
|
||||
let fs: any = null
|
||||
type fs = typeof fsNs
|
||||
let fs: fs | null = null
|
||||
|
||||
try {
|
||||
fs = require('fs')
|
||||
fs = require('fs') as fs
|
||||
} catch (e) {}
|
||||
|
||||
let exitHook: any = null
|
||||
type exitHook = typeof exitHookNs
|
||||
let exitHook: exitHook | null = null
|
||||
|
||||
try {
|
||||
exitHook = require('exit-hook')
|
||||
exitHook = require('exit-hook') as exitHook
|
||||
} catch (e) {}
|
||||
|
||||
export class JsonFileStorage extends JsonMemoryStorage {
|
||||
|
@ -47,7 +51,9 @@ export class JsonFileStorage extends JsonMemoryStorage {
|
|||
) {
|
||||
super()
|
||||
|
||||
if (!fs || !fs.readFile) { throw new Error('Node fs module is not available!') }
|
||||
if (!fs || !fs.readFile) {
|
||||
throw new Error('Node fs module is not available!')
|
||||
}
|
||||
|
||||
this._filename = filename
|
||||
this._safe = params?.safe ?? true
|
||||
|
@ -60,7 +66,9 @@ export class JsonFileStorage extends JsonMemoryStorage {
|
|||
}
|
||||
|
||||
if (this._cleanup) {
|
||||
this._unsubscribe = exitHook(this._onProcessExit.bind(this))
|
||||
this._unsubscribe = exitHook!.default(
|
||||
this._onProcessExit.bind(this),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,12 +76,8 @@ export class JsonFileStorage extends JsonMemoryStorage {
|
|||
try {
|
||||
this._loadJson(
|
||||
await new Promise((res, rej) =>
|
||||
fs.readFile(
|
||||
this._filename,
|
||||
'utf-8',
|
||||
(err?: Error, data?: string) =>
|
||||
|
||||
err ? rej(err) : res(data!),
|
||||
fs!.readFile(this._filename, 'utf-8', (err, data) =>
|
||||
err ? rej(err) : res(data),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
@ -82,16 +86,16 @@ export class JsonFileStorage extends JsonMemoryStorage {
|
|||
|
||||
save(): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.writeFile(
|
||||
fs!.writeFile(
|
||||
this._safe ? this._filename + '.tmp' : this._filename,
|
||||
this._saveJson(),
|
||||
(err?: Error) => {
|
||||
(err) => {
|
||||
if (err) reject(err)
|
||||
else if (this._safe) {
|
||||
fs.rename(
|
||||
fs!.rename(
|
||||
this._filename + '.tmp',
|
||||
this._filename,
|
||||
(err?: any) => {
|
||||
(err) => {
|
||||
if (err && err.code !== 'ENOENT') reject(err)
|
||||
else resolve()
|
||||
},
|
||||
|
@ -106,12 +110,12 @@ export class JsonFileStorage extends JsonMemoryStorage {
|
|||
// on exit handler must be synchronous, thus we use sync methods here
|
||||
|
||||
try {
|
||||
fs.writeFileSync(this._filename, this._saveJson())
|
||||
fs!.writeFileSync(this._filename, this._saveJson())
|
||||
} catch (e) {}
|
||||
|
||||
if (this._safe) {
|
||||
try {
|
||||
fs.unlinkSync(this._filename + '.tmp')
|
||||
fs!.unlinkSync(this._filename + '.tmp')
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
import { tl } from '@mtcute/tl'
|
||||
|
||||
import { longFromFastString, longToFastString } from '../utils'
|
||||
import { MemoryStorage } from './memory'
|
||||
import { MemorySessionState, MemoryStorage } from './memory'
|
||||
|
||||
/**
|
||||
* Helper class that provides json serialization functions
|
||||
|
@ -12,7 +15,7 @@ export class JsonMemoryStorage extends MemoryStorage {
|
|||
if (key === 'authKeys') {
|
||||
const ret: Record<string, Buffer> = {}
|
||||
|
||||
value.split('|').forEach((pair: string) => {
|
||||
;(value as string).split('|').forEach((pair: string) => {
|
||||
const [dcId, b64] = pair.split(',')
|
||||
ret[dcId] = Buffer.from(b64, 'base64')
|
||||
})
|
||||
|
@ -21,27 +24,26 @@ export class JsonMemoryStorage extends MemoryStorage {
|
|||
}
|
||||
|
||||
if (key === 'accessHash') {
|
||||
return longFromFastString(value)
|
||||
return longFromFastString(value as string)
|
||||
}
|
||||
|
||||
return value
|
||||
}),
|
||||
}) as MemorySessionState,
|
||||
)
|
||||
}
|
||||
|
||||
protected _saveJson(): string {
|
||||
return JSON.stringify(this._state, (key, value) => {
|
||||
if (key === 'authKeys') {
|
||||
return Object.entries(value)
|
||||
.filter((it) => it[1] !== null)
|
||||
.map(
|
||||
([dcId, key]) =>
|
||||
dcId + ',' + (key as Buffer).toString('base64'),
|
||||
)
|
||||
const value_ = value as Record<string, Buffer | null>
|
||||
|
||||
return Object.entries(value_)
|
||||
.filter((it): it is [string, Buffer] => it[1] !== null)
|
||||
.map(([dcId, key]) => dcId + ',' + key.toString('base64'))
|
||||
.join('|')
|
||||
}
|
||||
if (key === 'accessHash') {
|
||||
return longToFastString(value)
|
||||
return longToFastString(value as tl.Long)
|
||||
}
|
||||
|
||||
return value
|
||||
|
|
|
@ -15,7 +15,7 @@ export class LocalstorageStorage extends JsonMemoryStorage {
|
|||
|
||||
load(): void {
|
||||
try {
|
||||
this._loadJson(localStorage[this._key])
|
||||
this._loadJson(localStorage[this._key] as string)
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
|
|
|
@ -210,7 +210,9 @@ export class MemoryStorage implements ITelegramStorage, IStateStorage {
|
|||
if (tempIndex !== undefined) {
|
||||
const k = `${dcId}:${tempIndex}`
|
||||
|
||||
if (Date.now() > (this._state.authKeysTempExpiry[k] ?? 0)) { return null }
|
||||
if (Date.now() > (this._state.authKeysTempExpiry[k] ?? 0)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return this._state.authKeysTemp[k]
|
||||
}
|
||||
|
@ -248,7 +250,9 @@ export class MemoryStorage implements ITelegramStorage, IStateStorage {
|
|||
}
|
||||
}
|
||||
|
||||
if (peer.username) { this._state.usernameIndex[peer.username.toLowerCase()] = peer.id }
|
||||
if (peer.username) {
|
||||
this._state.usernameIndex[peer.username.toLowerCase()] = peer.id
|
||||
}
|
||||
if (peer.phone) this._state.phoneIndex[peer.phone] = peer.id
|
||||
this._state.entities[peer.id] = peer
|
||||
}
|
||||
|
@ -357,7 +361,7 @@ export class MemoryStorage implements ITelegramStorage, IStateStorage {
|
|||
|
||||
// IStateStorage implementation
|
||||
|
||||
getState(key: string): unknown | null {
|
||||
getState(key: string): unknown {
|
||||
const val = this._state.fsm[key]
|
||||
if (!val) return null
|
||||
|
||||
|
|
|
@ -35,9 +35,10 @@ export class AsyncLock {
|
|||
|
||||
return this.acquire()
|
||||
.then(() => func())
|
||||
.catch((e) => (err = e))
|
||||
.catch((e) => void (err = e))
|
||||
.then(() => {
|
||||
this.release()
|
||||
// eslint-disable-next-line @typescript-eslint/no-throw-literal
|
||||
if (err) throw err
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import type * as forgeNs from 'node-forge'
|
||||
|
||||
import { MaybeAsync } from '../../types'
|
||||
import {
|
||||
BaseCryptoProvider,
|
||||
|
@ -5,11 +7,11 @@ import {
|
|||
IEncryptionScheme,
|
||||
} from './abstract'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
let forge: any = null
|
||||
type forge = typeof forgeNs
|
||||
let forge: forge | null = null
|
||||
|
||||
try {
|
||||
forge = require('node-forge')
|
||||
forge = require('node-forge') as forge
|
||||
} catch (e) {}
|
||||
|
||||
export class ForgeCryptoProvider
|
||||
|
@ -26,14 +28,14 @@ export class ForgeCryptoProvider
|
|||
}
|
||||
|
||||
createAesCtr(key: Buffer, iv: Buffer, encrypt: boolean): IEncryptionScheme {
|
||||
const cipher = forge.cipher[
|
||||
const cipher = forge!.cipher[
|
||||
encrypt ? 'createCipher' : 'createDecipher'
|
||||
]('AES-CTR', key.toString('binary'))
|
||||
cipher.start({ iv: iv.toString('binary') })
|
||||
|
||||
const update = (data: Buffer): Buffer => {
|
||||
cipher.output.data = ''
|
||||
cipher.update(forge.util.createBuffer(data.toString('binary')))
|
||||
cipher.update(forge!.util.createBuffer(data.toString('binary')))
|
||||
|
||||
return Buffer.from(cipher.output.data, 'binary')
|
||||
}
|
||||
|
@ -49,19 +51,24 @@ export class ForgeCryptoProvider
|
|||
|
||||
return {
|
||||
encrypt(data: Buffer) {
|
||||
const cipher = forge.cipher.createCipher('AES-ECB', keyBuffer)
|
||||
const cipher = forge!.cipher.createCipher('AES-ECB', keyBuffer)
|
||||
cipher.start({})
|
||||
// @ts-expect-error wrong types
|
||||
cipher.mode.pad = cipher.mode.unpad = false
|
||||
cipher.update(forge.util.createBuffer(data.toString('binary')))
|
||||
cipher.update(forge!.util.createBuffer(data.toString('binary')))
|
||||
cipher.finish()
|
||||
|
||||
return Buffer.from(cipher.output.data, 'binary')
|
||||
},
|
||||
decrypt(data: Buffer) {
|
||||
const cipher = forge.cipher.createDecipher('AES-ECB', keyBuffer)
|
||||
const cipher = forge!.cipher.createDecipher(
|
||||
'AES-ECB',
|
||||
keyBuffer,
|
||||
)
|
||||
cipher.start({})
|
||||
// @ts-expect-error wrong types
|
||||
cipher.mode.pad = cipher.mode.unpad = false
|
||||
cipher.update(forge.util.createBuffer(data.toString('binary')))
|
||||
cipher.update(forge!.util.createBuffer(data.toString('binary')))
|
||||
cipher.finish()
|
||||
|
||||
return Buffer.from(cipher.output.data, 'binary')
|
||||
|
@ -77,12 +84,13 @@ export class ForgeCryptoProvider
|
|||
algo = 'sha512',
|
||||
): MaybeAsync<Buffer> {
|
||||
return new Promise((resolve, reject) =>
|
||||
forge.pkcs5.pbkdf2(
|
||||
forge!.pkcs5.pbkdf2(
|
||||
password.toString('binary'),
|
||||
salt.toString('binary'),
|
||||
iterations,
|
||||
keylen,
|
||||
forge.md[algo].create(),
|
||||
// eslint-disable-next-line
|
||||
(forge!.md as any)[algo].create(),
|
||||
(err: Error | null, buf: string) =>
|
||||
err !== null ?
|
||||
reject(err) :
|
||||
|
@ -93,7 +101,7 @@ export class ForgeCryptoProvider
|
|||
|
||||
sha1(data: Buffer): MaybeAsync<Buffer> {
|
||||
return Buffer.from(
|
||||
forge.md.sha1.create().update(data.toString('binary')).digest()
|
||||
forge!.md.sha1.create().update(data.toString('binary')).digest()
|
||||
.data,
|
||||
'binary',
|
||||
)
|
||||
|
@ -101,14 +109,14 @@ export class ForgeCryptoProvider
|
|||
|
||||
sha256(data: Buffer): MaybeAsync<Buffer> {
|
||||
return Buffer.from(
|
||||
forge.md.sha256.create().update(data.toString('binary')).digest()
|
||||
forge!.md.sha256.create().update(data.toString('binary')).digest()
|
||||
.data,
|
||||
'binary',
|
||||
)
|
||||
}
|
||||
|
||||
hmacSha256(data: Buffer, key: Buffer): MaybeAsync<Buffer> {
|
||||
const hmac = forge.hmac.create()
|
||||
const hmac = forge!.hmac.create()
|
||||
hmac.start('sha256', key.toString('binary'))
|
||||
hmac.update(data.toString('binary'))
|
||||
|
||||
|
|
|
@ -16,10 +16,6 @@ import {
|
|||
export class NodeCryptoProvider
|
||||
extends BaseCryptoProvider
|
||||
implements ICryptoProvider {
|
||||
constructor() {
|
||||
super()
|
||||
}
|
||||
|
||||
createAesCtr(key: Buffer, iv: Buffer, encrypt: boolean): IEncryptionScheme {
|
||||
const cipher = (encrypt ? createCipheriv : createDecipheriv)(
|
||||
`aes-${key.length * 8}-ctr`,
|
||||
|
|
|
@ -81,7 +81,7 @@ export async function computeSrpParams(
|
|||
// nice naming thx durov
|
||||
if (
|
||||
!request.currentAlgo ||
|
||||
request.currentAlgo?._ !==
|
||||
request.currentAlgo._ !==
|
||||
'passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow'
|
||||
) {
|
||||
throw new Error(`Unknown algo ${request.currentAlgo?._}`)
|
||||
|
|
|
@ -51,7 +51,7 @@ export class Deque<T> {
|
|||
}
|
||||
}
|
||||
|
||||
this._elements = new Array(capacity)
|
||||
this._elements = new Array<T | undefined>(capacity)
|
||||
this._capacity = capacity
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ export class Deque<T> {
|
|||
const newCapacity = n << 1
|
||||
if (newCapacity < 0) throw new Error('Deque is too big')
|
||||
|
||||
const arr = new Array(newCapacity)
|
||||
const arr = new Array<T | undefined>(newCapacity)
|
||||
|
||||
// copy items to the new array
|
||||
// copy head till the end of arr
|
||||
|
@ -251,7 +251,7 @@ export class Deque<T> {
|
|||
}
|
||||
|
||||
clear(): void {
|
||||
this._elements = new Array(this._capacity)
|
||||
this._elements = new Array<T | undefined>(this._capacity)
|
||||
this._head = this._tail = 0
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ if (typeof process !== 'undefined') {
|
|||
defaultLogLevel = envLogLevel
|
||||
}
|
||||
} else if (typeof localStorage !== 'undefined') {
|
||||
const localLogLevel = parseInt(localStorage.MTCUTE_LOG_LEVEL)
|
||||
const localLogLevel = parseInt(localStorage.MTCUTE_LOG_LEVEL as string)
|
||||
|
||||
if (!isNaN(localLogLevel)) {
|
||||
defaultLogLevel = localLogLevel
|
||||
|
@ -62,10 +62,10 @@ export class Logger {
|
|||
|
||||
// custom formatters
|
||||
if (
|
||||
fmt.indexOf('%h') > -1 ||
|
||||
fmt.indexOf('%b') > -1 ||
|
||||
fmt.indexOf('%j') > -1 ||
|
||||
fmt.indexOf('%l') > -1
|
||||
fmt.includes('%h') ||
|
||||
fmt.includes('%b') ||
|
||||
fmt.includes('%j') ||
|
||||
fmt.includes('%l')
|
||||
) {
|
||||
let idx = 0
|
||||
fmt = fmt.replace(FORMATTER_RE, (m) => {
|
||||
|
@ -89,7 +89,9 @@ export class Logger {
|
|||
v.type === 'Buffer' &&
|
||||
Array.isArray(v.data)
|
||||
) {
|
||||
let str = Buffer.from(v.data).toString('base64')
|
||||
let str = Buffer.from(
|
||||
v.data as number[],
|
||||
).toString('base64')
|
||||
|
||||
if (str.length > 300) {
|
||||
str = str.slice(0, 300) + '...'
|
||||
|
@ -98,6 +100,7 @@ export class Logger {
|
|||
return str
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return v
|
||||
})
|
||||
}
|
||||
|
@ -152,7 +155,7 @@ export class LogManager extends Logger {
|
|||
|
||||
constructor(tag = 'base') {
|
||||
// workaround because we cant pass this to super
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-argument
|
||||
super(null as any, tag)
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
;(this as any).mgr = this
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-argument,@typescript-eslint/no-unsafe-return */
|
||||
// ^^ because of performance reasons
|
||||
import Long from 'long'
|
||||
|
||||
|
@ -84,7 +85,9 @@ export function longFromFastString(val: string, unsigned = false): Long {
|
|||
const low = parseInt(parts[0])
|
||||
const high = parseInt(parts[1])
|
||||
|
||||
if (isNaN(low) || isNaN(high)) { throw new Error(`Invalid long fast string: ${val}`) }
|
||||
if (isNaN(low) || isNaN(high)) {
|
||||
throw new Error(`Invalid long fast string: ${val}`)
|
||||
}
|
||||
|
||||
return new Long(low, high, unsigned)
|
||||
}
|
||||
|
@ -166,19 +169,19 @@ export class LongMap<V> {
|
|||
}
|
||||
|
||||
private _setForObj(key: Long, value: V): void {
|
||||
this._obj![longToFastString(key)] = value
|
||||
this._obj[longToFastString(key)] = value
|
||||
}
|
||||
|
||||
private _hasForObj(key: Long): boolean {
|
||||
return longToFastString(key) in this._obj!
|
||||
return longToFastString(key) in this._obj
|
||||
}
|
||||
|
||||
private _getForObj(key: Long): V | undefined {
|
||||
return this._obj![longToFastString(key)]
|
||||
return this._obj[longToFastString(key)]
|
||||
}
|
||||
|
||||
private _deleteForObj(key: Long): void {
|
||||
delete this._obj![longToFastString(key)]
|
||||
delete this._obj[longToFastString(key)]
|
||||
}
|
||||
|
||||
private *_keysForObj(unsigned?: boolean): IterableIterator<Long> {
|
||||
|
@ -188,7 +191,7 @@ export class LongMap<V> {
|
|||
}
|
||||
|
||||
private *_valuesForObj(): IterableIterator<V> {
|
||||
yield* Object.values(this._obj!) as any
|
||||
yield* Object.values(this._obj) as any
|
||||
}
|
||||
|
||||
private _clearForObj(): void {
|
||||
|
@ -254,22 +257,22 @@ export class LongSet {
|
|||
|
||||
private _addForObj(val: Long) {
|
||||
const k = longToFastString(val)
|
||||
if (k in this._obj!) return
|
||||
if (k in this._obj) return
|
||||
|
||||
this._obj![k] = true
|
||||
this._obj[k] = true
|
||||
this._objSize! += 1
|
||||
}
|
||||
|
||||
private _deleteForObj(val: Long) {
|
||||
const k = longToFastString(val)
|
||||
if (!(k in this._obj!)) return
|
||||
if (!(k in this._obj)) return
|
||||
|
||||
delete this._obj![k]
|
||||
delete this._obj[k]
|
||||
this._objSize! -= 1
|
||||
}
|
||||
|
||||
private _hasForObj(val: Long) {
|
||||
return longToFastString(val) in this._obj!
|
||||
return longToFastString(val) in this._obj
|
||||
}
|
||||
|
||||
private _clearForObj() {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-argument,@typescript-eslint/no-unsafe-return */
|
||||
// ^^ because of performance reasons
|
||||
import { LongMap } from './long-utils'
|
||||
|
||||
|
@ -130,7 +131,7 @@ export class LruMap<K extends string | number, V> {
|
|||
if (oldest) {
|
||||
if (oldest.p) {
|
||||
this._last = oldest.p
|
||||
this._last!.n = undefined
|
||||
this._last.n = undefined
|
||||
} else {
|
||||
// exhausted
|
||||
this._last = undefined
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
||||
// ^^ because of performance reasons
|
||||
import Long from 'long'
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ describe('IntermediatePacketCodec', () => {
|
|||
|
||||
it('should correctly parse immediate framing', (done) => {
|
||||
const codec = new IntermediatePacketCodec()
|
||||
codec.on('packet', (data) => {
|
||||
codec.on('packet', (data: Buffer) => {
|
||||
expect([...data]).eql([5, 1, 2, 3, 4])
|
||||
done()
|
||||
})
|
||||
|
@ -21,7 +21,7 @@ describe('IntermediatePacketCodec', () => {
|
|||
|
||||
it('should correctly parse incomplete framing', (done) => {
|
||||
const codec = new IntermediatePacketCodec()
|
||||
codec.on('packet', (data) => {
|
||||
codec.on('packet', (data: Buffer) => {
|
||||
expect([...data]).eql([5, 1, 2, 3, 4])
|
||||
done()
|
||||
})
|
||||
|
@ -34,7 +34,7 @@ describe('IntermediatePacketCodec', () => {
|
|||
|
||||
let number = 0
|
||||
|
||||
codec.on('packet', (data) => {
|
||||
codec.on('packet', (data: Buffer) => {
|
||||
if (number === 0) {
|
||||
expect([...data]).eql([5, 1, 2, 3, 4])
|
||||
number = 1
|
||||
|
@ -51,7 +51,7 @@ describe('IntermediatePacketCodec', () => {
|
|||
it('should correctly parse transport errors', (done) => {
|
||||
const codec = new IntermediatePacketCodec()
|
||||
|
||||
codec.on('error', (err) => {
|
||||
codec.on('error', (err: TransportError) => {
|
||||
expect(err).to.have.instanceOf(TransportError)
|
||||
expect(err.code).eq(404)
|
||||
done()
|
||||
|
@ -63,7 +63,7 @@ describe('IntermediatePacketCodec', () => {
|
|||
it('should reset when called reset()', (done) => {
|
||||
const codec = new IntermediatePacketCodec()
|
||||
|
||||
codec.on('packet', (data) => {
|
||||
codec.on('packet', (data: Buffer) => {
|
||||
expect([...data]).eql([1, 2, 3, 4, 5])
|
||||
done()
|
||||
})
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"outDir": "./dist"
|
||||
},
|
||||
"include": [
|
||||
"./src"
|
||||
"./src",
|
||||
"./tests"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ export class CallbackDataBuilder<T extends string> {
|
|||
.map((f) => {
|
||||
const val = obj[f]
|
||||
|
||||
if (val.indexOf(this.sep) > -1) {
|
||||
if (val.includes(this.sep)) {
|
||||
throw new MtArgumentError(
|
||||
`Value for ${f} ${val} contains separator ${this.sep} and cannot be used.`,
|
||||
)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable max-depth */
|
||||
/* eslint-disable */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types */
|
||||
// ^^ will be looked into in MTQ-29
|
||||
|
||||
|
@ -122,7 +122,7 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
constructor(
|
||||
client?: TelegramClient | IStateStorage | StateKeyDelegate,
|
||||
storage?: IStateStorage | StateKeyDelegate,
|
||||
key?: StateKeyDelegate,
|
||||
key?: StateKeyDelegate
|
||||
) {
|
||||
this.dispatchRawUpdate = this.dispatchRawUpdate.bind(this)
|
||||
this.dispatchUpdate = this.dispatchUpdate.bind(this)
|
||||
|
@ -196,15 +196,14 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
*/
|
||||
dispatchRawUpdate(
|
||||
update: tl.TypeUpdate | tl.TypeMessage,
|
||||
peers: PeersIndex,
|
||||
peers: PeersIndex
|
||||
): void {
|
||||
if (!this._client) return
|
||||
|
||||
// order does not matter in the dispatcher,
|
||||
// so we can handle each update in its own task
|
||||
this.dispatchRawUpdateNow(update, peers).catch((err) =>
|
||||
// eslint-disable-next-line dot-notation
|
||||
this._client!['_emitError'](err),
|
||||
this._client!['_emitError'](err)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -222,7 +221,7 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
*/
|
||||
async dispatchRawUpdateNow(
|
||||
update: tl.TypeUpdate | tl.TypeMessage,
|
||||
peers: PeersIndex,
|
||||
peers: PeersIndex
|
||||
): Promise<boolean> {
|
||||
if (!this._client) return false
|
||||
|
||||
|
@ -282,8 +281,7 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
// order does not matter in the dispatcher,
|
||||
// so we can handle each update in its own task
|
||||
this.dispatchUpdateNow(update).catch((err) =>
|
||||
// eslint-disable-next-line dot-notation
|
||||
this._client!['_emitError'](err),
|
||||
this._client!['_emitError'](err)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -307,7 +305,7 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
// this is getting a bit crazy lol
|
||||
parsedState?: UpdateState<State, SceneName> | null,
|
||||
parsedScene?: string | null,
|
||||
forceScene?: true,
|
||||
forceScene?: true
|
||||
): Promise<boolean> {
|
||||
if (!this._client) return false
|
||||
|
||||
|
@ -349,7 +347,7 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
update,
|
||||
parsedState,
|
||||
parsedScene,
|
||||
true,
|
||||
true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -369,17 +367,16 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
if (
|
||||
!this._customStateKeyDelegate ||
|
||||
(customKey = await this._customStateKeyDelegate(
|
||||
update.data,
|
||||
update.data
|
||||
))
|
||||
) {
|
||||
parsedState = new UpdateState(
|
||||
|
||||
this._storage!,
|
||||
this._storage,
|
||||
key,
|
||||
this._scene ?? null,
|
||||
this._sceneScoped,
|
||||
this._customStorage,
|
||||
customKey,
|
||||
customKey
|
||||
)
|
||||
}
|
||||
} else {
|
||||
|
@ -421,12 +418,12 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
!h.check ||
|
||||
(await h.check(
|
||||
update.data as any,
|
||||
parsedState as never,
|
||||
parsedState as never
|
||||
))
|
||||
) {
|
||||
result = await h.callback(
|
||||
update.data as any,
|
||||
parsedState as never,
|
||||
parsedState as never
|
||||
)
|
||||
handled = true
|
||||
} else continue
|
||||
|
@ -443,16 +440,15 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
case 'scene': {
|
||||
if (!parsedState) {
|
||||
throw new MtArgumentError(
|
||||
'Cannot use ToScene without state',
|
||||
'Cannot use ToScene without state'
|
||||
)
|
||||
}
|
||||
|
||||
// eslint-disable-next-line dot-notation
|
||||
const scene = parsedState['_scene']
|
||||
|
||||
if (!scene) {
|
||||
throw new MtArgumentError(
|
||||
'Cannot use ToScene without entering a scene',
|
||||
'Cannot use ToScene without entering a scene'
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -462,7 +458,7 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
update,
|
||||
undefined,
|
||||
scene,
|
||||
true,
|
||||
true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -474,7 +470,7 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
const handled = await this._errorHandler(
|
||||
e,
|
||||
update,
|
||||
parsedState as never,
|
||||
parsedState as never
|
||||
)
|
||||
if (!handled) throw e
|
||||
} else {
|
||||
|
@ -527,7 +523,7 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
*/
|
||||
removeUpdateHandler(
|
||||
handler: UpdateHandler | UpdateHandler['name'] | 'all',
|
||||
group = 0,
|
||||
group = 0
|
||||
): void {
|
||||
if (group !== -1 && !(group in this._groups)) {
|
||||
return
|
||||
|
@ -581,7 +577,7 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
update: ParsedUpdate & T,
|
||||
state?: UpdateState<State, SceneName>
|
||||
) => MaybeAsync<boolean>)
|
||||
| null,
|
||||
| null
|
||||
): void {
|
||||
if (handler) this._errorHandler = handler
|
||||
else this._errorHandler = undefined
|
||||
|
@ -605,7 +601,7 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
update: ParsedUpdate & T,
|
||||
state?: UpdateState<State, SceneName>
|
||||
) => MaybeAsync<PropagationAction | void>)
|
||||
| null,
|
||||
| null
|
||||
): void {
|
||||
if (handler) this._preUpdateHandler = handler
|
||||
else this._preUpdateHandler = undefined
|
||||
|
@ -630,7 +626,7 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
update: ParsedUpdate & T,
|
||||
state?: UpdateState<State, SceneName>
|
||||
) => MaybeAsync<void>)
|
||||
| null,
|
||||
| null
|
||||
): void {
|
||||
if (handler) this._postUpdateHandler = handler
|
||||
else this._postUpdateHandler = undefined
|
||||
|
@ -643,9 +639,11 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
propagateErrorToParent(
|
||||
err: Error,
|
||||
update: ParsedUpdate,
|
||||
state?: UpdateState<State, SceneName>,
|
||||
state?: UpdateState<State, SceneName>
|
||||
): MaybeAsync<boolean> {
|
||||
if (!this.parent) { throw new MtArgumentError('This dispatcher is not a child') }
|
||||
if (!this.parent) {
|
||||
throw new MtArgumentError('This dispatcher is not a child')
|
||||
}
|
||||
|
||||
if (this.parent._errorHandler) {
|
||||
return this.parent._errorHandler(err, update, state)
|
||||
|
@ -667,9 +665,9 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
if (child._client) {
|
||||
throw new MtArgumentError(
|
||||
'Provided dispatcher is ' +
|
||||
(child._parent ?
|
||||
'already a child. Use parent.removeChild() before calling addChild()' :
|
||||
'already bound to a client. Use unbind() before calling addChild()'),
|
||||
(child._parent
|
||||
? 'already a child. Use parent.removeChild() before calling addChild()'
|
||||
: 'already bound to a client. Use unbind() before calling addChild()')
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -695,7 +693,7 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
* @param child Other dispatcher
|
||||
*/
|
||||
addChild(child: Dispatcher<State, SceneName>): void {
|
||||
if (this._children.indexOf(child) > -1) return
|
||||
if (this._children.includes(child)) return
|
||||
|
||||
this._prepareChild(child)
|
||||
this._children.push(child)
|
||||
|
@ -740,13 +738,13 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
addScene(
|
||||
uid: SceneName,
|
||||
scene: Dispatcher<any, SceneName>,
|
||||
scoped = true,
|
||||
scoped = true
|
||||
): void {
|
||||
if (!this._scenes) this._scenes = {}
|
||||
|
||||
if (uid in this._scenes) {
|
||||
throw new MtArgumentError(
|
||||
`Scene with UID ${uid} is already registered!`,
|
||||
`Scene with UID ${uid} is already registered!`
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -756,7 +754,7 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
|
||||
if (scene._scene) {
|
||||
throw new MtArgumentError(
|
||||
`This dispatcher is already registered as scene ${scene._scene}`,
|
||||
`This dispatcher is already registered as scene ${scene._scene}`
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -807,7 +805,7 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
extend(other: Dispatcher<State, SceneName>): void {
|
||||
if (other._customStorage || other._customStateKeyDelegate) {
|
||||
throw new MtArgumentError(
|
||||
'Provided dispatcher has custom storage and cannot be extended from.',
|
||||
'Provided dispatcher has custom storage and cannot be extended from.'
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -849,7 +847,7 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
this.addScene(
|
||||
key as any,
|
||||
myScenes[key] as any,
|
||||
myScenes[key]._sceneScoped as any,
|
||||
myScenes[key]._sceneScoped as any
|
||||
)
|
||||
})
|
||||
}
|
||||
|
@ -903,7 +901,7 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
key as any,
|
||||
scene as any,
|
||||
|
||||
this._scenes![key]._sceneScoped as any,
|
||||
this._scenes![key]._sceneScoped as any
|
||||
)
|
||||
})
|
||||
}
|
||||
|
@ -937,22 +935,21 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
object: Parameters<StateKeyDelegate>[0]
|
||||
): Promise<UpdateState<S, SceneName>>
|
||||
getState<S = State>(
|
||||
object: string | Parameters<StateKeyDelegate>[0],
|
||||
object: string | Parameters<StateKeyDelegate>[0]
|
||||
): MaybeAsync<UpdateState<S, SceneName>> {
|
||||
if (!this._storage) {
|
||||
throw new MtArgumentError(
|
||||
'Cannot use getUpdateState() filter without state storage',
|
||||
'Cannot use getUpdateState() filter without state storage'
|
||||
)
|
||||
}
|
||||
|
||||
if (typeof object === 'string') {
|
||||
return new UpdateState(
|
||||
|
||||
this._storage!,
|
||||
this._storage,
|
||||
object,
|
||||
this._scene ?? null,
|
||||
this._sceneScoped,
|
||||
this._customStorage,
|
||||
this._customStorage
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -963,12 +960,11 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
|
||||
if (!this._customStateKeyDelegate) {
|
||||
return new UpdateState(
|
||||
|
||||
this._storage!,
|
||||
key,
|
||||
this._scene ?? null,
|
||||
this._sceneScoped,
|
||||
this._customStorage,
|
||||
this._customStorage
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -976,20 +972,19 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
(customKey) => {
|
||||
if (!customKey) {
|
||||
throw new MtArgumentError(
|
||||
'Cannot derive custom key from given object',
|
||||
'Cannot derive custom key from given object'
|
||||
)
|
||||
}
|
||||
|
||||
return new UpdateState(
|
||||
|
||||
this._storage!,
|
||||
key,
|
||||
this._scene ?? null,
|
||||
this._sceneScoped,
|
||||
this._customStorage,
|
||||
customKey,
|
||||
customKey
|
||||
)
|
||||
},
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
@ -1001,7 +996,7 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
* ignoring local custom storage, key delegate and scene scope.
|
||||
*/
|
||||
getGlobalState<T>(
|
||||
object: Parameters<StateKeyDelegate>[0],
|
||||
object: Parameters<StateKeyDelegate>[0]
|
||||
): Promise<UpdateState<T, SceneName>> {
|
||||
if (!this._parent) {
|
||||
throw new MtArgumentError('This dispatcher does not have a parent')
|
||||
|
@ -1013,11 +1008,10 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
}
|
||||
|
||||
return new UpdateState(
|
||||
|
||||
this._storage!,
|
||||
key,
|
||||
this._scene ?? null,
|
||||
false,
|
||||
false
|
||||
)
|
||||
})
|
||||
}
|
||||
|
@ -1028,7 +1022,7 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
name: UpdateHandler['name'],
|
||||
filter: any,
|
||||
handler?: any,
|
||||
group?: number,
|
||||
group?: number
|
||||
): void {
|
||||
if (typeof handler === 'number' || typeof handler === 'undefined') {
|
||||
this.addUpdateHandler(
|
||||
|
@ -1036,7 +1030,7 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
name,
|
||||
callback: filter,
|
||||
},
|
||||
handler,
|
||||
handler
|
||||
)
|
||||
} else {
|
||||
this.addUpdateHandler(
|
||||
|
@ -1045,7 +1039,7 @@ export class Dispatcher<State = never, SceneName extends string = string> {
|
|||
callback: handler,
|
||||
check: filter,
|
||||
},
|
||||
group,
|
||||
group
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -209,18 +209,18 @@ export namespace filters {
|
|||
fn2: UpdateFilter<Base, Mod2, State2>,
|
||||
): UpdateFilter<Base, Mod1 & Mod2, State1 | State2> {
|
||||
return (upd, state) => {
|
||||
const res1 = fn1(upd, state as any)
|
||||
const res1 = fn1(upd, state as UpdateState<State1>)
|
||||
|
||||
if (typeof res1 === 'boolean') {
|
||||
if (!res1) return false
|
||||
|
||||
return fn2(upd, state as any)
|
||||
return fn2(upd, state as UpdateState<State2>)
|
||||
}
|
||||
|
||||
return res1.then((r1) => {
|
||||
if (!r1) return false
|
||||
|
||||
return fn2(upd, state as any)
|
||||
return fn2(upd, state as UpdateState<State2>)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -247,18 +247,18 @@ export namespace filters {
|
|||
fn2: UpdateFilter<Base, Mod2, State2>,
|
||||
): UpdateFilter<Base, Mod1 | Mod2, State1 | State2> {
|
||||
return (upd, state) => {
|
||||
const res1 = fn1(upd, state as any)
|
||||
const res1 = fn1(upd, state as UpdateState<State1>)
|
||||
|
||||
if (typeof res1 === 'boolean') {
|
||||
if (res1) return true
|
||||
|
||||
return fn2(upd, state as any)
|
||||
return fn2(upd, state as UpdateState<State2>)
|
||||
}
|
||||
|
||||
return res1.then((r1) => {
|
||||
if (r1) return true
|
||||
|
||||
return fn2(upd, state as any)
|
||||
return fn2(upd, state as UpdateState<State2>)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -947,7 +947,7 @@ export namespace filters {
|
|||
const m = txt.match(regex)
|
||||
|
||||
if (m) {
|
||||
(obj as any).match = m
|
||||
(obj as typeof obj & { match: RegExpMatchArray }).match = m
|
||||
|
||||
return true
|
||||
}
|
||||
|
@ -1002,14 +1002,14 @@ export namespace filters {
|
|||
return (obj) => {
|
||||
const txt = extractText(obj)
|
||||
|
||||
return txt != null && txt.toLowerCase().indexOf(str) > -1
|
||||
return txt != null && txt.toLowerCase().includes(str)
|
||||
}
|
||||
}
|
||||
|
||||
return (obj) => {
|
||||
const txt = extractText(obj)
|
||||
|
||||
return txt != null && txt.indexOf(str) > -1
|
||||
return txt != null && txt.includes(str)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1157,13 +1157,16 @@ export namespace filters {
|
|||
// we use .replace to iterate over global regex, not to replace the text
|
||||
withoutPrefix
|
||||
.slice(m[0].length)
|
||||
.replace(argumentsRe, ($0, $1, $2, $3) => {
|
||||
match.push(
|
||||
($2 || $3 || '').replace(unescapeRe, '$1'),
|
||||
)
|
||||
.replace(
|
||||
argumentsRe,
|
||||
($0, $1, $2: string, $3: string) => {
|
||||
match.push(
|
||||
($2 || $3 || '').replace(unescapeRe, '$1'),
|
||||
)
|
||||
|
||||
return ''
|
||||
})
|
||||
return ''
|
||||
},
|
||||
)
|
||||
;(msg as Message & { command: string[] }).command = match
|
||||
|
||||
return true
|
||||
|
|
|
@ -18,7 +18,7 @@ export interface IStateStorage {
|
|||
*
|
||||
* @param key Key of the state, as defined by {@link StateKeyDelegate}
|
||||
*/
|
||||
getState(key: string): MaybeAsync<unknown | null>
|
||||
getState(key: string): MaybeAsync<unknown>
|
||||
|
||||
/**
|
||||
* Save state to the storage
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"outDir": "./dist"
|
||||
},
|
||||
"include": [
|
||||
"./src"
|
||||
"./src",
|
||||
"./tests"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"outDir": "./dist"
|
||||
},
|
||||
"include": [
|
||||
"./src"
|
||||
"./src",
|
||||
"./tests",
|
||||
]
|
||||
}
|
||||
|
|
|
@ -28,9 +28,14 @@ export function html(
|
|||
if (typeof it === 'boolean' || !it) return
|
||||
|
||||
if (typeof it === 'string') {
|
||||
it = HtmlMessageEntityParser.escape(it, Boolean(str.match(/=['"]$/)))
|
||||
it = HtmlMessageEntityParser.escape(
|
||||
it,
|
||||
Boolean(str.match(/=['"]$/)),
|
||||
)
|
||||
} else {
|
||||
if (it.mode && it.mode !== 'html') { throw new Error(`Incompatible parse mode: ${it.mode}`) }
|
||||
if (it.mode && it.mode !== 'html') {
|
||||
throw new Error(`Incompatible parse mode: ${it.mode}`)
|
||||
}
|
||||
it = it.value
|
||||
}
|
||||
|
||||
|
@ -92,7 +97,7 @@ export class HtmlMessageEntityParser implements IMessageEntityParser {
|
|||
function processPendingText(tagEnd = false) {
|
||||
if (!pendingText.length) return
|
||||
|
||||
if (!stacks.pre?.length) {
|
||||
if (!stacks.pre.length) {
|
||||
pendingText = pendingText.replace(/[^\S\u00A0]+/gs, ' ')
|
||||
|
||||
if (tagEnd) pendingText = pendingText.trimEnd()
|
||||
|
@ -119,7 +124,7 @@ export class HtmlMessageEntityParser implements IMessageEntityParser {
|
|||
processPendingText()
|
||||
|
||||
// ignore tags inside pre (except pre)
|
||||
if (name !== 'pre' && stacks.pre?.length) return
|
||||
if (name !== 'pre' && stacks.pre.length) return
|
||||
|
||||
let entity: tl.TypeMessageEntity
|
||||
|
||||
|
@ -262,9 +267,9 @@ export class HtmlMessageEntityParser implements IMessageEntityParser {
|
|||
name = name.toLowerCase()
|
||||
|
||||
// ignore tags inside pre (except pre)
|
||||
if (name !== 'pre' && stacks.pre?.length) return
|
||||
if (name !== 'pre' && stacks.pre.length) return
|
||||
|
||||
const entity = stacks[name]?.pop()
|
||||
const entity = stacks[name].pop()
|
||||
|
||||
if (!entity) return // unmatched close tag
|
||||
|
||||
|
@ -338,7 +343,9 @@ export class HtmlMessageEntityParser implements IMessageEntityParser {
|
|||
relativeOffset = lastOffset
|
||||
}
|
||||
|
||||
if (length <= 0 || relativeOffset >= end || relativeOffset < 0) { continue }
|
||||
if (length <= 0 || relativeOffset >= end || relativeOffset < 0) {
|
||||
continue
|
||||
}
|
||||
|
||||
let skip = false
|
||||
|
||||
|
|
|
@ -620,7 +620,7 @@ describe('HtmlMessageEntityParser', () => {
|
|||
|
||||
expect(() => html`${unsafeString}`.value).not.throw(Error)
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
expect(() => html`${unsafeString2}`.value).throw(Error)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"outDir": "./dist"
|
||||
},
|
||||
"include": [
|
||||
"./src"
|
||||
"./src",
|
||||
"./tests",
|
||||
]
|
||||
}
|
||||
|
|
|
@ -79,7 +79,9 @@ export abstract class BaseHttpProxyTcpTransport extends BaseTcpTransport {
|
|||
}
|
||||
|
||||
connect(dc: tl.RawDcOption): void {
|
||||
if (this._state !== TransportState.Idle) { throw new Error('Transport is not IDLE') }
|
||||
if (this._state !== TransportState.Idle) {
|
||||
throw new Error('Transport is not IDLE')
|
||||
}
|
||||
|
||||
if (!this.packetCodecInitialized) {
|
||||
this._packetCodec.on('error', (err) => this.emit('error', err))
|
||||
|
@ -133,9 +135,10 @@ export abstract class BaseHttpProxyTcpTransport extends BaseTcpTransport {
|
|||
}
|
||||
headers['Proxy-Connection'] = 'Keep-Alive'
|
||||
|
||||
const packet = `CONNECT ${ip} HTTP/1.1${Object.keys(headers).map(
|
||||
(k) => `\r\n${k}: ${headers[k]}`,
|
||||
)}\r\n\r\n`
|
||||
const headersStr = Object.keys(headers)
|
||||
.map((k) => `\r\n${k}: ${headers[k]}`)
|
||||
.join('')
|
||||
const packet = `CONNECT ${ip} HTTP/1.1${headersStr}\r\n\r\n`
|
||||
|
||||
this._socket!.write(packet)
|
||||
this._socket!.once('data', (msg) => {
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
import type { BotChatJoinRequestUpdate, BotStoppedUpdate, CallbackQuery, ChatMemberUpdate, ChosenInlineResult, InlineQuery, Message, ParsedUpdate, PollVoteUpdate, User } from '@mtcute/client'
|
||||
import type * as clientNs from '@mtcute/client'
|
||||
|
||||
import { I18nStrings, I18nValue } from './types'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
let client: any
|
||||
let client: typeof clientNs
|
||||
|
||||
try {
|
||||
client = require('@mtcute/client')
|
||||
client = require('@mtcute/client') as typeof clientNs
|
||||
} catch (e) {}
|
||||
|
||||
/**
|
||||
|
@ -43,7 +42,7 @@ export function createI18nStringsIndex(
|
|||
* @param update Update to extract language from
|
||||
*/
|
||||
export function extractLanguageFromUpdate(
|
||||
update: ParsedUpdate['data'],
|
||||
update: clientNs.ParsedUpdate['data'],
|
||||
): string | null | undefined {
|
||||
if (!client) {
|
||||
throw new Error(
|
||||
|
@ -54,23 +53,26 @@ export function extractLanguageFromUpdate(
|
|||
switch (update.constructor) {
|
||||
case client.Message:
|
||||
// if sender is Chat it will just be undefined
|
||||
return ((update as Message).sender as User).language
|
||||
return ((update as clientNs.Message).sender as clientNs.User)
|
||||
.language
|
||||
case client.PollVoteUpdate:
|
||||
// if peer is Chat it will just be undefined
|
||||
return ((update as clientNs.PollVoteUpdate).peer as clientNs.User)
|
||||
.language
|
||||
case client.ChatMemberUpdate:
|
||||
case client.InlineQuery:
|
||||
case client.ChosenInlineResult:
|
||||
case client.CallbackQuery:
|
||||
case client.PollVoteUpdate:
|
||||
case client.BotStoppedUpdate:
|
||||
case client.BotChatJoinRequestUpdate:
|
||||
return (
|
||||
update as
|
||||
| ChatMemberUpdate
|
||||
| InlineQuery
|
||||
| ChosenInlineResult
|
||||
| CallbackQuery
|
||||
| PollVoteUpdate
|
||||
| BotStoppedUpdate
|
||||
| BotChatJoinRequestUpdate
|
||||
| clientNs.ChatMemberUpdate
|
||||
| clientNs.InlineQuery
|
||||
| clientNs.ChosenInlineResult
|
||||
| clientNs.CallbackQuery
|
||||
| clientNs.BotStoppedUpdate
|
||||
| clientNs.BotChatJoinRequestUpdate
|
||||
).user.language
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"outDir": "./dist"
|
||||
},
|
||||
"include": [
|
||||
"./src"
|
||||
"./src",
|
||||
"./tests",
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
import Long from 'long'
|
||||
|
||||
import type { FormattedString, IMessageEntityParser, MessageEntity, tl } from '@mtcute/client'
|
||||
import type {
|
||||
FormattedString,
|
||||
IMessageEntityParser,
|
||||
MessageEntity,
|
||||
tl,
|
||||
} from '@mtcute/client'
|
||||
|
||||
const MENTION_REGEX =
|
||||
/^tg:\/\/user\?id=(\d+)(?:&hash=(-?[0-9a-fA-F]+)(?:&|$)|&|$)/
|
||||
const EMOJI_REGEX =
|
||||
/^tg:\/\/emoji\?id=(-?\d+)/
|
||||
const EMOJI_REGEX = /^tg:\/\/emoji\?id=(-?\d+)/
|
||||
|
||||
const TAG_BOLD = '**'
|
||||
const TAG_ITALIC = '__'
|
||||
|
@ -41,7 +45,9 @@ export function md(
|
|||
|
||||
if (typeof it === 'string') it = MarkdownMessageEntityParser.escape(it)
|
||||
else {
|
||||
if (it.mode && it.mode !== 'markdown') { throw new Error(`Incompatible parse mode: ${it.mode}`) }
|
||||
if (it.mode && it.mode !== 'markdown') {
|
||||
throw new Error(`Incompatible parse mode: ${it.mode}`)
|
||||
}
|
||||
it = it.value
|
||||
}
|
||||
|
||||
|
@ -124,12 +130,12 @@ export class MarkdownMessageEntityParser implements IMessageEntityParser {
|
|||
pos += 3
|
||||
continue
|
||||
|
||||
// closed with single or double backtick
|
||||
// i.e. not closed actually! this is totally valid md:
|
||||
// ```javascript
|
||||
// const a = ``;
|
||||
// ```
|
||||
// compensate that `pos` change we made earliers
|
||||
// closed with single or double backtick
|
||||
// i.e. not closed actually! this is totally valid md:
|
||||
// ```javascript
|
||||
// const a = ``;
|
||||
// ```
|
||||
// compensate that `pos` change we made earliers
|
||||
} else if (c === '\n') {
|
||||
pos -= 1
|
||||
}
|
||||
|
@ -165,7 +171,9 @@ export class MarkdownMessageEntityParser implements IMessageEntityParser {
|
|||
|
||||
pos += 1 // )
|
||||
|
||||
if (pos > text.length) { throw new Error('Malformed LINK entity, expected )') }
|
||||
if (pos > text.length) {
|
||||
throw new Error('Malformed LINK entity, expected )')
|
||||
}
|
||||
|
||||
if (url.length) {
|
||||
ent.length = result.length - ent.offset
|
||||
|
@ -200,9 +208,8 @@ export class MarkdownMessageEntityParser implements IMessageEntityParser {
|
|||
).userId = userId
|
||||
}
|
||||
} else if ((m = EMOJI_REGEX.exec(url))) {
|
||||
(
|
||||
ent as tl.Mutable<tl.RawMessageEntityCustomEmoji>
|
||||
)._ = 'messageEntityCustomEmoji'
|
||||
(ent as tl.Mutable<tl.RawMessageEntityCustomEmoji>)._ =
|
||||
'messageEntityCustomEmoji'
|
||||
;(
|
||||
ent as tl.Mutable<tl.RawMessageEntityCustomEmoji>
|
||||
).documentId = Long.fromString(m[1])
|
||||
|
@ -224,10 +231,11 @@ export class MarkdownMessageEntityParser implements IMessageEntityParser {
|
|||
pos += 1
|
||||
insideLink = true
|
||||
if (!('link' in stacks)) stacks.link = []
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
stacks.link.push({
|
||||
offset: result.length,
|
||||
length: 0,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} as any) // other fields are added after the second part
|
||||
continue
|
||||
}
|
||||
|
@ -308,9 +316,7 @@ export class MarkdownMessageEntityParser implements IMessageEntityParser {
|
|||
|
||||
if (isBegin) {
|
||||
stacks[type].push({
|
||||
// this is valid, but idk how to make typescript happy
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
_: ('messageEntity' + type) as any,
|
||||
_: `messageEntity${type}`,
|
||||
offset: result.length,
|
||||
length: 0,
|
||||
})
|
||||
|
@ -379,7 +385,8 @@ export class MarkdownMessageEntityParser implements IMessageEntityParser {
|
|||
end += escapedPos
|
||||
}
|
||||
|
||||
let startTag; let endTag: string
|
||||
let startTag
|
||||
let endTag: string
|
||||
|
||||
switch (type) {
|
||||
case 'bold':
|
||||
|
@ -420,7 +427,7 @@ export class MarkdownMessageEntityParser implements IMessageEntityParser {
|
|||
break
|
||||
case 'emoji':
|
||||
startTag = '['
|
||||
endTag = `](tg://emoji?id=${entity.emojiId})`
|
||||
endTag = `](tg://emoji?id=${entity.emojiId!.toString()})`
|
||||
break
|
||||
default:
|
||||
continue
|
||||
|
|
|
@ -689,7 +689,7 @@ describe('MarkdownMessageEntityParser', () => {
|
|||
|
||||
expect(() => md`${unsafeString}`.value).not.throw(Error)
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
expect(() => md`${unsafeString2}`.value).throw(Error)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"outDir": "./dist"
|
||||
},
|
||||
"include": [
|
||||
"./src"
|
||||
"./src",
|
||||
"./tests",
|
||||
]
|
||||
}
|
||||
|
|
|
@ -112,8 +112,7 @@ export class MtProxyTcpTransport extends BaseTcpTransport {
|
|||
this.packetCodecInitialized = false
|
||||
this._packetCodec.reset()
|
||||
this._packetCodec.removeAllListeners()
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
delete (this as any)._packetCodec
|
||||
delete (this as Partial<MtProxyTcpTransport>)._packetCodec
|
||||
}
|
||||
|
||||
if (!this._packetCodec) {
|
||||
|
@ -155,12 +154,16 @@ export class MtProxyTcpTransport extends BaseTcpTransport {
|
|||
this._socket = connect(
|
||||
this._proxy.port,
|
||||
this._proxy.host,
|
||||
// MTQ-55
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
this._handleConnectFakeTls.bind(this),
|
||||
)
|
||||
} else {
|
||||
this._socket = connect(
|
||||
this._proxy.port,
|
||||
this._proxy.host,
|
||||
// MTQ-55
|
||||
|
||||
this.handleConnect.bind(this),
|
||||
)
|
||||
this._socket.on('data', (data) => this._packetCodec.feed(data))
|
||||
|
@ -219,18 +222,17 @@ export class MtProxyTcpTransport extends BaseTcpTransport {
|
|||
}
|
||||
}
|
||||
|
||||
const packetHandler = async (buf: Buffer): Promise<void> => {
|
||||
try {
|
||||
await checkHelloResponse(buf)
|
||||
const packetHandler = (buf: Buffer): void => {
|
||||
checkHelloResponse(buf)
|
||||
.then(() => {
|
||||
this._socket!.off('data', packetHandler)
|
||||
this._socket!.on('data', (data) =>
|
||||
this._packetCodec.feed(data),
|
||||
)
|
||||
|
||||
this._socket!.on('data', (data) =>
|
||||
this._packetCodec.feed(data),
|
||||
)
|
||||
this._socket!.off('data', packetHandler)
|
||||
this.handleConnect()
|
||||
} catch (e) {
|
||||
this._socket!.emit('error', e)
|
||||
}
|
||||
return this.handleConnect()
|
||||
})
|
||||
.catch((err) => this._socket!.emit('error', err))
|
||||
}
|
||||
|
||||
this._socket!.write(hello)
|
||||
|
|
|
@ -16,7 +16,7 @@ export { SqliteStorage }
|
|||
let nativeCrypto: any
|
||||
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
// eslint-disable-next-line
|
||||
nativeCrypto = require('@mtcute/crypto-node').NodeNativeCryptoProvider
|
||||
} catch (e) {}
|
||||
|
||||
|
@ -57,6 +57,7 @@ export interface NodeTelegramClientOptions
|
|||
export class NodeTelegramClient extends TelegramClient {
|
||||
constructor(opts: NodeTelegramClientOptions) {
|
||||
super({
|
||||
// eslint-disable-next-line
|
||||
crypto: nativeCrypto ? () => new nativeCrypto() : undefined,
|
||||
...opts,
|
||||
storage:
|
||||
|
@ -68,7 +69,9 @@ export class NodeTelegramClient extends TelegramClient {
|
|||
this.registerParseMode(new HtmlMessageEntityParser())
|
||||
this.registerParseMode(new MarkdownMessageEntityParser())
|
||||
|
||||
if (opts.defaultParseMode) { this.setDefaultParseMode(opts.defaultParseMode) }
|
||||
if (opts.defaultParseMode) {
|
||||
this.setDefaultParseMode(opts.defaultParseMode)
|
||||
}
|
||||
}
|
||||
|
||||
private _rl?: RlInterface
|
||||
|
@ -98,7 +101,9 @@ export class NodeTelegramClient extends TelegramClient {
|
|||
if (!params.phone) params.phone = () => this.input('Phone > ')
|
||||
if (!params.code) params.code = () => this.input('Code > ')
|
||||
|
||||
if (!params.password) { params.password = () => this.input('2FA password > ') }
|
||||
if (!params.password) {
|
||||
params.password = () => this.input('2FA password > ')
|
||||
}
|
||||
}
|
||||
|
||||
return super.start(params).then((user) => {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// ^^ because of this._socket. we know it's not null, almost everywhere, but TS doesn't
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
import { normalize } from 'ip6'
|
||||
import { connect } from 'net'
|
||||
|
||||
|
@ -115,8 +115,12 @@ function buildSocks5Auth(username: string, password: string) {
|
|||
const usernameBuf = Buffer.from(username)
|
||||
const passwordBuf = Buffer.from(password)
|
||||
|
||||
if (usernameBuf.length > 255) { throw new Error(`Too long username (${usernameBuf.length} > 255)`) }
|
||||
if (passwordBuf.length > 255) { throw new Error(`Too long password (${passwordBuf.length} > 255)`) }
|
||||
if (usernameBuf.length > 255) {
|
||||
throw new Error(`Too long username (${usernameBuf.length} > 255)`)
|
||||
}
|
||||
if (passwordBuf.length > 255) {
|
||||
throw new Error(`Too long password (${passwordBuf.length} > 255)`)
|
||||
}
|
||||
|
||||
const buf = Buffer.alloc(3 + usernameBuf.length + passwordBuf.length)
|
||||
buf[0] = 0x01 // VER of auth
|
||||
|
@ -129,7 +133,8 @@ function buildSocks5Auth(username: string, password: string) {
|
|||
}
|
||||
|
||||
function writeIpv6(ip: string, buf: Buffer, offset: number): void {
|
||||
ip = normalize(ip)
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
||||
ip = normalize(ip) as string
|
||||
const parts = ip.split(':')
|
||||
|
||||
if (parts.length !== 8) {
|
||||
|
@ -193,9 +198,14 @@ export abstract class BaseSocksTcpTransport extends BaseTcpTransport {
|
|||
constructor(proxy: SocksProxySettings) {
|
||||
super()
|
||||
|
||||
if (proxy.version != null && proxy.version !== 4 && proxy.version !== 5) {
|
||||
if (
|
||||
proxy.version != null &&
|
||||
proxy.version !== 4 &&
|
||||
proxy.version !== 5
|
||||
) {
|
||||
throw new SocksProxyConnectionError(
|
||||
proxy,
|
||||
|
||||
`Invalid SOCKS version: ${proxy.version}`,
|
||||
)
|
||||
}
|
||||
|
@ -204,7 +214,9 @@ export abstract class BaseSocksTcpTransport extends BaseTcpTransport {
|
|||
}
|
||||
|
||||
connect(dc: tl.RawDcOption): void {
|
||||
if (this._state !== TransportState.Idle) { throw new Error('Transport is not IDLE') }
|
||||
if (this._state !== TransportState.Idle) {
|
||||
throw new Error('Transport is not IDLE')
|
||||
}
|
||||
|
||||
if (!this.packetCodecInitialized) {
|
||||
this._packetCodec.on('error', (err) => this.emit('error', err))
|
||||
|
|
|
@ -359,7 +359,7 @@ export class SqliteStorage implements ITelegramStorage, IStateStorage {
|
|||
private _getFromKv<T>(key: string): T | null {
|
||||
const row = this._statements.getKv.get(key) as { value: string } | null
|
||||
|
||||
return row ? JSON.parse(row.value) : null
|
||||
return row ? (JSON.parse(row.value) as T) : null
|
||||
}
|
||||
|
||||
private _setToKv(key: string, value: unknown, now = false): void {
|
||||
|
@ -375,7 +375,7 @@ export class SqliteStorage implements ITelegramStorage, IStateStorage {
|
|||
}
|
||||
|
||||
private _runMany!: (stmts: [sqlite3.Statement, unknown[]][]) => void
|
||||
private _updateManyPeers!: (updates: unknown[]) => void
|
||||
private _updateManyPeers!: (updates: unknown[][]) => void
|
||||
|
||||
private _upgradeDatabase(from: number): void {
|
||||
if (from < 2 || from > CURRENT_VERSION) {
|
||||
|
@ -461,14 +461,16 @@ export class SqliteStorage implements ITelegramStorage, IStateStorage {
|
|||
}
|
||||
|
||||
// helper methods
|
||||
this._runMany = this._db.transaction((stmts) => {
|
||||
stmts.forEach((stmt: [sqlite3.Statement, unknown[]]) => {
|
||||
stmt[0].run(stmt[1])
|
||||
})
|
||||
})
|
||||
this._runMany = this._db.transaction(
|
||||
(stmts: [sqlite3.Statement, unknown[]][]) => {
|
||||
stmts.forEach((stmt) => {
|
||||
stmt[0].run(stmt[1])
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
this._updateManyPeers = this._db.transaction((data) => {
|
||||
data.forEach((it: unknown[]) => {
|
||||
this._updateManyPeers = this._db.transaction((data: unknown[][]) => {
|
||||
data.forEach((it: unknown) => {
|
||||
this._statements.updateCachedEnt.run(it)
|
||||
})
|
||||
})
|
||||
|
@ -727,7 +729,7 @@ export class SqliteStorage implements ITelegramStorage, IStateStorage {
|
|||
|
||||
// IStateStorage implementation
|
||||
|
||||
getState(key: string, parse = true): unknown | null {
|
||||
getState(key: string, parse = true): unknown {
|
||||
let val: FsmItem | undefined = this._fsmCache?.get(key)
|
||||
const cached = val
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@ export function gzipInflate(buf: Buffer): Buffer {
|
|||
return typedArrayToBuffer(inflate(buf))
|
||||
}
|
||||
|
||||
const ERROR_SIZE_LIMIT_REACHED = 'ERR_SIZE_LIMIT_REACHED'
|
||||
|
||||
class DeflateLimited extends Deflate {
|
||||
constructor(readonly limit: number) {
|
||||
super()
|
||||
|
@ -21,7 +23,9 @@ class DeflateLimited extends Deflate {
|
|||
this._size += (chunk as Uint8Array).length
|
||||
|
||||
if (this._size > this.limit) {
|
||||
throw 'ERR_SIZE'
|
||||
// caught locally
|
||||
// eslint-disable-next-line @typescript-eslint/no-throw-literal
|
||||
throw ERROR_SIZE_LIMIT_REACHED
|
||||
}
|
||||
|
||||
super.onData(chunk)
|
||||
|
@ -36,9 +40,9 @@ export function gzipDeflate(buf: Buffer, maxRatio?: number): Buffer | null {
|
|||
try {
|
||||
deflator.push(buf, true)
|
||||
} catch (e) {
|
||||
if (e === 'ERR_SIZE') return null
|
||||
if (e === ERROR_SIZE_LIMIT_REACHED) return null
|
||||
throw e
|
||||
}
|
||||
|
||||
return typedArrayToBuffer(deflator.result as Uint8Array)
|
||||
return typedArrayToBuffer(deflator.result)
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// eslint-disable-next-line max-len
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-return */
|
||||
import { expect } from 'chai'
|
||||
import { randomBytes } from 'crypto'
|
||||
import Long from 'long'
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
import { expect } from 'chai'
|
||||
import { randomBytes } from 'crypto'
|
||||
import Long from 'long'
|
||||
|
|
|
@ -5,5 +5,6 @@
|
|||
},
|
||||
"include": [
|
||||
"./src",
|
||||
"./tests",
|
||||
]
|
||||
}
|
||||
|
|
|
@ -188,6 +188,23 @@ export function generateReaderCodeForTlEntries(
|
|||
ret += generateReaderCodeForTlEntry(entry, params) + '\n'
|
||||
})
|
||||
|
||||
const usedInBareVector: Record<string, 1> = {}
|
||||
ret.replace(
|
||||
new RegExp(`(?<=r\\.vector\\(${variableName}\\[)(\\d+)(?=])`, 'g'),
|
||||
(_, id: string) => {
|
||||
usedInBareVector[id] = 1
|
||||
|
||||
return _
|
||||
},
|
||||
)
|
||||
|
||||
for (const id of Object.keys(usedInBareVector)) {
|
||||
ret = ret.replace(
|
||||
new RegExp(`(?<=^${id}:function\\()r(?=\\))`, 'gm'),
|
||||
'r=this',
|
||||
)
|
||||
}
|
||||
|
||||
if (params.includeMethodResults) {
|
||||
ret += '_results:{\n'
|
||||
|
||||
|
|
|
@ -60,7 +60,10 @@ export function generateWriterCodeForTlEntry(
|
|||
if (entry.id === 0) entry.id = computeConstructorIdFromEntry(entry)
|
||||
|
||||
const name = bare ? entry.id : `'${entry.name}'`
|
||||
let ret = `${name}:function(w${entry.arguments.length ? ',v' : ''}){`
|
||||
const defaultWriter = bare ? '=this' : ''
|
||||
let ret = `${name}:function(w${defaultWriter}${
|
||||
entry.arguments.length ? ',v' : ''
|
||||
}){`
|
||||
|
||||
if (!bare) ret += `w.uint(${entry.id});`
|
||||
|
||||
|
|
|
@ -5,7 +5,8 @@ import { generateWriterCodeForTlEntries } from './codegen/writer'
|
|||
import { parseTlToEntries } from './parse'
|
||||
|
||||
function evalForResult<T>(js: string): T {
|
||||
return new Function(js)()
|
||||
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
||||
return new Function(js)() as T
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -57,7 +58,7 @@ export function patchRuntimeTlSchema(
|
|||
},
|
||||
// ts is not smart enough
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
writerMap: {
|
||||
...writers,
|
||||
...newWriters,
|
||||
|
|
|
@ -68,9 +68,9 @@ export function stringifyArgumentType(
|
|||
if (!modifiers) return type
|
||||
let ret = type
|
||||
|
||||
if (modifiers?.isBareUnion) ret = `%${ret}`
|
||||
if (modifiers?.isVector) ret = `Vector<${ret}>`
|
||||
else if (modifiers?.isBareVector) ret = `vector<${ret}>`
|
||||
if (modifiers.isBareUnion) ret = `%${ret}`
|
||||
if (modifiers.isVector) ret = `Vector<${ret}>`
|
||||
else if (modifiers.isBareVector) ret = `vector<${ret}>`
|
||||
if (modifiers.predicate) ret = `${modifiers.predicate}?${ret}`
|
||||
|
||||
return ret
|
||||
|
|
|
@ -91,8 +91,8 @@ describe('mergeTlSchemas', () => {
|
|||
).eq(expected.join('\n'))
|
||||
}
|
||||
|
||||
it('merges different constructors', () => {
|
||||
test(
|
||||
it('merges different constructors', async () => {
|
||||
await test(
|
||||
[
|
||||
['testClass = Test;'],
|
||||
['testClass2 = Test;'],
|
||||
|
@ -106,8 +106,8 @@ describe('mergeTlSchemas', () => {
|
|||
)
|
||||
})
|
||||
|
||||
it('merges true flags in constructors', () => {
|
||||
test(
|
||||
it('merges true flags in constructors', async () => {
|
||||
await test(
|
||||
[
|
||||
['test foo:flags.0?true = Test;'],
|
||||
['test bar:flags.0?true = Test;'],
|
||||
|
@ -118,8 +118,8 @@ describe('mergeTlSchemas', () => {
|
|||
)
|
||||
})
|
||||
|
||||
it('resolves conflict using user-provided option', () => {
|
||||
test(
|
||||
it('resolves conflict using user-provided option', async () => {
|
||||
await test(
|
||||
[
|
||||
['test foo:int = Test;'],
|
||||
['test bar:int = Test;'],
|
||||
|
@ -128,7 +128,7 @@ describe('mergeTlSchemas', () => {
|
|||
0,
|
||||
'test foo:int = Test;',
|
||||
)
|
||||
test(
|
||||
await test(
|
||||
[
|
||||
['test foo:int = Test;'],
|
||||
['test bar:int = Test;'],
|
||||
|
@ -137,11 +137,15 @@ describe('mergeTlSchemas', () => {
|
|||
1,
|
||||
'test foo:int = Test;',
|
||||
)
|
||||
test([['test foo:int = Test;'], [], ['test bar:int = Test;']], 1, '')
|
||||
await test(
|
||||
[['test foo:int = Test;'], [], ['test bar:int = Test;']],
|
||||
1,
|
||||
'',
|
||||
)
|
||||
})
|
||||
|
||||
it('merges comments', () => {
|
||||
test(
|
||||
it('merges comments', async () => {
|
||||
await test(
|
||||
[
|
||||
['test foo:flags.0?true = Test;'],
|
||||
['// test ctor', 'test bar:flags.0?true = Test;'],
|
||||
|
@ -156,8 +160,8 @@ describe('mergeTlSchemas', () => {
|
|||
)
|
||||
})
|
||||
|
||||
it('merges arguments comments', () => {
|
||||
test(
|
||||
it('merges arguments comments', async () => {
|
||||
await test(
|
||||
[
|
||||
['test foo:flags.0?true = Test;'],
|
||||
['// @bar bar comment', 'test bar:flags.0?true = Test;'],
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"outDir": "./dist"
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*.ts"
|
||||
"./src/**/*.ts",
|
||||
"./tests/**/*.ts"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ import {
|
|||
DOC_CACHE_FILE,
|
||||
} from './constants'
|
||||
import { applyDescriptionsYamlFile } from './process-descriptions-yaml'
|
||||
import { packTlSchema, unpackTlSchema } from './schema'
|
||||
import { packTlSchema, TlPackedSchema, unpackTlSchema } from './schema'
|
||||
import { fetchRetry } from './utils'
|
||||
|
||||
export interface CachedDocumentationEntry {
|
||||
|
@ -38,7 +38,10 @@ export interface CachedDocumentation {
|
|||
unions: Record<string, string>
|
||||
}
|
||||
|
||||
function normalizeLinks(url: string, el: cheerio.Cheerio<cheerio.Element>): void {
|
||||
function normalizeLinks(
|
||||
url: string,
|
||||
el: cheerio.Cheerio<cheerio.Element>,
|
||||
): void {
|
||||
el.find('a').each((i, _it) => {
|
||||
const it = cheerio.default(_it)
|
||||
let href = it.attr('href')
|
||||
|
@ -314,7 +317,7 @@ export async function getCachedDocumentation(): Promise<CachedDocumentation | nu
|
|||
try {
|
||||
const file = await readFile(DOC_CACHE_FILE, 'utf8')
|
||||
|
||||
return JSON.parse(file)
|
||||
return JSON.parse(file) as CachedDocumentation
|
||||
} catch (e: unknown) {
|
||||
if (e && typeof e === 'object' && 'code' in e && e.code === 'ENOENT') {
|
||||
return null
|
||||
|
@ -355,7 +358,9 @@ async function main() {
|
|||
|
||||
if (act === 1) {
|
||||
const [schema, layer] = unpackTlSchema(
|
||||
JSON.parse(await readFile(API_SCHEMA_JSON_FILE, 'utf8')),
|
||||
JSON.parse(
|
||||
await readFile(API_SCHEMA_JSON_FILE, 'utf8'),
|
||||
) as TlPackedSchema,
|
||||
)
|
||||
cached = await fetchDocumentation(schema, layer)
|
||||
}
|
||||
|
@ -381,7 +386,9 @@ async function main() {
|
|||
}
|
||||
|
||||
const [schema, layer] = unpackTlSchema(
|
||||
JSON.parse(await readFile(API_SCHEMA_JSON_FILE, 'utf8')),
|
||||
JSON.parse(
|
||||
await readFile(API_SCHEMA_JSON_FILE, 'utf8'),
|
||||
) as TlPackedSchema,
|
||||
)
|
||||
|
||||
applyDocumentation(schema, cached)
|
||||
|
|
|
@ -36,7 +36,7 @@ import {
|
|||
fetchDocumentation,
|
||||
getCachedDocumentation,
|
||||
} from './documentation'
|
||||
import { packTlSchema, unpackTlSchema } from './schema'
|
||||
import { packTlSchema, TlPackedSchema, unpackTlSchema } from './schema'
|
||||
import { fetchRetry } from './utils'
|
||||
|
||||
import { bumpVersion } from '~scripts/version'
|
||||
|
@ -137,8 +137,10 @@ async function updatePackageVersion(
|
|||
rl: readline.Interface,
|
||||
currentLayer: number,
|
||||
) {
|
||||
const packageJson = JSON.parse(await readFile(PACKAGE_JSON_FILE, 'utf8'))
|
||||
const version: string = packageJson.version
|
||||
const packageJson = JSON.parse(
|
||||
await readFile(PACKAGE_JSON_FILE, 'utf8'),
|
||||
) as { version: string }
|
||||
const version = packageJson.version
|
||||
let [major, minor] = version.split('.').map((i) => parseInt(i))
|
||||
|
||||
if (major === currentLayer) {
|
||||
|
@ -168,7 +170,7 @@ async function overrideInt53(schema: TlFullSchema): Promise<void> {
|
|||
|
||||
const config = JSON.parse(
|
||||
await readFile(join(__dirname, '../data/int53-overrides.json'), 'utf8'),
|
||||
)
|
||||
) as Record<string, Record<string, string[]>>
|
||||
|
||||
schema.entries.forEach((entry) => {
|
||||
const overrides: string[] | undefined = config[entry.kind][entry.name]
|
||||
|
@ -274,8 +276,8 @@ async function main() {
|
|||
|
||||
console.log(
|
||||
'Conflict detected at %s %s:',
|
||||
nonEmptyOptions[0].entry?.kind,
|
||||
nonEmptyOptions[0].entry?.name,
|
||||
nonEmptyOptions[0].entry.kind,
|
||||
nonEmptyOptions[0].entry.name,
|
||||
)
|
||||
console.log('0. Remove')
|
||||
nonEmptyOptions.forEach((opt, idx) => {
|
||||
|
@ -329,7 +331,9 @@ async function main() {
|
|||
|
||||
console.log('Writing diff to file...')
|
||||
const oldSchema = unpackTlSchema(
|
||||
JSON.parse(await readFile(API_SCHEMA_JSON_FILE, 'utf8')),
|
||||
JSON.parse(
|
||||
await readFile(API_SCHEMA_JSON_FILE, 'utf8'),
|
||||
) as TlPackedSchema,
|
||||
)
|
||||
await writeFile(
|
||||
API_SCHEMA_DIFF_JSON_FILE,
|
||||
|
|
|
@ -83,6 +83,13 @@ const virtualErrors: TlError[] = [
|
|||
]
|
||||
virtualErrors.forEach((it) => (it.virtual = true))
|
||||
|
||||
interface TelegramErrorsSpec {
|
||||
errors: Record<string, Record<string, string[]>>
|
||||
descriptions: Record<string, string>
|
||||
user_only: string[]
|
||||
bot_only: string[]
|
||||
}
|
||||
|
||||
async function fetchFromTelegram(errors: TlErrors) {
|
||||
const page = await fetch(ERRORS_PAGE_TG).then((it) => it.text())
|
||||
const jsonUrl = page.match(
|
||||
|
@ -90,9 +97,9 @@ async function fetchFromTelegram(errors: TlErrors) {
|
|||
)?.[1]
|
||||
if (!jsonUrl) throw new Error('Cannot find JSON URL')
|
||||
|
||||
const json = await fetch(new URL(jsonUrl, ERRORS_PAGE_TG)).then((it) =>
|
||||
const json = (await fetch(new URL(jsonUrl, ERRORS_PAGE_TG)).then((it) =>
|
||||
it.json(),
|
||||
)
|
||||
)) as TelegramErrorsSpec
|
||||
|
||||
// since nobody fucking guarantees that .descriptions
|
||||
// will have description for each described here (or vice versa),
|
||||
|
@ -120,7 +127,7 @@ async function fetchFromTelegram(errors: TlErrors) {
|
|||
errors.throws[method] = []
|
||||
}
|
||||
|
||||
if (errors.throws[method].indexOf(name) === -1) {
|
||||
if (!errors.throws[method].includes(name)) {
|
||||
errors.throws[method].push(name)
|
||||
}
|
||||
}
|
||||
|
@ -185,14 +192,17 @@ async function fetchFromTelethon(errors: TlErrors) {
|
|||
// names for better code insights
|
||||
// we also prefer description from telegram, if it's available and doesn't use placeholders
|
||||
if (description) {
|
||||
const desc = description.replace(/{([a-z0-9_]+)}/gi, (_, name) => {
|
||||
if (!obj._paramNames) {
|
||||
obj._paramNames = []
|
||||
}
|
||||
obj._paramNames.push(name)
|
||||
const desc = description.replace(
|
||||
/{([a-z0-9_]+)}/gi,
|
||||
(_, name: string) => {
|
||||
if (!obj._paramNames) {
|
||||
obj._paramNames = []
|
||||
}
|
||||
obj._paramNames.push(name)
|
||||
|
||||
return '%d'
|
||||
})
|
||||
return '%d'
|
||||
},
|
||||
)
|
||||
|
||||
if (!obj.description || obj._paramNames?.length) {
|
||||
obj.description = desc
|
||||
|
@ -202,13 +212,24 @@ async function fetchFromTelethon(errors: TlErrors) {
|
|||
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
parser
|
||||
.on('data', ({ name, codes, description }) =>
|
||||
addError(name, codes, description),
|
||||
.on(
|
||||
'data',
|
||||
({
|
||||
name,
|
||||
codes,
|
||||
description,
|
||||
}: {
|
||||
name: string
|
||||
codes: string
|
||||
description: string
|
||||
}) => addError(name, codes, description),
|
||||
)
|
||||
.on('end', resolve)
|
||||
.on('error', reject)
|
||||
|
||||
csv.text().then((it) => parser.write(it)).catch(reject)
|
||||
csv.text()
|
||||
.then((it) => parser.write(it))
|
||||
.catch(reject)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -229,7 +250,7 @@ async function main() {
|
|||
await fetchFromTelethon(errors)
|
||||
|
||||
virtualErrors.forEach((err) => {
|
||||
if (errors.errors[err.name]) {
|
||||
if (err.name in errors.errors) {
|
||||
console.log(`Error ${err.name} already exists and is not virtual`)
|
||||
|
||||
return
|
||||
|
|
|
@ -29,13 +29,13 @@ async function main() {
|
|||
// remove manually parsed types
|
||||
entries = entries.filter(
|
||||
(it) =>
|
||||
[
|
||||
![
|
||||
'mt_msg_container',
|
||||
'mt_message',
|
||||
'mt_msg_copy',
|
||||
'mt_gzip_packed',
|
||||
'mt_rpc_result',
|
||||
].indexOf(it.name) === -1,
|
||||
].includes(it.name),
|
||||
)
|
||||
|
||||
// mtproto is handled internally, for simplicity we make them all classes
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
generateTypescriptDefinitionsForTlSchema,
|
||||
generateWriterCodeForTlEntries,
|
||||
parseFullTlSchema,
|
||||
TlEntry,
|
||||
TlErrors,
|
||||
TlFullSchema,
|
||||
} from '@mtcute/tl-utils'
|
||||
|
@ -16,7 +17,7 @@ import {
|
|||
ESM_PRELUDE,
|
||||
MTP_SCHEMA_JSON_FILE,
|
||||
} from './constants'
|
||||
import { unpackTlSchema } from './schema'
|
||||
import { TlPackedSchema, unpackTlSchema } from './schema'
|
||||
|
||||
const OUT_TYPINGS_FILE = join(__dirname, '../index.d.ts')
|
||||
const OUT_TYPINGS_JS_FILE = join(__dirname, '../index.js')
|
||||
|
@ -92,15 +93,17 @@ async function generateWriters(
|
|||
}
|
||||
|
||||
async function main() {
|
||||
const errors: TlErrors = JSON.parse(
|
||||
const errors = JSON.parse(
|
||||
await readFile(ERRORS_JSON_FILE, 'utf8'),
|
||||
)
|
||||
) as TlErrors
|
||||
|
||||
const [apiSchema, apiLayer] = unpackTlSchema(
|
||||
JSON.parse(await readFile(API_SCHEMA_JSON_FILE, 'utf8')),
|
||||
JSON.parse(
|
||||
await readFile(API_SCHEMA_JSON_FILE, 'utf8'),
|
||||
) as TlPackedSchema,
|
||||
)
|
||||
const mtpSchema = parseFullTlSchema(
|
||||
JSON.parse(await readFile(MTP_SCHEMA_JSON_FILE, 'utf8')),
|
||||
JSON.parse(await readFile(MTP_SCHEMA_JSON_FILE, 'utf8')) as TlEntry[],
|
||||
)
|
||||
|
||||
await generateTypings(apiSchema, apiLayer, mtpSchema, errors)
|
||||
|
|
|
@ -66,7 +66,7 @@ export function applyDescriptionsYamlFile(
|
|||
prefix: string,
|
||||
) {
|
||||
for (const name in obj) {
|
||||
objIndex[prefix + name] = obj[name]
|
||||
objIndex[prefix + name] = obj[name]!
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,7 @@ export function applyDescriptionsYamlFile(
|
|||
|
||||
// process byObjects
|
||||
for (const name in byObjects) {
|
||||
const rules = byObjects[name]
|
||||
const rules = byObjects[name]!
|
||||
const obj = objIndex[name]
|
||||
|
||||
if (!obj) continue
|
||||
|
@ -88,7 +88,7 @@ export function applyDescriptionsYamlFile(
|
|||
if (rules.arguments) {
|
||||
for (const arg in rules.arguments) {
|
||||
const repl = unwrapMaybe(
|
||||
rules.arguments[arg],
|
||||
rules.arguments[arg]!,
|
||||
obj.arguments !== undefined && arg in obj.arguments,
|
||||
)
|
||||
|
||||
|
@ -102,15 +102,14 @@ export function applyDescriptionsYamlFile(
|
|||
|
||||
// process byArguments
|
||||
for (const i in objIndex) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const obj = objIndex[i] as any
|
||||
const obj = objIndex[i]!
|
||||
|
||||
for (const arg in byArguments) {
|
||||
if (obj.arguments && !(arg in obj.arguments)) continue
|
||||
|
||||
const repl = unwrapMaybe(
|
||||
byArguments[arg],
|
||||
Boolean(obj.arguments) && arg in obj.arguments,
|
||||
byArguments[arg]!,
|
||||
Boolean(obj.arguments && arg in obj.arguments),
|
||||
)
|
||||
|
||||
if (repl) {
|
||||
|
@ -126,7 +125,7 @@ export function applyDescriptionsYamlFile(
|
|||
|
||||
if (!rule._cached) {
|
||||
let flags = rule.flags || ''
|
||||
if (flags.indexOf('g') === -1) flags += 'g'
|
||||
if (!flags.includes('g')) flags += 'g'
|
||||
|
||||
rule._cached = new RegExp(rule.regex, flags)
|
||||
}
|
||||
|
@ -135,7 +134,7 @@ export function applyDescriptionsYamlFile(
|
|||
}
|
||||
|
||||
for (const i in objIndex) {
|
||||
const obj = objIndex[i]
|
||||
const obj = objIndex[i]!
|
||||
|
||||
byRegex.forEach((rule) => {
|
||||
obj.comment = applyRegex(obj.comment, rule)
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
"./binary/reader.d.ts",
|
||||
"./binary/writer.d.ts",
|
||||
"./binary/rsa-keys.d.ts",
|
||||
"./scripts"
|
||||
"./scripts",
|
||||
"./tests/types.ts"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -157,6 +157,9 @@ importers:
|
|||
'@types/ws':
|
||||
specifier: 8.5.4
|
||||
version: 8.5.4
|
||||
exit-hook:
|
||||
specifier: ^4.0.0
|
||||
version: 4.0.0
|
||||
ws:
|
||||
specifier: 8.13.0
|
||||
version: 8.13.0
|
||||
|
@ -2442,6 +2445,11 @@ packages:
|
|||
strip-final-newline: 3.0.0
|
||||
dev: true
|
||||
|
||||
/exit-hook@4.0.0:
|
||||
resolution: {integrity: sha512-Fqs7ChZm72y40wKjOFXBKg7nJZvQJmewP5/7LtePDdnah/+FH9Hp5sgMujSCMPXlxOAW2//1jrW9pnsY7o20vQ==}
|
||||
engines: {node: '>=18'}
|
||||
dev: true
|
||||
|
||||
/exit-on-epipe@1.0.1:
|
||||
resolution: {integrity: sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==}
|
||||
engines: {node: '>=0.8'}
|
||||
|
|
Loading…
Reference in a new issue