Skip to Content
ReferenceNodeopentele2/mtcute

opentele2/mtcute

The mtcute side of the package: sessions and initConnection options for mtcute’s TelegramClient, a crypto provider on the core, and the client flows (QR login with 2FA, session admin, consistency checks, tdata from a client) run over an mtcute client.

mtcute.mjs
import { TelegramClient } from '@mtcute/node' import { loadTdata, profile } from 'opentele2' import { createCryptoProvider, initConnectionOptions, toStringSession } from 'opentele2/mtcute' const desktop = profile('TelegramDesktop') const { mainAccount } = await loadTdata('tdata') const client = new TelegramClient({ apiId: desktop.apiId, apiHash: desktop.apiHash, initConnectionOptions: initConnectionOptions(desktop), crypto: await createCryptoProvider(), }) await client.importSession(toStringSession(mainAccount))

Sessions and options

mtcute.d.ts
function toStringSession(account: AccountInput): string function initConnectionOptions(profile: ApiProfile): InitConnectionOptions function createCryptoProvider(): Promise<ICryptoProvider> interface InitConnectionOptions { deviceModel: string systemVersion: string appVersion: string systemLangCode: string langPack: string langCode: string params?: tl.TypeJSONValue }
FunctionDescription
toStringSession(account)The mtcute v3 string session of the account, for client.importSession() or the TelegramClient constructor.
initConnectionOptions(profile)The initConnectionOptions of a profile() or generate() result; pass apiId and apiHash to the client separately. A tdesktop profile also gets params with tz_offset, computed when the options are built.
createCryptoProvider()An mtcute ICryptoProvider whose every primitive is the core: hashes, HMAC, PBKDF2, AES-256-CTR and -IGE, pq factorisation, gzip and the OS random source. It needs neither Node’s crypto module nor @mtcute/node; its gzip writes a gzip stream.

FlowClient

The flows take any object with the members they use; an mtcute TelegramClient has them all.

mtcute.d.ts
interface FlowClient { call(request: { _: string; [field: string]: unknown }): Promise<any> getPrimaryDcId?(): Promise<number> changePrimaryDc?(dcId: number): Promise<void> notifyLoggedIn?(authorization: tl.auth.TypeAuthorization): Promise<unknown> getMe?(): Promise<{ id: number | bigint }> exportSession?(): Promise<string> disconnect?(): Promise<unknown> storage?: { clear(withAuthKeys?: boolean): Promise<unknown> } onServerUpdate?: { add(listener: (update: tl.TypeUpdates) => void): void remove(listener: (update: tl.TypeUpdates) => void): void } }

Only call is required everywhere, so a fake that answers it with canned TL objects drives every flow. changePrimaryDc is required for a QR login DC migration, exportSession by tdataFromClient, and disconnect with storage.clear to discard a session of another api id.

QR login

mtcute.d.ts
function qrLoginToNewClient<C extends FlowClient>( authorized: FlowClient, fresh: C, options: QrLoginOptions, ): Promise<QrLoginResult<C>> function postLoginRequests(client: FlowClient, langPack?: string, delay?: PostLoginDelay): Promise<number> interface QrLoginOptions { apiId?: number apiHash?: string password?: string profile?: ApiProfile postLogin?: boolean delay?: PostLoginDelay onUrl?: (url: string, expires: Date | null) => void } interface QrLoginResult<C extends FlowClient = FlowClient> { client: C; userId: number } type PostLoginDelay = (minMs: number, maxMs: number) => Promise<void> const QR_LOGIN_ATTEMPTS: number // 5 const QR_LOGIN_TIMEOUT: string const USER_ID_UNRESOLVED: string const POST_LOGIN_DELAYS_MS: ReadonlyArray<readonly [number, number] | null>

