Arch refactor #14
592 changed files with 9303 additions and 9171 deletions
|
@ -160,7 +160,7 @@ module.exports = {
|
||||||
'simple-import-sort/imports': [
|
'simple-import-sort/imports': [
|
||||||
'error',
|
'error',
|
||||||
{
|
{
|
||||||
groups: [['^[a-z]'], ['^@mtcute'], ['^@/'], ['^~/'], ['^\\.']],
|
groups: [['^[a-z]'], ['^@?mtcute'], ['^@/'], ['^~/'], ['^\\.']],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
'simple-import-sort/exports': 'error',
|
'simple-import-sort/exports': 'error',
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
const { MemoryStorage } = require('@mtcute/core/storage/memory.js')
|
const { MemoryStorage } = require('@mtcute/core')
|
||||||
const { LogManager } = require('@mtcute/core/utils.js')
|
const { LogManager } = require('@mtcute/core/utils.js')
|
||||||
|
|
||||||
exports.getApiParams = () => {
|
exports.getApiParams = () => {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { MemoryStorage } from '@mtcute/core/storage/memory.js'
|
import { MemoryStorage } from '@mtcute/core'
|
||||||
import { LogManager } from '@mtcute/core/utils.js'
|
import { LogManager } from '@mtcute/core/utils.js'
|
||||||
|
|
||||||
export const getApiParams = () => {
|
export const getApiParams = () => {
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
"name": "mtcute-e2e",
|
"name": "mtcute-e2e",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mtcute/client": "*",
|
|
||||||
"@mtcute/core": "*",
|
"@mtcute/core": "*",
|
||||||
"@mtcute/crypto-node": "*",
|
"@mtcute/crypto-node": "*",
|
||||||
"@mtcute/dispatcher": "*",
|
"@mtcute/dispatcher": "*",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { expect } from 'chai'
|
import { expect } from 'chai'
|
||||||
import { describe, it } from 'mocha'
|
import { describe, it } from 'mocha'
|
||||||
|
|
||||||
import { MtUnsupportedError, TelegramClient } from '@mtcute/client'
|
import { BaseTelegramClient, MtUnsupportedError, TelegramClient } from '@mtcute/core'
|
||||||
|
|
||||||
import { getApiParams } from '../utils.js'
|
import { getApiParams } from '../utils.js'
|
||||||
|
|
||||||
|
@ -14,11 +14,12 @@ describe('1. authorization', function () {
|
||||||
this.timeout(300_000)
|
this.timeout(300_000)
|
||||||
|
|
||||||
it('should authorize in default dc', async () => {
|
it('should authorize in default dc', async () => {
|
||||||
const tg = new TelegramClient(getApiParams('dc2.session'))
|
const base = new BaseTelegramClient(getApiParams('dc2.session'))
|
||||||
|
const tg = new TelegramClient({ client: base })
|
||||||
|
|
||||||
// reset storage just in case
|
// reset storage just in case
|
||||||
await tg.storage.load?.()
|
await base.mt.storage.load()
|
||||||
await tg.storage.reset(true)
|
await base.storage.clear(true)
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const phone = `999662${getAccountId()}`
|
const phone = `999662${getAccountId()}`
|
||||||
|
@ -45,11 +46,12 @@ describe('1. authorization', function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should authorize in dc 1', async () => {
|
it('should authorize in dc 1', async () => {
|
||||||
const tg = new TelegramClient(getApiParams('dc1.session'))
|
const base = new BaseTelegramClient(getApiParams('dc1.session'))
|
||||||
|
const tg = new TelegramClient({ client: base })
|
||||||
|
|
||||||
// reset storage just in case
|
// reset storage just in case
|
||||||
await tg.storage.load?.()
|
await base.mt.storage.load()
|
||||||
await tg.storage.reset(true)
|
await base.mt.storage.clear(true)
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const phone = `999661${getAccountId()}`
|
const phone = `999661${getAccountId()}`
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { expect } from 'chai'
|
import { expect } from 'chai'
|
||||||
import { describe, it } from 'mocha'
|
import { describe, it } from 'mocha'
|
||||||
|
|
||||||
import { TelegramClient } from '@mtcute/client'
|
import { TelegramClient } from '@mtcute/core'
|
||||||
|
|
||||||
import { getApiParams } from '../utils.js'
|
import { getApiParams } from '../utils.js'
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { expect } from 'chai'
|
||||||
import { createHash } from 'crypto'
|
import { createHash } from 'crypto'
|
||||||
import { describe, it } from 'mocha'
|
import { describe, it } from 'mocha'
|
||||||
|
|
||||||
import { FileDownloadLocation, TelegramClient, Thumbnail } from '@mtcute/client'
|
import { FileDownloadLocation, TelegramClient, Thumbnail } from '@mtcute/core'
|
||||||
import { sleep } from '@mtcute/core/utils.js'
|
import { sleep } from '@mtcute/core/utils.js'
|
||||||
|
|
||||||
import { getApiParams } from '../utils.js'
|
import { getApiParams } from '../utils.js'
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { expect } from 'chai'
|
import { expect } from 'chai'
|
||||||
import { describe, it } from 'mocha'
|
import { describe, it } from 'mocha'
|
||||||
|
|
||||||
import { Message, TelegramClient } from '@mtcute/client'
|
import { Message, TelegramClient } from '@mtcute/core'
|
||||||
|
|
||||||
import { getApiParams, waitFor } from '../utils.js'
|
import { getApiParams, waitFor } from '../utils.js'
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
// eslint-disable-next-line no-restricted-imports
|
// eslint-disable-next-line no-restricted-imports
|
||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
|
|
||||||
import { BaseTelegramClientOptions, MaybeAsync } from '@mtcute/core'
|
import { MaybePromise, MemoryStorage } from '@mtcute/core'
|
||||||
import { MemoryStorage } from '@mtcute/core/storage/memory.js'
|
|
||||||
import { LogManager, sleep } from '@mtcute/core/utils.js'
|
import { LogManager, sleep } from '@mtcute/core/utils.js'
|
||||||
import { SqliteStorage } from '@mtcute/sqlite'
|
import { SqliteStorage } from '@mtcute/sqlite'
|
||||||
|
|
||||||
export const getApiParams = (storage?: string): BaseTelegramClientOptions => {
|
export const getApiParams = (storage?: string) => {
|
||||||
if (!process.env.API_ID || !process.env.API_HASH) {
|
if (!process.env.API_ID || !process.env.API_HASH) {
|
||||||
throw new Error('API_ID and API_HASH env variables must be set')
|
throw new Error('API_ID and API_HASH env variables must be set')
|
||||||
}
|
}
|
||||||
|
@ -20,7 +19,7 @@ export const getApiParams = (storage?: string): BaseTelegramClientOptions => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function waitFor(condition: () => MaybeAsync<void>, timeout = 5000): Promise<void> {
|
export async function waitFor(condition: () => MaybePromise<void>, timeout = 5000): Promise<void> {
|
||||||
const start = Date.now()
|
const start = Date.now()
|
||||||
let lastError
|
let lastError
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"name": "mtcute",
|
"name": "mtcute-workspace",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.6.0",
|
"version": "0.6.0",
|
||||||
"description": "Type-safe library for MTProto (Telegram API) for browser and NodeJS",
|
"description": "Type-safe library for MTProto (Telegram API) for browser and NodeJS",
|
||||||
|
@ -61,7 +61,7 @@
|
||||||
"ts-node": "10.9.1",
|
"ts-node": "10.9.1",
|
||||||
"tsconfig-paths": "4.2.0",
|
"tsconfig-paths": "4.2.0",
|
||||||
"typedoc": "0.25.3",
|
"typedoc": "0.25.3",
|
||||||
"typescript": "5.0.4",
|
"typescript": "5.1.6",
|
||||||
"vite": "5.0.3",
|
"vite": "5.0.3",
|
||||||
"vitest": "0.34.6"
|
"vitest": "0.34.6"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
# @mtcute/client
|
|
||||||
|
|
||||||
📖 [API Reference](https://ref.mtcute.dev/modules/_mtcute_client.html)
|
|
||||||
|
|
||||||
High-level Telegram client implementation over the `@mtcute/core` base library.
|
|
||||||
|
|
||||||
## Features
|
|
||||||
- **Updates handling**: Implements proper updates handling, including ordering and gap recovery ([learn more](https://core.telegram.org/api/updates))
|
|
||||||
- **Wrapper classes**: Easy-to-use classes that wrap the complex TL objects and provide a clean interface
|
|
||||||
- **High-level methods**: Methods that wrap the low-level API calls and provide a clean interface
|
|
||||||
- **Tree-shaking**: Only import the methods you need, and the rest will not be included into the bundle
|
|
||||||
- **Web support**: Works in the browser with no additional configuration
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { TelegramClient } from '@mtcute/client'
|
|
||||||
|
|
||||||
const tg = new TelegramClient({
|
|
||||||
apiId: 12345,
|
|
||||||
apiHash: '0123456789abcdef0123456789abcdef',
|
|
||||||
// ... + supports all options from @mtcute/core ...
|
|
||||||
})
|
|
||||||
|
|
||||||
tg.start({
|
|
||||||
phone: '+1234567890',
|
|
||||||
password: () => prompt('Enter password'),
|
|
||||||
code: () => prompt('Enter code'),
|
|
||||||
}, (user) => {
|
|
||||||
console.log(`Logged in as ${user.displayName}`)
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
> **Note**: for web, prefer BaseTelegramClient over TelegramClient,
|
|
||||||
> as it is tree-shakeable – [learn more](https://mtcute.dev/guide/topics/treeshaking.html)
|
|
|
@ -1,3 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
esmOnlyDirectives: true,
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
{
|
|
||||||
"name": "@mtcute/client",
|
|
||||||
"private": true,
|
|
||||||
"version": "0.6.0",
|
|
||||||
"description": "High-level API over @mtcute/core",
|
|
||||||
"author": "Alina Sireneva <alina@tei.su>",
|
|
||||||
"license": "MIT",
|
|
||||||
"main": "src/index.ts",
|
|
||||||
"type": "module",
|
|
||||||
"scripts": {
|
|
||||||
"build": "pnpm run -w build-package client",
|
|
||||||
"gen-client": "node ./scripts/generate-client.cjs",
|
|
||||||
"gen-updates": "node ./scripts/generate-updates.cjs"
|
|
||||||
},
|
|
||||||
"distOnlyFields": {
|
|
||||||
"exports": {
|
|
||||||
".": {
|
|
||||||
"import": "./esm/index.js",
|
|
||||||
"require": "./cjs/index.js"
|
|
||||||
},
|
|
||||||
"./methods/*": {
|
|
||||||
"import": "./esm/methods/*",
|
|
||||||
"require": "./cjs/methods/*"
|
|
||||||
},
|
|
||||||
"./utils.js": {
|
|
||||||
"import": "./esm/utils/index.js",
|
|
||||||
"require": "./cjs/utils/index.js"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"browser": {
|
|
||||||
"./src/methods/files/_platform.js": "./src/methods/files/_platform.web.js",
|
|
||||||
"./src/methods/files/download-file.js": "./src/methods/files/download-file.web.js",
|
|
||||||
"./src/utils/platform/storage.js": "./src/utils/platform/storage.web.js"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@mtcute/core": "workspace:^",
|
|
||||||
"@mtcute/file-id": "workspace:^"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@mtcute/test": "workspace:^"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
export * from './client.js'
|
|
||||||
export * from './types/index.js'
|
|
||||||
export * from './utils/peer-utils.js'
|
|
||||||
export { createDummyUpdate } from './utils/updates-utils.js'
|
|
||||||
export * from '@mtcute/core'
|
|
|
@ -1,115 +0,0 @@
|
||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
||||||
|
|
||||||
import { BaseTelegramClientOptions, ITelegramStorage } from '@mtcute/core'
|
|
||||||
// @copy
|
|
||||||
import { MemoryStorage } from '@mtcute/core/src/storage/memory.js'
|
|
||||||
|
|
||||||
import { TelegramClient } from '../client.js'
|
|
||||||
// @copy
|
|
||||||
import { Conversation } from '../types/conversation.js'
|
|
||||||
// @copy
|
|
||||||
import { _defaultStorageFactory } from '../utils/platform/storage.js'
|
|
||||||
// @copy
|
|
||||||
import { setupAuthState } from './auth/_state.js'
|
|
||||||
// @copy
|
|
||||||
import {
|
|
||||||
enableUpdatesProcessing,
|
|
||||||
makeParsedUpdateHandler,
|
|
||||||
ParsedUpdateHandlerParams,
|
|
||||||
UpdatesManagerParams,
|
|
||||||
} from './updates/index.js'
|
|
||||||
|
|
||||||
// @extension
|
|
||||||
interface TelegramClientExt {
|
|
||||||
_disableUpdatesManager: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
// @copy
|
|
||||||
interface TelegramClientOptions extends Omit<BaseTelegramClientOptions, 'storage'> {
|
|
||||||
/**
|
|
||||||
* Storage to use for this client.
|
|
||||||
*
|
|
||||||
* If a string is passed, it will be used as:
|
|
||||||
* - a path to a JSON file for Node.js
|
|
||||||
* - IndexedDB database name for browsers
|
|
||||||
*
|
|
||||||
* If omitted, {@link MemoryStorage} is used
|
|
||||||
*/
|
|
||||||
storage?: string | ITelegramStorage
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parameters for updates manager.
|
|
||||||
*/
|
|
||||||
updates?: Omit<ParsedUpdateHandlerParams & UpdatesManagerParams, 'onUpdate' | 'onRawUpdate'>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* **ADVANCED**
|
|
||||||
*
|
|
||||||
* If set to `true`, updates manager will not be created,
|
|
||||||
* and only raw TL Updates will be emitted.
|
|
||||||
*
|
|
||||||
* Unlike {@link TelegramClientOptions.disableUpdates}, this
|
|
||||||
* does not prevent the updates from being sent by the server,
|
|
||||||
* but disables proper handling of them (see [Working with Updates](https://core.telegram.org/api/updates))
|
|
||||||
*
|
|
||||||
* This may be useful in some cases when you require more control over
|
|
||||||
* the updates or to minimize additional overhead from properly handling them
|
|
||||||
* for some very particular use cases.
|
|
||||||
*
|
|
||||||
* The updates **will not** be dispatched the normal way, instead
|
|
||||||
* you should manually add a handler using `client.network.setUpdateHandler`.
|
|
||||||
*/
|
|
||||||
disableUpdatesManager?: boolean
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If `true`, the updates that were handled by some {@link Conversation}
|
|
||||||
* will not be dispatched any further.
|
|
||||||
*
|
|
||||||
* @default true
|
|
||||||
*/
|
|
||||||
skipConversationUpdates?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
// @initialize=super
|
|
||||||
/** @internal */
|
|
||||||
function _initializeClientSuper(this: TelegramClient, opts: TelegramClientOptions) {
|
|
||||||
if (typeof opts.storage === 'string') {
|
|
||||||
opts.storage = _defaultStorageFactory(opts.storage)
|
|
||||||
} else if (!opts.storage) {
|
|
||||||
opts.storage = new MemoryStorage()
|
|
||||||
}
|
|
||||||
|
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
|
||||||
// @ts-expect-error codegen
|
|
||||||
super(opts)
|
|
||||||
/* eslint-enable @typescript-eslint/no-unsafe-call */
|
|
||||||
}
|
|
||||||
|
|
||||||
// @initialize
|
|
||||||
/** @internal */
|
|
||||||
function _initializeClient(this: TelegramClient, opts: TelegramClientOptions) {
|
|
||||||
this._disableUpdatesManager = opts.disableUpdatesManager ?? false
|
|
||||||
const skipConversationUpdates = opts.skipConversationUpdates ?? true
|
|
||||||
|
|
||||||
if (!opts.disableUpdates && !opts.disableUpdatesManager) {
|
|
||||||
const { messageGroupingInterval, ...managerParams } = opts.updates ?? {}
|
|
||||||
|
|
||||||
enableUpdatesProcessing(this, {
|
|
||||||
...managerParams,
|
|
||||||
onUpdate: makeParsedUpdateHandler({
|
|
||||||
messageGroupingInterval,
|
|
||||||
onUpdate: (update) => {
|
|
||||||
if (Conversation.handleUpdate(this, update) && skipConversationUpdates) return
|
|
||||||
|
|
||||||
this.emit('update', update)
|
|
||||||
this.emit(update.name, update.data)
|
|
||||||
},
|
|
||||||
onRawUpdate: (update, peers) => {
|
|
||||||
this.emit('raw_update', update, peers)
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
setupAuthState(this)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,144 +0,0 @@
|
||||||
/* eslint-disable no-inner-declarations */
|
|
||||||
import { BaseTelegramClient, MtArgumentError, MtUnsupportedError, tl } from '@mtcute/core'
|
|
||||||
import { assertTypeIs } from '@mtcute/core/utils.js'
|
|
||||||
|
|
||||||
import { User } from '../../types/peers/user.js'
|
|
||||||
|
|
||||||
const STATE_SYMBOL = Symbol('authState')
|
|
||||||
|
|
||||||
/** @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
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize auth state for the given client.
|
|
||||||
*
|
|
||||||
* Allows {@link getAuthState} to be used and is required for some methods.
|
|
||||||
* @noemit
|
|
||||||
*/
|
|
||||||
export function setupAuthState(client: BaseTelegramClient): void {
|
|
||||||
// eslint-disable-next-line
|
|
||||||
let state: AuthState = (client as any)[STATE_SYMBOL]
|
|
||||||
if (state) return
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get auth state for the given client, containing
|
|
||||||
* information about the current user.
|
|
||||||
*
|
|
||||||
* Auth state must first be initialized with {@link setupAuthState}.
|
|
||||||
*/
|
|
||||||
export function getAuthState(client: BaseTelegramClient): AuthState {
|
|
||||||
// eslint-disable-next-line
|
|
||||||
let state: AuthState = (client as any)[STATE_SYMBOL]
|
|
||||||
|
|
||||||
if (!state) {
|
|
||||||
throw new MtArgumentError('Auth state is not initialized, use setupAuthState()')
|
|
||||||
}
|
|
||||||
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
export async function _onAuthorization(
|
|
||||||
client: BaseTelegramClient,
|
|
||||||
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')
|
|
||||||
|
|
||||||
const state = getAuthState(client)
|
|
||||||
state.userId = auth.user.id
|
|
||||||
state.isBot = bot
|
|
||||||
state.selfUsername = auth.user.username ?? null
|
|
||||||
state.selfChanged = true
|
|
||||||
|
|
||||||
client.notifyLoggedIn(auth)
|
|
||||||
await client.saveStorage()
|
|
||||||
|
|
||||||
// telegram ignores invokeWithoutUpdates for auth methods
|
|
||||||
if (client.network.params.disableUpdates) client.network.resetSessions()
|
|
||||||
|
|
||||||
return new User(auth.user)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the given peer/input peer is referring to the current user
|
|
||||||
*/
|
|
||||||
export function isSelfPeer(
|
|
||||||
client: BaseTelegramClient,
|
|
||||||
peer: tl.TypeInputPeer | tl.TypePeer | tl.TypeInputUser,
|
|
||||||
): boolean {
|
|
||||||
const state = getAuthState(client)
|
|
||||||
|
|
||||||
switch (peer._) {
|
|
||||||
case 'inputPeerSelf':
|
|
||||||
case 'inputUserSelf':
|
|
||||||
return true
|
|
||||||
case 'inputPeerUser':
|
|
||||||
case 'inputPeerUserFromMessage':
|
|
||||||
case 'inputUser':
|
|
||||||
case 'inputUserFromMessage':
|
|
||||||
case 'peerUser':
|
|
||||||
return peer.userId === state.userId
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
import { BaseTelegramClient } from '@mtcute/core'
|
|
||||||
|
|
||||||
import { getAuthState } from './_state.js'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log out from Telegram account and optionally reset the session storage.
|
|
||||||
*
|
|
||||||
* When you log out, you can immediately log back in using
|
|
||||||
* the same {@link TelegramClient} instance.
|
|
||||||
*
|
|
||||||
* @returns On success, `true` is returned
|
|
||||||
*/
|
|
||||||
export async function logOut(client: BaseTelegramClient): Promise<true> {
|
|
||||||
await client.call({ _: 'auth.logOut' })
|
|
||||||
|
|
||||||
const authState = getAuthState(client)
|
|
||||||
authState.userId = null
|
|
||||||
authState.isBot = false
|
|
||||||
authState.selfUsername = null
|
|
||||||
authState.selfChanged = true
|
|
||||||
|
|
||||||
client.emit('logged_out')
|
|
||||||
|
|
||||||
await client.storage.reset()
|
|
||||||
await client.saveStorage()
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
import { BaseTelegramClient } from '@mtcute/core'
|
|
||||||
|
|
||||||
import { User } from '../../types/index.js'
|
|
||||||
import { _onAuthorization } from './_state.js'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Authorize a bot using its token issued by [@BotFather](//t.me/BotFather)
|
|
||||||
*
|
|
||||||
* @param token Bot token issued by BotFather
|
|
||||||
* @returns Bot's {@link User} object
|
|
||||||
* @throws BadRequestError In case the bot token is invalid
|
|
||||||
*/
|
|
||||||
export async function signInBot(client: BaseTelegramClient, token: string): Promise<User> {
|
|
||||||
const res = await client.call({
|
|
||||||
_: 'auth.importBotAuthorization',
|
|
||||||
flags: 0,
|
|
||||||
apiId: client.params.apiId,
|
|
||||||
apiHash: client.params.apiHash,
|
|
||||||
botAuthToken: token,
|
|
||||||
})
|
|
||||||
|
|
||||||
return _onAuthorization(client, res, true)
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
import { BaseTelegramClient, getMarkedPeerId, tl } from '@mtcute/core'
|
|
||||||
|
|
||||||
import { getAuthState } from '../auth/_state.js'
|
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
export function _getPeerChainId(client: BaseTelegramClient, peer: tl.TypeInputPeer, prefix = 'peer') {
|
|
||||||
const id = peer._ === 'inputPeerSelf' ? getAuthState(client).userId! : getMarkedPeerId(peer)
|
|
||||||
|
|
||||||
return `${prefix}:${id}`
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,42 +0,0 @@
|
||||||
import { tl } from '@mtcute/core'
|
|
||||||
|
|
||||||
export function messageToUpdate(message: tl.TypeMessage): tl.TypeUpdate {
|
|
||||||
switch (message.peerId!._) {
|
|
||||||
case 'peerUser':
|
|
||||||
case 'peerChat':
|
|
||||||
return {
|
|
||||||
_: 'updateNewMessage',
|
|
||||||
message,
|
|
||||||
pts: 0,
|
|
||||||
ptsCount: 0,
|
|
||||||
}
|
|
||||||
case 'peerChannel':
|
|
||||||
return {
|
|
||||||
_: 'updateNewChannelMessage',
|
|
||||||
message,
|
|
||||||
pts: 0,
|
|
||||||
ptsCount: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function extractChannelIdFromUpdate(upd: tl.TypeUpdate): number | undefined {
|
|
||||||
// holy shit
|
|
||||||
let res = 0
|
|
||||||
|
|
||||||
if ('channelId' in upd) {
|
|
||||||
res = upd.channelId
|
|
||||||
} else if (
|
|
||||||
'message' in upd &&
|
|
||||||
typeof upd.message !== 'string' &&
|
|
||||||
'peerId' in upd.message &&
|
|
||||||
upd.message.peerId &&
|
|
||||||
'channelId' in upd.message.peerId
|
|
||||||
) {
|
|
||||||
res = upd.message.peerId.channelId
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res === 0) return undefined
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
import { BaseTelegramClient } from '@mtcute/core'
|
|
||||||
import { assertTypeIs } from '@mtcute/core/utils.js'
|
|
||||||
|
|
||||||
import { User } from '../../types/index.js'
|
|
||||||
import { getAuthState } from '../auth/_state.js'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get currently authorized user's full information
|
|
||||||
*/
|
|
||||||
export function getMe(client: BaseTelegramClient): Promise<User> {
|
|
||||||
return client
|
|
||||||
.call({
|
|
||||||
_: 'users.getUsers',
|
|
||||||
id: [
|
|
||||||
{
|
|
||||||
_: 'inputUserSelf',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
.then(async ([user]) => {
|
|
||||||
assertTypeIs('getMe (@ users.getUsers)', user, 'user')
|
|
||||||
|
|
||||||
const authState = getAuthState(client)
|
|
||||||
|
|
||||||
if (authState.userId !== user.id) {
|
|
||||||
// there is such possibility, e.g. when
|
|
||||||
// using a string session without `self`,
|
|
||||||
// or logging out and re-logging in
|
|
||||||
// we need to update the fields accordingly,
|
|
||||||
// and force-save the session
|
|
||||||
authState.userId = user.id
|
|
||||||
authState.isBot = Boolean(user.bot)
|
|
||||||
authState.selfChanged = true
|
|
||||||
await client.saveStorage()
|
|
||||||
}
|
|
||||||
|
|
||||||
authState.selfUsername = user.username ?? null
|
|
||||||
|
|
||||||
return new User(user)
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
import { BaseTelegramClient } from '@mtcute/core'
|
|
||||||
|
|
||||||
import { getAuthState } from '../auth/_state.js'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get currently authorized user's username.
|
|
||||||
*
|
|
||||||
* This method uses locally available information and
|
|
||||||
* does not call any API methods.
|
|
||||||
*/
|
|
||||||
export function getMyUsername(client: BaseTelegramClient): string | null {
|
|
||||||
return getAuthState(client).selfUsername
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
import { JsonFileStorage } from '@mtcute/core/src/storage/json-file.js'
|
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
export const _defaultStorageFactory = (name: string) => {
|
|
||||||
return new JsonFileStorage(name)
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
import { MtTypeAssertionError, tl } from '@mtcute/core'
|
|
||||||
|
|
||||||
// dummy updates which are used for methods that return messages.affectedHistory.
|
|
||||||
// that is not an update, but it carries info about pts, and we need to handle it
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a dummy `updates` container with given updates.
|
|
||||||
*/
|
|
||||||
export function createDummyUpdatesContainer(updates: tl.TypeUpdate[], seq = 0): tl.TypeUpdates {
|
|
||||||
return {
|
|
||||||
_: 'updates',
|
|
||||||
seq,
|
|
||||||
date: 0,
|
|
||||||
chats: [],
|
|
||||||
users: [],
|
|
||||||
updates,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a dummy update from PTS and PTS count.
|
|
||||||
*
|
|
||||||
* @param pts PTS
|
|
||||||
* @param ptsCount PTS count
|
|
||||||
* @param channelId Channel ID (bare), if applicable
|
|
||||||
*/
|
|
||||||
export function createDummyUpdate(pts: number, ptsCount: number, channelId = 0): tl.TypeUpdates {
|
|
||||||
return createDummyUpdatesContainer([
|
|
||||||
{
|
|
||||||
_: 'mtcute.dummyUpdate',
|
|
||||||
channelId,
|
|
||||||
pts,
|
|
||||||
ptsCount,
|
|
||||||
},
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
export function assertIsUpdatesGroup(
|
|
||||||
ctx: string,
|
|
||||||
upd: tl.TypeUpdates,
|
|
||||||
): asserts upd is tl.RawUpdates | tl.RawUpdatesCombined {
|
|
||||||
switch (upd._) {
|
|
||||||
case 'updates':
|
|
||||||
case 'updatesCombined':
|
|
||||||
return
|
|
||||||
}
|
|
||||||
throw new MtTypeAssertionError(ctx, 'updates | updatesCombined', upd._)
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
{
|
|
||||||
"extends": "../../tsconfig.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"outDir": "./dist/esm",
|
|
||||||
"rootDir": "./src"
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"./src",
|
|
||||||
],
|
|
||||||
"references": [
|
|
||||||
{ "path": "../core" },
|
|
||||||
{ "path": "../test" }
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
extends: ['../../.config/typedoc/config.base.cjs'],
|
|
||||||
entryPoints: [
|
|
||||||
'./src/index.ts',
|
|
||||||
'./src/utils/index.ts',
|
|
||||||
'./src/methods/updates/index.ts',
|
|
||||||
],
|
|
||||||
entryPointStrategy: 'expand',
|
|
||||||
}
|
|
|
@ -1,4 +0,0 @@
|
||||||
// this file only exists as a hint to IDEs that we can use @mtcute/core/utils instead of @mtcute/core/src/utils.
|
|
||||||
// it is not present in the built package, just a DX improvement
|
|
||||||
|
|
||||||
export * from './src/utils/index.js'
|
|
|
@ -1,5 +1,6 @@
|
||||||
module.exports = ({ path, transformFile, packageDir, outDir }) => ({
|
module.exports = ({ path, transformFile, packageDir, outDir }) => ({
|
||||||
esmOnlyDirectives: true,
|
esmOnlyDirectives: true,
|
||||||
|
esmImportDirectives: true,
|
||||||
final() {
|
final() {
|
||||||
const version = require(path.join(packageDir, 'package.json')).version
|
const version = require(path.join(packageDir, 'package.json')).version
|
||||||
const replaceVersion = (content) => content.replace('%VERSION%', version)
|
const replaceVersion = (content) => content.replace('%VERSION%', version)
|
||||||
|
|
|
@ -2,13 +2,15 @@
|
||||||
"name": "@mtcute/core",
|
"name": "@mtcute/core",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.6.0",
|
"version": "0.6.0",
|
||||||
"description": "Core functions and base MTProto client",
|
"description": "Type-safe library for MTProto (Telegram API)",
|
||||||
"author": "Alina Sireneva <alina@tei.su>",
|
"author": "Alina Sireneva <alina@tei.su>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "pnpm run -w build-package core"
|
"build": "pnpm run -w build-package core",
|
||||||
|
"gen-client": "node ./scripts/generate-client.cjs",
|
||||||
|
"gen-updates": "node ./scripts/generate-updates.cjs"
|
||||||
},
|
},
|
||||||
"browser": {
|
"browser": {
|
||||||
"./src/utils/platform/crypto.js": "./src/utils/platform/crypto.web.js",
|
"./src/utils/platform/crypto.js": "./src/utils/platform/crypto.web.js",
|
||||||
|
@ -16,6 +18,11 @@
|
||||||
"./src/utils/platform/logging.js": "./src/utils/platform/logging.web.js",
|
"./src/utils/platform/logging.js": "./src/utils/platform/logging.web.js",
|
||||||
"./src/utils/platform/random.js": "./src/utils/platform/random.web.js",
|
"./src/utils/platform/random.js": "./src/utils/platform/random.web.js",
|
||||||
"./src/utils/platform/exit-hook.js": "./src/utils/platform/exit-hook.web.js",
|
"./src/utils/platform/exit-hook.js": "./src/utils/platform/exit-hook.web.js",
|
||||||
|
"./src/highlevel/worker/platform/connect.js": "./src/highlevel/worker/platform/connect.web.js",
|
||||||
|
"./src/highlevel/worker/platform/register.js": "./src/highlevel/worker/platform/register.web.js",
|
||||||
|
"./src/highlevel/methods/files/_platform.js": "./src/highlevel/methods/files/_platform.web.js",
|
||||||
|
"./src/highlevel/methods/files/download-file.js": "./src/highlevel/methods/files/download-file.web.js",
|
||||||
|
"./src/highlevel/utils/platform/storage.js": "./src/highlevel/utils/platform/storage.web.js",
|
||||||
"./src/storage/json-file.js": false
|
"./src/storage/json-file.js": false
|
||||||
},
|
},
|
||||||
"distOnlyFields": {
|
"distOnlyFields": {
|
||||||
|
@ -39,6 +46,14 @@
|
||||||
"./storage/*": {
|
"./storage/*": {
|
||||||
"import": "./esm/storage/*",
|
"import": "./esm/storage/*",
|
||||||
"require": "./cjs/storage/*"
|
"require": "./cjs/storage/*"
|
||||||
|
},
|
||||||
|
"./highlevel/*": {
|
||||||
|
"import": "./esm/highlevel/*",
|
||||||
|
"require": "./cjs/highlevel/*"
|
||||||
|
},
|
||||||
|
"./methods/*": {
|
||||||
|
"import": "./esm/highlevel/methods/*",
|
||||||
|
"require": "./cjs/highlevel/methods/*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -46,13 +61,13 @@
|
||||||
"@mtcute/tl": "workspace:^",
|
"@mtcute/tl": "workspace:^",
|
||||||
"@mtcute/tl-runtime": "workspace:^",
|
"@mtcute/tl-runtime": "workspace:^",
|
||||||
"@mtcute/wasm": "workspace:^",
|
"@mtcute/wasm": "workspace:^",
|
||||||
|
"@mtcute/file-id": "workspace:^",
|
||||||
"@types/events": "3.0.0",
|
"@types/events": "3.0.0",
|
||||||
"events": "3.2.0",
|
"events": "3.2.0",
|
||||||
"long": "5.2.3"
|
"long": "5.2.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/ws": "8.5.4",
|
"@types/ws": "8.5.4",
|
||||||
"node-forge": "1.3.1",
|
|
||||||
"@mtcute/test": "workspace:^",
|
"@mtcute/test": "workspace:^",
|
||||||
"ws": "8.13.0"
|
"ws": "8.13.0"
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ function findMethodAvailability(method) {
|
||||||
return entry.available ?? null
|
return entry.available ?? null
|
||||||
}
|
}
|
||||||
|
|
||||||
const targetDir = path.join(__dirname, '../src')
|
const targetDir = path.join(__dirname, '../src/highlevel')
|
||||||
|
|
||||||
async function* getFiles(dir) {
|
async function* getFiles(dir) {
|
||||||
const dirents = await fs.promises.readdir(dir, { withFileTypes: true })
|
const dirents = await fs.promises.readdir(dir, { withFileTypes: true })
|
||||||
|
@ -315,7 +315,7 @@ async function addSingleMethod(state, fileName) {
|
||||||
|
|
||||||
const firstArg = stmt.parameters[0]
|
const firstArg = stmt.parameters[0]
|
||||||
|
|
||||||
if (isExported && (!firstArg || firstArg.type.getText() !== 'BaseTelegramClient')) {
|
if (isExported && (!firstArg || firstArg.type.getText() !== 'ITelegramClient')) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -421,7 +421,8 @@ async function addSingleMethod(state, fileName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const output = fs.createWriteStream(path.join(__dirname, '../src/client.ts'))
|
const targetFile = path.join(__dirname, '../src/highlevel/client.ts')
|
||||||
|
const output = fs.createWriteStream(targetFile)
|
||||||
const state = {
|
const state = {
|
||||||
imports: {},
|
imports: {},
|
||||||
fields: [],
|
fields: [],
|
||||||
|
@ -435,7 +436,7 @@ async function main() {
|
||||||
files: {},
|
files: {},
|
||||||
}
|
}
|
||||||
|
|
||||||
for await (const file of getFiles(path.join(__dirname, '../src/methods'))) {
|
for await (const file of getFiles(path.join(__dirname, '../src/highlevel/methods'))) {
|
||||||
if (!file.startsWith('.') && file.endsWith('.ts') && !file.endsWith('.web.ts') && !file.endsWith('.test.ts')) {
|
if (!file.startsWith('.') && file.endsWith('.ts') && !file.endsWith('.web.ts') && !file.endsWith('.test.ts')) {
|
||||||
await addSingleMethod(state, file)
|
await addSingleMethod(state, file)
|
||||||
}
|
}
|
||||||
|
@ -444,7 +445,9 @@ async function main() {
|
||||||
output.write(
|
output.write(
|
||||||
'/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging, @typescript-eslint/unified-signatures */\n' +
|
'/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging, @typescript-eslint/unified-signatures */\n' +
|
||||||
'/* eslint-disable @typescript-eslint/no-unsafe-argument */\n' +
|
'/* eslint-disable @typescript-eslint/no-unsafe-argument */\n' +
|
||||||
'/* THIS FILE WAS AUTO-GENERATED */\n',
|
'/* THIS FILE WAS AUTO-GENERATED */\n' +
|
||||||
|
"import EventEmitter from 'events'\n" +
|
||||||
|
"import Long from 'long'\n",
|
||||||
)
|
)
|
||||||
Object.entries(state.imports).forEach(([module, items]) => {
|
Object.entries(state.imports).forEach(([module, items]) => {
|
||||||
items = [...items]
|
items = [...items]
|
||||||
|
@ -458,7 +461,7 @@ async function main() {
|
||||||
output.write(`// from ${from}\n${code}\n`)
|
output.write(`// from ${from}\n${code}\n`)
|
||||||
})
|
})
|
||||||
|
|
||||||
output.write('\nexport interface TelegramClient extends BaseTelegramClient {\n')
|
output.write('\nexport interface TelegramClient extends ITelegramClient {\n')
|
||||||
|
|
||||||
output.write(`/**
|
output.write(`/**
|
||||||
* Register a raw update handler
|
* Register a raw update handler
|
||||||
|
@ -547,7 +550,7 @@ on(name: string, handler: (...args: any[]) => void): this\n`)
|
||||||
`<${func.typeParameters.map((it) => it.getFullText()).join(', ')}>` :
|
`<${func.typeParameters.map((it) => it.getFullText()).join(', ')}>` :
|
||||||
''
|
''
|
||||||
const rawParams = (func.parameters || []).filter(
|
const rawParams = (func.parameters || []).filter(
|
||||||
(it) => !it.type || it.type.getText() !== 'BaseTelegramClient',
|
(it) => !it.type || it.type.getText() !== 'ITelegramClient',
|
||||||
)
|
)
|
||||||
const parameters = rawParams
|
const parameters = rawParams
|
||||||
.map((it) => {
|
.map((it) => {
|
||||||
|
@ -648,8 +651,8 @@ on(name: string, handler: (...args: any[]) => void): this\n`)
|
||||||
if (hasOverloads) {
|
if (hasOverloads) {
|
||||||
classProtoDecls.push('// @ts-expect-error this kinda breaks typings for overloads, idc')
|
classProtoDecls.push('// @ts-expect-error this kinda breaks typings for overloads, idc')
|
||||||
}
|
}
|
||||||
classProtoDecls.push(` return ${origName}(this, ...args);`)
|
classProtoDecls.push(` return ${origName}(this._client, ...args);`)
|
||||||
classProtoDecls.push('}\n')
|
classProtoDecls.push('}')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -657,11 +660,13 @@ on(name: string, handler: (...args: any[]) => void): this\n`)
|
||||||
output.write('}\n')
|
output.write('}\n')
|
||||||
|
|
||||||
output.write('\nexport type { TelegramClientOptions }\n')
|
output.write('\nexport type { TelegramClientOptions }\n')
|
||||||
output.write('\nexport class TelegramClient extends BaseTelegramClient {\n')
|
output.write('\nexport class TelegramClient extends EventEmitter implements ITelegramClient {\n')
|
||||||
|
|
||||||
|
output.write(' _client: ITelegramClient\n')
|
||||||
state.fields.forEach(({ code }) => output.write(`protected ${code}\n`))
|
state.fields.forEach(({ code }) => output.write(`protected ${code}\n`))
|
||||||
|
|
||||||
output.write('constructor(opts: TelegramClientOptions) {\n')
|
output.write('constructor(opts: TelegramClientOptions) {\n')
|
||||||
|
output.write(' super()\n')
|
||||||
state.init.forEach((code) => {
|
state.init.forEach((code) => {
|
||||||
output.write(code + '\n')
|
output.write(code + '\n')
|
||||||
})
|
})
|
||||||
|
@ -670,10 +675,47 @@ on(name: string, handler: (...args: any[]) => void): this\n`)
|
||||||
classContents.forEach((line) => output.write(line + '\n'))
|
classContents.forEach((line) => output.write(line + '\n'))
|
||||||
output.write('}\n')
|
output.write('}\n')
|
||||||
classProtoDecls.forEach((line) => output.write(line + '\n'))
|
classProtoDecls.forEach((line) => output.write(line + '\n'))
|
||||||
|
// proxied methods
|
||||||
|
;[
|
||||||
|
'prepare',
|
||||||
|
'connect',
|
||||||
|
'close',
|
||||||
|
'notifyLoggedIn',
|
||||||
|
'notifyLoggedOut',
|
||||||
|
'notifyChannelOpened',
|
||||||
|
'notifyChannelClosed',
|
||||||
|
'startUpdatesLoop',
|
||||||
|
'stopUpdatesLoop',
|
||||||
|
'call',
|
||||||
|
'importSession',
|
||||||
|
'exportSession',
|
||||||
|
'onError',
|
||||||
|
'emitError',
|
||||||
|
'handleClientUpdate',
|
||||||
|
'getApiCrenetials',
|
||||||
|
'getPoolSize',
|
||||||
|
'getPrimaryDcId',
|
||||||
|
'computeSrpParams',
|
||||||
|
'computeNewPasswordHash',
|
||||||
|
].forEach((name) => {
|
||||||
|
output.write(
|
||||||
|
`TelegramClient.prototype.${name} = function(...args) {\n` +
|
||||||
|
` return this._client.${name}(...args)\n` +
|
||||||
|
'}\n',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
// disabled methods - they are used internally and we don't want to expose them
|
||||||
|
// if the user *really* needs them, they can use `client._client` to access the underlying client
|
||||||
|
;['onServerUpdate', 'onUpdate'].forEach((name) => {
|
||||||
|
output.write(
|
||||||
|
`TelegramClient.prototype.${name} = function() {\n` +
|
||||||
|
` throw new Error('${name} is not available for TelegramClient, use .on() methods instead')\n` +
|
||||||
|
'}\n',
|
||||||
|
)
|
||||||
|
})
|
||||||
state.impls.forEach(({ name, code }) => output.write(`TelegramClient.prototype.${name} = ${code}\n`))
|
state.impls.forEach(({ name, code }) => output.write(`TelegramClient.prototype.${name} = ${code}\n`))
|
||||||
|
|
||||||
// format the resulting file with prettier
|
// format the resulting file with prettier
|
||||||
const targetFile = path.join(__dirname, '../src/client.ts')
|
|
||||||
const prettierConfig = await prettier.resolveConfig(targetFile)
|
const prettierConfig = await prettier.resolveConfig(targetFile)
|
||||||
let fullSource = await fs.promises.readFile(targetFile, 'utf-8')
|
let fullSource = await fs.promises.readFile(targetFile, 'utf-8')
|
||||||
fullSource = await prettier.format(fullSource, {
|
fullSource = await prettier.format(fullSource, {
|
|
@ -1,4 +1,3 @@
|
||||||
/* eslint-disable no-restricted-globals */
|
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const prettier = require('prettier')
|
const prettier = require('prettier')
|
||||||
|
@ -90,7 +89,7 @@ function toSentence(type, stype = 'inline') {
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateParsedUpdate() {
|
function generateParsedUpdate() {
|
||||||
replaceSections('types/updates/index.ts', {
|
replaceSections('highlevel/types/updates/index.ts', {
|
||||||
codegen:
|
codegen:
|
||||||
'export type ParsedUpdate =\n' +
|
'export type ParsedUpdate =\n' +
|
||||||
types.map((typ) => ` | { name: '${typ.typeName}'; data: ${typ.updateType} }\n`).join(''),
|
types.map((typ) => ` | { name: '${typ.typeName}'; data: ${typ.updateType} }\n`).join(''),
|
|
@ -1,460 +0,0 @@
|
||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
||||||
import EventEmitter from 'events'
|
|
||||||
import Long from 'long'
|
|
||||||
|
|
||||||
import { tl } from '@mtcute/tl'
|
|
||||||
import { __tlReaderMap as defaultReaderMap } from '@mtcute/tl/binary/reader.js'
|
|
||||||
import { __tlWriterMap as defaultWriterMap } from '@mtcute/tl/binary/writer.js'
|
|
||||||
import { TlReaderMap, TlWriterMap } from '@mtcute/tl-runtime'
|
|
||||||
|
|
||||||
import { BaseTelegramClientOptions } from './base-client.types.js'
|
|
||||||
import { ConfigManager } from './network/config-manager.js'
|
|
||||||
import { SessionConnection, TransportFactory } from './network/index.js'
|
|
||||||
import { NetworkManager, RpcCallOptions } from './network/network-manager.js'
|
|
||||||
import { ITelegramStorage } from './storage/index.js'
|
|
||||||
import { MustEqual } from './types/index.js'
|
|
||||||
import {
|
|
||||||
ControllablePromise,
|
|
||||||
createControllablePromise,
|
|
||||||
defaultCryptoProviderFactory,
|
|
||||||
defaultProductionDc,
|
|
||||||
defaultProductionIpv6Dc,
|
|
||||||
defaultTestDc,
|
|
||||||
defaultTestIpv6Dc,
|
|
||||||
getAllPeersFrom,
|
|
||||||
ICryptoProvider,
|
|
||||||
LogManager,
|
|
||||||
readStringSession,
|
|
||||||
StringSessionData,
|
|
||||||
toggleChannelIdMark,
|
|
||||||
writeStringSession,
|
|
||||||
} from './utils/index.js'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Basic Telegram client that only implements the bare minimum
|
|
||||||
* to make RPC calls and receive low-level updates.
|
|
||||||
*/
|
|
||||||
export class BaseTelegramClient extends EventEmitter {
|
|
||||||
/**
|
|
||||||
* Crypto provider taken from {@link BaseTelegramClientOptions.crypto}
|
|
||||||
*/
|
|
||||||
readonly crypto: ICryptoProvider
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Telegram storage taken from {@link BaseTelegramClientOptions.storage}
|
|
||||||
*/
|
|
||||||
readonly storage: ITelegramStorage
|
|
||||||
|
|
||||||
/**
|
|
||||||
* "Test mode" taken from {@link BaseTelegramClientOptions.testMode}
|
|
||||||
*/
|
|
||||||
protected readonly _testMode: boolean
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Primary DCs taken from {@link BaseTelegramClientOptions.defaultDcs},
|
|
||||||
* loaded from session or changed by other means (like redirecting).
|
|
||||||
*/
|
|
||||||
protected _defaultDcs: ITelegramStorage.DcOptions
|
|
||||||
|
|
||||||
private _niceStacks: boolean
|
|
||||||
/** TL layer used by the client */
|
|
||||||
readonly _layer: number
|
|
||||||
/** TL readers map used by the client */
|
|
||||||
readonly _readerMap: TlReaderMap
|
|
||||||
/** TL writers map used by the client */
|
|
||||||
readonly _writerMap: TlWriterMap
|
|
||||||
|
|
||||||
/** Unix timestamp when the last update was received */
|
|
||||||
protected _lastUpdateTime = 0
|
|
||||||
|
|
||||||
readonly _config = new ConfigManager(() => this.call({ _: 'help.getConfig' }))
|
|
||||||
|
|
||||||
// not really connected, but rather "connect() was called"
|
|
||||||
private _connected: ControllablePromise<void> | boolean = false
|
|
||||||
|
|
||||||
_emitError: (err: unknown, connection?: SessionConnection) => void = console.error.bind(console)
|
|
||||||
|
|
||||||
private _importFrom?: StringSessionData
|
|
||||||
private _importForce?: boolean
|
|
||||||
|
|
||||||
readonly log = new LogManager('client')
|
|
||||||
readonly network: NetworkManager
|
|
||||||
|
|
||||||
constructor(readonly params: BaseTelegramClientOptions) {
|
|
||||||
super()
|
|
||||||
|
|
||||||
if (params.logLevel !== undefined) {
|
|
||||||
this.log.level = params.logLevel
|
|
||||||
}
|
|
||||||
|
|
||||||
this.crypto = (params.crypto ?? defaultCryptoProviderFactory)()
|
|
||||||
this.storage = params.storage
|
|
||||||
this._testMode = Boolean(params.testMode)
|
|
||||||
|
|
||||||
let dc = params.defaultDcs
|
|
||||||
|
|
||||||
if (!dc) {
|
|
||||||
if (params.testMode) {
|
|
||||||
dc = params.useIpv6 ? defaultTestIpv6Dc : defaultTestDc
|
|
||||||
} else {
|
|
||||||
dc = params.useIpv6 ? defaultProductionIpv6Dc : defaultProductionDc
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this._defaultDcs = dc
|
|
||||||
this._niceStacks = params.niceStacks ?? true
|
|
||||||
|
|
||||||
this._layer = params.overrideLayer ?? tl.LAYER
|
|
||||||
this._readerMap = params.readerMap ?? defaultReaderMap
|
|
||||||
this._writerMap = params.writerMap ?? defaultWriterMap
|
|
||||||
|
|
||||||
this.network = new NetworkManager(
|
|
||||||
{
|
|
||||||
apiId: params.apiId,
|
|
||||||
crypto: this.crypto,
|
|
||||||
disableUpdates: params.disableUpdates ?? false,
|
|
||||||
initConnectionOptions: params.initConnectionOptions,
|
|
||||||
layer: this._layer,
|
|
||||||
log: this.log,
|
|
||||||
readerMap: this._readerMap,
|
|
||||||
writerMap: this._writerMap,
|
|
||||||
reconnectionStrategy: params.reconnectionStrategy,
|
|
||||||
storage: this.storage,
|
|
||||||
testMode: Boolean(params.testMode),
|
|
||||||
transport: params.transport,
|
|
||||||
_emitError: this._emitError.bind(this),
|
|
||||||
floodSleepThreshold: params.floodSleepThreshold ?? 10000,
|
|
||||||
maxRetryCount: params.maxRetryCount ?? 5,
|
|
||||||
isPremium: false,
|
|
||||||
useIpv6: Boolean(params.useIpv6),
|
|
||||||
keepAliveAction: this._keepAliveAction.bind(this),
|
|
||||||
enableErrorReporting: params.enableErrorReporting ?? false,
|
|
||||||
onUsable: () => this.emit('usable'),
|
|
||||||
...(params.network ?? {}),
|
|
||||||
},
|
|
||||||
this._config,
|
|
||||||
)
|
|
||||||
|
|
||||||
this.storage.setup?.(this.log, this._readerMap, this._writerMap)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected _keepAliveAction(): void {
|
|
||||||
this.emit('keep_alive')
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async _loadStorage(): Promise<void> {
|
|
||||||
await this.storage.load?.()
|
|
||||||
}
|
|
||||||
|
|
||||||
_beforeStorageSave: (() => Promise<void>)[] = []
|
|
||||||
|
|
||||||
beforeStorageSave(cb: () => Promise<void>): void {
|
|
||||||
this._beforeStorageSave.push(cb)
|
|
||||||
}
|
|
||||||
|
|
||||||
offBeforeStorageSave(cb: () => Promise<void>): void {
|
|
||||||
this._beforeStorageSave = this._beforeStorageSave.filter((x) => x !== cb)
|
|
||||||
}
|
|
||||||
|
|
||||||
async saveStorage(): Promise<void> {
|
|
||||||
for (const cb of this._beforeStorageSave) {
|
|
||||||
await cb()
|
|
||||||
}
|
|
||||||
await this.storage.save?.()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the connection to the primary DC.
|
|
||||||
*
|
|
||||||
* You shouldn't usually call this method directly as it is called
|
|
||||||
* implicitly the first time you call {@link call}.
|
|
||||||
*/
|
|
||||||
async connect(): Promise<void> {
|
|
||||||
if (this._connected) {
|
|
||||||
// avoid double-connect
|
|
||||||
await this._connected
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const promise = (this._connected = createControllablePromise())
|
|
||||||
|
|
||||||
await this.crypto.initialize?.()
|
|
||||||
await this._loadStorage()
|
|
||||||
const primaryDc = await this.storage.getDefaultDcs()
|
|
||||||
if (primaryDc !== null) this._defaultDcs = primaryDc
|
|
||||||
|
|
||||||
const defaultDcAuthKey = await this.storage.getAuthKeyFor(this._defaultDcs.main.id)
|
|
||||||
|
|
||||||
if ((this._importForce || !defaultDcAuthKey) && this._importFrom) {
|
|
||||||
const data = this._importFrom
|
|
||||||
|
|
||||||
if (data.testMode !== this._testMode) {
|
|
||||||
throw new Error(
|
|
||||||
'This session string is not for the current backend. ' +
|
|
||||||
`Session is ${data.testMode ? 'test' : 'prod'}, but the client is ${
|
|
||||||
this._testMode ? 'test' : 'prod'
|
|
||||||
}`,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
this._defaultDcs = data.primaryDcs
|
|
||||||
await this.storage.setDefaultDcs(data.primaryDcs)
|
|
||||||
|
|
||||||
if (data.self) {
|
|
||||||
await this.storage.setSelf(data.self)
|
|
||||||
}
|
|
||||||
|
|
||||||
// await this.primaryConnection.setupKeys(data.authKey)
|
|
||||||
await this.storage.setAuthKeyFor(data.primaryDcs.main.id, data.authKey)
|
|
||||||
|
|
||||||
await this.saveStorage()
|
|
||||||
}
|
|
||||||
|
|
||||||
this.emit('before_connect')
|
|
||||||
|
|
||||||
this.network
|
|
||||||
.connect(this._defaultDcs)
|
|
||||||
.then(() => {
|
|
||||||
promise.resolve()
|
|
||||||
this._connected = true
|
|
||||||
})
|
|
||||||
.catch((err: Error) => this._emitError(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close all connections and finalize the client.
|
|
||||||
*/
|
|
||||||
async close(): Promise<void> {
|
|
||||||
this.emit('before_close')
|
|
||||||
|
|
||||||
this._config.destroy()
|
|
||||||
this.network.destroy()
|
|
||||||
|
|
||||||
await this.saveStorage()
|
|
||||||
await this.storage.destroy?.()
|
|
||||||
|
|
||||||
this.emit('closed')
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make an RPC call to the primary DC.
|
|
||||||
* This method handles DC migration, flood waits and retries automatically.
|
|
||||||
*
|
|
||||||
* If you want more low-level control, use
|
|
||||||
* `primaryConnection.sendForResult()` (which is what this method wraps)
|
|
||||||
*
|
|
||||||
* This method is still quite low-level and you shouldn't use this
|
|
||||||
* when using high-level API provided by `@mtcute/client`.
|
|
||||||
*
|
|
||||||
* @param message RPC method to call
|
|
||||||
* @param params Additional call parameters
|
|
||||||
*/
|
|
||||||
async call<T extends tl.RpcMethod>(
|
|
||||||
message: MustEqual<T, tl.RpcMethod>,
|
|
||||||
params?: RpcCallOptions,
|
|
||||||
): Promise<tl.RpcCallReturn[T['_']]> {
|
|
||||||
if (this._connected !== true) {
|
|
||||||
await this.connect()
|
|
||||||
}
|
|
||||||
|
|
||||||
const stack = this._niceStacks ? new Error().stack : undefined
|
|
||||||
|
|
||||||
const res = await this.network.call(message, params, stack)
|
|
||||||
|
|
||||||
if (await this._cachePeersFrom(res)) {
|
|
||||||
await this.saveStorage()
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a Proxy that will call all methods with given call parameters
|
|
||||||
* (see {@link RpcCallOptions}})
|
|
||||||
*
|
|
||||||
* This is useful when you don't call `call()` directly, but rather
|
|
||||||
* use high-level API provided by `@mtcute/client`, for example:
|
|
||||||
*
|
|
||||||
* ```ts
|
|
||||||
* const client = new TelegramClient(...)
|
|
||||||
*
|
|
||||||
* const someone = await client
|
|
||||||
* .withCallParams({ timeout: 500 })
|
|
||||||
* .getUsers(...)
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
withCallParams(params: RpcCallOptions): this {
|
|
||||||
return new Proxy(this, {
|
|
||||||
get(target, prop, receiver) {
|
|
||||||
if (prop === 'call') {
|
|
||||||
return (message: tl.RpcMethod, paramsCustom?: RpcCallOptions) =>
|
|
||||||
target.call(message, {
|
|
||||||
...params,
|
|
||||||
...paramsCustom,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return Reflect.get(target, prop, receiver)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shorthand for `withCallParams({ abortSignal })`
|
|
||||||
*/
|
|
||||||
withAbortSignal(signal: AbortSignal): this {
|
|
||||||
return this.withCallParams({ abortSignal: signal })
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change transport for the client.
|
|
||||||
*
|
|
||||||
* Can be used, for example, to change proxy at runtime
|
|
||||||
*
|
|
||||||
* This effectively calls `changeTransport()` on
|
|
||||||
* `primaryConnection` and all additional connections.
|
|
||||||
*
|
|
||||||
* @param factory New transport factory
|
|
||||||
*/
|
|
||||||
changeTransport(factory: TransportFactory): void {
|
|
||||||
this.network.changeTransport(factory)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register an error handler for the client
|
|
||||||
*
|
|
||||||
* @param handler
|
|
||||||
* Error handler. Called with one or two parameters.
|
|
||||||
* The first one is always the error, and the second is
|
|
||||||
* the connection in which the error has occurred, in case
|
|
||||||
* this was connection-related error.
|
|
||||||
*/
|
|
||||||
onError(handler: (err: unknown, connection?: SessionConnection) => void): void {
|
|
||||||
this._emitError = handler
|
|
||||||
}
|
|
||||||
|
|
||||||
notifyLoggedIn(auth: tl.auth.RawAuthorization): void {
|
|
||||||
this.network.notifyLoggedIn(auth)
|
|
||||||
this.emit('logged_in', auth)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* **ADVANCED**
|
|
||||||
*
|
|
||||||
* Adds all peers from a given object to entity cache in storage.
|
|
||||||
*/
|
|
||||||
async _cachePeersFrom(obj: object): Promise<boolean> {
|
|
||||||
const parsedPeers: ITelegramStorage.PeerInfo[] = []
|
|
||||||
|
|
||||||
let count = 0
|
|
||||||
|
|
||||||
for (const peer of getAllPeersFrom(obj as tl.TlObject)) {
|
|
||||||
if ((peer as any).min) {
|
|
||||||
// no point in caching min peers as we can't use them
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
count += 1
|
|
||||||
|
|
||||||
switch (peer._) {
|
|
||||||
case 'user':
|
|
||||||
if (!peer.accessHash) {
|
|
||||||
this.log.warn('received user without access hash: %j', peer)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
parsedPeers.push({
|
|
||||||
id: peer.id,
|
|
||||||
accessHash: peer.accessHash,
|
|
||||||
username: peer.username?.toLowerCase(),
|
|
||||||
phone: peer.phone,
|
|
||||||
type: 'user',
|
|
||||||
full: peer,
|
|
||||||
})
|
|
||||||
break
|
|
||||||
case 'chat':
|
|
||||||
case 'chatForbidden':
|
|
||||||
parsedPeers.push({
|
|
||||||
id: -peer.id,
|
|
||||||
accessHash: Long.ZERO,
|
|
||||||
type: 'chat',
|
|
||||||
full: peer,
|
|
||||||
})
|
|
||||||
break
|
|
||||||
case 'channel':
|
|
||||||
case 'channelForbidden':
|
|
||||||
if (!peer.accessHash) {
|
|
||||||
this.log.warn('received user without access hash: %j', peer)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
parsedPeers.push({
|
|
||||||
id: toggleChannelIdMark(peer.id),
|
|
||||||
accessHash: peer.accessHash,
|
|
||||||
username: peer._ === 'channel' ? peer.username?.toLowerCase() : undefined,
|
|
||||||
type: 'channel',
|
|
||||||
full: peer,
|
|
||||||
})
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count > 0) {
|
|
||||||
await this.storage.updatePeers(parsedPeers)
|
|
||||||
this.log.debug('cached %d peers', count)
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Export current session to a single *LONG* string, containing
|
|
||||||
* all the needed information.
|
|
||||||
*
|
|
||||||
* > **Warning!** Anyone with this string will be able
|
|
||||||
* > to authorize as you and do anything. Treat this
|
|
||||||
* > as your password, and never give it away!
|
|
||||||
* >
|
|
||||||
* > In case you have accidentally leaked this string,
|
|
||||||
* > make sure to revoke this session in account settings:
|
|
||||||
* > "Privacy & Security" > "Active sessions" >
|
|
||||||
* > find the one containing `mtcute` > Revoke,
|
|
||||||
* > or, in case this is a bot, revoke bot token
|
|
||||||
* > with [@BotFather](//t.me/botfather)
|
|
||||||
*/
|
|
||||||
async exportSession(): Promise<string> {
|
|
||||||
const primaryDcs = (await this.storage.getDefaultDcs()) ?? this._defaultDcs
|
|
||||||
|
|
||||||
const authKey = await this.storage.getAuthKeyFor(primaryDcs.main.id)
|
|
||||||
if (!authKey) throw new Error('Auth key is not ready yet')
|
|
||||||
|
|
||||||
return writeStringSession(this._writerMap, {
|
|
||||||
version: 2,
|
|
||||||
self: await this.storage.getSelf(),
|
|
||||||
testMode: this._testMode,
|
|
||||||
primaryDcs,
|
|
||||||
authKey,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Request the session to be imported from the given session string.
|
|
||||||
*
|
|
||||||
* Note that the session will not be imported right away,
|
|
||||||
* instead, it will be imported once `connect()` is called
|
|
||||||
*
|
|
||||||
* Also note that the session will only be imported in case
|
|
||||||
* the storage is missing authorization (i.e. does not contain
|
|
||||||
* auth key for the primary DC), otherwise it will be ignored (unless `force`).
|
|
||||||
*
|
|
||||||
* @param session Session string to import
|
|
||||||
* @param force Whether to overwrite existing session
|
|
||||||
*/
|
|
||||||
importSession(session: string | StringSessionData, force = false): void {
|
|
||||||
this._importFrom = typeof session === 'string' ? readStringSession(this._readerMap, session) : session
|
|
||||||
this._importForce = force
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,173 +0,0 @@
|
||||||
import { tl } from '@mtcute/tl'
|
|
||||||
import { TlReaderMap, TlWriterMap } from '@mtcute/tl-runtime'
|
|
||||||
|
|
||||||
import { NetworkManagerExtraParams, ReconnectionStrategy, TransportFactory } from './network/index.js'
|
|
||||||
import { PersistentConnectionParams } from './network/persistent-connection.js'
|
|
||||||
import { ITelegramStorage } from './storage/abstract.js'
|
|
||||||
import { CryptoProviderFactory } from './utils/index.js'
|
|
||||||
|
|
||||||
/** Options for {@link BaseTelegramClient} */
|
|
||||||
export interface BaseTelegramClientOptions {
|
|
||||||
/**
|
|
||||||
* API ID from my.telegram.org
|
|
||||||
*/
|
|
||||||
apiId: number
|
|
||||||
/**
|
|
||||||
* API hash from my.telegram.org
|
|
||||||
*/
|
|
||||||
apiHash: string
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Storage to use for this client.
|
|
||||||
*/
|
|
||||||
storage: ITelegramStorage
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cryptography provider factory to allow delegating
|
|
||||||
* crypto to native addon, worker, etc.
|
|
||||||
*/
|
|
||||||
crypto?: CryptoProviderFactory
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether to use IPv6 datacenters
|
|
||||||
* (IPv6 will be preferred when choosing a DC by id)
|
|
||||||
* (default: false)
|
|
||||||
*/
|
|
||||||
useIpv6?: boolean
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Primary DC to use for initial connection.
|
|
||||||
* This does not mean this will be the only DC used,
|
|
||||||
* nor that this DC will actually be primary, this only
|
|
||||||
* determines the first DC the library will try to connect to.
|
|
||||||
* Can be used to connect to other networks (like test DCs).
|
|
||||||
*
|
|
||||||
* When session already contains primary DC, this parameter is ignored.
|
|
||||||
*
|
|
||||||
* @default Production DC 2.
|
|
||||||
*/
|
|
||||||
defaultDcs?: ITelegramStorage.DcOptions
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether to connect to test servers.
|
|
||||||
*
|
|
||||||
* If passed, {@link defaultDc} defaults to Test DC 2.
|
|
||||||
*
|
|
||||||
* **Must** be passed if using test servers, even if
|
|
||||||
* you passed custom {@link defaultDc}
|
|
||||||
*/
|
|
||||||
testMode?: boolean
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Additional options for initConnection call.
|
|
||||||
* `apiId` and `query` are not available and will be ignored.
|
|
||||||
* Omitted values will be filled with defaults
|
|
||||||
*/
|
|
||||||
initConnectionOptions?: Partial<Omit<tl.RawInitConnectionRequest, 'apiId' | 'query'>>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transport factory to use in the client.
|
|
||||||
*
|
|
||||||
* @default platform-specific transport: WebSocket on the web, TCP in node
|
|
||||||
*/
|
|
||||||
transport?: TransportFactory
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reconnection strategy.
|
|
||||||
*
|
|
||||||
* @default simple reconnection strategy: first 0ms, then up to 5s (increasing by 1s)
|
|
||||||
*/
|
|
||||||
reconnectionStrategy?: ReconnectionStrategy<PersistentConnectionParams>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maximum duration of a flood_wait that will be waited automatically.
|
|
||||||
* Flood waits above this threshold will throw a FloodWaitError.
|
|
||||||
* Set to 0 to disable. Can be overridden with `throwFlood` parameter in call() params
|
|
||||||
*
|
|
||||||
* @default 10000
|
|
||||||
*/
|
|
||||||
floodSleepThreshold?: number
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maximum number of retries when calling RPC methods.
|
|
||||||
* Call is retried when InternalError or FloodWaitError is encountered.
|
|
||||||
* Can be set to Infinity.
|
|
||||||
*
|
|
||||||
* @default 5
|
|
||||||
*/
|
|
||||||
maxRetryCount?: number
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If true, every single API call will be wrapped with `tl.invokeWithoutUpdates`,
|
|
||||||
* effectively disabling the server-sent events for the clients.
|
|
||||||
* May be useful in some cases.
|
|
||||||
*
|
|
||||||
* Note that this only wraps calls made with `.call()` within the primary
|
|
||||||
* connection. Additional connections and direct `.sendForResult()` calls
|
|
||||||
* must be wrapped manually.
|
|
||||||
*
|
|
||||||
* @default false
|
|
||||||
*/
|
|
||||||
disableUpdates?: boolean
|
|
||||||
|
|
||||||
/**
|
|
||||||
* mtcute can send all unknown RPC errors to [danog](https://github.com/danog)'s
|
|
||||||
* [error reporting service](https://rpc.pwrtelegram.xyz/).
|
|
||||||
*
|
|
||||||
* This is fully anonymous (except maybe IP) and is only used to improve the library
|
|
||||||
* and developer experience for everyone working with MTProto. This is fully opt-in,
|
|
||||||
* and if you're too paranoid, you can disable it by manually passing `enableErrorReporting: false` to the client.
|
|
||||||
*
|
|
||||||
* @default false
|
|
||||||
*/
|
|
||||||
enableErrorReporting?: boolean
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If true, RPC errors will have a stack trace of the initial `.call()`
|
|
||||||
* or `.sendForResult()` call position, which drastically improves
|
|
||||||
* debugging experience.<br>
|
|
||||||
* If false, they will have a stack trace of mtcute internals.
|
|
||||||
*
|
|
||||||
* Internally this creates a stack capture before every RPC call
|
|
||||||
* and stores it until the result is received. This might
|
|
||||||
* use a lot more memory than normal, thus can be disabled here.
|
|
||||||
*
|
|
||||||
* @default true
|
|
||||||
*/
|
|
||||||
niceStacks?: boolean
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extra parameters for {@link NetworkManager}
|
|
||||||
*/
|
|
||||||
network?: NetworkManagerExtraParams
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set logging level for the client.
|
|
||||||
*
|
|
||||||
* See static members of {@link LogManager} for possible values.
|
|
||||||
*/
|
|
||||||
logLevel?: number
|
|
||||||
|
|
||||||
/**
|
|
||||||
* **EXPERT USE ONLY!**
|
|
||||||
*
|
|
||||||
* Override TL layer used for the connection.
|
|
||||||
*
|
|
||||||
* **Does not** change the schema used.
|
|
||||||
*/
|
|
||||||
overrideLayer?: number
|
|
||||||
|
|
||||||
/**
|
|
||||||
* **EXPERT USE ONLY**
|
|
||||||
*
|
|
||||||
* Override reader map used for the connection.
|
|
||||||
*/
|
|
||||||
readerMap?: TlReaderMap
|
|
||||||
|
|
||||||
/**
|
|
||||||
* **EXPERT USE ONLY**
|
|
||||||
*
|
|
||||||
* Override writer map used for the connection.
|
|
||||||
*/
|
|
||||||
writerMap?: TlWriterMap
|
|
||||||
}
|
|
297
packages/core/src/highlevel/base.ts
Normal file
297
packages/core/src/highlevel/base.ts
Normal file
|
@ -0,0 +1,297 @@
|
||||||
|
/* eslint-disable @typescript-eslint/require-await */
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { MtClient, MtClientOptions } from '../network/client.js'
|
||||||
|
import { ConnectionKind, RpcCallOptions } from '../network/network-manager.js'
|
||||||
|
import { StorageManagerExtraOptions } from '../storage/storage.js'
|
||||||
|
import { MtArgumentError } from '../types/errors.js'
|
||||||
|
import { MustEqual } from '../types/utils.js'
|
||||||
|
import {
|
||||||
|
asyncResettable,
|
||||||
|
computeNewPasswordHash,
|
||||||
|
computeSrpParams,
|
||||||
|
readStringSession,
|
||||||
|
StringSessionData,
|
||||||
|
writeStringSession,
|
||||||
|
} from '../utils/index.js'
|
||||||
|
import { LogManager } from '../utils/logger.js'
|
||||||
|
import { ITelegramClient } from './client.types.js'
|
||||||
|
import { ITelegramStorageProvider } from './storage/provider.js'
|
||||||
|
import { TelegramStorageManager, TelegramStorageManagerExtraOptions } from './storage/storage.js'
|
||||||
|
import { UpdatesManager } from './updates/manager.js'
|
||||||
|
import { RawUpdateHandler, UpdatesManagerParams } from './updates/types.js'
|
||||||
|
|
||||||
|
export interface BaseTelegramClientOptions extends MtClientOptions {
|
||||||
|
storage: ITelegramStorageProvider
|
||||||
|
storageOptions?: StorageManagerExtraOptions & TelegramStorageManagerExtraOptions
|
||||||
|
updates?: UpdatesManagerParams | false
|
||||||
|
}
|
||||||
|
|
||||||
|
export class BaseTelegramClient implements ITelegramClient {
|
||||||
|
readonly updates?: UpdatesManager
|
||||||
|
private _serverUpdatesHandler: (updates: tl.TypeUpdates) => void = () => {}
|
||||||
|
|
||||||
|
constructor(readonly params: BaseTelegramClientOptions) {
|
||||||
|
if (!params.disableUpdates && params.updates !== false) {
|
||||||
|
this.updates = new UpdatesManager(this, params.updates)
|
||||||
|
this._serverUpdatesHandler = this.updates.handleUpdate.bind(this.updates)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mt.on('update', (update: tl.TypeUpdates) => {
|
||||||
|
this._serverUpdatesHandler(update)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly log = this.params.logger ?? new LogManager('client')
|
||||||
|
readonly mt = new MtClient({
|
||||||
|
...this.params,
|
||||||
|
logger: this.log.create('mtproto'),
|
||||||
|
})
|
||||||
|
readonly crypto = this.mt.crypto
|
||||||
|
readonly storage = new TelegramStorageManager(this.mt.storage, {
|
||||||
|
provider: this.params.storage,
|
||||||
|
...this.params.storageOptions,
|
||||||
|
})
|
||||||
|
|
||||||
|
private _prepare = asyncResettable(async () => {
|
||||||
|
await this.mt.prepare()
|
||||||
|
|
||||||
|
const self = await this.storage.self.fetch()
|
||||||
|
this.log.prefix = `[USER ${self?.userId ?? 'n/a'}] `
|
||||||
|
this.mt.network.setIsPremium(self?.isPremium ?? false)
|
||||||
|
|
||||||
|
await this.updates?.prepare()
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* **ADVANCED**
|
||||||
|
*
|
||||||
|
* Do all the preparations, but don't connect just yet.
|
||||||
|
* Useful when you want to do some preparations before
|
||||||
|
* connecting, like setting up session.
|
||||||
|
*
|
||||||
|
* Call {@link connect} to actually connect.
|
||||||
|
*/
|
||||||
|
prepare() {
|
||||||
|
return this._prepare.run()
|
||||||
|
}
|
||||||
|
|
||||||
|
// used in a hot path, avoid extra function calls
|
||||||
|
private _connected = false
|
||||||
|
private _connect = asyncResettable(async () => {
|
||||||
|
await this._prepare.run()
|
||||||
|
await this.mt.connect()
|
||||||
|
this._connected = true
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the connection to the primary DC.
|
||||||
|
*
|
||||||
|
* You shouldn't usually call this method directly as it is called
|
||||||
|
* implicitly the first time you call {@link call}.
|
||||||
|
*/
|
||||||
|
async connect(): Promise<void> {
|
||||||
|
return this._connect.run()
|
||||||
|
}
|
||||||
|
|
||||||
|
get isConnected(): boolean {
|
||||||
|
return this._connected
|
||||||
|
}
|
||||||
|
|
||||||
|
async close(): Promise<void> {
|
||||||
|
await this.mt.close()
|
||||||
|
this.updates?.stopLoop()
|
||||||
|
this._prepare.reset()
|
||||||
|
this._connect.reset()
|
||||||
|
this._connected = false
|
||||||
|
}
|
||||||
|
|
||||||
|
async notifyLoggedIn(auth: tl.auth.TypeAuthorization | tl.RawUser): Promise<tl.RawUser> {
|
||||||
|
const user = this.mt.network.notifyLoggedIn(auth)
|
||||||
|
|
||||||
|
this.log.prefix = `[USER ${user.id}] `
|
||||||
|
const self = await this.storage.self.storeFrom(user)
|
||||||
|
|
||||||
|
this.updates?.notifyLoggedIn(self)
|
||||||
|
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
|
||||||
|
async notifyLoggedOut(): Promise<void> {
|
||||||
|
this.mt.network.notifyLoggedOut()
|
||||||
|
|
||||||
|
this.log.prefix = '[USER n/a] '
|
||||||
|
await this.storage.self.store(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
async notifyChannelOpened(channelId: number, pts?: number): Promise<boolean> {
|
||||||
|
return this.updates?.notifyChannelOpened(channelId, pts) ?? false
|
||||||
|
}
|
||||||
|
|
||||||
|
async notifyChannelClosed(channelId: number): Promise<boolean> {
|
||||||
|
return this.updates?.notifyChannelClosed(channelId) ?? false
|
||||||
|
}
|
||||||
|
|
||||||
|
async startUpdatesLoop(): Promise<void> {
|
||||||
|
await this.updates?.startLoop()
|
||||||
|
}
|
||||||
|
|
||||||
|
async stopUpdatesLoop(): Promise<void> {
|
||||||
|
this.updates?.stopLoop()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make an RPC call
|
||||||
|
*
|
||||||
|
* This method is still quite low-level and you shouldn't use this
|
||||||
|
* when using high-level API provided by `@mtcute/client`.
|
||||||
|
*
|
||||||
|
* @param message RPC method to call
|
||||||
|
* @param params Additional call parameters
|
||||||
|
*/
|
||||||
|
async call<T extends tl.RpcMethod>(
|
||||||
|
message: MustEqual<T, tl.RpcMethod>,
|
||||||
|
params?: RpcCallOptions,
|
||||||
|
): Promise<tl.RpcCallReturn[T['_']]> {
|
||||||
|
if (!this._connected) {
|
||||||
|
await this._connect.run()
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await this.mt.call(message, params)
|
||||||
|
|
||||||
|
await this.storage.peers.updatePeersFrom(res)
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import the session from the given session string.
|
||||||
|
*
|
||||||
|
* Note that the session will only be imported in case
|
||||||
|
* the storage is missing authorization (i.e. does not contain
|
||||||
|
* auth key for the primary DC), otherwise it will be ignored (unless `force`).
|
||||||
|
*
|
||||||
|
* @param session Session string to import
|
||||||
|
* @param force Whether to overwrite existing session
|
||||||
|
*/
|
||||||
|
async importSession(session: string | StringSessionData, force = false): Promise<void> {
|
||||||
|
await this.prepare()
|
||||||
|
|
||||||
|
const defaultDcAuthKey = await this.mt.storage.provider.authKeys.get(this.mt._defaultDcs.main.id)
|
||||||
|
|
||||||
|
if (defaultDcAuthKey && !force) return
|
||||||
|
|
||||||
|
const data = typeof session === 'string' ? readStringSession(this.mt._readerMap, session) : session
|
||||||
|
|
||||||
|
if (data.testMode && !this.params.testMode) {
|
||||||
|
throw new Error(
|
||||||
|
'This session string is not for the current backend. ' +
|
||||||
|
`Session is ${data.testMode ? 'test' : 'prod'}, ` +
|
||||||
|
`but the client is ${this.params.testMode ? 'test' : 'prod'}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mt._defaultDcs = data.primaryDcs
|
||||||
|
await this.mt.storage.dcs.store(data.primaryDcs)
|
||||||
|
|
||||||
|
if (data.self) {
|
||||||
|
await this.storage.self.store(data.self)
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.mt.storage.provider.authKeys.set(data.primaryDcs.main.id, data.authKey)
|
||||||
|
|
||||||
|
await this.mt.storage.save()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export current session to a single *LONG* string, containing
|
||||||
|
* all the needed information.
|
||||||
|
*
|
||||||
|
* > **Warning!** Anyone with this string will be able
|
||||||
|
* > to authorize as you and do anything. Treat this
|
||||||
|
* > as your password, and never give it away!
|
||||||
|
* >
|
||||||
|
* > In case you have accidentally leaked this string,
|
||||||
|
* > make sure to revoke this session in account settings:
|
||||||
|
* > "Privacy & Security" > "Active sessions" >
|
||||||
|
* > find the one containing `mtcute` > Revoke,
|
||||||
|
* > or, in case this is a bot, revoke bot token
|
||||||
|
* > with [@BotFather](//t.me/botfather)
|
||||||
|
*/
|
||||||
|
async exportSession(): Promise<string> {
|
||||||
|
await this._prepare.run()
|
||||||
|
|
||||||
|
const primaryDcs = (await this.mt.storage.dcs.fetch()) ?? this.mt._defaultDcs
|
||||||
|
|
||||||
|
const authKey = await this.mt.storage.provider.authKeys.get(primaryDcs.main.id)
|
||||||
|
if (!authKey) throw new Error('Auth key is not ready yet')
|
||||||
|
|
||||||
|
return writeStringSession(this.mt._writerMap, {
|
||||||
|
version: 2,
|
||||||
|
self: await this.storage.self.fetch(),
|
||||||
|
testMode: Boolean(this.params.testMode),
|
||||||
|
primaryDcs,
|
||||||
|
authKey,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register an error handler for the client
|
||||||
|
*
|
||||||
|
* @param handler Error handler.
|
||||||
|
*/
|
||||||
|
onError(handler: (err: unknown) => void): void {
|
||||||
|
this.mt.onError(handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
emitError(err: unknown): void {
|
||||||
|
this.mt.emitError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClientUpdate(updates: tl.TypeUpdates, noDispatch?: boolean): void {
|
||||||
|
this.updates?.handleClientUpdate(updates, noDispatch)
|
||||||
|
}
|
||||||
|
|
||||||
|
onServerUpdate(handler: (update: tl.TypeUpdates) => void): void {
|
||||||
|
this._serverUpdatesHandler = handler
|
||||||
|
}
|
||||||
|
|
||||||
|
onUpdate(handler: RawUpdateHandler): void {
|
||||||
|
if (!this.updates) {
|
||||||
|
throw new MtArgumentError('Updates manager is disabled')
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updates.setHandler(handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
async getApiCrenetials() {
|
||||||
|
return {
|
||||||
|
id: this.params.apiId,
|
||||||
|
hash: this.params.apiHash,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getPoolSize(kind: ConnectionKind, dcId?: number): Promise<number> {
|
||||||
|
if (!this._connected) {
|
||||||
|
await this._connect.run()
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.mt.network.getPoolSize(kind, dcId)
|
||||||
|
}
|
||||||
|
|
||||||
|
async getPrimaryDcId(): Promise<number> {
|
||||||
|
if (!this._connected) {
|
||||||
|
await this._connect.run()
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.mt.network.getPrimaryDcId()
|
||||||
|
}
|
||||||
|
|
||||||
|
computeSrpParams(request: tl.account.RawPassword, password: string): Promise<tl.RawInputCheckPasswordSRP> {
|
||||||
|
return computeSrpParams(this.crypto, request, password)
|
||||||
|
}
|
||||||
|
computeNewPasswordHash(algo: tl.TypePasswordKdfAlgo, password: string): Promise<Uint8Array> {
|
||||||
|
return computeNewPasswordHash(this.crypto, algo, password)
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load diff
49
packages/core/src/highlevel/client.types.ts
Normal file
49
packages/core/src/highlevel/client.types.ts
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import type { ConnectionKind, RpcCallOptions } from '../network/index.js'
|
||||||
|
import type { MustEqual, PublicPart } from '../types/utils.js'
|
||||||
|
import type { Logger } from '../utils/logger.js'
|
||||||
|
import type { StringSessionData } from '../utils/string-session.js'
|
||||||
|
import type { TelegramStorageManager } from './storage/storage.js'
|
||||||
|
import type { RawUpdateHandler } from './updates/types.js'
|
||||||
|
|
||||||
|
// NB: when adding new methods, don't forget to add them to:
|
||||||
|
// - worker/port.ts
|
||||||
|
// - generate-client script
|
||||||
|
|
||||||
|
export interface ITelegramClient {
|
||||||
|
readonly log: Logger
|
||||||
|
readonly storage: PublicPart<TelegramStorageManager>
|
||||||
|
|
||||||
|
prepare(): Promise<void>
|
||||||
|
connect(): Promise<void>
|
||||||
|
close(): Promise<void>
|
||||||
|
notifyLoggedIn(auth: tl.auth.TypeAuthorization | tl.RawUser): Promise<tl.RawUser>
|
||||||
|
notifyLoggedOut(): Promise<void>
|
||||||
|
notifyChannelOpened(channelId: number, pts?: number): Promise<boolean>
|
||||||
|
notifyChannelClosed(channelId: number): Promise<boolean>
|
||||||
|
startUpdatesLoop(): Promise<void>
|
||||||
|
stopUpdatesLoop(): Promise<void>
|
||||||
|
call<T extends tl.RpcMethod>(
|
||||||
|
message: MustEqual<T, tl.RpcMethod>,
|
||||||
|
params?: RpcCallOptions,
|
||||||
|
): Promise<tl.RpcCallReturn[T['_']]>
|
||||||
|
importSession(session: string | StringSessionData, force?: boolean): Promise<void>
|
||||||
|
exportSession(): Promise<string>
|
||||||
|
onError(handler: (err: unknown) => void): void
|
||||||
|
emitError(err: unknown): void
|
||||||
|
handleClientUpdate(updates: tl.TypeUpdates, noDispatch?: boolean): void
|
||||||
|
|
||||||
|
onServerUpdate(handler: (update: tl.TypeUpdates) => void): void
|
||||||
|
onUpdate(handler: RawUpdateHandler): void
|
||||||
|
|
||||||
|
getApiCrenetials(): Promise<{ id: number; hash: string }>
|
||||||
|
// todo - this is only used for file dl/ul, which should probably be moved
|
||||||
|
// to the client to allow moving the thing to worker
|
||||||
|
// or at least load this once at startup (and then these methods can be made sync)
|
||||||
|
getPoolSize(kind: ConnectionKind, dcId?: number): Promise<number>
|
||||||
|
getPrimaryDcId(): Promise<number>
|
||||||
|
|
||||||
|
computeSrpParams(request: tl.account.RawPassword, password: string): Promise<tl.RawInputCheckPasswordSRP>
|
||||||
|
computeNewPasswordHash(algo: tl.TypePasswordKdfAlgo, password: string): Promise<Uint8Array>
|
||||||
|
}
|
6
packages/core/src/highlevel/index.ts
Normal file
6
packages/core/src/highlevel/index.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
export * from './base.js'
|
||||||
|
export * from './client.js'
|
||||||
|
export * from './client.types.js'
|
||||||
|
export * from './storage/index.js'
|
||||||
|
export * from './types/index.js'
|
||||||
|
export * from './updates/index.js'
|
|
@ -57,7 +57,7 @@ Example:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// @initialize
|
// @initialize
|
||||||
function _initializeAwesomeExtension(client: BaseTelegramClient) {
|
function _initializeAwesomeExtension(client: ITelegramClient) {
|
||||||
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(client: BaseTelegramClient): FooOrBar {
|
export function getFooOrBar(client: ITelegramClient): FooOrBar {
|
||||||
return new Foo()
|
return new Foo()
|
||||||
}
|
}
|
||||||
```
|
```
|
|
@ -1,19 +1,18 @@
|
||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
// @copy
|
|
||||||
import {
|
|
||||||
BaseTelegramClient,
|
|
||||||
BaseTelegramClientOptions,
|
|
||||||
ITelegramStorage,
|
|
||||||
Long,
|
|
||||||
MaybeArray,
|
|
||||||
MaybeAsync,
|
|
||||||
PartialExcept,
|
|
||||||
PartialOnly,
|
|
||||||
tl,
|
|
||||||
} from '@mtcute/core'
|
|
||||||
// @copy
|
// @copy
|
||||||
import { tdFileId } from '@mtcute/file-id'
|
import { tdFileId } from '@mtcute/file-id'
|
||||||
|
// @copy
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
// @copy
|
||||||
|
import { MaybeArray, MaybePromise, PartialExcept, PartialOnly } from '../../types/index.js'
|
||||||
|
// @copy
|
||||||
|
import { StringSessionData } from '../../utils/string-session.js'
|
||||||
|
// @copy
|
||||||
|
import { BaseTelegramClient, BaseTelegramClientOptions } from '../base.js'
|
||||||
|
// @copy
|
||||||
|
import { ITelegramClient } from '../client.types.js'
|
||||||
// @copy
|
// @copy
|
||||||
import {
|
import {
|
||||||
AllStories,
|
AllStories,
|
97
packages/core/src/highlevel/methods/_init.ts
Normal file
97
packages/core/src/highlevel/methods/_init.ts
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
|
|
||||||
|
// @copy
|
||||||
|
import { MemoryStorage } from '../../storage/providers/memory/index.js'
|
||||||
|
import { BaseTelegramClient, BaseTelegramClientOptions } from '../base.js'
|
||||||
|
import { TelegramClient } from '../client.js'
|
||||||
|
import { ITelegramClient } from '../client.types.js'
|
||||||
|
// @copy
|
||||||
|
import { ITelegramStorageProvider } from '../storage/provider.js'
|
||||||
|
// @copy
|
||||||
|
import { Conversation } from '../types/conversation.js'
|
||||||
|
// @copy
|
||||||
|
import { makeParsedUpdateHandler, ParsedUpdateHandlerParams } from '../updates/parsed.js'
|
||||||
|
// @copy
|
||||||
|
import { _defaultStorageFactory } from '../utils/platform/storage.js'
|
||||||
|
|
||||||
|
// @copy
|
||||||
|
type TelegramClientOptions = ((Omit<BaseTelegramClientOptions, 'storage'> & {
|
||||||
|
/**
|
||||||
|
* Storage to use for this client.
|
||||||
|
*
|
||||||
|
* If a string is passed, it will be used as:
|
||||||
|
* - a path to a JSON file for Node.js
|
||||||
|
* - IndexedDB database name for browsers
|
||||||
|
*
|
||||||
|
* If omitted, {@link MemoryStorage} is used
|
||||||
|
*/
|
||||||
|
storage?: string | ITelegramStorageProvider
|
||||||
|
}) | ({ client: ITelegramClient })) & {
|
||||||
|
updates?: Omit<ParsedUpdateHandlerParams, 'onUpdate'>
|
||||||
|
/**
|
||||||
|
* If `true`, the updates that were handled by some {@link Conversation}
|
||||||
|
* will not be dispatched any further.
|
||||||
|
*
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
|
skipConversationUpdates?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
// // @initialize=super
|
||||||
|
// /** @internal */
|
||||||
|
// function _initializeClientSuper(this: TelegramClient, opts: TelegramClientOptions) {
|
||||||
|
// if (typeof opts.storage === 'string') {
|
||||||
|
// opts.storage = _defaultStorageFactory(opts.storage)
|
||||||
|
// } else if (!opts.storage) {
|
||||||
|
// opts.storage = new MemoryStorage()
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||||
|
// // @ts-expect-error codegen
|
||||||
|
// super(opts)
|
||||||
|
// /* eslint-enable @typescript-eslint/no-unsafe-call */
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @initialize
|
||||||
|
/** @internal */
|
||||||
|
function _initializeClient(this: TelegramClient, opts: TelegramClientOptions) {
|
||||||
|
if ('client' in opts) {
|
||||||
|
this._client = opts.client
|
||||||
|
} else {
|
||||||
|
let storage: ITelegramStorageProvider
|
||||||
|
|
||||||
|
if (typeof opts.storage === 'string') {
|
||||||
|
storage = _defaultStorageFactory(opts.storage)
|
||||||
|
} else if (!opts.storage) {
|
||||||
|
storage = new MemoryStorage()
|
||||||
|
} else {
|
||||||
|
storage = opts.storage
|
||||||
|
}
|
||||||
|
|
||||||
|
this._client = new BaseTelegramClient({
|
||||||
|
...opts,
|
||||||
|
storage,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ts-expect-error codegen
|
||||||
|
this.log = this._client.log
|
||||||
|
// @ts-expect-error codegen
|
||||||
|
this.storage = this._client.storage
|
||||||
|
|
||||||
|
const skipConversationUpdates = opts.skipConversationUpdates ?? true
|
||||||
|
const { messageGroupingInterval } = opts.updates ?? {}
|
||||||
|
|
||||||
|
this._client.onUpdate(makeParsedUpdateHandler({
|
||||||
|
messageGroupingInterval,
|
||||||
|
onUpdate: (update) => {
|
||||||
|
if (Conversation.handleUpdate(this._client, update) && skipConversationUpdates) return
|
||||||
|
|
||||||
|
this.emit('update', update)
|
||||||
|
this.emit(update.name, update.data)
|
||||||
|
},
|
||||||
|
onRawUpdate: (update, peers) => {
|
||||||
|
this.emit('raw_update', update, peers)
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
}
|
|
@ -1,8 +1,6 @@
|
||||||
import { BaseTelegramClient } from '@mtcute/core'
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { computeSrpParams } from '@mtcute/core/utils.js'
|
|
||||||
|
|
||||||
import { User } from '../../types/index.js'
|
import { User } from '../../types/index.js'
|
||||||
import { _onAuthorization } from './_state.js'
|
import { _onAuthorization } from './utils.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check your Two-Step verification password and log in
|
* Check your Two-Step verification password and log in
|
||||||
|
@ -11,11 +9,10 @@ import { _onAuthorization } from './_state.js'
|
||||||
* @returns The authorized user
|
* @returns The authorized user
|
||||||
* @throws BadRequestError In case the password is invalid
|
* @throws BadRequestError In case the password is invalid
|
||||||
*/
|
*/
|
||||||
export async function checkPassword(client: BaseTelegramClient, password: string): Promise<User> {
|
export async function checkPassword(client: ITelegramClient, password: string): Promise<User> {
|
||||||
const res = await client.call({
|
const res = await client.call({
|
||||||
_: 'auth.checkPassword',
|
_: 'auth.checkPassword',
|
||||||
password: await computeSrpParams(
|
password: await client.computeSrpParams(
|
||||||
client.crypto,
|
|
||||||
await client.call({
|
await client.call({
|
||||||
_: 'account.getPassword',
|
_: 'account.getPassword',
|
||||||
}),
|
}),
|
|
@ -1,11 +1,11 @@
|
||||||
import { BaseTelegramClient } from '@mtcute/core'
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
*/
|
*/
|
||||||
export function getPasswordHint(client: BaseTelegramClient): Promise<string | null> {
|
export function getPasswordHint(client: ITelegramClient): Promise<string | null> {
|
||||||
return client
|
return client
|
||||||
.call({
|
.call({
|
||||||
_: 'account.getPassword',
|
_: 'account.getPassword',
|
16
packages/core/src/highlevel/methods/auth/log-out.ts
Normal file
16
packages/core/src/highlevel/methods/auth/log-out.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log out from Telegram account and optionally reset the session storage.
|
||||||
|
*
|
||||||
|
* When you log out, you can immediately log back in using
|
||||||
|
* the same {@link TelegramClient} instance.
|
||||||
|
*
|
||||||
|
* @returns On success, `true` is returned
|
||||||
|
*/
|
||||||
|
export async function logOut(client: ITelegramClient): Promise<true> {
|
||||||
|
await client.call({ _: 'auth.logOut' })
|
||||||
|
await client.notifyLoggedOut()
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
import { BaseTelegramClient } from '@mtcute/core'
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
|
||||||
import { User } from '../../types/index.js'
|
import { User } from '../../types/index.js'
|
||||||
import { _onAuthorization } from './_state.js'
|
import { _onAuthorization } from './utils.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recover your password with a recovery code and log in.
|
* Recover your password with a recovery code and log in.
|
||||||
|
@ -10,7 +9,7 @@ import { _onAuthorization } from './_state.js'
|
||||||
* @throws BadRequestError In case the code is invalid
|
* @throws BadRequestError In case the code is invalid
|
||||||
*/
|
*/
|
||||||
export async function recoverPassword(
|
export async function recoverPassword(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
params: {
|
params: {
|
||||||
/** The recovery code sent via email */
|
/** The recovery code sent via email */
|
||||||
recoveryCode: string
|
recoveryCode: string
|
|
@ -1,7 +1,6 @@
|
||||||
import { BaseTelegramClient } from '@mtcute/core'
|
import { assertTypeIs } from '../../../utils/type-assertions.js'
|
||||||
import { assertTypeIs } from '@mtcute/core/utils.js'
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
import { SentCode } from '../../types/auth/sent-code.js'
|
||||||
import { SentCode } from '../../types/index.js'
|
|
||||||
import { normalizePhoneNumber } from '../../utils/misc-utils.js'
|
import { normalizePhoneNumber } from '../../utils/misc-utils.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -11,7 +10,7 @@ import { normalizePhoneNumber } from '../../utils/misc-utils.js'
|
||||||
* {@link SentCode} object returned by {@link sendCode}
|
* {@link SentCode} object returned by {@link sendCode}
|
||||||
*/
|
*/
|
||||||
export async function resendCode(
|
export async function resendCode(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
params: {
|
params: {
|
||||||
/** Phone number in international format */
|
/** Phone number in international format */
|
||||||
phone: string
|
phone: string
|
|
@ -1,6 +1,4 @@
|
||||||
import { BaseTelegramClient } from '@mtcute/core'
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
|
||||||
import { TelegramClient } from '../../index.js'
|
|
||||||
import { User } from '../../types/index.js'
|
import { User } from '../../types/index.js'
|
||||||
import { start } from './start.js'
|
import { start } from './start.js'
|
||||||
|
|
||||||
|
@ -14,22 +12,13 @@ import { start } from './start.js'
|
||||||
*
|
*
|
||||||
* @param params Parameters to be passed to {@link start}
|
* @param params Parameters to be passed to {@link start}
|
||||||
* @param then Function to be called after {@link start} returns
|
* @param then Function to be called after {@link start} returns
|
||||||
* @manual=noemit
|
|
||||||
*/
|
*/
|
||||||
export function run(
|
export function run(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
params: Parameters<typeof start>[1],
|
params: Parameters<typeof start>[1],
|
||||||
then?: (user: User) => void | Promise<void>,
|
then?: (user: User) => void | Promise<void>,
|
||||||
): void {
|
): void {
|
||||||
start(client, params)
|
start(client, params)
|
||||||
.then(then)
|
.then(then)
|
||||||
.catch((err) => client._emitError(err))
|
.catch((err) => client.emitError(err))
|
||||||
}
|
|
||||||
|
|
||||||
// @manual-impl=run
|
|
||||||
/** @internal */
|
|
||||||
function _run(this: TelegramClient, params: Parameters<typeof start>[1], then?: (user: User) => void | Promise<void>) {
|
|
||||||
this.start(params)
|
|
||||||
.then(then)
|
|
||||||
.catch((err) => this._emitError(err))
|
|
||||||
}
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
import { BaseTelegramClient } from '@mtcute/core'
|
import { assertTypeIs } from '../../../utils/type-assertions.js'
|
||||||
import { assertTypeIs } from '@mtcute/core/utils.js'
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
import { SentCode } from '../../types/auth/sent-code.js'
|
||||||
import { SentCode } from '../../types/index.js'
|
|
||||||
import { normalizePhoneNumber } from '../../utils/misc-utils.js'
|
import { normalizePhoneNumber } from '../../utils/misc-utils.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -10,7 +9,7 @@ import { normalizePhoneNumber } from '../../utils/misc-utils.js'
|
||||||
* @returns An object containing information about the sent confirmation code
|
* @returns An object containing information about the sent confirmation code
|
||||||
*/
|
*/
|
||||||
export async function sendCode(
|
export async function sendCode(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
params: {
|
params: {
|
||||||
/** Phone number in international format */
|
/** Phone number in international format */
|
||||||
phone: string
|
phone: string
|
||||||
|
@ -18,11 +17,13 @@ export async function sendCode(
|
||||||
): Promise<SentCode> {
|
): Promise<SentCode> {
|
||||||
const phone = normalizePhoneNumber(params.phone)
|
const phone = normalizePhoneNumber(params.phone)
|
||||||
|
|
||||||
|
const { id, hash } = await client.getApiCrenetials()
|
||||||
|
|
||||||
const res = await client.call({
|
const res = await client.call({
|
||||||
_: 'auth.sendCode',
|
_: 'auth.sendCode',
|
||||||
phoneNumber: phone,
|
phoneNumber: phone,
|
||||||
apiId: client.params.apiId,
|
apiId: id,
|
||||||
apiHash: client.params.apiHash,
|
apiHash: hash,
|
||||||
settings: { _: 'codeSettings' },
|
settings: { _: 'codeSettings' },
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import { BaseTelegramClient } from '@mtcute/core'
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
*/
|
*/
|
||||||
export function sendRecoveryCode(client: BaseTelegramClient): Promise<string> {
|
export function sendRecoveryCode(client: ITelegramClient): Promise<string> {
|
||||||
return client
|
return client
|
||||||
.call({
|
.call({
|
||||||
_: 'auth.requestPasswordRecovery',
|
_: 'auth.requestPasswordRecovery',
|
24
packages/core/src/highlevel/methods/auth/sign-in-bot.ts
Normal file
24
packages/core/src/highlevel/methods/auth/sign-in-bot.ts
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
import { User } from '../../types/peers/user.js'
|
||||||
|
import { _onAuthorization } from './utils.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authorize a bot using its token issued by [@BotFather](//t.me/BotFather)
|
||||||
|
*
|
||||||
|
* @param token Bot token issued by BotFather
|
||||||
|
* @returns Bot's {@link User} object
|
||||||
|
* @throws BadRequestError In case the bot token is invalid
|
||||||
|
*/
|
||||||
|
export async function signInBot(client: ITelegramClient, token: string): Promise<User> {
|
||||||
|
const { id, hash } = await client.getApiCrenetials()
|
||||||
|
|
||||||
|
const res = await client.call({
|
||||||
|
_: 'auth.importBotAuthorization',
|
||||||
|
flags: 0,
|
||||||
|
apiId: id,
|
||||||
|
apiHash: hash,
|
||||||
|
botAuthToken: token,
|
||||||
|
})
|
||||||
|
|
||||||
|
return _onAuthorization(client, res)
|
||||||
|
}
|
|
@ -1,8 +1,7 @@
|
||||||
import { BaseTelegramClient } from '@mtcute/core'
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
import { User } from '../../types/peers/user.js'
|
||||||
import { User } from '../../types/index.js'
|
|
||||||
import { normalizePhoneNumber } from '../../utils/misc-utils.js'
|
import { normalizePhoneNumber } from '../../utils/misc-utils.js'
|
||||||
import { _onAuthorization } from './_state.js'
|
import { _onAuthorization } from './utils.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authorize a user in Telegram with a valid confirmation code.
|
* Authorize a user in Telegram with a valid confirmation code.
|
||||||
|
@ -12,7 +11,7 @@ import { _onAuthorization } from './_state.js'
|
||||||
* @throws SessionPasswordNeededError In case a password is needed to sign in
|
* @throws SessionPasswordNeededError In case a password is needed to sign in
|
||||||
*/
|
*/
|
||||||
export async function signIn(
|
export async function signIn(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
params: {
|
params: {
|
||||||
/** Phone number in international format */
|
/** Phone number in international format */
|
||||||
phone: string
|
phone: string
|
|
@ -1,5 +1,5 @@
|
||||||
import { BaseTelegramClient, MtArgumentError } from '@mtcute/core'
|
import { MtArgumentError } from '../../../types/errors.js'
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { User } from '../../types/index.js'
|
import { User } from '../../types/index.js'
|
||||||
import { logOut } from './log-out.js'
|
import { logOut } from './log-out.js'
|
||||||
import { start } from './start.js'
|
import { start } from './start.js'
|
||||||
|
@ -15,7 +15,7 @@ import { start } from './start.js'
|
||||||
* @param params Additional parameters
|
* @param params Additional parameters
|
||||||
*/
|
*/
|
||||||
export async function startTest(
|
export async function startTest(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
params?: {
|
params?: {
|
||||||
/**
|
/**
|
||||||
* Whether to log out if current session is logged in.
|
* Whether to log out if current session is logged in.
|
||||||
|
@ -63,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 = client.network.getPrimaryDcId()
|
let dcId = await client.getPrimaryDcId()
|
||||||
|
|
||||||
if (params.dcId) {
|
if (params.dcId) {
|
||||||
if (!availableDcs.find((dc) => dc.id === params!.dcId)) {
|
if (!availableDcs.find((dc) => dc.id === params!.dcId)) {
|
|
@ -1,8 +1,13 @@
|
||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
import { BaseTelegramClient, MaybeAsync, MtArgumentError, tl } from '@mtcute/core'
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
import type { TelegramClient } from '../../client.js'
|
import { MtArgumentError } from '../../../types/errors.js'
|
||||||
import { MaybeDynamic, SentCode, User } from '../../types/index.js'
|
import { MaybePromise } from '../../../types/utils.js'
|
||||||
|
import { StringSessionData } from '../../../utils/string-session.js'
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
import { SentCode } from '../../types/auth/sent-code.js'
|
||||||
|
import { User } from '../../types/peers/user.js'
|
||||||
|
import { MaybeDynamic } from '../../types/utils.js'
|
||||||
import { normalizePhoneNumber, resolveMaybeDynamic } from '../../utils/misc-utils.js'
|
import { normalizePhoneNumber, resolveMaybeDynamic } from '../../utils/misc-utils.js'
|
||||||
import { getMe } from '../users/get-me.js'
|
import { getMe } from '../users/get-me.js'
|
||||||
import { checkPassword } from './check-password.js'
|
import { checkPassword } from './check-password.js'
|
||||||
|
@ -11,7 +16,6 @@ import { sendCode } from './send-code.js'
|
||||||
import { signIn } from './sign-in.js'
|
import { signIn } from './sign-in.js'
|
||||||
import { signInBot } from './sign-in-bot.js'
|
import { signInBot } from './sign-in-bot.js'
|
||||||
|
|
||||||
// @manual
|
|
||||||
// @available=both
|
// @available=both
|
||||||
/**
|
/**
|
||||||
* Start the client in an interactive and declarative manner,
|
* Start the client in an interactive and declarative manner,
|
||||||
|
@ -20,14 +24,14 @@ import { signInBot } from './sign-in-bot.js'
|
||||||
* This method handles both login and sign up, and also handles 2FV
|
* This method handles both login and sign up, and also handles 2FV
|
||||||
*
|
*
|
||||||
* All parameters are `MaybeDynamic<T>`, meaning you
|
* All parameters are `MaybeDynamic<T>`, meaning you
|
||||||
* can either supply `T`, or a function that returns `MaybeAsync<T>`
|
* can either supply `T`, or a function that returns `MaybePromise<T>`
|
||||||
*
|
*
|
||||||
* 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.
|
||||||
*/
|
*/
|
||||||
export async function start(
|
export async function start(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
params: {
|
params: {
|
||||||
/**
|
/**
|
||||||
* String session exported using {@link TelegramClient.exportSession}.
|
* String session exported using {@link TelegramClient.exportSession}.
|
||||||
|
@ -37,7 +41,7 @@ export async function start(
|
||||||
* Note that passed session will be ignored in case storage already
|
* Note that passed session will be ignored in case storage already
|
||||||
* contains authorization.
|
* contains authorization.
|
||||||
*/
|
*/
|
||||||
session?: string
|
session?: string | StringSessionData
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to overwrite existing session.
|
* Whether to overwrite existing session.
|
||||||
|
@ -73,7 +77,7 @@ export async function start(
|
||||||
* If provided `code`/`password` is a constant string, providing an
|
* If provided `code`/`password` is a constant string, providing an
|
||||||
* invalid one will interrupt authorization flow.
|
* invalid one will interrupt authorization flow.
|
||||||
*/
|
*/
|
||||||
invalidCodeCallback?: (type: 'code' | 'password') => MaybeAsync<void>
|
invalidCodeCallback?: (type: 'code' | 'password') => MaybePromise<void>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to force code delivery through SMS
|
* Whether to force code delivery through SMS
|
||||||
|
@ -89,11 +93,11 @@ export async function start(
|
||||||
* @param code
|
* @param code
|
||||||
* @default `console.log`.
|
* @default `console.log`.
|
||||||
*/
|
*/
|
||||||
codeSentCallback?: (code: SentCode) => MaybeAsync<void>
|
codeSentCallback?: (code: SentCode) => MaybePromise<void>
|
||||||
},
|
},
|
||||||
): Promise<User> {
|
): Promise<User> {
|
||||||
if (params.session) {
|
if (params.session) {
|
||||||
client.importSession(params.session, params.sessionForce)
|
await client.importSession(params.session, params.sessionForce)
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -103,7 +107,7 @@ export async function start(
|
||||||
|
|
||||||
client.log.info('Logged in as %s (ID: %s, username: %s, bot: %s)', me.displayName, me.id, me.username, me.isBot)
|
client.log.info('Logged in as %s (ID: %s, username: %s, bot: %s)', me.displayName, me.id, me.username, me.isBot)
|
||||||
|
|
||||||
client.network.setIsPremium(me.isPremium)
|
await client.notifyLoggedIn(me.raw)
|
||||||
|
|
||||||
return me
|
return me
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -211,15 +215,3 @@ export async function start(
|
||||||
|
|
||||||
throw new MtArgumentError('Failed to log in with provided credentials')
|
throw new MtArgumentError('Failed to log in with provided credentials')
|
||||||
}
|
}
|
||||||
|
|
||||||
// @manual-impl=start
|
|
||||||
/** @internal */
|
|
||||||
async function _start(this: TelegramClient, params: Parameters<typeof start>[1]) {
|
|
||||||
const user = await start(this, params)
|
|
||||||
|
|
||||||
if (!this.network.params.disableUpdates && !this._disableUpdatesManager) {
|
|
||||||
await this.startUpdatesLoop()
|
|
||||||
}
|
|
||||||
|
|
||||||
return user
|
|
||||||
}
|
|
39
packages/core/src/highlevel/methods/auth/utils.ts
Normal file
39
packages/core/src/highlevel/methods/auth/utils.ts
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
import { User } from '../../types/peers/user.js'
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
export async function _onAuthorization(
|
||||||
|
client: ITelegramClient,
|
||||||
|
auth: tl.auth.TypeAuthorization,
|
||||||
|
): Promise<User> {
|
||||||
|
const user = await client.notifyLoggedIn(auth)
|
||||||
|
|
||||||
|
return new User(user)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the given peer/input peer is referring to the current user
|
||||||
|
*/
|
||||||
|
export function isSelfPeer(
|
||||||
|
client: ITelegramClient,
|
||||||
|
peer: tl.TypeInputPeer | tl.TypePeer | tl.TypeInputUser,
|
||||||
|
): boolean {
|
||||||
|
const state = client.storage.self.getCached()
|
||||||
|
if (!state) return false
|
||||||
|
|
||||||
|
switch (peer._) {
|
||||||
|
case 'inputPeerSelf':
|
||||||
|
case 'inputUserSelf':
|
||||||
|
return true
|
||||||
|
case 'inputPeerUser':
|
||||||
|
case 'inputPeerUserFromMessage':
|
||||||
|
case 'inputUser':
|
||||||
|
case 'inputUserFromMessage':
|
||||||
|
case 'peerUser':
|
||||||
|
return peer.userId === state.userId
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
import { BaseTelegramClient, Long } from '@mtcute/core'
|
import Long from 'long'
|
||||||
import { assertTrue } from '@mtcute/core/utils.js'
|
|
||||||
|
|
||||||
|
import { assertTrue } from '../../../utils/type-assertions.js'
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { CallbackQuery } from '../../types/updates/callback-query.js'
|
import { CallbackQuery } from '../../types/updates/callback-query.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -10,7 +11,7 @@ import { CallbackQuery } from '../../types/updates/callback-query.js'
|
||||||
* @param params Parameters of the answer
|
* @param params Parameters of the answer
|
||||||
*/
|
*/
|
||||||
export async function answerCallbackQuery(
|
export async function answerCallbackQuery(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
queryId: Long | CallbackQuery,
|
queryId: Long | CallbackQuery,
|
||||||
params?: {
|
params?: {
|
||||||
/**
|
/**
|
|
@ -1,5 +1,8 @@
|
||||||
import { BaseTelegramClient, Long, tl } from '@mtcute/core'
|
import Long from 'long'
|
||||||
|
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { BotInline, InputInlineResult } from '../../types/bots/index.js'
|
import { BotInline, InputInlineResult } from '../../types/bots/index.js'
|
||||||
import { InlineQuery } from '../../types/updates/inline-query.js'
|
import { InlineQuery } from '../../types/updates/inline-query.js'
|
||||||
|
|
||||||
|
@ -11,7 +14,7 @@ import { InlineQuery } from '../../types/updates/inline-query.js'
|
||||||
* @param params Additional parameters
|
* @param params Additional parameters
|
||||||
*/
|
*/
|
||||||
export async function answerInlineQuery(
|
export async function answerInlineQuery(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
queryId: tl.Long | InlineQuery,
|
queryId: tl.Long | InlineQuery,
|
||||||
results: InputInlineResult[],
|
results: InputInlineResult[],
|
||||||
params?: {
|
params?: {
|
|
@ -1,6 +1,9 @@
|
||||||
import { BaseTelegramClient, Long, tl } from '@mtcute/core'
|
import Long from 'long'
|
||||||
import { assertTrue } from '@mtcute/core/utils.js'
|
|
||||||
|
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { assertTrue } from '../../../utils/type-assertions.js'
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import type { PreCheckoutQuery } from '../../types/updates/pre-checkout-query.js'
|
import type { PreCheckoutQuery } from '../../types/updates/pre-checkout-query.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -9,7 +12,7 @@ import type { PreCheckoutQuery } from '../../types/updates/pre-checkout-query.js
|
||||||
* @param queryId Pre-checkout query ID
|
* @param queryId Pre-checkout query ID
|
||||||
*/
|
*/
|
||||||
export async function answerPreCheckoutQuery(
|
export async function answerPreCheckoutQuery(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
queryId: tl.Long | PreCheckoutQuery,
|
queryId: tl.Long | PreCheckoutQuery,
|
||||||
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 */
|
|
@ -1,5 +1,6 @@
|
||||||
import { BaseTelegramClient, tl } from '@mtcute/core'
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { BotCommands } from '../../types/index.js'
|
import { BotCommands } from '../../types/index.js'
|
||||||
import { _normalizeCommandScope } from './normalize-command-scope.js'
|
import { _normalizeCommandScope } from './normalize-command-scope.js'
|
||||||
|
|
||||||
|
@ -11,7 +12,7 @@ import { _normalizeCommandScope } from './normalize-command-scope.js'
|
||||||
* 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)
|
||||||
*/
|
*/
|
||||||
export async function deleteMyCommands(
|
export async function deleteMyCommands(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
params?: {
|
params?: {
|
||||||
/**
|
/**
|
||||||
* Scope of the commands.
|
* Scope of the commands.
|
|
@ -1,5 +1,6 @@
|
||||||
import { BaseTelegramClient, tl } from '@mtcute/core'
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { InputPeerLike } from '../../types/index.js'
|
import { InputPeerLike } from '../../types/index.js'
|
||||||
import { toInputUser } from '../../utils/peer-utils.js'
|
import { toInputUser } from '../../utils/peer-utils.js'
|
||||||
import { resolvePeer } from '../users/resolve-peer.js'
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
@ -8,7 +9,7 @@ import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
* 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)
|
||||||
*/
|
*/
|
||||||
export async function getBotInfo(
|
export async function getBotInfo(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
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.
|
|
@ -1,5 +1,6 @@
|
||||||
import { BaseTelegramClient, tl } from '@mtcute/core'
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { InputPeerLike } from '../../types/index.js'
|
import { InputPeerLike } from '../../types/index.js'
|
||||||
import { toInputUser } from '../../utils/peer-utils.js'
|
import { toInputUser } from '../../utils/peer-utils.js'
|
||||||
import { resolvePeer } from '../users/resolve-peer.js'
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
@ -7,7 +8,7 @@ import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
/**
|
/**
|
||||||
* Fetches the menu button set for the given user.
|
* Fetches the menu button set for the given user.
|
||||||
*/
|
*/
|
||||||
export async function getBotMenuButton(client: BaseTelegramClient, user: InputPeerLike): Promise<tl.TypeBotMenuButton> {
|
export async function getBotMenuButton(client: ITelegramClient, user: InputPeerLike): Promise<tl.TypeBotMenuButton> {
|
||||||
return await client.call({
|
return await client.call({
|
||||||
_: 'bots.getBotMenuButton',
|
_: 'bots.getBotMenuButton',
|
||||||
userId: toInputUser(await resolvePeer(client, user), user),
|
userId: toInputUser(await resolvePeer(client, user), user),
|
|
@ -1,6 +1,7 @@
|
||||||
import { BaseTelegramClient, tl } from '@mtcute/core'
|
import { tl } from '@mtcute/tl'
|
||||||
import { computeSrpParams, utf8EncodeToBuffer } from '@mtcute/core/utils.js'
|
import { utf8EncodeToBuffer } from '@mtcute/tl-runtime'
|
||||||
|
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { InputMessageId, normalizeInputMessageId } from '../../types/index.js'
|
import { InputMessageId, normalizeInputMessageId } from '../../types/index.js'
|
||||||
import { resolvePeer } from '../users/resolve-peer.js'
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
|
||||||
|
@ -11,7 +12,7 @@ import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
* @param params
|
* @param params
|
||||||
*/
|
*/
|
||||||
export async function getCallbackAnswer(
|
export async function getCallbackAnswer(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
params: InputMessageId & {
|
params: InputMessageId & {
|
||||||
/** Data contained in the button */
|
/** Data contained in the button */
|
||||||
data: string | Uint8Array
|
data: string | Uint8Array
|
||||||
|
@ -44,7 +45,7 @@ export async function getCallbackAnswer(
|
||||||
|
|
||||||
if (params?.password) {
|
if (params?.password) {
|
||||||
const pwd = await client.call({ _: 'account.getPassword' })
|
const pwd = await client.call({ _: 'account.getPassword' })
|
||||||
password = await computeSrpParams(client.crypto, pwd, params.password)
|
password = await client.computeSrpParams(pwd, params.password)
|
||||||
}
|
}
|
||||||
|
|
||||||
return await client.call(
|
return await client.call(
|
|
@ -1,5 +1,6 @@
|
||||||
import { BaseTelegramClient, tl } from '@mtcute/core'
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { GameHighScore, InputMessageId, InputPeerLike, normalizeInputMessageId, PeersIndex } from '../../types/index.js'
|
import { GameHighScore, InputMessageId, InputPeerLike, normalizeInputMessageId, PeersIndex } from '../../types/index.js'
|
||||||
import { normalizeInlineId } from '../../utils/inline-utils.js'
|
import { normalizeInlineId } from '../../utils/inline-utils.js'
|
||||||
import { toInputUser } from '../../utils/peer-utils.js'
|
import { toInputUser } from '../../utils/peer-utils.js'
|
||||||
|
@ -9,7 +10,7 @@ import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
* Get high scores of a game
|
* Get high scores of a game
|
||||||
*/
|
*/
|
||||||
export async function getGameHighScores(
|
export async function getGameHighScores(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
params: InputMessageId & {
|
params: InputMessageId & {
|
||||||
/** ID of the user to find high scores for */
|
/** ID of the user to find high scores for */
|
||||||
userId?: InputPeerLike
|
userId?: InputPeerLike
|
||||||
|
@ -47,7 +48,7 @@ export async function getGameHighScores(
|
||||||
* @param userId ID of the user to find high scores for
|
* @param userId ID of the user to find high scores for
|
||||||
*/
|
*/
|
||||||
export async function getInlineGameHighScores(
|
export async function getInlineGameHighScores(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
messageId: string | tl.TypeInputBotInlineMessageID,
|
messageId: string | tl.TypeInputBotInlineMessageID,
|
||||||
userId?: InputPeerLike,
|
userId?: InputPeerLike,
|
||||||
): Promise<GameHighScore[]> {
|
): Promise<GameHighScore[]> {
|
|
@ -1,5 +1,6 @@
|
||||||
import { BaseTelegramClient, tl } from '@mtcute/core'
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { BotCommands } from '../../types/index.js'
|
import { BotCommands } from '../../types/index.js'
|
||||||
import { _normalizeCommandScope } from './normalize-command-scope.js'
|
import { _normalizeCommandScope } from './normalize-command-scope.js'
|
||||||
|
|
||||||
|
@ -10,7 +11,7 @@ import { _normalizeCommandScope } from './normalize-command-scope.js'
|
||||||
* 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)
|
||||||
*/
|
*/
|
||||||
export async function getMyCommands(
|
export async function getMyCommands(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
params?: {
|
params?: {
|
||||||
/**
|
/**
|
||||||
* Scope of the commands.
|
* Scope of the commands.
|
|
@ -1,12 +1,14 @@
|
||||||
import { assertNever, BaseTelegramClient, tl } from '@mtcute/core'
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { assertNever } from '../../../types/utils.js'
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { BotCommands } from '../../types/index.js'
|
import { BotCommands } from '../../types/index.js'
|
||||||
import { toInputUser } from '../../utils/peer-utils.js'
|
import { toInputUser } from '../../utils/peer-utils.js'
|
||||||
import { resolvePeer } from '../users/resolve-peer.js'
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
export async function _normalizeCommandScope(
|
export async function _normalizeCommandScope(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
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
|
|
@ -1,6 +1,5 @@
|
||||||
import { BaseTelegramClient } from '@mtcute/core'
|
import { assertTrue } from '../../../utils/type-assertions.js'
|
||||||
import { assertTrue } from '@mtcute/core/utils.js'
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
|
||||||
import { InputPeerLike } from '../../types/index.js'
|
import { InputPeerLike } from '../../types/index.js'
|
||||||
import { toInputUser } from '../../utils/peer-utils.js'
|
import { toInputUser } from '../../utils/peer-utils.js'
|
||||||
import { resolvePeer } from '../users/resolve-peer.js'
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
@ -9,7 +8,7 @@ import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
* 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)
|
||||||
*/
|
*/
|
||||||
export async function setBotInfo(
|
export async function setBotInfo(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
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.
|
|
@ -1,6 +1,7 @@
|
||||||
import { BaseTelegramClient, tl } from '@mtcute/core'
|
import { tl } from '@mtcute/tl'
|
||||||
import { assertTrue } from '@mtcute/core/utils.js'
|
|
||||||
|
|
||||||
|
import { assertTrue } from '../../../utils/type-assertions.js'
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { InputPeerLike } from '../../types/index.js'
|
import { InputPeerLike } from '../../types/index.js'
|
||||||
import { toInputUser } from '../../utils/peer-utils.js'
|
import { toInputUser } from '../../utils/peer-utils.js'
|
||||||
import { resolvePeer } from '../users/resolve-peer.js'
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
@ -9,7 +10,7 @@ import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
* Sets a menu button for the given user.
|
* Sets a menu button for the given user.
|
||||||
*/
|
*/
|
||||||
export async function setBotMenuButton(
|
export async function setBotMenuButton(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
user: InputPeerLike,
|
user: InputPeerLike,
|
||||||
button: tl.TypeBotMenuButton,
|
button: tl.TypeBotMenuButton,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
|
@ -1,6 +1,7 @@
|
||||||
import { BaseTelegramClient, tl } from '@mtcute/core'
|
import { tl } from '@mtcute/tl'
|
||||||
import { assertTrue } from '@mtcute/core/utils.js'
|
|
||||||
|
|
||||||
|
import { assertTrue } from '../../../utils/type-assertions.js'
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { InputMessageId, InputPeerLike, Message, normalizeInputMessageId } from '../../types/index.js'
|
import { InputMessageId, InputPeerLike, Message, normalizeInputMessageId } from '../../types/index.js'
|
||||||
import { normalizeInlineId } from '../../utils/inline-utils.js'
|
import { normalizeInlineId } from '../../utils/inline-utils.js'
|
||||||
import { toInputUser } from '../../utils/peer-utils.js'
|
import { toInputUser } from '../../utils/peer-utils.js'
|
||||||
|
@ -14,7 +15,7 @@ import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
* @returns The modified message
|
* @returns The modified message
|
||||||
*/
|
*/
|
||||||
export async function setGameScore(
|
export async function setGameScore(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
params: InputMessageId & {
|
params: InputMessageId & {
|
||||||
/** ID of the user who has scored */
|
/** ID of the user who has scored */
|
||||||
userId: InputPeerLike
|
userId: InputPeerLike
|
||||||
|
@ -67,7 +68,7 @@ export async function setGameScore(
|
||||||
* @param params
|
* @param params
|
||||||
*/
|
*/
|
||||||
export async function setInlineGameScore(
|
export async function setInlineGameScore(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
params: {
|
params: {
|
||||||
/** ID of the inline message */
|
/** ID of the inline message */
|
||||||
messageId: string | tl.TypeInputBotInlineMessageID
|
messageId: string | tl.TypeInputBotInlineMessageID
|
|
@ -1,6 +1,7 @@
|
||||||
import { BaseTelegramClient, tl } from '@mtcute/core'
|
import { tl } from '@mtcute/tl'
|
||||||
import { assertTrue } from '@mtcute/core/utils.js'
|
|
||||||
|
|
||||||
|
import { assertTrue } from '../../../utils/type-assertions.js'
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { BotCommands } from '../../types/index.js'
|
import { BotCommands } from '../../types/index.js'
|
||||||
import { _normalizeCommandScope } from './normalize-command-scope.js'
|
import { _normalizeCommandScope } from './normalize-command-scope.js'
|
||||||
|
|
||||||
|
@ -10,7 +11,7 @@ import { _normalizeCommandScope } from './normalize-command-scope.js'
|
||||||
* 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)
|
||||||
*/
|
*/
|
||||||
export async function setMyCommands(
|
export async function setMyCommands(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
params: {
|
params: {
|
||||||
/**
|
/**
|
||||||
* New list of bot commands for the given scope.
|
* New list of bot commands for the given scope.
|
|
@ -1,11 +1,13 @@
|
||||||
import { BaseTelegramClient, tl } from '@mtcute/core'
|
import { tl } from '@mtcute/tl'
|
||||||
import { assertTrue } from '@mtcute/core/utils.js'
|
|
||||||
|
import { assertTrue } from '../../../utils/type-assertions.js'
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
*/
|
*/
|
||||||
export async function setMyDefaultRights(
|
export async function setMyDefaultRights(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
params: {
|
params: {
|
||||||
/** Whether to target groups or channels. */
|
/** Whether to target groups or channels. */
|
||||||
target: 'channel' | 'group'
|
target: 'channel' | 'group'
|
|
@ -1,5 +1,5 @@
|
||||||
import { BaseTelegramClient, MaybeArray } from '@mtcute/core'
|
import { MaybeArray } from '../../../types/utils.js'
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { InputPeerLike, MtInvalidPeerTypeError } from '../../types/index.js'
|
import { InputPeerLike, MtInvalidPeerTypeError } from '../../types/index.js'
|
||||||
import { isInputPeerChannel, isInputPeerChat, toInputChannel, toInputUser } from '../../utils/peer-utils.js'
|
import { isInputPeerChannel, isInputPeerChat, toInputChannel, toInputUser } from '../../utils/peer-utils.js'
|
||||||
import { resolvePeer } from '../users/resolve-peer.js'
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
@ -12,7 +12,7 @@ import { resolvePeerMany } from '../users/resolve-peer-many.js'
|
||||||
* @param users ID(s) of the user(s) to add
|
* @param users ID(s) of the user(s) to add
|
||||||
*/
|
*/
|
||||||
export async function addChatMembers(
|
export async function addChatMembers(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
chatId: InputPeerLike,
|
chatId: InputPeerLike,
|
||||||
users: MaybeArray<InputPeerLike>,
|
users: MaybeArray<InputPeerLike>,
|
||||||
params: {
|
params: {
|
||||||
|
@ -41,7 +41,7 @@ export async function addChatMembers(
|
||||||
userId: p,
|
userId: p,
|
||||||
fwdLimit: forwardCount,
|
fwdLimit: forwardCount,
|
||||||
})
|
})
|
||||||
client.network.handleUpdate(updates)
|
client.handleClientUpdate(updates)
|
||||||
}
|
}
|
||||||
} else if (isInputPeerChannel(chat)) {
|
} else if (isInputPeerChannel(chat)) {
|
||||||
const updates = await client.call({
|
const updates = await client.call({
|
||||||
|
@ -49,7 +49,6 @@ export async function addChatMembers(
|
||||||
channel: toInputChannel(chat),
|
channel: toInputChannel(chat),
|
||||||
users: await resolvePeerMany(client, users, toInputUser),
|
users: await resolvePeerMany(client, users, toInputUser),
|
||||||
})
|
})
|
||||||
|
client.handleClientUpdate(updates)
|
||||||
client.network.handleUpdate(updates)
|
|
||||||
} else throw new MtInvalidPeerTypeError(chatId, 'chat or channel')
|
} else throw new MtInvalidPeerTypeError(chatId, 'chat or channel')
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
import { BaseTelegramClient, MaybeArray } from '@mtcute/core'
|
import { MaybeArray } from '../../../types/utils.js'
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { InputPeerLike } from '../../types/index.js'
|
import { InputPeerLike } from '../../types/index.js'
|
||||||
import { resolvePeerMany } from '../users/resolve-peer-many.js'
|
import { resolvePeerMany } from '../users/resolve-peer-many.js'
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import { resolvePeerMany } from '../users/resolve-peer-many.js'
|
||||||
*
|
*
|
||||||
* @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"`
|
||||||
*/
|
*/
|
||||||
export async function archiveChats(client: BaseTelegramClient, chats: MaybeArray<InputPeerLike>): Promise<void> {
|
export async function archiveChats(client: ITelegramClient, chats: MaybeArray<InputPeerLike>): Promise<void> {
|
||||||
if (!Array.isArray(chats)) chats = [chats]
|
if (!Array.isArray(chats)) chats = [chats]
|
||||||
|
|
||||||
const resolvedPeers = await resolvePeerMany(client, chats)
|
const resolvedPeers = await resolvePeerMany(client, chats)
|
||||||
|
@ -21,5 +21,5 @@ export async function archiveChats(client: BaseTelegramClient, chats: MaybeArray
|
||||||
folderId: 1,
|
folderId: 1,
|
||||||
})),
|
})),
|
||||||
})
|
})
|
||||||
client.network.handleUpdate(updates)
|
client.handleClientUpdate(updates)
|
||||||
}
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
import { BaseTelegramClient } from '@mtcute/core'
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
|
||||||
import { InputPeerLike, Message, MtInvalidPeerTypeError } from '../../types/index.js'
|
import { InputPeerLike, Message, MtInvalidPeerTypeError } from '../../types/index.js'
|
||||||
import { isInputPeerChannel, isInputPeerChat, toInputChannel, toInputUser } from '../../utils/peer-utils.js'
|
import { isInputPeerChannel, isInputPeerChat, toInputChannel, toInputUser } from '../../utils/peer-utils.js'
|
||||||
import { _findMessageInUpdate } from '../messages/find-in-update.js'
|
import { _findMessageInUpdate } from '../messages/find-in-update.js'
|
||||||
|
@ -16,7 +15,7 @@ import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
* @returns Service message about removed user, if one was generated.
|
* @returns Service message about removed user, if one was generated.
|
||||||
*/
|
*/
|
||||||
export async function banChatMember(
|
export async function banChatMember(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
params: {
|
params: {
|
||||||
/** Chat ID */
|
/** Chat ID */
|
||||||
chatId: InputPeerLike
|
chatId: InputPeerLike
|
|
@ -1,5 +1,7 @@
|
||||||
import { BaseTelegramClient, MtArgumentError, tl } from '@mtcute/core'
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { MtArgumentError } from '../../../types/errors.js'
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import {
|
import {
|
||||||
isInputPeerChannel,
|
isInputPeerChannel,
|
||||||
isInputPeerChat,
|
isInputPeerChat,
|
||||||
|
@ -8,7 +10,6 @@ import {
|
||||||
toInputUser,
|
toInputUser,
|
||||||
} from '../../utils/peer-utils.js'
|
} from '../../utils/peer-utils.js'
|
||||||
import { batchedQuery } from '../../utils/query-batcher.js'
|
import { batchedQuery } from '../../utils/query-batcher.js'
|
||||||
import { getAuthState } from '../auth/_state.js'
|
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
export const _getUsersBatched = batchedQuery<tl.TypeInputUser, tl.TypeUser, number>({
|
export const _getUsersBatched = batchedQuery<tl.TypeInputUser, tl.TypeUser, number>({
|
||||||
|
@ -27,7 +28,7 @@ export const _getUsersBatched = batchedQuery<tl.TypeInputUser, tl.TypeUser, numb
|
||||||
case 'inputUserFromMessage':
|
case 'inputUserFromMessage':
|
||||||
return item.userId
|
return item.userId
|
||||||
case 'inputUserSelf':
|
case 'inputUserSelf':
|
||||||
return getAuthState(client).userId!
|
return client.storage.self.getCached()!.userId
|
||||||
default:
|
default:
|
||||||
throw new MtArgumentError('Invalid input user')
|
throw new MtArgumentError('Invalid input user')
|
||||||
}
|
}
|
||||||
|
@ -130,7 +131,7 @@ export const _getChannelsBatched = batchedQuery<tl.TypeInputChannel, tl.RawChann
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
export function _getRawPeerBatched(
|
export function _getRawPeerBatched(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
peer: tl.TypeInputPeer,
|
peer: tl.TypeInputPeer,
|
||||||
): Promise<tl.TypeUser | tl.TypeChat | null> {
|
): Promise<tl.TypeUser | tl.TypeChat | null> {
|
||||||
if (isInputPeerUser(peer)) {
|
if (isInputPeerUser(peer)) {
|
|
@ -1,7 +1,6 @@
|
||||||
import { BaseTelegramClient } from '@mtcute/core'
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
|
||||||
import { Chat } from '../../types/index.js'
|
import { Chat } from '../../types/index.js'
|
||||||
import { assertIsUpdatesGroup } from '../../utils/updates-utils.js'
|
import { assertIsUpdatesGroup } from '../../updates/utils.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new broadcast channel
|
* Create a new broadcast channel
|
||||||
|
@ -9,7 +8,7 @@ import { assertIsUpdatesGroup } from '../../utils/updates-utils.js'
|
||||||
* @returns Newly created channel
|
* @returns Newly created channel
|
||||||
*/
|
*/
|
||||||
export async function createChannel(
|
export async function createChannel(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
params: {
|
params: {
|
||||||
/**
|
/**
|
||||||
* Channel title
|
* Channel title
|
||||||
|
@ -33,7 +32,7 @@ export async function createChannel(
|
||||||
|
|
||||||
assertIsUpdatesGroup('channels.createChannel', res)
|
assertIsUpdatesGroup('channels.createChannel', res)
|
||||||
|
|
||||||
client.network.handleUpdate(res)
|
client.handleClientUpdate(res)
|
||||||
|
|
||||||
return new Chat(res.chats[0])
|
return new Chat(res.chats[0])
|
||||||
}
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
import { BaseTelegramClient, MaybeArray } from '@mtcute/core'
|
import { MaybeArray } from '../../../types/utils.js'
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { Chat, InputPeerLike } from '../../types/index.js'
|
import { Chat, InputPeerLike } from '../../types/index.js'
|
||||||
|
import { assertIsUpdatesGroup } from '../../updates/utils.js'
|
||||||
import { toInputUser } from '../../utils/peer-utils.js'
|
import { toInputUser } from '../../utils/peer-utils.js'
|
||||||
import { assertIsUpdatesGroup } from '../../utils/updates-utils.js'
|
|
||||||
import { resolvePeerMany } from '../users/resolve-peer-many.js'
|
import { resolvePeerMany } from '../users/resolve-peer-many.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,7 +12,7 @@ import { resolvePeerMany } from '../users/resolve-peer-many.js'
|
||||||
* instead.
|
* instead.
|
||||||
*/
|
*/
|
||||||
export async function createGroup(
|
export async function createGroup(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
params: {
|
params: {
|
||||||
/**
|
/**
|
||||||
* Group title
|
* Group title
|
||||||
|
@ -48,7 +48,7 @@ export async function createGroup(
|
||||||
|
|
||||||
assertIsUpdatesGroup('messages.createChat', res)
|
assertIsUpdatesGroup('messages.createChat', res)
|
||||||
|
|
||||||
client.network.handleUpdate(res)
|
client.handleClientUpdate(res)
|
||||||
|
|
||||||
return new Chat(res.chats[0])
|
return new Chat(res.chats[0])
|
||||||
}
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
import { BaseTelegramClient } from '@mtcute/core'
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
|
||||||
import { Chat } from '../../types/index.js'
|
import { Chat } from '../../types/index.js'
|
||||||
import { assertIsUpdatesGroup } from '../../utils/updates-utils.js'
|
import { assertIsUpdatesGroup } from '../../updates/utils.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new supergroup
|
* Create a new supergroup
|
||||||
|
@ -9,7 +8,7 @@ import { assertIsUpdatesGroup } from '../../utils/updates-utils.js'
|
||||||
* @returns Newly created supergroup
|
* @returns Newly created supergroup
|
||||||
*/
|
*/
|
||||||
export async function createSupergroup(
|
export async function createSupergroup(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
params: {
|
params: {
|
||||||
/**
|
/**
|
||||||
* Supergroup title
|
* Supergroup title
|
||||||
|
@ -47,7 +46,7 @@ export async function createSupergroup(
|
||||||
|
|
||||||
assertIsUpdatesGroup('channels.createChannel', res)
|
assertIsUpdatesGroup('channels.createChannel', res)
|
||||||
|
|
||||||
client.network.handleUpdate(res)
|
client.handleClientUpdate(res)
|
||||||
|
|
||||||
return new Chat(res.chats[0])
|
return new Chat(res.chats[0])
|
||||||
}
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
import { BaseTelegramClient } from '@mtcute/core'
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
|
||||||
import { InputPeerLike } from '../../types/index.js'
|
import { InputPeerLike } from '../../types/index.js'
|
||||||
import { toInputChannel } from '../../utils/peer-utils.js'
|
import { toInputChannel } from '../../utils/peer-utils.js'
|
||||||
import { resolvePeer } from '../users/resolve-peer.js'
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
@ -10,10 +9,10 @@ import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
*
|
*
|
||||||
* @param chatId Chat ID or username
|
* @param chatId Chat ID or username
|
||||||
*/
|
*/
|
||||||
export async function deleteChannel(client: BaseTelegramClient, chatId: InputPeerLike): Promise<void> {
|
export async function deleteChannel(client: ITelegramClient, chatId: InputPeerLike): Promise<void> {
|
||||||
const res = await client.call({
|
const res = await client.call({
|
||||||
_: 'channels.deleteChannel',
|
_: 'channels.deleteChannel',
|
||||||
channel: toInputChannel(await resolvePeer(client, chatId), chatId),
|
channel: toInputChannel(await resolvePeer(client, chatId), chatId),
|
||||||
})
|
})
|
||||||
client.network.handleUpdate(res)
|
client.handleClientUpdate(res)
|
||||||
}
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
import { BaseTelegramClient } from '@mtcute/core'
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
|
||||||
import { InputPeerLike, MtInvalidPeerTypeError } from '../../types/index.js'
|
import { InputPeerLike, MtInvalidPeerTypeError } from '../../types/index.js'
|
||||||
import { isInputPeerChannel, isInputPeerChat, toInputChannel } from '../../utils/peer-utils.js'
|
import { isInputPeerChannel, isInputPeerChat, toInputChannel } from '../../utils/peer-utils.js'
|
||||||
import { resolvePeer } from '../users/resolve-peer.js'
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
@ -11,7 +10,7 @@ import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
*
|
*
|
||||||
* @param chatId Chat ID or username
|
* @param chatId Chat ID or username
|
||||||
*/
|
*/
|
||||||
export async function deleteChatPhoto(client: BaseTelegramClient, chatId: InputPeerLike): Promise<void> {
|
export async function deleteChatPhoto(client: ITelegramClient, chatId: InputPeerLike): Promise<void> {
|
||||||
const chat = await resolvePeer(client, chatId)
|
const chat = await resolvePeer(client, chatId)
|
||||||
|
|
||||||
let res
|
let res
|
||||||
|
@ -29,5 +28,5 @@ export async function deleteChatPhoto(client: BaseTelegramClient, chatId: InputP
|
||||||
})
|
})
|
||||||
} else throw new MtInvalidPeerTypeError(chatId, 'chat or channel')
|
} else throw new MtInvalidPeerTypeError(chatId, 'chat or channel')
|
||||||
|
|
||||||
client.network.handleUpdate(res)
|
client.handleClientUpdate(res)
|
||||||
}
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
import { BaseTelegramClient } from '@mtcute/core'
|
import { assertTrue } from '../../../utils/type-assertions.js'
|
||||||
import { assertTrue } from '@mtcute/core/utils.js'
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
|
||||||
import { InputPeerLike, MtInvalidPeerTypeError } from '../../types/index.js'
|
import { InputPeerLike, MtInvalidPeerTypeError } from '../../types/index.js'
|
||||||
import { isInputPeerChat } from '../../utils/peer-utils.js'
|
import { isInputPeerChat } from '../../utils/peer-utils.js'
|
||||||
import { resolvePeer } from '../users/resolve-peer.js'
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
@ -10,7 +9,7 @@ import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
*
|
*
|
||||||
* @param chatId Chat ID
|
* @param chatId Chat ID
|
||||||
*/
|
*/
|
||||||
export async function deleteGroup(client: BaseTelegramClient, chatId: InputPeerLike): Promise<void> {
|
export async function deleteGroup(client: ITelegramClient, chatId: InputPeerLike): Promise<void> {
|
||||||
const chat = await resolvePeer(client, chatId)
|
const chat = await resolvePeer(client, chatId)
|
||||||
if (!isInputPeerChat(chat)) throw new MtInvalidPeerTypeError(chatId, 'chat')
|
if (!isInputPeerChat(chat)) throw new MtInvalidPeerTypeError(chatId, 'chat')
|
||||||
|
|
||||||
|
@ -20,7 +19,7 @@ export async function deleteGroup(client: BaseTelegramClient, chatId: InputPeerL
|
||||||
chatId: chat.chatId,
|
chatId: chat.chatId,
|
||||||
userId: { _: 'inputUserSelf' },
|
userId: { _: 'inputUserSelf' },
|
||||||
})
|
})
|
||||||
client.network.handleUpdate(res)
|
client.handleClientUpdate(res)
|
||||||
|
|
||||||
const r = await client.call({
|
const r = await client.call({
|
||||||
_: 'messages.deleteChat',
|
_: 'messages.deleteChat',
|
|
@ -1,15 +1,14 @@
|
||||||
import { BaseTelegramClient } from '@mtcute/core'
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
|
||||||
import { InputPeerLike } from '../../types/index.js'
|
import { InputPeerLike } from '../../types/index.js'
|
||||||
|
import { createDummyUpdate } from '../../updates/utils.js'
|
||||||
import { isInputPeerChannel } from '../../utils/peer-utils.js'
|
import { isInputPeerChannel } from '../../utils/peer-utils.js'
|
||||||
import { createDummyUpdate } from '../../utils/updates-utils.js'
|
|
||||||
import { resolvePeer } from '../users/resolve-peer.js'
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete communication history (for private chats and legacy groups)
|
* Delete communication history (for private chats and legacy groups)
|
||||||
*/
|
*/
|
||||||
export async function deleteHistory(
|
export async function deleteHistory(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
chat: InputPeerLike,
|
chat: InputPeerLike,
|
||||||
params?: {
|
params?: {
|
||||||
/**
|
/**
|
||||||
|
@ -45,8 +44,8 @@ export async function deleteHistory(
|
||||||
})
|
})
|
||||||
|
|
||||||
if (isInputPeerChannel(peer)) {
|
if (isInputPeerChannel(peer)) {
|
||||||
client.network.handleUpdate(createDummyUpdate(res.pts, res.ptsCount, peer.channelId))
|
client.handleClientUpdate(createDummyUpdate(res.pts, res.ptsCount, peer.channelId))
|
||||||
} else {
|
} else {
|
||||||
client.network.handleUpdate(createDummyUpdate(res.pts, res.ptsCount))
|
client.handleClientUpdate(createDummyUpdate(res.pts, res.ptsCount))
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,15 +1,16 @@
|
||||||
import { BaseTelegramClient, tl } from '@mtcute/core'
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { InputPeerLike } from '../../types/index.js'
|
import { InputPeerLike } from '../../types/index.js'
|
||||||
|
import { createDummyUpdate } from '../../updates/utils.js'
|
||||||
import { toInputChannel } from '../../utils/peer-utils.js'
|
import { toInputChannel } from '../../utils/peer-utils.js'
|
||||||
import { createDummyUpdate } from '../../utils/updates-utils.js'
|
|
||||||
import { resolvePeer } from '../users/resolve-peer.js'
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete all messages of a user (or channel) in a supergroup
|
* Delete all messages of a user (or channel) in a supergroup
|
||||||
*/
|
*/
|
||||||
export async function deleteUserHistory(
|
export async function deleteUserHistory(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
params: {
|
params: {
|
||||||
/** Chat ID */
|
/** Chat ID */
|
||||||
chatId: InputPeerLike
|
chatId: InputPeerLike
|
||||||
|
@ -29,5 +30,5 @@ export async function deleteUserHistory(
|
||||||
participant: peer,
|
participant: peer,
|
||||||
})
|
})
|
||||||
|
|
||||||
client.network.handleUpdate(createDummyUpdate(res.pts, res.ptsCount, (channel as tl.RawInputChannel).channelId))
|
client.handleClientUpdate(createDummyUpdate(res.pts, res.ptsCount, (channel as tl.RawInputChannel).channelId))
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
import { BaseTelegramClient, tl } from '@mtcute/core'
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { InputPeerLike } from '../../types/index.js'
|
import { InputPeerLike } from '../../types/index.js'
|
||||||
import { toInputChannel, toInputUser } from '../../utils/peer-utils.js'
|
import { toInputChannel, toInputUser } from '../../utils/peer-utils.js'
|
||||||
import { resolvePeer } from '../users/resolve-peer.js'
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
@ -8,7 +9,7 @@ import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
* Edit supergroup/channel admin rights of a user.
|
* Edit supergroup/channel admin rights of a user.
|
||||||
*/
|
*/
|
||||||
export async function editAdminRights(
|
export async function editAdminRights(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
params: {
|
params: {
|
||||||
/** Chat ID */
|
/** Chat ID */
|
||||||
chatId: InputPeerLike
|
chatId: InputPeerLike
|
||||||
|
@ -36,5 +37,5 @@ export async function editAdminRights(
|
||||||
rank,
|
rank,
|
||||||
})
|
})
|
||||||
|
|
||||||
client.network.handleUpdate(res)
|
client.handleClientUpdate(res)
|
||||||
}
|
}
|
|
@ -1,5 +1,8 @@
|
||||||
import { BaseTelegramClient, Long, tl } from '@mtcute/core'
|
import Long from 'long'
|
||||||
|
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { ChatEvent, InputPeerLike, PeersIndex } from '../../types/index.js'
|
import { ChatEvent, InputPeerLike, PeersIndex } from '../../types/index.js'
|
||||||
import { InputChatEventFilters, normalizeChatEventFilters } from '../../types/peers/chat-event/filters.js'
|
import { InputChatEventFilters, normalizeChatEventFilters } from '../../types/peers/chat-event/filters.js'
|
||||||
import { toInputChannel, toInputUser } from '../../utils/peer-utils.js'
|
import { toInputChannel, toInputUser } from '../../utils/peer-utils.js'
|
||||||
|
@ -20,7 +23,7 @@ import { resolvePeerMany } from '../users/resolve-peer-many.js'
|
||||||
* @param params
|
* @param params
|
||||||
*/
|
*/
|
||||||
export async function getChatEventLog(
|
export async function getChatEventLog(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
chatId: InputPeerLike,
|
chatId: InputPeerLike,
|
||||||
params?: {
|
params?: {
|
||||||
/**
|
/**
|
|
@ -1,6 +1,7 @@
|
||||||
import { BaseTelegramClient, tl } from '@mtcute/core'
|
import { tl } from '@mtcute/tl'
|
||||||
import { assertTypeIs } from '@mtcute/core/utils.js'
|
|
||||||
|
|
||||||
|
import { assertTypeIs } from '../../../utils/type-assertions.js'
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { ChatMember, InputPeerLike, MtInvalidPeerTypeError, PeersIndex } from '../../types/index.js'
|
import { ChatMember, InputPeerLike, MtInvalidPeerTypeError, PeersIndex } from '../../types/index.js'
|
||||||
import { isInputPeerChannel, isInputPeerChat, isInputPeerUser, toInputChannel } from '../../utils/peer-utils.js'
|
import { isInputPeerChannel, isInputPeerChat, isInputPeerUser, toInputChannel } from '../../utils/peer-utils.js'
|
||||||
import { resolvePeer } from '../users/resolve-peer.js'
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
@ -13,7 +14,7 @@ import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
* @returns Chat member, or `null` if user is not a member of the chat
|
* @returns Chat member, or `null` if user is not a member of the chat
|
||||||
*/
|
*/
|
||||||
export async function getChatMember(
|
export async function getChatMember(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
params: {
|
params: {
|
||||||
/** Chat ID or username */
|
/** Chat ID or username */
|
||||||
chatId: InputPeerLike
|
chatId: InputPeerLike
|
|
@ -1,6 +1,10 @@
|
||||||
import { assertNever, BaseTelegramClient, Long, tl } from '@mtcute/core'
|
import Long from 'long'
|
||||||
import { assertTypeIs } from '@mtcute/core/utils.js'
|
|
||||||
|
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { assertNever } from '../../../types/utils.js'
|
||||||
|
import { assertTypeIs } from '../../../utils/type-assertions.js'
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { ArrayWithTotal, ChatMember, InputPeerLike, MtInvalidPeerTypeError, PeersIndex } from '../../types/index.js'
|
import { ArrayWithTotal, ChatMember, InputPeerLike, MtInvalidPeerTypeError, PeersIndex } from '../../types/index.js'
|
||||||
import { makeArrayWithTotal } from '../../utils/index.js'
|
import { makeArrayWithTotal } from '../../utils/index.js'
|
||||||
import { isInputPeerChannel, isInputPeerChat, toInputChannel } from '../../utils/peer-utils.js'
|
import { isInputPeerChannel, isInputPeerChat, toInputChannel } from '../../utils/peer-utils.js'
|
||||||
|
@ -15,7 +19,7 @@ import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
* @param params Additional parameters
|
* @param params Additional parameters
|
||||||
*/
|
*/
|
||||||
export async function getChatMembers(
|
export async function getChatMembers(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
chatId: InputPeerLike,
|
chatId: InputPeerLike,
|
||||||
params?: {
|
params?: {
|
||||||
/**
|
/**
|
|
@ -1,5 +1,5 @@
|
||||||
import { BaseTelegramClient, MtArgumentError } from '@mtcute/core'
|
import { MtArgumentError } from '../../../types/errors.js'
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { ChatPreview, MtPeerNotFoundError } from '../../types/index.js'
|
import { ChatPreview, MtPeerNotFoundError } from '../../types/index.js'
|
||||||
import { INVITE_LINK_REGEX } from '../../utils/peer-utils.js'
|
import { INVITE_LINK_REGEX } from '../../utils/peer-utils.js'
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ import { INVITE_LINK_REGEX } from '../../utils/peer-utils.js'
|
||||||
* 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.
|
||||||
*/
|
*/
|
||||||
export async function getChatPreview(client: BaseTelegramClient, inviteLink: string): Promise<ChatPreview> {
|
export async function getChatPreview(client: ITelegramClient, 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')
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { BaseTelegramClient, MtArgumentError } from '@mtcute/core'
|
import { MtArgumentError } from '../../../types/errors.js'
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { Chat, InputPeerLike, MtPeerNotFoundError } from '../../types/index.js'
|
import { Chat, InputPeerLike, MtPeerNotFoundError } from '../../types/index.js'
|
||||||
import { INVITE_LINK_REGEX } from '../../utils/peer-utils.js'
|
import { INVITE_LINK_REGEX } from '../../utils/peer-utils.js'
|
||||||
import { resolvePeer } from '../users/resolve-peer.js'
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
@ -14,7 +14,7 @@ import { _getRawPeerBatched } from './batched-queries.js'
|
||||||
* 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.
|
||||||
*/
|
*/
|
||||||
export async function getChat(client: BaseTelegramClient, chatId: InputPeerLike): Promise<Chat> {
|
export async function getChat(client: ITelegramClient, 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)
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import { BaseTelegramClient, MtArgumentError, tl } from '@mtcute/core'
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { MtArgumentError } from '../../../types/errors.js'
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { Chat, InputPeerLike } from '../../types/index.js'
|
import { Chat, InputPeerLike } from '../../types/index.js'
|
||||||
import {
|
import {
|
||||||
INVITE_LINK_REGEX,
|
INVITE_LINK_REGEX,
|
||||||
|
@ -20,7 +22,7 @@ import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
* 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.
|
||||||
*/
|
*/
|
||||||
export async function getFullChat(client: BaseTelegramClient, chatId: InputPeerLike): Promise<Chat> {
|
export async function getFullChat(client: ITelegramClient, 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)
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import { BaseTelegramClient, getMarkedPeerId, tl } from '@mtcute/core'
|
import { tl } from '@mtcute/tl'
|
||||||
import { assertTypeIs } from '@mtcute/core/utils.js'
|
|
||||||
|
|
||||||
|
import { getMarkedPeerId } from '../../../utils/peer-utils.js'
|
||||||
|
import { assertTypeIs } from '../../../utils/type-assertions.js'
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { Chat } from '../../types/index.js'
|
import { Chat } from '../../types/index.js'
|
||||||
import { assertIsUpdatesGroup } from '../../utils/updates-utils.js'
|
import { assertIsUpdatesGroup } from '../../updates/utils.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get nearby chats
|
* Get nearby chats
|
||||||
|
@ -10,7 +12,7 @@ import { assertIsUpdatesGroup } from '../../utils/updates-utils.js'
|
||||||
* @param latitude Latitude of the location
|
* @param latitude Latitude of the location
|
||||||
* @param longitude Longitude of the location
|
* @param longitude Longitude of the location
|
||||||
*/
|
*/
|
||||||
export async function getNearbyChats(client: BaseTelegramClient, latitude: number, longitude: number): Promise<Chat[]> {
|
export async function getNearbyChats(client: ITelegramClient, latitude: number, longitude: number): Promise<Chat[]> {
|
||||||
const res = await client.call({
|
const res = await client.call({
|
||||||
_: 'contacts.getLocated',
|
_: 'contacts.getLocated',
|
||||||
geoPoint: {
|
geoPoint: {
|
||||||
|
@ -21,7 +23,7 @@ export async function getNearbyChats(client: BaseTelegramClient, latitude: numbe
|
||||||
})
|
})
|
||||||
|
|
||||||
assertIsUpdatesGroup('contacts.getLocated', res)
|
assertIsUpdatesGroup('contacts.getLocated', res)
|
||||||
client.network.handleUpdate(res, true)
|
// client.handleClientUpdate(res, true)
|
||||||
|
|
||||||
if (!res.updates.length) return []
|
if (!res.updates.length) return []
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { BaseTelegramClient } from '@mtcute/core'
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
|
||||||
import { ArrayWithTotal, Chat, InputPeerLike } from '../../types/index.js'
|
import { ArrayWithTotal, Chat, InputPeerLike } from '../../types/index.js'
|
||||||
import { makeArrayWithTotal } from '../../utils/misc-utils.js'
|
import { makeArrayWithTotal } from '../../utils/misc-utils.js'
|
||||||
import { toInputChannel } from '../../utils/peer-utils.js'
|
import { toInputChannel } from '../../utils/peer-utils.js'
|
||||||
|
@ -16,7 +15,7 @@ import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
* > Returns empty array in case there are no similar channels available.
|
* > Returns empty array in case there are no similar channels available.
|
||||||
*/
|
*/
|
||||||
export async function getSimilarChannels(
|
export async function getSimilarChannels(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
channel: InputPeerLike,
|
channel: InputPeerLike,
|
||||||
): Promise<ArrayWithTotal<Chat>> {
|
): Promise<ArrayWithTotal<Chat>> {
|
||||||
const res = await client.call({
|
const res = await client.call({
|
|
@ -1,5 +1,8 @@
|
||||||
import { BaseTelegramClient, Long, tl } from '@mtcute/core'
|
import Long from 'long'
|
||||||
|
|
||||||
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { ChatEvent, InputPeerLike } from '../../types/index.js'
|
import { ChatEvent, InputPeerLike } from '../../types/index.js'
|
||||||
import { normalizeChatEventFilters } from '../../types/peers/chat-event/filters.js'
|
import { normalizeChatEventFilters } from '../../types/peers/chat-event/filters.js'
|
||||||
import { toInputChannel, toInputUser } from '../../utils/peer-utils.js'
|
import { toInputChannel, toInputUser } from '../../utils/peer-utils.js'
|
||||||
|
@ -16,7 +19,7 @@ import { getChatEventLog } from './get-chat-event-log.js'
|
||||||
* @param params
|
* @param params
|
||||||
*/
|
*/
|
||||||
export async function* iterChatEventLog(
|
export async function* iterChatEventLog(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
chatId: InputPeerLike,
|
chatId: InputPeerLike,
|
||||||
params?: Parameters<typeof getChatEventLog>[2] & {
|
params?: Parameters<typeof getChatEventLog>[2] & {
|
||||||
/**
|
/**
|
|
@ -1,5 +1,4 @@
|
||||||
import { BaseTelegramClient } from '@mtcute/core'
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
|
||||||
import { ChatMember, InputPeerLike } from '../../types/index.js'
|
import { ChatMember, InputPeerLike } from '../../types/index.js'
|
||||||
import { isInputPeerChat } from '../../utils/peer-utils.js'
|
import { isInputPeerChat } from '../../utils/peer-utils.js'
|
||||||
import { resolvePeer } from '../users/resolve-peer.js'
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
@ -16,7 +15,7 @@ import { getChatMembers } from './get-chat-members.js'
|
||||||
* @param params Additional parameters
|
* @param params Additional parameters
|
||||||
*/
|
*/
|
||||||
export async function* iterChatMembers(
|
export async function* iterChatMembers(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
chatId: InputPeerLike,
|
chatId: InputPeerLike,
|
||||||
params?: Parameters<typeof getChatMembers>[2] & {
|
params?: Parameters<typeof getChatMembers>[2] & {
|
||||||
/**
|
/**
|
|
@ -1,8 +1,7 @@
|
||||||
import { BaseTelegramClient } from '@mtcute/core'
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
|
||||||
import { Chat, InputPeerLike } from '../../types/index.js'
|
import { Chat, InputPeerLike } from '../../types/index.js'
|
||||||
|
import { assertIsUpdatesGroup } from '../../updates/utils.js'
|
||||||
import { INVITE_LINK_REGEX, toInputChannel } from '../../utils/peer-utils.js'
|
import { INVITE_LINK_REGEX, toInputChannel } from '../../utils/peer-utils.js'
|
||||||
import { assertIsUpdatesGroup } from '../../utils/updates-utils.js'
|
|
||||||
import { resolvePeer } from '../users/resolve-peer.js'
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -16,7 +15,7 @@ import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
* 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.
|
||||||
*/
|
*/
|
||||||
export async function joinChat(client: BaseTelegramClient, chatId: InputPeerLike): Promise<Chat> {
|
export async function joinChat(client: ITelegramClient, 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)
|
||||||
|
|
||||||
|
@ -27,7 +26,7 @@ export async function joinChat(client: BaseTelegramClient, chatId: InputPeerLike
|
||||||
})
|
})
|
||||||
assertIsUpdatesGroup('messages.importChatInvite', res)
|
assertIsUpdatesGroup('messages.importChatInvite', res)
|
||||||
|
|
||||||
client.network.handleUpdate(res)
|
client.handleClientUpdate(res)
|
||||||
|
|
||||||
return new Chat(res.chats[0])
|
return new Chat(res.chats[0])
|
||||||
}
|
}
|
||||||
|
@ -40,7 +39,7 @@ export async function joinChat(client: BaseTelegramClient, chatId: InputPeerLike
|
||||||
|
|
||||||
assertIsUpdatesGroup('channels.joinChannel', res)
|
assertIsUpdatesGroup('channels.joinChannel', res)
|
||||||
|
|
||||||
client.network.handleUpdate(res)
|
client.handleClientUpdate(res)
|
||||||
|
|
||||||
return new Chat(res.chats[0])
|
return new Chat(res.chats[0])
|
||||||
}
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
import { BaseTelegramClient } from '@mtcute/core'
|
import { sleep } from '../../../utils/misc-utils.js'
|
||||||
import { sleep } from '@mtcute/core/utils.js'
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
|
||||||
import { InputPeerLike, Message } from '../../types/index.js'
|
import { InputPeerLike, Message } from '../../types/index.js'
|
||||||
import { isInputPeerChannel } from '../../utils/peer-utils.js'
|
import { isInputPeerChannel } from '../../utils/peer-utils.js'
|
||||||
import { resolvePeer } from '../users/resolve-peer.js'
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
@ -15,7 +14,7 @@ import { unbanChatMember } from './unban-chat-member.js'
|
||||||
* @returns Service message about removed user, if one was generated.
|
* @returns Service message about removed user, if one was generated.
|
||||||
*/
|
*/
|
||||||
export async function kickChatMember(
|
export async function kickChatMember(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
params: {
|
params: {
|
||||||
/** Chat ID */
|
/** Chat ID */
|
||||||
chatId: InputPeerLike
|
chatId: InputPeerLike
|
|
@ -1,5 +1,4 @@
|
||||||
import { BaseTelegramClient } from '@mtcute/core'
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
|
||||||
import { InputPeerLike, MtInvalidPeerTypeError } from '../../types/index.js'
|
import { InputPeerLike, MtInvalidPeerTypeError } from '../../types/index.js'
|
||||||
import { isInputPeerChannel, isInputPeerChat, toInputChannel } from '../../utils/peer-utils.js'
|
import { isInputPeerChannel, isInputPeerChat, toInputChannel } from '../../utils/peer-utils.js'
|
||||||
import { resolvePeer } from '../users/resolve-peer.js'
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
@ -11,7 +10,7 @@ import { deleteHistory } from './delete-history.js'
|
||||||
* @param chatId Chat ID or username
|
* @param chatId Chat ID or username
|
||||||
*/
|
*/
|
||||||
export async function leaveChat(
|
export async function leaveChat(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
chatId: InputPeerLike,
|
chatId: InputPeerLike,
|
||||||
params?: {
|
params?: {
|
||||||
/**
|
/**
|
||||||
|
@ -27,14 +26,14 @@ export async function leaveChat(
|
||||||
_: 'channels.leaveChannel',
|
_: 'channels.leaveChannel',
|
||||||
channel: toInputChannel(chat),
|
channel: toInputChannel(chat),
|
||||||
})
|
})
|
||||||
client.network.handleUpdate(res)
|
client.handleClientUpdate(res)
|
||||||
} else if (isInputPeerChat(chat)) {
|
} else if (isInputPeerChat(chat)) {
|
||||||
const res = await client.call({
|
const res = await client.call({
|
||||||
_: 'messages.deleteChatUser',
|
_: 'messages.deleteChatUser',
|
||||||
chatId: chat.chatId,
|
chatId: chat.chatId,
|
||||||
userId: { _: 'inputUserSelf' },
|
userId: { _: 'inputUserSelf' },
|
||||||
})
|
})
|
||||||
client.network.handleUpdate(res)
|
client.handleClientUpdate(res)
|
||||||
|
|
||||||
if (params?.clear) {
|
if (params?.clear) {
|
||||||
await deleteHistory(client, chat)
|
await deleteHistory(client, chat)
|
|
@ -1,6 +1,5 @@
|
||||||
import { BaseTelegramClient } from '@mtcute/core'
|
import { assertTrue } from '../../../utils/type-assertions.js'
|
||||||
import { assertTrue } from '@mtcute/core/utils.js'
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
|
||||||
import { InputPeerLike } from '../../types/index.js'
|
import { InputPeerLike } from '../../types/index.js'
|
||||||
import { resolvePeer } from '../users/resolve-peer.js'
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
|
||||||
|
@ -9,7 +8,7 @@ import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
*
|
*
|
||||||
* @param chatId Chat ID
|
* @param chatId Chat ID
|
||||||
*/
|
*/
|
||||||
export async function markChatUnread(client: BaseTelegramClient, chatId: InputPeerLike): Promise<void> {
|
export async function markChatUnread(client: ITelegramClient, chatId: InputPeerLike): Promise<void> {
|
||||||
const r = await client.call({
|
const r = await client.call({
|
||||||
_: 'messages.markDialogUnread',
|
_: 'messages.markDialogUnread',
|
||||||
peer: {
|
peer: {
|
|
@ -1,9 +1,7 @@
|
||||||
import { BaseTelegramClient } from '@mtcute/core'
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
|
|
||||||
import { InputPeerLike } from '../../types/peers/index.js'
|
import { InputPeerLike } from '../../types/peers/index.js'
|
||||||
import { isInputPeerChannel } from '../../utils/peer-utils.js'
|
import { isInputPeerChannel } from '../../utils/peer-utils.js'
|
||||||
import { getPeerDialogs } from '../dialogs/get-peer-dialogs.js'
|
import { getPeerDialogs } from '../dialogs/get-peer-dialogs.js'
|
||||||
import { notifyChannelClosed, notifyChannelOpened } from '../updates/manager.js'
|
|
||||||
import { resolvePeer } from '../users/resolve-peer.js'
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -14,15 +12,13 @@ import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
*
|
*
|
||||||
* @param chat Chat to open
|
* @param chat Chat to open
|
||||||
*/
|
*/
|
||||||
export async function openChat(client: BaseTelegramClient, chat: InputPeerLike): Promise<void> {
|
export async function openChat(client: ITelegramClient, chat: InputPeerLike): Promise<void> {
|
||||||
const peer = await resolvePeer(client, chat)
|
const peer = await resolvePeer(client, chat)
|
||||||
|
|
||||||
if (isInputPeerChannel(peer)) {
|
if (isInputPeerChannel(peer)) {
|
||||||
const [dialog] = await getPeerDialogs(client, peer)
|
const [dialog] = await getPeerDialogs(client, peer)
|
||||||
|
|
||||||
if (!client.network.params.disableUpdates) {
|
await client.notifyChannelOpened(peer.channelId, dialog.raw.pts)
|
||||||
notifyChannelOpened(client, peer.channelId, dialog.raw.pts)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: once we have proper dialogs/peers db, we should also
|
// todo: once we have proper dialogs/peers db, we should also
|
||||||
|
@ -38,11 +34,11 @@ export async function openChat(client: BaseTelegramClient, chat: InputPeerLike):
|
||||||
*
|
*
|
||||||
* @param chat Chat to open
|
* @param chat Chat to open
|
||||||
*/
|
*/
|
||||||
export async function closeChat(client: BaseTelegramClient, chat: InputPeerLike): Promise<void> {
|
export async function closeChat(client: ITelegramClient, chat: InputPeerLike): Promise<void> {
|
||||||
const peer = await resolvePeer(client, chat)
|
const peer = await resolvePeer(client, chat)
|
||||||
|
|
||||||
if (isInputPeerChannel(peer) && !client.network.params.disableUpdates) {
|
if (isInputPeerChannel(peer)) {
|
||||||
notifyChannelClosed(client, peer.channelId)
|
await client.notifyChannelClosed(peer.channelId)
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: once we have proper dialogs/peers db, we should also
|
// todo: once we have proper dialogs/peers db, we should also
|
|
@ -1,8 +1,8 @@
|
||||||
import { BaseTelegramClient } from '@mtcute/core'
|
import { assertTrue } from '../../../utils/type-assertions.js'
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { InputPeerLike } from '../../types/index.js'
|
import { InputPeerLike } from '../../types/index.js'
|
||||||
import { assertTrue, isInputPeerChannel, isInputPeerUser, toInputChannel, toInputUser } from '../../utils/index.js'
|
import { isInputPeerChannel, isInputPeerUser, toInputChannel, toInputUser } from '../../utils/index.js'
|
||||||
import { isSelfPeer } from '../auth/_state.js'
|
import { isSelfPeer } from '../auth/utils.js'
|
||||||
import { resolvePeer } from '../users/resolve-peer.js'
|
import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -11,7 +11,7 @@ import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
* @param peerId Bot, channel or "me"/"self"
|
* @param peerId Bot, channel or "me"/"self"
|
||||||
*/
|
*/
|
||||||
export async function reorderUsernames(
|
export async function reorderUsernames(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
peerId: InputPeerLike,
|
peerId: InputPeerLike,
|
||||||
order: string[],
|
order: string[],
|
||||||
): Promise<void> {
|
): Promise<void> {
|
|
@ -1,5 +1,6 @@
|
||||||
import { BaseTelegramClient, tl } from '@mtcute/core'
|
import { tl } from '@mtcute/tl'
|
||||||
|
|
||||||
|
import { ITelegramClient } from '../../client.types.js'
|
||||||
import { InputPeerLike, MtInvalidPeerTypeError } from '../../types/index.js'
|
import { InputPeerLike, MtInvalidPeerTypeError } from '../../types/index.js'
|
||||||
import { normalizeDate } from '../../utils/misc-utils.js'
|
import { normalizeDate } from '../../utils/misc-utils.js'
|
||||||
import { isInputPeerChannel, toInputChannel } from '../../utils/peer-utils.js'
|
import { isInputPeerChannel, toInputChannel } from '../../utils/peer-utils.js'
|
||||||
|
@ -9,7 +10,7 @@ import { resolvePeer } from '../users/resolve-peer.js'
|
||||||
* Restrict a user in a supergroup.
|
* Restrict a user in a supergroup.
|
||||||
*/
|
*/
|
||||||
export async function restrictChatMember(
|
export async function restrictChatMember(
|
||||||
client: BaseTelegramClient,
|
client: ITelegramClient,
|
||||||
params: {
|
params: {
|
||||||
/** Chat ID */
|
/** Chat ID */
|
||||||
chatId: InputPeerLike
|
chatId: InputPeerLike
|
||||||
|
@ -56,5 +57,5 @@ export async function restrictChatMember(
|
||||||
...restrictions,
|
...restrictions,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
client.network.handleUpdate(res)
|
client.handleClientUpdate(res)
|
||||||
}
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue