refactor: initial support for esm

also fixed all circular imports and added checking for them via dpdm
This commit is contained in:
alina 🌸 2023-10-09 05:59:48 +03:00 committed by Alina Tumanova
parent 280a98f52a
commit a03d73503a
339 changed files with 3919 additions and 4983 deletions

View file

@ -33,4 +33,6 @@ jobs:
env: env:
NODE_OPTIONS: "--max_old_space_size=4096" NODE_OPTIONS: "--max_old_space_size=4096"
run: pnpm run lint:ci run: pnpm run lint:ci
- name: 'Circular dependencies'
run: pnpm run lint:dpdm
- run: pnpm run test:all - run: pnpm run test:all

View file

@ -15,6 +15,7 @@ module.exports = {
return [ return [
`prettier --write ${filenames.join(' ')}`, `prettier --write ${filenames.join(' ')}`,
`eslint -c ${eslintCiConfig} --fix ${filenames.join(' ')}`, `eslint -c ${eslintCiConfig} --fix ${filenames.join(' ')}`,
'pnpm run lint:dpdm',
...[...modifiedPackages].map((pkg) => `pnpm -C packages/${pkg} run --if-present build --noEmit`) ...[...modifiedPackages].map((pkg) => `pnpm -C packages/${pkg} run --if-present build --noEmit`)
] ]
} }

View file

@ -12,6 +12,7 @@
"lint": "eslint .", "lint": "eslint .",
"lint:ci": "eslint --config .eslintrc.ci.js .", "lint:ci": "eslint --config .eslintrc.ci.js .",
"lint:tsc": "pnpm run -r build --noEmit", "lint:tsc": "pnpm run -r build --noEmit",
"lint:dpdm": "dpdm -T --no-warning --no-tree --exit-code circular:1 packages/*",
"lint:fix": "eslint --fix .", "lint:fix": "eslint --fix .",
"format": "prettier --write \"packages/**/*.ts\"", "format": "prettier --write \"packages/**/*.ts\"",
"publish-all": "node scripts/publish.js all", "publish-all": "node scripts/publish.js all",
@ -32,6 +33,7 @@
"@typescript-eslint/parser": "6.4.0", "@typescript-eslint/parser": "6.4.0",
"chai": "4.3.7", "chai": "4.3.7",
"dotenv-flow": "3.2.0", "dotenv-flow": "3.2.0",
"dpdm": "^3.14.0",
"eslint": "8.47.0", "eslint": "8.47.0",
"eslint-config-prettier": "8.8.0", "eslint-config-prettier": "8.8.0",
"eslint-import-resolver-typescript": "3.6.0", "eslint-import-resolver-typescript": "3.6.0",

View file

@ -6,10 +6,11 @@
"author": "Alina Sireneva <alina@tei.su>", "author": "Alina Sireneva <alina@tei.su>",
"license": "LGPL-3.0", "license": "LGPL-3.0",
"main": "src/index.ts", "main": "src/index.ts",
"module": "_esm/index.js",
"scripts": { "scripts": {
"test": "mocha -r ts-node/register \"tests/**/*.spec.ts\"", "test": "mocha -r ts-node/register \"tests/**/*.spec.ts\"",
"docs": "typedoc", "docs": "typedoc",
"build": "tsc", "build": "tsc | tsc -p tsconfig.cjs.json",
"gen-client": "node ./scripts/generate-client.js", "gen-client": "node ./scripts/generate-client.js",
"gen-updates": "node ./scripts/generate-updates.js" "gen-updates": "node ./scripts/generate-updates.js"
}, },

View file