qrLoginToNewClient logs fresh, a client with empty storage, in through the authorised authorized by QR login: DC alignment, auth.exportLoginToken on fresh (following loginTokenMigrateTo), auth.acceptLoginToken on authorized, 2FA through account.getPassword and the native srpCheck, then the post-login requests.

OptionDescription
apiId, apiHashSent with auth.exportLoginToken; profile.apiId and profile.apiHash by default.
passwordThe 2FA password; without it a 2FA account rejects with OT_NO_PASSWORD_PROVIDED.
profileThe new client’s profile; its langPack drives the post-login requests.
postLoginWhether to send the post-login requests; true by default.
delayThe wait before each post-login request; a random sleep of randomDelayMs by default.
onUrlReceives each exported token’s qrLoginUrl and expiry before it is accepted.

An already authorised fresh of the same api id is returned as is with the EXISTING_SESSION_KEPT warning; one of another api id warns EXISTING_SESSION_REPLACED, has its session discarded locally (the old authorization is not terminated on the server) and is logged in again. The promise rejects with OT_NO_PASSWORD_PROVIDED, OT_PASSWORD_INCORRECT, OT_UNSUPPORTED_PASSWORD_ALGORITHM, OT_QR_LOGIN_TIMEOUT, OT_SIGN_UP_REQUIRED, OT_SRP_BAD_B or mtcute’s RpcError (AUTH_TOKEN_* included). postLoginRequests sends the post-login requests alone and resolves to how many failed.

Session admin

mtcute.d.ts
function isAuthorized(client: FlowClient): Promise<boolean> function getMeId(client: FlowClient): Promise<number> function getSessions(client: FlowClient): Promise<tl.account.RawAuthorizations> function getCurrentSession(client: FlowClient): Promise<tl.RawAuthorization | null> function terminateSession(client: FlowClient, hash: tl.Long): Promise<void> function terminateAllSessions(client: FlowClient): Promise<number> function sessionRow(authorization: tl.RawAuthorization): SessionRow & { current: boolean; officialApp: boolean } function formatSessions(source: FlowClient | tl.account.RawAuthorizations | tl.RawAuthorization[]): Promise<string> function isOfficialApp(client: FlowClient): Promise<boolean>
FunctionDescription
isAuthorized(client)Whether updates.getState succeeds.
getMeId(client)The self user id; rejects with OT_USER_ID_UNRESOLVED without one.
getSessions(client)account.getAuthorizations; rejects with OT_SESSIONS_UNAVAILABLE when the answer holds no list.
getCurrentSession(client)The session flagged current, else null.
terminateSession(client, hash)account.resetAuthorization; rejects with OT_FRESH_RESET_FORBIDDEN or OT_HASH_INVALID, the RPC error as cause.
terminateAllSessions(client)Ends every non-current session in list order and resolves to how many were ended.
sessionRow(authorization)The session table row of an mtcute authorization.
formatSessions(source)The session table for a client (its sessions are fetched), an account.authorizations answer or a list of authorizations.
isOfficialApp(client)Whether the current session is officialApp.

Consistency checks

mtcute.d.ts
function runConsistencyChecks( client: FlowClient, profile: ApiProfile, versions?: Versions | null, options?: ConsistencyOptions, ): Promise<CheckResult[]> interface ConsistencyOptions { layer?: number autoWarn?: boolean }

The seven check results for client used with profile, in consistencyChecks() order; a failing check emits the consistency warning with autoWarn (default true). layer is the library layer layer_match compares, @mtcute/core’s tl.LAYER by default. Join the results with consistencySummary.

tdata from a client

mtcute.d.ts
function tdataFromClient(client: FlowClient, options?: TdataFromClientOptions): Promise<TData> interface TdataFromClientOptions { passcode?: string | Uint8Array performanceMode?: boolean }

A new tdata folder with the client’s session as its only account: main DC and auth key from client.exportSession(), user id from getMeId. Save it with saveTdata. To store a new session instead of the client’s own, log one in with qrLoginToNewClient first.

Last updated on