build: updated to layer 139
didn't add any new layers' features, only bumped layer
This commit is contained in:
parent
ec736f8590
commit
9493759572
48 changed files with 651 additions and 405 deletions
|
@ -14,7 +14,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/long": "^4.0.1",
|
"@types/long": "^4.0.1",
|
||||||
"@types/node": "^15.12.1",
|
"@types/node": "^15.12.1",
|
||||||
"@mtcute/tl": "~134.0",
|
"@mtcute/tl": "~139.0",
|
||||||
"@mtcute/core": "^1.0.0",
|
"@mtcute/core": "^1.0.0",
|
||||||
"@mtcute/file-id": "^1.0.0",
|
"@mtcute/file-id": "^1.0.0",
|
||||||
"eager-async-pool": "^1.0.0",
|
"eager-async-pool": "^1.0.0",
|
||||||
|
|
|
@ -5,7 +5,6 @@ export {
|
||||||
tl,
|
tl,
|
||||||
defaultDcs
|
defaultDcs
|
||||||
} from '@mtcute/core'
|
} from '@mtcute/core'
|
||||||
export * from '@mtcute/tl/errors'
|
|
||||||
|
|
||||||
export * from './types'
|
export * from './types'
|
||||||
export * from './client'
|
export * from './client'
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { TelegramClient } from '../../client'
|
import { TelegramClient } from '../../client'
|
||||||
import { tl } from '@mtcute/tl'
|
|
||||||
|
|
||||||
// @extension
|
// @extension
|
||||||
interface AuthState {
|
interface AuthState {
|
||||||
|
|
|
@ -11,15 +11,7 @@ import {
|
||||||
resolveMaybeDynamic,
|
resolveMaybeDynamic,
|
||||||
normalizePhoneNumber,
|
normalizePhoneNumber,
|
||||||
} from '../../utils/misc-utils'
|
} from '../../utils/misc-utils'
|
||||||
import {
|
import { tl } from '@mtcute/tl'
|
||||||
AuthKeyUnregisteredError,
|
|
||||||
PasswordHashInvalidError,
|
|
||||||
PhoneCodeEmptyError,
|
|
||||||
PhoneCodeExpiredError,
|
|
||||||
PhoneCodeHashEmptyError,
|
|
||||||
PhoneCodeInvalidError,
|
|
||||||
SessionPasswordNeededError,
|
|
||||||
} from '@mtcute/tl/errors'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start the client in an interactive and declarative manner,
|
* Start the client in an interactive and declarative manner,
|
||||||
|
@ -174,7 +166,7 @@ export async function start(
|
||||||
|
|
||||||
return me
|
return me
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (!(e instanceof AuthKeyUnregisteredError)) throw e
|
if (!(e instanceof tl.errors.AuthKeyUnregisteredError)) throw e
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!params.phone && !params.botToken)
|
if (!params.phone && !params.botToken)
|
||||||
|
@ -215,19 +207,19 @@ export async function start(
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const code = await resolveMaybeDynamic(params.code)
|
const code = await resolveMaybeDynamic(params.code)
|
||||||
if (!code) throw new PhoneCodeEmptyError()
|
if (!code) throw new tl.errors.PhoneCodeEmptyError()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
result = await this.signIn(phone, sentCode.phoneCodeHash, code)
|
result = await this.signIn(phone, sentCode.phoneCodeHash, code)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof SessionPasswordNeededError) {
|
if (e instanceof tl.errors.SessionPasswordNeededError) {
|
||||||
has2fa = true
|
has2fa = true
|
||||||
break
|
break
|
||||||
} else if (
|
} else if (
|
||||||
e instanceof PhoneCodeEmptyError ||
|
e instanceof tl.errors.PhoneCodeEmptyError ||
|
||||||
e instanceof PhoneCodeExpiredError ||
|
e instanceof tl.errors.PhoneCodeExpiredError ||
|
||||||
e instanceof PhoneCodeHashEmptyError ||
|
e instanceof tl.errors.PhoneCodeHashEmptyError ||
|
||||||
e instanceof PhoneCodeInvalidError
|
e instanceof tl.errors.PhoneCodeInvalidError
|
||||||
) {
|
) {
|
||||||
if (typeof params.code !== 'function') {
|
if (typeof params.code !== 'function') {
|
||||||
throw new MtArgumentError('Provided code was invalid')
|
throw new MtArgumentError('Provided code was invalid')
|
||||||
|
@ -263,7 +255,7 @@ export async function start(
|
||||||
throw new MtArgumentError('Provided password was invalid')
|
throw new MtArgumentError('Provided password was invalid')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e instanceof PasswordHashInvalidError) {
|
if (e instanceof tl.errors.PasswordHashInvalidError) {
|
||||||
if (params.invalidCodeCallback) {
|
if (params.invalidCodeCallback) {
|
||||||
await params.invalidCodeCallback('password')
|
await params.invalidCodeCallback('password')
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -2,33 +2,32 @@ import { TelegramClient } from '../../client'
|
||||||
import { InputPeerLike, MtInvalidPeerTypeError } from '../../types'
|
import { InputPeerLike, MtInvalidPeerTypeError } from '../../types'
|
||||||
import {
|
import {
|
||||||
normalizeToInputChannel,
|
normalizeToInputChannel,
|
||||||
normalizeToInputUser,
|
normalizeToInputPeer,
|
||||||
} from '../../utils/peer-utils'
|
} from '../../utils/peer-utils'
|
||||||
import { tl } from '@mtcute/tl'
|
import { tl } from '@mtcute/tl'
|
||||||
import { createDummyUpdate } from '../../utils/updates-utils'
|
import { createDummyUpdate } from '../../utils/updates-utils'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete all messages of a user in a supergroup
|
* Delete all messages of a user (or channel) in a supergroup
|
||||||
*
|
*
|
||||||
* @param chatId Chat ID
|
* @param chatId Chat ID
|
||||||
* @param userId User ID
|
* @param participantId User/channel ID
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
export async function deleteUserHistory(
|
export async function deleteUserHistory(
|
||||||
this: TelegramClient,
|
this: TelegramClient,
|
||||||
chatId: InputPeerLike,
|
chatId: InputPeerLike,
|
||||||
userId: InputPeerLike
|
participantId: InputPeerLike
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const channel = normalizeToInputChannel(await this.resolvePeer(chatId))
|
const channel = normalizeToInputChannel(await this.resolvePeer(chatId))
|
||||||
if (!channel) throw new MtInvalidPeerTypeError(chatId, 'channel')
|
if (!channel) throw new MtInvalidPeerTypeError(chatId, 'channel')
|
||||||
|
|
||||||
const user = normalizeToInputUser(await this.resolvePeer(userId))
|
const peer = normalizeToInputPeer(await this.resolvePeer(participantId))
|
||||||
if (!user) throw new MtInvalidPeerTypeError(userId, 'user')
|
|
||||||
|
|
||||||
const res = await this.call({
|
const res = await this.call({
|
||||||
_: 'channels.deleteUserHistory',
|
_: 'channels.deleteParticipantHistory',
|
||||||
channel,
|
channel,
|
||||||
userId: user,
|
participant: peer,
|
||||||
})
|
})
|
||||||
|
|
||||||
this._handleUpdate(
|
this._handleUpdate(
|
||||||
|
|
|
@ -9,7 +9,6 @@ import {
|
||||||
import { assertTypeIs } from '../../utils/type-assertion'
|
import { assertTypeIs } from '../../utils/type-assertion'
|
||||||
import { tl } from '@mtcute/tl'
|
import { tl } from '@mtcute/tl'
|
||||||
import { ChatMember } from '../../types'
|
import { ChatMember } from '../../types'
|
||||||
import { UserNotParticipantError } from '@mtcute/tl/errors'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get information about a single chat member
|
* Get information about a single chat member
|
||||||
|
@ -59,7 +58,7 @@ export async function getChatMember(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new UserNotParticipantError()
|
throw new tl.errors.UserNotParticipantError()
|
||||||
} else if (isInputPeerChannel(chat)) {
|
} else if (isInputPeerChannel(chat)) {
|
||||||
const res = await this.call({
|
const res = await this.call({
|
||||||
_: 'channels.getParticipant',
|
_: 'channels.getParticipant',
|
||||||
|
|
|
@ -44,7 +44,7 @@ export async function getFullChat(
|
||||||
|
|
||||||
const peer = await this.resolvePeer(chatId)
|
const peer = await this.resolvePeer(chatId)
|
||||||
|
|
||||||
let res: tl.messages.TypeChatFull | tl.TypeUserFull
|
let res: tl.messages.TypeChatFull | tl.users.TypeUserFull
|
||||||
if (isInputPeerChannel(peer)) {
|
if (isInputPeerChannel(peer)) {
|
||||||
res = await this.call({
|
res = await this.call({
|
||||||
_: 'channels.getFullChannel',
|
_: 'channels.getFullChannel',
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { TelegramClient } from '../../client'
|
import { TelegramClient } from '../../client'
|
||||||
import { determinePartSize } from '../../utils/file-utils'
|
import { determinePartSize } from '../../utils/file-utils'
|
||||||
import { tl } from '@mtcute/tl'
|
import { tl } from '@mtcute/tl'
|
||||||
import { FileMigrateError, FilerefUpgradeNeededError } from '@mtcute/tl/errors'
|
|
||||||
import {
|
import {
|
||||||
MtArgumentError,
|
MtArgumentError,
|
||||||
MtUnsupportedError,
|
MtUnsupportedError,
|
||||||
|
@ -102,14 +101,14 @@ export async function* downloadAsIterable(
|
||||||
{ connection }
|
{ connection }
|
||||||
)
|
)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.constructor === FileMigrateError) {
|
if (e.constructor === tl.errors.FileMigrateXError) {
|
||||||
connection = this._downloadConnections[e.newDc]
|
connection = this._downloadConnections[e.new_dc]
|
||||||
if (!connection) {
|
if (!connection) {
|
||||||
connection = await this.createAdditionalConnection(e.newDc)
|
connection = await this.createAdditionalConnection(e.new_dc)
|
||||||
this._downloadConnections[e.newDc] = connection
|
this._downloadConnections[e.new_dc] = connection
|
||||||
}
|
}
|
||||||
return requestCurrent()
|
return requestCurrent()
|
||||||
} else if (e.constructor === FilerefUpgradeNeededError) {
|
} else if (e.constructor === tl.errors.FilerefUpgradeNeededError) {
|
||||||
// todo: implement someday
|
// todo: implement someday
|
||||||
// see: https://github.com/LonamiWebs/Telethon/blob/0e8bd8248cc649637b7c392616887c50986427a0/telethon/client/downloads.py#L99
|
// see: https://github.com/LonamiWebs/Telethon/blob/0e8bd8248cc649637b7c392616887c50986427a0/telethon/client/downloads.py#L99
|
||||||
throw new MtUnsupportedError('File ref expired!')
|
throw new MtUnsupportedError('File ref expired!')
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { TelegramClient } from '../../client'
|
import { TelegramClient } from '../../client'
|
||||||
import { InputPeerLike, Message, FormattedString, ReplyMarkup } from '../../types'
|
import { InputPeerLike, Message, FormattedString, ReplyMarkup } from '../../types'
|
||||||
import { tl } from '@mtcute/tl'
|
import { tl } from '@mtcute/tl'
|
||||||
import { MessageNotFoundError } from '@mtcute/tl/errors'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy a message (i.e. send the same message,
|
* Copy a message (i.e. send the same message,
|
||||||
|
@ -99,7 +98,7 @@ export async function sendCopy(
|
||||||
|
|
||||||
const msg = await this.getMessages(fromPeer, message)
|
const msg = await this.getMessages(fromPeer, message)
|
||||||
|
|
||||||
if (!msg) throw new MessageNotFoundError()
|
if (!msg) throw new tl.errors.MessageNotFoundError()
|
||||||
|
|
||||||
return msg.sendCopy(toChatId, params)
|
return msg.sendCopy(toChatId, params)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ import {
|
||||||
} from '../../utils/misc-utils'
|
} from '../../utils/misc-utils'
|
||||||
import { tl } from '@mtcute/tl'
|
import { tl } from '@mtcute/tl'
|
||||||
import { assertIsUpdatesGroup } from '../../utils/updates-utils'
|
import { assertIsUpdatesGroup } from '../../utils/updates-utils'
|
||||||
import { MessageNotFoundError } from '@mtcute/tl/errors'
|
|
||||||
import { randomLong } from '@mtcute/core'
|
import { randomLong } from '@mtcute/core'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -130,7 +129,7 @@ export async function sendMediaGroup(
|
||||||
const msg = await this.getMessages(peer, replyTo)
|
const msg = await this.getMessages(peer, replyTo)
|
||||||
|
|
||||||
if (!msg)
|
if (!msg)
|
||||||
throw new MessageNotFoundError()
|
throw new tl.errors.MessageNotFoundError()
|
||||||
}
|
}
|
||||||
|
|
||||||
const multiMedia: tl.RawInputSingleMedia[] = []
|
const multiMedia: tl.RawInputSingleMedia[] = []
|
||||||
|
|
|
@ -10,7 +10,6 @@ import {
|
||||||
} from '../../types'
|
} from '../../types'
|
||||||
import { normalizeDate, normalizeMessageId } from '../../utils/misc-utils'
|
import { normalizeDate, normalizeMessageId } from '../../utils/misc-utils'
|
||||||
import { tl } from '@mtcute/tl'
|
import { tl } from '@mtcute/tl'
|
||||||
import { MessageNotFoundError } from '@mtcute/tl/errors'
|
|
||||||
import { randomLong } from '@mtcute/core'
|
import { randomLong } from '@mtcute/core'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -156,7 +155,7 @@ export async function sendMedia(
|
||||||
|
|
||||||
const msg = await this.getMessages(peer, replyTo)
|
const msg = await this.getMessages(peer, replyTo)
|
||||||
|
|
||||||
if (!msg) throw new MessageNotFoundError()
|
if (!msg) throw new tl.errors.MessageNotFoundError()
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await this.call({
|
const res = await this.call({
|
||||||
|
|
|
@ -13,7 +13,7 @@ import {
|
||||||
MtTypeAssertionError,
|
MtTypeAssertionError,
|
||||||
MtArgumentError, FormattedString, PeersIndex,
|
MtArgumentError, FormattedString, PeersIndex,
|
||||||
} from '../../types'
|
} from '../../types'
|
||||||
import { getMarkedPeerId, MessageNotFoundError, randomLong } from '@mtcute/core'
|
import { getMarkedPeerId, randomLong } from '@mtcute/core'
|
||||||
import { createDummyUpdate } from '../../utils/updates-utils'
|
import { createDummyUpdate } from '../../utils/updates-utils'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -131,7 +131,7 @@ export async function sendText(
|
||||||
const msg = await this.getMessages(peer, replyTo)
|
const msg = await this.getMessages(peer, replyTo)
|
||||||
|
|
||||||
if (!msg)
|
if (!msg)
|
||||||
throw new MessageNotFoundError()
|
throw new tl.errors.MessageNotFoundError()
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await this.call({
|
const res = await this.call({
|
||||||
|
|
|
@ -6,9 +6,10 @@ import {
|
||||||
PeersIndex,
|
PeersIndex,
|
||||||
Poll,
|
Poll,
|
||||||
} from '../../types'
|
} from '../../types'
|
||||||
import { MaybeArray, MessageNotFoundError } from '@mtcute/core'
|
import { MaybeArray } from '@mtcute/core'
|
||||||
import { assertTypeIs } from '../../utils/type-assertion'
|
import { assertTypeIs } from '../../utils/type-assertion'
|
||||||
import { assertIsUpdatesGroup } from '../../utils/updates-utils'
|
import { assertIsUpdatesGroup } from '../../utils/updates-utils'
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send or retract a vote in a poll.
|
* Send or retract a vote in a poll.
|
||||||
|
@ -37,7 +38,7 @@ export async function sendVote(
|
||||||
if (options.some((it) => typeof it === 'number')) {
|
if (options.some((it) => typeof it === 'number')) {
|
||||||
const msg = await this.getMessages(peer, message)
|
const msg = await this.getMessages(peer, message)
|
||||||
|
|
||||||
if (!msg) throw new MessageNotFoundError()
|
if (!msg) throw new tl.errors.MessageNotFoundError()
|
||||||
|
|
||||||
if (!(msg.media instanceof Poll))
|
if (!(msg.media instanceof Poll))
|
||||||
throw new MtArgumentError(
|
throw new MtArgumentError(
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { TelegramClient } from '../../client'
|
import { TelegramClient } from '../../client'
|
||||||
import { InputStickerSetItem, StickerSet } from '../../types'
|
import { InputStickerSetItem, MtTypeAssertionError, StickerSet } from '../../types'
|
||||||
import { tl } from '@mtcute/tl'
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
const MASK_POS = {
|
const MASK_POS = {
|
||||||
|
|
|
@ -35,6 +35,7 @@ export async function getStickerSet(
|
||||||
const res = await this.call({
|
const res = await this.call({
|
||||||
_: 'messages.getStickerSet',
|
_: 'messages.getStickerSet',
|
||||||
stickerset: input,
|
stickerset: input,
|
||||||
|
hash: 0
|
||||||
})
|
})
|
||||||
|
|
||||||
return new StickerSet(this, res)
|
return new StickerSet(this, res)
|
||||||
|
|
|
@ -9,6 +9,7 @@ const sentCodeMap: Record<
|
||||||
'auth.sentCodeTypeCall': 'call',
|
'auth.sentCodeTypeCall': 'call',
|
||||||
'auth.sentCodeTypeFlashCall': 'flash_call',
|
'auth.sentCodeTypeFlashCall': 'flash_call',
|
||||||
'auth.sentCodeTypeSms': 'sms',
|
'auth.sentCodeTypeSms': 'sms',
|
||||||
|
'auth.sentCodeTypeMissedCall': 'missed_call',
|
||||||
}
|
}
|
||||||
|
|
||||||
const nextCodeMap: Record<
|
const nextCodeMap: Record<
|
||||||
|
@ -18,6 +19,7 @@ const nextCodeMap: Record<
|
||||||
'auth.codeTypeCall': 'call',
|
'auth.codeTypeCall': 'call',
|
||||||
'auth.codeTypeFlashCall': 'flash_call',
|
'auth.codeTypeFlashCall': 'flash_call',
|
||||||
'auth.codeTypeSms': 'sms',
|
'auth.codeTypeSms': 'sms',
|
||||||
|
'auth.codeTypeMissedCall': 'missed_call',
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace SentCode {
|
export namespace SentCode {
|
||||||
|
@ -28,7 +30,7 @@ export namespace SentCode {
|
||||||
* - `call`: Code is sent via voice call
|
* - `call`: Code is sent via voice call
|
||||||
* - `flash_call`: Code is the last 5 digits of the caller's phone number
|
* - `flash_call`: Code is the last 5 digits of the caller's phone number
|
||||||
*/
|
*/
|
||||||
export type DeliveryType = 'app' | 'sms' | 'call' | 'flash_call'
|
export type DeliveryType = 'app' | 'sms' | 'call' | 'flash_call' | 'missed_call'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type describing next code delivery type.
|
* Type describing next code delivery type.
|
||||||
|
|
|
@ -6,7 +6,6 @@ import { MtArgumentError } from '../errors'
|
||||||
import { BasicPeerType, getBasicPeerType, getMarkedPeerId } from '@mtcute/core'
|
import { BasicPeerType, getBasicPeerType, getMarkedPeerId } from '@mtcute/core'
|
||||||
import { encodeInlineMessageId } from '../../utils/inline-utils'
|
import { encodeInlineMessageId } from '../../utils/inline-utils'
|
||||||
import { User, PeersIndex } from '../peers'
|
import { User, PeersIndex } from '../peers'
|
||||||
import { MessageNotFoundError } from '@mtcute/core'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An incoming callback query, originated from a callback button
|
* An incoming callback query, originated from a callback button
|
||||||
|
@ -189,7 +188,7 @@ export class CallbackQuery {
|
||||||
getMarkedPeerId(this.raw.peer),
|
getMarkedPeerId(this.raw.peer),
|
||||||
this.raw.msgId
|
this.raw.msgId
|
||||||
)
|
)
|
||||||
if (!msg) throw new MessageNotFoundError()
|
if (!msg) throw new tl.errors.MessageNotFoundError()
|
||||||
|
|
||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ import { HistoryReadUpdate } from './updates'
|
||||||
import { FormattedString } from './parser'
|
import { FormattedString } from './parser'
|
||||||
import { Message } from './messages'
|
import { Message } from './messages'
|
||||||
import { tl } from '@mtcute/tl'
|
import { tl } from '@mtcute/tl'
|
||||||
import { TimeoutError } from '@mtcute/tl/errors'
|
|
||||||
|
|
||||||
interface QueuedHandler<T> {
|
interface QueuedHandler<T> {
|
||||||
promise: ControllablePromise<T>
|
promise: ControllablePromise<T>
|
||||||
|
@ -270,7 +269,7 @@ export class Conversation {
|
||||||
let timer: NodeJS.Timeout | undefined = undefined
|
let timer: NodeJS.Timeout | undefined = undefined
|
||||||
if (timeout !== null) {
|
if (timeout !== null) {
|
||||||
timer = setTimeout(() => {
|
timer = setTimeout(() => {
|
||||||
promise.reject(new TimeoutError())
|
promise.reject(new tl.errors.TimeoutError())
|
||||||
this._queuedNewMessage.removeBy((it) => it.promise === promise)
|
this._queuedNewMessage.removeBy((it) => it.promise === promise)
|
||||||
}, timeout)
|
}, timeout)
|
||||||
}
|
}
|
||||||
|
@ -412,7 +411,7 @@ export class Conversation {
|
||||||
let timer: NodeJS.Timeout | undefined = undefined
|
let timer: NodeJS.Timeout | undefined = undefined
|
||||||
if (params?.timeout !== null) {
|
if (params?.timeout !== null) {
|
||||||
timer = setTimeout(() => {
|
timer = setTimeout(() => {
|
||||||
promise.reject(new TimeoutError())
|
promise.reject(new tl.errors.TimeoutError())
|
||||||
delete this._pendingEditMessage[msgId]
|
delete this._pendingEditMessage[msgId]
|
||||||
}, params?.timeout ?? 15000)
|
}, params?.timeout ?? 15000)
|
||||||
}
|
}
|
||||||
|
@ -458,7 +457,7 @@ export class Conversation {
|
||||||
let timer: NodeJS.Timeout | undefined = undefined
|
let timer: NodeJS.Timeout | undefined = undefined
|
||||||
if (timeout !== null) {
|
if (timeout !== null) {
|
||||||
timer = setTimeout(() => {
|
timer = setTimeout(() => {
|
||||||
promise.reject(new TimeoutError())
|
promise.reject(new tl.errors.TimeoutError())
|
||||||
delete this._pendingRead[msgId]
|
delete this._pendingRead[msgId]
|
||||||
}, timeout)
|
}, timeout)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { Chat, PeersIndex } from '../peers'
|
||||||
import { Message } from './message'
|
import { Message } from './message'
|
||||||
import { DraftMessage } from './draft-message'
|
import { DraftMessage } from './draft-message'
|
||||||
import { makeInspectable } from '../utils'
|
import { makeInspectable } from '../utils'
|
||||||
import { getMarkedPeerId, MessageNotFoundError } from '@mtcute/core'
|
import { getMarkedPeerId } from '@mtcute/core'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A dialog.
|
* A dialog.
|
||||||
|
@ -184,7 +184,7 @@ export class Dialog {
|
||||||
this._peers
|
this._peers
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
throw new MessageNotFoundError()
|
throw new tl.errors.MessageNotFoundError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,13 +42,19 @@ export class StickerSet {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly client: TelegramClient,
|
readonly client: TelegramClient,
|
||||||
raw: tl.RawStickerSet | tl.messages.RawStickerSet
|
raw: tl.TypeStickerSet | tl.messages.TypeStickerSet
|
||||||
) {
|
) {
|
||||||
if (raw._ === 'messages.stickerSet') {
|
if (raw._ === 'messages.stickerSet') {
|
||||||
this.full = raw
|
this.full = raw
|
||||||
this.brief = raw.set
|
this.brief = raw.set
|
||||||
} else {
|
} else if (raw._ === 'stickerSet') {
|
||||||
this.brief = raw
|
this.brief = raw
|
||||||
|
} else {
|
||||||
|
throw new MtTypeAssertionError(
|
||||||
|
'StickerSet',
|
||||||
|
'messages.stickerSet | stickerSet',
|
||||||
|
raw._
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isFull = raw._ === 'messages.stickerSet'
|
this.isFull = raw._ === 'messages.stickerSet'
|
||||||
|
|
|
@ -494,10 +494,19 @@ export class Chat {
|
||||||
/** @internal */
|
/** @internal */
|
||||||
static _parseFull(
|
static _parseFull(
|
||||||
client: TelegramClient,
|
client: TelegramClient,
|
||||||
full: tl.messages.RawChatFull | tl.RawUserFull
|
full: tl.messages.RawChatFull | tl.users.TypeUserFull,
|
||||||
): Chat {
|
): Chat {
|
||||||
if (full._ === 'userFull') {
|
if (full._ === 'users.userFull') {
|
||||||
return new Chat(client, full.user, full)
|
const user = full.users.find((it) => it.id === full.fullUser.id)
|
||||||
|
if (!user || user._ === 'userEmpty') {
|
||||||
|
throw new MtTypeAssertionError(
|
||||||
|
'Chat._parseFull',
|
||||||
|
'user',
|
||||||
|
user?._ ?? 'undefined'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Chat(client, user, full.fullUser)
|
||||||
} else {
|
} else {
|
||||||
const fullChat = full.fullChat
|
const fullChat = full.fullChat
|
||||||
let chat: tl.TypeChat | undefined = undefined
|
let chat: tl.TypeChat | undefined = undefined
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { tl } from '@mtcute/tl'
|
import { tl } from '@mtcute/tl'
|
||||||
import { MtTypeAssertionError } from '../types'
|
import { MtTypeAssertionError } from '../types'
|
||||||
import Long from 'long'
|
|
||||||
|
|
||||||
// dummy updates which are used for methods that return messages.affectedHistory.
|
// dummy updates which are used for methods that return messages.affectedHistory.
|
||||||
// that is not an update, but it carries info about pts, and we need to handle it
|
// that is not an update, but it carries info about pts, and we need to handle it
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "^15.12.1",
|
"@types/node": "^15.12.1",
|
||||||
"@types/events": "^3.0.0",
|
"@types/events": "^3.0.0",
|
||||||
"@mtcute/tl": "^134.0.0",
|
"@mtcute/tl": "~139.0",
|
||||||
"@mtcute/tl-runtime": "^1.0.0",
|
"@mtcute/tl-runtime": "^1.0.0",
|
||||||
"big-integer": "1.6.48",
|
"big-integer": "1.6.48",
|
||||||
"long": "^4.0.0",
|
"long": "^4.0.0",
|
||||||
|
|
|
@ -24,17 +24,6 @@ import {
|
||||||
defaultTestDc,
|
defaultTestDc,
|
||||||
defaultTestIpv6Dc,
|
defaultTestIpv6Dc,
|
||||||
} from './utils/default-dcs'
|
} from './utils/default-dcs'
|
||||||
import {
|
|
||||||
AuthKeyUnregisteredError,
|
|
||||||
FloodTestPhoneWaitError,
|
|
||||||
FloodWaitError,
|
|
||||||
InternalError,
|
|
||||||
NetworkMigrateError,
|
|
||||||
PhoneMigrateError,
|
|
||||||
RpcError,
|
|
||||||
SlowmodeWaitError,
|
|
||||||
UserMigrateError,
|
|
||||||
} from '@mtcute/tl/errors'
|
|
||||||
import { addPublicKey } from './utils/crypto/keys'
|
import { addPublicKey } from './utils/crypto/keys'
|
||||||
import { ITelegramStorage, MemoryStorage } from './storage'
|
import { ITelegramStorage, MemoryStorage } from './storage'
|
||||||
import EventEmitter from 'events'
|
import EventEmitter from 'events'
|
||||||
|
@ -375,7 +364,7 @@ export class BaseTelegramClient extends EventEmitter {
|
||||||
// so we just use getState so the server knows
|
// so we just use getState so the server knows
|
||||||
// we still do need updates
|
// we still do need updates
|
||||||
this.call({ _: 'updates.getState' }).catch((e) => {
|
this.call({ _: 'updates.getState' }).catch((e) => {
|
||||||
if (!(e instanceof RpcError)) {
|
if (!(e instanceof tl.errors.RpcError)) {
|
||||||
this.primaryConnection.reconnect()
|
this.primaryConnection.reconnect()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -651,7 +640,7 @@ export class BaseTelegramClient extends EventEmitter {
|
||||||
await sleep(delta)
|
await sleep(delta)
|
||||||
delete this._floodWaitedRequests[message._]
|
delete this._floodWaitedRequests[message._]
|
||||||
} else {
|
} else {
|
||||||
throw new FloodWaitError(delta / 1000)
|
throw new tl.errors.FloodWaitXError(delta / 1000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -673,7 +662,7 @@ export class BaseTelegramClient extends EventEmitter {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
lastError = e
|
lastError = e
|
||||||
|
|
||||||
if (e instanceof InternalError) {
|
if (e instanceof tl.errors.InternalError) {
|
||||||
this.log.warn('Telegram is having internal issues: %s', e)
|
this.log.warn('Telegram is having internal issues: %s', e)
|
||||||
if (e.message === 'WORKER_BUSY_TOO_LONG_RETRY') {
|
if (e.message === 'WORKER_BUSY_TOO_LONG_RETRY') {
|
||||||
// according to tdlib, "it is dangerous to resend query without timeout, so use 1"
|
// according to tdlib, "it is dangerous to resend query without timeout, so use 1"
|
||||||
|
@ -683,11 +672,11 @@ export class BaseTelegramClient extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
e.constructor === FloodWaitError ||
|
e.constructor === tl.errors.FloodWaitXError ||
|
||||||
e.constructor === SlowmodeWaitError ||
|
e.constructor === tl.errors.SlowmodeWaitXError ||
|
||||||
e.constructor === FloodTestPhoneWaitError
|
e.constructor === tl.errors.FloodTestPhoneWaitXError
|
||||||
) {
|
) {
|
||||||
if (e.constructor !== SlowmodeWaitError) {
|
if (e.constructor !== tl.errors.SlowmodeWaitXError) {
|
||||||
// SLOW_MODE_WAIT is chat-specific, not request-specific
|
// SLOW_MODE_WAIT is chat-specific, not request-specific
|
||||||
this._floodWaitedRequests[message._] =
|
this._floodWaitedRequests[message._] =
|
||||||
Date.now() + e.seconds * 1000
|
Date.now() + e.seconds * 1000
|
||||||
|
@ -696,7 +685,7 @@ export class BaseTelegramClient extends EventEmitter {
|
||||||
// In test servers, FLOOD_WAIT_0 has been observed, and sleeping for
|
// In test servers, FLOOD_WAIT_0 has been observed, and sleeping for
|
||||||
// such a short amount will cause retries very fast leading to issues
|
// such a short amount will cause retries very fast leading to issues
|
||||||
if (e.seconds === 0) {
|
if (e.seconds === 0) {
|
||||||
e.seconds = 1
|
;(e as any).seconds = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
@ -711,16 +700,16 @@ export class BaseTelegramClient extends EventEmitter {
|
||||||
|
|
||||||
if (connection.params.dc.id === this._primaryDc.id) {
|
if (connection.params.dc.id === this._primaryDc.id) {
|
||||||
if (
|
if (
|
||||||
e.constructor === PhoneMigrateError ||
|
e.constructor === tl.errors.PhoneMigrateXError ||
|
||||||
e.constructor === UserMigrateError ||
|
e.constructor === tl.errors.UserMigrateXError ||
|
||||||
e.constructor === NetworkMigrateError
|
e.constructor === tl.errors.NetworkMigrateXError
|
||||||
) {
|
) {
|
||||||
this.log.info('Migrate error, new dc = %d', e.newDc)
|
this.log.info('Migrate error, new dc = %d', e.new_dc)
|
||||||
await this.changeDc(e.newDc)
|
await this.changeDc(e.new_dc)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (e.constructor === AuthKeyUnregisteredError) {
|
if (e.constructor === tl.errors.AuthKeyUnregisteredError) {
|
||||||
// we can try re-exporting auth from the primary connection
|
// we can try re-exporting auth from the primary connection
|
||||||
this.log.warn('exported auth key error, re-exporting..')
|
this.log.warn('exported auth key error, re-exporting..')
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ export * from './types'
|
||||||
export * from './utils'
|
export * from './utils'
|
||||||
|
|
||||||
export * from '@mtcute/tl'
|
export * from '@mtcute/tl'
|
||||||
export * from '@mtcute/tl/errors'
|
|
||||||
export * from '@mtcute/tl-runtime'
|
export * from '@mtcute/tl-runtime'
|
||||||
|
|
||||||
export { defaultDcs } from './utils/default-dcs'
|
export { defaultDcs } from './utils/default-dcs'
|
||||||
|
|
|
@ -13,11 +13,6 @@ import {
|
||||||
ControllablePromise,
|
ControllablePromise,
|
||||||
createCancellablePromise,
|
createCancellablePromise,
|
||||||
} from '../utils/controllable-promise'
|
} from '../utils/controllable-promise'
|
||||||
import {
|
|
||||||
createRpcErrorFromTl,
|
|
||||||
RpcError,
|
|
||||||
RpcTimeoutError,
|
|
||||||
} from '@mtcute/tl/errors'
|
|
||||||
import { gzipDeflate, gzipInflate } from '@mtcute/tl-runtime/src/platform/gzip'
|
import { gzipDeflate, gzipInflate } from '@mtcute/tl-runtime/src/platform/gzip'
|
||||||
import { SortedArray } from '../utils/sorted-array'
|
import { SortedArray } from '../utils/sorted-array'
|
||||||
import { EarlyTimer } from '../utils/early-timer'
|
import { EarlyTimer } from '../utils/early-timer'
|
||||||
|
@ -96,7 +91,7 @@ type PendingMessage =
|
||||||
// todo
|
// todo
|
||||||
const DESTROY_SESSION_ID = Buffer.from('262151e7', 'hex')
|
const DESTROY_SESSION_ID = Buffer.from('262151e7', 'hex')
|
||||||
|
|
||||||
function makeNiceStack(error: RpcError, stack: string, method?: string) {
|
function makeNiceStack(error: tl.errors.RpcError, stack: string, method?: string) {
|
||||||
error.stack = `${error.constructor.name} (${error.code} ${error.text}): ${
|
error.stack = `${error.constructor.name} (${error.code} ${error.text}): ${
|
||||||
error.message
|
error.message
|
||||||
}\n at ${method}\n${stack.split('\n').slice(2).join('\n')}`
|
}\n at ${method}\n${stack.split('\n').slice(2).join('\n')}`
|
||||||
|
@ -526,7 +521,7 @@ export class SessionConnection extends PersistentConnection {
|
||||||
|
|
||||||
if (rpc.cancelled) return
|
if (rpc.cancelled) return
|
||||||
|
|
||||||
const error = createRpcErrorFromTl(res)
|
const error = tl.errors.createRpcErrorFromTl(res)
|
||||||
if (this.params.niceStacks !== false) {
|
if (this.params.niceStacks !== false) {
|
||||||
makeNiceStack(error, rpc.stack!, rpc.method)
|
makeNiceStack(error, rpc.stack!, rpc.method)
|
||||||
}
|
}
|
||||||
|
@ -1144,7 +1139,7 @@ export class SessionConnection extends PersistentConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (onTimeout) {
|
if (onTimeout) {
|
||||||
const error = new RpcTimeoutError()
|
const error = new tl.errors.RpcTimeoutError()
|
||||||
if (this.params.niceStacks !== false) {
|
if (this.params.niceStacks !== false) {
|
||||||
makeNiceStack(error, rpc.stack!, rpc.method)
|
makeNiceStack(error, rpc.stack!, rpc.method)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import { describe, it } from 'mocha'
|
import { describe, it } from 'mocha'
|
||||||
import { expect } from 'chai'
|
import { expect } from 'chai'
|
||||||
import { randomBytes } from '../../src'
|
import { randomBytes, sleep } from '../../src'
|
||||||
import { sleep } from '../../src/utils/misc-utils'
|
|
||||||
import { UserMigrateError } from '@mtcute/tl/errors'
|
|
||||||
import { createTestTelegramClient } from '../e2e/utils'
|
import { createTestTelegramClient } from '../e2e/utils'
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
require('dotenv-flow').config()
|
require('dotenv-flow').config()
|
||||||
|
|
||||||
|
@ -62,7 +61,7 @@ describe('fuzz : session', async function () {
|
||||||
await client.waitUntilUsable()
|
await client.waitUntilUsable()
|
||||||
|
|
||||||
const conn = await client.createAdditionalConnection(1)
|
const conn = await client.createAdditionalConnection(1)
|
||||||
await conn.sendForResult({ _: 'help.getConfig' })
|
await conn.sendRpc({ _: 'help.getConfig' })
|
||||||
|
|
||||||
await sleep(10000)
|
await sleep(10000)
|
||||||
|
|
||||||
|
@ -116,7 +115,7 @@ describe('fuzz : session', async function () {
|
||||||
]
|
]
|
||||||
}, { connection: conn })
|
}, { connection: conn })
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof UserMigrateError) {
|
if (e instanceof tl.errors.UserMigrateXError) {
|
||||||
hadError = true
|
hadError = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
"build": "tsc"
|
"build": "tsc"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mtcute/tl": "^134.0",
|
"@mtcute/tl": "~139.0",
|
||||||
"@mtcute/core": "^1.0.0",
|
"@mtcute/core": "^1.0.0",
|
||||||
"@mtcute/client": "^1.0.0",
|
"@mtcute/client": "^1.0.0",
|
||||||
"events": "^3.2.0"
|
"events": "^3.2.0"
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
"build": "tsc"
|
"build": "tsc"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mtcute/tl": "^134.0.0",
|
"@mtcute/tl": "~139.0",
|
||||||
"@mtcute/tl-runtime": "^1.0.0",
|
"@mtcute/tl-runtime": "^1.0.0",
|
||||||
"@mtcute/core": "^1.0.0",
|
"@mtcute/core": "^1.0.0",
|
||||||
"long": "^4.0.0"
|
"long": "^4.0.0"
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
"docs": "npx typedoc"
|
"docs": "npx typedoc"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mtcute/tl": "^134.0.0",
|
"@mtcute/tl": "~139.0",
|
||||||
"htmlparser2": "^6.0.1",
|
"htmlparser2": "^6.0.1",
|
||||||
"long": "^4.0.0"
|
"long": "^4.0.0"
|
||||||
},
|
},
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
"docs": "npx typedoc"
|
"docs": "npx typedoc"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mtcute/tl": "^134.0.0",
|
"@mtcute/tl": "~139.0",
|
||||||
"long": "^4.0.0"
|
"long": "^4.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
274
packages/tl-utils/src/codegen/errors.ts
Normal file
274
packages/tl-utils/src/codegen/errors.ts
Normal file
|
@ -0,0 +1,274 @@
|
||||||
|
import { camelToPascal, jsComment, snakeToCamel } from './utils'
|
||||||
|
import { TlError, TlErrors } from '../types'
|
||||||
|
|
||||||
|
export function errorCodeToClassName(code: string): string {
|
||||||
|
let str =
|
||||||
|
camelToPascal(
|
||||||
|
snakeToCamel(
|
||||||
|
code
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/ /g, '_')
|
||||||
|
)
|
||||||
|
) + 'Error'
|
||||||
|
if (str[0].match(/\d/)) {
|
||||||
|
str = '_' + str
|
||||||
|
}
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
const RPC_ERROR_CLASS_JS = `
|
||||||
|
class RpcError extends Error {
|
||||||
|
constructor(code, text, description) {
|
||||||
|
super(description);
|
||||||
|
this.code = code;
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{exports}RpcError = RpcError;
|
||||||
|
`.trimStart()
|
||||||
|
|
||||||
|
const RPC_ERROR_CLASS_TS = `
|
||||||
|
export class RpcError extends Error {
|
||||||
|
readonly code: number;
|
||||||
|
readonly text: string;
|
||||||
|
constructor(code: number, text: string, description?: string);
|
||||||
|
}
|
||||||
|
`.trimStart()
|
||||||
|
|
||||||
|
const BASE_ERROR_JS = `
|
||||||
|
class {className} extends RpcError {
|
||||||
|
constructor(name, description) {
|
||||||
|
super({code}, name, description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{exports}{className} = {className}
|
||||||
|
`
|
||||||
|
const BASE_ERROR_TS = `
|
||||||
|
export class {className} extends RpcError {
|
||||||
|
constructor(name: string, description: string);
|
||||||
|
}
|
||||||
|
`.trimStart()
|
||||||
|
|
||||||
|
const ERROR_PRELUDE = `{ts}class {className} extends {base} {
|
||||||
|
constructor({arguments})`
|
||||||
|
|
||||||
|
const TL_BUILDER_TEMPLATE_JS = `
|
||||||
|
{exports}createRpcErrorFromTl = function (obj) {
|
||||||
|
if (obj.errorMessage in _byName) return new _byName[obj.errorMessage]();
|
||||||
|
|
||||||
|
let match;
|
||||||
|
{inner}
|
||||||
|
|
||||||
|
if (obj.errorCode in _byCode) return new _byCode[obj.errorCode](obj.errorMessage);
|
||||||
|
|
||||||
|
return new RpcError(obj.errorCode, obj.errorMessage);
|
||||||
|
}
|
||||||
|
`.trim()
|
||||||
|
|
||||||
|
const template = (str: string, params: Record<string, any>): string => {
|
||||||
|
return str.replace(/{([a-z]+)}/gi, (_, name) => params[name] ?? '')
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseCode(
|
||||||
|
err: string,
|
||||||
|
placeholders?: string[]
|
||||||
|
): [string, string[], boolean] {
|
||||||
|
let addPlaceholders = false
|
||||||
|
|
||||||
|
if (!placeholders) {
|
||||||
|
placeholders = []
|
||||||
|
addPlaceholders = true
|
||||||
|
}
|
||||||
|
|
||||||
|
let wildcard = false
|
||||||
|
|
||||||
|
err = err
|
||||||
|
.replace(/%[a-z]/g, (ph) => {
|
||||||
|
if (ph !== '%d') {
|
||||||
|
throw new Error(`Unsupported placeholder: ${ph}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addPlaceholders) {
|
||||||
|
const idx = placeholders!.length
|
||||||
|
placeholders!.push(`duration${idx === 0 ? '' : idx}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'X'
|
||||||
|
})
|
||||||
|
.replace(/_\*$/, () => {
|
||||||
|
wildcard = true
|
||||||
|
return ''
|
||||||
|
})
|
||||||
|
|
||||||
|
return [err, placeholders, wildcard]
|
||||||
|
}
|
||||||
|
|
||||||
|
function placeholderType(name: string): string {
|
||||||
|
// if (!name.startsWith('duration')) {
|
||||||
|
// throw new Error('Invalid placeholder name')
|
||||||
|
// }
|
||||||
|
return 'number'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function generateCodeForErrors(
|
||||||
|
errors: TlErrors,
|
||||||
|
exports = 'exports.'
|
||||||
|
): [string, string] {
|
||||||
|
let ts = RPC_ERROR_CLASS_TS
|
||||||
|
let js = template(RPC_ERROR_CLASS_JS, { exports })
|
||||||
|
|
||||||
|
const baseErrorsClasses: Record<number, string> = {}
|
||||||
|
|
||||||
|
for (const it of errors.base) {
|
||||||
|
const className = errorCodeToClassName(it.name)
|
||||||
|
baseErrorsClasses[it.code] = className
|
||||||
|
|
||||||
|
if (it.description) ts += jsComment(it.description) + '\n'
|
||||||
|
ts +=
|
||||||
|
template(BASE_ERROR_TS, {
|
||||||
|
className,
|
||||||
|
}) + '\n'
|
||||||
|
js += template(BASE_ERROR_JS, {
|
||||||
|
className,
|
||||||
|
code: it.code,
|
||||||
|
exports,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const errorClasses: Record<string, string> = {}
|
||||||
|
const wildcardClasses: [string, string][] = []
|
||||||
|
const withPlaceholders: [string, string][] = []
|
||||||
|
|
||||||
|
function findBaseClass(it: TlError) {
|
||||||
|
for (const [prefix, cls] of wildcardClasses) {
|
||||||
|
if (it.name.startsWith(prefix)) return cls
|
||||||
|
}
|
||||||
|
|
||||||
|
return baseErrorsClasses[it.code] ?? 'RpcError'
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const it of Object.values(errors.errors)) {
|
||||||
|
if (it._auto) {
|
||||||
|
// information about the error is incomplete
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const [name, placeholders, wildcard] = parseCode(
|
||||||
|
it.name,
|
||||||
|
it._paramNames
|
||||||
|
)
|
||||||
|
|
||||||
|
const className = errorCodeToClassName(name)
|
||||||
|
const baseClass = findBaseClass(it)
|
||||||
|
|
||||||
|
if (!it.virtual && !wildcard) {
|
||||||
|
errorClasses[it.name] = className
|
||||||
|
}
|
||||||
|
if (wildcard) {
|
||||||
|
wildcardClasses.push([it.name.replace('*', ''), className])
|
||||||
|
}
|
||||||
|
if (placeholders.length) {
|
||||||
|
withPlaceholders.push([it.name, className])
|
||||||
|
}
|
||||||
|
|
||||||
|
js +=
|
||||||
|
template(ERROR_PRELUDE, {
|
||||||
|
className,
|
||||||
|
base: baseClass,
|
||||||
|
arguments: wildcard
|
||||||
|
? 'code, description'
|
||||||
|
: placeholders.join(', '),
|
||||||
|
}) + '{\n'
|
||||||
|
|
||||||
|
let description
|
||||||
|
let comment = ''
|
||||||
|
if (it.description) {
|
||||||
|
let idx = 0
|
||||||
|
description = JSON.stringify(it.description).replace(
|
||||||
|
/%[a-z]/g,
|
||||||
|
() => `" + ${placeholders[idx++]} + "`
|
||||||
|
)
|
||||||
|
|
||||||
|
if (wildcard) {
|
||||||
|
description = description.replace(/"$/, ': " + description')
|
||||||
|
}
|
||||||
|
|
||||||
|
idx = 0
|
||||||
|
comment += it.description.replace(
|
||||||
|
/%[a-z]/g,
|
||||||
|
() => `{@see ${placeholders[idx++]}}`
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
description = `"Unknown RPC error: [${it.code}:${it.name}]"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it.virtual) {
|
||||||
|
if (comment) comment += '\n\n'
|
||||||
|
comment +=
|
||||||
|
'This is a *virtual* error, meaning that it may only occur when using MTCute APIs (not MTProto)'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wildcard) {
|
||||||
|
if (comment) comment += '\n\n'
|
||||||
|
comment +=
|
||||||
|
'This is an *abstract* error, meaning that only its subclasses may occur when using the API'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (comment) ts += jsComment(comment) + '\n'
|
||||||
|
ts +=
|
||||||
|
template(ERROR_PRELUDE, {
|
||||||
|
ts: 'export ',
|
||||||
|
className,
|
||||||
|
base: baseClass,
|
||||||
|
arguments: placeholders
|
||||||
|
.map((it) => `${it}: ${placeholderType(it)}`)
|
||||||
|
.join(', '),
|
||||||
|
}) + ';'
|
||||||
|
|
||||||
|
if (baseClass === 'RpcError') {
|
||||||
|
js += `super(${it.code}, '${it.name}', ${description});`
|
||||||
|
} else if (wildcard) {
|
||||||
|
js += `super(code, ${description});`
|
||||||
|
} else {
|
||||||
|
js += `super('${it.name}', ${description});`
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const ph of placeholders) {
|
||||||
|
js += `\nthis.${ph} = ${ph};`
|
||||||
|
ts += `\n readonly ${ph}: ${placeholderType(ph)}`
|
||||||
|
}
|
||||||
|
|
||||||
|
js += '\n }\n}\n'
|
||||||
|
js += `${exports}${className} = ${className};\n`
|
||||||
|
|
||||||
|
ts += '\n}\n'
|
||||||
|
}
|
||||||
|
|
||||||
|
ts += 'export function createRpcErrorFromTl (obj: object): RpcError;\n'
|
||||||
|
|
||||||
|
// and now we need to implement it
|
||||||
|
js += 'const _byName = {\n'
|
||||||
|
for (const [name, cls] of Object.entries(errorClasses)) {
|
||||||
|
js += `'${name.replace(/%[a-z]/gi, 'X')}': ${cls},\n`
|
||||||
|
}
|
||||||
|
js += '};\n'
|
||||||
|
|
||||||
|
js += 'const _byCode = {\n'
|
||||||
|
for (const [code, cls] of Object.entries(baseErrorsClasses)) {
|
||||||
|
js += `${code}: ${cls},\n`
|
||||||
|
}
|
||||||
|
js += '};\n'
|
||||||
|
|
||||||
|
// finally, the function itself
|
||||||
|
|
||||||
|
let inner = ''
|
||||||
|
|
||||||
|
for (const [name, cls] of withPlaceholders) {
|
||||||
|
const regex = name.replace('%d', '(\\d+)')
|
||||||
|
inner += `if ((match=obj.errorMessage.match(/^${regex}$/))!=null)return new ${cls}(parseInt(match[1]));\n`
|
||||||
|
}
|
||||||
|
|
||||||
|
js += template(TL_BUILDER_TEMPLATE_JS, { inner, exports })
|
||||||
|
|
||||||
|
return [ts, js]
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
import { TlEntry, TlFullSchema } from '../types'
|
import { TlEntry, TlErrors, TlFullSchema } from '../types'
|
||||||
import { groupTlEntriesByNamespace, splitNameToNamespace } from '../utils'
|
import { groupTlEntriesByNamespace, splitNameToNamespace } from '../utils'
|
||||||
import { camelToPascal, snakeToCamel } from './utils'
|
import { camelToPascal, indent, jsComment, snakeToCamel } from './utils'
|
||||||
|
import { errorCodeToClassName, generateCodeForErrors } from './errors'
|
||||||
|
|
||||||
const PRIMITIVE_TO_TS: Record<string, string> = {
|
const PRIMITIVE_TO_TS: Record<string, string> = {
|
||||||
int: 'number',
|
int: 'number',
|
||||||
|
@ -14,23 +15,7 @@ const PRIMITIVE_TO_TS: Record<string, string> = {
|
||||||
Bool: 'boolean',
|
Bool: 'boolean',
|
||||||
true: 'boolean',
|
true: 'boolean',
|
||||||
null: 'null',
|
null: 'null',
|
||||||
any: 'any'
|
any: 'any',
|
||||||
}
|
|
||||||
|
|
||||||
function jsComment(s: string): string {
|
|
||||||
return (
|
|
||||||
'/**' +
|
|
||||||
s
|
|
||||||
.replace(/(?![^\n]{1,60}$)([^\n]{1,60})\s/g, '$1\n')
|
|
||||||
.replace(/\n|^/g, '\n * ') +
|
|
||||||
'\n */'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function indent(size: number, s: string): string {
|
|
||||||
let prefix = ''
|
|
||||||
while (size--) prefix += ' '
|
|
||||||
return prefix + s.replace(/\n/g, '\n' + prefix)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function fullTypeName(
|
function fullTypeName(
|
||||||
|
@ -68,7 +53,8 @@ function entryFullTypeName(entry: TlEntry): string {
|
||||||
|
|
||||||
export function generateTypescriptDefinitionsForTlEntry(
|
export function generateTypescriptDefinitionsForTlEntry(
|
||||||
entry: TlEntry,
|
entry: TlEntry,
|
||||||
baseNamespace = 'tl.'
|
baseNamespace = 'tl.',
|
||||||
|
errors?: TlErrors
|
||||||
): string {
|
): string {
|
||||||
let ret = ''
|
let ret = ''
|
||||||
|
|
||||||
|
@ -83,6 +69,20 @@ export function generateTypescriptDefinitionsForTlEntry(
|
||||||
entry.type,
|
entry.type,
|
||||||
baseNamespace
|
baseNamespace
|
||||||
)}}`
|
)}}`
|
||||||
|
|
||||||
|
if (errors) {
|
||||||
|
if (errors.userOnly[entry.name]) {
|
||||||
|
comment += `\n\nThis method is **not** available for bots`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errors.throws[entry.name]) {
|
||||||
|
comment +=
|
||||||
|
`\n\nThis method *may* throw one of these errors: ` +
|
||||||
|
errors.throws[entry.name]
|
||||||
|
.map((it) => `{$see ${errorCodeToClassName(it)}`)
|
||||||
|
.join(', ')
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (comment) ret += jsComment(comment) + '\n'
|
if (comment) ret += jsComment(comment) + '\n'
|
||||||
|
|
||||||
|
@ -172,7 +172,8 @@ ns.LAYER = $LAYER$;
|
||||||
export function generateTypescriptDefinitionsForTlSchema(
|
export function generateTypescriptDefinitionsForTlSchema(
|
||||||
schema: TlFullSchema,
|
schema: TlFullSchema,
|
||||||
layer: number,
|
layer: number,
|
||||||
namespace = 'tl'
|
namespace = 'tl',
|
||||||
|
errors?: TlErrors
|
||||||
): [string, string] {
|
): [string, string] {
|
||||||
let ts = PRELUDE.replace('$NS$', namespace).replace('$LAYER$', layer + '')
|
let ts = PRELUDE.replace('$NS$', namespace).replace('$LAYER$', layer + '')
|
||||||
let js = PRELUDE_JS.replace('$NS$', namespace).replace(
|
let js = PRELUDE_JS.replace('$NS$', namespace).replace(
|
||||||
|
@ -180,6 +181,18 @@ export function generateTypescriptDefinitionsForTlSchema(
|
||||||
layer + ''
|
layer + ''
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (errors) {
|
||||||
|
ts += `\n namespace errors {\n`
|
||||||
|
js += `ns.errors = {};\n(function(ns){\n`
|
||||||
|
|
||||||
|
const [_ts, _js] = generateCodeForErrors(errors, 'ns.')
|
||||||
|
ts += indent(8, _ts)
|
||||||
|
js += _js
|
||||||
|
|
||||||
|
ts += `}\n`
|
||||||
|
js += `})(ns.errors);\n`
|
||||||
|
}
|
||||||
|
|
||||||
const namespaces = groupTlEntriesByNamespace(schema.entries)
|
const namespaces = groupTlEntriesByNamespace(schema.entries)
|
||||||
|
|
||||||
for (const ns in namespaces) {
|
for (const ns in namespaces) {
|
||||||
|
|
|
@ -6,3 +6,19 @@ export const snakeToCamel = (s: string): string => {
|
||||||
|
|
||||||
export const camelToPascal = (s: string): string =>
|
export const camelToPascal = (s: string): string =>
|
||||||
s[0].toUpperCase() + s.substr(1)
|
s[0].toUpperCase() + s.substr(1)
|
||||||
|
|
||||||
|
export function jsComment(s: string): string {
|
||||||
|
return (
|
||||||
|
'/**' +
|
||||||
|
s
|
||||||
|
.replace(/(?![^\n]{1,60}$)([^\n]{1,60})\s/g, '$1\n')
|
||||||
|
.replace(/\n|^/g, '\n * ') +
|
||||||
|
'\n */'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function indent(size: number, s: string): string {
|
||||||
|
let prefix = ''
|
||||||
|
while (size--) prefix += ' '
|
||||||
|
return prefix + s.replace(/\n/g, '\n' + prefix)
|
||||||
|
}
|
||||||
|
|
|
@ -42,6 +42,24 @@ export interface TlFullSchema {
|
||||||
unions: Record<string, TlUnion>
|
unions: Record<string, TlUnion>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TlError {
|
||||||
|
code: number
|
||||||
|
name: string
|
||||||
|
description?: string
|
||||||
|
virtual?: true
|
||||||
|
|
||||||
|
// internal fields used by generator
|
||||||
|
_auto?: true
|
||||||
|
_paramNames?: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TlErrors {
|
||||||
|
base: TlError[]
|
||||||
|
errors: Record<string, TlError>
|
||||||
|
throws: Record<string, string[]>
|
||||||
|
userOnly: Record<string, 1>
|
||||||
|
}
|
||||||
|
|
||||||
interface BasicDiff<T, K> {
|
interface BasicDiff<T, K> {
|
||||||
added: T[]
|
added: T[]
|
||||||
removed: T[]
|
removed: T[]
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
> TL schema and related utils used for MTCute.
|
> TL schema and related utils used for MTCute.
|
||||||
|
|
||||||
Generated from TL layer **134** (last updated on 20.11.2021).
|
Generated from TL layer **139** (last updated on 23.03.2022).
|
||||||
|
|
||||||
## About
|
## About
|
||||||
|
|
||||||
|
@ -34,15 +34,31 @@ use-cases for mutable TL objects, so you can use exported
|
||||||
`tl` is exported as a namespace to allow better code insights, and to avoid cluttering global namespace and very long
|
`tl` is exported as a namespace to allow better code insights, and to avoid cluttering global namespace and very long
|
||||||
import statements.
|
import statements.
|
||||||
|
|
||||||
|
MTProto schema is available in namespace `mtp`, also exported by this package.
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { tl } from '@mtcute/tl'
|
import { tl } from '@mtcute/tl'
|
||||||
const obj: tl.RawInputPeerChat = { _: 'inputPeerChat', chatId: 42 }
|
const obj: tl.RawInputPeerChat = { _: 'inputPeerChat', chatId: 42 }
|
||||||
console.log(tl.isAnyInputPeer(obj)) // true
|
console.log(tl.isAnyInputPeer(obj)) // true
|
||||||
```
|
```
|
||||||
|
|
||||||
### `@mtcute/tl/raw-schema`
|
|
||||||
|
|
||||||
[Documentation](./modules/raw_schema.html)
|
RPC errors are also exposed in this package in `tl.errors` namespace:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
try {
|
||||||
|
await client.call(...)
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof tl.errors.ChatInvalidError) {
|
||||||
|
console.log('invalid chat')
|
||||||
|
} else throw e
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `@mtcute/tl/api-schema`
|
||||||
|
|
||||||
|
[Documentation](./modules/api_schema.html)
|
||||||
|
|
||||||
JSON file describing all available TL classes, methods and unions. Can be used to write custom code generators
|
JSON file describing all available TL classes, methods and unions. Can be used to write custom code generators
|
||||||
> This very file is used to generate binary serialization and TypeScript typings for `@mtcute/tl`.
|
> This very file is used to generate binary serialization and TypeScript typings for `@mtcute/tl`.
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,29 +1,24 @@
|
||||||
// this file is sourced *before* actual schema.
|
|
||||||
// should be used for types that are not currently added to the schema,
|
|
||||||
// but seem to work
|
|
||||||
// in case of conflict, type from main schema is preferred
|
|
||||||
|
|
||||||
// for internal use
|
// for internal use
|
||||||
---types---
|
---types---
|
||||||
|
|
||||||
dummyUpdate pts:int pts_count:int channel_id:int53 = Update;
|
dummyUpdate pts:int pts_count:int channel_id:int53 = Update;
|
||||||
|
|
||||||
// reactions
|
// reactions
|
||||||
// taken from official docs coz why not lol
|
// taken from OLD official
|
||||||
// ctor ids will be generated by the codegen
|
// no longer work on newer layers because they changed this thing entirely
|
||||||
// *does* work with layer 131 (as of 25.07.21)
|
// kept only as a historical reference
|
||||||
|
|
||||||
---types---
|
// ---types---
|
||||||
|
//
|
||||||
updateMessageReactions peer:Peer msg_id:int reactions:MessageReactions = Update;
|
// updateMessageReactions peer:Peer msg_id:int reactions:MessageReactions = Update;
|
||||||
messageReactions flags:# min:flags.0?true results:Vector<ReactionCount> = MessageReactions;
|
// messageReactions flags:# min:flags.0?true results:Vector<ReactionCount> = MessageReactions;
|
||||||
reactionCount flags:# chosen:flags.0?true reaction:string count:int = ReactionCount;
|
// reactionCount flags:# chosen:flags.0?true reaction:string count:int = ReactionCount;
|
||||||
|
//
|
||||||
messageReactionsList flags:# count:int reactions:Vector<MessageUserReaction> users:Vector<User> next_offset:flags.0?string = MessageReactionsList;
|
// messageReactionsList flags:# count:int reactions:Vector<MessageUserReaction> users:Vector<User> next_offset:flags.0?string = MessageReactionsList;
|
||||||
messageUserReaction user_id:int reaction:string = MessageUserReaction;
|
// messageUserReaction user_id:int reaction:string = MessageUserReaction;
|
||||||
|
//
|
||||||
---functions---
|
// ---functions---
|
||||||
|
//
|
||||||
messages.sendReaction flags:# peer:InputPeer msg_id:int reaction:flags.0?string = Updates;
|
// messages.sendReaction flags:# peer:InputPeer msg_id:int reaction:flags.0?string = Updates;
|
||||||
messages.getMessagesReactions peer:InputPeer id:Vector<int> = Updates;
|
// messages.getMessagesReactions peer:InputPeer id:Vector<int> = Updates;
|
||||||
messages.getMessageReactionsList flags:# peer:InputPeer id:int reaction:flags.0?string offset:flags.1?string limit:int = MessageReactionsList;
|
// messages.getMessageReactionsList flags:# peer:InputPeer id:int reaction:flags.0?string offset:flags.1?string limit:int = MessageReactionsList;
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
"inputPrivacyValueDisallowChatParticipants": ["chats"],
|
"inputPrivacyValueDisallowChatParticipants": ["chats"],
|
||||||
"inputUser": ["user_id"],
|
"inputUser": ["user_id"],
|
||||||
"inputUserFromMessage": ["user_id"],
|
"inputUserFromMessage": ["user_id"],
|
||||||
|
"keyboardButtonUserProfile": ["user_id"],
|
||||||
"message": ["via_bot_id"],
|
"message": ["via_bot_id"],
|
||||||
"messageActionChannelMigrateFrom": ["chat_id"],
|
"messageActionChannelMigrateFrom": ["chat_id"],
|
||||||
"messageActionChatAddUser": ["users"],
|
"messageActionChatAddUser": ["users"],
|
||||||
|
@ -120,6 +121,7 @@
|
||||||
"updateUserTyping": ["user_id"],
|
"updateUserTyping": ["user_id"],
|
||||||
"user": ["id"],
|
"user": ["id"],
|
||||||
"userEmpty": ["id"],
|
"userEmpty": ["id"],
|
||||||
|
"userFull": ["id"],
|
||||||
"webAuthorization": ["bot_id"],
|
"webAuthorization": ["bot_id"],
|
||||||
"_": "Dummy line teehee~"
|
"_": "Dummy line teehee~"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@mtcute/tl",
|
"name": "@mtcute/tl",
|
||||||
"version": "134.0.0",
|
"version": "139.0.0",
|
||||||
"description": "TL schema used for MTCute",
|
"description": "TL schema used for MTCute",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"author": "Alisa Sireneva <me@tei.su>",
|
"author": "Alisa Sireneva <me@tei.su>",
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -4,8 +4,10 @@ export const DOC_CACHE_FILE = join(__dirname, '.documentation.cache.json')
|
||||||
export const DESCRIPTIONS_YAML_FILE = join(__dirname, '../data/descriptions.yaml')
|
export const DESCRIPTIONS_YAML_FILE = join(__dirname, '../data/descriptions.yaml')
|
||||||
export const API_SCHEMA_JSON_FILE = join(__dirname, '../api-schema.json')
|
export const API_SCHEMA_JSON_FILE = join(__dirname, '../api-schema.json')
|
||||||
export const MTP_SCHEMA_JSON_FILE = join(__dirname, '../mtp-schema.json')
|
export const MTP_SCHEMA_JSON_FILE = join(__dirname, '../mtp-schema.json')
|
||||||
|
export const ERRORS_JSON_FILE = join(__dirname, '../raw-errors.json')
|
||||||
|
|
||||||
export const CORE_DOMAIN = 'https://corefork.telegram.org'
|
export const CORE_DOMAIN = 'https://core.telegram.org'
|
||||||
|
export const COREFORK_DOMAIN = 'https://core.telegram.org'
|
||||||
|
|
||||||
export const TDESKTOP_SCHEMA =
|
export const TDESKTOP_SCHEMA =
|
||||||
'https://raw.githubusercontent.com/telegramdesktop/tdesktop/dev/Telegram/Resources/tl/api.tl'
|
'https://raw.githubusercontent.com/telegramdesktop/tdesktop/dev/Telegram/Resources/tl/api.tl'
|
||||||
|
|
|
@ -15,10 +15,7 @@ import fetch from 'node-fetch'
|
||||||
import readline from 'readline'
|
import readline from 'readline'
|
||||||
import { writeTlEntryToString } from '@mtcute/tl-utils/src/stringify'
|
import { writeTlEntryToString } from '@mtcute/tl-utils/src/stringify'
|
||||||
import {
|
import {
|
||||||
CORE_DOMAIN,
|
CORE_DOMAIN, API_SCHEMA_JSON_FILE, TDESKTOP_SCHEMA, TDLIB_SCHEMA, COREFORK_DOMAIN
|
||||||
API_SCHEMA_JSON_FILE,
|
|
||||||
TDESKTOP_SCHEMA,
|
|
||||||
TDLIB_SCHEMA,
|
|
||||||
} from './constants'
|
} from './constants'
|
||||||
import { fetchRetry } from './utils'
|
import { fetchRetry } from './utils'
|
||||||
import {
|
import {
|
||||||
|
@ -69,8 +66,8 @@ async function fetchTdesktopSchema(): Promise<Schema> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchCoreSchema(): Promise<Schema> {
|
async function fetchCoreSchema(domain = CORE_DOMAIN, name = 'Core'): Promise<Schema> {
|
||||||
const html = await fetchRetry(`${CORE_DOMAIN}/schema`)
|
const html = await fetchRetry(`${domain}/schema`)
|
||||||
const $ = cheerio.load(html)
|
const $ = cheerio.load(html)
|
||||||
// cheerio doesn't always unescape them
|
// cheerio doesn't always unescape them
|
||||||
const schema = $('.page_scheme code')
|
const schema = $('.page_scheme code')
|
||||||
|
@ -85,7 +82,7 @@ async function fetchCoreSchema(): Promise<Schema> {
|
||||||
if (!layer) throw new Error('Layer number not available')
|
if (!layer) throw new Error('Layer number not available')
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: 'Core',
|
name,
|
||||||
layer: parseInt(layer[1]),
|
layer: parseInt(layer[1]),
|
||||||
content: tlToFullSchema(schema),
|
content: tlToFullSchema(schema),
|
||||||
}
|
}
|
||||||
|
@ -175,6 +172,7 @@ async function main() {
|
||||||
await fetchTdlibSchema(),
|
await fetchTdlibSchema(),
|
||||||
await fetchTdesktopSchema(),
|
await fetchTdesktopSchema(),
|
||||||
await fetchCoreSchema(),
|
await fetchCoreSchema(),
|
||||||
|
await fetchCoreSchema(COREFORK_DOMAIN, 'Corefork'),
|
||||||
{
|
{
|
||||||
name: 'Custom',
|
name: 'Custom',
|
||||||
layer: 0, // handled manually
|
layer: 0, // handled manually
|
||||||
|
|
|
@ -1,26 +1,16 @@
|
||||||
import { join } from 'path'
|
import { TlError, TlErrors } from '@mtcute/tl-utils/src/types'
|
||||||
import fetch from 'node-fetch'
|
import fetch from 'node-fetch'
|
||||||
import csvParser from 'csv-parser'
|
import csvParser from 'csv-parser'
|
||||||
import { camelToPascal, snakeToCamel } from '@mtcute/tl-utils/src/codegen/utils'
|
|
||||||
import { writeFile } from 'fs/promises'
|
import { writeFile } from 'fs/promises'
|
||||||
|
import { ERRORS_JSON_FILE } from './constants'
|
||||||
|
|
||||||
const OUT_TS_FILE = join(__dirname, '../errors.d.ts')
|
const ERRORS_PAGE_TG = 'https://corefork.telegram.org/api/errors'
|
||||||
const OUT_JS_FILE = join(__dirname, '../errors.js')
|
const ERRORS_PAGE_TELETHON =
|
||||||
|
|
||||||
const TELETHON_ERRORS_CSV =
|
|
||||||
'https://raw.githubusercontent.com/LonamiWebs/Telethon/master/telethon_generator/data/errors.csv'
|
'https://raw.githubusercontent.com/LonamiWebs/Telethon/master/telethon_generator/data/errors.csv'
|
||||||
|
|
||||||
interface ErrorInfo {
|
const baseErrors: TlError[] = [
|
||||||
base?: true
|
|
||||||
virtual?: true
|
|
||||||
codes: string
|
|
||||||
name: string
|
|
||||||
description: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const baseErrors: ErrorInfo[] = [
|
|
||||||
{
|
{
|
||||||
codes: '400',
|
code: 400,
|
||||||
name: 'BAD_REQUEST',
|
name: 'BAD_REQUEST',
|
||||||
description:
|
description:
|
||||||
'The query contains errors. In the event that a request was created using a form ' +
|
'The query contains errors. In the event that a request was created using a form ' +
|
||||||
|
@ -28,26 +18,26 @@ const baseErrors: ErrorInfo[] = [
|
||||||
'be corrected before the query is repeated',
|
'be corrected before the query is repeated',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
codes: '401',
|
code: 401,
|
||||||
name: 'UNAUTHORIZED',
|
name: 'UNAUTHORIZED',
|
||||||
description:
|
description:
|
||||||
'There was an unauthorized attempt to use functionality available only to authorized users.',
|
'There was an unauthorized attempt to use functionality available only to authorized users.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
codes: '403',
|
code: 403,
|
||||||
name: 'FORBIDDEN',
|
name: 'FORBIDDEN',
|
||||||
description:
|
description:
|
||||||
'Privacy violation. For example, an attempt to write a message ' +
|
'Privacy violation. For example, an attempt to write a message ' +
|
||||||
'to someone who has blacklisted the current user.',
|
'to someone who has blacklisted the current user.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
codes: '404',
|
code: 404,
|
||||||
name: 'NOT_FOUND',
|
name: 'NOT_FOUND',
|
||||||
description:
|
description:
|
||||||
'An attempt to invoke a non-existent object, such as a method.',
|
'An attempt to invoke a non-existent object, such as a method.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
codes: '420',
|
code: 420,
|
||||||
name: 'FLOOD',
|
name: 'FLOOD',
|
||||||
description:
|
description:
|
||||||
'The maximum allowed number of attempts to invoke the given method' +
|
'The maximum allowed number of attempts to invoke the given method' +
|
||||||
|
@ -56,13 +46,13 @@ const baseErrors: ErrorInfo[] = [
|
||||||
'phone number.',
|
'phone number.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
codes: '303',
|
code: 303,
|
||||||
name: 'SEE_OTHER',
|
name: 'SEE_OTHER',
|
||||||
description:
|
description:
|
||||||
'The request must be repeated, but directed to a different data center',
|
'The request must be repeated, but directed to a different data center',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
codes: '406',
|
code: 406,
|
||||||
name: 'NOT_ACCEPTABLE',
|
name: 'NOT_ACCEPTABLE',
|
||||||
description:
|
description:
|
||||||
'Similar to 400 BAD_REQUEST, but the app should not display any error messages to user ' +
|
'Similar to 400 BAD_REQUEST, but the app should not display any error messages to user ' +
|
||||||
|
@ -70,239 +60,174 @@ const baseErrors: ErrorInfo[] = [
|
||||||
'updateServiceNotification instead.',
|
'updateServiceNotification instead.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
codes: '500',
|
code: 500,
|
||||||
name: 'INTERNAL',
|
name: 'INTERNAL',
|
||||||
description:
|
description:
|
||||||
'An internal server error occurred while a request was being processed; ' +
|
'An internal server error occurred while a request was being processed; ' +
|
||||||
'for example, there was a disruption while accessing a database or file storage.',
|
'for example, there was a disruption while accessing a database or file storage.',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
baseErrors.forEach((it) => (it.base = true))
|
|
||||||
|
|
||||||
const virtualErrors: ErrorInfo[] = [
|
const virtualErrors: TlError[] = [
|
||||||
{
|
{
|
||||||
name: 'RPC_TIMEOUT',
|
name: 'RPC_TIMEOUT',
|
||||||
codes: '408',
|
code: 408,
|
||||||
description: 'The set RPC timeout has exceeded',
|
description: 'The set RPC timeout has exceeded',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'MESSAGE_NOT_FOUND',
|
name: 'MESSAGE_NOT_FOUND',
|
||||||
codes: '404',
|
code: 404,
|
||||||
description: 'Message was not found',
|
description: 'Message was not found',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
virtualErrors.forEach((it) => (it.virtual = true))
|
virtualErrors.forEach((it) => (it.virtual = true))
|
||||||
|
|
||||||
const inheritanceTable: Record<string, string> = {
|
async function fetchFromTelegram(errors: TlErrors) {
|
||||||
400: 'BadRequestError',
|
const page = await fetch(ERRORS_PAGE_TG).then((it) => it.text())
|
||||||
401: 'UnauthorizedError',
|
const jsonUrl = page.match(
|
||||||
403: 'ForbiddenError',
|
/can be found <a href="([^"]+)">here »<\/a>/i
|
||||||
404: 'NotFoundError',
|
)![1]
|
||||||
420: 'FloodError',
|
|
||||||
303: 'SeeOtherError',
|
|
||||||
406: 'NotAcceptableError',
|
|
||||||
500: 'InternalError',
|
|
||||||
}
|
|
||||||
|
|
||||||
const RPC_ERROR_CLASS_JS = `
|
const json = await fetch(new URL(jsonUrl, ERRORS_PAGE_TG)).then((it) =>
|
||||||
class RpcError extends Error {
|
it.json()
|
||||||
constructor(code, text, description) {
|
|
||||||
super(description);
|
|
||||||
this.code = code;
|
|
||||||
this.text = text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exports.RpcError = RpcError;
|
|
||||||
`.trimStart()
|
|
||||||
|
|
||||||
const RPC_ERROR_CLASS_TS = `
|
|
||||||
export declare class RpcError extends Error {
|
|
||||||
code: number;
|
|
||||||
text: string;
|
|
||||||
constructor (code: number, text: string, description?: string);
|
|
||||||
}
|
|
||||||
`.trimStart()
|
|
||||||
|
|
||||||
const BASE_ERROR_TEMPLATE_JS = `
|
|
||||||
class {className} extends RpcError {
|
|
||||||
constructor(name, description) {
|
|
||||||
super({code}, name, description);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exports.{className} = {className}
|
|
||||||
`
|
|
||||||
const BASE_ERROR_TEMPLATE_TS = `
|
|
||||||
export declare class {className} extends RpcError {
|
|
||||||
constructor (name: string, description: string);
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const TL_BUILDER_TEMPLATE_JS = `
|
|
||||||
exports.createRpcErrorFromTl = function (obj) {
|
|
||||||
if (obj.errorMessage in _staticNameErrors) return new _staticNameErrors[obj.errorMessage]();
|
|
||||||
|
|
||||||
let match;
|
|
||||||
{parametrized}
|
|
||||||
|
|
||||||
if (obj.errorCode in _baseCodeErrors) return new _baseCodeErrors[obj.errorCode](obj.errorMessage);
|
|
||||||
|
|
||||||
return new RpcError(obj.errorCode, obj.errorMessage);
|
|
||||||
}
|
|
||||||
`.trim()
|
|
||||||
|
|
||||||
const DESCRIPTION_PARAM_RE = /_X_|_X$|^X_/
|
|
||||||
|
|
||||||
function jsComment(s: string): string {
|
|
||||||
return (
|
|
||||||
'/**' +
|
|
||||||
s
|
|
||||||
.replace(/(?![^\n]{1,60}$)([^\n]{1,60})\s/g, '$1\n')
|
|
||||||
.replace(/\n|^/g, '\n * ') +
|
|
||||||
'\n */'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// since nobody fucking guarantees that .descriptions
|
||||||
|
// will have description for each described here (or vice versa),
|
||||||
|
// we will process them independently
|
||||||
|
|
||||||
|
for (const code of Object.keys(json.errors)) {
|
||||||
|
for (const name of Object.keys(json.errors[code])) {
|
||||||
|
const thrownBy = json.errors[code][name]
|
||||||
|
|
||||||
|
const _code = parseInt(code)
|
||||||
|
if (isNaN(_code)) {
|
||||||
|
throw new Error(`Invalid code: ${code}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchTelethonErrors(): Promise<ErrorInfo[]> {
|
if (!(name in errors.errors)) {
|
||||||
const stream = await fetch(TELETHON_ERRORS_CSV).then((i) => i.body!)
|
errors.errors[name] = {
|
||||||
|
code: _code,
|
||||||
|
name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
for (const method of thrownBy) {
|
||||||
const ret: ErrorInfo[] = []
|
if (!(method in errors.throws)) {
|
||||||
|
errors.throws[method] = []
|
||||||
|
}
|
||||||
|
|
||||||
stream
|
if (errors.throws[method].indexOf(name) === -1) {
|
||||||
.pipe(csvParser())
|
errors.throws[method].push(name)
|
||||||
.on('data', (it) => ret.push(it))
|
}
|
||||||
.on('end', () => resolve(ret))
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const name of Object.keys(json.descriptions)) {
|
||||||
|
if (!(name in errors.errors)) {
|
||||||
|
errors.errors[name] = {
|
||||||
|
_auto: true,
|
||||||
|
code: 400,
|
||||||
|
name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errors.errors[name].description = json.descriptions[name]
|
||||||
|
}
|
||||||
|
|
||||||
|
json.user_only.forEach((it: string) => (errors.userOnly[it] = 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchFromTelethon(errors: TlErrors) {
|
||||||
|
const csv = await fetch(ERRORS_PAGE_TELETHON)
|
||||||
|
const parser = csvParser()
|
||||||
|
|
||||||
|
function addError(name: string, codes: string, description: string): void {
|
||||||
|
if (!codes) return
|
||||||
|
if (name === 'TIMEOUT') return
|
||||||
|
|
||||||
|
const code = parseInt(codes)
|
||||||
|
if (isNaN(code)) {
|
||||||
|
throw new Error(`Invalid code: ${codes} (name: ${name})`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// telethon uses numbers for parameters instead of printf-like
|
||||||
|
// we'll convert it back to printf-like
|
||||||
|
// so far, only one param is supported
|
||||||
|
name = name.replace(/_0(_)?/g, '_%d$1')
|
||||||
|
|
||||||
|
if (!(name in errors.errors)) {
|
||||||
|
errors.errors[name] = {
|
||||||
|
code,
|
||||||
|
name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const obj = errors.errors[name]
|
||||||
|
if (obj._auto) {
|
||||||
|
obj.code = code
|
||||||
|
delete obj._auto
|
||||||
|
}
|
||||||
|
|
||||||
|
// same with descriptions, telethon uses python-like formatting
|
||||||
|
// strings. we'll convert it to printf-like, while also saving parameter
|
||||||
|
// 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)
|
||||||
|
return '%d'
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!obj.description || obj._paramNames?.length) {
|
||||||
|
obj.description = desc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
csv.body
|
||||||
|
.pipe(parser)
|
||||||
|
.on('data', ({ name, codes, description }) =>
|
||||||
|
addError(name, codes, description)
|
||||||
|
)
|
||||||
|
.on('end', resolve)
|
||||||
.on('error', reject)
|
.on('error', reject)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ExtendedErrorInfo extends ErrorInfo {
|
|
||||||
className: string
|
|
||||||
code: string
|
|
||||||
inherits: string
|
|
||||||
argument: string | null
|
|
||||||
}
|
|
||||||
|
|
||||||
function getExtendedErrorInfo(err: ErrorInfo): ExtendedErrorInfo {
|
|
||||||
const [, argument] = err.description.match(/{([a-z_]+)}/i) ?? [, null]
|
|
||||||
|
|
||||||
const ret = err as ExtendedErrorInfo
|
|
||||||
|
|
||||||
let className = err.name
|
|
||||||
if (className[0].match(/[0-9]/)) {
|
|
||||||
className = '_' + className
|
|
||||||
}
|
|
||||||
className = className.replace(DESCRIPTION_PARAM_RE, (i) =>
|
|
||||||
i === '_X_' ? '_' : ''
|
|
||||||
)
|
|
||||||
|
|
||||||
ret.className =
|
|
||||||
camelToPascal(snakeToCamel(className.toLowerCase())) + 'Error'
|
|
||||||
ret.code = err.codes.split(' ')[0]
|
|
||||||
ret.inherits = err.base
|
|
||||||
? 'RpcError'
|
|
||||||
: inheritanceTable[ret.code] ?? 'RpcError'
|
|
||||||
ret.argument = argument ? snakeToCamel(argument) : null
|
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
|
const errors: TlErrors = {
|
||||||
|
base: baseErrors,
|
||||||
|
errors: {},
|
||||||
|
throws: {},
|
||||||
|
userOnly: {},
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Fetching errors from Telegram...')
|
||||||
|
await fetchFromTelegram(errors)
|
||||||
|
|
||||||
|
// using some incredible fucking crutches we are also able to parse telethon errors file
|
||||||
|
// and add missing error descriptions
|
||||||
console.log('Fetching errors from Telethon...')
|
console.log('Fetching errors from Telethon...')
|
||||||
|
await fetchFromTelethon(errors)
|
||||||
|
|
||||||
const errors = [
|
virtualErrors.forEach((err) => {
|
||||||
...baseErrors,
|
if (errors.errors[err.name]) {
|
||||||
...(await fetchTelethonErrors()),
|
console.log(`Error ${err.name} already exists and is not virtual`)
|
||||||
...virtualErrors,
|
return
|
||||||
].map(getExtendedErrorInfo)
|
|
||||||
|
|
||||||
console.log('Generating code...')
|
|
||||||
|
|
||||||
let js = RPC_ERROR_CLASS_JS
|
|
||||||
let ts = RPC_ERROR_CLASS_TS
|
|
||||||
|
|
||||||
for (const err of errors) {
|
|
||||||
// generate error class in js
|
|
||||||
if (err.base) {
|
|
||||||
js += BASE_ERROR_TEMPLATE_JS.replace(
|
|
||||||
/{className}/g,
|
|
||||||
err.className
|
|
||||||
).replace(/{code}/g, err.code)
|
|
||||||
} else {
|
|
||||||
js += `class ${err.className} extends ${err.inherits} {\n`
|
|
||||||
js += ` constructor(${err.argument ?? ''}) {\n`
|
|
||||||
|
|
||||||
const description = JSON.stringify(err.description).replace(
|
|
||||||
/{([a-z_]+)}/gi,
|
|
||||||
(_, $1) => `" + ${snakeToCamel($1)} + "`
|
|
||||||
)
|
|
||||||
|
|
||||||
if (err.inherits === 'RpcError') {
|
|
||||||
js += ` super(${err.code}, '${err.name}', ${description});\n`
|
|
||||||
} else {
|
|
||||||
js += ` super('${err.name}', ${description});\n`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err.argument) {
|
errors.errors[err.name] = err
|
||||||
js += ` this.${err.argument} = ${err.argument};\n`
|
})
|
||||||
}
|
|
||||||
|
|
||||||
js += ' }\n}\n'
|
console.log('Saving...')
|
||||||
js += `exports.${err.className} = ${err.className};\n`
|
|
||||||
}
|
|
||||||
|
|
||||||
// generate error class typings
|
await writeFile(ERRORS_JSON_FILE, JSON.stringify(errors))
|
||||||
if (err.description) {
|
|
||||||
ts += jsComment(err.description) + '\n'
|
|
||||||
}
|
|
||||||
if (err.base) {
|
|
||||||
ts += BASE_ERROR_TEMPLATE_TS.replace(/{className}/g, err.className)
|
|
||||||
} else {
|
|
||||||
ts += `export declare class ${err.className} extends ${err.inherits} {\n`
|
|
||||||
|
|
||||||
if (err.argument) {
|
|
||||||
ts += ` ${err.argument}: number;\n`
|
|
||||||
}
|
|
||||||
|
|
||||||
ts += ` constructor (${
|
|
||||||
err.argument ? err.argument + ': number' : ''
|
|
||||||
});\n`
|
|
||||||
ts += '}\n'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ts +=
|
|
||||||
'export declare function createRpcErrorFromTl (obj: object): RpcError;\n'
|
|
||||||
|
|
||||||
js += 'const _staticNameErrors = {\n'
|
|
||||||
for (const err of errors) {
|
|
||||||
if (err.virtual || err.argument) continue
|
|
||||||
js += ` '${err.name}': ${err.className},\n`
|
|
||||||
}
|
|
||||||
js += ` 'Timeout': TimeoutError,\n` // because telegram c:
|
|
||||||
js += '};\n'
|
|
||||||
|
|
||||||
js += 'const _baseCodeErrors = {\n'
|
|
||||||
for (const [code, error] of Object.entries(inheritanceTable)) {
|
|
||||||
js += ` ${code}: ${error},\n`
|
|
||||||
}
|
|
||||||
js += '};\n'
|
|
||||||
|
|
||||||
let builderInner = ''
|
|
||||||
for (const err of errors) {
|
|
||||||
if (err.virtual || !err.argument) continue
|
|
||||||
|
|
||||||
const regex = err.name.replace(DESCRIPTION_PARAM_RE, (s) =>
|
|
||||||
s.replace('X', '(\\d+)')
|
|
||||||
)
|
|
||||||
builderInner +=
|
|
||||||
`if ((match=obj.errorMessage.match(/${regex}/))!=null)` +
|
|
||||||
`return new ${err.className}(parseInt(match[1]));\n`
|
|
||||||
}
|
|
||||||
js += TL_BUILDER_TEMPLATE_JS.replace('{parametrized}', builderInner)
|
|
||||||
|
|
||||||
await writeFile(OUT_JS_FILE, js)
|
|
||||||
await writeFile(OUT_TS_FILE, ts)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch(console.error)
|
main().catch(console.error)
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
import { unpackTlSchema } from './schema'
|
import { unpackTlSchema } from './schema'
|
||||||
import { API_SCHEMA_JSON_FILE, MTP_SCHEMA_JSON_FILE, ESM_PRELUDE } from './constants'
|
import {
|
||||||
|
API_SCHEMA_JSON_FILE,
|
||||||
|
MTP_SCHEMA_JSON_FILE,
|
||||||
|
ESM_PRELUDE,
|
||||||
|
ERRORS_JSON_FILE,
|
||||||
|
} from './constants'
|
||||||
import { readFile, writeFile } from 'fs/promises'
|
import { readFile, writeFile } from 'fs/promises'
|
||||||
import { parseFullTlSchema } from '@mtcute/tl-utils/src/schema'
|
import { parseFullTlSchema } from '@mtcute/tl-utils/src/schema'
|
||||||
import { TlFullSchema } from '@mtcute/tl-utils/src/types'
|
import { TlErrors, TlFullSchema } from '@mtcute/tl-utils/src/types'
|
||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
import { generateTypescriptDefinitionsForTlSchema } from '@mtcute/tl-utils/src/codegen/types'
|
import { generateTypescriptDefinitionsForTlSchema } from '@mtcute/tl-utils/src/codegen/types'
|
||||||
import { generateReaderCodeForTlEntries } from '@mtcute/tl-utils/src/codegen/reader'
|
import { generateReaderCodeForTlEntries } from '@mtcute/tl-utils/src/codegen/reader'
|
||||||
|
@ -16,17 +21,21 @@ const OUT_WRITERS_FILE = join(__dirname, '../binary/writer.js')
|
||||||
async function generateTypings(
|
async function generateTypings(
|
||||||
apiSchema: TlFullSchema,
|
apiSchema: TlFullSchema,
|
||||||
apiLayer: number,
|
apiLayer: number,
|
||||||
mtpSchema: TlFullSchema
|
mtpSchema: TlFullSchema,
|
||||||
|
errors: TlErrors
|
||||||
) {
|
) {
|
||||||
console.log('Generating typings...')
|
console.log('Generating typings...')
|
||||||
const [apiTs, apiJs] = generateTypescriptDefinitionsForTlSchema(
|
const [apiTs, apiJs] = generateTypescriptDefinitionsForTlSchema(
|
||||||
apiSchema,
|
apiSchema,
|
||||||
apiLayer
|
apiLayer,
|
||||||
|
undefined,
|
||||||
|
errors
|
||||||
)
|
)
|
||||||
const [mtpTs, mtpJs] = generateTypescriptDefinitionsForTlSchema(
|
const [mtpTs, mtpJs] = generateTypescriptDefinitionsForTlSchema(
|
||||||
mtpSchema,
|
mtpSchema,
|
||||||
0,
|
0,
|
||||||
'mtp'
|
'mtp',
|
||||||
|
errors
|
||||||
)
|
)
|
||||||
|
|
||||||
await writeFile(
|
await writeFile(
|
||||||
|
@ -67,6 +76,10 @@ async function generateWriters(
|
||||||
}
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
|
const errors: TlErrors = JSON.parse(
|
||||||
|
await readFile(ERRORS_JSON_FILE, 'utf8')
|
||||||
|
)
|
||||||
|
|
||||||
const [apiSchema, apiLayer] = unpackTlSchema(
|
const [apiSchema, apiLayer] = unpackTlSchema(
|
||||||
JSON.parse(await readFile(API_SCHEMA_JSON_FILE, 'utf8'))
|
JSON.parse(await readFile(API_SCHEMA_JSON_FILE, 'utf8'))
|
||||||
)
|
)
|
||||||
|
@ -74,7 +87,7 @@ async function main() {
|
||||||
JSON.parse(await readFile(MTP_SCHEMA_JSON_FILE, 'utf8'))
|
JSON.parse(await readFile(MTP_SCHEMA_JSON_FILE, 'utf8'))
|
||||||
)
|
)
|
||||||
|
|
||||||
await generateTypings(apiSchema, apiLayer, mtpSchema)
|
await generateTypings(apiSchema, apiLayer, mtpSchema, errors)
|
||||||
await generateReaders(apiSchema, mtpSchema)
|
await generateReaders(apiSchema, mtpSchema)
|
||||||
await generateWriters(apiSchema, mtpSchema)
|
await generateWriters(apiSchema, mtpSchema)
|
||||||
|
|
||||||
|
|
|
@ -2,22 +2,14 @@
|
||||||
// This is a test for TypeScript typings
|
// This is a test for TypeScript typings
|
||||||
// This file is never executed, only compiled
|
// This file is never executed, only compiled
|
||||||
|
|
||||||
import * as rawSchema from '../raw-schema'
|
|
||||||
import readerMap from '../binary/reader'
|
import readerMap from '../binary/reader'
|
||||||
import writerMap from '../binary/writer'
|
import writerMap from '../binary/writer'
|
||||||
import { BadRequestError, RpcError } from '../errors'
|
import { tl } from '../'
|
||||||
|
|
||||||
const layer: string = rawSchema.apiLayer
|
readerMap[0].call(null, null)
|
||||||
Object.entries(rawSchema.api).forEach(([ns, content]) => {
|
writerMap['mt_message'].call(null, null, {})
|
||||||
content.classes.forEach((cls) => {
|
|
||||||
const name: string = cls.type
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
readerMap[0].call(null)
|
const error: tl.errors.RpcError = new tl.errors.BadRequestError(
|
||||||
writerMap['mt_message'].call(null, {})
|
|
||||||
|
|
||||||
const error: RpcError = new BadRequestError(
|
|
||||||
'BAD_REQUEST',
|
'BAD_REQUEST',
|
||||||
'Client has issued an invalid request'
|
'Client has issued an invalid request'
|
||||||
)
|
)
|
||||||
|
|
|
@ -1121,7 +1121,7 @@
|
||||||
integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==
|
integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==
|
||||||
|
|
||||||
"@types/integer@*":
|
"@types/integer@*":
|
||||||
version "4.0.0"
|
version "5.4.1
|
||||||
resolved "https://registry.yarnpkg.com/@types/integer/-/integer-4.0.0.tgz#3b778715df72d2cf8ba73bad27bd9d830907f944"
|
resolved "https://registry.yarnpkg.com/@types/integer/-/integer-4.0.0.tgz#3b778715df72d2cf8ba73bad27bd9d830907f944"
|
||||||
integrity sha512-2U1i6bIRiqizl6O+ETkp2HhUZIxg7g+burUabh9tzGd0qcszfNaFRaY9bGNlQKgEU7DCsH5qMajRDW5QamWQbw==
|
integrity sha512-2U1i6bIRiqizl6O+ETkp2HhUZIxg7g+burUabh9tzGd0qcszfNaFRaY9bGNlQKgEU7DCsH5qMajRDW5QamWQbw==
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue