diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index 4102091e..56ef75f2 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -115,6 +115,7 @@ export default ({ mode }) => defineConfig({ { text: 'Converting sessions', link: '/guide/advanced/session-convert' }, { text: 'Network middlewares', link: '/guide/advanced/net-middlewares' }, { text: 'Object serialization', link: '/guide/advanced/serialization' }, + { text: 'Custom schema', link: '/guide/advanced/custom-schema' }, ], }, ], diff --git a/docs/guide/advanced/custom-schema.md b/docs/guide/advanced/custom-schema.md new file mode 100644 index 00000000..90a1aa8b --- /dev/null +++ b/docs/guide/advanced/custom-schema.md @@ -0,0 +1,100 @@ +# Custom schema + +::: danger +While this *is* a somewhat supported feature/use-case, very limited support is provided +because of the nature of the feature. + +When having any problems with the **implementation**, feel free to open an issue. + +In all other cases linked to usage of this, but not caused by the implementation itself +(e.g. internal state breaking, storage corruption, missing updates, wrong types, etc.), please deal with it as you see fit. +::: + +In some cases it might be viable for you to use a custom schema for your bot, +including but not limited to: + +- Using a yet unreleased layer (e.g. taken from [Telegram Android](https://github.com/TGScheme/Schema)) +- Using a newer layer before the library is updated to support it +- Using an older layer +- Using undocumented/non-existent constructors (e.g. fuzzing) + +## Basics + +At the base level, mtcute provides a special `mtcute.customMethod` method that basically forwards +the bytes you pass to the server as-is, without any additional serialization, and return the result as-is too: + +```ts +const res = tg.call({ + _: 'mtcute.customMethod', + // `bytes` is the raw TL serialization of the method you want to call + bytes: new Uint8Array([0xde, 0xad, 0xbe, 0xef]) +}) +// res is the raw TL serialization of the result +console.log(res) +``` + +Additionally, there's `overrideLayer` client option that allows you to override the layer number: + +```ts +const tg = new TelegramClient({ + ..., + overrideLayer: 1337 +}) +``` + +## Parsing TL schema + +However, manually de/serializing everything would be super tedious, +so you can use `@mtcute/tl-utils` to code-gen everything on demand: + +```ts +import { patchRuntimeTlSchema } from '@mtcute/tl-utils' +// note: make sure @mtcute/tl version matches the one used by @mtcute/core +import { __tlReaderMap } from '@mtcute/tl/binary/reader.js' +import { __tlWriterMap } from '@mtcute/tl/binary/writer.js' + +// here you can pass just the difference between +// the built-in schema and the custom one +const nextSchema = patchRuntimeTlSchema(` +updateWoof from:Peer = Update; +---functions--- +woof.bark at:InputPeer = Bool; +`.trim(), __tlReaderMap, __tlWriterMap) +``` +::: tip +`patchRuntimeTlSchema` uses `eval` under the hood, so it might not work in all environments +::: + +Once parsed, you can pass `nextSchema` to `TlBinaryReader` and `TlBinaryWriter` to use it: + +```ts +import { TlBinaryReader, TlBinaryWriter } from '@mtcute/tl-runtime' + +const r = await tg.call({ + _: 'mtcute.customMethod', + bytes: TlBinaryWriter.serializeObject(nextSchema.writerMap, { + _: 'woof.bark', + at: await tg.resolvePeer('teidesu') + } as any) +}) + +console.log(TlBinaryReader.deserializeObject(nextSchema.readerMap, r)) +``` + +## Updates + +Handling new updates is a bit more involved, since there is no request-response mechanism, +so you will have to hack into the inners of the library. + +```ts +const tg = new TelegramClient({ + ..., + readerMap: nextSchema.readerMap +}) + +tg.onRawUpdate.add(({ update, peers }) => { + if (update._ === 'updateWoof') { + console.log('got woof from %o', peers.get(update.at)) + } +}) +``` \ No newline at end of file diff --git a/docs/guide/intro/updates.md b/docs/guide/intro/updates.md index e58a95dd..d1aaa12e 100755 --- a/docs/guide/intro/updates.md +++ b/docs/guide/intro/updates.md @@ -50,8 +50,8 @@ tg.onUpdate.add((upd) => { }) // As well as raw MTProto updates: -tg.onRawUpdate.add((upd, users, chats) => { - console.log(upd._) +tg.onRawUpdate.add(({ update, peers }) => { + console.log(update._) }) ```