build: preparing for publish, day 6
i am slowly descending to madness bugs fixed, stuff exported, and maybe something else
This commit is contained in:
parent
c46f113f1f
commit
079d65b38d
20 changed files with 152 additions and 88 deletions
|
@ -21,6 +21,7 @@
|
||||||
"@types/mocha": "^8.2.0",
|
"@types/mocha": "^8.2.0",
|
||||||
"@types/node": "^14.14.22",
|
"@types/node": "^14.14.22",
|
||||||
"@types/node-forge": "^0.9.7",
|
"@types/node-forge": "^0.9.7",
|
||||||
|
"@types/node-fetch": "^2.5.10",
|
||||||
"@types/pako": "^1.0.1",
|
"@types/pako": "^1.0.1",
|
||||||
"@types/ws": "^7.4.0",
|
"@types/ws": "^7.4.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.15.0",
|
"@typescript-eslint/eslint-plugin": "^4.15.0",
|
||||||
|
|
|
@ -155,6 +155,7 @@ import { updateUsername } from './methods/users/update-username'
|
||||||
import { IMessageEntityParser } from './parser'
|
import { IMessageEntityParser } from './parser'
|
||||||
import { Readable } from 'stream'
|
import { Readable } from 'stream'
|
||||||
import {
|
import {
|
||||||
|
ArrayWithTotal,
|
||||||
Chat,
|
Chat,
|
||||||
ChatEvent,
|
ChatEvent,
|
||||||
ChatInviteLink,
|
ChatInviteLink,
|
||||||
|
@ -523,7 +524,6 @@ export interface TelegramClient extends BaseTelegramClient {
|
||||||
* @param queryId Inline query ID
|
* @param queryId Inline query ID
|
||||||
* @param results Results of the query
|
* @param results Results of the query
|
||||||
* @param params Additional parameters
|
* @param params Additional parameters
|
||||||
|
|
||||||
*/
|
*/
|
||||||
answerInlineQuery(
|
answerInlineQuery(
|
||||||
queryId: tl.Long,
|
queryId: tl.Long,
|
||||||
|
@ -984,7 +984,7 @@ export interface TelegramClient extends BaseTelegramClient {
|
||||||
| 'contacts'
|
| 'contacts'
|
||||||
| 'mention'
|
| 'mention'
|
||||||
}
|
}
|
||||||
): Promise<ChatMember[]>
|
): Promise<ArrayWithTotal<ChatMember>>
|
||||||
/**
|
/**
|
||||||
* Get preview information about a private chat.
|
* Get preview information about a private chat.
|
||||||
*
|
*
|
||||||
|
@ -1286,7 +1286,6 @@ export interface TelegramClient extends BaseTelegramClient {
|
||||||
*
|
*
|
||||||
* @param folder Parameters for the folder
|
* @param folder Parameters for the folder
|
||||||
* @returns Newly created folder
|
* @returns Newly created folder
|
||||||
|
|
||||||
*/
|
*/
|
||||||
createFolder(
|
createFolder(
|
||||||
folder: PartialExcept<tl.RawDialogFilter, 'title'>
|
folder: PartialExcept<tl.RawDialogFilter, 'title'>
|
||||||
|
@ -1443,7 +1442,6 @@ export interface TelegramClient extends BaseTelegramClient {
|
||||||
* > into memory at once. This might cause an issue, so use wisely!
|
* > into memory at once. This might cause an issue, so use wisely!
|
||||||
*
|
*
|
||||||
* @param params File download parameters
|
* @param params File download parameters
|
||||||
|
|
||||||
*/
|
*/
|
||||||
downloadAsBuffer(params: FileDownloadParameters): Promise<Buffer>
|
downloadAsBuffer(params: FileDownloadParameters): Promise<Buffer>
|
||||||
/**
|
/**
|
||||||
|
@ -1452,7 +1450,6 @@ export interface TelegramClient extends BaseTelegramClient {
|
||||||
*
|
*
|
||||||
* @param filename Local file name to which the remote file will be downloaded
|
* @param filename Local file name to which the remote file will be downloaded
|
||||||
* @param params File download parameters
|
* @param params File download parameters
|
||||||
|
|
||||||
*/
|
*/
|
||||||
downloadToFile(
|
downloadToFile(
|
||||||
filename: string,
|
filename: string,
|
||||||
|
@ -1464,7 +1461,6 @@ export interface TelegramClient extends BaseTelegramClient {
|
||||||
* consecutive.
|
* consecutive.
|
||||||
*
|
*
|
||||||
* @param params Download parameters
|
* @param params Download parameters
|
||||||
|
|
||||||
*/
|
*/
|
||||||
downloadAsIterable(
|
downloadAsIterable(
|
||||||
params: FileDownloadParameters
|
params: FileDownloadParameters
|
||||||
|
@ -1474,7 +1470,6 @@ export interface TelegramClient extends BaseTelegramClient {
|
||||||
* streaming file contents.
|
* streaming file contents.
|
||||||
*
|
*
|
||||||
* @param params File download parameters
|
* @param params File download parameters
|
||||||
|
|
||||||
*/
|
*/
|
||||||
downloadAsStream(params: FileDownloadParameters): Readable
|
downloadAsStream(params: FileDownloadParameters): Readable
|
||||||
/**
|
/**
|
||||||
|
@ -1983,7 +1978,6 @@ export interface TelegramClient extends BaseTelegramClient {
|
||||||
*
|
*
|
||||||
* @param chatId Chat ID
|
* @param chatId Chat ID
|
||||||
* @param message ID of one of the messages in the group
|
* @param message ID of one of the messages in the group
|
||||||
|
|
||||||
*/
|
*/
|
||||||
getMessageGroup(chatId: InputPeerLike, message: number): Promise<Message[]>
|
getMessageGroup(chatId: InputPeerLike, message: number): Promise<Message[]>
|
||||||
/**
|
/**
|
||||||
|
@ -2275,6 +2269,9 @@ export interface TelegramClient extends BaseTelegramClient {
|
||||||
/**
|
/**
|
||||||
* Send a group of media.
|
* Send a group of media.
|
||||||
*
|
*
|
||||||
|
* To add a caption to the group, add caption to the first
|
||||||
|
* media in the group and don't add caption for any other.
|
||||||
|
*
|
||||||
* @param chatId ID of the chat, its username, phone or `"me"` or `"self"`
|
* @param chatId ID of the chat, its username, phone or `"me"` or `"self"`
|
||||||
* @param medias Medias contained in the message.
|
* @param medias Medias contained in the message.
|
||||||
* @param params Additional sending parameters
|
* @param params Additional sending parameters
|
||||||
|
@ -2282,7 +2279,7 @@ export interface TelegramClient extends BaseTelegramClient {
|
||||||
*/
|
*/
|
||||||
sendMediaGroup(
|
sendMediaGroup(
|
||||||
chatId: InputPeerLike,
|
chatId: InputPeerLike,
|
||||||
medias: InputMediaLike[],
|
medias: (InputMediaLike | string)[],
|
||||||
params?: {
|
params?: {
|
||||||
/**
|
/**
|
||||||
* Message to reply to. Either a message object or message ID.
|
* Message to reply to. Either a message object or message ID.
|
||||||
|
|
|
@ -10,3 +10,4 @@ export * from './parser'
|
||||||
export * from './types'
|
export * from './types'
|
||||||
export * from './client'
|
export * from './client'
|
||||||
export * from './utils/peer-utils'
|
export * from './utils/peer-utils'
|
||||||
|
export { createDummyUpdate } from './utils/updates-utils'
|
||||||
|
|
|
@ -38,6 +38,7 @@ import {
|
||||||
UsersIndex,
|
UsersIndex,
|
||||||
ChatsIndex,
|
ChatsIndex,
|
||||||
GameHighScore,
|
GameHighScore,
|
||||||
|
ArrayWithTotal,
|
||||||
} from '../types'
|
} from '../types'
|
||||||
|
|
||||||
// @copy
|
// @copy
|
||||||
|
|
|
@ -12,6 +12,7 @@ import {
|
||||||
} from '../../utils/peer-utils'
|
} from '../../utils/peer-utils'
|
||||||
import { assertTypeIs } from '../../utils/type-assertion'
|
import { assertTypeIs } from '../../utils/type-assertion'
|
||||||
import { tl } from '@mtcute/tl'
|
import { tl } from '@mtcute/tl'
|
||||||
|
import { ArrayWithTotal } from '../../types'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a chunk of members of some chat.
|
* Get a chunk of members of some chat.
|
||||||
|
@ -68,7 +69,7 @@ export async function getChatMembers(
|
||||||
| 'contacts'
|
| 'contacts'
|
||||||
| 'mention'
|
| 'mention'
|
||||||
}
|
}
|
||||||
): Promise<ChatMember[]> {
|
): Promise<ArrayWithTotal<ChatMember>> {
|
||||||
if (!params) params = {}
|
if (!params) params = {}
|
||||||
|
|
||||||
const chat = await this.resolvePeer(chatId)
|
const chat = await this.resolvePeer(chatId)
|
||||||
|
@ -95,7 +96,10 @@ export async function getChatMembers(
|
||||||
|
|
||||||
const { users } = createUsersChatsIndex(res)
|
const { users } = createUsersChatsIndex(res)
|
||||||
|
|
||||||
return members.map((m) => new ChatMember(this, m, users))
|
const ret = members.map((m) => new ChatMember(this, m, users)) as ArrayWithTotal<ChatMember>
|
||||||
|
|
||||||
|
ret.total = ret.length
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isInputPeerChannel(chat)) {
|
if (isInputPeerChannel(chat)) {
|
||||||
|
@ -146,7 +150,10 @@ export async function getChatMembers(
|
||||||
)
|
)
|
||||||
|
|
||||||
const { users } = createUsersChatsIndex(res)
|
const { users } = createUsersChatsIndex(res)
|
||||||
return res.participants.map((i) => new ChatMember(this, i, users))
|
|
||||||
|
const ret = res.participants.map((i) => new ChatMember(this, i, users)) as ArrayWithTotal<ChatMember>
|
||||||
|
ret.total = res.count
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new MtCuteInvalidPeerTypeError(chatId, 'chat or channel')
|
throw new MtCuteInvalidPeerTypeError(chatId, 'chat or channel')
|
||||||
|
|
|
@ -136,6 +136,45 @@ export async function uploadFile(
|
||||||
file = convertWebStreamToNodeReadable(file)
|
file = convertWebStreamToNodeReadable(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof file === 'object' && 'headers' in file && 'body' in file && 'url' in file) {
|
||||||
|
// fetch() response
|
||||||
|
const length = parseInt(file.headers.get('content-length') || '0')
|
||||||
|
if (!isNaN(length) && length) fileSize = length
|
||||||
|
|
||||||
|
fileMime = file.headers.get('content-type')?.split(';')[0]
|
||||||
|
|
||||||
|
const disposition = file.headers.get('content-disposition')
|
||||||
|
if (disposition) {
|
||||||
|
const idx = disposition.indexOf('filename=')
|
||||||
|
|
||||||
|
if (idx > -1) {
|
||||||
|
const raw = disposition.slice(idx + 9).split(';')[0]
|
||||||
|
fileName = JSON.parse(raw)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileName === 'unnamed') {
|
||||||
|
// try to infer from url
|
||||||
|
const url = new URL(file.url)
|
||||||
|
const name = url.pathname.split('/').pop()
|
||||||
|
if (name && name.indexOf('.') > -1) {
|
||||||
|
fileName = name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file.body)
|
||||||
|
throw new MtCuteArgumentError('Fetch response contains `null` body')
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof ReadableStream !== 'undefined' &&
|
||||||
|
file.body instanceof ReadableStream
|
||||||
|
) {
|
||||||
|
file = convertWebStreamToNodeReadable(file.body)
|
||||||
|
} else {
|
||||||
|
file = file.body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// override file name and mime (if any)
|
// override file name and mime (if any)
|
||||||
if (params.fileName) fileName = params.fileName
|
if (params.fileName) fileName = params.fileName
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,9 @@ export async function getHistory(
|
||||||
|
|
||||||
const { users, chats } = createUsersChatsIndex(res)
|
const { users, chats } = createUsersChatsIndex(res)
|
||||||
|
|
||||||
const msgs = res.messages.map((msg) => new Message(this, msg, users, chats))
|
const msgs = res.messages
|
||||||
|
.filter((msg) => msg._ !== 'messageEmpty')
|
||||||
|
.map((msg) => new Message(this, msg, users, chats))
|
||||||
|
|
||||||
if (params.reverse) msgs.reverse()
|
if (params.reverse) msgs.reverse()
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,9 @@ export async function getMessages(
|
||||||
|
|
||||||
const { users, chats } = createUsersChatsIndex(res)
|
const { users, chats } = createUsersChatsIndex(res)
|
||||||
|
|
||||||
const ret = res.messages.map((msg) => new Message(this, msg, users, chats))
|
const ret = res.messages
|
||||||
|
.filter((msg) => msg._ !== 'messageEmpty')
|
||||||
|
.map((msg) => new Message(this, msg, users, chats))
|
||||||
|
|
||||||
return isSingle ? ret[0] : ret
|
return isSingle ? ret[0] : ret
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,9 +79,9 @@ export async function* searchGlobal(
|
||||||
|
|
||||||
const { users, chats } = createUsersChatsIndex(res)
|
const { users, chats } = createUsersChatsIndex(res)
|
||||||
|
|
||||||
const msgs = res.messages.map(
|
const msgs = res.messages
|
||||||
(msg) => new Message(this, msg, users, chats)
|
.filter((msg) => msg._ !== 'messageEmpty')
|
||||||
)
|
.map((msg) => new Message(this, msg, users, chats))
|
||||||
|
|
||||||
if (!msgs.length) break
|
if (!msgs.length) break
|
||||||
|
|
||||||
|
|
|
@ -100,9 +100,9 @@ export async function* searchMessages(
|
||||||
|
|
||||||
const { users, chats } = createUsersChatsIndex(res)
|
const { users, chats } = createUsersChatsIndex(res)
|
||||||
|
|
||||||
const msgs = res.messages.map(
|
const msgs = res.messages
|
||||||
(msg) => new Message(this, msg, users, chats)
|
.filter((msg) => msg._ !== 'messageEmpty')
|
||||||
)
|
.map((msg) => new Message(this, msg, users, chats))
|
||||||
|
|
||||||
if (!msgs.length) break
|
if (!msgs.length) break
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { TelegramClient } from '../../client'
|
import { TelegramClient } from '../../client'
|
||||||
import {
|
import {
|
||||||
BotKeyboard,
|
BotKeyboard, InputFileLike,
|
||||||
InputMediaLike,
|
InputMediaLike,
|
||||||
InputPeerLike,
|
InputPeerLike,
|
||||||
Message,
|
Message,
|
||||||
|
@ -18,6 +18,9 @@ import { createUsersChatsIndex } from '../../utils/peer-utils'
|
||||||
/**
|
/**
|
||||||
* Send a group of media.
|
* Send a group of media.
|
||||||
*
|
*
|
||||||
|
* To add a caption to the group, add caption to the first
|
||||||
|
* media in the group and don't add caption for any other.
|
||||||
|
*
|
||||||
* @param chatId ID of the chat, its username, phone or `"me"` or `"self"`
|
* @param chatId ID of the chat, its username, phone or `"me"` or `"self"`
|
||||||
* @param medias Medias contained in the message.
|
* @param medias Medias contained in the message.
|
||||||
* @param params Additional sending parameters
|
* @param params Additional sending parameters
|
||||||
|
@ -27,7 +30,7 @@ import { createUsersChatsIndex } from '../../utils/peer-utils'
|
||||||
export async function sendMediaGroup(
|
export async function sendMediaGroup(
|
||||||
this: TelegramClient,
|
this: TelegramClient,
|
||||||
chatId: InputPeerLike,
|
chatId: InputPeerLike,
|
||||||
medias: InputMediaLike[],
|
medias: (InputMediaLike | string)[],
|
||||||
params?: {
|
params?: {
|
||||||
/**
|
/**
|
||||||
* Message to reply to. Either a message object or message ID.
|
* Message to reply to. Either a message object or message ID.
|
||||||
|
@ -108,7 +111,15 @@ export async function sendMediaGroup(
|
||||||
const multiMedia: tl.RawInputSingleMedia[] = []
|
const multiMedia: tl.RawInputSingleMedia[] = []
|
||||||
|
|
||||||
for (let i = 0; i < medias.length; i++) {
|
for (let i = 0; i < medias.length; i++) {
|
||||||
const media = medias[i]
|
let media = medias[i]
|
||||||
|
|
||||||
|
if (typeof media === 'string') {
|
||||||
|
media = {
|
||||||
|
type: 'auto',
|
||||||
|
file: media,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const inputMedia = await this._normalizeInputMedia(media, {
|
const inputMedia = await this._normalizeInputMedia(media, {
|
||||||
progressCallback: params.progressCallback?.bind(null, i),
|
progressCallback: params.progressCallback?.bind(null, i),
|
||||||
})
|
})
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { tdFileId } from '@mtcute/file-id'
|
||||||
* - `ReadStream` (for NodeJS, from the `fs` module)
|
* - `ReadStream` (for NodeJS, from the `fs` module)
|
||||||
* - `ReadableStream` (from the Web API, base readable stream)
|
* - `ReadableStream` (from the Web API, base readable stream)
|
||||||
* - `Readable` (for NodeJS, base readable stream)
|
* - `Readable` (for NodeJS, base readable stream)
|
||||||
|
* - `Response` (from `window.fetch` or `node-fetch`)
|
||||||
*/
|
*/
|
||||||
export type UploadFileLike =
|
export type UploadFileLike =
|
||||||
| Buffer
|
| Buffer
|
||||||
|
@ -21,7 +22,14 @@ export type UploadFileLike =
|
||||||
| string
|
| string
|
||||||
| ReadStream
|
| ReadStream
|
||||||
| ReadableStream
|
| ReadableStream
|
||||||
|
| NodeJS.ReadableStream
|
||||||
| Readable
|
| Readable
|
||||||
|
// fetch() response
|
||||||
|
| {
|
||||||
|
headers: any
|
||||||
|
url: string
|
||||||
|
body: ReadableStream<Uint8Array> | NodeJS.ReadableStream | null
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Describes types that can be used as an input
|
* Describes types that can be used as an input
|
||||||
|
|
|
@ -7,5 +7,5 @@ export * from './peers'
|
||||||
export * from './misc'
|
export * from './misc'
|
||||||
|
|
||||||
export * from './errors'
|
export * from './errors'
|
||||||
export { MaybeDynamic } from './utils'
|
export { MaybeDynamic, ArrayWithTotal } from './utils'
|
||||||
export { MaybeAsync, PartialExcept, PartialOnly } from '@mtcute/core'
|
export { MaybeAsync, PartialExcept, PartialOnly } from '@mtcute/core'
|
||||||
|
|
|
@ -101,16 +101,6 @@ export class Message {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Raw TL object.
|
* Raw TL object.
|
||||||
*
|
|
||||||
* > **Note**: In fact, `raw` can also be {@link tl.RawMessageEmpty}.
|
|
||||||
* > But since it is quite rare, for the simplicity sake
|
|
||||||
* > we don't bother thinking about it (and you shouldn't too).
|
|
||||||
* >
|
|
||||||
* > When the {@link Message} is in fact `messageEmpty`,
|
|
||||||
* > `.empty` will be true and trying to access properties
|
|
||||||
* > that are not available will result in {@link MtCuteEmptyError}.
|
|
||||||
* >
|
|
||||||
* > The only property that is available on an "empty" message is `.id`
|
|
||||||
*/
|
*/
|
||||||
readonly raw: tl.RawMessage | tl.RawMessageService
|
readonly raw: tl.RawMessage | tl.RawMessageService
|
||||||
|
|
||||||
|
@ -119,8 +109,6 @@ export class Message {
|
||||||
/** Map of chats in this message. Mainly for internal use */
|
/** Map of chats in this message. Mainly for internal use */
|
||||||
readonly _chats: ChatsIndex
|
readonly _chats: ChatsIndex
|
||||||
|
|
||||||
private _emptyError?: MtCuteEmptyError
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
client: TelegramClient,
|
client: TelegramClient,
|
||||||
raw: tl.TypeMessage,
|
raw: tl.TypeMessage,
|
||||||
|
@ -128,33 +116,18 @@ export class Message {
|
||||||
chats: ChatsIndex,
|
chats: ChatsIndex,
|
||||||
isScheduled = false
|
isScheduled = false
|
||||||
) {
|
) {
|
||||||
|
if (raw._ === 'messageEmpty')
|
||||||
|
throw new MtCuteTypeAssertionError('Message#ctor', 'not messageEmpty', 'messageEmpty')
|
||||||
|
|
||||||
this.client = client
|
this.client = client
|
||||||
this._users = users
|
this._users = users
|
||||||
this._chats = chats
|
this._chats = chats
|
||||||
|
|
||||||
// a bit of cheating in terms of types but whatever :shrug:
|
this.raw = raw
|
||||||
//
|
|
||||||
// using exclude instead of `typeof this.raw` because
|
|
||||||
// TypeMessage might have some other types added, and we'll detect
|
|
||||||
// that at compile time
|
|
||||||
this.raw = raw as Exclude<tl.TypeMessage, tl.RawMessageEmpty>
|
|
||||||
this.empty = raw._ === 'messageEmpty'
|
|
||||||
|
|
||||||
if (this.empty) {
|
|
||||||
this._emptyError = new MtCuteEmptyError()
|
|
||||||
}
|
|
||||||
this.isScheduled = isScheduled
|
this.isScheduled = isScheduled
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the message is empty.
|
|
||||||
*
|
|
||||||
* Note that if the message is empty,
|
|
||||||
* accessing any other property except `id` and `raw`
|
|
||||||
* will result in {@link MtCuteEmptyError}
|
|
||||||
*/
|
|
||||||
readonly empty: boolean
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the message is scheduled.
|
* Whether the message is scheduled.
|
||||||
* If it is, then its {@link date} is set to future.
|
* If it is, then its {@link date} is set to future.
|
||||||
|
@ -172,8 +145,6 @@ export class Message {
|
||||||
* `null` for service messages and non-post messages.
|
* `null` for service messages and non-post messages.
|
||||||
*/
|
*/
|
||||||
get views(): number | null {
|
get views(): number | null {
|
||||||
if (this._emptyError) throw this._emptyError
|
|
||||||
|
|
||||||
return this.raw._ === 'message' ? this.raw.views ?? null : null
|
return this.raw._ === 'message' ? this.raw.views ?? null : null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,8 +155,6 @@ export class Message {
|
||||||
* - Messages to yourself (i.e. *Saved Messages*) are incoming (`outgoing = false`)
|
* - Messages to yourself (i.e. *Saved Messages*) are incoming (`outgoing = false`)
|
||||||
*/
|
*/
|
||||||
get isOutgoing(): boolean {
|
get isOutgoing(): boolean {
|
||||||
if (this._emptyError) throw this._emptyError
|
|
||||||
|
|
||||||
return this.raw.out!
|
return this.raw.out!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,8 +172,6 @@ export class Message {
|
||||||
* `null` for service messages and non-grouped messages
|
* `null` for service messages and non-grouped messages
|
||||||
*/
|
*/
|
||||||
get groupedId(): tl.Long | null {
|
get groupedId(): tl.Long | null {
|
||||||
if (this._emptyError) throw this._emptyError
|
|
||||||
|
|
||||||
return this.raw._ === 'message' ? this.raw.groupedId ?? null : null
|
return this.raw._ === 'message' ? this.raw.groupedId ?? null : null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,8 +191,6 @@ export class Message {
|
||||||
* sender is the channel itself.
|
* sender is the channel itself.
|
||||||
*/
|
*/
|
||||||
get sender(): User | Chat {
|
get sender(): User | Chat {
|
||||||
if (this._emptyError) throw this._emptyError
|
|
||||||
|
|
||||||
if (this._sender === undefined) {
|
if (this._sender === undefined) {
|
||||||
const from = this.raw.fromId
|
const from = this.raw.fromId
|
||||||
if (!from) {
|
if (!from) {
|
||||||
|
@ -270,8 +235,6 @@ export class Message {
|
||||||
* Conversation the message belongs to
|
* Conversation the message belongs to
|
||||||
*/
|
*/
|
||||||
get chat(): Chat {
|
get chat(): Chat {
|
||||||
if (this._emptyError) throw this._emptyError
|
|
||||||
|
|
||||||
if (this._chat === undefined) {
|
if (this._chat === undefined) {
|
||||||
this._chat = Chat._parseFromMessage(
|
this._chat = Chat._parseFromMessage(
|
||||||
this.client,
|
this.client,
|
||||||
|
@ -288,8 +251,6 @@ export class Message {
|
||||||
* Date the message was sent
|
* Date the message was sent
|
||||||
*/
|
*/
|
||||||
get date(): Date {
|
get date(): Date {
|
||||||
if (this._emptyError) throw this._emptyError
|
|
||||||
|
|
||||||
return new Date(this.raw.date * 1000)
|
return new Date(this.raw.date * 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,8 +260,6 @@ export class Message {
|
||||||
* If this message is a forward, contains info about it.
|
* If this message is a forward, contains info about it.
|
||||||
*/
|
*/
|
||||||
get forward(): Message.MessageForwardInfo | null {
|
get forward(): Message.MessageForwardInfo | null {
|
||||||
if (this._emptyError) throw this._emptyError
|
|
||||||
|
|
||||||
if (!this._forward) {
|
if (!this._forward) {
|
||||||
if (this.raw._ !== 'message' || !this.raw.fwdFrom) {
|
if (this.raw._ !== 'message' || !this.raw.fwdFrom) {
|
||||||
this._forward = null
|
this._forward = null
|
||||||
|
@ -386,8 +345,6 @@ export class Message {
|
||||||
* replies to.
|
* replies to.
|
||||||
*/
|
*/
|
||||||
get replyToMessageId(): number | null {
|
get replyToMessageId(): number | null {
|
||||||
if (this._emptyError) throw this._emptyError
|
|
||||||
|
|
||||||
return this.raw.replyTo?.replyToMsgId ?? null
|
return this.raw.replyTo?.replyToMsgId ?? null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,8 +352,6 @@ export class Message {
|
||||||
* Whether this message contains mention of the current user
|
* Whether this message contains mention of the current user
|
||||||
*/
|
*/
|
||||||
get isMention(): boolean {
|
get isMention(): boolean {
|
||||||
if (this._emptyError) throw this._emptyError
|
|
||||||
|
|
||||||
return this.raw.mentioned!
|
return this.raw.mentioned!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,8 +361,6 @@ export class Message {
|
||||||
* information about the bot which generated it
|
* information about the bot which generated it
|
||||||
*/
|
*/
|
||||||
get viaBot(): User | null {
|
get viaBot(): User | null {
|
||||||
if (this._emptyError) throw this._emptyError
|
|
||||||
|
|
||||||
if (this._viaBot === undefined) {
|
if (this._viaBot === undefined) {
|
||||||
if (this.raw._ === 'messageService' || !this.raw.viaBotId) {
|
if (this.raw._ === 'messageService' || !this.raw.viaBotId) {
|
||||||
this._viaBot = null
|
this._viaBot = null
|
||||||
|
@ -429,8 +382,6 @@ export class Message {
|
||||||
* (you should handle i18n yourself)
|
* (you should handle i18n yourself)
|
||||||
*/
|
*/
|
||||||
get text(): string {
|
get text(): string {
|
||||||
if (this._emptyError) throw this._emptyError
|
|
||||||
|
|
||||||
return this.raw._ === 'messageService' ? '' : this.raw.message
|
return this.raw._ === 'messageService' ? '' : this.raw.message
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,8 +390,6 @@ export class Message {
|
||||||
* Message text/caption entities (may be empty)
|
* Message text/caption entities (may be empty)
|
||||||
*/
|
*/
|
||||||
get entities(): ReadonlyArray<MessageEntity> {
|
get entities(): ReadonlyArray<MessageEntity> {
|
||||||
if (this._emptyError) throw this._emptyError
|
|
||||||
|
|
||||||
if (!this._entities) {
|
if (!this._entities) {
|
||||||
this._entities = []
|
this._entities = []
|
||||||
if (this.raw._ === 'message' && this.raw.entities?.length) {
|
if (this.raw._ === 'message' && this.raw.entities?.length) {
|
||||||
|
|
|
@ -2,6 +2,8 @@ import { MaybeAsync } from '@mtcute/core'
|
||||||
|
|
||||||
export type MaybeDynamic<T> = MaybeAsync<T> | (() => MaybeAsync<T>)
|
export type MaybeDynamic<T> = MaybeAsync<T> | (() => MaybeAsync<T>)
|
||||||
|
|
||||||
|
export type ArrayWithTotal<T> = T[] & { total: number }
|
||||||
|
|
||||||
let util: any | null = null
|
let util: any | null = null
|
||||||
try {
|
try {
|
||||||
util = require('util')
|
util = require('util')
|
||||||
|
|
|
@ -62,6 +62,8 @@ export function normalizeToInputUser(
|
||||||
if (tl.isAnyInputUser(res)) return res
|
if (tl.isAnyInputUser(res)) return res
|
||||||
|
|
||||||
switch (res._) {
|
switch (res._) {
|
||||||
|
case 'inputPeerSelf':
|
||||||
|
return { _: 'inputUserSelf' }
|
||||||
case 'inputPeerUser':
|
case 'inputPeerUser':
|
||||||
return {
|
return {
|
||||||
_: 'inputUser',
|
_: 'inputUser',
|
||||||
|
|
|
@ -72,8 +72,18 @@ export function convertWebStreamToNodeReadable(
|
||||||
|
|
||||||
export async function readStreamUntilEnd(stream: Readable): Promise<Buffer> {
|
export async function readStreamUntilEnd(stream: Readable): Promise<Buffer> {
|
||||||
const chunks = []
|
const chunks = []
|
||||||
|
let length = 0
|
||||||
|
|
||||||
while (stream.readable) {
|
while (stream.readable) {
|
||||||
chunks.push(await stream.read())
|
const c = await stream.read()
|
||||||
|
if (c === null) break
|
||||||
|
|
||||||
|
length += c.length
|
||||||
|
if (length > 2097152000) {
|
||||||
|
throw new Error('File is too big')
|
||||||
|
}
|
||||||
|
|
||||||
|
chunks.push(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Buffer.concat(chunks)
|
return Buffer.concat(chunks)
|
||||||
|
|
|
@ -4,7 +4,13 @@ import { MtCuteTypeAssertionError } from '../types'
|
||||||
// dummy updates which are used for methods that return messages.affectedHistory.
|
// dummy updates which are used for methods that return messages.affectedHistory.
|
||||||
// that is not an update, but it carries info about pts, and we need to handle it
|
// that is not an update, but it carries info about pts, and we need to handle it
|
||||||
|
|
||||||
/** @internal */
|
/**
|
||||||
|
* Create a dummy update from PTS and PTS count.
|
||||||
|
*
|
||||||
|
* @param pts PTS
|
||||||
|
* @param ptsCount PTS count
|
||||||
|
* @param channelId Channel ID (bare), if applicable
|
||||||
|
*/
|
||||||
export function createDummyUpdate(
|
export function createDummyUpdate(
|
||||||
pts: number,
|
pts: number,
|
||||||
ptsCount: number,
|
ptsCount: number,
|
||||||
|
|
|
@ -4,6 +4,8 @@ import { parseFileId } from './parse'
|
||||||
import { getBasicPeerType, markedPeerIdToBare } from '@mtcute/core'
|
import { getBasicPeerType, markedPeerIdToBare } from '@mtcute/core'
|
||||||
import FileType = tdFileId.FileType
|
import FileType = tdFileId.FileType
|
||||||
|
|
||||||
|
const EMPTY_BUFFER = Buffer.alloc(0)
|
||||||
|
|
||||||
type FileId = td.RawFullRemoteFileLocation
|
type FileId = td.RawFullRemoteFileLocation
|
||||||
|
|
||||||
function dialogPhotoToInputPeer(
|
function dialogPhotoToInputPeer(
|
||||||
|
@ -182,14 +184,21 @@ export function fileIdToInputDocument(
|
||||||
)
|
)
|
||||||
throw new td.ConversionError('inputDocument')
|
throw new td.ConversionError('inputDocument')
|
||||||
|
|
||||||
if (!fileId.fileReference)
|
let fileRef = fileId.fileReference
|
||||||
|
if (!fileId.fileReference) {
|
||||||
|
if (fileId.type === FileType.Sticker) {
|
||||||
|
// older stickers' file IDs don't have file ref
|
||||||
|
fileRef = EMPTY_BUFFER
|
||||||
|
} else {
|
||||||
throw new td.InvalidFileIdError(
|
throw new td.InvalidFileIdError(
|
||||||
'Expected document to have file reference'
|
'Expected document to have file reference'
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
_: 'inputDocument',
|
_: 'inputDocument',
|
||||||
fileReference: fileId.fileReference,
|
fileReference: fileRef!,
|
||||||
id: fileId.location.id,
|
id: fileId.location.id,
|
||||||
accessHash: fileId.location.accessHash,
|
accessHash: fileId.location.accessHash,
|
||||||
}
|
}
|
||||||
|
|
21
yarn.lock
21
yarn.lock
|
@ -1145,6 +1145,14 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-8.2.0.tgz#3eb56d13a1de1d347ecb1957c6860c911704bc44"
|
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-8.2.0.tgz#3eb56d13a1de1d347ecb1957c6860c911704bc44"
|
||||||
integrity sha512-/Sge3BymXo4lKc31C8OINJgXLaw+7vL1/L1pGiBNpGrBiT8FQiaFpSYV0uhTaG4y78vcMBTMFsWaHDvuD+xGzQ==
|
integrity sha512-/Sge3BymXo4lKc31C8OINJgXLaw+7vL1/L1pGiBNpGrBiT8FQiaFpSYV0uhTaG4y78vcMBTMFsWaHDvuD+xGzQ==
|
||||||
|
|
||||||
|
"@types/node-fetch@^2.5.10":
|
||||||
|
version "2.5.10"
|
||||||
|
resolved "http://localhost:4873/@types%2fnode-fetch/-/node-fetch-2.5.10.tgz#9b4d4a0425562f9fcea70b12cb3fcdd946ca8132"
|
||||||
|
integrity sha512-IpkX0AasN44hgEad0gEF/V6EgR5n69VEqPEgnmoM8GsIGro3PowbWs4tR6IhxUTyPLpOn+fiGG6nrQhcmoCuIQ==
|
||||||
|
dependencies:
|
||||||
|
"@types/node" "*"
|
||||||
|
form-data "^3.0.0"
|
||||||
|
|
||||||
"@types/node-forge@^0.9.7":
|
"@types/node-forge@^0.9.7":
|
||||||
version "0.9.7"
|
version "0.9.7"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node-forge/-/node-forge-0.9.7.tgz#948f7b52d352a6c4ab22d3328c206f0870672db5"
|
resolved "https://registry.yarnpkg.com/@types/node-forge/-/node-forge-0.9.7.tgz#948f7b52d352a6c4ab22d3328c206f0870672db5"
|
||||||
|
@ -1953,9 +1961,9 @@ columnify@^1.5.4:
|
||||||
strip-ansi "^3.0.0"
|
strip-ansi "^3.0.0"
|
||||||
wcwidth "^1.0.0"
|
wcwidth "^1.0.0"
|
||||||
|
|
||||||
combined-stream@^1.0.6, combined-stream@~1.0.6:
|
combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6:
|
||||||
version "1.0.8"
|
version "1.0.8"
|
||||||
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
resolved "http://localhost:4873/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
||||||
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
|
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
|
||||||
dependencies:
|
dependencies:
|
||||||
delayed-stream "~1.0.0"
|
delayed-stream "~1.0.0"
|
||||||
|
@ -2869,6 +2877,15 @@ forever-agent@~0.6.1:
|
||||||
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
|
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
|
||||||
integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
|
integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
|
||||||
|
|
||||||
|
form-data@^3.0.0:
|
||||||
|
version "3.0.1"
|
||||||
|
resolved "http://localhost:4873/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f"
|
||||||
|
integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==
|
||||||
|
dependencies:
|
||||||
|
asynckit "^0.4.0"
|
||||||
|
combined-stream "^1.0.8"
|
||||||
|
mime-types "^2.1.12"
|
||||||
|
|
||||||
form-data@~2.3.2:
|
form-data@~2.3.2:
|
||||||
version "2.3.3"
|
version "2.3.3"
|
||||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
|
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
|
||||||
|
|
Loading…
Reference in a new issue