Compare commits

..

No commits in common. "d98281f30fc5205190ecbabfb714e8f8eabd647d" and "690948b8b1e58af87b765990e50cfcf2d055212a" have entirely different histories.

9 changed files with 82 additions and 83 deletions

View file

@ -43,19 +43,6 @@ const client = new TelegramClient({ ... })
await client.importSession(convertFromGramjsSession("..."))
```
### Store session
In some version GramJS added support for storing session as a directory of files,
and can be imported like so:
```ts
import { readGramjsStoreSession, convertFromGramjsSession } from '@mtcute/convert'
const client = new TelegramClient({ ... })
const session = await readGramjsStoreSession('/path/to/session')
await client.importSession(convertFromGramjsSession(session))
```
## [MTKruto](https://github.com/MTKruto/MTKruto)
```ts
@ -65,19 +52,6 @@ const client = new TelegramClient({ ... })
await client.importSession(convertFromMtkrutoSession("..."))
```
## [Telegram Desktop](https://github.com/telegramdesktop/tdesktop) (tdata)
```ts
import { convertFromTdata } from '@mtcute/convert'
const client = new TelegramClient({ ... })
await client.importSession(convertFromTdata({
path: '/path/to/tdata',
ignoreVersion: true // note: this might break
// passcode: '123456' // if you have a passcode
}))
```
## Backwards
If you need to convert a session from mtcute to another library, you can use the `convertTo*` functions instead:

View file

@ -60,7 +60,7 @@ no extra steps are required.
## Bun
Support for Bun is provided in `@mtcute/bun` package, and
Experimental support for Bun is provided in `@mtcute/bun` package, and
Bun is also supported in `@mtcute/create-bot`.
```bash
@ -71,7 +71,7 @@ bun add @mtcute/bun
## Deno
Support for Deno is provided in `@mtcute/deno` package, which is published
Experimental support for Deno is provided in `@mtcute/deno` package, which is published
to the [jsr.io](https://jsr.io) registry:
```ts
@ -137,20 +137,34 @@ See also: [Tree-shaking](/guide/advanced/treeshaking.md)
## Other runtimes
mtcute strives to be as runtime-agnostic as possible, so it should work in any environment that supports some basic ES2020 features (notably, bigints. There's an [unofficial fork](https://github.com/cyan-2048/mtcute) that uses polyfills for bigints, if you're into that).
mtcute strives to be as runtime-agnostic as possible, so it should work in any environment that supports
some basic ES2020 features.
In case your runtime of choice is not listed above, you can try using `@mtcute/core` directly
You will need to provide your own implementations of storage, networking and crypto - feel free to take a look at web/node implementations for reference (or even extend them to better fit your needs, e.g. if some runtime only partially supports some Node.js APIs).
You will need to provide your own implementations of storage, networking and crypto - feel free to take a
look at web/node implementations for reference (or even extend them to better fit your needs, e.g. if some runtime
only partially supports some Node.js APIs).
```ts
import { TelegramClient } from '@mtcute/core/client.js'
import { setPlatform } from '@mtcute/core/platform.js'
setPlatform(new MyPlatform())
const tg = new TelegramClient({
...,
storage: new MyStorage(),
crypto: new MyCrypto()
transport: new MyTransport(),
platform: new MyPlatform(),
transport: () => new MyTransport(),
})
```
::: info
You only need to call `setPlatform` once, before creating any clients.
Platform is set once globally and cannot be changed afterwards.
It is safe to call `setPlatform` multiple times, as long as the constructor is the same - it will be ignored if the platform is already set.
A good starting point might be to use [WebPlatform](https://ref.mtcute.dev/classes/_mtcute_web.WebPlatform.html),
since it implements everything in portable JavaScript.
:::

View file

@ -103,7 +103,14 @@ You can handle these errors using `TelegramClient#onError`:
```ts
const tg = new TelegramClient(...)
tg.onError.add((err) => {
tg.onError((err, conn) => {
if (conn) {
// `err` is the error
// `conn` is the connection where the error happened
console.log(err, conn)
}
// `err` is not a connection-related error
console.log(err)
})
```
@ -112,8 +119,7 @@ tg.onError.add((err) => {
mtcute handles reconnection and stuff automatically, so you don't need to
call `.connect()` again!
This should primarily be used for logging and debugging, as well as some
edge cases where you might need access to low-level connection state
This should primarily be used for logging and debugging
:::
## Dispatcher errors

View file

@ -38,28 +38,29 @@ const tg = new TelegramClient({
The updates themselves are dispatched on the client as events (see [reference](https://ref.mtcute.dev/classes/_mtcute_core.index.TelegramClient.html#on)):
```ts
tg.onNewMessage.add((msg) => {
tg.on('new_message', (msg) => {
console.log(msg.text)
})
// You can also handle any supported update at once:
tg.onUpdate.add((upd) => {
tg.on('update', (upd) => {
if (upd.name === 'new_message') {
console.log(upd.data.text)
}
})
// As well as raw MTProto updates:
tg.onRawUpdate.add((upd, users, chats) => {
tg.on('raw_update', (upd, users, chats) => {
console.log(upd._)
})
```
::: tip
The handlers should be synchronous, so if you want to do something async, make sure to also handle the errors:
Client events are based on EventEmitter. It expects handlers to be synchronous,
so if you want to do something async, make sure to also handle the errors:
```ts
tg.onNewMessage.add(async (msg) => {
tg.on('new_message', async (msg) => {
try {
await msg.answerText('test')
} catch (e) {

View file

@ -9,7 +9,7 @@ To download a file, just use `downloadIterable`, `downloadStream`,
`downloadBuffer`or `downloadToFile` method on the object that represents a file, for example:
```ts
tg.onNewMessage.add(async (msg) => {
tg.on('new_message', async (msg) => {
if (msg.media?.type === 'photo') {
await tg.downloadToFile('download.jpg', msg.media)
}
@ -161,7 +161,7 @@ them you'll need to have some understanding of how files in MTProto work.
File ID is available in `.fileId` field:
```ts
tg.onNewMessage.add(async (msg) => {
tg.on('new_message', async (msg) => {
if (msg.media?.type === 'photo') {
console.log(msg.media.fileId)
}
@ -181,7 +181,7 @@ for different users/bots.
Unique File ID is available in `.uniqueFileId` field:
```ts
tg.onNewMessage.add(async (msg) => {
tg.on('new_message', async (msg) => {
if (msg.media?.type === 'photo') {
console.log(msg.media.uniqueFileId)
}

View file

@ -15,7 +15,7 @@ Instead of Dispatcher, you can also use client events (however you will miss
features that Dispatcher provides):
```ts
tg.onInlineQuery.add(async (query) => {
tg.on('inline_query', async (query) => {
await query.answer([])
})
```

View file

@ -29,18 +29,15 @@ and also caching won't work past a single run.
## SQLite storage
The preferred storage for a server application is the one using SQLite,
The preferred storage for a Node.js application is the one using SQLite,
because it does not require loading the entire thing into memory, and
is also faster than simply reading/writing a file.
mtcute implements sqlite storages in runtime-specific packages,
using the best libraries available for each runtime:
- Node.js: [better-sqlite3](https://www.npmjs.com/package/better-sqlite3)
- Bun: `bun:sqlite`
- Deno: [@db/sqlite](https://jsr.io/@db/sqlite)
mtcute implements it in a separate package, `@mtcute/sqlite`, and internally
uses [better-sqlite3](https://www.npmjs.com/package/better-sqlite3)
```ts{4}
import { SqliteStorage } from '@mtcute/node' // or '@mtcute/bun' / '@mtcute/deno'
import { SqliteStorage } from '@mtcute/sqlite'
const tg = new TelegramClient({
storage: new SqliteStorage('my-account.session')
@ -48,7 +45,7 @@ const tg = new TelegramClient({
```
::: tip
In runtime-specific packages, SQLite storage is the default,
If you are using `@mtcute/node`, SQLite storage is the default,
and you can simply pass a string with file name instead
of instantiating `SqliteStorage` manually:
@ -59,7 +56,8 @@ const tg = new TelegramClient({
```
:::
To improve performance, we use WAL mode by default ([Learn more](https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/performance.md)).
To improve performance, `@mtcute/sqlite` by default uses
WAL mode ([Learn more](https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/performance.md)).
When using WAL, along with your SQLite file there may also
be `-shm` and `-wal` files. If you don't like seeing those files,
@ -83,11 +81,8 @@ const tg = new TelegramClient({
})
```
> Note that the string passed will be used as-is as the database name,
> so you might want to prefix it to avoid conflicts.
::: tip
In `@mtcute/web`, IndexedDB storage is the default,
In the browser, IndexedDB storage is the default,
and you can simply pass a string with file name instead
of instantiating `IdbStorage` manually:
@ -149,14 +144,14 @@ Most of the string is occupied by 256 bytes long
MTProto authorization key, which, when Base64 encoded,
results in **344** characters. Additionally, information
about user (their ID and whether the user is a bot) and their DC
is included, which results in an average of ~**400** characters
is included, which results in an average of **407** characters
:::
## Implementing custom storage
The easiest way to implement a custom storage would be to make a subclass of `MemoryStorage`.
Additionaly, mtcute abstracts away the sqlite storage implementation, so you can use the the `BaseSqliteStorage` API to implement sqlite storage using your library of choice (see [Node.js implementation](https://github.com/mtcute/mtcute/tree/master/packages/node/src/sqlite) for reference).
The easiest way to implement a custom storage would be to make a subclass of `MemoryStorage`,
or check the [source code of SqliteStorage](https://github.com/mtcute/mtcute/blob/master/packages/sqlite/src/index.ts)
and implement something similar with your DB of choice.
### Architecture
@ -168,7 +163,8 @@ A storage provider in mtcute is composed of:
more efficient and organized access to the data. Repositories are registered in the driver and are used to
access the data in the storage
Such composable architecture allows for custom storages to implement a specific set of repositories, and to reuse the same driver for different providers.
Such composable architecture allows for custom storages to implement a specific set of repositories,
and to reuse the same driver for different providers.
In mtcute, these sets of repositories are defined:
- [IMtStorageProvider](https://ref.mtcute.dev/types/_mtcute_core.index.IMtStorageProvider.html), used by `BaseTelegramClient` for low-level

View file

@ -15,7 +15,7 @@ import { TcpTransport } from '@mtcute/node'
const tg = new TelegramClient({
// ...
transport: new TcpTransport()
transport: () => new TcpTransport()
})
```
@ -35,7 +35,7 @@ import { WebSocketTransport } from '@mtcute/web'
const tg = new TelegramClient({
// ...
transport: new WebSocketTransport()
transport: () => new WebSocketTransport()
})
```
@ -46,14 +46,19 @@ In browser, it is used automatically, you don't need to pass this explicitly
## HTTP(s) Proxy transport
To access Telegram via HTTP(s) proxy, you can use
`HttpProxyTcpTransport`, which is provided by runtime-specific packages:
`HttpProxyTcpTransport`, which is provided
by `@mtcute/http-proxy` (Node.js only):
```bash
pnpm add @mtcute/http-proxy
```
```ts{5-8}
import { HttpProxyTcpTransport } from '@mtcute/node' // or '@mtcute/bun' / '@mtcute/deno'
import { HttpProxyTcpTransport } from '@mtcute/http-proxy'
const tg = new TelegramClient({
// ...
transport: new HttpProxyTcpTransport({
transport: () => new HttpProxyTcpTransport({
host: '127.0.0.1',
port: 8080
})
@ -63,14 +68,19 @@ const tg = new TelegramClient({
## SOCKS4/5 Proxy transport
To access Telegram via SOCKS4/5 proxy, you can use
`SocksProxyTcpTransport`, which is provided by runtime-specific packages:
`SocksTcpTransport`, which is provided
by `@mtcute/socks-proxy` (Node.js only):
```bash
pnpm add @mtcute/socks-proxy
```
```ts{5-8}
import { SocksProxyTcpTransport } from '@mtcute/node' // or '@mtcute/bun' / '@mtcute/deno'
import { SocksTcpTransport } from '@mtcute/socks-proxy'
const tg = new TelegramClient({
// ...
transport: new SocksProxyTcpTransport({
transport: () => new SocksTcpTransport({
host: '127.0.0.1',
port: 8080
})
@ -80,14 +90,18 @@ const tg = new TelegramClient({
## MTProxy transport
To access Telegram via MTProxy (MTProto proxy), you can use
`MtProxyTcpTransport`, which is provided by runtime-specific packages:
`MtProxyTcpTransport`, which is provided by `@mtcute/mtproxy` (Node.js only):
```bash
pnpm add @mtcute/mtproxy
```
```ts{5-8}
import { MtProxyTcpTransport } from '@mtcute/node' // or '@mtcute/bun' / '@mtcute/deno'
import { MtProxyTcpTransport } from '@mtcute/mtproxy'
const tg = new TelegramClient({
// ...
transport: new MtProxyTcpTransport({
transport: () => new MtProxyTcpTransport({
host: '127.0.0.1',
port: 8080,
secret: '0123456789abcdef0123456789abcdef'
@ -108,11 +122,9 @@ could be used to change proxy used to connect to Telegram.
To change the transport, simply call `changeTransport`:
```ts
tg.mt.network.changeTransport(new MtProxyTcpTransport({...}))
tg.changeTransport(() => new MtProxyTcpTransport({...}))
```
> Note: the `mt` field is only available on `BaseTelegramClient` instances.
## Implementing custom transport
When targeting an environment which is not supported already,
@ -123,7 +135,3 @@ You can check out source code for the bundled transports
to get the basic idea
[here](https://github.com/mtcute/mtcute/tree/master/packages/core/src/network/transports),
and re-use any packet codecs that are included.
Transports in mtcute are built on top of [`@fuman/net`](https://github.com/teidesu/fuman/tree/main/packages/net), which is an in-house networking abstraction library used by mtcute.
It is a very powerful library which makes it super easy to implement custom transports.
There isn't much documentation, but feel free to check out the source code [here](https://github.com/teidesu/fuman/blob/main/packages/node/src/net/connection.ts).

View file

@ -1,13 +1,13 @@
import type { StringSessionData } from '@mtcute/core/utils.js'
import type { TelethonSession } from '../telethon/types.js'
import type { GramjsSession } from './types.js'
import { readStringSession } from '@mtcute/core/utils.js'
import { convertFromTelethonSession } from '../telethon/convert.js'
import { parseGramjsSession } from './parse.js'
import { serializeGramjsSession } from './serialize.js'
export function convertFromGramjsSession(session: GramjsSession | string): StringSessionData {
export function convertFromGramjsSession(session: TelethonSession | string): StringSessionData {
if (typeof session === 'string') {
session = parseGramjsSession(session)
}