@ -64,7 +64,11 @@ function visitRecursively(ast, check, callback) {
} }
function findRawApiUsages(ast, fileName) { function findRawApiUsages(ast, fileName) {
// find `this.call({ _: '...', ...}) // find `cilent.call({ _: '...', ...})
if (ast.kind !== ts.SyntaxKind.FunctionDeclaration) return []
const firstParamName = ast.parameters[0]?.name?.escapedText
if (!firstParamName) return []
const usages = [] const usages = []
@ -75,7 +79,11 @@ function findRawApiUsages(ast, fileName) {
if (call.expression.kind !== ts.SyntaxKind.PropertyAccessExpression) return if (call.expression.kind !== ts.SyntaxKind.PropertyAccessExpression) return
const prop = call.expression const prop = call.expression
if (prop.name.escapedText === 'call' && prop.expression.kind === ts.SyntaxKind.ThisKeyword) { if (
prop.name.escapedText === 'call' &&
prop.expression.kind === ts.SyntaxKind.Identifier &&
prop.expression.escapedText === firstParamName
) {
usages.push(call) usages.push(call)
} }
}, },
@ -248,12 +256,6 @@ async function addSingleMethod(state, fileName) {
) )
} }
const isPrivate =
name[0] === '_' &&
name !== '_handleUpdate' &&
name !== '_normalizeInputFile' &&
name !== '_normalizeInputMedia'
const isExported = (stmt.modifiers || []).find((mod) => mod.kind === ts.SyntaxKind.ExportKeyword) const isExported = (stmt.modifiers || []).find((mod) => mod.kind === ts.SyntaxKind.ExportKeyword)
const isInitialize = checkForFlag(stmt, '@initialize') const isInitialize = checkForFlag(stmt, '@initialize')
const aliases = (function () { const aliases = (function () {
@ -281,18 +283,6 @@ async function addSingleMethod(state, fileName) {
const rawApiMethods = available === null && findRawApiUsages(stmt, fileName) const rawApiMethods = available === null && findRawApiUsages(stmt, fileName)
const dependencies = findDependencies(stmt).filter((it) => it !== name) const dependencies = findDependencies(stmt).filter((it) => it !== name)
if (!isExported && !isPrivate) {
throwError(stmt, fileName, 'Public methods MUST be exported.')
}
if (isExported && !checkForFlag(stmt, '@internal')) {
throwError(
isExported,
fileName,
'Exported methods must be marked as @internal so TS compiler strips them away.',
)
}
if (isInitialize && isExported) { if (isInitialize && isExported) {
throwError(isExported, fileName, 'Initialization methods must not be exported') throwError(isExported, fileName, 'Initialization methods must not be exported')
} }
@ -312,16 +302,8 @@ async function addSingleMethod(state, fileName) {
const firstArg = stmt.parameters[0] const firstArg = stmt.parameters[0]
if ( if (isExported && (!firstArg || firstArg.type.getText() !== 'BaseTelegramClient')) {
isExported && continue
(!firstArg ||
(firstArg.type.getText() !== 'TelegramClient' && firstArg.type.getText() !== 'BaseTelegramClient'))
) {
throwError(
firstArg || stmt.name,
fileName,
'Exported methods must have `BaseTelegramClient` or `TelegramClient` as their first parameter',
)
} }
// overloads // overloads
@ -334,10 +316,19 @@ async function addSingleMethod(state, fileName) {
} }
if (isExported) { if (isExported) {
const isPrivate = checkForFlag(stmt, '@internal')
const isManual = checkForFlag(stmt, '@manual')
const isNoemit = checkForFlag(stmt, '@noemit')
const shouldEmit = !isNoemit && !(isPrivate && !isOverload && !hasOverloads)
if (shouldEmit) {
state.methods.list.push({ state.methods.list.push({
from: relPath, from: relPath,
name, name,
isPrivate, isPrivate,
isManual,
isNoemit,
shouldEmit,
func: stmt, func: stmt,
comment: getLeadingComments(stmt), comment: getLeadingComments(stmt),
aliases, aliases,
@ -354,6 +345,7 @@ async function addSingleMethod(state, fileName) {
state.imports[module].add(name) state.imports[module].add(name)
} }
}
} else if (stmt.kind === ts.SyntaxKind.InterfaceDeclaration) { } else if (stmt.kind === ts.SyntaxKind.InterfaceDeclaration) {
if (isCopy) { if (isCopy) {
state.copy.push({ state.copy.push({
@ -484,6 +476,7 @@ on(name: '${type.typeName}', handler: ((upd: ${type.updateType}) => void)): this
({ ({
name: origName, name: origName,
// isPrivate, // isPrivate,
isManual,
func, func,
comment, comment,
aliases, aliases,
@ -531,7 +524,9 @@ on(name: '${type.typeName}', handler: ((upd: ${type.updateType}) => void)): this
const generics = func.typeParameters ? const generics = func.typeParameters ?
`<${func.typeParameters.map((it) => it.getFullText()).join(', ')}>` : `<${func.typeParameters.map((it) => it.getFullText()).join(', ')}>` :
'' ''
const rawParams = (func.parameters || []).filter((it) => !it.type || it.type.getText() !== 'TelegramClient') const rawParams = (func.parameters || []).filter(
(it) => !it.type || it.type.getText() !== 'BaseTelegramClient',
)
const parameters = rawParams const parameters = rawParams
.map((it) => { .map((it) => {
if (it.initializer) { if (it.initializer) {
@ -590,7 +585,7 @@ on(name: '${type.typeName}', handler: ((upd: ${type.updateType}) => void)): this
// remove @internal mark and set default values for parameters // remove @internal mark and set default values for parameters
comment = comment comment = comment
.replace(/^\s*\/\/+\s*@(alias|available).*$/m, '') .replace(/^\s*\/\/+\s*@(alias|available|manual).*$/gm, '')
.replace(/(\n^|\/\*)\s*\*\s*@internal.*/m, '') .replace(/(\n^|\/\*)\s*\*\s*@internal.*/m, '')
.replace(/((?:\n^|\/\*)\s*\*\s*@param )([^\s]+?)($|\s+)/gm, (_, pref, arg, post) => { .replace(/((?:\n^|\/\*)\s*\*\s*@param )([^\s]+?)($|\s+)/gm, (_, pref, arg, post) => {
const param = rawParams.find((it) => it.name.escapedText === arg) const param = rawParams.find((it) => it.name.escapedText === arg)
@ -599,7 +594,6 @@ on(name: '${type.typeName}', handler: ((upd: ${type.updateType}) => void)): this
return `${pref}[${arg}=${param._savedDefault.trim()}]${post}` return `${pref}[${arg}=${param._savedDefault.trim()}]${post}`
}) })
// insert "some text" at the end of comment before jsdoc
.replace(/(?<=\/\*.*)(?=\n\s*\*\s*(?:@[a-z]+|\/))/s, () => { .replace(/(?<=\/\*.*)(?=\n\s*\*\s*(?:@[a-z]+|\/))/s, () => {
switch (available) { switch (available) {
case 'user': case 'user':
@ -623,8 +617,11 @@ on(name: '${type.typeName}', handler: ((upd: ${type.updateType}) => void)): this
output.write(`${name}${generics}(${parameters})${returnType}\n`) output.write(`${name}${generics}(${parameters})${returnType}\n`)
} }
if (!overload) { if (!overload && !isManual) {
classContents.push(`${name} = ${origName}`) if (hasOverloads) {
classContents.push('// @ts-expect-error .bind() kinda breaks typings for overloads')
}
classContents.push(`${name} = ${origName}.bind(null, this)`)
} }
} }
}, },

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,3 @@
/** @hidden */
export * from './client' export * from './client'
export * from './types' export * from './types'
export * from './utils/peer-utils' export * from './utils/peer-utils'

View file

@ -57,7 +57,7 @@ Example:
```typescript ```typescript
// @initialize // @initialize
function _initializeAwesomeExtension(this: TelegramClient) { function _initializeAwesomeExtension(client: BaseTelegramClient) {
this._field1 = 42 this._field1 = 42
this._field2 = 'uwu' this._field2 = 'uwu'
} }
@ -74,7 +74,7 @@ Example:
// @exported // @exported
export type FooOrBar = Foo | Bar export type FooOrBar = Foo | Bar
export function getFooOrBar(this: TelegramClient): FooOrBar { export function getFooOrBar(client: BaseTelegramClient): FooOrBar {
return new Foo() return new Foo()
} }
``` ```

View file

@ -5,8 +5,6 @@ import { Readable } from 'stream'
// @copy // @copy
import { MaybeArray, MaybeAsync, PartialExcept, PartialOnly } from '@mtcute/core' import { MaybeArray, MaybeAsync, PartialExcept, PartialOnly } from '@mtcute/core'
// @copy // @copy
import { AsyncLock, ConditionVariable, Deque, Logger, SortedLinkedList } from '@mtcute/core/utils'
// @copy
import { tdFileId } from '@mtcute/file-id' import { tdFileId } from '@mtcute/file-id'
// @copy // @copy
@ -29,7 +27,6 @@ import {
ChatMemberUpdate, ChatMemberUpdate,
ChatPreview, ChatPreview,
ChosenInlineResult, ChosenInlineResult,
Conversation,
DeleteMessageUpdate, DeleteMessageUpdate,
DeleteStoryUpdate, DeleteStoryUpdate,
Dialog, Dialog,

View file

@ -0,0 +1,48 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { BaseTelegramClientOptions } from '@mtcute/core'
import { TelegramClient } from '../client'
// @copy
import { Conversation } from '../types/conversation'
// @copy
import { start } from './auth/start'
// @copy
import { enableUpdatesProcessing, makeParsedUpdateHandler, ParsedUpdateHandlerParams } from './updates'
// @copy
interface TelegramClientOptions extends BaseTelegramClientOptions {
/**
* Parameters for updates manager.
*/
updates?: Omit<ParsedUpdateHandlerParams, 'onUpdate' | 'onRawUpdate'>
}
// @initialize
/** @internal */
function _initializeClient(this: TelegramClient, opts: TelegramClientOptions) {
if (!opts.disableUpdates) {
enableUpdatesProcessing(this, {
onUpdate: makeParsedUpdateHandler({
...opts.updates,
onUpdate: (update) => {
Conversation.handleUpdate(this, update)
this.emit('update', update)
this.emit(update.name, update.data)
},
onRawUpdate: (update, peers) => {
this.emit('raw_update', update, peers)
},
}),
})
this.start = async (params) => {
const user = await start(this, params)
await this.startUpdatesLoop()
return user
}
} else {
this.start = start.bind(null, this)
}
}

View file

@ -1,64 +0,0 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { BaseTelegramClientOptions } from '@mtcute/core'
// @copy
interface TelegramClientOptions extends BaseTelegramClientOptions {
/**
* **ADVANCED**
*
* Whether to disable no-dispatch mechanism.
*
* No-dispatch is a mechanism that allows you to call methods
* that return updates and correctly handle them, without
* actually dispatching them to the event handlers.
*
* In other words, the following code will work differently:
* ```ts
* dp.onNewMessage(console.log)
* console.log(await tg.sendText('me', 'hello'))
* ```
* - if `disableNoDispatch` is `true`, the sent message will be
* dispatched to the event handler, thus it will be printed twice
* - if `disableNoDispatch` is `false`, the sent message will not be
* dispatched to the event handler, thus it will onlt be printed once
*
* Disabling it also may improve performance, but it's not guaranteed.
*
* @default false
*/
disableNoDispatch?: boolean
/**
* Limit of {@link resolvePeerMany} internal async pool.
*
* Higher value means more parallel requests, but also
* higher risk of getting flood-wait errors.
* Most resolves will however likely be a DB cache hit.
*
* Only change this if you know what you're doing.
*
* @default 8
*/
resolvePeerManyPoolLimit?: number
/**
* When non-zero, allows the library to automatically handle Telegram
* media groups (e.g. albums) in {@link MessageGroup} updates
* in a given time interval (in ms).
*
* **Note**: this does not catch messages that happen to be consecutive,
* only messages belonging to the same "media group".
*
* This will cause up to `messageGroupingInterval` delay
* in handling media group messages.
*
* This option only applies to `new_message` updates,
* and the updates being grouped **will not** be dispatched on their own.
*
* Recommended value is 250 ms.
*
* @default 0 (disabled)
*/
messageGroupingInterval?: number
}

View file

@ -1,58 +0,0 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { MtUnsupportedError, tl } from '@mtcute/core'
import { assertTypeIs } from '@mtcute/core/utils'
import { TelegramClient } from '../../client'
import { User } from '../../types'
// @extension
interface AuthState {
// local copy of "self" in storage,
// so we can use it w/out relying on storage.
// they are both loaded and saved to storage along with the updates
// (see methods/updates)
_userId: number | null
_isBot: boolean
_selfUsername: string | null
}
// @initialize
function _initializeAuthState(this: TelegramClient) {
this._userId = null
this._isBot = false
this._selfUsername = null
this.log.prefix = '[USER N/A] '
}
/** @internal */
export async function _onAuthorization(
this: TelegramClient,
auth: tl.auth.TypeAuthorization,
bot = false,
): Promise<User> {
if (auth._ === 'auth.authorizationSignUpRequired') {
throw new MtUnsupportedError(
'Signup is no longer supported by Telegram for non-official clients. Please use your mobile device to sign up.',
)
}
assertTypeIs('_onAuthorization (@ auth.authorization -> user)', auth.user, 'user')
this._userId = auth.user.id
this.log.prefix = `[USER ${this._userId}] `
this._isBot = bot
this._selfUsername = auth.user.username!
this._selfChanged = true
await this.network.notifyLoggedIn(auth)
await this._fetchUpdatesState()
await this._saveStorage()
// telegram ignores invokeWithoutUpdates for auth methods
if (this.network.params.disableUpdates) this.network.resetSessions()
else this.startUpdatesLoop()
return new User(this, auth.user)
}

View file

@ -0,0 +1,98 @@
/* eslint-disable no-inner-declarations */
import { BaseTelegramClient, MtUnsupportedError, tl } from '@mtcute/core'
import { assertTypeIs } from '@mtcute/core/utils'
import { User } from '../../types/peers/user'
const STATE_SYMBOL = Symbol('authState')
/**
* @internal
* @exported
*/
export interface AuthState {
// local copy of "self" in storage,
// so we can use it w/out relying on storage.
// they are both loaded and saved to storage along with the updates
// (see methods/updates)
userId: number | null
isBot: boolean
selfUsername: string | null
selfChanged?: boolean
}
/** @internal */
export function getAuthState(client: BaseTelegramClient): AuthState {
// eslint-disable-next-line
let state: AuthState = (client as any)[STATE_SYMBOL]
if (!state) {
// init
// eslint-disable-next-line @typescript-eslint/no-explicit-any
state = (client as any)[STATE_SYMBOL] = {
userId: null,
isBot: false,
selfUsername: null,
}
client.log.prefix = '[USER N/A] '
function onBeforeConnect() {
Promise.resolve(client.storage.getSelf())
.then((self) => {
if (!self) return
state.userId = self.userId
state.isBot = self.isBot
client.log.prefix = `[USER ${self.userId}] `
})
.catch((err) => client._emitError(err))
}
async function onBeforeStorageSave() {
if (state.selfChanged) {
await client.storage.setSelf(
state.userId ?
{
userId: state.userId,
isBot: state.isBot,
} :
null,
)
state.selfChanged = false
}
}
client.on('before_connect', onBeforeConnect)
client.beforeStorageSave(onBeforeStorageSave)
client.on('before_stop', () => {
client.off('before_connect', onBeforeConnect)
client.offBeforeStorageSave(onBeforeStorageSave)
})
}
return state
}
/** @internal */
export function _onAuthorization(client: BaseTelegramClient, auth: tl.auth.TypeAuthorization, bot = false): User {
if (auth._ === 'auth.authorizationSignUpRequired') {
throw new MtUnsupportedError(
'Signup is no longer supported by Telegram for non-official clients. Please use your mobile device to sign up.',
)
}
assertTypeIs('_onAuthorization (@ auth.authorization -> user)', auth.user, 'user')
const state = getAuthState(client)
state.userId = auth.user.id
state.isBot = bot
state.selfUsername = auth.user.username ?? null
state.selfChanged = true
client.notifyLoggedIn(auth)
// telegram ignores invokeWithoutUpdates for auth methods
if (client.network.params.disableUpdates) client.network.resetSessions()
return new User(auth.user)
}

View file

@ -1,7 +1,8 @@
import { BaseTelegramClient } from '@mtcute/core'
import { computeSrpParams } from '@mtcute/core/utils' import { computeSrpParams } from '@mtcute/core/utils'
import { TelegramClient } from '../../client'
import { User } from '../../types' import { User } from '../../types'
import { _onAuthorization } from './_state'
/** /**
* Check your Two-Step verification password and log in * Check your Two-Step verification password and log in
@ -9,19 +10,18 @@ import { User } from '../../types'
* @param password Your Two-Step verification password * @param password Your Two-Step verification password
* @returns The authorized user * @returns The authorized user
* @throws BadRequestError In case the password is invalid * @throws BadRequestError In case the password is invalid
* @internal
*/ */
export async function checkPassword(this: TelegramClient, password: string): Promise<User> { export async function checkPassword(client: BaseTelegramClient, password: string): Promise<User> {
const res = await this.call({ const res = await client.call({
_: 'auth.checkPassword', _: 'auth.checkPassword',
password: await computeSrpParams( password: await computeSrpParams(
this._crypto, client.crypto,
await this.call({ await client.call({
_: 'account.getPassword', _: 'account.getPassword',
}), }),
password, password,
), ),
}) })
return this._onAuthorization(res) return _onAuthorization(client, res)
} }

View file

@ -1,13 +1,14 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
/** /**
* Get your Two-Step Verification password hint. * Get your Two-Step Verification password hint.
* *
* @returns The password hint as a string, if any * @returns The password hint as a string, if any
* @internal
*/ */
export function getPasswordHint(this: TelegramClient): Promise<string | null> { export function getPasswordHint(client: BaseTelegramClient): Promise<string | null> {
return this.call({ return client
.call({
_: 'account.getPassword', _: 'account.getPassword',
}).then((res) => res.hint ?? null) })
.then((res) => res.hint ?? null)
} }

View file

@ -1,4 +1,6 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { getAuthState } from './_state'
/** /**
* Log out from Telegram account and optionally reset the session storage. * Log out from Telegram account and optionally reset the session storage.
@ -7,20 +9,20 @@ import { TelegramClient } from '../../client'
* the same {@link TelegramClient} instance. * the same {@link TelegramClient} instance.
* *
* @returns On success, `true` is returned * @returns On success, `true` is returned
* @internal
*/ */
export async function logOut(this: TelegramClient): Promise<true> { export async function logOut(client: BaseTelegramClient): Promise<true> {
await this.call({ _: 'auth.logOut' }) await client.call({ _: 'auth.logOut' })
this._userId = null const authState = getAuthState(client)
this._isBot = false authState.userId = null
// some implicit magic in favor of performance authState.isBot = false
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment authState.selfUsername = null
this._pts = this._seq = this._date = undefined as any authState.selfChanged = true
this._selfUsername = null
this._selfChanged = true client.emit('logged_out')
this.storage.reset()
await this._saveStorage() client.storage.reset()
await client.saveStorage()
return true return true
} }

View file

@ -1,15 +1,16 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { User } from '../../types' import { User } from '../../types'
import { _onAuthorization } from './_state'
/** /**
* Recover your password with a recovery code and log in. * Recover your password with a recovery code and log in.
* *
* @returns The authorized user * @returns The authorized user
* @throws BadRequestError In case the code is invalid * @throws BadRequestError In case the code is invalid
* @internal
*/ */
export async function recoverPassword( export async function recoverPassword(
this: TelegramClient, client: BaseTelegramClient,
params: { params: {
/** The recovery code sent via email */ /** The recovery code sent via email */
recoveryCode: string recoveryCode: string
@ -17,10 +18,10 @@ export async function recoverPassword(
): Promise<User> { ): Promise<User> {
const { recoveryCode } = params const { recoveryCode } = params
const res = await this.call({ const res = await client.call({
_: 'auth.recoverPassword', _: 'auth.recoverPassword',
code: recoveryCode, code: recoveryCode,
}) })
return this._onAuthorization(res) return _onAuthorization(client, res)
} }

View file

@ -1,6 +1,6 @@
import { BaseTelegramClient } from '@mtcute/core'
import { assertTypeIs } from '@mtcute/core/utils' import { assertTypeIs } from '@mtcute/core/utils'
import { TelegramClient } from '../../client'
import { SentCode } from '../../types' import { SentCode } from '../../types'
import { normalizePhoneNumber } from '../../utils/misc-utils' import { normalizePhoneNumber } from '../../utils/misc-utils'
@ -9,11 +9,9 @@ import { normalizePhoneNumber } from '../../utils/misc-utils'
* *
* The type of the code to be re-sent is specified in the `nextType` attribute of * The type of the code to be re-sent is specified in the `nextType` attribute of
* {@link SentCode} object returned by {@link sendCode} * {@link SentCode} object returned by {@link sendCode}
*
* @internal
*/ */
export async function resendCode( export async function resendCode(
this: TelegramClient, client: BaseTelegramClient,
params: { params: {
/** Phone number in international format */ /** Phone number in international format */
phone: string phone: string
@ -24,7 +22,7 @@ export async function resendCode(
): Promise<SentCode> { ): Promise<SentCode> {
const { phone, phoneCodeHash } = params const { phone, phoneCodeHash } = params
const res = await this.call({ const res = await client.call({
_: 'auth.resendCode', _: 'auth.resendCode',
phoneNumber: normalizePhoneNumber(phone), phoneNumber: normalizePhoneNumber(phone),
phoneCodeHash, phoneCodeHash,

View file

@ -1,5 +1,7 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { User } from '../../types' import { User } from '../../types'
import { start } from './start'
/** /**
* Simple wrapper that calls {@link start} and then * Simple wrapper that calls {@link start} and then
@ -9,16 +11,15 @@ import { User } from '../../types'
* Errors that were encountered while calling {@link start} * Errors that were encountered while calling {@link start}
* and `then` will be emitted as usual, and can be caught with {@link onError} * and `then` will be emitted as usual, and can be caught with {@link onError}
* *
* @param params Parameters to be passed to {@link TelegramClient.start} * @param params Parameters to be passed to {@link start}
* @param then Function to be called after {@link TelegramClient.start} returns * @param then Function to be called after {@link start} returns
* @internal
*/ */
export function run( export function run(
this: TelegramClient, client: BaseTelegramClient,
params: Parameters<TelegramClient['start']>[0], params: Parameters<typeof start>[1],
then?: (user: User) => void | Promise<void>, then?: (user: User) => void | Promise<void>,
): void { ): void {
this.start(params) start(client, params)
.then(then) .then(then)
.catch((err) => this._emitError(err)) .catch((err) => client._emitError(err))
} }

View file

@ -1,6 +1,6 @@
import { BaseTelegramClient } from '@mtcute/core'
import { assertTypeIs } from '@mtcute/core/utils' import { assertTypeIs } from '@mtcute/core/utils'
import { TelegramClient } from '../../client'
import { SentCode } from '../../types' import { SentCode } from '../../types'
import { normalizePhoneNumber } from '../../utils/misc-utils' import { normalizePhoneNumber } from '../../utils/misc-utils'
@ -8,10 +8,9 @@ import { normalizePhoneNumber } from '../../utils/misc-utils'
* Send the confirmation code to the given phone number * Send the confirmation code to the given phone number
* *
* @returns An object containing information about the sent confirmation code * @returns An object containing information about the sent confirmation code
* @internal
*/ */
export async function sendCode( export async function sendCode(
this: TelegramClient, client: BaseTelegramClient,
params: { params: {
/** Phone number in international format */ /** Phone number in international format */
phone: string phone: string
@ -19,11 +18,12 @@ export async function sendCode(
): Promise<SentCode> { ): Promise<SentCode> {
const phone = normalizePhoneNumber(params.phone) const phone = normalizePhoneNumber(params.phone)
const res = await this.call({ const res = await client.call({
_: 'auth.sendCode', _: 'auth.sendCode',
phoneNumber: phone, phoneNumber: phone,
apiId: this.network._initConnectionParams.apiId, apiId: client.network._initConnectionParams.apiId,
apiHash: this._apiHash, // eslint-disable-next-line dot-notation
apiHash: client['_apiHash'],
settings: { _: 'codeSettings' }, settings: { _: 'codeSettings' },
}) })

View file

@ -1,13 +1,14 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
/** /**
* Send a code to email needed to recover your password * Send a code to email needed to recover your password
* *
* @returns String containing email pattern to which the recovery code was sent * @returns String containing email pattern to which the recovery code was sent
* @internal
*/ */
export function sendRecoveryCode(this: TelegramClient): Promise<string> { export function sendRecoveryCode(client: BaseTelegramClient): Promise<string> {
return this.call({ return client
.call({
_: 'auth.requestPasswordRecovery', _: 'auth.requestPasswordRecovery',
}).then((res) => res.emailPattern) })
.then((res) => res.emailPattern)
} }

View file

@ -1,5 +1,7 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { User } from '../../types' import { User } from '../../types'
import { _onAuthorization } from './_state'
/** /**
* Authorize a bot using its token issued by [@BotFather](//t.me/BotFather) * Authorize a bot using its token issued by [@BotFather](//t.me/BotFather)
@ -7,16 +9,16 @@ import { User } from '../../types'
* @param token Bot token issued by BotFather * @param token Bot token issued by BotFather
* @returns Bot's {@link User} object * @returns Bot's {@link User} object
* @throws BadRequestError In case the bot token is invalid * @throws BadRequestError In case the bot token is invalid
* @internal
*/ */
export async function signInBot(this: TelegramClient, token: string): Promise<User> { export async function signInBot(client: BaseTelegramClient, token: string): Promise<User> {
const res = await this.call({ const res = await client.call({
_: 'auth.importBotAuthorization', _: 'auth.importBotAuthorization',
flags: 0, flags: 0,
apiId: this.network._initConnectionParams.apiId, apiId: client.network._initConnectionParams.apiId,
apiHash: this._apiHash, // eslint-disable-next-line dot-notation
apiHash: client['_apiHash'],
botAuthToken: token, botAuthToken: token,
}) })
return this._onAuthorization(res, true) return _onAuthorization(client, res, true)
} }

View file

@ -1,6 +1,8 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { User } from '../../types' import { User } from '../../types'
import { normalizePhoneNumber } from '../../utils/misc-utils' import { normalizePhoneNumber } from '../../utils/misc-utils'
import { _onAuthorization } from './_state'
/** /**
* Authorize a user in Telegram with a valid confirmation code. * Authorize a user in Telegram with a valid confirmation code.
@ -8,10 +10,9 @@ import { normalizePhoneNumber } from '../../utils/misc-utils'
* @returns If the code was valid and authorization succeeded, the {@link User} is returned. * @returns If the code was valid and authorization succeeded, the {@link User} is returned.
* @throws BadRequestError In case the arguments are invalid * @throws BadRequestError In case the arguments are invalid
* @throws SessionPasswordNeededError In case a password is needed to sign in * @throws SessionPasswordNeededError In case a password is needed to sign in
* @internal
*/ */
export async function signIn( export async function signIn(
this: TelegramClient, client: BaseTelegramClient,
params: { params: {
/** Phone number in international format */ /** Phone number in international format */
phone: string phone: string
@ -23,12 +24,12 @@ export async function signIn(
): Promise<User> { ): Promise<User> {
const { phone, phoneCodeHash, phoneCode } = params const { phone, phoneCodeHash, phoneCode } = params
const res = await this.call({ const res = await client.call({
_: 'auth.signIn', _: 'auth.signIn',
phoneNumber: normalizePhoneNumber(phone), phoneNumber: normalizePhoneNumber(phone),
phoneCodeHash, phoneCodeHash,
phoneCode, phoneCode,
}) })
return this._onAuthorization(res) return _onAuthorization(client, res)
} }

View file

@ -1,7 +1,8 @@
import { MtArgumentError } from '@mtcute/core' import { BaseTelegramClient, MtArgumentError } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { User } from '../../types' import { User } from '../../types'
import { logOut } from './log-out'
import { start } from './start'
/** /**
* Utility function to quickly authorize on test DC * Utility function to quickly authorize on test DC
@ -12,10 +13,9 @@ import { User } from '../../types'
* > are using a test DC in `primaryDc` parameter. * > are using a test DC in `primaryDc` parameter.
* *
* @param params Additional parameters * @param params Additional parameters
* @internal
*/ */
export async function startTest( export async function startTest(
this: TelegramClient, client: BaseTelegramClient,
params?: { params?: {
/** /**
* Whether to log out if current session is logged in. * Whether to log out if current session is logged in.
@ -41,13 +41,15 @@ export async function startTest(
if (params.logout) { if (params.logout) {
try { try {
await this.logOut() await logOut(client)
} catch (e) {} } catch (e) {}
} }
const availableDcs = await this.call({ const availableDcs = await client
.call({
_: 'help.getConfig', _: 'help.getConfig',
}).then((res) => res.dcOptions) })
.then((res) => res.dcOptions)
let phone = params.phone let phone = params.phone
@ -61,7 +63,7 @@ export async function startTest(
throw new MtArgumentError(`${phone} has invalid DC ID (${id})`) throw new MtArgumentError(`${phone} has invalid DC ID (${id})`)
} }
} else { } else {
let dcId = this._defaultDcs.main.id let dcId = client.network.getPrimaryDcId()
if (params.dcId) { if (params.dcId) {
if (!availableDcs.find((dc) => dc.id === params!.dcId)) { if (!availableDcs.find((dc) => dc.id === params!.dcId)) {
@ -78,7 +80,7 @@ export async function startTest(
let code = '' let code = ''
return this.start({ return start(client, {
phone, phone,
code: () => code, code: () => code,
codeSentCallback: (sent) => { codeSentCallback: (sent) => {

View file

@ -1,10 +1,16 @@
/* eslint-disable no-console */ /* eslint-disable no-console */
import { MaybeAsync, MtArgumentError, tl } from '@mtcute/core' import { BaseTelegramClient, MaybeAsync, MtArgumentError, tl } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { MaybeDynamic, SentCode, User } from '../../types' import { MaybeDynamic, SentCode, User } from '../../types'
import { normalizePhoneNumber, resolveMaybeDynamic } from '../../utils/misc-utils' import { normalizePhoneNumber, resolveMaybeDynamic } from '../../utils/misc-utils'
import { getMe } from '../users/get-me'
import { checkPassword } from './check-password'
import { resendCode } from './resend-code'
import { sendCode } from './send-code'
import { signIn } from './sign-in'
import { signInBot } from './sign-in-bot'
// @manual
// @available=both // @available=both
/** /**
* Start the client in an interactive and declarative manner, * Start the client in an interactive and declarative manner,
@ -18,11 +24,9 @@ import { normalizePhoneNumber, resolveMaybeDynamic } from '../../utils/misc-util
* This method is intended for simple and fast use in automated * This method is intended for simple and fast use in automated
* scripts and bots. If you are developing a custom client, * scripts and bots. If you are developing a custom client,
* you'll probably need to use other auth methods. * you'll probably need to use other auth methods.
*
* @internal
*/ */
export async function start( export async function start(
this: TelegramClient, client: BaseTelegramClient,
params: { params: {
/** /**
* String session exported using {@link TelegramClient.exportSession}. * String session exported using {@link TelegramClient.exportSession}.
@ -80,58 +84,25 @@ export async function start(
* to show a GUI alert of some kind. * to show a GUI alert of some kind.
* Defaults to `console.log`. * Defaults to `console.log`.
* *
* This method is called *before* {@link TelegramClient.start.params.code}. * This method is called *before* {@link start.params.code}.
* *
* @param code * @param code
*/ */
codeSentCallback?: (code: SentCode) => MaybeAsync<void> codeSentCallback?: (code: SentCode) => MaybeAsync<void>
/**
* Whether to "catch up" (load missed updates).
* Only applicable if the saved session already
* contained authorization and updates state.
*
* Note: you should register your handlers
* before calling `start()`, otherwise they will
* not be called.
*
* Note: In case the storage was not properly
* closed the last time, "catching up" might
* result in duplicate updates.
*
* Defaults to `false`.
*/
catchUp?: boolean
}, },
): Promise<User> { ): Promise<User> {
if (params.session) { if (params.session) {
this.importSession(params.session, params.sessionForce) client.importSession(params.session, params.sessionForce)
} }
try { try {
const me = await this.getMe() const me = await getMe(client)
// user is already authorized // user is already authorized
this.log.prefix = `[USER ${me.id}] ` client.log.info('Logged in as %s (ID: %s, username: %s, bot: %s)', me.displayName, me.id, me.username, me.isBot)
this.log.info('Logged in as %s (ID: %s, username: %s, bot: %s)', me.displayName, me.id, me.username, me.isBot)
this.network.setIsPremium(me.isPremium) client.network.setIsPremium(me.isPremium)
if (!this.network.params.disableUpdates) {
this._catchUpChannels = Boolean(params.catchUp)
if (!params.catchUp) {
// otherwise we will catch up as soon as we receive a new update
await this._fetchUpdatesState()
}
this.startUpdatesLoop()
if (params.catchUp) {
this.catchUp()
}
}
return me return me
} catch (e) { } catch (e) {
@ -157,13 +128,13 @@ export async function start(
throw new MtArgumentError('Either bot token or phone number must be provided') throw new MtArgumentError('Either bot token or phone number must be provided')
} }
return await this.signInBot(botToken) return await signInBot(client, botToken)
} }
let sentCode = await this.sendCode({ phone }) let sentCode = await sendCode(client, { phone })
if (params.forceSms && sentCode.type === 'app') { if (params.forceSms && sentCode.type === 'app') {
sentCode = await this.resendCode({ phone, phoneCodeHash: sentCode.phoneCodeHash }) sentCode = await resendCode(client, { phone, phoneCodeHash: sentCode.phoneCodeHash })
} }
if (params.codeSentCallback) { if (params.codeSentCallback) {
@ -179,7 +150,7 @@ export async function start(
if (!code) throw new tl.RpcError(400, 'PHONE_CODE_EMPTY') if (!code) throw new tl.RpcError(400, 'PHONE_CODE_EMPTY')
try { try {
return await this.signIn({ phone, phoneCodeHash: sentCode.phoneCodeHash, phoneCode: code }) return await signIn(client, { phone, phoneCodeHash: sentCode.phoneCodeHash, phoneCode: code })
} catch (e) { } catch (e) {
if (!tl.RpcError.is(e)) throw e if (!tl.RpcError.is(e)) throw e
@ -219,7 +190,7 @@ export async function start(
const password = await resolveMaybeDynamic(params.password) const password = await resolveMaybeDynamic(params.password)
try { try {
return await this.checkPassword(password) return await checkPassword(client, password)
} catch (e) { } catch (e) {
if (typeof params.password !== 'function') { if (typeof params.password !== 'function') {
throw new MtArgumentError('Provided password was invalid') throw new MtArgumentError('Provided password was invalid')

View file

@ -1,16 +1,13 @@
import { Long } from '@mtcute/core' import { BaseTelegramClient, Long } from '@mtcute/core'
import { TelegramClient } from '../../client'
/** /**
* Send an answer to a callback query. * Send an answer to a callback query.
* *
* @param queryId ID of the callback query * @param queryId ID of the callback query
* @param params Parameters of the answer * @param params Parameters of the answer
* @internal
*/ */
export async function answerCallbackQuery( export async function answerCallbackQuery(
this: TelegramClient, client: BaseTelegramClient,
queryId: Long, queryId: Long,
params?: { params?: {
/** /**
@ -50,7 +47,7 @@ export async function answerCallbackQuery(
): Promise<void> { ): Promise<void> {
const { cacheTime = 0, text, alert, url } = params ?? {} const { cacheTime = 0, text, alert, url } = params ?? {}
await this.call({ await client.call({
_: 'messages.setBotCallbackAnswer', _: 'messages.setBotCallbackAnswer',
queryId, queryId,
cacheTime, cacheTime,

View file

@ -1,6 +1,5 @@
import { tl } from '@mtcute/core' import { BaseTelegramClient, tl } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { BotInline, InputInlineResult } from '../../types' import { BotInline, InputInlineResult } from '../../types'
/** /**
@ -9,10 +8,9 @@ import { BotInline, InputInlineResult } from '../../types'
* @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
* @internal
*/ */
export async function answerInlineQuery( export async function answerInlineQuery(
this: TelegramClient, client: BaseTelegramClient,
queryId: tl.Long, queryId: tl.Long,
results: InputInlineResult[], results: InputInlineResult[],
params?: { params?: {
@ -97,9 +95,9 @@ export async function answerInlineQuery(
): Promise<void> { ): Promise<void> {
const { cacheTime = 300, gallery, private: priv, nextOffset, switchPm, parseMode } = params ?? {} const { cacheTime = 300, gallery, private: priv, nextOffset, switchPm, parseMode } = params ?? {}
const [defaultGallery, tlResults] = await BotInline._convertToTl(this, results, parseMode) const [defaultGallery, tlResults] = await BotInline._convertToTl(client, results, parseMode)
await this.call({ await client.call({
_: 'messages.setInlineBotResults', _: 'messages.setInlineBotResults',
queryId, queryId,
results: tlResults, results: tlResults,

View file

@ -1,15 +1,12 @@
import { tl } from '@mtcute/core' import { BaseTelegramClient, tl } from '@mtcute/core'
import { TelegramClient } from '../../client'
/** /**
* Answer a pre-checkout query. * Answer a pre-checkout query.
* *
* @param queryId Pre-checkout query ID * @param queryId Pre-checkout query ID
* @internal
*/ */
export async function answerPreCheckoutQuery( export async function answerPreCheckoutQuery(
this: TelegramClient, client: BaseTelegramClient,
queryId: tl.Long, queryId: tl.Long,
params?: { params?: {
/** If pre-checkout is rejected, error message to show to the user */ /** If pre-checkout is rejected, error message to show to the user */
@ -18,7 +15,7 @@ export async function answerPreCheckoutQuery(
): Promise<void> { ): Promise<void> {
const { error } = params ?? {} const { error } = params ?? {}
await this.call({ await client.call({
_: 'messages.setBotPrecheckoutResults', _: 'messages.setBotPrecheckoutResults',
queryId, queryId,
success: !error, success: !error,

View file

@ -1,7 +1,7 @@
import { tl } from '@mtcute/core' import { BaseTelegramClient, tl } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { BotCommands } from '../../types' import { BotCommands } from '../../types'
import { _normalizeCommandScope } from './normalize-command-scope'
/** /**
* Delete commands for the current bot and the given scope. * Delete commands for the current bot and the given scope.
@ -9,11 +9,9 @@ import { BotCommands } from '../../types'
* Does the same as passing `null` to {@link setMyCommands} * Does the same as passing `null` to {@link setMyCommands}
* *
* Learn more about scopes in the [Bot API docs](https://core.telegram.org/bots/api#botcommandscope) * Learn more about scopes in the [Bot API docs](https://core.telegram.org/bots/api#botcommandscope)
*
* @internal
*/ */
export async function deleteMyCommands( export async function deleteMyCommands(
this: TelegramClient, client: BaseTelegramClient,
params?: { params?: {
/** /**
* Scope of the commands. * Scope of the commands.
@ -29,12 +27,12 @@ export async function deleteMyCommands(
}, },
): Promise<void> { ): Promise<void> {
const scope: tl.TypeBotCommandScope = params?.scope ? const scope: tl.TypeBotCommandScope = params?.scope ?
await this._normalizeCommandScope(params.scope) : await _normalizeCommandScope(client, params.scope) :
{ {
_: 'botCommandScopeDefault', _: 'botCommandScopeDefault',
} }
await this.call({ await client.call({
_: 'bots.resetBotCommands', _: 'bots.resetBotCommands',
scope, scope,
langCode: params?.langCode ?? '', langCode: params?.langCode ?? '',

View file

@ -1,16 +1,14 @@
import { tl } from '@mtcute/core' import { BaseTelegramClient, tl } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { InputPeerLike } from '../../types' import { InputPeerLike } from '../../types'
import { normalizeToInputUser } from '../../utils/peer-utils' import { normalizeToInputUser } from '../../utils/peer-utils'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Gets information about a bot the current uzer owns (or the current bot) * Gets information about a bot the current uzer owns (or the current bot)
*
* @internal
*/ */
export async function getBotInfo( export async function getBotInfo(
this: TelegramClient, client: BaseTelegramClient,
params: { params: {
/** /**
* When called by a user, a bot the user owns must be specified. * When called by a user, a bot the user owns must be specified.
@ -27,9 +25,9 @@ export async function getBotInfo(
): Promise<tl.bots.RawBotInfo> { ): Promise<tl.bots.RawBotInfo> {
const { bot, langCode = '' } = params const { bot, langCode = '' } = params
return this.call({ return client.call({
_: 'bots.getBotInfo', _: 'bots.getBotInfo',
bot: bot ? normalizeToInputUser(await this.resolvePeer(bot), bot) : undefined, bot: bot ? normalizeToInputUser(await resolvePeer(client, bot), bot) : undefined,
langCode: langCode, langCode: langCode,
}) })
} }

View file

@ -1,17 +1,15 @@
import { tl } from '@mtcute/core' import { BaseTelegramClient, tl } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { InputPeerLike } from '../../types' import { InputPeerLike } from '../../types'
import { normalizeToInputUser } from '../../utils/peer-utils' import { normalizeToInputUser } from '../../utils/peer-utils'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Fetches the menu button set for the given user. * Fetches the menu button set for the given user.
*
* @internal
*/ */
export async function getBotMenuButton(this: TelegramClient, user: InputPeerLike): Promise<tl.TypeBotMenuButton> { export async function getBotMenuButton(client: BaseTelegramClient, user: InputPeerLike): Promise<tl.TypeBotMenuButton> {
return await this.call({ return await client.call({
_: 'bots.getBotMenuButton', _: 'bots.getBotMenuButton',
userId: normalizeToInputUser(await this.resolvePeer(user), user), userId: normalizeToInputUser(await resolvePeer(client, user), user),
}) })
} }

View file

@ -1,18 +1,17 @@
import { tl } from '@mtcute/core' import { BaseTelegramClient, tl } from '@mtcute/core'
import { computeSrpParams } from '@mtcute/core/utils' import { computeSrpParams } from '@mtcute/core/utils'
import { TelegramClient } from '../../client'
import { InputPeerLike } from '../../types' import { InputPeerLike } from '../../types'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Request a callback answer from a bot, * Request a callback answer from a bot,
* i.e. click an inline button that contains data. * i.e. click an inline button that contains data.
* *
* @param params * @param params
* @internal
*/ */
export async function getCallbackAnswer( export async function getCallbackAnswer(
this: TelegramClient, client: BaseTelegramClient,
params: { params: {
/** Chat ID where the message was found */ /** Chat ID where the message was found */
chatId: InputPeerLike chatId: InputPeerLike
@ -49,14 +48,14 @@ export async function getCallbackAnswer(
let password: tl.TypeInputCheckPasswordSRP | undefined = undefined let password: tl.TypeInputCheckPasswordSRP | undefined = undefined
if (params?.password) { if (params?.password) {
const pwd = await this.call({ _: 'account.getPassword' }) const pwd = await client.call({ _: 'account.getPassword' })
password = await computeSrpParams(this._crypto, pwd, params.password) password = await computeSrpParams(client.crypto, pwd, params.password)
} }
return await this.call( return await client.call(
{ {
_: 'messages.getBotCallbackAnswer', _: 'messages.getBotCallbackAnswer',
peer: await this.resolvePeer(chatId), peer: await resolvePeer(client, chatId),
msgId: message, msgId: message,
data: typeof data === 'string' ? Buffer.from(data) : data, data: typeof data === 'string' ? Buffer.from(data) : data,
password, password,

View file

@ -1,17 +1,15 @@
import { tl } from '@mtcute/core' import { BaseTelegramClient, tl } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { GameHighScore, InputPeerLike, PeersIndex } from '../../types' import { GameHighScore, InputPeerLike, PeersIndex } from '../../types'
import { normalizeInlineId } from '../../utils/inline-utils' import { normalizeInlineId } from '../../utils/inline-utils'
import { normalizeToInputUser } from '../../utils/peer-utils' import { normalizeToInputUser } from '../../utils/peer-utils'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Get high scores of a game * Get high scores of a game
*
* @internal
*/ */
export async function getGameHighScores( export async function getGameHighScores(
this: TelegramClient, client: BaseTelegramClient,
params: { params: {
/** ID of the chat where the game was found */ /** ID of the chat where the game was found */
chatId: InputPeerLike chatId: InputPeerLike
@ -25,17 +23,17 @@ export async function getGameHighScores(
): Promise<GameHighScore[]> { ): Promise<GameHighScore[]> {
const { chatId, message, userId } = params const { chatId, message, userId } = params
const chat = await this.resolvePeer(chatId) const chat = await resolvePeer(client, chatId)
let user: tl.TypeInputUser let user: tl.TypeInputUser
if (userId) { if (userId) {
user = normalizeToInputUser(await this.resolvePeer(userId), userId) user = normalizeToInputUser(await resolvePeer(client, userId), userId)
} else { } else {
user = { _: 'inputUserEmpty' } user = { _: 'inputUserEmpty' }
} }
const res = await this.call({ const res = await client.call({
_: 'messages.getGameHighScores', _: 'messages.getGameHighScores',
peer: chat, peer: chat,
id: message, id: message,
@ -44,7 +42,7 @@ export async function getGameHighScores(
const peers = PeersIndex.from(res) const peers = PeersIndex.from(res)
return res.scores.map((score) => new GameHighScore(this, score, peers)) return res.scores.map((score) => new GameHighScore(score, peers))
} }
/** /**
@ -52,10 +50,9 @@ export async function getGameHighScores(
* *
* @param messageId ID of the inline message containing the game * @param messageId ID of the inline message containing the game
* @param userId ID of the user to find high scores for * @param userId ID of the user to find high scores for
* @internal
*/ */
export async function getInlineGameHighScores( export async function getInlineGameHighScores(
this: TelegramClient, client: BaseTelegramClient,
messageId: string | tl.TypeInputBotInlineMessageID, messageId: string | tl.TypeInputBotInlineMessageID,
userId?: InputPeerLike, userId?: InputPeerLike,
): Promise<GameHighScore[]> { ): Promise<GameHighScore[]> {
@ -64,12 +61,12 @@ export async function getInlineGameHighScores(
let user: tl.TypeInputUser let user: tl.TypeInputUser
if (userId) { if (userId) {
user = normalizeToInputUser(await this.resolvePeer(userId), userId) user = normalizeToInputUser(await resolvePeer(client, userId), userId)
} else { } else {
user = { _: 'inputUserEmpty' } user = { _: 'inputUserEmpty' }
} }
const res = await this.call( const res = await client.call(
{ {
_: 'messages.getInlineGameHighScores', _: 'messages.getInlineGameHighScores',
id, id,
@ -80,5 +77,5 @@ export async function getInlineGameHighScores(
const peers = PeersIndex.from(res) const peers = PeersIndex.from(res)
return res.scores.map((score) => new GameHighScore(this, score, peers)) return res.scores.map((score) => new GameHighScore(score, peers))
} }

View file

@ -1,18 +1,16 @@
import { tl } from '@mtcute/core' import { BaseTelegramClient, tl } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { BotCommands } from '../../types' import { BotCommands } from '../../types'
import { _normalizeCommandScope } from './normalize-command-scope'
/** /**
* Get a list of current bot's commands for the given command scope * Get a list of current bot's commands for the given command scope
* and user language. If they are not set, empty set is returned. * and user language. If they are not set, empty set is returned.
* *
* Learn more about scopes in the [Bot API docs](https://core.telegram.org/bots/api#botcommandscope) * Learn more about scopes in the [Bot API docs](https://core.telegram.org/bots/api#botcommandscope)
*
* @internal
*/ */
export async function getMyCommands( export async function getMyCommands(
this: TelegramClient, client: BaseTelegramClient,
params?: { params?: {
/** /**
* Scope of the commands. * Scope of the commands.
@ -27,10 +25,10 @@ export async function getMyCommands(
langCode?: string langCode?: string
}, },
): Promise<tl.RawBotCommand[]> { ): Promise<tl.RawBotCommand[]> {
return this.call({ return client.call({
_: 'bots.getBotCommands', _: 'bots.getBotCommands',
scope: params?.scope ? scope: params?.scope ?
await this._normalizeCommandScope(params.scope) : await _normalizeCommandScope(client, params.scope) :
{ {
_: 'botCommandScopeDefault', _: 'botCommandScopeDefault',
}, },

View file

@ -1,12 +1,12 @@
import { assertNever, tl } from '@mtcute/core' import { assertNever, BaseTelegramClient, tl } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { BotCommands } from '../../types' import { BotCommands } from '../../types'
import { normalizeToInputUser } from '../../utils/peer-utils' import { normalizeToInputUser } from '../../utils/peer-utils'
import { resolvePeer } from '../users/resolve-peer'
/** @internal */ /** @internal */
export async function _normalizeCommandScope( export async function _normalizeCommandScope(
this: TelegramClient, client: BaseTelegramClient,
scope: tl.TypeBotCommandScope | BotCommands.IntermediateScope, scope: tl.TypeBotCommandScope | BotCommands.IntermediateScope,
): Promise<tl.TypeBotCommandScope> { ): Promise<tl.TypeBotCommandScope> {
if (tl.isAnyBotCommandScope(scope)) return scope if (tl.isAnyBotCommandScope(scope)) return scope
@ -14,7 +14,7 @@ export async function _normalizeCommandScope(
switch (scope.type) { switch (scope.type) {
case 'peer': case 'peer':
case 'peer_admins': { case 'peer_admins': {
const peer = await this.resolvePeer(scope.peer) const peer = await resolvePeer(client, scope.peer)
return { return {
_: scope.type === 'peer' ? 'botCommandScopePeer' : 'botCommandScopePeerAdmins', _: scope.type === 'peer' ? 'botCommandScopePeer' : 'botCommandScopePeerAdmins',
@ -22,8 +22,8 @@ export async function _normalizeCommandScope(
} }
} }
case 'member': { case 'member': {
const user = normalizeToInputUser(await this.resolvePeer(scope.user), scope.user) const user = normalizeToInputUser(await resolvePeer(client, scope.user), scope.user)
const chat = await this.resolvePeer(scope.chat) const chat = await resolvePeer(client, scope.chat)
return { return {
_: 'botCommandScopePeerUser', _: 'botCommandScopePeerUser',

View file

@ -1,14 +1,14 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { InputPeerLike } from '../../types' import { InputPeerLike } from '../../types'
import { normalizeToInputUser } from '../../utils/peer-utils' import { normalizeToInputUser } from '../../utils/peer-utils'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Sets information about a bot the current uzer owns (or the current bot) * Sets information about a bot the current uzer owns (or the current bot)
*
* @internal
*/ */
export async function setBotInfo( export async function setBotInfo(
this: TelegramClient, client: BaseTelegramClient,
params: { params: {
/** /**
* When called by a user, a bot the user owns must be specified. * When called by a user, a bot the user owns must be specified.
@ -34,9 +34,9 @@ export async function setBotInfo(
): Promise<void> { ): Promise<void> {
const { bot, langCode = '', name, bio, description } = params const { bot, langCode = '', name, bio, description } = params
await this.call({ await client.call({
_: 'bots.setBotInfo', _: 'bots.setBotInfo',
bot: bot ? normalizeToInputUser(await this.resolvePeer(bot), bot) : undefined, bot: bot ? normalizeToInputUser(await resolvePeer(client, bot), bot) : undefined,
langCode: langCode, langCode: langCode,
name, name,
about: bio, about: bio,

View file

@ -1,22 +1,20 @@
import { tl } from '@mtcute/core' import { BaseTelegramClient, tl } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { InputPeerLike } from '../../types' import { InputPeerLike } from '../../types'
import { normalizeToInputUser } from '../../utils/peer-utils' import { normalizeToInputUser } from '../../utils/peer-utils'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Sets a menu button for the given user. * Sets a menu button for the given user.
*
* @internal
*/ */
export async function setBotMenuButton( export async function setBotMenuButton(
this: TelegramClient, client: BaseTelegramClient,
user: InputPeerLike, user: InputPeerLike,
button: tl.TypeBotMenuButton, button: tl.TypeBotMenuButton,
): Promise<void> { ): Promise<void> {
await this.call({ await client.call({
_: 'bots.setBotMenuButton', _: 'bots.setBotMenuButton',
userId: normalizeToInputUser(await this.resolvePeer(user), user), userId: normalizeToInputUser(await resolvePeer(client, user), user),
button, button,
}) })
} }

View file

@ -1,19 +1,19 @@
import { tl } from '@mtcute/core' import { BaseTelegramClient, tl } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { InputPeerLike, Message } from '../../types' import { InputPeerLike, Message } from '../../types'
import { normalizeInlineId } from '../../utils/inline-utils' import { normalizeInlineId } from '../../utils/inline-utils'
import { normalizeToInputUser } from '../../utils/peer-utils' import { normalizeToInputUser } from '../../utils/peer-utils'
import { _findMessageInUpdate } from '../messages/find-in-update'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Set a score of a user in a game * Set a score of a user in a game
* *
* @param params * @param params
* @returns The modified message * @returns The modified message
* @internal
*/ */
export async function setGameScore( export async function setGameScore(
this: TelegramClient, client: BaseTelegramClient,
params: { params: {
/** Chat where the game was found */ /** Chat where the game was found */
chatId: InputPeerLike chatId: InputPeerLike
@ -42,10 +42,10 @@ export async function setGameScore(
): Promise<Message> { ): Promise<Message> {
const { chatId, message, userId, score, noEdit, force } = params const { chatId, message, userId, score, noEdit, force } = params
const user = normalizeToInputUser(await this.resolvePeer(userId), userId) const user = normalizeToInputUser(await resolvePeer(client, userId), userId)
const chat = await this.resolvePeer(chatId) const chat = await resolvePeer(client, chatId)
const res = await this.call({ const res = await client.call({
_: 'messages.setGameScore', _: 'messages.setGameScore',
peer: chat, peer: chat,
id: message, id: message,
@ -55,7 +55,7 @@ export async function setGameScore(
force, force,
}) })
return this._findMessageInUpdate(res, true) return _findMessageInUpdate(client, res, true)
} }
/** /**
@ -63,10 +63,9 @@ export async function setGameScore(
* an inline message * an inline message
* *
* @param params * @param params
* @internal
*/ */
export async function setInlineGameScore( export async function setInlineGameScore(
this: TelegramClient, client: BaseTelegramClient,
params: { params: {
/** ID of the inline message */ /** ID of the inline message */
messageId: string | tl.TypeInputBotInlineMessageID messageId: string | tl.TypeInputBotInlineMessageID
@ -89,11 +88,11 @@ export async function setInlineGameScore(
): Promise<void> { ): Promise<void> {
const { messageId, userId, score, noEdit, force } = params const { messageId, userId, score, noEdit, force } = params
const user = normalizeToInputUser(await this.resolvePeer(userId), userId) const user = normalizeToInputUser(await resolvePeer(client, userId), userId)
const id = normalizeInlineId(messageId) const id = normalizeInlineId(messageId)
await this.call( await client.call(
{ {
_: 'messages.setInlineGameScore', _: 'messages.setInlineGameScore',
id, id,

View file

@ -1,17 +1,15 @@
import { tl } from '@mtcute/core' import { BaseTelegramClient, tl } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { BotCommands } from '../../types' import { BotCommands } from '../../types'
import { _normalizeCommandScope } from './normalize-command-scope'
/** /**
* Set or delete commands for the current bot and the given scope * Set or delete commands for the current bot and the given scope
* *
* Learn more about scopes in the [Bot API docs](https://core.telegram.org/bots/api#botcommandscope) * Learn more about scopes in the [Bot API docs](https://core.telegram.org/bots/api#botcommandscope)
*
* @internal
*/ */
export async function setMyCommands( export async function setMyCommands(
this: TelegramClient, client: BaseTelegramClient,
params: { params: {
/** /**
* New list of bot commands for the given scope. * New list of bot commands for the given scope.
@ -34,20 +32,20 @@ export async function setMyCommands(
}, },
): Promise<void> { ): Promise<void> {
const scope: tl.TypeBotCommandScope = params.scope ? const scope: tl.TypeBotCommandScope = params.scope ?
await this._normalizeCommandScope(params.scope) : await _normalizeCommandScope(client, params.scope) :
{ {
_: 'botCommandScopeDefault', _: 'botCommandScopeDefault',
} }
if (params.commands?.length) { if (params.commands?.length) {
await this.call({ await client.call({
_: 'bots.setBotCommands', _: 'bots.setBotCommands',
commands: params.commands, commands: params.commands,
scope, scope,
langCode: params.langCode ?? '', langCode: params.langCode ?? '',
}) })
} else { } else {
await this.call({ await client.call({
_: 'bots.resetBotCommands', _: 'bots.resetBotCommands',
scope, scope,
langCode: params.langCode ?? '', langCode: params.langCode ?? '',

View file

@ -1,14 +1,10 @@
import { tl } from '@mtcute/core' import { BaseTelegramClient, tl } from '@mtcute/core'
import { TelegramClient } from '../../client'
/** /**
* Sets the default chat permissions for the bot in the supergroup or channel. * Sets the default chat permissions for the bot in the supergroup or channel.
*
* @internal
*/ */
export async function setMyDefaultRights( export async function setMyDefaultRights(
this: TelegramClient, client: BaseTelegramClient,
params: { params: {
/** Whether to target groups or channels. */ /** Whether to target groups or channels. */
target: 'channel' | 'group' target: 'channel' | 'group'
@ -18,7 +14,7 @@ export async function setMyDefaultRights(
): Promise<void> { ): Promise<void> {
const { target, rights } = params const { target, rights } = params
await this.call({ await client.call({
_: target === 'group' ? 'bots.setBotGroupDefaultAdminRights' : 'bots.setBotBroadcastDefaultAdminRights', _: target === 'group' ? 'bots.setBotGroupDefaultAdminRights' : 'bots.setBotBroadcastDefaultAdminRights',
adminRights: { adminRights: {
_: 'chatAdminRights', _: 'chatAdminRights',

View file

@ -1,6 +1,5 @@
import { MaybeArray } from '@mtcute/core' import { BaseTelegramClient, MaybeArray } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { InputPeerLike, MtInvalidPeerTypeError } from '../../types' import { InputPeerLike, MtInvalidPeerTypeError } from '../../types'
import { import {
isInputPeerChannel, isInputPeerChannel,
@ -8,16 +7,17 @@ import {
normalizeToInputChannel, normalizeToInputChannel,
normalizeToInputUser, normalizeToInputUser,
} from '../../utils/peer-utils' } from '../../utils/peer-utils'
import { resolvePeer } from '../users/resolve-peer'
import { resolvePeerMany } from '../users/resolve-peer-many'
/** /**
* Add one or more new members to a group, supergroup or channel. * Add one or more new members to a group, supergroup or channel.
* *
* @param chatId ID of the chat or its username * @param chatId ID of the chat or its username
* @param users ID(s) of the user(s) to add * @param users ID(s) of the user(s) to add
* @internal
*/ */
export async function addChatMembers( export async function addChatMembers(
this: TelegramClient, client: BaseTelegramClient,
chatId: InputPeerLike, chatId: InputPeerLike,
users: MaybeArray<InputPeerLike>, users: MaybeArray<InputPeerLike>,
params: { params: {
@ -32,28 +32,29 @@ export async function addChatMembers(
): Promise<void> { ): Promise<void> {
const { forwardCount = 100 } = params const { forwardCount = 100 } = params
const chat = await this.resolvePeer(chatId) const chat = await resolvePeer(client, chatId)
if (!Array.isArray(users)) users = [users] if (!Array.isArray(users)) users = [users]
if (isInputPeerChat(chat)) { if (isInputPeerChat(chat)) {
for (const user of users) { for (const user of users) {
const p = normalizeToInputUser(await this.resolvePeer(user)) const p = normalizeToInputUser(await resolvePeer(client, user))
const updates = await this.call({ const updates = await client.call({
_: 'messages.addChatUser', _: 'messages.addChatUser',
chatId: chat.chatId, chatId: chat.chatId,
userId: p, userId: p,
fwdLimit: forwardCount, fwdLimit: forwardCount,
}) })
this._handleUpdate(updates) client.network.handleUpdate(updates)
} }
} else if (isInputPeerChannel(chat)) { } else if (isInputPeerChannel(chat)) {
const updates = await this.call({ const updates = await client.call({
_: 'channels.inviteToChannel', _: 'channels.inviteToChannel',
channel: normalizeToInputChannel(chat), channel: normalizeToInputChannel(chat),
users: await this.resolvePeerMany(users, normalizeToInputUser), users: await resolvePeerMany(client, users, normalizeToInputUser),
}) })
this._handleUpdate(updates)
client.network.handleUpdate(updates)
} else throw new MtInvalidPeerTypeError(chatId, 'chat or channel') } else throw new MtInvalidPeerTypeError(chatId, 'chat or channel')
} }

View file

@ -1,20 +1,19 @@
import { MaybeArray } from '@mtcute/core' import { BaseTelegramClient, MaybeArray } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { InputPeerLike } from '../../types' import { InputPeerLike } from '../../types'
import { resolvePeerMany } from '../users/resolve-peer-many'
/** /**
* Archive one or more chats * Archive one or more chats
* *
* @param chats Chat ID(s), username(s), phone number(s), `"me"` or `"self"` * @param chats Chat ID(s), username(s), phone number(s), `"me"` or `"self"`
* @internal
*/ */
export async function archiveChats(this: TelegramClient, chats: MaybeArray<InputPeerLike>): Promise<void> { export async function archiveChats(client: BaseTelegramClient, chats: MaybeArray<InputPeerLike>): Promise<void> {
if (!Array.isArray(chats)) chats = [chats] if (!Array.isArray(chats)) chats = [chats]
const resolvedPeers = await this.resolvePeerMany(chats) const resolvedPeers = await resolvePeerMany(client, chats)
const updates = await this.call({ const updates = await client.call({
_: 'folders.editPeerFolders', _: 'folders.editPeerFolders',
folderPeers: resolvedPeers.map((peer) => ({ folderPeers: resolvedPeers.map((peer) => ({
_: 'inputFolderPeer', _: 'inputFolderPeer',
@ -22,5 +21,5 @@ export async function archiveChats(this: TelegramClient, chats: MaybeArray<Input
folderId: 1, folderId: 1,
})), })),
}) })
this._handleUpdate(updates) client.network.handleUpdate(updates)
} }

View file

@ -1,6 +1,5 @@
import { MtTypeAssertionError } from '@mtcute/core' import { BaseTelegramClient, MtTypeAssertionError } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { InputPeerLike, Message, MtInvalidPeerTypeError } from '../../types' import { InputPeerLike, Message, MtInvalidPeerTypeError } from '../../types'
import { import {
isInputPeerChannel, isInputPeerChannel,
@ -8,6 +7,8 @@ import {
normalizeToInputChannel, normalizeToInputChannel,
normalizeToInputUser, normalizeToInputUser,
} from '../../utils/peer-utils' } from '../../utils/peer-utils'
import { _findMessageInUpdate } from '../messages/find-in-update'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Ban a user/channel from a legacy group, a supergroup or a channel. * Ban a user/channel from a legacy group, a supergroup or a channel.
@ -18,10 +19,9 @@ import {
* any of their channels to post until the ban is lifted. * any of their channels to post until the ban is lifted.
* *
* @returns Service message about removed user, if one was generated. * @returns Service message about removed user, if one was generated.
* @internal
*/ */
export async function banChatMember( export async function banChatMember(
this: TelegramClient, client: BaseTelegramClient,
params: { params: {
/** Chat ID */ /** Chat ID */
chatId: InputPeerLike chatId: InputPeerLike
@ -29,12 +29,12 @@ export async function banChatMember(
participantId: InputPeerLike participantId: InputPeerLike
}, },
): Promise<Message | null> { ): Promise<Message | null> {
const chat = await this.resolvePeer(params.chatId) const chat = await resolvePeer(client, params.chatId)
const peer = await this.resolvePeer(params.participantId) const peer = await resolvePeer(client, params.participantId)
let res let res
if (isInputPeerChannel(chat)) { if (isInputPeerChannel(chat)) {
res = await this.call({ res = await client.call({
_: 'channels.editBanned', _: 'channels.editBanned',
channel: normalizeToInputChannel(chat), channel: normalizeToInputChannel(chat),
participant: peer, participant: peer,
@ -46,7 +46,7 @@ export async function banChatMember(
}, },
}) })
} else if (isInputPeerChat(chat)) { } else if (isInputPeerChat(chat)) {
res = await this.call({ res = await client.call({
_: 'messages.deleteChatUser', _: 'messages.deleteChatUser',
chatId: chat.chatId, chatId: chat.chatId,
userId: normalizeToInputUser(peer), userId: normalizeToInputUser(peer),
@ -54,7 +54,7 @@ export async function banChatMember(
} else throw new MtInvalidPeerTypeError(params.chatId, 'chat or channel') } else throw new MtInvalidPeerTypeError(params.chatId, 'chat or channel')
try { try {
return this._findMessageInUpdate(res) return _findMessageInUpdate(client, res)
} catch (e) { } catch (e) {
if (e instanceof MtTypeAssertionError && e.context === '_findInUpdate (@ .updates[*])') { if (e instanceof MtTypeAssertionError && e.context === '_findInUpdate (@ .updates[*])') {
// no service message // no service message

View file

@ -1,4 +1,5 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { Chat } from '../../types' import { Chat } from '../../types'
import { assertIsUpdatesGroup } from '../../utils/updates-utils' import { assertIsUpdatesGroup } from '../../utils/updates-utils'
@ -6,10 +7,9 @@ import { assertIsUpdatesGroup } from '../../utils/updates-utils'
* Create a new broadcast channel * Create a new broadcast channel
* *
* @returns Newly created channel * @returns Newly created channel
* @internal
*/ */
export async function createChannel( export async function createChannel(
this: TelegramClient, client: BaseTelegramClient,
params: { params: {
/** /**
* Channel title * Channel title
@ -24,7 +24,7 @@ export async function createChannel(
): Promise<Chat> { ): Promise<Chat> {
const { title, description = '' } = params const { title, description = '' } = params
const res = await this.call({ const res = await client.call({
_: 'channels.createChannel', _: 'channels.createChannel',
title, title,
about: description, about: description,
@ -33,7 +33,7 @@ export async function createChannel(
assertIsUpdatesGroup('channels.createChannel', res) assertIsUpdatesGroup('channels.createChannel', res)
this._handleUpdate(res) client.network.handleUpdate(res)
return new Chat(this, res.chats[0]) return new Chat(res.chats[0])
} }

View file

@ -1,20 +1,18 @@
import { MaybeArray } from '@mtcute/core' import { BaseTelegramClient, MaybeArray } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { Chat, InputPeerLike } from '../../types' import { Chat, InputPeerLike } from '../../types'
import { normalizeToInputUser } from '../../utils/peer-utils' import { normalizeToInputUser } from '../../utils/peer-utils'
import { assertIsUpdatesGroup } from '../../utils/updates-utils' import { assertIsUpdatesGroup } from '../../utils/updates-utils'
import { resolvePeerMany } from '../users/resolve-peer-many'
/** /**
* Create a legacy group chat * Create a legacy group chat
* *
* If you want to create a supergroup, use {@link createSupergroup} * If you want to create a supergroup, use {@link createSupergroup}
* instead. * instead.
*
* @internal
*/ */
export async function createGroup( export async function createGroup(
this: TelegramClient, client: BaseTelegramClient,
params: { params: {
/** /**
* Group title * Group title
@ -40,9 +38,9 @@ export async function createGroup(
if (!Array.isArray(users)) users = [users] if (!Array.isArray(users)) users = [users]
const peers = await this.resolvePeerMany(users, normalizeToInputUser) const peers = await resolvePeerMany(client, users, normalizeToInputUser)
const res = await this.call({ const res = await client.call({
_: 'messages.createChat', _: 'messages.createChat',
title, title,
users: peers, users: peers,
@ -50,7 +48,7 @@ export async function createGroup(
assertIsUpdatesGroup('messages.createChat', res) assertIsUpdatesGroup('messages.createChat', res)
this._handleUpdate(res) client.network.handleUpdate(res)
return new Chat(this, res.chats[0]) return new Chat(res.chats[0])
} }

View file

@ -1,4 +1,5 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { Chat } from '../../types' import { Chat } from '../../types'
import { assertIsUpdatesGroup } from '../../utils/updates-utils' import { assertIsUpdatesGroup } from '../../utils/updates-utils'
@ -6,10 +7,9 @@ import { assertIsUpdatesGroup } from '../../utils/updates-utils'
* Create a new supergroup * Create a new supergroup
* *
* @returns Newly created supergroup * @returns Newly created supergroup
* @internal
*/ */
export async function createSupergroup( export async function createSupergroup(
this: TelegramClient, client: BaseTelegramClient,
params: { params: {
/** /**
* Supergroup title * Supergroup title
@ -36,7 +36,7 @@ export async function createSupergroup(
): Promise<Chat> { ): Promise<Chat> {
const { title, description = '', forum, ttlPeriod = 0 } = params const { title, description = '', forum, ttlPeriod = 0 } = params
const res = await this.call({ const res = await client.call({
_: 'channels.createChannel', _: 'channels.createChannel',
title, title,
about: description, about: description,
@ -47,7 +47,7 @@ export async function createSupergroup(
assertIsUpdatesGroup('channels.createChannel', res) assertIsUpdatesGroup('channels.createChannel', res)
this._handleUpdate(res) client.network.handleUpdate(res)
return new Chat(this, res.chats[0]) return new Chat(res.chats[0])
} }

View file

@ -1,18 +1,19 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { InputPeerLike } from '../../types' import { InputPeerLike } from '../../types'
import { normalizeToInputChannel } from '../../utils/peer-utils' import { normalizeToInputChannel } from '../../utils/peer-utils'
import { resolvePeer } from '../users/resolve-peer'
// @alias=deleteSupergroup // @alias=deleteSupergroup
/** /**
* Delete a channel or a supergroup * Delete a channel or a supergroup
* *
* @param chatId Chat ID or username * @param chatId Chat ID or username
* @internal
*/ */
export async function deleteChannel(this: TelegramClient, chatId: InputPeerLike): Promise<void> { export async function deleteChannel(client: BaseTelegramClient, chatId: InputPeerLike): Promise<void> {
const res = await this.call({ const res = await client.call({
_: 'channels.deleteChannel', _: 'channels.deleteChannel',
channel: normalizeToInputChannel(await this.resolvePeer(chatId), chatId), channel: normalizeToInputChannel(await resolvePeer(client, chatId), chatId),
}) })
this._handleUpdate(res) client.network.handleUpdate(res)
} }

View file

@ -1,6 +1,8 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { InputPeerLike, MtInvalidPeerTypeError } from '../../types' import { InputPeerLike, MtInvalidPeerTypeError } from '../../types'
import { isInputPeerChannel, isInputPeerChat, normalizeToInputChannel } from '../../utils/peer-utils' import { isInputPeerChannel, isInputPeerChat, normalizeToInputChannel } from '../../utils/peer-utils'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Delete a chat photo * Delete a chat photo
@ -8,25 +10,24 @@ import { isInputPeerChannel, isInputPeerChat, normalizeToInputChannel } from '..
* You must be an administrator and have the appropriate permissions. * You must be an administrator and have the appropriate permissions.
* *
* @param chatId Chat ID or username * @param chatId Chat ID or username
* @internal
*/ */
export async function deleteChatPhoto(this: TelegramClient, chatId: InputPeerLike): Promise<void> { export async function deleteChatPhoto(client: BaseTelegramClient, chatId: InputPeerLike): Promise<void> {
const chat = await this.resolvePeer(chatId) const chat = await resolvePeer(client, chatId)
let res let res
if (isInputPeerChat(chat)) { if (isInputPeerChat(chat)) {
res = await this.call({ res = await client.call({
_: 'messages.editChatPhoto', _: 'messages.editChatPhoto',
chatId: chat.chatId, chatId: chat.chatId,
photo: { _: 'inputChatPhotoEmpty' }, photo: { _: 'inputChatPhotoEmpty' },
}) })
} else if (isInputPeerChannel(chat)) { } else if (isInputPeerChannel(chat)) {
res = await this.call({ res = await client.call({
_: 'channels.editPhoto', _: 'channels.editPhoto',
channel: normalizeToInputChannel(chat), channel: normalizeToInputChannel(chat),
photo: { _: 'inputChatPhotoEmpty' }, photo: { _: 'inputChatPhotoEmpty' },
}) })
} else throw new MtInvalidPeerTypeError(chatId, 'chat or channel') } else throw new MtInvalidPeerTypeError(chatId, 'chat or channel')
this._handleUpdate(res) client.network.handleUpdate(res)
} }

View file

@ -1,26 +1,27 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { InputPeerLike, MtInvalidPeerTypeError } from '../../types' import { InputPeerLike, MtInvalidPeerTypeError } from '../../types'
import { isInputPeerChat } from '../../utils/peer-utils' import { isInputPeerChat } from '../../utils/peer-utils'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Delete a legacy group chat for all members * Delete a legacy group chat for all members
* *
* @param chatId Chat ID * @param chatId Chat ID
* @internal
*/ */
export async function deleteGroup(this: TelegramClient, chatId: InputPeerLike): Promise<void> { export async function deleteGroup(client: BaseTelegramClient, chatId: InputPeerLike): Promise<void> {
const chat = await this.resolvePeer(chatId) const chat = await resolvePeer(client, chatId)
if (!isInputPeerChat(chat)) throw new MtInvalidPeerTypeError(chatId, 'chat') if (!isInputPeerChat(chat)) throw new MtInvalidPeerTypeError(chatId, 'chat')
const res = await this.call({ const res = await client.call({
_: 'messages.deleteChatUser', _: 'messages.deleteChatUser',
revokeHistory: true, revokeHistory: true,
chatId: chat.chatId, chatId: chat.chatId,
userId: { _: 'inputUserSelf' }, userId: { _: 'inputUserSelf' },
}) })
this._handleUpdate(res) client.network.handleUpdate(res)
await this.call({ await client.call({
_: 'messages.deleteChat', _: 'messages.deleteChat',
chatId: chat.chatId, chatId: chat.chatId,
}) })

View file

@ -1,16 +1,15 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { InputPeerLike } from '../../types' import { InputPeerLike } from '../../types'
import { isInputPeerChannel } from '../../utils/peer-utils' import { isInputPeerChannel } from '../../utils/peer-utils'
import { createDummyUpdate } from '../../utils/updates-utils' import { createDummyUpdate } from '../../utils/updates-utils'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Delete communication history (for private chats * Delete communication history (for private chats and legacy groups)
* and legacy groups)
*
* @internal
*/ */
export async function deleteHistory( export async function deleteHistory(
this: TelegramClient, client: BaseTelegramClient,
chat: InputPeerLike, chat: InputPeerLike,
params?: { params?: {
/** /**
@ -35,9 +34,9 @@ export async function deleteHistory(
): Promise<void> { ): Promise<void> {
const { mode = 'delete', maxId = 0 } = params ?? {} const { mode = 'delete', maxId = 0 } = params ?? {}
const peer = await this.resolvePeer(chat) const peer = await resolvePeer(client, chat)
const res = await this.call({ const res = await client.call({
_: 'messages.deleteHistory', _: 'messages.deleteHistory',
justClear: mode === 'clear', justClear: mode === 'clear',
revoke: mode === 'revoke', revoke: mode === 'revoke',
@ -46,8 +45,8 @@ export async function deleteHistory(
}) })
if (isInputPeerChannel(peer)) { if (isInputPeerChannel(peer)) {
this._handleUpdate(createDummyUpdate(res.pts, res.ptsCount, peer.channelId)) client.network.handleUpdate(createDummyUpdate(res.pts, res.ptsCount, peer.channelId))
} else { } else {
this._handleUpdate(createDummyUpdate(res.pts, res.ptsCount)) client.network.handleUpdate(createDummyUpdate(res.pts, res.ptsCount))
} }
} }

View file

@ -1,17 +1,15 @@
import { tl } from '@mtcute/core' import { BaseTelegramClient, tl } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { InputPeerLike } from '../../types' import { InputPeerLike } from '../../types'
import { normalizeToInputChannel } from '../../utils/peer-utils' import { normalizeToInputChannel } from '../../utils/peer-utils'
import { createDummyUpdate } from '../../utils/updates-utils' import { createDummyUpdate } from '../../utils/updates-utils'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Delete all messages of a user (or channel) in a supergroup * Delete all messages of a user (or channel) in a supergroup
*
* @internal
*/ */
export async function deleteUserHistory( export async function deleteUserHistory(
this: TelegramClient, client: BaseTelegramClient,
params: { params: {
/** Chat ID */ /** Chat ID */
chatId: InputPeerLike chatId: InputPeerLike
@ -21,15 +19,15 @@ export async function deleteUserHistory(
): Promise<void> { ): Promise<void> {
const { chatId, participantId } = params const { chatId, participantId } = params
const channel = normalizeToInputChannel(await this.resolvePeer(chatId), chatId) const channel = normalizeToInputChannel(await resolvePeer(client, chatId), chatId)
const peer = await this.resolvePeer(participantId) const peer = await resolvePeer(client, participantId)
const res = await this.call({ const res = await client.call({
_: 'channels.deleteParticipantHistory', _: 'channels.deleteParticipantHistory',
channel, channel,
participant: peer, participant: peer,
}) })
this._handleUpdate(createDummyUpdate(res.pts, res.ptsCount, (channel as tl.RawInputChannel).channelId)) client.network.handleUpdate(createDummyUpdate(res.pts, res.ptsCount, (channel as tl.RawInputChannel).channelId))
} }

View file

@ -1,16 +1,14 @@
import { tl } from '@mtcute/core' import { BaseTelegramClient, tl } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { InputPeerLike } from '../../types' import { InputPeerLike } from '../../types'
import { normalizeToInputChannel, normalizeToInputUser } from '../../utils/peer-utils' import { normalizeToInputChannel, normalizeToInputUser } from '../../utils/peer-utils'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Edit supergroup/channel admin rights of a user. * Edit supergroup/channel admin rights of a user.
*
* @internal
*/ */
export async function editAdminRights( export async function editAdminRights(
this: TelegramClient, client: BaseTelegramClient,
params: { params: {
/** Chat ID */ /** Chat ID */
chatId: InputPeerLike chatId: InputPeerLike
@ -24,10 +22,10 @@ export async function editAdminRights(
): Promise<void> { ): Promise<void> {
const { chatId, userId, rights, rank = '' } = params const { chatId, userId, rights, rank = '' } = params
const chat = normalizeToInputChannel(await this.resolvePeer(chatId), chatId) const chat = normalizeToInputChannel(await resolvePeer(client, chatId), chatId)
const user = normalizeToInputUser(await this.resolvePeer(userId), userId) const user = normalizeToInputUser(await resolvePeer(client, userId), userId)
const res = await this.call({ const res = await client.call({
_: 'channels.editAdmin', _: 'channels.editAdmin',
channel: chat, channel: chat,
userId: user, userId: user,
@ -38,5 +36,5 @@ export async function editAdminRights(
rank, rank,
}) })
this._handleUpdate(res) client.network.handleUpdate(res)
} }

View file

@ -1,9 +1,10 @@
import { Long, tl } from '@mtcute/core' import { BaseTelegramClient, Long, tl } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { ChatEvent, InputPeerLike, PeersIndex } from '../../types' import { ChatEvent, InputPeerLike, PeersIndex } from '../../types'
import { InputChatEventFilters, normalizeChatEventFilters } from '../../types/peers/chat-event/filters' import { InputChatEventFilters, normalizeChatEventFilters } from '../../types/peers/chat-event/filters'
import { normalizeToInputChannel, normalizeToInputUser } from '../../utils/peer-utils' import { normalizeToInputChannel, normalizeToInputUser } from '../../utils/peer-utils'
import { resolvePeer } from '../users/resolve-peer'
import { resolvePeerMany } from '../users/resolve-peer-many'
/** /**
* Get chat event log ("Recent actions" in official clients). * Get chat event log ("Recent actions" in official clients).
@ -17,10 +18,9 @@ import { normalizeToInputChannel, normalizeToInputUser } from '../../utils/peer-
* events have bigger event ID) * events have bigger event ID)
* *
* @param params * @param params
* @internal
*/ */
export async function getChatEventLog( export async function getChatEventLog(
this: TelegramClient, client: BaseTelegramClient,
chatId: InputPeerLike, chatId: InputPeerLike,
params?: { params?: {
/** /**
@ -74,15 +74,15 @@ export async function getChatEventLog(
): Promise<ChatEvent[]> { ): Promise<ChatEvent[]> {
const { maxId = Long.ZERO, minId = Long.ZERO, query = '', limit = 100, users, filters } = params ?? {} const { maxId = Long.ZERO, minId = Long.ZERO, query = '', limit = 100, users, filters } = params ?? {}
const channel = normalizeToInputChannel(await this.resolvePeer(chatId), chatId) const channel = normalizeToInputChannel(await resolvePeer(client, chatId), chatId)
const admins: tl.TypeInputUser[] | undefined = users ? const admins: tl.TypeInputUser[] | undefined = users ?
await this.resolvePeerMany(users, normalizeToInputUser) : await resolvePeerMany(client, users, normalizeToInputUser) :
undefined undefined
const { serverFilter, localFilter } = normalizeChatEventFilters(filters) const { serverFilter, localFilter } = normalizeChatEventFilters(filters)
const res = await this.call({ const res = await client.call({
_: 'channels.getAdminLog', _: 'channels.getAdminLog',
channel, channel,
q: query, q: query,
@ -100,7 +100,7 @@ export async function getChatEventLog(
const results: ChatEvent[] = [] const results: ChatEvent[] = []
for (const evt of res.events) { for (const evt of res.events) {
const parsed = new ChatEvent(this, evt, peers) const parsed = new ChatEvent(evt, peers)
if (localFilter && (!parsed.action || !localFilter[parsed.action.type])) { if (localFilter && (!parsed.action || !localFilter[parsed.action.type])) {
continue continue

View file

@ -1,9 +1,9 @@
import { tl } from '@mtcute/core' import { BaseTelegramClient, tl } from '@mtcute/core'
import { assertTypeIs } from '@mtcute/core/utils' import { assertTypeIs } from '@mtcute/core/utils'
import { TelegramClient } from '../../client'
import { ChatMember, InputPeerLike, MtInvalidPeerTypeError, PeersIndex } from '../../types' import { ChatMember, InputPeerLike, MtInvalidPeerTypeError, PeersIndex } from '../../types'
import { isInputPeerChannel, isInputPeerChat, isInputPeerUser, normalizeToInputChannel } from '../../utils/peer-utils' import { isInputPeerChannel, isInputPeerChat, isInputPeerUser, normalizeToInputChannel } from '../../utils/peer-utils'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Get information about a single chat member * Get information about a single chat member
@ -11,10 +11,9 @@ import { isInputPeerChannel, isInputPeerChat, isInputPeerUser, normalizeToInputC
* @param chatId Chat ID or username * @param chatId Chat ID or username
* @param userId User ID, username, phone number, `"me"` or `"self"` * @param userId User ID, username, phone number, `"me"` or `"self"`
* @throws UserNotParticipantError In case given user is not a participant of a given chat * @throws UserNotParticipantError In case given user is not a participant of a given chat
* @internal
*/ */
export async function getChatMember( export async function getChatMember(
this: TelegramClient, client: BaseTelegramClient,
params: { params: {
/** Chat ID or username */ /** Chat ID or username */
chatId: InputPeerLike chatId: InputPeerLike
@ -24,15 +23,15 @@ export async function getChatMember(
): Promise<ChatMember> { ): Promise<ChatMember> {
const { chatId, userId } = params const { chatId, userId } = params
const user = await this.resolvePeer(userId) const user = await resolvePeer(client, userId)
const chat = await this.resolvePeer(chatId) const chat = await resolvePeer(client, chatId)
if (isInputPeerChat(chat)) { if (isInputPeerChat(chat)) {
if (!isInputPeerUser(user)) { if (!isInputPeerUser(user)) {
throw new MtInvalidPeerTypeError(userId, 'user') throw new MtInvalidPeerTypeError(userId, 'user')
} }
const res = await this.call({ const res = await client.call({
_: 'messages.getFullChat', _: 'messages.getFullChat',
chatId: chat.chatId, chatId: chat.chatId,
}) })
@ -49,13 +48,13 @@ export async function getChatMember(
(user._ === 'inputPeerSelf' && (peers.user(m.userId) as tl.RawUser).self) || (user._ === 'inputPeerSelf' && (peers.user(m.userId) as tl.RawUser).self) ||
(user._ === 'inputPeerUser' && m.userId === user.userId) (user._ === 'inputPeerUser' && m.userId === user.userId)
) { ) {
return new ChatMember(this, m, peers) return new ChatMember(m, peers)
} }
} }
throw new tl.RpcError(404, 'USER_NOT_PARTICIPANT') throw new tl.RpcError(404, 'USER_NOT_PARTICIPANT')
} else if (isInputPeerChannel(chat)) { } else if (isInputPeerChannel(chat)) {
const res = await this.call({ const res = await client.call({
_: 'channels.getParticipant', _: 'channels.getParticipant',
channel: normalizeToInputChannel(chat), channel: normalizeToInputChannel(chat),
participant: user, participant: user,
@ -63,6 +62,6 @@ export async function getChatMember(
const peers = PeersIndex.from(res) const peers = PeersIndex.from(res)
return new ChatMember(this, res.participant, peers) return new ChatMember(res.participant, peers)
} else throw new MtInvalidPeerTypeError(chatId, 'chat or channel') } else throw new MtInvalidPeerTypeError(chatId, 'chat or channel')
} }

View file

@ -1,10 +1,10 @@
import { assertNever, Long, tl } from '@mtcute/core' import { assertNever, BaseTelegramClient, Long, tl } from '@mtcute/core'
import { assertTypeIs } from '@mtcute/core/utils' import { assertTypeIs } from '@mtcute/core/utils'
import { TelegramClient } from '../../client'
import { ArrayWithTotal, ChatMember, InputPeerLike, MtInvalidPeerTypeError, PeersIndex } from '../../types' import { ArrayWithTotal, ChatMember, InputPeerLike, MtInvalidPeerTypeError, PeersIndex } from '../../types'
import { makeArrayWithTotal } from '../../utils' import { makeArrayWithTotal } from '../../utils'
import { isInputPeerChannel, isInputPeerChat, normalizeToInputChannel } from '../../utils/peer-utils' import { isInputPeerChannel, isInputPeerChat, normalizeToInputChannel } from '../../utils/peer-utils'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Get a chunk of members of some chat. * Get a chunk of members of some chat.
@ -13,10 +13,9 @@ import { isInputPeerChannel, isInputPeerChat, normalizeToInputChannel } from '..
* *
* @param chatId Chat ID or username * @param chatId Chat ID or username
* @param params Additional parameters * @param params Additional parameters
* @internal
*/ */
export async function getChatMembers( export async function getChatMembers(
this: TelegramClient, client: BaseTelegramClient,
chatId: InputPeerLike, chatId: InputPeerLike,
params?: { params?: {
/** /**
@ -62,10 +61,10 @@ export async function getChatMembers(
): Promise<ArrayWithTotal<ChatMember>> { ): Promise<ArrayWithTotal<ChatMember>> {
const { query = '', offset = 0, limit = 200, type = 'recent' } = params ?? {} const { query = '', offset = 0, limit = 200, type = 'recent' } = params ?? {}
const chat = await this.resolvePeer(chatId) const chat = await resolvePeer(client, chatId)
if (isInputPeerChat(chat)) { if (isInputPeerChat(chat)) {
const res = await this.call({ const res = await client.call({
_: 'messages.getFullChat', _: 'messages.getFullChat',
chatId: chat.chatId, chatId: chat.chatId,
}) })
@ -80,7 +79,7 @@ export async function getChatMembers(
const peers = PeersIndex.from(res) const peers = PeersIndex.from(res)
const ret = members.map((m) => new ChatMember(this, m, peers)) const ret = members.map((m) => new ChatMember(m, peers))
return makeArrayWithTotal(ret, ret.length) return makeArrayWithTotal(ret, ret.length)
} }
@ -119,7 +118,7 @@ export async function getChatMembers(
assertNever(type) assertNever(type)
} }
const res = await this.call({ const res = await client.call({
_: 'channels.getParticipants', _: 'channels.getParticipants',
channel: normalizeToInputChannel(chat), channel: normalizeToInputChannel(chat),
filter, filter,
@ -132,7 +131,7 @@ export async function getChatMembers(
const peers = PeersIndex.from(res) const peers = PeersIndex.from(res)
const ret = res.participants.map((i) => new ChatMember(this, i, peers)) as ArrayWithTotal<ChatMember> const ret = res.participants.map((i) => new ChatMember(i, peers))
return makeArrayWithTotal(ret, res.count) return makeArrayWithTotal(ret, res.count)
} }

View file

@ -1,6 +1,5 @@
import { MtArgumentError } from '@mtcute/core' import { BaseTelegramClient, MtArgumentError } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { ChatPreview, MtPeerNotFoundError } from '../../types' import { ChatPreview, MtPeerNotFoundError } from '../../types'
import { INVITE_LINK_REGEX } from '../../utils/peer-utils' import { INVITE_LINK_REGEX } from '../../utils/peer-utils'
@ -12,13 +11,12 @@ import { INVITE_LINK_REGEX } from '../../utils/peer-utils'
* @throws MtPeerNotFoundError * @throws MtPeerNotFoundError
* In case you are trying to get info about private chat that you have already joined. * In case you are trying to get info about private chat that you have already joined.
* Use {@link getChat} or {@link getFullChat} instead. * Use {@link getChat} or {@link getFullChat} instead.
* @internal
*/ */
export async function getChatPreview(this: TelegramClient, inviteLink: string): Promise<ChatPreview> { export async function getChatPreview(client: BaseTelegramClient, inviteLink: string): Promise<ChatPreview> {
const m = inviteLink.match(INVITE_LINK_REGEX) const m = inviteLink.match(INVITE_LINK_REGEX)
if (!m) throw new MtArgumentError('Invalid invite link') if (!m) throw new MtArgumentError('Invalid invite link')
const res = await this.call({ const res = await client.call({
_: 'messages.checkChatInvite', _: 'messages.checkChatInvite',
hash: m[1], hash: m[1],
}) })
@ -27,5 +25,5 @@ export async function getChatPreview(this: TelegramClient, inviteLink: string):
throw new MtPeerNotFoundError('You have already joined this chat!') throw new MtPeerNotFoundError('You have already joined this chat!')
} }
return new ChatPreview(this, res, inviteLink) return new ChatPreview(res, inviteLink)
} }

View file

@ -1,6 +1,5 @@
import { MtArgumentError, tl } from '@mtcute/core' import { BaseTelegramClient, MtArgumentError, tl } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { Chat, InputPeerLike } from '../../types' import { Chat, InputPeerLike } from '../../types'
import { import {
INVITE_LINK_REGEX, INVITE_LINK_REGEX,
@ -10,6 +9,7 @@ import {
normalizeToInputChannel, normalizeToInputChannel,
normalizeToInputUser, normalizeToInputUser,
} from '../../utils/peer-utils' } from '../../utils/peer-utils'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Get basic information about a chat. * Get basic information about a chat.
@ -18,14 +18,13 @@ import {
* @throws MtArgumentError * @throws MtArgumentError
* In case you are trying to get info about private chat that you haven't joined. * In case you are trying to get info about private chat that you haven't joined.
* Use {@link getChatPreview} instead. * Use {@link getChatPreview} instead.
* @internal
*/ */
export async function getChat(this: TelegramClient, chatId: InputPeerLike): Promise<Chat> { export async function getChat(client: BaseTelegramClient, chatId: InputPeerLike): Promise<Chat> {
if (typeof chatId === 'string') { if (typeof chatId === 'string') {
const m = chatId.match(INVITE_LINK_REGEX) const m = chatId.match(INVITE_LINK_REGEX)
if (m) { if (m) {
const res = await this.call({ const res = await client.call({
_: 'messages.checkChatInvite', _: 'messages.checkChatInvite',
hash: m[1], hash: m[1],
}) })
@ -34,32 +33,32 @@ export async function getChat(this: TelegramClient, chatId: InputPeerLike): Prom
throw new MtArgumentError(`You haven't joined ${JSON.stringify(res.title)}`) throw new MtArgumentError(`You haven't joined ${JSON.stringify(res.title)}`)
} }
return new Chat(this, res.chat) return new Chat(res.chat)
} }
} }
const peer = await this.resolvePeer(chatId) const peer = await resolvePeer(client, chatId)
let res: tl.TypeChat | tl.TypeUser let res: tl.TypeChat | tl.TypeUser
if (isInputPeerChannel(peer)) { if (isInputPeerChannel(peer)) {
const r = await this.call({ const r = await client.call({
_: 'channels.getChannels', _: 'channels.getChannels',
id: [normalizeToInputChannel(peer)], id: [normalizeToInputChannel(peer)],
}) })
res = r.chats[0] res = r.chats[0]
} else if (isInputPeerUser(peer)) { } else if (isInputPeerUser(peer)) {
const r = await this.call({ const r = await client.call({
_: 'users.getUsers', _: 'users.getUsers',
id: [normalizeToInputUser(peer)], id: [normalizeToInputUser(peer)],
}) })
res = r[0] res = r[0]
} else if (isInputPeerChat(peer)) { } else if (isInputPeerChat(peer)) {
const r = await this.call({ const r = await client.call({
_: 'messages.getChats', _: 'messages.getChats',
id: [peer.chatId], id: [peer.chatId],
}) })
res = r.chats[0] res = r.chats[0]
} else throw new Error('should not happen') } else throw new Error('should not happen')
return new Chat(this, res) return new Chat(res)
} }

View file

@ -1,6 +1,5 @@
import { MtArgumentError, tl } from '@mtcute/core' import { BaseTelegramClient, MtArgumentError, tl } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { Chat, InputPeerLike } from '../../types' import { Chat, InputPeerLike } from '../../types'
import { import {
INVITE_LINK_REGEX, INVITE_LINK_REGEX,
@ -10,6 +9,7 @@ import {
normalizeToInputChannel, normalizeToInputChannel,
normalizeToInputUser, normalizeToInputUser,
} from '../../utils/peer-utils' } from '../../utils/peer-utils'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Get full information about a chat. * Get full information about a chat.
@ -18,14 +18,13 @@ import {
* @throws MtArgumentError * @throws MtArgumentError
* In case you are trying to get info about private chat that you haven't joined. * In case you are trying to get info about private chat that you haven't joined.
* Use {@link getChatPreview} instead. * Use {@link getChatPreview} instead.
* @internal
*/ */
export async function getFullChat(this: TelegramClient, chatId: InputPeerLike): Promise<Chat> { export async function getFullChat(client: BaseTelegramClient, chatId: InputPeerLike): Promise<Chat> {
if (typeof chatId === 'string') { if (typeof chatId === 'string') {
const m = chatId.match(INVITE_LINK_REGEX) const m = chatId.match(INVITE_LINK_REGEX)
if (m) { if (m) {
const res = await this.call({ const res = await client.call({
_: 'messages.checkChatInvite', _: 'messages.checkChatInvite',
hash: m[1], hash: m[1],
}) })
@ -39,25 +38,25 @@ export async function getFullChat(this: TelegramClient, chatId: InputPeerLike):
} }
} }
const peer = await this.resolvePeer(chatId) const peer = await resolvePeer(client, chatId)
let res: tl.messages.TypeChatFull | tl.users.TypeUserFull let res: tl.messages.TypeChatFull | tl.users.TypeUserFull
if (isInputPeerChannel(peer)) { if (isInputPeerChannel(peer)) {
res = await this.call({ res = await client.call({
_: 'channels.getFullChannel', _: 'channels.getFullChannel',
channel: normalizeToInputChannel(peer), channel: normalizeToInputChannel(peer),
}) })
} else if (isInputPeerUser(peer)) { } else if (isInputPeerUser(peer)) {
res = await this.call({ res = await client.call({
_: 'users.getFullUser', _: 'users.getFullUser',
id: normalizeToInputUser(peer)!, id: normalizeToInputUser(peer)!,
}) })
} else if (isInputPeerChat(peer)) { } else if (isInputPeerChat(peer)) {
res = await this.call({ res = await client.call({
_: 'messages.getFullChat', _: 'messages.getFullChat',
chatId: peer.chatId, chatId: peer.chatId,
}) })
} else throw new Error('should not happen') } else throw new Error('should not happen')
return Chat._parseFull(this, res) return Chat._parseFull(res)
} }

View file

@ -1,7 +1,6 @@
import { getMarkedPeerId, tl } from '@mtcute/core' import { BaseTelegramClient, getMarkedPeerId, tl } from '@mtcute/core'
import { assertTypeIs } from '@mtcute/core/utils' import { assertTypeIs } from '@mtcute/core/utils'
import { TelegramClient } from '../../client'
import { Chat } from '../../types' import { Chat } from '../../types'
import { assertIsUpdatesGroup } from '../../utils/updates-utils' import { assertIsUpdatesGroup } from '../../utils/updates-utils'
@ -10,10 +9,9 @@ import { assertIsUpdatesGroup } from '../../utils/updates-utils'
* *
* @param latitude Latitude of the location * @param latitude Latitude of the location
* @param longitude Longitude of the location * @param longitude Longitude of the location
* @internal
*/ */
export async function getNearbyChats(this: TelegramClient, latitude: number, longitude: number): Promise<Chat[]> { export async function getNearbyChats(client: BaseTelegramClient, latitude: number, longitude: number): Promise<Chat[]> {
const res = await this.call({ const res = await client.call({
_: 'contacts.getLocated', _: 'contacts.getLocated',
geoPoint: { geoPoint: {
_: 'inputGeoPoint', _: 'inputGeoPoint',
@ -23,13 +21,13 @@ export async function getNearbyChats(this: TelegramClient, latitude: number, lon
}) })
assertIsUpdatesGroup('contacts.getLocated', res) assertIsUpdatesGroup('contacts.getLocated', res)
this._handleUpdate(res, true) client.network.handleUpdate(res, true)
if (!res.updates.length) return [] if (!res.updates.length) return []
assertTypeIs('contacts.getLocated (@ .updates[0])', res.updates[0], 'updatePeerLocated') assertTypeIs('contacts.getLocated (@ .updates[0])', res.updates[0], 'updatePeerLocated')
const chats = res.chats.map((it) => new Chat(this, it)) const chats = res.chats.map((it) => new Chat(it))
const index: Record<number, Chat> = {} const index: Record<number, Chat> = {}
chats.forEach((c) => (index[c.id] = c)) chats.forEach((c) => (index[c.id] = c))

View file

@ -1,9 +1,11 @@
import { Long, tl } from '@mtcute/core' import { BaseTelegramClient, Long, tl } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { ChatEvent, InputPeerLike } from '../../types' import { ChatEvent, InputPeerLike } from '../../types'
import { normalizeChatEventFilters } from '../../types/peers/chat-event/filters' import { normalizeChatEventFilters } from '../../types/peers/chat-event/filters'
import { normalizeToInputChannel, normalizeToInputUser } from '../../utils/peer-utils' import { normalizeToInputChannel, normalizeToInputUser } from '../../utils/peer-utils'
import { resolvePeer } from '../users/resolve-peer'
import { resolvePeerMany } from '../users/resolve-peer-many'
import { getChatEventLog } from './get-chat-event-log'
/** /**
* Iterate over chat event log. * Iterate over chat event log.
@ -12,12 +14,11 @@ import { normalizeToInputChannel, normalizeToInputUser } from '../../utils/peer-
* *
* @param chatId Chat ID * @param chatId Chat ID
* @param params * @param params
* @internal
*/ */
export async function* iterChatEventLog( export async function* iterChatEventLog(
this: TelegramClient, client: BaseTelegramClient,
chatId: InputPeerLike, chatId: InputPeerLike,
params?: Parameters<TelegramClient['getChatEventLog']>[1] & { params?: Parameters<typeof getChatEventLog>[2] & {
/** /**
* Total number of events to return. * Total number of events to return.
* *
@ -36,12 +37,12 @@ export async function* iterChatEventLog(
): AsyncIterableIterator<ChatEvent> { ): AsyncIterableIterator<ChatEvent> {
if (!params) params = {} if (!params) params = {}
const channel = normalizeToInputChannel(await this.resolvePeer(chatId), chatId) const channel = normalizeToInputChannel(await resolvePeer(client, chatId), chatId)
const { minId = Long.ZERO, query = '', limit = Infinity, chunkSize = 100, users, filters } = params const { minId = Long.ZERO, query = '', limit = Infinity, chunkSize = 100, users, filters } = params
const admins: tl.TypeInputUser[] | undefined = users ? const admins: tl.TypeInputUser[] | undefined = users ?
await this.resolvePeerMany(users, normalizeToInputUser) : await resolvePeerMany(client, users, normalizeToInputUser) :
undefined undefined
const { serverFilter, localFilter } = normalizeChatEventFilters(filters) const { serverFilter, localFilter } = normalizeChatEventFilters(filters)
@ -50,7 +51,7 @@ export async function* iterChatEventLog(
let maxId = params.maxId ?? Long.ZERO let maxId = params.maxId ?? Long.ZERO
for (;;) { for (;;) {
const chunk = await this.getChatEventLog(channel, { const chunk = await getChatEventLog(client, channel, {
minId, minId,
maxId, maxId,
query, query,

View file

@ -1,6 +1,9 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { ChatMember, InputPeerLike } from '../../types' import { ChatMember, InputPeerLike } from '../../types'
import { isInputPeerChat } from '../../utils/peer-utils' import { isInputPeerChat } from '../../utils/peer-utils'
import { resolvePeer } from '../users/resolve-peer'
import { getChatMembers } from './get-chat-members'
/** /**
* Iterate through chat members * Iterate through chat members
@ -11,15 +14,14 @@ import { isInputPeerChat } from '../../utils/peer-utils'
* *
* @param chatId Chat ID or username * @param chatId Chat ID or username
* @param params Additional parameters * @param params Additional parameters
* @internal
*/ */
export async function* iterChatMembers( export async function* iterChatMembers(
this: TelegramClient, client: BaseTelegramClient,
chatId: InputPeerLike, chatId: InputPeerLike,
params?: Parameters<TelegramClient['getChatMembers']>[1] & { params?: Parameters<typeof getChatMembers>[2] & {
/** /**
* Chunk size, which will be passed as `limit` parameter * Chunk size, which will be passed as `limit` parameter
* to {@link TelegramClient.getChatMembers}. Usually you shouldn't care about this. * to {@link getChatMembers}. Usually you shouldn't care about this.
* *
* Defaults to `200` * Defaults to `200`
*/ */
@ -34,10 +36,10 @@ export async function* iterChatMembers(
let offset = params.offset ?? 0 let offset = params.offset ?? 0
const yielded = new Set() const yielded = new Set()
const chat = await this.resolvePeer(chatId) const chat = await resolvePeer(client, chatId)
for (;;) { for (;;) {
const members = await this.getChatMembers(chat, { const members = await getChatMembers(client, chat, {
offset, offset,
limit, limit,
query: params.query, query: params.query,

View file

@ -1,7 +1,9 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { Chat, InputPeerLike } from '../../types' import { Chat, InputPeerLike } from '../../types'
import { INVITE_LINK_REGEX, normalizeToInputChannel } from '../../utils/peer-utils' import { INVITE_LINK_REGEX, normalizeToInputChannel } from '../../utils/peer-utils'
import { assertIsUpdatesGroup } from '../../utils/updates-utils' import { assertIsUpdatesGroup } from '../../utils/updates-utils'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Join a channel or supergroup * Join a channel or supergroup
@ -13,33 +15,32 @@ import { assertIsUpdatesGroup } from '../../utils/updates-utils'
* @param chatId * @param chatId
* Chat identifier. Either an invite link (`t.me/joinchat/*`), a username (`@username`) * Chat identifier. Either an invite link (`t.me/joinchat/*`), a username (`@username`)
* or ID of the linked supergroup or channel. * or ID of the linked supergroup or channel.
* @internal
*/ */
export async function joinChat(this: TelegramClient, chatId: InputPeerLike): Promise<Chat> { export async function joinChat(client: BaseTelegramClient, chatId: InputPeerLike): Promise<Chat> {
if (typeof chatId === 'string') { if (typeof chatId === 'string') {
const m = chatId.match(INVITE_LINK_REGEX) const m = chatId.match(INVITE_LINK_REGEX)
if (m) { if (m) {
const res = await this.call({ const res = await client.call({
_: 'messages.importChatInvite', _: 'messages.importChatInvite',
hash: m[1], hash: m[1],
}) })
assertIsUpdatesGroup('messages.importChatInvite', res) assertIsUpdatesGroup('messages.importChatInvite', res)
this._handleUpdate(res) client.network.handleUpdate(res)
return new Chat(this, res.chats[0]) return new Chat(res.chats[0])
} }
} }
const res = await this.call({ const res = await client.call({
_: 'channels.joinChannel', _: 'channels.joinChannel',
channel: normalizeToInputChannel(await this.resolvePeer(chatId), chatId), channel: normalizeToInputChannel(await resolvePeer(client, chatId), chatId),
}) })
assertIsUpdatesGroup('channels.joinChannel', res) assertIsUpdatesGroup('channels.joinChannel', res)
this._handleUpdate(res) client.network.handleUpdate(res)
return new Chat(this, res.chats[0]) return new Chat(res.chats[0])
} }

View file

@ -1,18 +1,19 @@
import { BaseTelegramClient } from '@mtcute/core'
import { sleep } from '@mtcute/core/utils' import { sleep } from '@mtcute/core/utils'
import { TelegramClient } from '../../client'
import { InputPeerLike } from '../../types' import { InputPeerLike } from '../../types'
import { isInputPeerChannel } from '../../utils/peer-utils' import { isInputPeerChannel } from '../../utils/peer-utils'
import { resolvePeer } from '../users/resolve-peer'
import { banChatMember } from './ban-chat-member'
import { unbanChatMember } from './unban-chat-member'
/** /**
* Kick a user from a chat. * Kick a user from a chat.
* *
* This effectively bans a user and immediately unbans them. * This effectively bans a user and immediately unbans them.
*
* @internal
*/ */
export async function kickChatMember( export async function kickChatMember(
this: TelegramClient, client: BaseTelegramClient,
params: { params: {
/** Chat ID */ /** Chat ID */
chatId: InputPeerLike chatId: InputPeerLike
@ -22,15 +23,15 @@ export async function kickChatMember(
): Promise<void> { ): Promise<void> {
const { chatId, userId } = params const { chatId, userId } = params
const chat = await this.resolvePeer(chatId) const chat = await resolvePeer(client, chatId)
const user = await this.resolvePeer(userId) const user = await resolvePeer(client, userId)
await this.banChatMember({ chatId: chat, participantId: user }) await banChatMember(client, { chatId: chat, participantId: user })
// not needed in case this is a legacy group // not needed in case this is a legacy group
if (isInputPeerChannel(chat)) { if (isInputPeerChannel(chat)) {
// i fucking love telegram serverside race conditions // i fucking love telegram serverside race conditions
await sleep(1000) await sleep(1000)
await this.unbanChatMember({ chatId: chat, participantId: user }) await unbanChatMember(client, { chatId: chat, participantId: user })
} }
} }

View file

@ -1,15 +1,17 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { InputPeerLike, MtInvalidPeerTypeError } from '../../types' import { InputPeerLike, MtInvalidPeerTypeError } from '../../types'
import { isInputPeerChannel, isInputPeerChat, normalizeToInputChannel } from '../../utils/peer-utils' import { isInputPeerChannel, isInputPeerChat, normalizeToInputChannel } from '../../utils/peer-utils'
import { resolvePeer } from '../users/resolve-peer'
import { deleteHistory } from './delete-history'
/** /**
* Leave a group chat, supergroup or channel * Leave a group chat, supergroup or channel
* *
* @param chatId Chat ID or username * @param chatId Chat ID or username
* @internal
*/ */
export async function leaveChat( export async function leaveChat(
this: TelegramClient, client: BaseTelegramClient,
chatId: InputPeerLike, chatId: InputPeerLike,
params?: { params?: {
/** /**
@ -18,24 +20,24 @@ export async function leaveChat(
clear?: boolean clear?: boolean
}, },
): Promise<void> { ): Promise<void> {
const chat = await this.resolvePeer(chatId) const chat = await resolvePeer(client, chatId)
if (isInputPeerChannel(chat)) { if (isInputPeerChannel(chat)) {
const res = await this.call({ const res = await client.call({
_: 'channels.leaveChannel', _: 'channels.leaveChannel',
channel: normalizeToInputChannel(chat), channel: normalizeToInputChannel(chat),
}) })
this._handleUpdate(res) client.network.handleUpdate(res)
} else if (isInputPeerChat(chat)) { } else if (isInputPeerChat(chat)) {
const res = await this.call({ const res = await client.call({
_: 'messages.deleteChatUser', _: 'messages.deleteChatUser',
chatId: chat.chatId, chatId: chat.chatId,
userId: { _: 'inputUserSelf' }, userId: { _: 'inputUserSelf' },
}) })
this._handleUpdate(res) client.network.handleUpdate(res)
if (params?.clear) { if (params?.clear) {
await this.deleteHistory(chat) await deleteHistory(client, chat)
} }
} else throw new MtInvalidPeerTypeError(chatId, 'chat or channel') } else throw new MtInvalidPeerTypeError(chatId, 'chat or channel')
} }

View file

@ -1,18 +1,19 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { InputPeerLike } from '../../types' import { InputPeerLike } from '../../types'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Mark a chat as unread * Mark a chat as unread
* *
* @param chatId Chat ID * @param chatId Chat ID
* @internal
*/ */
export async function markChatUnread(this: TelegramClient, chatId: InputPeerLike): Promise<void> { export async function markChatUnread(client: BaseTelegramClient, chatId: InputPeerLike): Promise<void> {
await this.call({ await client.call({
_: 'messages.markDialogUnread', _: 'messages.markDialogUnread',
peer: { peer: {
_: 'inputDialogPeer', _: 'inputDialogPeer',
peer: await this.resolvePeer(chatId), peer: await resolvePeer(client, chatId),
}, },
unread: true, unread: true,
}) })

View file

@ -1,22 +1,28 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { InputPeerLike } from '../../types' import { InputPeerLike } from '../../types'
import { isInputPeerChannel, isInputPeerUser, normalizeToInputChannel, normalizeToInputUser } from '../../utils' import { isInputPeerChannel, isInputPeerUser, normalizeToInputChannel, normalizeToInputUser } from '../../utils'
import { getAuthState } from '../auth/_state'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Reorder usernames * Reorder usernames
* *
* @param peerId Bot, channel or "me"/"self" * @param peerId Bot, channel or "me"/"self"
* @internal
*/ */
export async function reorderUsernames(this: TelegramClient, peerId: InputPeerLike, order: string[]): Promise<void> { export async function reorderUsernames(
const peer = await this.resolvePeer(peerId) client: BaseTelegramClient,
peerId: InputPeerLike,
order: string[],
): Promise<void> {
const peer = await resolvePeer(client, peerId)
if (isInputPeerUser(peer)) { if (isInputPeerUser(peer)) {
// either a bot or self // either a bot or self
if (peer._ === 'inputPeerSelf' || peer.userId === this._userId) { if (peer._ === 'inputPeerSelf' || peer.userId === getAuthState(client).userId) {
// self // self
await this.call({ await client.call({
_: 'account.reorderUsernames', _: 'account.reorderUsernames',
order, order,
}) })
@ -25,13 +31,13 @@ export async function reorderUsernames(this: TelegramClient, peerId: InputPeerLi
} }
// bot // bot
await this.call({ await client.call({
_: 'bots.reorderUsernames', _: 'bots.reorderUsernames',
bot: normalizeToInputUser(peer, peerId), bot: normalizeToInputUser(peer, peerId),
order, order,
}) })
} else if (isInputPeerChannel(peer)) { } else if (isInputPeerChannel(peer)) {
await this.call({ await client.call({
_: 'channels.reorderUsernames', _: 'channels.reorderUsernames',
channel: normalizeToInputChannel(peer, peerId), channel: normalizeToInputChannel(peer, peerId),
order, order,

View file

@ -1,17 +1,15 @@
import { tl } from '@mtcute/core' import { BaseTelegramClient, tl } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { InputPeerLike, MtInvalidPeerTypeError } from '../../types' import { InputPeerLike, MtInvalidPeerTypeError } from '../../types'
import { normalizeDate } from '../../utils/misc-utils' import { normalizeDate } from '../../utils/misc-utils'
import { isInputPeerChannel, normalizeToInputChannel } from '../../utils/peer-utils' import { isInputPeerChannel, normalizeToInputChannel } from '../../utils/peer-utils'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Restrict a user in a supergroup. * Restrict a user in a supergroup.
*
* @internal
*/ */
export async function restrictChatMember( export async function restrictChatMember(
this: TelegramClient, client: BaseTelegramClient,
params: { params: {
/** Chat ID */ /** Chat ID */
chatId: InputPeerLike chatId: InputPeerLike
@ -40,15 +38,15 @@ export async function restrictChatMember(
): Promise<void> { ): Promise<void> {
const { chatId, userId, restrictions, until = 0 } = params const { chatId, userId, restrictions, until = 0 } = params
const chat = await this.resolvePeer(chatId) const chat = await resolvePeer(client, chatId)
if (!isInputPeerChannel(chat)) { if (!isInputPeerChannel(chat)) {
throw new MtInvalidPeerTypeError(chatId, 'channel') throw new MtInvalidPeerTypeError(chatId, 'channel')
} }
const user = await this.resolvePeer(userId) const user = await resolvePeer(client, userId)
const res = await this.call({ const res = await client.call({
_: 'channels.editBanned', _: 'channels.editBanned',
channel: normalizeToInputChannel(chat), channel: normalizeToInputChannel(chat),
participant: user, participant: user,
@ -58,5 +56,5 @@ export async function restrictChatMember(
...restrictions, ...restrictions,
}, },
}) })
this._handleUpdate(res) client.network.handleUpdate(res)
} }

View file

@ -1,30 +1,29 @@
import { tl } from '@mtcute/core' import { BaseTelegramClient, tl } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { InputPeerLike } from '../../types' import { InputPeerLike } from '../../types'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Save or delete a draft message associated with some chat * Save or delete a draft message associated with some chat
* *
* @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 draft Draft message, or `null` to delete. * @param draft Draft message, or `null` to delete.
* @internal
*/ */
export async function saveDraft( export async function saveDraft(
this: TelegramClient, client: BaseTelegramClient,
chatId: InputPeerLike, chatId: InputPeerLike,
draft: null | Omit<tl.RawDraftMessage, '_' | 'date'>, draft: null | Omit<tl.RawDraftMessage, '_' | 'date'>,
): Promise<void> { ): Promise<void> {
const peer = await this.resolvePeer(chatId) const peer = await resolvePeer(client, chatId)
if (draft) { if (draft) {
await this.call({ await client.call({
_: 'messages.saveDraft', _: 'messages.saveDraft',
peer, peer,
...draft, ...draft,
}) })
} else { } else {
await this.call({ await client.call({
_: 'messages.saveDraft', _: 'messages.saveDraft',
peer, peer,
message: '', message: '',

View file

@ -1,8 +1,8 @@
import { tl } from '@mtcute/core' import { BaseTelegramClient, tl } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { Chat, InputPeerLike } from '../../types' import { Chat, InputPeerLike } from '../../types'
import { assertIsUpdatesGroup } from '../../utils/updates-utils' import { assertIsUpdatesGroup } from '../../utils/updates-utils'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Change default chat permissions for all members. * Change default chat permissions for all members.
@ -15,16 +15,15 @@ import { assertIsUpdatesGroup } from '../../utils/updates-utils'
* the restrictions, and not the permissions, i.e. * the restrictions, and not the permissions, i.e.
* passing `sendMessages=true` will disallow the users to send messages, * passing `sendMessages=true` will disallow the users to send messages,
* and passing `{}` (empty object) will lift any restrictions * and passing `{}` (empty object) will lift any restrictions
* @internal
*/ */
export async function setChatDefaultPermissions( export async function setChatDefaultPermissions(
this: TelegramClient, client: BaseTelegramClient,
chatId: InputPeerLike, chatId: InputPeerLike,
restrictions: Omit<tl.RawChatBannedRights, '_' | 'untilDate'>, restrictions: Omit<tl.RawChatBannedRights, '_' | 'untilDate'>,
): Promise<Chat> { ): Promise<Chat> {
const peer = await this.resolvePeer(chatId) const peer = await resolvePeer(client, chatId)
const res = await this.call({ const res = await client.call({
_: 'messages.editChatDefaultBannedRights', _: 'messages.editChatDefaultBannedRights',
peer, peer,
bannedRights: { bannedRights: {
@ -36,7 +35,7 @@ export async function setChatDefaultPermissions(
assertIsUpdatesGroup('messages.editChatDefaultBannedRights', res) assertIsUpdatesGroup('messages.editChatDefaultBannedRights', res)
this._handleUpdate(res) client.network.handleUpdate(res)
return new Chat(this, res.chats[0]) return new Chat(res.chats[0])
} }

View file

@ -1,5 +1,7 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { InputPeerLike } from '../../types' import { InputPeerLike } from '../../types'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Change chat description * Change chat description
@ -8,16 +10,15 @@ import { InputPeerLike } from '../../types'
* *
* @param chatId Chat ID or username * @param chatId Chat ID or username
* @param description New chat description, 0-255 characters * @param description New chat description, 0-255 characters
* @internal
*/ */
export async function setChatDescription( export async function setChatDescription(
this: TelegramClient, client: BaseTelegramClient,
chatId: InputPeerLike, chatId: InputPeerLike,
description: string, description: string,
): Promise<void> { ): Promise<void> {
const chat = await this.resolvePeer(chatId) const chat = await resolvePeer(client, chatId)
await this.call({ await client.call({
_: 'messages.editChatAbout', _: 'messages.editChatAbout',
peer: chat, peer: chat,
about: description, about: description,

View file

@ -1,19 +1,18 @@
import { MtArgumentError, tl } from '@mtcute/core' import { BaseTelegramClient, MtArgumentError, tl } from '@mtcute/core'
import { fileIdToInputPhoto, tdFileId } from '@mtcute/file-id' import { fileIdToInputPhoto, tdFileId } from '@mtcute/file-id'
import { TelegramClient } from '../../client'
import { InputFileLike, InputPeerLike, isUploadedFile, MtInvalidPeerTypeError } from '../../types' import { InputFileLike, InputPeerLike, isUploadedFile, MtInvalidPeerTypeError } from '../../types'
import { isInputPeerChannel, isInputPeerChat, normalizeToInputChannel } from '../../utils/peer-utils' import { isInputPeerChannel, isInputPeerChat, normalizeToInputChannel } from '../../utils/peer-utils'
import { uploadFile } from '../files/upload-file'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Set a new chat photo or video. * Set a new chat photo or video.
* *
* You must be an administrator and have the appropriate permissions. * You must be an administrator and have the appropriate permissions.
*
* @internal
*/ */
export async function setChatPhoto( export async function setChatPhoto(
this: TelegramClient, client: BaseTelegramClient,
params: { params: {
/** Chat ID or username */ /** Chat ID or username */
chatId: InputPeerLike chatId: InputPeerLike
@ -33,7 +32,7 @@ export async function setChatPhoto(
): Promise<void> { ): Promise<void> {
const { chatId, type, media, previewSec } = params const { chatId, type, media, previewSec } = params
const chat = await this.resolvePeer(chatId) const chat = await resolvePeer(client, chatId)
if (!(isInputPeerChannel(chat) || isInputPeerChat(chat))) { if (!(isInputPeerChannel(chat) || isInputPeerChat(chat))) {
throw new MtInvalidPeerTypeError(chatId, 'chat or channel') throw new MtInvalidPeerTypeError(chatId, 'chat or channel')
@ -48,7 +47,7 @@ export async function setChatPhoto(
throw new MtArgumentError("Chat photo can't be external") throw new MtArgumentError("Chat photo can't be external")
} }
if (typeof media === 'string' && media.match(/^file:/)) { if (typeof media === 'string' && media.match(/^file:/)) {
const uploaded = await this.uploadFile({ const uploaded = await uploadFile(client, {
file: media.substring(5), file: media.substring(5),
}) })
inputFile = uploaded.inputFile inputFile = uploaded.inputFile
@ -71,7 +70,7 @@ export async function setChatPhoto(
} else if (typeof media === 'object' && tl.isAnyInputFile(media)) { } else if (typeof media === 'object' && tl.isAnyInputFile(media)) {
inputFile = media inputFile = media
} else { } else {
const uploaded = await this.uploadFile({ const uploaded = await uploadFile(client, {
file: media, file: media,
}) })
inputFile = uploaded.inputFile inputFile = uploaded.inputFile
@ -88,17 +87,17 @@ export async function setChatPhoto(
let res let res
if (isInputPeerChat(chat)) { if (isInputPeerChat(chat)) {
res = await this.call({ res = await client.call({
_: 'messages.editChatPhoto', _: 'messages.editChatPhoto',
chatId: chat.chatId, chatId: chat.chatId,
photo, photo,
}) })
} else { } else {
res = await this.call({ res = await client.call({
_: 'channels.editPhoto', _: 'channels.editPhoto',
channel: normalizeToInputChannel(chat), channel: normalizeToInputChannel(chat),
photo, photo,
}) })
} }
this._handleUpdate(res) client.network.handleUpdate(res)
} }

View file

@ -1,6 +1,8 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { InputPeerLike, MtInvalidPeerTypeError } from '../../types' import { InputPeerLike, MtInvalidPeerTypeError } from '../../types'
import { isInputPeerChannel, isInputPeerChat, normalizeToInputChannel } from '../../utils/peer-utils' import { isInputPeerChannel, isInputPeerChat, normalizeToInputChannel } from '../../utils/peer-utils'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Change chat title * Change chat title
@ -9,25 +11,24 @@ import { isInputPeerChannel, isInputPeerChat, normalizeToInputChannel } from '..
* *
* @param chatId Chat ID or username * @param chatId Chat ID or username
* @param title New chat title, 1-255 characters * @param title New chat title, 1-255 characters
* @internal
*/ */
export async function setChatTitle(this: TelegramClient, chatId: InputPeerLike, title: string): Promise<void> { export async function setChatTitle(client: BaseTelegramClient, chatId: InputPeerLike, title: string): Promise<void> {
const chat = await this.resolvePeer(chatId) const chat = await resolvePeer(client, chatId)
let res let res
if (isInputPeerChat(chat)) { if (isInputPeerChat(chat)) {
res = await this.call({ res = await client.call({
_: 'messages.editChatTitle', _: 'messages.editChatTitle',
chatId: chat.chatId, chatId: chat.chatId,
title, title,
}) })
} else if (isInputPeerChannel(chat)) { } else if (isInputPeerChannel(chat)) {
res = await this.call({ res = await client.call({
_: 'channels.editTitle', _: 'channels.editTitle',
channel: normalizeToInputChannel(chat), channel: normalizeToInputChannel(chat),
title, title,
}) })
} else throw new MtInvalidPeerTypeError(chatId, 'chat or channel') } else throw new MtInvalidPeerTypeError(chatId, 'chat or channel')
this._handleUpdate(res) client.network.handleUpdate(res)
} }

View file

@ -1,17 +1,18 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { InputPeerLike } from '../../types' import { InputPeerLike } from '../../types'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Set maximum Time-To-Live of all newly sent messages in the specified chat * Set maximum Time-To-Live of all newly sent messages in the specified chat
* *
* @param chatId Chat ID * @param chatId Chat ID
* @param period New TTL period, in seconds (or 0 to disable) * @param period New TTL period, in seconds (or 0 to disable)
* @internal
*/ */
export async function setChatTtl(this: TelegramClient, chatId: InputPeerLike, period: number): Promise<void> { export async function setChatTtl(client: BaseTelegramClient, chatId: InputPeerLike, period: number): Promise<void> {
await this.call({ await client.call({
_: 'messages.setHistoryTTL', _: 'messages.setHistoryTTL',
peer: await this.resolvePeer(chatId), peer: await resolvePeer(client, chatId),
period, period,
}) })
} }

View file

@ -1,6 +1,8 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { InputPeerLike } from '../../types' import { InputPeerLike } from '../../types'
import { normalizeToInputChannel } from '../../utils/peer-utils' import { normalizeToInputChannel } from '../../utils/peer-utils'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Change supergroup/channel username * Change supergroup/channel username
@ -9,16 +11,15 @@ import { normalizeToInputChannel } from '../../utils/peer-utils'
* *
* @param chatId Chat ID or current username * @param chatId Chat ID or current username
* @param username New username, or `null` to remove * @param username New username, or `null` to remove
* @internal
*/ */
export async function setChatUsername( export async function setChatUsername(
this: TelegramClient, client: BaseTelegramClient,
chatId: InputPeerLike, chatId: InputPeerLike,
username: string | null, username: string | null,
): Promise<void> { ): Promise<void> {
await this.call({ await client.call({
_: 'channels.updateUsername', _: 'channels.updateUsername',
channel: normalizeToInputChannel(await this.resolvePeer(chatId), chatId), channel: normalizeToInputChannel(await resolvePeer(client, chatId), chatId),
username: username || '', username: username || '',
}) })
} }

View file

@ -1,6 +1,8 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { InputPeerLike } from '../../types' import { InputPeerLike } from '../../types'
import { normalizeToInputChannel } from '../../utils/peer-utils' import { normalizeToInputChannel } from '../../utils/peer-utils'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Set supergroup's slow mode interval. * Set supergroup's slow mode interval.
@ -10,13 +12,12 @@ import { normalizeToInputChannel } from '../../utils/peer-utils'
* Slow mode interval in seconds. * Slow mode interval in seconds.
* Users will be able to send a message only once per this interval. * Users will be able to send a message only once per this interval.
* Valid values are: `0 (off), 10, 30, 60 (1m), 300 (5m), 900 (15m) or 3600 (1h)` * Valid values are: `0 (off), 10, 30, 60 (1m), 300 (5m), 900 (15m) or 3600 (1h)`
* @internal
*/ */
export async function setSlowMode(this: TelegramClient, chatId: InputPeerLike, seconds = 0): Promise<void> { export async function setSlowMode(client: BaseTelegramClient, chatId: InputPeerLike, seconds = 0): Promise<void> {
const res = await this.call({ const res = await client.call({
_: 'channels.toggleSlowMode', _: 'channels.toggleSlowMode',
channel: normalizeToInputChannel(await this.resolvePeer(chatId), chatId), channel: normalizeToInputChannel(await resolvePeer(client, chatId), chatId),
seconds, seconds,
}) })
this._handleUpdate(res) client.network.handleUpdate(res)
} }

View file

@ -1,22 +1,23 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { InputPeerLike } from '../../types' import { InputPeerLike } from '../../types'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Set whether a chat has content protection (i.e. forwarding messages is disabled) * Set whether a chat has content protection (i.e. forwarding messages is disabled)
* *
* @param chatId Chat ID or username * @param chatId Chat ID or username
* @param enabled Whether content protection should be enabled * @param enabled Whether content protection should be enabled
* @internal
*/ */
export async function toggleContentProtection( export async function toggleContentProtection(
this: TelegramClient, client: BaseTelegramClient,
chatId: InputPeerLike, chatId: InputPeerLike,
enabled = false, enabled = false,
): Promise<void> { ): Promise<void> {
const res = await this.call({ const res = await client.call({
_: 'messages.toggleNoForwards', _: 'messages.toggleNoForwards',
peer: await this.resolvePeer(chatId), peer: await resolvePeer(client, chatId),
enabled, enabled,
}) })
this._handleUpdate(res) client.network.handleUpdate(res)
} }

View file

@ -1,17 +1,18 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { InputPeerLike } from '../../types' import { InputPeerLike } from '../../types'
import { isInputPeerChannel, isInputPeerUser, normalizeToInputChannel, normalizeToInputUser } from '../../utils' import { isInputPeerChannel, isInputPeerUser, normalizeToInputChannel, normalizeToInputUser } from '../../utils'
import { getAuthState } from '../auth/_state'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Toggle a collectible (Fragment) username * Toggle a collectible (Fragment) username
* *
* > **Note**: non-collectible usernames must still be changed * > **Note**: non-collectible usernames must still be changed
* > using {@link setUsername}/{@link setChatUsername} * > using {@link setUsername}/{@link setChatUsername}
*
* @internal
*/ */
export async function toggleFragmentUsername( export async function toggleFragmentUsername(
this: TelegramClient, client: BaseTelegramClient,
params: { params: {
/** Peer ID whose username to toggle */ /** Peer ID whose username to toggle */
peerId: InputPeerLike peerId: InputPeerLike
@ -29,14 +30,14 @@ export async function toggleFragmentUsername(
): Promise<void> { ): Promise<void> {
const { peerId, username, active } = params const { peerId, username, active } = params
const peer = await this.resolvePeer(peerId) const peer = await resolvePeer(client, peerId)
if (isInputPeerUser(peer)) { if (isInputPeerUser(peer)) {
// either a bot or self // either a bot or self
if (peer._ === 'inputPeerSelf' || peer.userId === this._userId) { if (peer._ === 'inputPeerSelf' || peer.userId === getAuthState(client).userId) {
// self // self
await this.call({ await client.call({
_: 'account.toggleUsername', _: 'account.toggleUsername',
username, username,
active, active,
@ -46,14 +47,14 @@ export async function toggleFragmentUsername(
} }
// bot // bot
await this.call({ await client.call({
_: 'bots.toggleUsername', _: 'bots.toggleUsername',
bot: normalizeToInputUser(peer, peerId), bot: normalizeToInputUser(peer, peerId),
username, username,
active, active,
}) })
} else if (isInputPeerChannel(peer)) { } else if (isInputPeerChannel(peer)) {
await this.call({ await client.call({
_: 'channels.toggleUsername', _: 'channels.toggleUsername',
channel: normalizeToInputChannel(peer, peerId), channel: normalizeToInputChannel(peer, peerId),
username, username,

View file

@ -1,6 +1,8 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { InputPeerLike } from '../../types' import { InputPeerLike } from '../../types'
import { normalizeToInputChannel } from '../../utils/peer-utils' import { normalizeToInputChannel } from '../../utils/peer-utils'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Set whether a channel/supergroup has join requests enabled. * Set whether a channel/supergroup has join requests enabled.
@ -10,13 +12,16 @@ import { normalizeToInputChannel } from '../../utils/peer-utils'
* *
* @param chatId Chat ID or username * @param chatId Chat ID or username
* @param enabled Whether join requests should be enabled * @param enabled Whether join requests should be enabled
* @internal
*/ */
export async function toggleJoinRequests(this: TelegramClient, chatId: InputPeerLike, enabled = false): Promise<void> { export async function toggleJoinRequests(
const res = await this.call({ client: BaseTelegramClient,
chatId: InputPeerLike,
enabled = false,
): Promise<void> {
const res = await client.call({
_: 'channels.toggleJoinRequest', _: 'channels.toggleJoinRequest',
channel: normalizeToInputChannel(await this.resolvePeer(chatId), chatId), channel: normalizeToInputChannel(await resolvePeer(client, chatId), chatId),
enabled, enabled,
}) })
this._handleUpdate(res) client.network.handleUpdate(res)
} }

View file

@ -1,6 +1,8 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { InputPeerLike } from '../../types' import { InputPeerLike } from '../../types'
import { normalizeToInputChannel } from '../../utils/peer-utils' import { normalizeToInputChannel } from '../../utils/peer-utils'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Set whether a channel/supergroup has join-to-send setting enabled. * Set whether a channel/supergroup has join-to-send setting enabled.
@ -10,13 +12,16 @@ import { normalizeToInputChannel } from '../../utils/peer-utils'
* *
* @param chatId Chat ID or username * @param chatId Chat ID or username
* @param enabled Whether join-to-send setting should be enabled * @param enabled Whether join-to-send setting should be enabled
* @internal
*/ */
export async function toggleJoinToSend(this: TelegramClient, chatId: InputPeerLike, enabled = false): Promise<void> { export async function toggleJoinToSend(
const res = await this.call({ client: BaseTelegramClient,
chatId: InputPeerLike,
enabled = false,
): Promise<void> {
const res = await client.call({
_: 'channels.toggleJoinToSend', _: 'channels.toggleJoinToSend',
channel: normalizeToInputChannel(await this.resolvePeer(chatId), chatId), channel: normalizeToInputChannel(await resolvePeer(client, chatId), chatId),
enabled, enabled,
}) })
this._handleUpdate(res) client.network.handleUpdate(res)
} }

View file

@ -1,15 +1,14 @@
import { MaybeArray, tl } from '@mtcute/core' import { BaseTelegramClient, MaybeArray, tl } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { InputPeerLike } from '../../types' import { InputPeerLike } from '../../types'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Unarchive one or more chats * Unarchive one or more chats
* *
* @param chats Chat ID(s), username(s), phone number(s), `"me"` or `"self"` * @param chats Chat ID(s), username(s), phone number(s), `"me"` or `"self"`
* @internal
*/ */
export async function unarchiveChats(this: TelegramClient, chats: MaybeArray<InputPeerLike>): Promise<void> { export async function unarchiveChats(client: BaseTelegramClient, chats: MaybeArray<InputPeerLike>): Promise<void> {
if (!Array.isArray(chats)) chats = [chats] if (!Array.isArray(chats)) chats = [chats]
const folderPeers: tl.TypeInputFolderPeer[] = [] const folderPeers: tl.TypeInputFolderPeer[] = []
@ -17,14 +16,14 @@ export async function unarchiveChats(this: TelegramClient, chats: MaybeArray<Inp
for (const chat of chats) { for (const chat of chats) {
folderPeers.push({ folderPeers.push({
_: 'inputFolderPeer', _: 'inputFolderPeer',
peer: await this.resolvePeer(chat), peer: await resolvePeer(client, chat),
folderId: 0, folderId: 0,
}) })
} }
const res = await this.call({ const res = await client.call({
_: 'folders.editPeerFolders', _: 'folders.editPeerFolders',
folderPeers, folderPeers,
}) })
this._handleUpdate(res) client.network.handleUpdate(res)
} }

View file

@ -1,6 +1,8 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { InputPeerLike, MtInvalidPeerTypeError } from '../../types' import { InputPeerLike, MtInvalidPeerTypeError } from '../../types'
import { isInputPeerChannel, isInputPeerChat, normalizeToInputChannel } from '../../utils/peer-utils' import { isInputPeerChannel, isInputPeerChat, normalizeToInputChannel } from '../../utils/peer-utils'
import { resolvePeer } from '../users/resolve-peer'
// @alias=unrestrictChatMember // @alias=unrestrictChatMember
/** /**
@ -10,11 +12,9 @@ import { isInputPeerChannel, isInputPeerChat, normalizeToInputChannel } from '..
* just allows the user to join the chat again, if they want. * just allows the user to join the chat again, if they want.
* *
* This method acts as a no-op in case a legacy group is passed. * This method acts as a no-op in case a legacy group is passed.
*
* @internal
*/ */
export async function unbanChatMember( export async function unbanChatMember(
this: TelegramClient, client: BaseTelegramClient,
params: { params: {
/** Chat ID */ /** Chat ID */
chatId: InputPeerLike chatId: InputPeerLike
@ -24,11 +24,11 @@ export async function unbanChatMember(
}, },
): Promise<void> { ): Promise<void> {
const { chatId, participantId } = params const { chatId, participantId } = params
const chat = await this.resolvePeer(chatId) const chat = await resolvePeer(client, chatId)
const peer = await this.resolvePeer(participantId) const peer = await resolvePeer(client, participantId)
if (isInputPeerChannel(chat)) { if (isInputPeerChannel(chat)) {
const res = await this.call({ const res = await client.call({
_: 'channels.editBanned', _: 'channels.editBanned',
channel: normalizeToInputChannel(chat), channel: normalizeToInputChannel(chat),
participant: peer, participant: peer,
@ -38,7 +38,7 @@ export async function unbanChatMember(
}, },
}) })
this._handleUpdate(res) client.network.handleUpdate(res)
} else if (isInputPeerChat(chat)) { } else if (isInputPeerChat(chat)) {
// no-op // // no-op //
} else throw new MtInvalidPeerTypeError(chatId, 'chat or channel') } else throw new MtInvalidPeerTypeError(chatId, 'chat or channel')

View file

@ -1,15 +1,15 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { InputPeerLike, User } from '../../types' import { InputPeerLike, User } from '../../types'
import { normalizeToInputUser } from '../../utils/peer-utils' import { normalizeToInputUser } from '../../utils/peer-utils'
import { assertIsUpdatesGroup } from '../../utils/updates-utils' import { assertIsUpdatesGroup } from '../../utils/updates-utils'
import { resolvePeer } from '../users/resolve-peer'
/** /**
* Add an existing Telegram user as a contact * Add an existing Telegram user as a contact
*
* @internal
*/ */
export async function addContact( export async function addContact(
this: TelegramClient, client: BaseTelegramClient,
params: { params: {
/** User ID, username or phone number */ /** User ID, username or phone number */
userId: InputPeerLike userId: InputPeerLike
@ -37,9 +37,9 @@ export async function addContact(
}, },
): Promise<User> { ): Promise<User> {
const { userId, firstName, lastName = '', phone = '', sharePhone = false } = params const { userId, firstName, lastName = '', phone = '', sharePhone = false } = params
const peer = normalizeToInputUser(await this.resolvePeer(userId), userId) const peer = normalizeToInputUser(await resolvePeer(client, userId), userId)
const res = await this.call({ const res = await client.call({
_: 'contacts.addContact', _: 'contacts.addContact',
id: peer, id: peer,
firstName, firstName,
@ -50,7 +50,7 @@ export async function addContact(
assertIsUpdatesGroup('contacts.addContact', res) assertIsUpdatesGroup('contacts.addContact', res)
this._handleUpdate(res) client.network.handleUpdate(res)
return new User(this, res.users[0]) return new User(res.users[0])
} }

View file

@ -1,9 +1,9 @@
import { MaybeArray } from '@mtcute/core' import { BaseTelegramClient, MaybeArray } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { InputPeerLike, MtInvalidPeerTypeError, User } from '../../types' import { InputPeerLike, MtInvalidPeerTypeError, User } from '../../types'
import { normalizeToInputUser } from '../../utils/peer-utils' import { normalizeToInputUser } from '../../utils/peer-utils'
import { assertIsUpdatesGroup } from '../../utils/updates-utils' import { assertIsUpdatesGroup } from '../../utils/updates-utils'
import { resolvePeerMany } from '../users/resolve-peer-many'
/** /**
* Delete a single contact from your Telegram contacts list * Delete a single contact from your Telegram contacts list
@ -12,9 +12,8 @@ import { assertIsUpdatesGroup } from '../../utils/updates-utils'
* that user was not in your contacts list * that user was not in your contacts list
* *
* @param userId User ID, username or phone number * @param userId User ID, username or phone number
* @internal
*/ */
export async function deleteContacts(this: TelegramClient, userId: InputPeerLike): Promise<User | null> export async function deleteContacts(client: BaseTelegramClient, userId: InputPeerLike): Promise<User | null>
/** /**
* Delete one or more contacts from your Telegram contacts list * Delete one or more contacts from your Telegram contacts list
@ -23,25 +22,24 @@ export async function deleteContacts(this: TelegramClient, userId: InputPeerLike
* profiles of users that were not in your contacts list * profiles of users that were not in your contacts list
* *
* @param userIds User IDs, usernames or phone numbers * @param userIds User IDs, usernames or phone numbers
* @internal
*/ */
export async function deleteContacts(this: TelegramClient, userIds: InputPeerLike[]): Promise<User[]> export async function deleteContacts(client: BaseTelegramClient, userIds: InputPeerLike[]): Promise<User[]>
/** @internal */ /** @internal */
export async function deleteContacts( export async function deleteContacts(
this: TelegramClient, client: BaseTelegramClient,
userIds: MaybeArray<InputPeerLike>, userIds: MaybeArray<InputPeerLike>,
): Promise<MaybeArray<User> | null> { ): Promise<MaybeArray<User> | null> {
const single = !Array.isArray(userIds) const single = !Array.isArray(userIds)
if (single) userIds = [userIds as InputPeerLike] if (single) userIds = [userIds as InputPeerLike]
const inputPeers = await this.resolvePeerMany(userIds as InputPeerLike[], normalizeToInputUser) const inputPeers = await resolvePeerMany(client, userIds as InputPeerLike[], normalizeToInputUser)
if (single && !inputPeers.length) { if (single && !inputPeers.length) {
throw new MtInvalidPeerTypeError((userIds as InputPeerLike[])[0], 'user') throw new MtInvalidPeerTypeError((userIds as InputPeerLike[])[0], 'user')
} }
const res = await this.call({ const res = await client.call({
_: 'contacts.deleteContacts', _: 'contacts.deleteContacts',
id: inputPeers, id: inputPeers,
}) })
@ -50,9 +48,9 @@ export async function deleteContacts(
if (single && !res.updates.length) return null if (single && !res.updates.length) return null
this._handleUpdate(res) client.network.handleUpdate(res)
const users = res.users.map((user) => new User(this, user)) const users = res.users.map((user) => new User(user))
return single ? users[0] : users return single ? users[0] : users
} }

View file

@ -1,19 +1,17 @@
import { Long } from '@mtcute/core' import { BaseTelegramClient, Long } from '@mtcute/core'
import { assertTypeIs } from '@mtcute/core/utils' import { assertTypeIs } from '@mtcute/core/utils'
import { TelegramClient } from '../../client'
import { User } from '../../types' import { User } from '../../types'
/** /**
* Get list of contacts from your Telegram contacts list. * Get list of contacts from your Telegram contacts list.
* @internal
*/ */
export async function getContacts(this: TelegramClient): Promise<User[]> { export async function getContacts(client: BaseTelegramClient): Promise<User[]> {
const res = await this.call({ const res = await client.call({
_: 'contacts.getContacts', _: 'contacts.getContacts',
hash: Long.ZERO, hash: Long.ZERO,
}) })
assertTypeIs('getContacts', res, 'contacts.contacts') assertTypeIs('getContacts', res, 'contacts.contacts')
return res.users.map((user) => new User(this, user)) return res.users.map((user) => new User(user))
} }

View file

@ -1,15 +1,12 @@
import { Long, PartialOnly, tl } from '@mtcute/core' import { BaseTelegramClient, Long, PartialOnly, tl } from '@mtcute/core'
import { TelegramClient } from '../../client'
/** /**
* Import contacts to your Telegram contacts list. * Import contacts to your Telegram contacts list.
* *
* @param contacts List of contacts * @param contacts List of contacts
* @internal
*/ */
export async function importContacts( export async function importContacts(
this: TelegramClient, client: BaseTelegramClient,
contacts: PartialOnly<Omit<tl.RawInputPhoneContact, '_'>, 'clientId'>[], contacts: PartialOnly<Omit<tl.RawInputPhoneContact, '_'>, 'clientId'>[],
): Promise<tl.contacts.RawImportedContacts> { ): Promise<tl.contacts.RawImportedContacts> {
let seq = Long.ZERO let seq = Long.ZERO
@ -20,7 +17,7 @@ export async function importContacts(
...input, ...input,
})) }))
return await this.call({ return await client.call({
_: 'contacts.importContacts', _: 'contacts.importContacts',
contacts: contactsNorm, contacts: contactsNorm,
}) })

View file

@ -1,31 +0,0 @@
/* eslint-disable @typescript-eslint/no-unused-vars, dot-notation */
import { getMarkedPeerId } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { Conversation, Message } from '../../types'
// @extension
interface ConversationsState {
_pendingConversations: Map<number, Conversation[]>
_hasConversations: boolean
}
// @initialize
function _initializeConversation(this: TelegramClient) {
this._pendingConversations = new Map()
this._hasConversations = false
}
/** @internal */
export function _pushConversationMessage(this: TelegramClient, msg: Message, incoming = false): void {
// shortcut
if (!this._hasConversations) return
const chatId = getMarkedPeerId(msg.raw.peerId)
const msgId = msg.raw.id
this._pendingConversations.get(chatId)?.forEach((conv) => {
conv['_lastMessage'] = msgId
if (incoming) conv['_lastReceivedMessage'] = msgId
})
}

View file

@ -1,6 +1,6 @@
import { PartialExcept, tl } from '@mtcute/core' import { BaseTelegramClient, PartialExcept, tl } from '@mtcute/core'
import { TelegramClient } from '../../client' import { getFolders } from './get-folders'
/** /**
* Create a folder from given parameters * Create a folder from given parameters
@ -10,16 +10,15 @@ import { TelegramClient } from '../../client'
* *
* @param folder Parameters for the folder * @param folder Parameters for the folder
* @returns Newly created folder * @returns Newly created folder
* @internal
*/ */
export async function createFolder( export async function createFolder(
this: TelegramClient, client: BaseTelegramClient,
folder: PartialExcept<tl.RawDialogFilter, 'title'>, folder: PartialExcept<tl.RawDialogFilter, 'title'>,
): Promise<tl.RawDialogFilter> { ): Promise<tl.RawDialogFilter> {
let id = folder.id let id = folder.id
if (!id) { if (!id) {
const old = await this.getFolders() const old = await getFolders(client)
// determine next id by finding max id // determine next id by finding max id
// thanks durov for awesome api // thanks durov for awesome api
@ -39,7 +38,7 @@ export async function createFolder(
id, id,
} }
await this.call({ await client.call({
_: 'messages.updateDialogFilter', _: 'messages.updateDialogFilter',
id, id,
filter, filter,

View file

@ -1,15 +1,12 @@
import { tl } from '@mtcute/core' import { BaseTelegramClient, tl } from '@mtcute/core'
import { TelegramClient } from '../../client'
/** /**
* Delete a folder by its ID * Delete a folder by its ID
* *
* @param id Folder ID or folder itself * @param id Folder ID or folder itself
* @internal
*/ */
export async function deleteFolder(this: TelegramClient, id: number | tl.RawDialogFilter): Promise<void> { export async function deleteFolder(client: BaseTelegramClient, id: number | tl.RawDialogFilter): Promise<void> {
await this.call({ await client.call({
_: 'messages.updateDialogFilter', _: 'messages.updateDialogFilter',
id: typeof id === 'number' ? id : id.id, id: typeof id === 'number' ? id : id.id,
}) })

View file

@ -1,15 +1,14 @@
import { MtArgumentError, tl } from '@mtcute/core' import { BaseTelegramClient, MtArgumentError, tl } from '@mtcute/core'
import { TelegramClient } from '../../client' import { getFolders } from './get-folders'
/** /**
* Edit a folder with given modification * Edit a folder with given modification
* *
* @returns Modified folder * @returns Modified folder
* @internal
*/ */
export async function editFolder( export async function editFolder(
this: TelegramClient, client: BaseTelegramClient,
params: { params: {
/** /**
* Folder, folder ID or name. * Folder, folder ID or name.
@ -30,7 +29,7 @@ export async function editFolder(
throw new MtArgumentError('Cannot modify default folder') throw new MtArgumentError('Cannot modify default folder')
} }
if (typeof folder === 'number' || typeof folder === 'string') { if (typeof folder === 'number' || typeof folder === 'string') {
const old = await this.getFolders() const old = await getFolders(client)
const found = old.find((it) => it._ === 'dialogFilter' && (it.id === folder || it.title === folder)) const found = old.find((it) => it._ === 'dialogFilter' && (it.id === folder || it.title === folder))
if (!found) { if (!found) {
@ -45,7 +44,7 @@ export async function editFolder(
...modification, ...modification,
} }
await this.call({ await client.call({
_: 'messages.updateDialogFilter', _: 'messages.updateDialogFilter',
id: folder.id, id: folder.id,
filter, filter,

View file

@ -1,6 +1,6 @@
import { MtArgumentError, tl } from '@mtcute/core' import { BaseTelegramClient, MtArgumentError, tl } from '@mtcute/core'
import { TelegramClient } from '../../client' import { getFolders } from './get-folders'
/** /**
* Find a folder by its parameter. * Find a folder by its parameter.
@ -10,10 +10,9 @@ import { TelegramClient } from '../../client'
* > to multiple folders. * > to multiple folders.
* *
* @param params Search parameters. At least one must be set. * @param params Search parameters. At least one must be set.
* @internal
*/ */
export async function findFolder( export async function findFolder(
this: TelegramClient, client: BaseTelegramClient,
params: { params: {
/** Folder title */ /** Folder title */
title?: string title?: string
@ -27,7 +26,7 @@ export async function findFolder(
throw new MtArgumentError('One of search parameters must be passed') throw new MtArgumentError('One of search parameters must be passed')
} }
const folders = await this.getFolders() const folders = await getFolders(client)
return ( return (
(folders.find((it) => { (folders.find((it) => {

View file

@ -1,25 +1,23 @@
import { MtArgumentError, tl } from '@mtcute/core' import { BaseTelegramClient, MtArgumentError, tl } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { InputDialogFolder } from '../../types' import { InputDialogFolder } from '../../types'
/** /**
* Get list of folders. * Get list of folders.
* @internal
*/ */
export async function getFolders(this: TelegramClient): Promise<tl.TypeDialogFilter[]> { export async function getFolders(client: BaseTelegramClient): Promise<tl.TypeDialogFilter[]> {
return this.call({ return client.call({
_: 'messages.getDialogFilters', _: 'messages.getDialogFilters',
}) })
} }
/** @internal */ /** @internal */
export async function _normalizeInputFolder( export async function _normalizeInputFolder(
this: TelegramClient, client: BaseTelegramClient,
folder: InputDialogFolder, folder: InputDialogFolder,
): Promise<tl.TypeDialogFilter> { ): Promise<tl.TypeDialogFilter> {
if (typeof folder === 'string' || typeof folder === 'number') { if (typeof folder === 'string' || typeof folder === 'number') {
const folders = await this.getFolders() const folders = await getFolders(client)
const found = folders.find((it) => { const found = folders.find((it) => {
if (it._ === 'dialogFilterDefault') { if (it._ === 'dialogFilterDefault') {
return folder === 0 return folder === 0

View file

@ -1,36 +1,33 @@
import { MaybeArray } from '@mtcute/core' import { BaseTelegramClient, MaybeArray } from '@mtcute/core'
import { TelegramClient } from '../../client' import { Dialog } from '../../types/messages/dialog'
import { Dialog, InputPeerLike } from '../../types' import { InputPeerLike } from '../../types/peers'
import { resolvePeerMany } from '../users/resolve-peer-many'
/** /**
* Get dialogs with certain peers. * Get dialogs with certain peers.
* *
* @param peers Peers for which to fetch dialogs. * @param peers Peers for which to fetch dialogs.
* @internal
*/ */
export async function getPeerDialogs(this: TelegramClient, peers: InputPeerLike): Promise<Dialog> export async function getPeerDialogs(client: BaseTelegramClient, peers: InputPeerLike): Promise<Dialog>
/** /**
* Get dialogs with certain peers. * Get dialogs with certain peers.
* *
* @param peers Peers for which to fetch dialogs. * @param peers Peers for which to fetch dialogs.
* @internal
*/ */
export async function getPeerDialogs(this: TelegramClient, peers: InputPeerLike[]): Promise<Dialog[]> export async function getPeerDialogs(client: BaseTelegramClient, peers: InputPeerLike[]): Promise<Dialog[]>
/** /** @internal */
* @internal
*/
export async function getPeerDialogs( export async function getPeerDialogs(
this: TelegramClient, client: BaseTelegramClient,
peers: MaybeArray<InputPeerLike>, peers: MaybeArray<InputPeerLike>,
): Promise<MaybeArray<Dialog>> { ): Promise<MaybeArray<Dialog>> {
const isSingle = !Array.isArray(peers) const isSingle = !Array.isArray(peers)
if (isSingle) peers = [peers as InputPeerLike] if (isSingle) peers = [peers as InputPeerLike]
const res = await this.call({ const res = await client.call({
_: 'messages.getPeerDialogs', _: 'messages.getPeerDialogs',
peers: await this.resolvePeerMany(peers as InputPeerLike[]).then((peers) => peers: await resolvePeerMany(client, peers as InputPeerLike[]).then((peers) =>
peers.map((it) => ({ peers.map((it) => ({
_: 'inputDialogPeer', _: 'inputDialogPeer',
peer: it, peer: it,
@ -38,7 +35,7 @@ export async function getPeerDialogs(
), ),
}) })
const dialogs = Dialog.parseTlDialogs(this, res) const dialogs = Dialog.parseTlDialogs(res)
return isSingle ? dialogs[0] : dialogs return isSingle ? dialogs[0] : dialogs
} }

View file

@ -1,8 +1,8 @@
import { Long, MtUnsupportedError, tl } from '@mtcute/core' import { BaseTelegramClient, Long, MtUnsupportedError, tl } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { Dialog, InputDialogFolder } from '../../types' import { Dialog, InputDialogFolder } from '../../types'
import { normalizeDate } from '../../utils/misc-utils' import { normalizeDate } from '../../utils/misc-utils'
import { _normalizeInputFolder } from './get-folders'
/** /**
* Iterate over dialogs. * Iterate over dialogs.
@ -13,10 +13,9 @@ import { normalizeDate } from '../../utils/misc-utils'
* is not considered when sorting. * is not considered when sorting.
* *
* @param params Fetch parameters * @param params Fetch parameters
* @internal
*/ */
export async function* iterDialogs( export async function* iterDialogs(
this: TelegramClient, client: BaseTelegramClient,
params?: { params?: {
/** /**
* Offset message date used as an anchor for pagination. * Offset message date used as an anchor for pagination.
@ -127,7 +126,7 @@ export async function* iterDialogs(
let localFilters_: tl.TypeDialogFilter | undefined let localFilters_: tl.TypeDialogFilter | undefined
if (folder) { if (folder) {
localFilters_ = await this._normalizeInputFolder(folder) localFilters_ = await _normalizeInputFolder(client, folder)
} }
if (filter) { if (filter) {
@ -167,7 +166,7 @@ export async function* iterDialogs(
if (!localFilters || !localFilters.pinnedPeers.length) { if (!localFilters || !localFilters.pinnedPeers.length) {
return null return null
} }
const res = await this.call({ const res = await client.call({
_: 'messages.getPeerDialogs', _: 'messages.getPeerDialogs',
peers: localFilters.pinnedPeers.map((peer) => ({ peers: localFilters.pinnedPeers.map((peer) => ({
_: 'inputDialogPeer' as const, _: 'inputDialogPeer' as const,
@ -186,12 +185,12 @@ export async function* iterDialogs(
if (localFilters) { if (localFilters) {
res = await fetchPinnedDialogsFromFolder() res = await fetchPinnedDialogsFromFolder()
} else { } else {
res = await this.call({ res = await client.call({
_: 'messages.getPinnedDialogs', _: 'messages.getPinnedDialogs',
folderId: archived === 'exclude' ? 0 : 1, folderId: archived === 'exclude' ? 0 : 1,
}) })
} }
if (res) yield* Dialog.parseTlDialogs(this, res, limit) if (res) yield* Dialog.parseTlDialogs(res, limit)
return return
} }
@ -208,7 +207,7 @@ export async function* iterDialogs(
const res = await fetchPinnedDialogsFromFolder() const res = await fetchPinnedDialogsFromFolder()
if (res) { if (res) {
const dialogs = Dialog.parseTlDialogs(this, res, limit) const dialogs = Dialog.parseTlDialogs(res, limit)
for (const d of dialogs) { for (const d of dialogs) {
yield d yield d
@ -234,8 +233,7 @@ export async function* iterDialogs(
for (;;) { for (;;) {
const dialogs = Dialog.parseTlDialogs( const dialogs = Dialog.parseTlDialogs(
this, await client.call({
await this.call({
_: 'messages.getDialogs', _: 'messages.getDialogs',
excludePinned: params.pinned === 'exclude', excludePinned: params.pinned === 'exclude',
folderId, folderId,

View file

@ -1,13 +1,12 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
/** /**
* Reorder folders * Reorder folders
* *
* @param order New order of folders (folder IDs, where default = 0) * @param order New order of folders (folder IDs, where default = 0)
* @internal
*/ */
export async function setFoldersOrder(this: TelegramClient, order: number[]): Promise<void> { export async function setFoldersOrder(client: BaseTelegramClient, order: number[]): Promise<void> {
await this.call({ await client.call({
_: 'messages.updateDialogFiltersOrder', _: 'messages.updateDialogFiltersOrder',
order, order,
}) })

View file

@ -1,5 +1,7 @@
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { FileDownloadParameters, FileLocation } from '../../types' import { FileDownloadParameters, FileLocation } from '../../types'
import { downloadAsIterable } from './download-iterable'
/** /**
* Download a file and return its contents as a Buffer. * Download a file and return its contents as a Buffer.
@ -8,16 +10,15 @@ import { FileDownloadParameters, FileLocation } from '../../types'
* > 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
* @internal
*/ */
export async function downloadAsBuffer(this: TelegramClient, params: FileDownloadParameters): Promise<Buffer> { export async function downloadAsBuffer(client: BaseTelegramClient, params: FileDownloadParameters): Promise<Buffer> {
if (params.location instanceof FileLocation && Buffer.isBuffer(params.location.location)) { if (params.location instanceof FileLocation && Buffer.isBuffer(params.location.location)) {
return params.location.location return params.location.location
} }
const chunks = [] const chunks = []
for await (const chunk of this.downloadAsIterable(params)) { for await (const chunk of downloadAsIterable(client, params)) {
chunks.push(chunk) chunks.push(chunk)
} }

View file

@ -1,7 +1,7 @@
import { MtUnsupportedError } from '@mtcute/core' import { BaseTelegramClient, MtUnsupportedError } from '@mtcute/core'
import { TelegramClient } from '../../client'
import { FileDownloadParameters, FileLocation } from '../../types' import { FileDownloadParameters, FileLocation } from '../../types'
import { downloadAsStream } from './download-stream'
let fs: typeof import('fs') | null = null let fs: typeof import('fs') | null = null
try { try {
@ -14,9 +14,12 @@ try {
* *
* @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
* @internal
*/ */
export function downloadToFile(this: TelegramClient, filename: string, params: FileDownloadParameters): Promise<void> { export function downloadToFile(
client: BaseTelegramClient,
filename: string,
params: FileDownloadParameters,
): Promise<void> {
if (!fs) { if (!fs) {
throw new MtUnsupportedError('Downloading to file is only supported in NodeJS') throw new MtUnsupportedError('Downloading to file is only supported in NodeJS')
} }
@ -34,11 +37,11 @@ export function downloadToFile(this: TelegramClient, filename: string, params: F
} }
const output = fs.createWriteStream(filename) const output = fs.createWriteStream(filename)
const stream = this.downloadAsStream(params) const stream = downloadAsStream(client, params)
if (params.abortSignal) { if (params.abortSignal) {
params.abortSignal.addEventListener('abort', () => { params.abortSignal.addEventListener('abort', () => {
this.log.debug('aborting file download %s - cleaning up', filename) client.log.debug('aborting file download %s - cleaning up', filename)
output.destroy() output.destroy()
stream.destroy() stream.destroy()
fs!.rmSync(filename) fs!.rmSync(filename)

View file

@ -1,8 +1,7 @@
import { ConnectionKind, MtArgumentError, MtUnsupportedError, tl } from '@mtcute/core' import { BaseTelegramClient, ConnectionKind, MtArgumentError, MtUnsupportedError, tl } from '@mtcute/core'
import { ConditionVariable } from '@mtcute/core/utils' import { ConditionVariable } from '@mtcute/core/utils'
import { fileIdToInputFileLocation, fileIdToInputWebFileLocation, parseFileId } from '@mtcute/file-id' import { fileIdToInputFileLocation, fileIdToInputWebFileLocation, parseFileId } from '@mtcute/file-id'
import { TelegramClient } from '../../client'
import { FileDownloadParameters, FileLocation } from '../../types' import { FileDownloadParameters, FileLocation } from '../../types'
import { determinePartSize } from '../../utils/file-utils' import { determinePartSize } from '../../utils/file-utils'
@ -18,10 +17,9 @@ const REQUESTS_PER_CONNECTION = 3 // some arbitrary magic value that seems to wo
* consecutive. * consecutive.
* *
* @param params Download parameters * @param params Download parameters
* @internal
*/ */
export async function* downloadAsIterable( export async function* downloadAsIterable(
this: TelegramClient, client: BaseTelegramClient,
params: FileDownloadParameters, params: FileDownloadParameters,
): AsyncIterableIterator<Buffer> { ): AsyncIterableIterator<Buffer> {
const offset = params.offset ?? 0 const offset = params.offset ?? 0
@ -63,7 +61,7 @@ export async function* downloadAsIterable(
const isWeb = tl.isAnyInputWebFileLocation(location) const isWeb = tl.isAnyInputWebFileLocation(location)
// we will receive a FileMigrateError in case this is invalid // we will receive a FileMigrateError in case this is invalid
if (!dcId) dcId = this._defaultDcs.main.id if (!dcId) dcId = client.network.getPrimaryDcId()
const partSizeKb = params.partSize ?? (fileSize ? determinePartSize(fileSize) : 64) const partSizeKb = params.partSize ?? (fileSize ? determinePartSize(fileSize) : 64)
@ -87,13 +85,13 @@ export async function* downloadAsIterable(
let connectionKind: ConnectionKind let connectionKind: ConnectionKind
if (isSmall) { if (isSmall) {
connectionKind = dcId === this.network.getPrimaryDcId() ? 'main' : 'downloadSmall' connectionKind = dcId === client.network.getPrimaryDcId() ? 'main' : 'downloadSmall'
} else { } else {
connectionKind = 'download' connectionKind = 'download'
} }
const poolSize = this.network.getPoolSize(connectionKind, dcId) const poolSize = client.network.getPoolSize(connectionKind, dcId)
this.log.debug( client.log.debug(
'Downloading file of size %d from dc %d using %s connection pool (pool size: %d)', 'Downloading file of size %d from dc %d using %s connection pool (pool size: %d)',
limitBytes, limitBytes,
dcId, dcId,
@ -105,7 +103,7 @@ export async function* downloadAsIterable(
let result: tl.RpcCallReturn['upload.getFile'] | tl.RpcCallReturn['upload.getWebFile'] let result: tl.RpcCallReturn['upload.getFile'] | tl.RpcCallReturn['upload.getWebFile']
try { try {
result = await this.call( result = await client.call(
{ {
_: isWeb ? 'upload.getWebFile' : 'upload.getFile', _: isWeb ? 'upload.getWebFile' : 'upload.getFile',
// eslint-disable-next-line // eslint-disable-next-line
@ -155,12 +153,12 @@ export async function* downloadAsIterable(
let error: unknown = undefined let error: unknown = undefined
void Promise.all(Array.from({ length: Math.min(poolSize * REQUESTS_PER_CONNECTION, numChunks) }, downloadChunk)) void Promise.all(Array.from({ length: Math.min(poolSize * REQUESTS_PER_CONNECTION, numChunks) }, downloadChunk))
.catch((e) => { .catch((e) => {
this.log.debug('download workers errored: %s', e.message) client.log.debug('download workers errored: %s', e.message)
error = e error = e
nextChunkCv.notify() nextChunkCv.notify()
}) })
.then(() => { .then(() => {
this.log.debug('download workers finished') client.log.debug('download workers finished')
}) })
let position = offset let position = offset

View file

@ -1,17 +1,18 @@
import { Readable } from 'stream' import { Readable } from 'stream'
import { TelegramClient } from '../../client' import { BaseTelegramClient } from '@mtcute/core'
import { FileDownloadParameters, FileLocation } from '../../types' import { FileDownloadParameters, FileLocation } from '../../types'
import { bufferToStream } from '../../utils/stream-utils' import { bufferToStream } from '../../utils/stream-utils'
import { downloadAsIterable } from './download-iterable'
/** /**
* Download a file and return it as a Node readable stream, * Download a file and return it as a Node readable stream,
* streaming file contents. * streaming file contents.
* *
* @param params File download parameters * @param params File download parameters
* @internal
*/ */
export function downloadAsStream(this: TelegramClient, params: FileDownloadParameters): Readable { export function downloadAsStream(client: BaseTelegramClient, params: FileDownloadParameters): Readable {
if (params.location instanceof FileLocation && Buffer.isBuffer(params.location.location)) { if (params.location instanceof FileLocation && Buffer.isBuffer(params.location.location)) {
return bufferToStream(params.location.location) return bufferToStream(params.location.location)
} }
@ -23,7 +24,7 @@ export function downloadAsStream(this: TelegramClient, params: FileDownloadParam
// eslint-disable-next-line @typescript-eslint/no-misused-promises // eslint-disable-next-line @typescript-eslint/no-misused-promises
setTimeout(async () => { setTimeout(async () => {
try { try {
for await (const chunk of this.downloadAsIterable(params)) { for await (const chunk of downloadAsIterable(client, params)) {
ret.push(chunk) ret.push(chunk)
} }

View file

@ -1,14 +1,14 @@
import { tl } from '@mtcute/core' import { BaseTelegramClient, tl } from '@mtcute/core'
import { assertTypeIs } from '@mtcute/core/utils' import { assertTypeIs } from '@mtcute/core/utils'
import { TelegramClient } from '../../client'
import { InputFileLike } from '../../types' import { InputFileLike } from '../../types'
import { _normalizeInputMedia } from './normalize-input-media'
/** /**
* @internal * @internal
*/ */
export async function _normalizeFileToDocument( export async function _normalizeFileToDocument(
this: TelegramClient, client: BaseTelegramClient,
file: InputFileLike | tl.TypeInputDocument, file: InputFileLike | tl.TypeInputDocument,
params: { params: {
progressCallback?: (uploaded: number, total: number) => void progressCallback?: (uploaded: number, total: number) => void
@ -18,7 +18,8 @@ export async function _normalizeFileToDocument(
return file return file
} }
const media = await this._normalizeInputMedia( const media = await _normalizeInputMedia(
client,
{ {
type: 'document', type: 'document',
file, file,
@ -27,8 +28,8 @@ export async function _normalizeFileToDocument(
true, true,
) )
assertTypeIs('createStickerSet', media, 'inputMediaDocument') assertTypeIs('_normalizeFileToDocument', media, 'inputMediaDocument')
assertTypeIs('createStickerSet', media.id, 'inputDocument') assertTypeIs('_normalizeFileToDocument', media.id, 'inputDocument')
return media.id return media.id
} }

View file

@ -1,17 +1,15 @@
import { MtArgumentError, tl } from '@mtcute/core' import { BaseTelegramClient, MtArgumentError, tl } from '@mtcute/core'
import { tdFileId } from '@mtcute/file-id' import { tdFileId } from '@mtcute/file-id'
import { TelegramClient } from '../../client' import { InputFileLike, isUploadedFile } from '../../types/files'
import { InputFileLike, isUploadedFile } from '../../types' import { uploadFile } from './upload-file'
/** /**
* Normalize a {@link InputFileLike} to `InputFile`, * Normalize a {@link InputFileLike} to `InputFile`,
* uploading it if needed. * uploading it if needed.
*
* @internal
*/ */
export async function _normalizeInputFile( export async function _normalizeInputFile(
this: TelegramClient, client: BaseTelegramClient,
input: InputFileLike, input: InputFileLike,
params: { params: {
progressCallback?: (uploaded: number, total: number) => void progressCallback?: (uploaded: number, total: number) => void
@ -24,7 +22,7 @@ export async function _normalizeInputFile(
throw new MtArgumentError("InputFile can't be created from an InputMedia") throw new MtArgumentError("InputFile can't be created from an InputMedia")
} else if (tdFileId.isFileIdLike(input)) { } else if (tdFileId.isFileIdLike(input)) {
if (typeof input === 'string' && input.match(/^file:/)) { if (typeof input === 'string' && input.match(/^file:/)) {
const uploaded = await this.uploadFile({ const uploaded = await uploadFile(client, {
file: input.substring(5), file: input.substring(5),
...params, ...params,
}) })
@ -37,7 +35,7 @@ export async function _normalizeInputFile(
} else if (typeof input === 'object' && tl.isAnyInputFile(input)) { } else if (typeof input === 'object' && tl.isAnyInputFile(input)) {
return input return input
} else { } else {
const uploaded = await this.uploadFile({ const uploaded = await uploadFile(client, {
file: input, file: input,
...params, ...params,
}) })

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