Ver código fonte

massive overhaul

painor 4 anos atrás
pai
commit
057be18646
100 arquivos alterados com 5828 adições e 2330 exclusões
  1. 5 0
      .bablerc
  2. 8 0
      .eslintignore
  3. 40 0
      .eslintrc.json
  4. 10 0
      .github/workflows/lint.yml
  5. 25 7
      .gitignore
  6. 31 0
      .npmignore
  7. 21 0
      LICENSE
  8. 21 0
      README.md
  9. 41 0
      __tests__/crypto/AES.spec.js
  10. 19 0
      __tests__/crypto/calcKey.spec.js
  11. 11 0
      __tests__/crypto/factorizator.spec.js
  12. 70 0
      __tests__/crypto/readBuffer.spec.js
  13. 107 0
      __tests__/extensions/HTML.spec.js
  14. 95 0
      __tests__/extensions/Markdown.spec.js
  15. 100 0
      __tests__/extensions/Scanner.spec.js
  16. 19 0
      babel.config.js
  17. 38 0
      examples/betterLogging.js
  18. 13 0
      examples/main.js
  19. 47 0
      examples/simpleLogin.html
  20. 78 0
      examples/simpleLogin.js
  21. 12 0
      gramjs/.editorconfig
  22. 14 5
      gramjs/Helpers.js
  23. 1 0
      gramjs/Password.js
  24. 7 15
      gramjs/Utils.js
  25. 1 0
      gramjs/Version.js
  26. 22 0
      gramjs/client/TelegramClient.d.ts
  27. 74 619
      gramjs/client/TelegramClient.js
  28. 138 42
      gramjs/client/auth.ts
  29. 189 0
      gramjs/client/downloadFile.ts
  30. 2 27
      gramjs/client/uploadFile.ts
  31. 0 0
      gramjs/crypto/AuthKey.js
  32. 0 0
      gramjs/crypto/CTR.js
  33. 0 0
      gramjs/crypto/Factorizator.js
  34. 37 0
      gramjs/crypto/IGE.js
  35. 22 45
      gramjs/crypto/RSA.js
  36. 55 0
      gramjs/crypto/converters.ts
  37. 124 0
      gramjs/crypto/crypto.js
  38. 51 0
      gramjs/crypto/words.ts
  39. 4 1
      gramjs/errors/Common.js
  40. 0 0
      gramjs/errors/RPCBaseErrors.js
  41. 0 0
      gramjs/errors/index.js
  42. 0 0
      gramjs/events/NewMessage.js
  43. 21 0
      gramjs/events/Raw.js
  44. 22 0
      gramjs/events/common.js
  45. 8 0
      gramjs/events/index.js
  46. 30 0
      gramjs/extensions/AsyncQueue.js
  47. 0 0
      gramjs/extensions/BinaryReader.js
  48. 15 0
      gramjs/extensions/BinaryWriter.js
  49. 9 9
      gramjs/extensions/Logger.js
  50. 0 0
      gramjs/extensions/MessagePacker.js
  51. 0 0
      gramjs/extensions/PromisedWebSockets.js
  52. 0 0
      gramjs/extensions/index.js
  53. 10 0
      gramjs/index.d.ts
  54. 16 0
      gramjs/index.js
  55. 7 5
      gramjs/network/Authenticator.js
  56. 0 0
      gramjs/network/MTProtoPlainSender.js
  57. 7 5
      gramjs/network/MTProtoSender.js
  58. 5 5
      gramjs/network/MTProtoState.js
  59. 0 0
      gramjs/network/RequestState.js
  60. 0 0
      gramjs/network/connection/Connection.js
  61. 0 0
      gramjs/network/connection/TCPAbridged.js
  62. 57 0
      gramjs/network/connection/TCPFull.js
  63. 0 0
      gramjs/network/connection/TCPObfuscated.js
  64. 11 0
      gramjs/network/connection/index.js
  65. 0 0
      gramjs/network/index.js
  66. 0 0
      gramjs/sessions/Abstract.js
  67. 0 0
      gramjs/sessions/CacheApiSession.js
  68. 2 2
      gramjs/sessions/Memory.js
  69. 18 0
      gramjs/sessions/StringSession.js
  70. 2 2
      gramjs/sessions/index.js
  71. 42 0
      gramjs/tl/MTProtoRequest.js
  72. 845 55
      gramjs/tl/api.d.ts
  73. 37 110
      gramjs/tl/api.js
  74. 9 2
      gramjs/tl/core/GZIPPacked.js
  75. 0 0
      gramjs/tl/core/MessageContainer.js
  76. 0 0
      gramjs/tl/core/RPCResult.js
  77. 0 0
      gramjs/tl/core/TLMessage.js
  78. 17 0
      gramjs/tl/core/index.js
  79. 326 0
      gramjs/tl/generationHelpers.js
  80. 4 3
      gramjs/tl/index.js
  81. 66 12
      gramjs/tl/static/api.reduced.tl
  82. 1500 0
      gramjs/tl/static/api.tl
  83. 37 0
      gramjs/tl/static/schema.reduced.tl
  84. 0 0
      gramjs/tl/static/schema.tl
  85. 57 0
      gramjs/tl/types-generator/generate.js
  86. 219 0
      gramjs/tl/types-generator/template.js
  87. 186 0
      index.js
  88. 188 0
      jest.config.js
  89. 462 362
      package-lock.json
  90. 41 79
      package.json
  91. 0 13
      src/@types/global.d.ts
  92. 0 64
      src/api/gramjs/builders/chats.ts
  93. 0 34
      src/api/gramjs/builders/common.ts
  94. 0 208
      src/api/gramjs/builders/messages.ts
  95. 0 13
      src/api/gramjs/builders/peers.ts
  96. 0 39
      src/api/gramjs/builders/users.ts
  97. 0 212
      src/api/gramjs/client.ts
  98. 0 122
      src/api/gramjs/connectors/auth.ts
  99. 0 129
      src/api/gramjs/connectors/chats.ts
  100. 0 84
      src/api/gramjs/connectors/files.ts

+ 5 - 0
.bablerc

@@ -0,0 +1,5 @@
+ {
+ "presets": [
+      "@babel/preset-env"
+    ]
+ }

+ 8 - 0
.eslintignore

@@ -0,0 +1,8 @@
+gramjs_generator/data/html/js/search.js
+gramjs/tl/functions
+gramjs/tl/patched
+gramjs/tl/types
+gramjs/tl/AllTLObjects.js
+gramjs/errors/RPCErrorList.js
+browser/
+example.js

+ 40 - 0
.eslintrc.json

@@ -0,0 +1,40 @@
+{
+    "env": {
+        "commonjs": true,
+        "es6": true,
+        "node": true,
+        "jest": true
+    },
+    "extends": ["eslint:recommended"],
+    "globals": {
+        "BigInt": true,
+        "Atomics": "readonly",
+        "SharedArrayBuffer": "readonly"
+    },
+    "parser": "babel-eslint",
+    "parserOptions": {
+        "ecmaVersion": 2018
+    },
+    "rules": {
+        "arrow-parens": ["error", "as-needed"],
+        "brace-style": ["error", "1tbs"],
+        "comma-dangle": ["error", "always-multiline"],
+        "curly": ["error", "all"],
+        "indent": ["error", 4],
+        "linebreak-style": ["error", "unix"],
+        "no-var": "error",
+        "operator-linebreak": ["error", "after"],
+        "prefer-const": ["error", { "destructuring": "any" }],
+        "quotes": ["error", "single", { "avoidEscape": true }],
+        "semi": ["error", "never"],
+        "max-len": [
+            "error",
+            {
+                "code": 120,
+                "ignoreUrls": true,
+                "ignoreStrings": true,
+                "ignoreTemplateLiterals": true
+            }
+        ]
+    }
+}

+ 10 - 0
.github/workflows/lint.yml

@@ -0,0 +1,10 @@
+name: Lint
+on: [push, pull_request]
+jobs:
+    lint:
+        runs-on: ubuntu-latest
+        steps:
+            - uses: actions/checkout@v2
+            - uses: Adzz/yarn_command_action@v1.0.0
+              with:
+                  command: lint

+ 25 - 7
.gitignore

@@ -1,8 +1,26 @@
-node_modules
-dist
-.cache
+/node_modules/
+/.vscode/
+/.idea/
+# Generated code
+/docs/
+/gramjs/tl/functions/
+/gramjs/tl/types/
+/gramjs/tl/patched/
+/gramjs/tl/AllTLObjects.js
+/gramjs/errors/RPCErrorList.js
+/dist/
+/coverage/
+
+# User session
+*.session
+usermedia/
+
+# Quick tests should live in this file
+example.js
+
+# dotenv
 .env
 .env
-src/lib/gramjs/build/
-build-contest/
-.idea
-*.iml
+
+settings
+
+/browser/

+ 31 - 0
.npmignore

@@ -0,0 +1,31 @@
+/node_modules/
+/.vscode/
+/.idea/
+# Generated code
+/docs/
+/gramjs/tl/functions/
+/gramjs/tl/types/
+/gramjs/tl/patched/
+/gramjs/tl/AllTLObjects.js
+/gramjs/errors/RPCErrorList.js
+/dist/
+
+# User session
+*.session
+usermedia/
+
+# Quick tests should live in this file
+example.js
+
+# dotenv
+.env
+
+settings
+
+/browser/
+
+.babelrc
+.eslintignore
+.eslintrc.json
+webpack.config.babel.js
+/examples/

+ 21 - 0
LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 GramJS
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 21 - 0
README.md

@@ -0,0 +1,21 @@
+# GramJS
+**GramJS** is Telegram client implementation in Javascript. This project's _core_ is **completely based** on
+[Telethon](https://github.com/LonamiWebs/Telethon). All the files which are fully based on it.
+don't forget to have a look to the original project.
+
+### Obtaining your `API ID` and `Hash`
+1. Follow [this link](https://my.telegram.org) and login with your phone number.
+2. Click under `API Development tools`.
+3. A `Create new application` window will appear. Fill in your application details.
+There is no need to enter any `URL`, and only the first two fields (`App title` and `Short name`)
+can be changed later as long as I'm aware.
+4. Click on `Create application` at the end. Now that you have the `API ID` and `Hash`
+
+## Running GramJS
+First of all, you need to run the `index.js` by issuing `node index.js gen`. This will generate all the
+TLObjects from the given `scheme.tl` file.
+Then check the `examples` folder to check how to use the library
+
+## Using raw api
+Currently you can use any raw api function using `await client.invoke(new RequestClass(args))` .
+you can find all the requests and types at https://gram.js.org/

+ 41 - 0
__tests__/crypto/AES.spec.js

@@ -0,0 +1,41 @@
+const AES = require('../../gramjs/crypto/AES')
+const AESModeCTR = require('../../gramjs/crypto/AESCTR')
+describe('IGE encrypt function', () => {
+    test('it should return 4a657a834edc2956ec95b2a42ec8c1f2d1f0a6028ac26fd830ed23855574b4e69dd1a2be2ba18a53a49b879b2' +
+        '45e1065e14b6e8ac5ba9b24befaff3209b77b5f', () => {
+        const plainText = Buffer.from('this should hold a 64 characters long string. only 10 more left.')
+        const iv = Buffer.from('the iv needs 32 characters long.')
+        const key = Buffer.from('the key needs 32 characters long')
+        const encrypted = Buffer.from('4a657a834edc2956ec95b2a42ec8c1f2d1f0a6028ac26fd830ed23855574b4e69dd1a2be' +
+            '2ba18a53a49b879b245e1065e14b6e8ac5ba9b24befaff3209b77b5f', 'hex')
+        expect(AES.encryptIge(plainText, key, iv)).toEqual(encrypted)
+    })
+})
+describe('IGE decrypt function', () => {
+    test('it should return "this should hold a 64 characters long string. only 10 more left."', () => {
+        const encrypted = Buffer.from('4a657a834edc2956ec95b2a42ec8c1f2d1f0a6028ac26fd830ed23855574b4e69dd1a2be' +
+            '2ba18a53a49b879b245e1065e14b6e8ac5ba9b24befaff3209b77b5f', 'hex')
+        const iv = Buffer.from('the iv needs 32 characters long.')
+        const key = Buffer.from('the key needs 32 characters long')
+        const plainText = Buffer.from('this should hold a 64 characters long string. only 10 more left.')
+        expect(AES.decryptIge(encrypted, key, iv)).toEqual(plainText)
+
+    })
+})
+describe('CTR encrypt function', () => {
+    test('it should return 5f40f14f8b70178f70e8045b44eff5f1b148714f23cd and' +
+        ' cd0779d148b466935cf573450212451692bc82fccd5b106e53', () => {
+        const encryptKey = Buffer.from('the key needs 32 characters long')
+        const encryptIv = Buffer.from('the iv does not.')
+        const encryptor = new AESModeCTR(encryptKey, encryptIv)
+        const firstData = Buffer.from('this can be any length')
+        const firstResult = encryptor.encrypt(firstData)
+        const secondData = Buffer.from('this also can be anything')
+        const secondResult = encryptor.encrypt(secondData)
+
+        const outputFirst = Buffer.from('5f40f14f8b70178f70e8045b44eff5f1b148714f23cd', 'hex')
+        const outputSecond = Buffer.from('cd0779d148b466935cf573450212451692bc82fccd5b106e53', 'hex')
+        expect([firstResult, secondResult]).toEqual([outputFirst, outputSecond])
+    })
+})
+

+ 19 - 0
__tests__/crypto/calcKey.spec.js

@@ -0,0 +1,19 @@
+const MTProtoState = require('../../gramjs/network/MTProtoState')
+
+describe('calcKey function', () => {
+    test('it should return 0x93355e3f1f50529b6fb93eaf97f29b69c16345f53621e9d45cd9a11ddfbebac9 and' +
+        ' 11e94363ad7145222e2fbac4aaa27f01a6d832fb8115e89395bc43e23f868e47', () => {
+        const authKey = Buffer.from('bbf38532a79cd64363b490b3bc5e258adfc1d1a67ef3c6d322caac603f90a15215b609' +
+            '0ccb2226b477b24eb3412757d078d53c72b81864d1376ff20eb405a591781726495407628d8d611e37ecd6e23c605b57c5' +
+            '3b40270bac7e7de0312a5deb3a1a16e65808b944fcf700d3788da10074d5c088e9e6aca119320d7f07c16d7e3c9fd48e9d' +
+            '3f50ccc5276a30002d9919831bf783c368ce4b3e6f25f95875ec9315523cfcaa3ee50b1e40e5552cee2e16eec86b46308c' +
+            '97f808d58f249479bb0ee1b7b08cf7f0fc047fbe38df6083558494e732dbf26d16b1538c22d361bf31d3dc4f2b2cb115b3' +
+            'bfac1ec45c960e0854221cf484533025fa679a9b7a8ae11a00', 'hex')
+        const msgKey = Buffer.from('00f285b0bf254b5242e075bf87806c51', 'hex')
+        const aesKey = Buffer.from('93355e3f1f50529b6fb93eaf97f29b69c16345f53621e9d45cd9a11ddfbebac9', 'hex')
+        const aesIv = Buffer.from('11e94363ad7145222e2fbac4aaa27f01a6d832fb8115e89395bc43e23f868e47', 'hex')
+        const { key, iv } = new MTProtoState()._calcKey(authKey, msgKey, false)
+
+        expect([aesKey, aesIv]).toEqual([key, iv])
+    })
+})

+ 11 - 0
__tests__/crypto/factorizator.spec.js

@@ -0,0 +1,11 @@
+const Factorizator = require('../../gramjs/crypto/Factorizator')
+
+describe('calcKey function', () => {
+    test('it should return 0x20a13b25e1726bfc', () => {
+        const input = BigInt('325672672642762197972197217945794795197912791579174576454600704764276407047277')
+        const { p, q } = Factorizator.factorize(input)
+        const outP = BigInt(19)
+        const outQ = BigInt('17140666981198010419589327260304989220942778504167082971294773934961916160383')
+        expect([p, q]).toEqual([outP, outQ])
+    })
+})

+ 70 - 0
__tests__/crypto/readBuffer.spec.js

@@ -0,0 +1,70 @@
+const Helpers = require('../../gramjs/Helpers')
+
+describe('readBufferFromBigInt 8 bytes function', () => {
+    test('it should return 0x20a13b25e1726bfc', () => {
+        const input = BigInt('-257986242325798624')
+        const output = Buffer.from('20a13b25e1726bfc', 'hex')
+        expect(Helpers.readBufferFromBigInt(input, 8, true, true)).toEqual(output)
+    })
+    test('it should return 0xe05ec4da1e8d9403', () => {
+        const input = BigInt('257986242325798624')
+        const output = Buffer.from('e05ec4da1e8d9403', 'hex')
+        expect(Helpers.readBufferFromBigInt(input, 8, true, false)).toEqual(output)
+    })
+    test('it should return 0xfc6b72e1253ba120', () => {
+        const input = BigInt('-257986242325798624')
+        const output = Buffer.from('fc6b72e1253ba120', 'hex')
+        expect(Helpers.readBufferFromBigInt(input, 8, false, true)).toEqual(output)
+    })
+    test('it should return 0x03948d1edac45ee0', () => {
+        const input = BigInt('257986242325798624')
+        const output = Buffer.from('03948d1edac45ee0', 'hex')
+        expect(Helpers.readBufferFromBigInt(input, 8, false, false)).toEqual(output)
+    })
+})
+
+describe('readBufferFromBigInt 16 bytes function', () => {
+    test('it should return 0x8416c07962dac053b4346df39e5d97ec', () => {
+        const input = BigInt('-25798624232579862436622316998984984956')
+        const output = Buffer.from('8416c07962dac053b4346df39e5d97ec', 'hex')
+        expect(Helpers.readBufferFromBigInt(input, 16, true, true)).toEqual(output)
+    })
+    test('it should return 0x7ce93f869d253fac4bcb920c61a26813', () => {
+        const input = BigInt('25798624232579862436622316998984984956')
+        const output = Buffer.from('7ce93f869d253fac4bcb920c61a26813', 'hex')
+        expect(Helpers.readBufferFromBigInt(input, 16, true, false)).toEqual(output)
+    })
+    test('it should return 0xec975d9ef36d34b453c0da6279c01684', () => {
+        const input = BigInt('-25798624232579862436622316998984984956')
+        const output = Buffer.from('ec975d9ef36d34b453c0da6279c01684', 'hex')
+        expect(Helpers.readBufferFromBigInt(input, 16, false, true)).toEqual(output)
+    })
+    test('it should return 0x1368a2610c92cb4bac3f259d863fe97c', () => {
+        const input = BigInt('25798624232579862436622316998984984956')
+        const output = Buffer.from('1368a2610c92cb4bac3f259d863fe97c', 'hex')
+        expect(Helpers.readBufferFromBigInt(input, 16, false, false)).toEqual(output)
+    })
+})
+
+describe('readBufferFromBigInt 32 bytes function', () => {
+    test('it should return 0x7f113f5e2096936ec90cc4c73cc7bd3c96d20c115bf9ceb05c34232c037ff6c6', () => {
+        const input = BigInt('-25798624232579862436622316998984984912345482145214526587420145210501554564737')
+        const output = Buffer.from('7f113f5e2096936ec90cc4c73cc7bd3c96d20c115bf9ceb05c34232c037ff6c6', 'hex')
+        expect(Helpers.readBufferFromBigInt(input, 32, true, true)).toEqual(output)
+    })
+    test('it should return 0x81eec0a1df696c9136f33b38c33842c3692df3eea406314fa3cbdcd3fc800939', () => {
+        const input = BigInt('25798624232579862436622316998984984912345482145214526587420145210501554564737')
+        const output = Buffer.from('81eec0a1df696c9136f33b38c33842c3692df3eea406314fa3cbdcd3fc800939', 'hex')
+        expect(Helpers.readBufferFromBigInt(input, 32, true, false)).toEqual(output)
+    })
+    test('it should return 0xc6f67f032c23345cb0cef95b110cd2963cbdc73cc7c40cc96e9396205e3f117f', () => {
+        const input = BigInt('-25798624232579862436622316998984984912345482145214526587420145210501554564737')
+        const output = Buffer.from('c6f67f032c23345cb0cef95b110cd2963cbdc73cc7c40cc96e9396205e3f117f', 'hex')
+        expect(Helpers.readBufferFromBigInt(input, 32, false, true)).toEqual(output)
+    })
+    test('it should return 0x390980fcd3dccba34f3106a4eef32d69c34238c3383bf336916c69dfa1c0ee81', () => {
+        const input = BigInt('25798624232579862436622316998984984912345482145214526587420145210501554564737')
+        const output = Buffer.from('390980fcd3dccba34f3106a4eef32d69c34238c3383bf336916c69dfa1c0ee81', 'hex')
+        expect(Helpers.readBufferFromBigInt(input, 32, false, false)).toEqual(output)
+    })
+})

+ 107 - 0
__tests__/extensions/HTML.spec.js

@@ -0,0 +1,107 @@
+const { HTMLParser } = require('../../gramjs/extensions/HTML')
+const types = require('../../gramjs/tl/types')
+
+describe('HTMLParser', () => {
+    test('it should construct a new HTMLParser', () => {
+        const parser = new HTMLParser('Hello world')
+        expect(parser.text).toEqual('')
+        expect(parser.entities).toEqual([])
+    })
+
+    describe('.parse', () => {
+        test('it should parse bold entities', () => {
+            const parser = new HTMLParser('Hello <strong>world</strong>')
+            const [text, entities] = parser.parse()
+            expect(text).toEqual('Hello world')
+            expect(entities.length).toEqual(1)
+            expect(entities[0]).toBeInstanceOf(types.MessageEntityBold)
+        })
+
+        test('it should parse italic entities', () => {
+            const parser = new HTMLParser('Hello <em>world</em>')
+            const [text, entities] = parser.parse()
+            expect(text).toEqual('Hello world')
+            expect(entities.length).toEqual(1)
+            expect(entities[0]).toBeInstanceOf(types.MessageEntityItalic)
+        })
+
+        test('it should parse code entities', () => {
+            const parser = new HTMLParser('Hello <code>world</code>')
+            const [text, entities] = parser.parse()
+            expect(text).toEqual('Hello world')
+            expect(entities.length).toEqual(1)
+            expect(entities[0]).toBeInstanceOf(types.MessageEntityCode)
+        })
+
+        test('it should parse pre entities', () => {
+            const parser = new HTMLParser('Hello <pre>world</pre>')
+            const [text, entities] = parser.parse()
+            expect(text).toEqual('Hello world')
+            expect(entities.length).toEqual(1)
+            expect(entities[0]).toBeInstanceOf(types.MessageEntityPre)
+        })
+
+        test('it should parse strike entities', () => {
+            const parser = new HTMLParser('Hello <del>world</del>')
+            const [text, entities] = parser.parse()
+            expect(text).toEqual('Hello world')
+            expect(entities.length).toEqual(1)
+            expect(entities[0]).toBeInstanceOf(types.MessageEntityStrike)
+        })
+
+        test('it should parse link entities', () => {
+            const parser = new HTMLParser('Hello <a href="https://hello.world">world</a>')
+            const [text, entities] = parser.parse()
+            expect(text).toEqual('Hello world')
+            expect(entities.length).toEqual(1)
+            expect(entities[0]).toBeInstanceOf(types.MessageEntityTextUrl)
+            expect(entities[0].url).toEqual('https://hello.world')
+        })
+
+        test('it should parse nested entities', () => {
+            const parser = new HTMLParser('Hello <strong><em>world</em></strong>')
+            const [text, entities] = parser.parse()
+            expect(text).toEqual('Hello world')
+            expect(entities.length).toEqual(2)
+            expect(entities[0]).toBeInstanceOf(types.MessageEntityItalic)
+            expect(entities[1]).toBeInstanceOf(types.MessageEntityBold)
+        })
+
+        test('it should parse multiple entities', () => {
+            const parser = new HTMLParser('<em>Hello</em> <strong>world</strong>')
+            const [text, entities] = parser.parse()
+            expect(text).toEqual('Hello world')
+            expect(entities.length).toEqual(2)
+            expect(entities[0]).toBeInstanceOf(types.MessageEntityItalic)
+            expect(entities[1]).toBeInstanceOf(types.MessageEntityBold)
+        })
+    })
+
+    describe('.unparse', () => {
+        test('it should create a markdown string from raw text and entities', () => {
+            const unparsed = '<strong>hello</strong> <em>hello</em> <del>hello</del> <code>hello</code> <pre>hello</pre> <a href="https://hello.world">hello</a>'
+            const strippedText = 'hello hello hello hello hello hello'
+            const rawEntities = [
+                new types.MessageEntityBold({ offset: 0, length: 5 }),
+                new types.MessageEntityItalic({ offset: 6, length: 5 }),
+                new types.MessageEntityStrike({ offset: 12, length: 5 }),
+                new types.MessageEntityCode({ offset: 18, length: 5 }),
+                new types.MessageEntityPre({ offset: 24, length: 5 }),
+                new types.MessageEntityTextUrl({ offset: 30, length: 5, url: 'https://hello.world' }),
+            ]
+            const text = HTMLParser.unparse(strippedText, rawEntities)
+            expect(text).toEqual(unparsed)
+        })
+
+        test('it should unparse nested entities', () => {
+            const unparsed = '<strong><em>Hello world</em></strong>'
+            const strippedText = 'Hello world'
+            const rawEntities = [
+                new types.MessageEntityBold({ offset: 0, length: 11 }),
+                new types.MessageEntityItalic({ offset: 0, length: 11 }),
+            ]
+            const text = HTMLParser.unparse(strippedText, rawEntities)
+            expect(text).toEqual(unparsed)
+        })
+    })
+})

+ 95 - 0
__tests__/extensions/Markdown.spec.js

@@ -0,0 +1,95 @@
+const { MarkdownParser } = require('../../gramjs/extensions/Markdown')
+const types = require('../../gramjs/tl/types')
+
+describe('MarkdownParser', () => {
+    test('it should construct a new MarkdownParser', () => {
+        const parser = new MarkdownParser('Hello world')
+        expect(parser.text).toEqual('')
+        expect(parser.entities).toEqual([])
+    })
+
+    describe('.parse', () => {
+        test('it should parse bold entities', () => {
+            const parser = new MarkdownParser('Hello **world**')
+            const [text, entities] = parser.parse()
+            expect(text).toEqual('Hello world')
+            expect(entities.length).toEqual(1)
+            expect(entities[0]).toBeInstanceOf(types.MessageEntityBold)
+        })
+
+        test('it should parse italic entities', () => {
+            const parser = new MarkdownParser('Hello __world__')
+            const [text, entities] = parser.parse()
+            expect(text).toEqual('Hello world')
+            expect(entities.length).toEqual(1)
+            expect(entities[0]).toBeInstanceOf(types.MessageEntityItalic)
+        })
+
+        test('it should parse code entities', () => {
+            const parser = new MarkdownParser('Hello `world`')
+            const [text, entities] = parser.parse()
+            expect(text).toEqual('Hello world')
+            expect(entities.length).toEqual(1)
+            expect(entities[0]).toBeInstanceOf(types.MessageEntityCode)
+        })
+
+        test('it should parse pre entities', () => {
+            const parser = new MarkdownParser('Hello ```world```')
+            const [text, entities] = parser.parse()
+            expect(text).toEqual('Hello world')
+            expect(entities.length).toEqual(1)
+            expect(entities[0]).toBeInstanceOf(types.MessageEntityPre)
+        })
+
+        test('it should parse strike entities', () => {
+            const parser = new MarkdownParser('Hello ~~world~~')
+            const [text, entities] = parser.parse()
+            expect(text).toEqual('Hello world')
+            expect(entities.length).toEqual(1)
+            expect(entities[0]).toBeInstanceOf(types.MessageEntityStrike)
+        })
+
+        test('it should parse link entities', () => {
+            const parser = new MarkdownParser('Hello [world](https://hello.world)')
+            const [text, entities] = parser.parse()
+            expect(text).toEqual('Hello world')
+            expect(entities.length).toEqual(1)
+            expect(entities[0]).toBeInstanceOf(types.MessageEntityTextUrl)
+            expect(entities[0].url).toEqual('https://hello.world')
+        })
+
+        test('it should not parse nested entities', () => {
+            const parser = new MarkdownParser('Hello **__world__**')
+            const [text, entities] = parser.parse()
+            expect(text).toEqual('Hello __world__')
+            expect(entities.length).toEqual(1)
+            expect(entities[0]).toBeInstanceOf(types.MessageEntityBold)
+        })
+
+        test('it should parse multiple entities', () => {
+            const parser = new MarkdownParser('__Hello__ **world**')
+            const [text, entities] = parser.parse()
+            expect(text).toEqual('Hello world')
+            expect(entities.length).toEqual(2)
+            expect(entities[0]).toBeInstanceOf(types.MessageEntityItalic)
+            expect(entities[1]).toBeInstanceOf(types.MessageEntityBold)
+        })
+    })
+
+    describe('.unparse', () => {
+        test('it should create a markdown string from raw text and entities', () => {
+            const unparsed = '**hello** __hello__ ~~hello~~ `hello` ```hello``` [hello](https://hello.world)'
+            const strippedText = 'hello hello hello hello hello hello'
+            const rawEntities = [
+                new types.MessageEntityBold({ offset: 0, length: 5 }),
+                new types.MessageEntityItalic({ offset: 6, length: 5 }),
+                new types.MessageEntityStrike({ offset: 12, length: 5 }),
+                new types.MessageEntityCode({ offset: 18, length: 5 }),
+                new types.MessageEntityPre({ offset: 24, length: 5 }),
+                new types.MessageEntityTextUrl({ offset: 30, length: 5, url: 'https://hello.world' }),
+            ]
+            const text = MarkdownParser.unparse(strippedText, rawEntities)
+            expect(text).toEqual(unparsed)
+        })
+    })
+})

+ 100 - 0
__tests__/extensions/Scanner.spec.js

@@ -0,0 +1,100 @@
+const Scanner = require('../../gramjs/extensions/Scanner')
+
+const helloScanner = new Scanner('Hello world')
+
+describe('Scanner', () => {
+    beforeEach(() => helloScanner.reset())
+
+    test('it should construct a new Scanner', () => {
+        expect(helloScanner.str).toEqual('Hello world')
+        expect(helloScanner.pos).toEqual(0)
+        expect(helloScanner.lastMatch).toBeNull()
+    })
+
+    describe('.chr', () => {
+        test('it should return the character at the current pos', () => {
+            expect(helloScanner.chr).toEqual('H')
+        })
+    })
+
+    describe('.peek', () => {
+        test('it should return the character at the current pos', () => {
+            expect(helloScanner.peek()).toEqual('H')
+        })
+
+        test('it should return the next n characters', () => {
+            expect(helloScanner.peek(3)).toEqual('Hel')
+            expect(helloScanner.peek(5)).toEqual('Hello')
+        })
+    })
+
+    describe('.consume', () => {
+        test('it should consume the current character', () => {
+            const char = helloScanner.consume()
+            expect(char).toEqual('H')
+            expect(helloScanner.pos).toEqual(1)
+        })
+
+        test('it should consume the next n characters', () => {
+            const chars = helloScanner.consume(5)
+            expect(chars).toEqual('Hello')
+            expect(helloScanner.pos).toEqual(5)
+        })
+    })
+
+    describe('.reverse', () => {
+        test('it should set pos back n characters', () => {
+            helloScanner.consume(5)
+            helloScanner.reverse(5)
+            expect(helloScanner.pos).toEqual(0)
+        })
+
+        test('it should not go back further than 0', () => {
+            helloScanner.reverse(10)
+            expect(helloScanner.pos).toEqual(0)
+        })
+    })
+
+    describe('.scanUntil', () => {
+        test('it should scan the string for a regular expression starting at the current pos', () => {
+            helloScanner.scanUntil(/w/)
+            expect(helloScanner.pos).toEqual(6)
+        })
+
+        test('it should do nothing if the pattern is not found', () => {
+            helloScanner.scanUntil(/G/)
+            expect(helloScanner.pos).toEqual(0)
+        })
+    })
+
+    describe('.rest', () => {
+        test('it should return the unconsumed input', () => {
+            helloScanner.consume(6)
+            expect(helloScanner.rest).toEqual('world')
+        })
+    })
+
+    describe('.reset', () => {
+        test('it should reset the pos to 0', () => {
+            helloScanner.consume(5)
+            helloScanner.reset()
+            expect(helloScanner.pos).toEqual(0)
+        })
+    })
+
+    describe('.eof', () => {
+        test('it should return true if the scanner has reached the end of the input', () => {
+            expect(helloScanner.eof()).toBe(false)
+            helloScanner.consume(11)
+            expect(helloScanner.eof()).toBe(true)
+        })
+    })
+
+    describe('.bof', () => {
+        test('it should return true if pos is 0', () => {
+            expect(helloScanner.bof()).toBe(true)
+            helloScanner.consume(11)
+            expect(helloScanner.bof()).toBe(false)
+        })
+    })
+})

+ 19 - 0
babel.config.js

@@ -0,0 +1,19 @@
+// babel.config.js
+module.exports = {
+    presets: [
+        [
+            '@babel/preset-env',
+            {
+                targets: {
+                    node: 'current',
+                },
+            },
+        ],
+    ],
+    plugins: [
+        [
+            '@babel/plugin-proposal-class-properties',
+        ],
+    ],
+
+}

+ 38 - 0
examples/betterLogging.js

@@ -0,0 +1,38 @@
+rewireLoggingToElement(
+  () => document.getElementById("log"),
+  () => document.getElementById("log-container"),
+  true
+);
+
+function rewireLoggingToElement(eleLocator, eleOverflowLocator, autoScroll) {
+  fixLoggingFunc("log");
+
+  function fixLoggingFunc(name) {
+      console.old = console.log
+    console.log = function(...arg) {
+      const output = produceOutput(name, arg);
+      const eleLog = eleLocator();
+
+      if (autoScroll) {
+        const eleContainerLog = eleOverflowLocator();
+        const isScrolledToBottom =
+          eleContainerLog.scrollHeight - eleContainerLog.clientHeight <=
+          eleContainerLog.scrollTop + 1;
+        eleLog.innerHTML += output + "<br>";
+        if (isScrolledToBottom) {
+          eleContainerLog.scrollTop =
+            eleContainerLog.scrollHeight - eleContainerLog.clientHeight;
+        }
+      } else {
+        eleLog.innerHTML += output + "<br>";
+      }
+
+    };
+  }
+
+  function produceOutput(name, args) {
+      arg =  args[0].replace("%c","")
+    return '<span style="'+ args[1]+'">'+arg+"</span>&nbsp;"
+    
+  }
+}

+ 13 - 0
examples/main.js

@@ -0,0 +1,13 @@
+const { TelegramClient } = require('../gramjs')
+
+
+(async () => {
+    console.log('Loading interactive example...')
+    const sessionName = 'anon'
+    const apiId = -1
+    const apiHash = ''
+    const client = new TelegramClient(sessionName, apiId, apiHash)
+    await client.connect()
+
+    console.log('You should now be connected.')
+})()

+ 47 - 0
examples/simpleLogin.html

@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <meta http-equiv="X-UA-Compatible" content="ie=edge">
+    <title>Telegram Login</title>
+    <style>
+        #log-container {
+            overflow: auto;
+            height: 150px;
+            width: 20%;
+            resize: both;
+        }
+    </style>
+</head>
+
+<body>
+<form>
+    <div id="phoneDiv">
+        <label>phone number</label> <input disabled type="text" id="phone">
+        <button type="button" disabled id="phoneSend">Send</button>
+    </div>
+    <div id="codeDiv" style="visibility: hidden;">
+        <label>code you recieved</label> <input type="text" id="code">
+        <button type="button" id="codeSend">Send</button>
+    </div>
+    <div id="passDiv" style="visibility: hidden;">
+        <label>password</label> <input type="text" id="pass">
+        <button type="button" id="passSend">Send</button>
+    </div>
+    <div id="log-container">
+        <pre id="log"></pre>
+    </div>
+
+
+</form>
+</body>
+<script src="https://painor.dev/gramjs.js?version=0.0.2"></script>
+<!--Loading the library-->
+<script src="betterLogging.js"></script>
+<!--beautifies the ouput (this rewrites console.log)-->
+
+<script src="simpleLogin.js"></script>
+
+</html>

+ 78 - 0
examples/simpleLogin.js

@@ -0,0 +1,78 @@
+const phoneDiv = document.getElementById('phoneDiv')
+const phone = document.getElementById('phone')
+const phoneSend = document.getElementById('phoneSend')
+const codeDiv = document.getElementById('codeDiv')
+const code = document.getElementById('code')
+const codeSend = document.getElementById('codeSend')
+const passDiv = document.getElementById('passDiv')
+const pass = document.getElementById('pass')
+const passSend = document.getElementById('passSend')
+const logger = document.getElementById('log')
+
+function phoneCallback() {
+    phone.disabled = false
+    phoneSend.disabled = false
+
+    return new Promise(resolve => {
+        phoneSend.addEventListener('click', function() {
+            phone.disabled = true
+            phoneSend.disabled = true
+            resolve(phone.value)
+        })
+    })
+}
+
+
+function passwordCallback() {
+    passDiv.style.visibility = 'visible'
+
+    return new Promise(resolve => {
+        passSend.addEventListener('click', function() {
+            code.disabled = true
+            codeSend.disabled = true
+
+            resolve(pass.value)
+            alert('welcome')
+
+        })
+    })
+}
+
+function codeCallback() {
+    code.disabled = false
+    codeSend.disabled = false
+
+    codeDiv.style.visibility = 'visible'
+
+    return new Promise(resolve => {
+        codeSend.addEventListener('click', function() {
+            code.disabled = true
+            codeSend.disabled = true
+            resolve(code.value)
+        })
+    })
+}
+
+
+const { TelegramClient } = gramjs
+const { StringSession } = gramjs.session
+const apiId = process.env.APP_ID // put your api id here [for example 123456789]
+const apiHash = process.env.APP_HASH // put your api hash here [for example '123456abcfghe']
+
+const client = new TelegramClient(new StringSession(''), apiId, apiHash) // you can pass a string session here from previous logins.
+// If you want to run this example in the test servers uncomment this line
+// client.session.setDC(2, '149.154.167.40', 80)
+
+client.start({
+    phone: phoneCallback,
+    password: passwordCallback,
+    code: codeCallback,
+}).then(() => {
+    console.log('%c you should now be connected', 'color:#B54128')
+    console.log('%c your string session is ' + client.session.save(), 'color:#B54128')
+    console.log('%c you can save it to login with it next time', 'color:#B54128')
+
+})
+
+
+

+ 12 - 0
gramjs/.editorconfig

@@ -0,0 +1,12 @@
+# EditorConfig is awesome: http://EditorConfig.org
+
+# top-most EditorConfig file
+root = true
+
+[*]
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+charset = utf-8
+indent_style = space
+indent_size = 4

+ 14 - 5
src/lib/gramjs/Helpers.js → gramjs/Helpers.js

@@ -1,7 +1,6 @@
 const crypto = require('./crypto/crypto')
 const crypto = require('./crypto/crypto')
 const BigInt = require('big-integer')
 const BigInt = require('big-integer')
 
 
-
 /**
 /**
  * converts a buffer to big int
  * converts a buffer to big int
  * @param buffer
  * @param buffer
@@ -29,11 +28,11 @@ function readBigIntFromBuffer(buffer, little = true, signed = false) {
  * @param number
  * @param number
  * @returns {Buffer}
  * @returns {Buffer}
  */
  */
-function toSignedLittleBuffer(big, number=8) {
+function toSignedLittleBuffer(big, number = 8) {
     const bigNumber = BigInt(big)
     const bigNumber = BigInt(big)
     const byteArray = []
     const byteArray = []
     for (let i = 0; i < number; i++) {
     for (let i = 0; i < number; i++) {
-        byteArray[i] = bigNumber.shiftRight(8*i).and(255)
+        byteArray[i] = bigNumber.shiftRight(8 * i).and(255)
     }
     }
     return Buffer.from(byteArray)
     return Buffer.from(byteArray)
 }
 }
@@ -135,7 +134,6 @@ function generateRandomBytes(count) {
     return Buffer.from(crypto.randomBytes(count))
     return Buffer.from(crypto.randomBytes(count))
 }
 }
 
 
-
 /**
 /**
  * Calculate the key based on Telegram guidelines, specifying whether it's the client or not
  * Calculate the key based on Telegram guidelines, specifying whether it's the client or not
  * @param sharedKey
  * @param sharedKey
@@ -185,6 +183,15 @@ async function generateKeyDataFromNonce(serverNonce, newNonce) {
     }
     }
 }
 }
 
 
+function convertToLittle(buf) {
+    const correct = Buffer.alloc(buf.length * 4);
+
+    for (let i = 0; i < buf.length; i++) {
+        correct.writeUInt32BE(buf[i], i * 4)
+    }
+    return correct;
+}
+
 /**
 /**
  * Calculates the SHA1 digest for the given data
  * Calculates the SHA1 digest for the given data
  * @param data
  * @param data
@@ -335,5 +342,7 @@ module.exports = {
     sleep,
     sleep,
     getByteArray,
     getByteArray,
     //isArrayLike,
     //isArrayLike,
-    toSignedLittleBuffer
+    toSignedLittleBuffer,
+    convertToLittle
+
 }
 }

+ 1 - 0
src/lib/gramjs/Password.js → gramjs/Password.js

@@ -1,3 +1,4 @@
+const BigInt = require('big-integer')
 const Factorizator = require('./crypto/Factorizator')
 const Factorizator = require('./crypto/Factorizator')
 const { constructors } = require('./tl')
 const { constructors } = require('./tl')
 const { readBigIntFromBuffer, readBufferFromBigInt, sha256, bigIntMod, modExp,
 const { readBigIntFromBuffer, readBufferFromBigInt, sha256, bigIntMod, modExp,

+ 7 - 15
src/lib/gramjs/Utils.js → gramjs/Utils.js

@@ -19,7 +19,7 @@ function _raiseCastFail(entity, target) {
  Gets the input peer for the given "entity" (user, chat or channel).
  Gets the input peer for the given "entity" (user, chat or channel).
 
 
  A ``TypeError`` is raised if the given entity isn't a supported type
  A ``TypeError`` is raised if the given entity isn't a supported type
- or if ``check_hash is True`` but the entity's ``access_hash is None``
+ or if ``check_hash is True`` but the entity's ``accessHash is None``
  *or* the entity contains ``min`` information. In this case, the hash
  *or* the entity contains ``min`` information. In this case, the hash
  cannot be used for general purposes, and thus is not returned to avoid
  cannot be used for general purposes, and thus is not returned to avoid
  any issues which can derive from invalid access hashes.
  any issues which can derive from invalid access hashes.
@@ -57,7 +57,7 @@ function getInputPeer(entity, allowSelf = true, checkHash = true) {
                 accessHash: entity.accessHash,
                 accessHash: entity.accessHash,
             })
             })
         } else {
         } else {
-            throw new Error('User without access_hash or min info cannot be input')
+            throw new Error('User without accessHash or min info cannot be input')
         }
         }
     }
     }
     if (entity instanceof constructors.Chat || entity instanceof constructors.ChatEmpty ||
     if (entity instanceof constructors.Chat || entity instanceof constructors.ChatEmpty ||
@@ -71,7 +71,7 @@ function getInputPeer(entity, allowSelf = true, checkHash = true) {
                 accessHash: entity.accessHash
                 accessHash: entity.accessHash
             })
             })
         } else {
         } else {
-            throw new TypeError('Channel without access_hash or min info cannot be input')
+            throw new TypeError('Channel without accessHash or min info cannot be input')
         }
         }
     }
     }
     if (entity instanceof constructors.ChannelForbidden) {
     if (entity instanceof constructors.ChannelForbidden) {
@@ -107,7 +107,7 @@ function getInputPeer(entity, allowSelf = true, checkHash = true) {
     }
     }
 
 
     if (entity instanceof constructors.PeerChat) {
     if (entity instanceof constructors.PeerChat) {
-        return new constructors.InputPeerChat(entity.chat_id)
+        return new constructors.InputPeerChat(entity.chatId)
     }
     }
 
 
     _raiseCastFail(entity, 'InputPeer')
     _raiseCastFail(entity, 'InputPeer')
@@ -395,8 +395,8 @@ function getPeer(peer) {
  can be identified back. User ID is left unmodified, chat ID is negated,
  can be identified back. User ID is left unmodified, chat ID is negated,
  and channel ID is prefixed with -100:
  and channel ID is prefixed with -100:
 
 
- * ``user_id``
- * ``-chat_id``
+ * ``userId``
+ * ``-chatId``
  * ``-100channel_id``
  * ``-100channel_id``
 
 
  The original ID and the peer type class can be returned with
  The original ID and the peer type class can be returned with
@@ -518,15 +518,7 @@ function getMessageId(message) {
  * @param phone
  * @param phone
  */
  */
 function parsePhone(phone) {
 function parsePhone(phone) {
-    if (typeof phone === 'number') {
-        return phone.toString()
-    } else {
-        phone = phone.toString()
-            .replace(/[+()\s-]/gm, '')
-        if (!isNaN(phone)) {
-            return phone
-        }
-    }
+    return phone.toString().replace(/[+()\s-]/gm, '')
 }
 }
 
 
 /**
 /**

+ 1 - 0
gramjs/Version.js

@@ -0,0 +1 @@
+module.exports = '0.0.2'

+ 22 - 0
gramjs/client/TelegramClient.d.ts

@@ -0,0 +1,22 @@
+import { Api } from '..';
+
+import { BotAuthParams, UserAuthParams } from './auth';
+import { uploadFile, UploadFileParams } from './uploadFile';
+import { downloadFile, DownloadFileParams } from './downloadFile';
+
+declare class TelegramClient {
+    constructor(...args: any)
+
+    async start(authParams: UserAuthParams | BotAuthParams);
+
+    async invoke<R extends Api.AnyRequest>(request: R): Promise<R['__response']>;
+
+    async uploadFile(uploadParams: UploadFileParams): ReturnType<typeof uploadFile>;
+
+    async downloadFile(uploadParams: DownloadFileParams): ReturnType<typeof downloadFile>;
+
+    // Untyped methods.
+    [prop: string]: any;
+}
+
+export default TelegramClient;

Diferenças do arquivo suprimidas por serem muito extensas
+ 74 - 619
gramjs/client/TelegramClient.js


+ 138 - 42
src/lib/gramjs/client/auth.ts → gramjs/client/auth.ts

@@ -1,13 +1,15 @@
 import { default as Api } from '../tl/api';
 import { default as Api } from '../tl/api';
 import TelegramClient from './TelegramClient';
 import TelegramClient from './TelegramClient';
 import utils from '../Utils';
 import utils from '../Utils';
+import { sleep } from '../Helpers';
 import { computeCheck as computePasswordSrpCheck } from '../Password';
 import { computeCheck as computePasswordSrpCheck } from '../Password';
 
 
 export interface UserAuthParams {
 export interface UserAuthParams {
     phoneNumber: string | (() => Promise<string>);
     phoneNumber: string | (() => Promise<string>);
-    phoneCode: () => Promise<string>;
-    password: () => Promise<string>;
+    phoneCode: (isCodeViaApp?: boolean) => Promise<string>;
+    password: (hint?: string) => Promise<string>;
     firstAndLastNames: () => Promise<[string, string?]>;
     firstAndLastNames: () => Promise<[string, string?]>;
+    qrCode: (qrCode: { token: Buffer, expires: number }) => Promise<void>;
     onError: (err: Error) => void;
     onError: (err: Error) => void;
     forceSMS?: boolean;
     forceSMS?: boolean;
 }
 }
@@ -21,6 +23,8 @@ interface ApiCredentials {
     apiHash: string,
     apiHash: string,
 }
 }
 
 
+const QR_CODE_TIMEOUT = 30000;
+
 export async function authFlow(
 export async function authFlow(
     client: TelegramClient,
     client: TelegramClient,
     apiCredentials: ApiCredentials,
     apiCredentials: ApiCredentials,
@@ -47,17 +51,28 @@ export async function checkAuthorization(client: TelegramClient) {
 async function signInUser(
 async function signInUser(
     client: TelegramClient, apiCredentials: ApiCredentials, authParams: UserAuthParams,
     client: TelegramClient, apiCredentials: ApiCredentials, authParams: UserAuthParams,
 ): Promise<Api.TypeUser> {
 ): Promise<Api.TypeUser> {
-    let me: Api.TypeUser;
-
     let phoneNumber;
     let phoneNumber;
     let phoneCodeHash;
     let phoneCodeHash;
+    let isCodeViaApp = false;
 
 
     while (1) {
     while (1) {
         try {
         try {
-            phoneNumber = typeof authParams.phoneNumber === 'function'
-                ? await authParams.phoneNumber()
-                : authParams.phoneNumber;
-            phoneCodeHash = await sendCode(client, apiCredentials, phoneNumber, authParams.forceSMS);
+            if (typeof authParams.phoneNumber === 'function') {
+                try {
+                    phoneNumber = await authParams.phoneNumber();
+                } catch (err) {
+                    if (err.message === 'RESTART_AUTH_WITH_QR') {
+                        return signInUserWithQrCode(client, apiCredentials, authParams);
+                    }
+
+                    throw err;
+                }
+            } else {
+                phoneNumber = authParams.phoneNumber;
+            }
+            const sendCodeResult = await sendCode(client, apiCredentials, phoneNumber, authParams.forceSMS);
+            phoneCodeHash = sendCodeResult.phoneCodeHash;
+            isCodeViaApp = sendCodeResult.isCodeViaApp;
 
 
             if (typeof phoneCodeHash !== 'string') {
             if (typeof phoneCodeHash !== 'string') {
                 throw new Error('Failed to retrieve phone code hash');
                 throw new Error('Failed to retrieve phone code hash');
@@ -74,14 +89,13 @@ async function signInUser(
     }
     }
 
 
     let phoneCode;
     let phoneCode;
-    let isPasswordRequired = false;
     let isRegistrationRequired = false;
     let isRegistrationRequired = false;
     let termsOfService;
     let termsOfService;
 
 
     while (1) {
     while (1) {
         try {
         try {
             try {
             try {
-                phoneCode = await authParams.phoneCode();
+                phoneCode = await authParams.phoneCode(isCodeViaApp);
             } catch (err) {
             } catch (err) {
                 // This is the support for changing phone number from the phone code screen.
                 // This is the support for changing phone number from the phone code screen.
                 if (err.message === 'RESTART_AUTH') {
                 if (err.message === 'RESTART_AUTH') {
@@ -104,43 +118,19 @@ async function signInUser(
             if (result instanceof Api.auth.AuthorizationSignUpRequired) {
             if (result instanceof Api.auth.AuthorizationSignUpRequired) {
                 isRegistrationRequired = true;
                 isRegistrationRequired = true;
                 termsOfService = result.termsOfService;
                 termsOfService = result.termsOfService;
-            } else {
-                me = result.user;
+                break;
             }
             }
 
 
-            break;
+            return result.user;
         } catch (err) {
         } catch (err) {
             if (err.message === 'SESSION_PASSWORD_NEEDED') {
             if (err.message === 'SESSION_PASSWORD_NEEDED') {
-                isPasswordRequired = true;
-                break;
+                return signInWithPassword(client, apiCredentials, authParams);
             } else {
             } else {
                 authParams.onError(err);
                 authParams.onError(err);
             }
             }
         }
         }
     }
     }
 
 
-    if (isPasswordRequired) {
-        while (1) {
-            try {
-                const password = await authParams.password();
-                if (!password) {
-                    throw new Error('Password is empty');
-                }
-
-                const passwordSrpResult = await client.invoke(new Api.account.GetPassword());
-                const passwordSrpCheck = await computePasswordSrpCheck(passwordSrpResult, password);
-                const { user } = await client.invoke(new Api.auth.CheckPassword({
-                    password: passwordSrpCheck,
-                })) as Api.auth.Authorization;
-                me = user;
-
-                break;
-            } catch (err) {
-                authParams.onError(err);
-            }
-        }
-    }
-
     if (isRegistrationRequired) {
     if (isRegistrationRequired) {
         while (1) {
         while (1) {
             try {
             try {
@@ -161,19 +151,94 @@ async function signInUser(
                     await client.invoke(new Api.help.AcceptTermsOfService({ id: termsOfService.id }));
                     await client.invoke(new Api.help.AcceptTermsOfService({ id: termsOfService.id }));
                 }
                 }
 
 
-                me = user;
+                return user;
             } catch (err) {
             } catch (err) {
                 authParams.onError(err);
                 authParams.onError(err);
             }
             }
         }
         }
     }
     }
 
 
-    return me!;
+    authParams.onError(new Error('Auth failed'));
+    return signInUser(client, apiCredentials, authParams);
+}
+
+async function signInUserWithQrCode(
+    client: TelegramClient, apiCredentials: ApiCredentials, authParams: UserAuthParams,
+): Promise<Api.TypeUser> {
+    const inputPromise = (async () => {
+        while (1) {
+            const result = await client.invoke(new Api.auth.ExportLoginToken({
+                apiId: Number(process.env.TELEGRAM_T_API_ID),
+                apiHash: process.env.TELEGRAM_T_API_HASH,
+                exceptIds: [],
+            }));
+
+            if (!(result instanceof Api.auth.LoginToken)) {
+                throw new Error('Unexpected');
+            }
+
+            const { token, expires } = result;
+
+            await Promise.race([
+                authParams.qrCode({ token, expires }),
+                sleep(QR_CODE_TIMEOUT),
+            ]);
+        }
+    })();
+
+    const updatePromise = new Promise((resolve) => {
+        client.addEventHandler((update: Api.TypeUpdate) => {
+            if (update instanceof Api.UpdateLoginToken) {
+                resolve();
+            }
+        }, { build: (update: object) => update });
+    });
+
+    try {
+        await Promise.race([updatePromise, inputPromise]);
+    } catch (err) {
+        if (err.message === 'RESTART_AUTH') {
+            return signInUser(client, apiCredentials, authParams);
+        }
+
+        throw err;
+    }
+
+    try {
+        const result2 = await client.invoke(new Api.auth.ExportLoginToken({
+            apiId: Number(process.env.TELEGRAM_T_API_ID),
+            apiHash: process.env.TELEGRAM_T_API_HASH,
+            exceptIds: [],
+        }));
+
+        if (result2 instanceof Api.auth.LoginTokenSuccess && result2.authorization instanceof Api.auth.Authorization) {
+            return result2.authorization.user;
+        } else if (result2 instanceof Api.auth.LoginTokenMigrateTo) {
+            await client._switchDC(result2.dcId);
+            const migratedResult = await client.invoke(new Api.auth.ImportLoginToken({
+                token: result2.token,
+            }));
+
+            if (migratedResult instanceof Api.auth.LoginTokenSuccess && migratedResult.authorization instanceof Api.auth.Authorization) {
+                return migratedResult.authorization.user;
+            }
+        }
+    } catch (err) {
+        if (err.message === 'SESSION_PASSWORD_NEEDED') {
+            return signInWithPassword(client, apiCredentials, authParams);
+        }
+    }
+
+    authParams.onError(new Error('QR auth failed'));
+    return signInUser(client, apiCredentials, authParams);
 }
 }
 
 
 async function sendCode(
 async function sendCode(
     client: TelegramClient, apiCredentials: ApiCredentials, phoneNumber: string, forceSMS = false,
     client: TelegramClient, apiCredentials: ApiCredentials, phoneNumber: string, forceSMS = false,
-): Promise<string | undefined> {
+): Promise<{
+    phoneCodeHash: string;
+    isCodeViaApp: boolean;
+}> {
     try {
     try {
         const { apiId, apiHash } = apiCredentials;
         const { apiId, apiHash } = apiCredentials;
         const sendResult = await client.invoke(new Api.auth.SendCode({
         const sendResult = await client.invoke(new Api.auth.SendCode({
@@ -185,7 +250,10 @@ async function sendCode(
 
 
         // If we already sent a SMS, do not resend the phoneCode (hash may be empty)
         // If we already sent a SMS, do not resend the phoneCode (hash may be empty)
         if (!forceSMS || (sendResult.type instanceof Api.auth.SentCodeTypeSms)) {
         if (!forceSMS || (sendResult.type instanceof Api.auth.SentCodeTypeSms)) {
-            return sendResult.phoneCodeHash;
+            return {
+                phoneCodeHash: sendResult.phoneCodeHash,
+                isCodeViaApp: sendResult.type instanceof Api.auth.SentCodeTypeApp,
+            };
         }
         }
 
 
         const resendResult = await client.invoke(new Api.auth.ResendCode({
         const resendResult = await client.invoke(new Api.auth.ResendCode({
@@ -193,7 +261,10 @@ async function sendCode(
             phoneCodeHash: sendResult.phoneCodeHash,
             phoneCodeHash: sendResult.phoneCodeHash,
         }));
         }));
 
 
-        return resendResult.phoneCodeHash;
+        return {
+            phoneCodeHash: resendResult.phoneCodeHash,
+            isCodeViaApp: resendResult.type instanceof Api.auth.SentCodeTypeApp,
+        };
     } catch (err) {
     } catch (err) {
         if (err.message === 'AUTH_RESTART') {
         if (err.message === 'AUTH_RESTART') {
             return sendCode(client, apiCredentials, phoneNumber, forceSMS);
             return sendCode(client, apiCredentials, phoneNumber, forceSMS);
@@ -203,6 +274,31 @@ async function sendCode(
     }
     }
 }
 }
 
 
+async function signInWithPassword(
+    client: TelegramClient, apiCredentials: ApiCredentials, authParams: UserAuthParams,
+): Promise<Api.TypeUser> {
+    while (1) {
+        try {
+            const passwordSrpResult = await client.invoke(new Api.account.GetPassword());
+            const password = await authParams.password(passwordSrpResult.hint);
+            if (!password) {
+                throw new Error('Password is empty');
+            }
+
+            const passwordSrpCheck = await computePasswordSrpCheck(passwordSrpResult, password);
+            const { user } = await client.invoke(new Api.auth.CheckPassword({
+                password: passwordSrpCheck,
+            })) as Api.auth.Authorization;
+
+            return user;
+        } catch (err) {
+            authParams.onError(err);
+        }
+    }
+
+    return undefined!; // Never reached (TypeScript fix)
+}
+
 async function signInBot(client: TelegramClient, apiCredentials: ApiCredentials, authParams: BotAuthParams) {
 async function signInBot(client: TelegramClient, apiCredentials: ApiCredentials, authParams: BotAuthParams) {
     const { apiId, apiHash } = apiCredentials;
     const { apiId, apiHash } = apiCredentials;
     const { botAuthToken } = authParams;
     const { botAuthToken } = authParams;

+ 189 - 0
gramjs/client/downloadFile.ts

@@ -0,0 +1,189 @@
+import { default as Api } from '../tl/api';
+import TelegramClient from './TelegramClient';
+import { getAppropriatedPartSize } from '../Utils';
+import { sleep } from '../Helpers';
+
+export interface progressCallback {
+    (
+        progress: number, // Float between 0 and 1.
+        ...args: any[]
+    ): void;
+
+    isCanceled?: boolean;
+    acceptsBuffer?: boolean;
+}
+
+export interface DownloadFileParams {
+    dcId: number;
+    fileSize: number;
+    workers?: number;
+    partSizeKb?: number;
+    start?: number;
+    end?: number;
+    progressCallback?: progressCallback;
+}
+
+interface Deferred {
+    promise: Promise<any>;
+    resolve: (value?: any) => void;
+}
+
+// Chunk sizes for `upload.getFile` must be multiple of the smallest size
+const MIN_CHUNK_SIZE = 4096;
+const DEFAULT_CHUNK_SIZE = 64; // kb
+const ONE_MB = 1024 * 1024;
+const REQUEST_TIMEOUT = 15000;
+
+export async function downloadFile(
+    client: TelegramClient,
+    inputLocation: Api.InputFileLocation,
+    fileParams: DownloadFileParams,
+) {
+    let { partSizeKb, fileSize, workers = 1, end } = fileParams;
+    const { dcId, progressCallback, start = 0 } = fileParams;
+
+    end = end && end < fileSize ? end : fileSize - 1;
+
+    if (!partSizeKb) {
+        partSizeKb = fileSize ? getAppropriatedPartSize(fileSize) : DEFAULT_CHUNK_SIZE;
+    }
+
+    const partSize = partSizeKb * 1024;
+    const partsCount = end ? Math.ceil((end - start) / partSize) : 1;
+
+    if (partSize % MIN_CHUNK_SIZE !== 0) {
+        throw new Error(`The part size must be evenly divisible by ${MIN_CHUNK_SIZE}`);
+    }
+
+    let sender: any;
+    if (dcId) {
+        try {
+            sender = await client._borrowExportedSender(dcId);
+        } catch (e) {
+            // This should never raise
+            client._log.error(e);
+            if (e.message === 'DC_ID_INVALID') {
+                // Can't export a sender for the ID we are currently in
+                sender = client._sender;
+            } else {
+                throw e;
+            }
+        }
+    } else {
+        sender = client._sender;
+    }
+
+    client._log.info(`Downloading file in chunks of ${partSize} bytes`);
+
+    const foreman = new Foreman(workers);
+    const promises: Promise<any>[] = [];
+    let offset = start;
+    // Used for files with unknown size and for manual cancellations
+    let hasEnded = false;
+
+    let progress = 0;
+    if (progressCallback) {
+        progressCallback(progress);
+    }
+
+    while (true) {
+        let limit = partSize;
+        let isPrecise = false;
+
+        if (Math.floor(offset / ONE_MB) !== Math.floor((offset + limit - 1) / ONE_MB)) {
+            limit = ONE_MB - offset % ONE_MB;
+            isPrecise = true;
+        }
+
+        await foreman.requestWorker();
+
+        if (hasEnded) {
+            await foreman.releaseWorker();
+            break;
+        }
+
+        promises.push((async () => {
+            try {
+                const result = await Promise.race([
+                    await sender.send(new Api.upload.GetFile({
+                        location: inputLocation,
+                        offset,
+                        limit,
+                        precise: isPrecise || undefined,
+                    })),
+                    sleep(REQUEST_TIMEOUT).then(() => Promise.reject(new Error('REQUEST_TIMEOUT'))),
+                ]);
+
+                if (progressCallback) {
+                    if (progressCallback.isCanceled) {
+                        throw new Error('USER_CANCELED');
+                    }
+
+                    progress += (1 / partsCount);
+                    progressCallback(progress);
+                }
+
+                if (!end && (result.bytes.length < limit)) {
+                    hasEnded = true;
+                }
+
+                return result.bytes;
+            } catch (err) {
+                hasEnded = true;
+                throw err;
+            } finally {
+                foreman.releaseWorker();
+            }
+        })());
+
+        offset += limit;
+
+        if (end && (offset > end)) {
+            break;
+        }
+    }
+
+    const results = await Promise.all(promises);
+    const buffers = results.filter(Boolean);
+    const totalLength = end ? (end + 1) - start : undefined;
+    return Buffer.concat(buffers, totalLength);
+}
+
+class Foreman {
+    private deferred: Deferred | undefined;
+    private activeWorkers = 0;
+
+    constructor(private maxWorkers: number) {
+    }
+
+    requestWorker() {
+        this.activeWorkers++;
+
+        if (this.activeWorkers > this.maxWorkers) {
+            this.deferred = createDeferred();
+            return this.deferred.promise;
+        }
+
+        return Promise.resolve();
+    }
+
+    releaseWorker() {
+        this.activeWorkers--;
+
+        if (this.deferred && (this.activeWorkers <= this.maxWorkers)) {
+            this.deferred.resolve();
+        }
+    }
+}
+
+function createDeferred(): Deferred {
+    let resolve: Deferred['resolve'];
+    const promise = new Promise((_resolve) => {
+        resolve = _resolve;
+    });
+
+    return {
+        promise,
+        resolve: resolve!,
+    };
+}

+ 2 - 27
src/lib/gramjs/client/uploadFile.ts → gramjs/client/uploadFile.ts

@@ -1,7 +1,7 @@
 import { default as Api } from '../tl/api';
 import { default as Api } from '../tl/api';
 
 
 import TelegramClient from './TelegramClient';
 import TelegramClient from './TelegramClient';
-import { generateRandomBytes, readBigIntFromBuffer } from '../Helpers';
+import { generateRandomBytes, readBigIntFromBuffer, sleep } from '../Helpers';
 import { getAppropriatedPartSize } from '../Utils';
 import { getAppropriatedPartSize } from '../Utils';
 
 
 interface OnProgress {
 interface OnProgress {
@@ -19,6 +19,7 @@ export interface UploadFileParams {
 
 
 const KB_TO_BYTES = 1024;
 const KB_TO_BYTES = 1024;
 const LARGE_FILE_THRESHOLD = 10 * 1024 * 1024;
 const LARGE_FILE_THRESHOLD = 10 * 1024 * 1024;
+const UPLOAD_TIMEOUT = 15 * 1000;
 
 
 export async function uploadFile(
 export async function uploadFile(
     client: TelegramClient,
     client: TelegramClient,
@@ -50,31 +51,6 @@ export async function uploadFile(
         onProgress(progress);
         onProgress(progress);
     }
     }
 
 
-<<<<<<< HEAD
-    for (let i = 0; i < partCount; i++) {
-        const bytes = buffer.slice(i * partSize, (i + 1) * partSize);
-        const result = await sender.send(
-            isLarge
-                ? new Api.upload.SaveBigFilePart({
-                    fileId,
-                    filePart: i,
-                    fileTotalParts: partCount,
-                    bytes,
-                })
-                : new Api.upload.SaveFilePart({
-                    fileId,
-                    filePart: i,
-                    bytes,
-                }),
-        );
-
-        if (result && onProgress) {
-            if (onProgress.isCanceled) {
-                throw new Error('USER_CANCELED')
-            }
-
-            onProgress((i + 1) / partCount);
-=======
     for (let i = 0; i < partCount; i += workers) {
     for (let i = 0; i < partCount; i += workers) {
         let sendingParts = [];
         let sendingParts = [];
         let end = i + workers;
         let end = i + workers;
@@ -125,7 +101,6 @@ export async function uploadFile(
             }
             }
 
 
             throw err;
             throw err;
->>>>>>> edef29da... [Perf] GramJs: Add parallel uploads (#659)
         }
         }
     }
     }
 
 

+ 0 - 0
src/lib/gramjs/crypto/AuthKey.js → gramjs/crypto/AuthKey.js


+ 0 - 0
src/lib/gramjs/crypto/CTR.js → gramjs/crypto/CTR.js


+ 0 - 0
src/lib/gramjs/crypto/Factorizator.js → gramjs/crypto/Factorizator.js


+ 37 - 0
gramjs/crypto/IGE.js

@@ -0,0 +1,37 @@
+const Helpers = require("../Helpers");
+
+const {IGE:aes_ige} = require('@cryptography/aes');
+
+class IGENEW {
+    constructor(key, iv) {
+        this.ige = new aes_ige(key,iv);
+    }
+
+    /**
+     * Decrypts the given text in 16-bytes blocks by using the given key and 32-bytes initialization vector
+     * @param cipherText {Buffer}
+     * @returns {Buffer}
+     */
+    decryptIge(cipherText) {
+        return Helpers.convertToLittle(this.ige.decrypt(cipherText));
+    }
+
+    /**
+     * Encrypts the given text in 16-bytes blocks by using the given key and 32-bytes initialization vector
+     * @param plainText {Buffer}
+     * @returns {Buffer}
+     */
+    encryptIge(plainText) {
+        const padding = plainText.length % 16
+        if (padding) {
+            plainText = Buffer.concat([plainText, Helpers.generateRandomBytes(16 - padding)])
+        }
+
+        return Helpers.convertToLittle(this.ige.encrypt(plainText));
+
+
+    }
+
+}
+
+module.exports = IGENEW

+ 22 - 45
src/lib/gramjs/crypto/RSA.js → gramjs/crypto/RSA.js

@@ -1,31 +1,29 @@
-const { serializeBytes } = require('../tl')
-const { readBigIntFromBuffer, readBufferFromBigInt, getByteArray, sha1, generateRandomBytes, modExp } = require('../Helpers')
-const _serverKeys = {}
 const BigInt = require('big-integer')
 const BigInt = require('big-integer')
+const { readBigIntFromBuffer, readBufferFromBigInt, getByteArray, sha1, generateRandomBytes, modExp } = require('../Helpers')
 
 
+const PUBLIC_KEYS = [{
+    'fingerprint': [40, 85, 94, 156, 117, 240, 61, 22, 65, 244, 169, 2, 33, 107, 232, 108, 2, 43, 180, 195],
+    'n': BigInt('24403446649145068056824081744112065346446136066297307473868293895086332508101251964919587745984311372853053253457835208829824428441874946556659953519213382748319518214765985662663680818277989736779506318868003755216402538945900388706898101286548187286716959100102939636333452457308619454821845196109544157601096359148241435922125602449263164512290854366930013825808102403072317738266383237191313714482187326643144603633877219028262697593882410403273959074350849923041765639673335775605842311578109726403165298875058941765362622936097839775380070572921007586266115476975819175319995527916042178582540628652481530373407'),
+    'e': 65537
+}, {
+    'fingerprint': [140, 171, 9, 34, 146, 246, 166, 50, 10, 170, 229, 247, 155, 114, 28, 177, 29, 106, 153, 154],
+    'n': BigInt('25081407810410225030931722734886059247598515157516470397242545867550116598436968553551465554653745201634977779380884774534457386795922003815072071558370597290368737862981871277312823942822144802509055492512145589734772907225259038113414940384446493111736999668652848440655603157665903721517224934142301456312994547591626081517162758808439979745328030376796953660042629868902013177751703385501412640560275067171555763725421377065095231095517201241069856888933358280729674273422117201596511978645878544308102076746465468955910659145532699238576978901011112475698963666091510778777356966351191806495199073754705289253783'),
+    'e': 65537
+}, {
+    'fingerprint': [243, 218, 109, 239, 16, 202, 176, 78, 167, 8, 255, 209, 120, 234, 205, 112, 111, 42, 91, 176],
+    'n': BigInt('22347337644621997830323797217583448833849627595286505527328214795712874535417149457567295215523199212899872122674023936713124024124676488204889357563104452250187725437815819680799441376434162907889288526863223004380906766451781702435861040049293189979755757428366240570457372226323943522935844086838355728767565415115131238950994049041950699006558441163206523696546297006014416576123345545601004508537089192869558480948139679182328810531942418921113328804749485349441503927570568778905918696883174575510385552845625481490900659718413892216221539684717773483326240872061786759868040623935592404144262688161923519030977'),
+    'e': 65537
+}, {
+    'fingerprint': [128, 80, 214, 72, 77, 244, 98, 7, 201, 250, 37, 244, 227, 51, 96, 199, 182, 37, 224, 113],
+    'n': BigInt('24573455207957565047870011785254215390918912369814947541785386299516827003508659346069416840622922416779652050319196701077275060353178142796963682024347858398319926119639265555410256455471016400261630917813337515247954638555325280392998950756512879748873422896798579889820248358636937659872379948616822902110696986481638776226860777480684653756042166610633513404129518040549077551227082262066602286208338952016035637334787564972991208252928951876463555456715923743181359826124083963758009484867346318483872552977652588089928761806897223231500970500186019991032176060579816348322451864584743414550721639495547636008351'),
+    'e': 65537
+}]
 
 
-/**
- * Given a RSA key, computes its fingerprint like Telegram does.
- * @param key the RSA key.
- * @returns {bigInt.BigInteger|*} its 8-bytes-long fingerprint
- * @private
- */
-async function _computeFingerprint(key) {
+const _serverKeys = {}
 
 
-    const n = serializeBytes(getByteArray(key.n))
-    const e = serializeBytes(getByteArray(key.e))
-    // Telegram uses the last 8 bytes as the fingerprint
-    const sh = await sha1(Buffer.concat([n, e]))
-    return readBigIntFromBuffer(sh.slice(-8), true, true)
-}
-
-/**
- * Adds a new public key to be used when encrypting new data is needed
- * @param pub {{n:BigInt,e:BigInt}}
- */
-async function addKey(pub) {
-    _serverKeys[await _computeFingerprint(pub)] = pub
-}
+PUBLIC_KEYS.forEach(({ fingerprint, ...keyInfo }) => {
+    _serverKeys[readBigIntFromBuffer(fingerprint.slice(-8), true, true)] = keyInfo
+})
 
 
 /**
 /**
  * Encrypts the given data known the fingerprint to be used
  * Encrypts the given data known the fingerprint to be used
@@ -54,27 +52,6 @@ async function encrypt(fingerprint, data) {
     return readBufferFromBigInt(encrypted, 256, false)
     return readBufferFromBigInt(encrypted, 256, false)
 }
 }
 
 
-const publicKeys = [{
-    'n': BigInt('24403446649145068056824081744112065346446136066297307473868293895086332508101251964919587745984311372853053253457835208829824428441874946556659953519213382748319518214765985662663680818277989736779506318868003755216402538945900388706898101286548187286716959100102939636333452457308619454821845196109544157601096359148241435922125602449263164512290854366930013825808102403072317738266383237191313714482187326643144603633877219028262697593882410403273959074350849923041765639673335775605842311578109726403165298875058941765362622936097839775380070572921007586266115476975819175319995527916042178582540628652481530373407'),
-    'e': 65537
-}, {
-    'n': BigInt('25081407810410225030931722734886059247598515157516470397242545867550116598436968553551465554653745201634977779380884774534457386795922003815072071558370597290368737862981871277312823942822144802509055492512145589734772907225259038113414940384446493111736999668652848440655603157665903721517224934142301456312994547591626081517162758808439979745328030376796953660042629868902013177751703385501412640560275067171555763725421377065095231095517201241069856888933358280729674273422117201596511978645878544308102076746465468955910659145532699238576978901011112475698963666091510778777356966351191806495199073754705289253783'),
-    'e': 65537
-}, {
-    'n': BigInt('22347337644621997830323797217583448833849627595286505527328214795712874535417149457567295215523199212899872122674023936713124024124676488204889357563104452250187725437815819680799441376434162907889288526863223004380906766451781702435861040049293189979755757428366240570457372226323943522935844086838355728767565415115131238950994049041950699006558441163206523696546297006014416576123345545601004508537089192869558480948139679182328810531942418921113328804749485349441503927570568778905918696883174575510385552845625481490900659718413892216221539684717773483326240872061786759868040623935592404144262688161923519030977'),
-    'e': 65537
-}, {
-    'n': BigInt('24573455207957565047870011785254215390918912369814947541785386299516827003508659346069416840622922416779652050319196701077275060353178142796963682024347858398319926119639265555410256455471016400261630917813337515247954638555325280392998950756512879748873422896798579889820248358636937659872379948616822902110696986481638776226860777480684653756042166610633513404129518040549077551227082262066602286208338952016035637334787564972991208252928951876463555456715923743181359826124083963758009484867346318483872552977652588089928761806897223231500970500186019991032176060579816348322451864584743414550721639495547636008351'),
-    'e': 65537
-}]
-
-async function init() {
-    await Promise.all(publicKeys.map(addKey));
-}
-
 module.exports = {
 module.exports = {
     encrypt,
     encrypt,
-    addKey,
-    init
 }
 }
-

+ 55 - 0
gramjs/crypto/converters.ts

@@ -0,0 +1,55 @@
+/**
+ * Uint32Array -> ArrayBuffer (low-endian os)
+ */
+export function i2abLow(buf: Uint32Array): ArrayBuffer {
+    const uint8 = new Uint8Array(buf.length * 4);
+    let i = 0;
+
+    for (let j = 0; j < buf.length; j++) {
+        const int = buf[j];
+
+        uint8[i++] = int >>> 24;
+        uint8[i++] = (int >> 16) & 0xFF;
+        uint8[i++] = (int >> 8) & 0xFF;
+        uint8[i++] = int & 0xFF;
+    }
+
+    return uint8.buffer;
+}
+
+/**
+ * Uint32Array -> ArrayBuffer (big-endian os)
+ */
+export function i2abBig(buf: Uint32Array): ArrayBuffer {
+    return buf.buffer;
+}
+
+/**
+ * ArrayBuffer -> Uint32Array (low-endian os)
+ */
+export function ab2iLow(ab: ArrayBuffer | SharedArrayBuffer | Uint8Array): Uint32Array {
+    const uint8 = new Uint8Array(ab);
+    const buf = new Uint32Array(uint8.length / 4);
+
+    for (let i = 0; i < uint8.length; i += 4) {
+        buf[i / 4] = (
+            uint8[i] << 24
+            ^ uint8[i + 1] << 16
+            ^ uint8[i + 2] << 8
+            ^ uint8[i + 3]
+        );
+    }
+
+    return buf;
+}
+
+/**
+ * ArrayBuffer -> Uint32Array (big-endian os)
+ */
+export function ab2iBig(ab: ArrayBuffer | SharedArrayBuffer | Uint8Array): Uint32Array {
+    return new Uint32Array(ab);
+}
+
+export const isBigEndian = new Uint8Array(new Uint32Array([0x01020304]))[0] === 0x01;
+export const i2ab = isBigEndian ? i2abBig : i2abLow;
+export const ab2i = isBigEndian ? ab2iBig : ab2iLow;

+ 124 - 0
gramjs/crypto/crypto.js

@@ -0,0 +1,124 @@
+const AES = require('@cryptography/aes').default;
+const { i2ab, ab2i } = require('./converters');
+const { getWords } = require('./words');
+
+class Counter {
+    constructor(initialValue) {
+        this.setBytes(initialValue)
+    }
+
+    setBytes(bytes) {
+        bytes = Buffer.from(bytes)
+        this._counter = bytes
+    }
+
+    increment() {
+        for (let i = 15; i >= 0; i--) {
+            if (this._counter[i] === 255) {
+                this._counter[i] = 0
+            } else {
+                this._counter[i]++
+                break
+            }
+        }
+    }
+}
+
+class CTR {
+    constructor(key, counter) {
+
+        if (!(counter instanceof Counter)) {
+            counter = new Counter(counter)
+        }
+
+        this._counter = counter
+
+        this._remainingCounter = null
+        this._remainingCounterIndex = 16
+
+        this._aes = new AES(getWords(key))
+    }
+
+    update(plainText) {
+        return this.encrypt(plainText)
+    }
+
+    encrypt(plainText) {
+        const encrypted = Buffer.from(plainText)
+
+        for (let i = 0; i < encrypted.length; i++) {
+            if (this._remainingCounterIndex === 16) {
+                this._remainingCounter = Buffer.from(i2ab(this._aes.encrypt(ab2i(this._counter._counter))))
+                this._remainingCounterIndex = 0
+                this._counter.increment()
+            }
+            encrypted[i] ^= this._remainingCounter[this._remainingCounterIndex++]
+        }
+
+        return encrypted
+    }
+}
+
+// endregion
+function createDecipheriv(algorithm, key, iv) {
+    if (algorithm.includes('ECB')) {
+        throw new Error('Not supported');
+    } else {
+        return new CTR(key, iv)
+    }
+}
+
+function createCipheriv(algorithm, key, iv) {
+    if (algorithm.includes('ECB')) {
+        throw new Error('Not supported');
+    } else {
+        return new CTR(key, iv)
+    }
+}
+
+function randomBytes(count) {
+    const bytes = new Uint8Array(count)
+    crypto.getRandomValues(bytes)
+    return bytes
+}
+
+class Hash {
+    constructor(algorithm) {
+        this.algorithm = algorithm
+    }
+
+    update(data) {
+        //We shouldn't be needing new Uint8Array but it doesn't
+        //work without it
+        this.data = new Uint8Array(data)
+    }
+
+    async digest() {
+        if (this.algorithm === 'sha1') {
+            return Buffer.from(await self.crypto.subtle.digest('SHA-1', this.data))
+        } else if (this.algorithm === 'sha256') {
+            return Buffer.from(await self.crypto.subtle.digest('SHA-256', this.data))
+        }
+    }
+}
+
+async function pbkdf2(password, salt, iterations) {
+    const passwordKey = await crypto.subtle.importKey('raw', password,
+        {name: 'PBKDF2'}, false, ['deriveBits'])
+    return Buffer.from(await crypto.subtle.deriveBits({
+        name: 'PBKDF2',
+        hash: 'SHA-512', salt, iterations
+    }, passwordKey, 512));
+}
+
+function createHash(algorithm) {
+    return new Hash(algorithm)
+}
+
+module.exports = {
+    createCipheriv,
+    createDecipheriv,
+    randomBytes,
+    createHash,
+    pbkdf2
+}

+ 51 - 0
gramjs/crypto/words.ts

@@ -0,0 +1,51 @@
+/*
+ * Imported from https://github.com/spalt08/cryptography/blob/master/packages/aes/src/utils/words.ts
+ */
+
+export function s2i(str: string, pos: number) {
+    return (
+        str.charCodeAt(pos) << 24
+        ^ str.charCodeAt(pos + 1) << 16
+        ^ str.charCodeAt(pos + 2) << 8
+        ^ str.charCodeAt(pos + 3)
+    );
+}
+
+/**
+ * Helper function for transforming string key to Uint32Array
+ */
+export function getWords(key: string | Uint8Array | Uint32Array) {
+    if (key instanceof Uint32Array) {
+        return key;
+    }
+
+    if (typeof key === 'string') {
+        if (key.length % 4 !== 0) for (let i = key.length % 4; i <= 4; i++) key += '\0x00';
+
+        const buf = new Uint32Array(key.length / 4);
+        for (let i = 0; i < key.length; i += 4) buf[i / 4] = s2i(key, i);
+
+        return buf;
+    }
+
+    if (key instanceof Uint8Array) {
+        const buf = new Uint32Array(key.length / 4);
+
+        for (let i = 0; i < key.length; i += 4) {
+            buf[i / 4] = (
+                key[i] << 24
+                ^ key[i + 1] << 16
+                ^ key[i + 2] << 8
+                ^ key[i + 3]
+            );
+        }
+
+        return buf;
+    }
+
+    throw new Error('Unable to create 32-bit words');
+}
+
+export function xor(left: Uint32Array, right: Uint32Array, to = left) {
+    for (let i = 0; i < left.length; i++) to[i] = left[i] ^ right[i];
+}

+ 4 - 1
src/lib/gramjs/errors/Common.js → gramjs/errors/Common.js

@@ -20,7 +20,10 @@ class TypeNotFoundError extends Error {
     constructor(invalidConstructorId, remaining) {
     constructor(invalidConstructorId, remaining) {
         super(`Could not find a matching Constructor ID for the TLObject that was supposed to be
         super(`Could not find a matching Constructor ID for the TLObject that was supposed to be
         read with ID ${invalidConstructorId}. Most likely, a TLObject was trying to be read when
         read with ID ${invalidConstructorId}. Most likely, a TLObject was trying to be read when
-         it should not be read. Remaining bytes: ${remaining}`)
+         it should not be read. Remaining bytes: ${remaining.length}`)
+        if (typeof alert !== 'undefined') {
+            alert(`Missing MTProto Entity: Please, make sure to add TL definition for ID ${invalidConstructorId}`)
+        }
         this.invalidConstructorId = invalidConstructorId
         this.invalidConstructorId = invalidConstructorId
         this.remaining = remaining
         this.remaining = remaining
     }
     }

+ 0 - 0
src/lib/gramjs/errors/RPCBaseErrors.js → gramjs/errors/RPCBaseErrors.js


+ 0 - 0
src/lib/gramjs/errors/index.js → gramjs/errors/index.js


+ 0 - 0
src/lib/gramjs/events/NewMessage.js → gramjs/events/NewMessage.js


+ 21 - 0
gramjs/events/Raw.js

@@ -0,0 +1,21 @@
+const { EventBuilder } = require('./common')
+
+class Raw extends EventBuilder {
+    constructor(args = {
+        types: null,
+        func: null,
+    }) {
+        super()
+        if (!args.types) {
+            this.types = true
+        } else {
+            this.types = args.types
+        }
+    }
+
+    build(update, others = null) {
+        return update
+    }
+}
+
+module.exports = Raw

+ 22 - 0
gramjs/events/common.js

@@ -0,0 +1,22 @@
+class EventBuilder {
+    constructor(args = {
+        chats: null, blacklistChats: null, func: null,
+    },
+    ) {
+        this.chats = args.chats
+        this.blacklistChats = Boolean(args.blacklistChats)
+        this.resolved = false
+        this.func = args.func
+    }
+
+    build(update, others = null) {
+
+    }
+}
+
+class EventCommon {
+
+}
+
+
+module.exports = { EventBuilder, EventCommon }

+ 8 - 0
gramjs/events/index.js

@@ -0,0 +1,8 @@
+const NewMessage = require('./NewMessage')
+const Raw = require('./Raw')
+
+class StopPropagation extends Error {
+
+}
+
+module.exports = { NewMessage, StopPropagation, Raw }

+ 30 - 0
gramjs/extensions/AsyncQueue.js

@@ -0,0 +1,30 @@
+class AsyncQueue {
+    constructor() {
+        this._queue = []
+        this.canGet = new Promise((resolve) => {
+            this.resolveGet = resolve
+        })
+        this.canPush = true
+    }
+
+    async push(value) {
+        await this.canPush
+        this._queue.push(value)
+        this.resolveGet(true)
+        this.canPush = new Promise((resolve) => {
+            this.resolvePush = resolve
+        })
+    }
+
+    async pop() {
+        await this.canGet
+        const returned = this._queue.pop()
+        this.resolvePush(true)
+        this.canGet = new Promise((resolve) => {
+            this.resolveGet = resolve
+        })
+        return returned
+    }
+}
+
+module.exports = AsyncQueue

+ 0 - 0
src/lib/gramjs/extensions/BinaryReader.js → gramjs/extensions/BinaryReader.js


+ 15 - 0
gramjs/extensions/BinaryWriter.js

@@ -0,0 +1,15 @@
+class BinaryWriter {
+    constructor(stream) {
+        this._stream = stream
+    }
+
+    write(buffer) {
+        this._stream = Buffer.concat([this._stream, buffer])
+    }
+
+    getValue() {
+        return this._stream
+    }
+}
+
+module.exports = BinaryWriter

+ 9 - 9
src/lib/gramjs/extensions/Logger.js → gramjs/extensions/Logger.js

@@ -1,10 +1,13 @@
-let logger = null
+let _level = null
 
 
 class Logger {
 class Logger {
     static levels = ['error', 'warn', 'info', 'debug']
     static levels = ['error', 'warn', 'info', 'debug']
 
 
     constructor(level) {
     constructor(level) {
-        this.level = level || 'debug'
+        if (!_level) {
+            _level = level || 'debug'
+        }
+
         this.isBrowser = typeof process === 'undefined' ||
         this.isBrowser = typeof process === 'undefined' ||
             process.type === 'renderer' ||
             process.type === 'renderer' ||
             process.browser === true ||
             process.browser === true ||
@@ -37,7 +40,7 @@ class Logger {
      * @returns {boolean}
      * @returns {boolean}
      */
      */
     canSend(level) {
     canSend(level) {
-        return (Logger.levels.indexOf(this.level) >= Logger.levels.indexOf(level))
+        return (Logger.levels.indexOf(_level) >= Logger.levels.indexOf(level))
     }
     }
 
 
     /**
     /**
@@ -74,11 +77,8 @@ class Logger {
             .replace('%m', message)
             .replace('%m', message)
     }
     }
 
 
-    static getLogger() {
-        if (!logger) {
-            logger = new Logger('debug')
-        }
-        return logger
+    static setLevel(level) {
+        _level = level;
     }
     }
 
 
     /**
     /**
@@ -87,7 +87,7 @@ class Logger {
      * @param color {string}
      * @param color {string}
      */
      */
     _log(level, message, color) {
     _log(level, message, color) {
-        if (!logger){
+        if (!_level){
             return
             return
         }
         }
         if (this.canSend(level)) {
         if (this.canSend(level)) {

+ 0 - 0
src/lib/gramjs/extensions/MessagePacker.js → gramjs/extensions/MessagePacker.js


+ 0 - 0
src/lib/gramjs/extensions/PromisedWebSockets.js → gramjs/extensions/PromisedWebSockets.js


+ 0 - 0
src/lib/gramjs/extensions/index.js → gramjs/extensions/index.js


+ 10 - 0
gramjs/index.d.ts

@@ -0,0 +1,10 @@
+export { default as Api } from './tl/api';
+export { default as TelegramClient } from './client/TelegramClient';
+export { default as connection } from './network';
+export { default as tl } from './tl';
+export { default as version } from './Version';
+export { default as events } from './events';
+export { default as utils } from './Utils';
+export { default as errors } from './errors';
+export { default as sessions } from './sessions';
+export { default as helpers } from './Helpers';

+ 16 - 0
gramjs/index.js

@@ -0,0 +1,16 @@
+const Api = require('./tl/api')
+const TelegramClient = require('./client/TelegramClient')
+const connection = require('./network')
+const tl = require('./tl')
+const version = require('./Version')
+const events = require('./events')
+const utils = require('./Utils')
+const errors = require('./errors')
+const sessions = require('./sessions')
+const extensions = require('./extensions')
+const helpers = require('./Helpers')
+
+module.exports = {
+    Api, TelegramClient, sessions, connection, extensions,
+    tl, version, events, utils, errors, helpers,
+}

+ 7 - 5
src/lib/gramjs/network/Authenticator.js → gramjs/network/Authenticator.js

@@ -20,7 +20,7 @@ async function doAuthentication(sender, log) {
 
 
     const nonce = Helpers.readBigIntFromBuffer(bytes, false, true)
     const nonce = Helpers.readBigIntFromBuffer(bytes, false, true)
 
 
-    const resPQ = await sender.send(new requests.ReqPqMultiRequest({ nonce: nonce }))
+    const resPQ = await sender.send(new requests.ReqPqMulti({ nonce: nonce }))
     log.debug('Starting authKey generation step 1')
     log.debug('Starting authKey generation step 1')
 
 
     if (!(resPQ instanceof constructors.ResPQ)) {
     if (!(resPQ instanceof constructors.ResPQ)) {
@@ -66,7 +66,7 @@ async function doAuthentication(sender, log) {
     }
     }
 
 
     const serverDhParams = await sender.send(
     const serverDhParams = await sender.send(
-        new requests.ReqDHParamsRequest({
+        new requests.ReqDHParams({
             nonce: resPQ.nonce,
             nonce: resPQ.nonce,
             serverNonce: resPQ.serverNonce,
             serverNonce: resPQ.serverNonce,
             p: p,
             p: p,
@@ -105,7 +105,8 @@ async function doAuthentication(sender, log) {
         // See PR#453
         // See PR#453
         throw new SecurityError('Step 3 AES block size mismatch')
         throw new SecurityError('Step 3 AES block size mismatch')
     }
     }
-    const plainTextAnswer = IGE.decryptIge(serverDhParams.encryptedAnswer, key, iv)
+    const ige = new IGE(key,iv)
+    const plainTextAnswer = ige.decryptIge(serverDhParams.encryptedAnswer)
     const reader = new BinaryReader(plainTextAnswer)
     const reader = new BinaryReader(plainTextAnswer)
     reader.read(20) // hash sum
     reader.read(20) // hash sum
     const serverDhInner = reader.tgReadObject()
     const serverDhInner = reader.tgReadObject()
@@ -136,9 +137,10 @@ async function doAuthentication(sender, log) {
 
 
     const clientDdhInnerHashed = Buffer.concat([await Helpers.sha1(clientDhInner), clientDhInner])
     const clientDdhInnerHashed = Buffer.concat([await Helpers.sha1(clientDhInner), clientDhInner])
     // Encryption
     // Encryption
-    const clientDhEncrypted = IGE.encryptIge(clientDdhInnerHashed, key, iv)
+
+    const clientDhEncrypted = ige.encryptIge(clientDdhInnerHashed)
     const dhGen = await sender.send(
     const dhGen = await sender.send(
-        new requests.SetClientDHParamsRequest({
+        new requests.SetClientDHParams({
             nonce: resPQ.nonce,
             nonce: resPQ.nonce,
             serverNonce: resPQ.serverNonce,
             serverNonce: resPQ.serverNonce,
             encryptedData: clientDhEncrypted,
             encryptedData: clientDhEncrypted,

+ 0 - 0
src/lib/gramjs/network/MTProtoPlainSender.js → gramjs/network/MTProtoPlainSender.js


+ 7 - 5
src/lib/gramjs/network/MTProtoSender.js → gramjs/network/MTProtoSender.js

@@ -25,7 +25,7 @@ const {
 } = require('../tl').constructors
 } = require('../tl').constructors
 const { SecurityError } = require('../errors/Common')
 const { SecurityError } = require('../errors/Common')
 const { InvalidBufferError } = require('../errors/Common')
 const { InvalidBufferError } = require('../errors/Common')
-const { LogOutRequest } = require('../tl').requests.auth
+const { LogOut } = require('../tl').requests.auth
 const { RPCMessageToError } = require('../errors')
 const { RPCMessageToError } = require('../errors')
 const { TypeNotFoundError } = require('../errors/Common')
 const { TypeNotFoundError } = require('../errors/Common')
 
 
@@ -406,6 +406,7 @@ class MTProtoSender {
                 } else {
                 } else {
                     this._log.error('Unhandled error while receiving data')
                     this._log.error('Unhandled error while receiving data')
                     this._log.error(e)
                     this._log.error(e)
+                    console.log(e)
                     this._startReconnect()
                     this._startReconnect()
                     return
                     return
                 }
                 }
@@ -414,6 +415,7 @@ class MTProtoSender {
                 await this._processMessage(message)
                 await this._processMessage(message)
             } catch (e) {
             } catch (e) {
                 this._log.error('Unhandled error while receiving data')
                 this._log.error('Unhandled error while receiving data')
+                console.log(e)
                 this._log.error(e)
                 this._log.error(e)
             }
             }
         }
         }
@@ -458,7 +460,7 @@ class MTProtoSender {
         const toPop = []
         const toPop = []
 
 
         for (state of Object.values(this._pending_state)) {
         for (state of Object.values(this._pending_state)) {
-            if (state.containerId.equals(msgId)) {
+            if (state.containerId && state.containerId.equals(msgId)) {
                 toPop.push(state.msgId)
                 toPop.push(state.msgId)
             }
             }
         }
         }
@@ -489,7 +491,7 @@ class MTProtoSender {
      * @returns {Promise<void>}
      * @returns {Promise<void>}
      * @private
      * @private
      */
      */
-    async _handleRPCResult(message) {
+    _handleRPCResult(message) {
         const RPCResult = message.obj
         const RPCResult = message.obj
         const state = this._pending_state[RPCResult.reqMsgId]
         const state = this._pending_state[RPCResult.reqMsgId]
         if (state) {
         if (state) {
@@ -524,7 +526,7 @@ class MTProtoSender {
             state.reject(error)
             state.reject(error)
         } else {
         } else {
             const reader = new BinaryReader(RPCResult.body)
             const reader = new BinaryReader(RPCResult.body)
-            const read = await state.request.readResult(reader)
+            const read = state.request.readResult(reader)
             state.resolve(read)
             state.resolve(read)
         }
         }
     }
     }
@@ -712,7 +714,7 @@ class MTProtoSender {
         this._log.debug(`Handling acknowledge for ${ack.msgIds}`)
         this._log.debug(`Handling acknowledge for ${ack.msgIds}`)
         for (const msgId of ack.msgIds) {
         for (const msgId of ack.msgIds) {
             const state = this._pending_state[msgId]
             const state = this._pending_state[msgId]
-            if (state && state.request instanceof LogOutRequest) {
+            if (state && state.request instanceof LogOut) {
                 delete this._pending_state[msgId]
                 delete this._pending_state[msgId]
                 state.resolve(true)
                 state.resolve(true)
             }
             }

+ 5 - 5
src/lib/gramjs/network/MTProtoState.js → gramjs/network/MTProtoState.js

@@ -4,7 +4,7 @@ const BinaryReader = require('../extensions/BinaryReader')
 const GZIPPacked = require('../tl/core/GZIPPacked')
 const GZIPPacked = require('../tl/core/GZIPPacked')
 const { TLMessage } = require('../tl/core')
 const { TLMessage } = require('../tl/core')
 const { SecurityError, InvalidBufferError } = require('../errors/Common')
 const { SecurityError, InvalidBufferError } = require('../errors/Common')
-const { InvokeAfterMsgRequest } = require('../tl').requests
+const { InvokeAfterMsg } = require('../tl').requests
 const BigInt = require('big-integer')
 const BigInt = require('big-integer')
 const { toSignedLittleBuffer,readBufferFromBigInt } = require("../Helpers")
 const { toSignedLittleBuffer,readBufferFromBigInt } = require("../Helpers")
 const { readBigIntFromBuffer } = require("../Helpers")
 const { readBigIntFromBuffer } = require("../Helpers")
@@ -97,7 +97,7 @@ class MTProtoState {
         if (!afterId) {
         if (!afterId) {
             body = await GZIPPacked.gzipIfSmaller(contentRelated, data)
             body = await GZIPPacked.gzipIfSmaller(contentRelated, data)
         } else {
         } else {
-            body = await GZIPPacked.gzipIfSmaller(contentRelated, new InvokeAfterMsgRequest(afterId, data).getBytes())
+            body = await GZIPPacked.gzipIfSmaller(contentRelated, new InvokeAfterMsg(afterId, data).getBytes())
         }
         }
         const s = Buffer.alloc(4)
         const s = Buffer.alloc(4)
         s.writeInt32LE(seqNo, 0)
         s.writeInt32LE(seqNo, 0)
@@ -129,7 +129,7 @@ class MTProtoState {
         const { iv, key } = await this._calcKey(this.authKey.getKey(), msgKey, true)
         const { iv, key } = await this._calcKey(this.authKey.getKey(), msgKey, true)
 
 
         const keyId = Helpers.readBufferFromBigInt(this.authKey.keyId, 8)
         const keyId = Helpers.readBufferFromBigInt(this.authKey.keyId, 8)
-        return Buffer.concat([keyId, msgKey, IGE.encryptIge(Buffer.concat([data, padding]), key, iv)])
+        return Buffer.concat([keyId, msgKey, new IGE(key,iv).encryptIge(Buffer.concat([data, padding]))])
     }
     }
 
 
     /**
     /**
@@ -149,7 +149,7 @@ class MTProtoState {
 
 
         const msgKey = body.slice(8, 24)
         const msgKey = body.slice(8, 24)
         const { iv, key } = await this._calcKey(this.authKey.getKey(), msgKey, false)
         const { iv, key } = await this._calcKey(this.authKey.getKey(), msgKey, false)
-        body = IGE.decryptIge(body.slice(24), key, iv)
+        body = new IGE(key,iv).decryptIge(body.slice(24))
 
 
         // https://core.telegram.org/mtproto/security_guidelines
         // https://core.telegram.org/mtproto/security_guidelines
         // Sections "checking sha256 hash" and "message length"
         // Sections "checking sha256 hash" and "message length"
@@ -174,7 +174,7 @@ class MTProtoState {
         // We could read msg_len bytes and use those in a new reader to read
         // We could read msg_len bytes and use those in a new reader to read
         // the next TLObject without including the padding, but since the
         // the next TLObject without including the padding, but since the
         // reader isn't used for anything else after this, it's unnecessary.
         // reader isn't used for anything else after this, it's unnecessary.
-        const obj = await reader.tgReadObject()
+        const obj = reader.tgReadObject()
 
 
         return new TLMessage(remoteMsgId, remoteSequence, obj)
         return new TLMessage(remoteMsgId, remoteSequence, obj)
     }
     }

+ 0 - 0
src/lib/gramjs/network/RequestState.js → gramjs/network/RequestState.js


+ 0 - 0
src/lib/gramjs/network/connection/Connection.js → gramjs/network/connection/Connection.js


+ 0 - 0
src/lib/gramjs/network/connection/TCPAbridged.js → gramjs/network/connection/TCPAbridged.js


+ 57 - 0
gramjs/network/connection/TCPFull.js

@@ -0,0 +1,57 @@
+//CONTEST
+// const { Connection, PacketCodec } = require('./Connection')
+// const { crc32 } = require('../../Helpers')
+// const { InvalidChecksumError } = require('../../errors/Common')
+//
+// class FullPacketCodec extends PacketCodec {
+//     constructor(connection) {
+//         super(connection)
+//         this._sendCounter = 0 // Telegram will ignore us otherwise
+//     }
+//
+//     encodePacket(data) {
+//         // https://core.telegram.org/mtproto#tcp-transport
+//         // total length, sequence number, packet and checksum (CRC32)
+//         const length = data.length + 12
+//         const e = Buffer.alloc(8)
+//         e.writeInt32LE(length,0)
+//         e.writeInt32LE(this._sendCounter,4)
+//         data = Buffer.concat([e, data])
+//         const crc =  Buffer.alloc(4)
+//         crc.writeUInt32LE(crc32(data),0)
+//         this._sendCounter += 1
+//         return Buffer.concat([data, crc])
+//     }
+//
+//     /**
+//      *
+//      * @param reader {PromisedWebSockets}
+//      * @returns {Promise<*>}
+//      */
+//     async readPacket(reader) {
+//         const packetLenSeq = await reader.read(8) // 4 and 4
+//         // process.exit(0);
+//         if (packetLenSeq === undefined) {
+//             return false
+//         }
+//         const packetLen = packetLenSeq.readInt32LE(0)
+//         let body = await reader.read(packetLen - 8)
+//         const [checksum] = body.slice(-4).readUInt32LE(0)
+//         body = body.slice(0, -4)
+//
+//         const validChecksum = crc32(Buffer.concat([packetLenSeq, body]))
+//         if (!(validChecksum === checksum)) {
+//             throw new InvalidChecksumError(checksum, validChecksum)
+//         }
+//         return body
+//     }
+// }
+//
+// class ConnectionTCPFull extends Connection {
+//     PacketCodecClass = FullPacketCodec;
+// }
+//
+// module.exports = {
+//     FullPacketCodec,
+//     ConnectionTCPFull,
+// }

+ 0 - 0
src/lib/gramjs/network/connection/TCPObfuscated.js → gramjs/network/connection/TCPObfuscated.js


+ 11 - 0
gramjs/network/connection/index.js

@@ -0,0 +1,11 @@
+const { Connection } = require('./Connection')
+const { ConnectionTCPFull } = require('./TCPFull')
+const { ConnectionTCPAbridged } = require('./TCPAbridged')
+const { ConnectionTCPObfuscated } = require('./TCPObfuscated')
+
+module.exports = {
+    Connection,
+    ConnectionTCPFull,
+    ConnectionTCPAbridged,
+    ConnectionTCPObfuscated,
+}

+ 0 - 0
src/lib/gramjs/network/index.js → gramjs/network/index.js


+ 0 - 0
src/lib/gramjs/sessions/Abstract.js → gramjs/sessions/Abstract.js


+ 0 - 0
src/lib/gramjs/sessions/CacheApiSession.js → gramjs/sessions/CacheApiSession.js


+ 2 - 2
src/lib/gramjs/sessions/Memory.js → gramjs/sessions/Memory.js

@@ -88,9 +88,9 @@ class MemorySession extends Session {
             p = utils.getInputPeer(e, false)
             p = utils.getInputPeer(e, false)
             markedId = utils.getPeerId(p)
             markedId = utils.getPeerId(p)
         } catch (e) {
         } catch (e) {
-            // Note: `get_input_peer` already checks for non-zero `access_hash`.
+            // Note: `get_input_peer` already checks for non-zero `accessHash`.
             // See issues #354 and #392. It also checks that the entity
             // See issues #354 and #392. It also checks that the entity
-            // is not `min`, because its `access_hash` cannot be used
+            // is not `min`, because its `accessHash` cannot be used
             // anywhere (since layer 102, there are two access hashes).
             // anywhere (since layer 102, there are two access hashes).
             return
             return
         }
         }

+ 18 - 0
src/lib/gramjs/sessions/StringSession.js → gramjs/sessions/StringSession.js

@@ -82,6 +82,24 @@ class StringSession extends MemorySession {
             this.authKey.getKey(),
             this.authKey.getKey(),
         ]))
         ]))
     }
     }
+
+    getAuthKey(dcId) {
+        if (dcId && dcId !== this.dcId) {
+            // Not supported.
+            return undefined
+        }
+
+        return this.authKey
+    }
+
+    setAuthKey(authKey, dcId) {
+        if (dcId && dcId !== this.dcId) {
+            // Not supported.
+            return undefined
+        }
+
+        this.authKey = authKey
+    }
 }
 }
 
 
 module.exports = StringSession
 module.exports = StringSession

+ 2 - 2
src/lib/gramjs/sessions/index.js → gramjs/sessions/index.js

@@ -1,9 +1,9 @@
 const Memory = require('./Memory')
 const Memory = require('./Memory')
 const StringSession = require('./StringSession')
 const StringSession = require('./StringSession')
-const LocalStorageSession = require('./LocalStorageSession')
+const CacheApiSession = require('./CacheApiSession')
 
 
 module.exports = {
 module.exports = {
     Memory,
     Memory,
     StringSession,
     StringSession,
-    LocalStorageSession
+    CacheApiSession
 }
 }

+ 42 - 0
gramjs/tl/MTProtoRequest.js

@@ -0,0 +1,42 @@
+class MTProtoRequest {
+    constructor() {
+        this.sent = false
+        this.msgId = 0 // long
+        this.sequence = 0
+
+        this.dirty = false
+        this.sendTime = 0
+        this.confirmReceived = false
+
+        // These should be overrode
+
+        this.constructorId = 0
+        this.confirmed = false
+        this.responded = false
+    }
+
+    // these should not be overrode
+    onSendSuccess() {
+        this.sendTime = new Date().getTime()
+        this.sent = true
+    }
+
+    onConfirm() {
+        this.confirmReceived = true
+    }
+
+    needResend() {
+        return this.dirty || (this.confirmed && !this.confirmReceived && new Date().getTime() - this.sendTime > 3000)
+    }
+
+    // These should be overrode
+    onSend() {
+        throw Error('Not overload ' + this.constructor.name)
+    }
+
+    onResponse(buffer) {}
+
+    onException(exception) {}
+}
+
+module.exports = MTProtoRequest

Diferenças do arquivo suprimidas por serem muito extensas
+ 845 - 55
gramjs/tl/api.d.ts


+ 37 - 110
src/lib/gramjs/tl/gramJsApi.js → gramjs/tl/api.js

@@ -1,25 +1,14 @@
-<<<<<<< HEAD:src/lib/gramjs/tl/gramJsApi.js
-//const { readFileSync } = require('fs')
-import { readFileSync } from 'fs'
-
-
-=======
-const { readFileSync } = require('fs')
->>>>>>> 1ab480fe... Gram JS: Remove deps; Fix Factorizator and remove leemon lib:src/lib/gramjs/tl/api.js
 const {
 const {
     parseTl,
     parseTl,
     serializeBytes,
     serializeBytes,
     serializeDate
     serializeDate
 } = require('./generationHelpers')
 } = require('./generationHelpers')
-<<<<<<< HEAD:src/lib/gramjs/tl/gramJsApi.js
-=======
 const { readBufferFromBigInt,toSignedLittleBuffer } = require('../Helpers')
 const { readBufferFromBigInt,toSignedLittleBuffer } = require('../Helpers')
-<<<<<<< HEAD:src/lib/gramjs/tl/gramJsApi.js
->>>>>>> 1a0b5c54... GramJS: Fix images loading: add `async-mutex`; Fix signed LE ints; Bring back `readExactly`:src/lib/gramjs/tl/api.js
 
 
-=======
+const tlContent = require('./static/api.reduced.tl').default;
+const schemeContent = require('./static/schema.reduced.tl').default;
+
 /*CONTEST
 /*CONTEST
->>>>>>> 3f7f5bfa... GramJS: Comment out unused things:src/lib/gramjs/tl/api.js
 const NAMED_AUTO_CASTS = new Set([
 const NAMED_AUTO_CASTS = new Set([
     'chatId,int'
     'chatId,int'
 ])
 ])
@@ -36,21 +25,15 @@ const AUTO_CASTS = new Set([
     'InputPhoto',
     'InputPhoto',
     'InputMessage',
     'InputMessage',
     'InputDocument',
     'InputDocument',
-    'InputChatPhoto',
+    'InputChatPhoto'
 ])
 ])
-<<<<<<< HEAD:src/lib/gramjs/tl/gramJsApi.js
-const struct = require('python-struct')
-=======
 
 
  */
  */
 const CACHING_SUPPORTED = typeof self !== 'undefined' && self.localStorage !== undefined
 const CACHING_SUPPORTED = typeof self !== 'undefined' && self.localStorage !== undefined
->>>>>>> 3f7f5bfa... GramJS: Comment out unused things:src/lib/gramjs/tl/api.js
 
 
-const { readBufferFromBigInt } = require('../Helpers')
+const CACHE_KEY = 'GramJs:apiCache'
 
 
 function buildApiFromTlSchema() {
 function buildApiFromTlSchema() {
-<<<<<<< HEAD:src/lib/gramjs/tl/gramJsApi.js
-=======
     let definitions;
     let definitions;
     const fromCache = CACHING_SUPPORTED && loadFromCache()
     const fromCache = CACHING_SUPPORTED && loadFromCache()
 
 
@@ -76,19 +59,27 @@ function loadFromCache() {
 }
 }
 
 
 function loadFromTlSchemas() {
 function loadFromTlSchemas() {
->>>>>>> 48d2d818... Support reconnect and re-sync:src/lib/gramjs/tl/api.js
-    const tlContent = readFileSync('./static/api.tl', 'utf-8')
     const [constructorParamsApi, functionParamsApi] = extractParams(tlContent)
     const [constructorParamsApi, functionParamsApi] = extractParams(tlContent)
-    const schemeContent = readFileSync('./static/schema.tl', 'utf-8')
     const [constructorParamsSchema, functionParamsSchema] = extractParams(schemeContent)
     const [constructorParamsSchema, functionParamsSchema] = extractParams(schemeContent)
-    const constructors = [...constructorParamsApi, ...constructorParamsSchema]
-    const requests = [...functionParamsApi, ...functionParamsSchema]
-    return {
-        constructors: createClasses('constructor', constructors),
-        requests: createClasses('request', requests),
-    }
+    const constructors = [].concat(constructorParamsApi, constructorParamsSchema)
+    const requests = [].concat(functionParamsApi, functionParamsSchema)
+
+    return { constructors, requests }
 }
 }
 
 
+function mergeWithNamespaces(obj1, obj2) {
+    const result = { ...obj1 }
+
+    Object.keys(obj2).forEach((key) => {
+        if (typeof obj2[key] === 'function' || !result[key]) {
+            result[key] = obj2[key]
+        } else {
+            Object.assign(result[key], obj2[key])
+        }
+    })
+
+    return result
+}
 
 
 function extractParams(fileContent) {
 function extractParams(fileContent) {
     const f = parseTl(fileContent, 109)
     const f = parseTl(fileContent, 109)
@@ -100,7 +91,6 @@ function extractParams(fileContent) {
     return [constructors, functions]
     return [constructors, functions]
 }
 }
 
 
-
 function argToBytes(x, type) {
 function argToBytes(x, type) {
     switch (type) {
     switch (type) {
         case 'int':
         case 'int':
@@ -128,7 +118,7 @@ function argToBytes(x, type) {
         case 'date':
         case 'date':
             return serializeDate(x)
             return serializeDate(x)
         default:
         default:
-            throw new Error("unsupported")
+            return x.getBytes()
     }
     }
 }
 }
 /*
 /*
@@ -159,9 +149,7 @@ async function getInputFromResolve(utils, client, peer, peerType) {
             return await client.getPeerId(peer, false)
             return await client.getPeerId(peer, false)
         default:
         default:
             throw new Error('unsupported peer type : ' + peerType)
             throw new Error('unsupported peer type : ' + peerType)
-
     }
     }
-
 }
 }
 */
 */
 function getArgFromReader(reader, arg) {
 function getArgFromReader(reader, arg) {
@@ -202,31 +190,30 @@ function getArgFromReader(reader, arg) {
             case 'date':
             case 'date':
                 return reader.tgReadDate()
                 return reader.tgReadDate()
             default:
             default:
-
                 if (!arg.skipConstructorId) {
                 if (!arg.skipConstructorId) {
                     return reader.tgReadObject()
                     return reader.tgReadObject()
                 } else {
                 } else {
-                    return gramJsApi.constructors[arg.type].fromReader(reader)
+                    return api.constructors[arg.type].fromReader(reader)
                 }
                 }
         }
         }
     }
     }
-
 }
 }
 
 
 function createClasses(classesType, params) {
 function createClasses(classesType, params) {
     const classes = {}
     const classes = {}
     for (const classParams of params) {
     for (const classParams of params) {
-        const { name, constructorId, subclassOfId, argsConfig, namespace ,result} = classParams
+        const { name, constructorId, subclassOfId, argsConfig, namespace, result } = classParams
+        const fullName = [namespace, name].join('.').replace(/^\./, '')
 
 
         class VirtualClass {
         class VirtualClass {
             static CONSTRUCTOR_ID = constructorId
             static CONSTRUCTOR_ID = constructorId
             static SUBCLASS_OF_ID = subclassOfId
             static SUBCLASS_OF_ID = subclassOfId
-            static className = name
+            static className = fullName
             static classType = classesType
             static classType = classesType
 
 
             CONSTRUCTOR_ID = constructorId
             CONSTRUCTOR_ID = constructorId
             SUBCLASS_OF_ID = subclassOfId
             SUBCLASS_OF_ID = subclassOfId
-            className = name
+            className = fullName
             classType = classesType
             classType = classesType
 
 
             constructor(args) {
             constructor(args) {
@@ -274,36 +261,18 @@ function createClasses(classesType, params) {
                 for (const arg in argsConfig) {
                 for (const arg in argsConfig) {
                     if (argsConfig.hasOwnProperty(arg)) {
                     if (argsConfig.hasOwnProperty(arg)) {
                         if (argsConfig[arg].isFlag) {
                         if (argsConfig[arg].isFlag) {
-<<<<<<< HEAD:src/lib/gramjs/tl/gramJsApi.js
-                            const tempBuffers = []
-                            if (argsConfig[arg] === 'true') {
-
-                            } else if (argsConfig[arg].isVector) {
-                                if (argsConfig[arg].useVectorId) {
-                                    tempBuffers.push(Buffer.from('15c4b51c', 'hex'))
-                                }
-                                const l = Buffer.alloc(4)
-                                l.writeInt32LE(this[arg].length, 0)
-                                buffers.push((!this[arg] ? Buffer.alloc(0) : Buffer.concat([...tempBuffers,
-                                    l, Buffer.concat(this[arg].map(x => argToBytes(x, argsConfig[arg].type)))])))
-                            }
-                        } else if (argsConfig[arg].isVector && !argsConfig[arg].isFlag) {
-                            if (argsConfig[arg].isVector) {
-=======
                           if (this[arg]===false || this[arg]===null || this[arg]===undefined || argsConfig[arg].type==='true'){
                           if (this[arg]===false || this[arg]===null || this[arg]===undefined || argsConfig[arg].type==='true'){
                               continue
                               continue
                           }
                           }
                         }
                         }
                         if (argsConfig[arg].isVector) {
                         if (argsConfig[arg].isVector) {
                             if (argsConfig[arg].useVectorId) {
                             if (argsConfig[arg].useVectorId) {
->>>>>>> 49c97f0a... GramJS : Fix flags and vector reading (#154):src/lib/gramjs/tl/api.js
                                 buffers.push(Buffer.from('15c4b51c', 'hex'))
                                 buffers.push(Buffer.from('15c4b51c', 'hex'))
                             }
                             }
                             const l = Buffer.alloc(4)
                             const l = Buffer.alloc(4)
                             l.writeInt32LE(this[arg].length, 0)
                             l.writeInt32LE(this[arg].length, 0)
                             buffers.push(l, Buffer.concat(this[arg].map(x => argToBytes(x, argsConfig[arg].type))))
                             buffers.push(l, Buffer.concat(this[arg].map(x => argToBytes(x, argsConfig[arg].type))))
                         } else if (argsConfig[arg].flagIndicator) {
                         } else if (argsConfig[arg].flagIndicator) {
-                            // @ts-ignore
                             if (!Object.values(argsConfig)
                             if (!Object.values(argsConfig)
                               .some((f) => f.isFlag)) {
                               .some((f) => f.isFlag)) {
                                 buffers.push(Buffer.alloc(4))
                                 buffers.push(Buffer.alloc(4))
@@ -323,48 +292,14 @@ function createClasses(classesType, params) {
                                 buffers.push(f)
                                 buffers.push(f)
                             }
                             }
                         } else {
                         } else {
+                            buffers.push(argToBytes(this[arg], argsConfig[arg].type))
 
 
-                            switch (argsConfig[arg].type) {
-                                case 'int':
-                                    const i = Buffer.alloc(4)
-                                    i.writeInt32LE(this[arg], 0)
-                                    buffers.push(i)
-                                    break
-                                case 'long':
-                                    buffers.push(toSignedLittleBuffer(this[arg], 8))
-                                    break
-                                case 'int128':
-                                    buffers.push(toSignedLittleBuffer(this[arg], 16))
-                                    break
-                                case 'int256':
-                                    buffers.push(toSignedLittleBuffer(this[arg], 32))
-                                    break
-                                case 'double':
-                                    const d = Buffer.alloc(8)
-                                    d.writeDoubleLE(this[arg].toString(), 0)
-                                    buffers.push(d)
-                                    break
-                                case 'string':
-                                    buffers.push(serializeBytes(this[arg]))
-                                    break
-                                case 'Bool':
-                                    buffers.push(this[arg] ? Buffer.from('b5757299', 'hex') : Buffer.from('379779bc', 'hex'))
-                                    break
-                                case 'true':
-                                    break
-                                case 'bytes':
-                                    buffers.push(serializeBytes(this[arg]))
-                                    break
-                                case 'date':
-                                    buffers.push(serializeDate(this[arg]))
-                                    break
-                                default:
-                                    buffers.push(this[arg].getBytes())
-                                    let boxed = (argsConfig[arg].type.charAt(argsConfig[arg].type.indexOf('.') + 1))
-                                    boxed = boxed === boxed.toUpperCase()
-                                    if (!boxed) {
-                                        buffers.shift()
-                                    }
+                            if (this[arg] && typeof this[arg].getBytes === 'function') {
+                                let boxed = (argsConfig[arg].type.charAt(argsConfig[arg].type.indexOf('.') + 1))
+                                boxed = boxed === boxed.toUpperCase()
+                                if (!boxed) {
+                                    buffers.shift()
+                                }
                             }
                             }
                         }
                         }
                     }
                     }
@@ -420,11 +355,11 @@ function createClasses(classesType, params) {
                         if (argsConfig[arg].isVector) {
                         if (argsConfig[arg].isVector) {
                             const temp = []
                             const temp = []
                             for (const x of this[arg]) {
                             for (const x of this[arg]) {
-                                temp.push(await getInputFromResolve(utils, client, this[arg], argsConfig[arg].type))
+                                temp.push(await getInputFromResolve(utils, client, x, argsConfig[arg].type))
                             }
                             }
                             this[arg] = temp
                             this[arg] = temp
                         } else {
                         } else {
-                            this[arg] =await getInputFromResolve(utils, client, this[arg], argsConfig[arg].type)
+                            this[arg] = await getInputFromResolve(utils, client, this[arg], argsConfig[arg].type)
                         }
                         }
                     }
                     }
                 }
                 }
@@ -433,24 +368,16 @@ function createClasses(classesType, params) {
 
 
         if (namespace) {
         if (namespace) {
             if (!classes[namespace]) {
             if (!classes[namespace]) {
-                // @ts-ignore
                 classes[namespace] = {}
                 classes[namespace] = {}
             }
             }
             classes[namespace][name] = VirtualClass
             classes[namespace][name] = VirtualClass
 
 
         } else {
         } else {
             classes[name] = VirtualClass
             classes[name] = VirtualClass
-
         }
         }
     }
     }
 
 
     return classes
     return classes
 }
 }
 
 
-<<<<<<< HEAD:src/lib/gramjs/tl/gramJsApi.js
-const gramJsApi = buildApiFromTlSchema()
-module.exports = gramJsApi
-=======
 module.exports = buildApiFromTlSchema()
 module.exports = buildApiFromTlSchema()
-console.log(module.exports)
->>>>>>> 1ab480fe... Gram JS: Remove deps; Fix Factorizator and remove leemon lib:src/lib/gramjs/tl/api.js

+ 9 - 2
src/lib/gramjs/tl/core/GZIPPacked.js → gramjs/tl/core/GZIPPacked.js

@@ -1,5 +1,6 @@
 const { serializeBytes } = require('../index')
 const { serializeBytes } = require('../index')
 const { inflate } = require('pako/dist/pako_inflate')
 const { inflate } = require('pako/dist/pako_inflate')
+//CONTEST const { deflate } = require('pako/dist/pako_deflate')
 
 
 class GZIPPacked {
 class GZIPPacked {
     static CONSTRUCTOR_ID = 0x3072cfa1
     static CONSTRUCTOR_ID = 0x3072cfa1
@@ -13,7 +14,7 @@ class GZIPPacked {
 
 
     static async gzipIfSmaller(contentRelated, data) {
     static async gzipIfSmaller(contentRelated, data) {
         if (contentRelated && data.length > 512) {
         if (contentRelated && data.length > 512) {
-            const gzipped = await new GZIPPacked(data).toBytes()
+            const gzipped = await (new GZIPPacked(data)).toBytes()
             if (gzipped.length < data.length) {
             if (gzipped.length < data.length) {
                 return gzipped
                 return gzipped
             }
             }
@@ -21,12 +22,18 @@ class GZIPPacked {
         return data
         return data
     }
     }
 
 
+    static gzip(input) {
+        return Buffer.from(input)
+        // TODO this usually makes it faster for large requests
+        //return Buffer.from(deflate(input, { level: 9, gzip: true }))
+    }
+
     static ungzip(input) {
     static ungzip(input) {
         return Buffer.from(inflate(input))
         return Buffer.from(inflate(input))
     }
     }
 
 
     async toBytes() {
     async toBytes() {
-        const g = Buffer.alloc(0)
+        const g = Buffer.alloc(4)
         g.writeUInt32LE(GZIPPacked.CONSTRUCTOR_ID, 0)
         g.writeUInt32LE(GZIPPacked.CONSTRUCTOR_ID, 0)
         return Buffer.concat([
         return Buffer.concat([
             g,
             g,

+ 0 - 0
src/lib/gramjs/tl/core/MessageContainer.js → gramjs/tl/core/MessageContainer.js


+ 0 - 0
src/lib/gramjs/tl/core/RPCResult.js → gramjs/tl/core/RPCResult.js


+ 0 - 0
src/lib/gramjs/tl/core/TLMessage.js → gramjs/tl/core/TLMessage.js


+ 17 - 0
gramjs/tl/core/index.js

@@ -0,0 +1,17 @@
+const TLMessage = require('./TLMessage')
+const RPCResult = require('./RPCResult')
+const MessageContainer = require('./MessageContainer')
+const GZIPPacked = require('./GZIPPacked')
+const coreObjects = {
+    [RPCResult.CONSTRUCTOR_ID]: RPCResult,
+    [GZIPPacked.CONSTRUCTOR_ID]: GZIPPacked,
+    [MessageContainer.CONSTRUCTOR_ID]: MessageContainer,
+}
+
+module.exports = {
+    TLMessage,
+    RPCResult,
+    MessageContainer,
+    GZIPPacked,
+    coreObjects,
+}

+ 326 - 0
gramjs/tl/generationHelpers.js

@@ -0,0 +1,326 @@
+const { crc32 } = require('../Helpers')
+const snakeToCamelCase = (name) => {
+    const result = name.replace(/(?:^|_)([a-z])/g, (_, g) => g.toUpperCase())
+    return result.replace(/_/g, '')
+}
+const variableSnakeToCamelCase = (str) => str.replace(
+    /([-_][a-z])/g,
+    (group) => group.toUpperCase()
+        .replace('-', '')
+        .replace('_', '')
+)
+
+const CORE_TYPES = new Set([
+    0xbc799737, // boolFalse#bc799737 = Bool;
+    0x997275b5, // boolTrue#997275b5 = Bool;
+    0x3fedd339, // true#3fedd339 = True;
+    0xc4b9f9bb, // error#c4b9f9bb code:int text:string = Error;
+    0x56730bcc // null#56730bcc = Null;
+])
+const AUTH_KEY_TYPES = new Set([
+    0x05162463, // resPQ,
+    0x83c95aec, // p_q_inner_data
+    0xa9f55f95, // p_q_inner_data_dc
+    0x3c6a84d4, // p_q_inner_data_temp
+    0x56fddf88, // p_q_inner_data_temp_dc
+    0xd0e8075c, // server_DH_params_ok
+    0xb5890dba, // server_DH_inner_data
+    0x6643b654, // client_DH_inner_data
+    0xd712e4be, // req_DH_params
+    0xf5045f1f, // set_client_DH_params
+    0x3072cfa1 // gzip_packed
+])
+
+
+const fromLine = (line, isFunction) => {
+    const match = line.match(/([\w.]+)(?:#([0-9a-fA-F]+))?(?:\s{?\w+:[\w\d<>#.?!]+}?)*\s=\s([\w\d<>#.?]+);$/)
+    if (!match) {
+        // Probably "vector#1cb5c415 {t:Type} # [ t ] = Vector t;"
+        throw new Error(`Cannot parse TLObject ${line}`)
+    }
+
+    const argsMatch = findAll(/({)?(\w+):([\w\d<>#.?!]+)}?/, line)
+    const currentConfig = {
+        name: match[1],
+        constructorId: parseInt(match[2], 16),
+        argsConfig: {},
+        subclassOfId: crc32(match[3]),
+        result: match[3],
+        isFunction: isFunction,
+        namespace: null
+    }
+    if (!currentConfig.constructorId) {
+
+        let hexId = ''
+        let args
+
+        if (Object.values(currentConfig.argsConfig).length) {
+            args = ` ${Object.keys(currentConfig.argsConfig).map((arg) => arg.toString()).join(' ')}`
+        } else {
+            args = ''
+        }
+
+        const representation = `${currentConfig.name}${hexId}${args} = ${currentConfig.result}`
+            .replace(/(:|\?)bytes /g, '$1string ')
+            .replace(/</g, ' ')
+            .replace(/>|{|}/g, '')
+            .replace(/ \w+:flags\.\d+\?true/g, '')
+
+        if (currentConfig.name === 'inputMediaInvoice') {
+            // eslint-disable-next-line no-empty
+            if (currentConfig.name === 'inputMediaInvoice') {
+            }
+        }
+
+        currentConfig.constructorId = crc32(Buffer.from(representation, 'utf8'))
+    }
+    for (const [brace, name, argType] of argsMatch) {
+        if (brace === undefined) {
+            currentConfig.argsConfig[variableSnakeToCamelCase(name)] = buildArgConfig(name, argType)
+        }
+    }
+    if (currentConfig.name.includes('.')) {
+        [currentConfig.namespace, currentConfig.name] = currentConfig.name.split(/\.(.+)/)
+    }
+    currentConfig.name = snakeToCamelCase(currentConfig.name)
+    /*
+    for (const arg in currentConfig.argsConfig){
+      if (currentConfig.argsConfig.hasOwnProperty(arg)){
+        if (currentConfig.argsConfig[arg].flagIndicator){
+          delete  currentConfig.argsConfig[arg]
+        }
+      }
+    }*/
+    return currentConfig
+}
+
+function buildArgConfig(name, argType) {
+    name = name === 'self' ? 'is_self' : name
+    // Default values
+    const currentConfig = {
+        isVector: false,
+        isFlag: false,
+        skipConstructorId: false,
+        flagIndex: -1,
+        flagIndicator: true,
+        type: null,
+        useVectorId: null
+    }
+
+    // Special case: some types can be inferred, which makes it
+    // less annoying to type. Currently the only type that can
+    // be inferred is if the name is 'random_id', to which a
+    // random ID will be assigned if left as None (the default)
+    let canBeInferred = name === 'random_id'
+
+    // The type can be an indicator that other arguments will be flags
+    if (argType !== '#') {
+        currentConfig.flagIndicator = false
+        // Strip the exclamation mark always to have only the name
+        currentConfig.type = argType.replace(/^!+/, '')
+
+        // The type may be a flag (flags.IDX?REAL_TYPE)
+        // Note that 'flags' is NOT the flags name; this
+        // is determined by a previous argument
+        // However, we assume that the argument will always be called 'flags'
+        // @ts-ignore
+        const flagMatch = currentConfig.type.match(/flags.(\d+)\?([\w<>.]+)/)
+
+        if (flagMatch) {
+            currentConfig.isFlag = true
+            currentConfig.flagIndex = Number(flagMatch[1]);
+            // Update the type to match the exact type, not the "flagged" one
+            [, , currentConfig.type] = flagMatch
+        }
+
+        // Then check if the type is a Vector<REAL_TYPE>
+        // @ts-ignore
+        const vectorMatch = currentConfig.type.match(/[Vv]ector<([\w\d.]+)>/)
+
+        if (vectorMatch) {
+            currentConfig.isVector = true
+
+            // If the type's first letter is not uppercase, then
+            // it is a constructor and we use (read/write) its ID.
+            // @ts-ignore
+            currentConfig.useVectorId = currentConfig.type.charAt(0) === 'V';
+
+            // Update the type to match the one inside the vector
+            [, currentConfig.type] = vectorMatch
+        }
+
+        // See use_vector_id. An example of such case is ipPort in
+        // help.configSpecial
+        // @ts-ignore
+        if (/^[a-z]$/.test(currentConfig.type.split('.')
+            .pop()
+            .charAt(0)
+        )
+        ) {
+            currentConfig.skipConstructorId = true
+        }
+
+        // The name may contain "date" in it, if this is the case and
+        // the type is "int", we can safely assume that this should be
+        // treated as a "date" object. Note that this is not a valid
+        // Telegram object, but it's easier to work with
+        // if (
+        //     this.type === 'int' &&
+        //     (/(\b|_)([dr]ate|until|since)(\b|_)/.test(name) ||
+        //         ['expires', 'expires_at', 'was_online'].includes(name))
+        // ) {
+        //     this.type = 'date';
+        // }
+    }
+    return currentConfig
+}
+
+
+const parseTl = function* (content, layer, methods = [], ignoreIds = CORE_TYPES) {
+    const methodInfo = (methods || []).reduce((o, m) => ({ ...o, [m.name]: m }), {})
+    const objAll = []
+    const objByName = {}
+    const objByType = {}
+
+    const file = content
+
+    let isFunction = false
+
+    for (let line of file.split('\n')) {
+        const commentIndex = line.indexOf('//')
+
+        if (commentIndex !== -1) {
+            line = line.slice(0, commentIndex)
+        }
+
+        line = line.trim()
+
+        if (!line) {
+            continue
+        }
+
+        const match = line.match(/---(\w+)---/)
+
+        if (match) {
+            const [, followingTypes] = match
+            isFunction = followingTypes === 'functions'
+            continue
+        }
+
+        try {
+            const result = fromLine(line, isFunction)
+
+            if (ignoreIds.has(result.constructorId)) {
+                continue
+            }
+
+            objAll.push(result)
+
+            if (!result.isFunction) {
+                if (!objByType[result.result]) {
+                    objByType[result.result] = []
+                }
+
+                objByName[result.name] = result
+                objByType[result.result].push(result)
+            }
+        } catch (e) {
+            if (!e.toString().includes('vector#1cb5c415')) {
+                throw e
+            }
+        }
+    }
+
+    // Once all objects have been parsed, replace the
+    // string type from the arguments with references
+    for (const obj of objAll) {
+        //console.log(obj)
+        if (AUTH_KEY_TYPES.has(obj.constructorId)) {
+            for (const arg in obj.argsConfig) {
+                if (obj.argsConfig[arg].type === 'string') {
+                    obj.argsConfig[arg].type = 'bytes'
+                }
+            }
+        }
+    }
+
+    for (const obj of objAll) {
+        yield obj
+    }
+
+}
+
+const findAll = (regex, str, matches = []) => {
+    if (!regex.flags.includes(`g`)) {
+        regex = new RegExp(regex.source, `g`)
+    }
+
+    const res = regex.exec(str)
+
+    if (res) {
+        matches.push(res.slice(1))
+        findAll(regex, str, matches)
+    }
+
+    return matches
+}
+
+function serializeBytes(data) {
+    if (!(data instanceof Buffer)) {
+        if (typeof data == 'string') {
+            data = Buffer.from(data)
+        } else {
+            throw Error(`Bytes or str expected, not ${data.constructor.name}`)
+        }
+    }
+    const r = []
+    let padding
+    if (data.length < 254) {
+        padding = (data.length + 1) % 4
+        if (padding !== 0) {
+            padding = 4 - padding
+        }
+        r.push(Buffer.from([data.length]))
+        r.push(data)
+    } else {
+        padding = data.length % 4
+        if (padding !== 0) {
+            padding = 4 - padding
+        }
+        r.push(Buffer.from([254, data.length % 256, (data.length >> 8) % 256, (data.length >> 16) % 256]))
+        r.push(data)
+    }
+    r.push(Buffer.alloc(padding)
+        .fill(0))
+
+    return Buffer.concat(r)
+
+}
+
+function serializeDate(dt) {
+    if (!dt) {
+        return Buffer.alloc(4)
+            .fill(0)
+    }
+    if (dt instanceof Date) {
+        dt = Math.floor((Date.now() - dt.getTime()) / 1000)
+    }
+    if (typeof dt == 'number') {
+        const t = Buffer.alloc(4)
+        t.writeInt32LE(dt, 0)
+        return t
+    }
+    throw Error(`Cannot interpret "${dt}" as a date`)
+}
+
+module.exports = {
+    findAll,
+    parseTl,
+    buildArgConfig,
+    fromLine,
+    CORE_TYPES,
+    serializeDate,
+    serializeBytes,
+    snakeToCamelCase,
+    variableSnakeToCamelCase
+}

+ 4 - 3
src/lib/gramjs/tl/index.js → gramjs/tl/index.js

@@ -1,10 +1,11 @@
-const { constructors, requests } = require('./gramJsApi')
+const api = require('./api')
 const { serializeBytes, serializeDate } = require('./generationHelpers')
 const { serializeBytes, serializeDate } = require('./generationHelpers')
 const patched = null
 const patched = null
 
 
 module.exports = {
 module.exports = {
-    constructors,
-    requests,
+    // TODO Refactor internal usages to always use `api`.
+    constructors: api,
+    requests: api,
     patched,
     patched,
     serializeBytes,
     serializeBytes,
     serializeDate
     serializeDate

+ 66 - 12
src/lib/gramjs/tl/static/api.tl → gramjs/tl/static/api.reduced.tl

@@ -32,7 +32,8 @@ inputMediaDocumentExternal#fb52dc99 flags:# url:string ttl_seconds:flags.0?int =
 inputMediaGame#d33f43f3 id:InputGame = InputMedia;
 inputMediaGame#d33f43f3 id:InputGame = InputMedia;
 inputMediaInvoice#f4e096c3 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:string = InputMedia;
 inputMediaInvoice#f4e096c3 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:string = InputMedia;
 inputMediaGeoLive#ce4e82fd flags:# stopped:flags.0?true geo_point:InputGeoPoint period:flags.1?int = InputMedia;
 inputMediaGeoLive#ce4e82fd flags:# stopped:flags.0?true geo_point:InputGeoPoint period:flags.1?int = InputMedia;
-inputMediaPoll#abe9ca25 flags:# poll:Poll correct_answers:flags.0?Vector<bytes> = InputMedia;
+inputMediaPoll#f94e5f1 flags:# poll:Poll correct_answers:flags.0?Vector<bytes> solution:flags.1?string solution_entities:flags.1?Vector<MessageEntity> = InputMedia;
+inputMediaDice#e66fbf7b emoticon:string = InputMedia;
 inputChatPhotoEmpty#1ca48f57 = InputChatPhoto;
 inputChatPhotoEmpty#1ca48f57 = InputChatPhoto;
 inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto;
 inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto;
 inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto;
 inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto;
@@ -78,7 +79,7 @@ chatForbidden#7328bdb id:int title:string = Chat;
 channel#d31a961e flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?Vector<RestrictionReason> admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = Chat;
 channel#d31a961e flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?Vector<RestrictionReason> admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = Chat;
 channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat;
 channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat;
 chatFull#1b7c9db3 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true id:int about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int folder_id:flags.11?int = ChatFull;
 chatFull#1b7c9db3 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true id:int about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int folder_id:flags.11?int = ChatFull;
-channelFull#2d895c74 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_view_stats:flags.12?true can_set_location:flags.16?true has_scheduled:flags.19?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?int location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int pts:int = ChatFull;
+channelFull#f0e6672a flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_view_stats:flags.12?true can_set_location:flags.16?true has_scheduled:flags.19?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?int location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int = ChatFull;
 chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant;
 chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant;
 chatParticipantCreator#da13538a user_id:int = ChatParticipant;
 chatParticipantCreator#da13538a user_id:int = ChatParticipant;
 chatParticipantAdmin#e2d6e436 user_id:int inviter_id:int date:int = ChatParticipant;
 chatParticipantAdmin#e2d6e436 user_id:int inviter_id:int date:int = ChatParticipant;
@@ -101,6 +102,7 @@ messageMediaGame#fdb19008 game:Game = MessageMedia;
 messageMediaInvoice#84551347 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string = MessageMedia;
 messageMediaInvoice#84551347 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string = MessageMedia;
 messageMediaGeoLive#7c3c2609 geo:GeoPoint period:int = MessageMedia;
 messageMediaGeoLive#7c3c2609 geo:GeoPoint period:int = MessageMedia;
 messageMediaPoll#4bd6e798 poll:Poll results:PollResults = MessageMedia;
 messageMediaPoll#4bd6e798 poll:Poll results:PollResults = MessageMedia;
+messageMediaDice#3f7ee58b value:int emoticon:string = MessageMedia;
 messageActionEmpty#b6aef7b0 = MessageAction;
 messageActionEmpty#b6aef7b0 = MessageAction;
 messageActionChatCreate#a6638b9a title:string users:Vector<int> = MessageAction;
 messageActionChatCreate#a6638b9a title:string users:Vector<int> = MessageAction;
 messageActionChatEditTitle#b5a1ce5a title:string = MessageAction;
 messageActionChatEditTitle#b5a1ce5a title:string = MessageAction;
@@ -268,6 +270,9 @@ updateTheme#8216fba3 theme:Theme = Update;
 updateGeoLiveViewed#871fb939 peer:Peer msg_id:int = Update;
 updateGeoLiveViewed#871fb939 peer:Peer msg_id:int = Update;
 updateLoginToken#564fe691 = Update;
 updateLoginToken#564fe691 = Update;
 updateMessagePollVote#42f88f2c poll_id:long user_id:int options:Vector<bytes> = Update;
 updateMessagePollVote#42f88f2c poll_id:long user_id:int options:Vector<bytes> = Update;
+updateDialogFilter#26ffde7d flags:# id:int filter:flags.0?DialogFilter = Update;
+updateDialogFilterOrder#a5d72105 order:Vector<int> = Update;
+updateDialogFilters#3504914f = Update;
 updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
 updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
 updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference;
 updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference;
 updates.difference#f49ca0 new_messages:Vector<Message> new_encrypted_messages:Vector<EncryptedMessage> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> state:updates.State = updates.Difference;
 updates.difference#f49ca0 new_messages:Vector<Message> new_encrypted_messages:Vector<EncryptedMessage> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> state:updates.State = updates.Difference;
@@ -382,7 +387,7 @@ messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMess
 webPageEmpty#eb1477e8 id:long = WebPage;
 webPageEmpty#eb1477e8 id:long = WebPage;
 webPagePending#c586da1c id:long date:int = WebPage;
 webPagePending#c586da1c id:long date:int = WebPage;
 webPage#e89c45b2 flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page attributes:flags.12?Vector<WebPageAttribute> = WebPage;
 webPage#e89c45b2 flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page attributes:flags.12?Vector<WebPageAttribute> = WebPage;
-webPageNotModified#85849473 = WebPage;
+webPageNotModified#7311ca11 flags:# cached_page_views:flags.0?int = WebPage;
 authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true password_pending:flags.2?true hash:long device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization;
 authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true password_pending:flags.2?true hash:long device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization;
 account.authorizations#1250abde authorizations:Vector<Authorization> = account.Authorizations;
 account.authorizations#1250abde authorizations:Vector<Authorization> = account.Authorizations;
 account.password#ad2641f8 flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes = account.Password;
 account.password#ad2641f8 flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes = account.Password;
@@ -398,6 +403,7 @@ inputStickerSetEmpty#ffb62b95 = InputStickerSet;
 inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet;
 inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet;
 inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet;
 inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet;
 inputStickerSetAnimatedEmoji#28703c8 = InputStickerSet;
 inputStickerSetAnimatedEmoji#28703c8 = InputStickerSet;
+inputStickerSetDice#e67f520e emoticon:string = InputStickerSet;
 stickerSet#eeb46f27 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumb:flags.4?PhotoSize thumb_dc_id:flags.4?int count:int hash:int = StickerSet;
 stickerSet#eeb46f27 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumb:flags.4?PhotoSize thumb_dc_id:flags.4?int count:int hash:int = StickerSet;
 messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet;
 messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet;
 botCommand#c27ac8c7 command:string description:string = BotCommand;
 botCommand#c27ac8c7 command:string description:string = BotCommand;
@@ -436,6 +442,7 @@ messageEntityCashtag#4c4e743f offset:int length:int = MessageEntity;
 messageEntityUnderline#9c4e7e8b offset:int length:int = MessageEntity;
 messageEntityUnderline#9c4e7e8b offset:int length:int = MessageEntity;
 messageEntityStrike#bf0693d4 offset:int length:int = MessageEntity;
 messageEntityStrike#bf0693d4 offset:int length:int = MessageEntity;
 messageEntityBlockquote#20df5d0 offset:int length:int = MessageEntity;
 messageEntityBlockquote#20df5d0 offset:int length:int = MessageEntity;
+messageEntityBankCard#761e6af4 offset:int length:int = MessageEntity;
 inputChannelEmpty#ee8c1e86 = InputChannel;
 inputChannelEmpty#ee8c1e86 = InputChannel;
 inputChannel#afeb712e channel_id:int access_hash:long = InputChannel;
 inputChannel#afeb712e channel_id:int access_hash:long = InputChannel;
 inputChannelFromMessage#2a286531 peer:InputPeer msg_id:int channel_id:int = InputChannel;
 inputChannelFromMessage#2a286531 peer:InputPeer msg_id:int channel_id:int = InputChannel;
@@ -514,8 +521,8 @@ contacts.topPeers#70b772a8 categories:Vector<TopPeerCategoryPeers> chats:Vector<
 contacts.topPeersDisabled#b52c939d = contacts.TopPeers;
 contacts.topPeersDisabled#b52c939d = contacts.TopPeers;
 draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage;
 draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage;
 draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector<MessageEntity> date:int = DraftMessage;
 draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector<MessageEntity> date:int = DraftMessage;
-messages.featuredStickersNotModified#4ede3cf = messages.FeaturedStickers;
-messages.featuredStickers#f89d88e5 hash:int sets:Vector<StickerSetCovered> unread:Vector<long> = messages.FeaturedStickers;
+messages.featuredStickersNotModified#c6dc0c66 count:int = messages.FeaturedStickers;
+messages.featuredStickers#b6abc341 hash:int count:int sets:Vector<StickerSetCovered> unread:Vector<long> = messages.FeaturedStickers;
 messages.recentStickersNotModified#b17f890 = messages.RecentStickers;
 messages.recentStickersNotModified#b17f890 = messages.RecentStickers;
 messages.recentStickers#22f3afb3 hash:int packs:Vector<StickerPack> stickers:Vector<Document> dates:Vector<int> = messages.RecentStickers;
 messages.recentStickers#22f3afb3 hash:int packs:Vector<StickerPack> stickers:Vector<Document> dates:Vector<int> = messages.RecentStickers;
 messages.archivedStickers#4fcba9c8 count:int sets:Vector<StickerSetCovered> = messages.ArchivedStickers;
 messages.archivedStickers#4fcba9c8 count:int sets:Vector<StickerSetCovered> = messages.ArchivedStickers;
@@ -614,7 +621,7 @@ phoneCallAccepted#997c454a flags:# video:flags.5?true id:long access_hash:long d
 phoneCall#8742ae7f flags:# p2p_allowed:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connections:Vector<PhoneConnection> start_date:int = PhoneCall;
 phoneCall#8742ae7f flags:# p2p_allowed:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connections:Vector<PhoneConnection> start_date:int = PhoneCall;
 phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true video:flags.5?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall;
 phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true video:flags.5?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall;
 phoneConnection#9d4c17c0 id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection;
 phoneConnection#9d4c17c0 id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection;
-phoneCallProtocol#a2bb35cb flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int = PhoneCallProtocol;
+phoneCallProtocol#fc878fc8 flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int library_versions:Vector<string> = PhoneCallProtocol;
 phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector<User> = phone.PhoneCall;
 phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector<User> = phone.PhoneCall;
 upload.cdnFileReuploadNeeded#eea8e46e request_token:bytes = upload.CdnFile;
 upload.cdnFileReuploadNeeded#eea8e46e request_token:bytes = upload.CdnFile;
 upload.cdnFile#a99fca4f bytes:bytes = upload.CdnFile;
 upload.cdnFile#a99fca4f bytes:bytes = upload.CdnFile;
@@ -743,20 +750,21 @@ pageListItemBlocks#25e073fc blocks:Vector<PageBlock> = PageListItem;
 pageListOrderedItemText#5e068047 num:string text:RichText = PageListOrderedItem;
 pageListOrderedItemText#5e068047 num:string text:RichText = PageListOrderedItem;
 pageListOrderedItemBlocks#98dd8936 num:string blocks:Vector<PageBlock> = PageListOrderedItem;
 pageListOrderedItemBlocks#98dd8936 num:string blocks:Vector<PageBlock> = PageListOrderedItem;
 pageRelatedArticle#b390dc08 flags:# url:string webpage_id:long title:flags.0?string description:flags.1?string photo_id:flags.2?long author:flags.3?string published_date:flags.4?int = PageRelatedArticle;
 pageRelatedArticle#b390dc08 flags:# url:string webpage_id:long title:flags.0?string description:flags.1?string photo_id:flags.2?long author:flags.3?string published_date:flags.4?int = PageRelatedArticle;
-page#ae891bec flags:# part:flags.0?true rtl:flags.1?true v2:flags.2?true url:string blocks:Vector<PageBlock> photos:Vector<Photo> documents:Vector<Document> = Page;
+page#98657f0d flags:# part:flags.0?true rtl:flags.1?true v2:flags.2?true url:string blocks:Vector<PageBlock> photos:Vector<Photo> documents:Vector<Document> views:flags.3?int = Page;
 help.supportName#8c05f1c9 name:string = help.SupportName;
 help.supportName#8c05f1c9 name:string = help.SupportName;
 help.userInfoEmpty#f3ae2eed = help.UserInfo;
 help.userInfoEmpty#f3ae2eed = help.UserInfo;
 help.userInfo#1eb3758 message:string entities:Vector<MessageEntity> author:string date:int = help.UserInfo;
 help.userInfo#1eb3758 message:string entities:Vector<MessageEntity> author:string date:int = help.UserInfo;
 pollAnswer#6ca9c2e9 text:string option:bytes = PollAnswer;
 pollAnswer#6ca9c2e9 text:string option:bytes = PollAnswer;
-poll#d5529d06 id:long flags:# closed:flags.0?true public_voters:flags.1?true multiple_choice:flags.2?true quiz:flags.3?true question:string answers:Vector<PollAnswer> = Poll;
+poll#86e18161 id:long flags:# closed:flags.0?true public_voters:flags.1?true multiple_choice:flags.2?true quiz:flags.3?true question:string answers:Vector<PollAnswer> close_period:flags.4?int close_date:flags.5?int = Poll;
 pollAnswerVoters#3b6ddad2 flags:# chosen:flags.0?true correct:flags.1?true option:bytes voters:int = PollAnswerVoters;
 pollAnswerVoters#3b6ddad2 flags:# chosen:flags.0?true correct:flags.1?true option:bytes voters:int = PollAnswerVoters;
-pollResults#c87024a2 flags:# min:flags.0?true results:flags.1?Vector<PollAnswerVoters> total_voters:flags.2?int recent_voters:flags.3?Vector<int> = PollResults;
+pollResults#badcc1a3 flags:# min:flags.0?true results:flags.1?Vector<PollAnswerVoters> total_voters:flags.2?int recent_voters:flags.3?Vector<int> solution:flags.4?string solution_entities:flags.4?Vector<MessageEntity> = PollResults;
 chatOnlines#f041e250 onlines:int = ChatOnlines;
 chatOnlines#f041e250 onlines:int = ChatOnlines;
 statsURL#47a971e0 url:string = StatsURL;
 statsURL#47a971e0 url:string = StatsURL;
 chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true = ChatAdminRights;
 chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true = ChatAdminRights;
 chatBannedRights#9f120418 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true send_polls:flags.8?true change_info:flags.10?true invite_users:flags.15?true pin_messages:flags.17?true until_date:int = ChatBannedRights;
 chatBannedRights#9f120418 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true send_polls:flags.8?true change_info:flags.10?true invite_users:flags.15?true pin_messages:flags.17?true until_date:int = ChatBannedRights;
 inputWallPaper#e630b979 id:long access_hash:long = InputWallPaper;
 inputWallPaper#e630b979 id:long access_hash:long = InputWallPaper;
 inputWallPaperSlug#72091c80 slug:string = InputWallPaper;
 inputWallPaperSlug#72091c80 slug:string = InputWallPaper;
+inputWallPaperNoFile#8427bbac = InputWallPaper;
 account.wallPapersNotModified#1c199183 = account.WallPapers;
 account.wallPapersNotModified#1c199183 = account.WallPapers;
 account.wallPapers#702b65a9 hash:int wallpapers:Vector<WallPaper> = account.WallPapers;
 account.wallPapers#702b65a9 hash:int wallpapers:Vector<WallPaper> = account.WallPapers;
 codeSettings#debebe83 flags:# allow_flashcall:flags.0?true current_number:flags.1?true allow_app_hash:flags.4?true = CodeSettings;
 codeSettings#debebe83 flags:# allow_flashcall:flags.0?true current_number:flags.1?true allow_app_hash:flags.4?true = CodeSettings;
@@ -779,6 +787,7 @@ urlAuthResultDefault#a9d6db1f = UrlAuthResult;
 channelLocationEmpty#bfb5ad8b = ChannelLocation;
 channelLocationEmpty#bfb5ad8b = ChannelLocation;
 channelLocation#209b82db geo_point:GeoPoint address:string = ChannelLocation;
 channelLocation#209b82db geo_point:GeoPoint address:string = ChannelLocation;
 peerLocated#ca461b5d peer:Peer expires:int distance:int = PeerLocated;
 peerLocated#ca461b5d peer:Peer expires:int distance:int = PeerLocated;
+peerSelfLocated#f8ec284b expires:int = PeerLocated;
 restrictionReason#d072acb4 platform:string reason:string text:string = RestrictionReason;
 restrictionReason#d072acb4 platform:string reason:string text:string = RestrictionReason;
 inputTheme#3c5693e9 id:long access_hash:long = InputTheme;
 inputTheme#3c5693e9 id:long access_hash:long = InputTheme;
 inputThemeSlug#f5890df1 slug:string = InputTheme;
 inputThemeSlug#f5890df1 slug:string = InputTheme;
@@ -802,9 +811,11 @@ messageUserVote#a28e5559 user_id:int option:bytes date:int = MessageUserVote;
 messageUserVoteInputOption#36377430 user_id:int date:int = MessageUserVote;
 messageUserVoteInputOption#36377430 user_id:int date:int = MessageUserVote;
 messageUserVoteMultiple#e8fe0de user_id:int options:Vector<bytes> date:int = MessageUserVote;
 messageUserVoteMultiple#e8fe0de user_id:int options:Vector<bytes> date:int = MessageUserVote;
 messages.votesList#823f649 flags:# count:int votes:Vector<MessageUserVote> users:Vector<User> next_offset:flags.0?string = messages.VotesList;
 messages.votesList#823f649 flags:# count:int votes:Vector<MessageUserVote> users:Vector<User> next_offset:flags.0?string = messages.VotesList;
-
+dialogFilter#7438f7e8 flags:# contacts:flags.0?true non_contacts:flags.1?true groups:flags.2?true broadcasts:flags.3?true bots:flags.4?true exclude_muted:flags.11?true exclude_read:flags.12?true exclude_archived:flags.13?true id:int title:string emoticon:flags.25?string pinned_peers:Vector<InputPeer> include_peers:Vector<InputPeer> exclude_peers:Vector<InputPeer> = DialogFilter;
+dialogFilterSuggested#77744d4a filter:DialogFilter description:string = DialogFilterSuggested;
+// Some unused types were removed here
 ---functions---
 ---functions---
-initConnection#785188b8 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy query:!X = X;
+initConnection#c1cd5ea9 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy params:flags.1?JSONValue query:!X = X;
 invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X;
 invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X;
 auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode;
 auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode;
 auth.signUp#80eee427 phone_number:string phone_code_hash:string first_name:string last_name:string = auth.Authorization;
 auth.signUp#80eee427 phone_number:string phone_code_hash:string first_name:string last_name:string = auth.Authorization;
@@ -819,8 +830,13 @@ auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery;
 auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode;
 auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode;
 auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool;
 auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool;
 auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector<long> = Bool;
 auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector<long> = Bool;
+account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User;
+account.getWallPapers#aabb1763 hash:int = account.WallPapers;
+auth.exportLoginToken#b1b41517 api_id:int api_hash:string except_ids:Vector<int> = auth.LoginToken;
+auth.importLoginToken#95ac5ce4 token:bytes = auth.LoginToken;
 account.checkUsername#2714d86c username:string = Bool;
 account.checkUsername#2714d86c username:string = Bool;
 account.updateUsername#3e0bdd7c username:string = User;
 account.updateUsername#3e0bdd7c username:string = User;
+account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool;
 account.getAuthorizations#e320c158 = account.Authorizations;
 account.getAuthorizations#e320c158 = account.Authorizations;
 account.resetAuthorization#df77f3bc hash:long = Bool;
 account.resetAuthorization#df77f3bc hash:long = Bool;
 account.getPassword#548a30f5 = account.Password;
 account.getPassword#548a30f5 = account.Password;
@@ -830,39 +846,70 @@ account.getTmpPassword#449e0b51 password:InputCheckPasswordSRP period:int = acco
 account.sendVerifyPhoneCode#a5a356f9 phone_number:string settings:CodeSettings = auth.SentCode;
 account.sendVerifyPhoneCode#a5a356f9 phone_number:string settings:CodeSettings = auth.SentCode;
 users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
 users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
 users.getFullUser#ca30a5b1 id:InputUser = UserFull;
 users.getFullUser#ca30a5b1 id:InputUser = UserFull;
+contacts.getContacts#c023849f hash:int = contacts.Contacts;
 contacts.search#11f812d8 q:string limit:int = contacts.Found;
 contacts.search#11f812d8 q:string limit:int = contacts.Found;
 contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer;
 contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer;
+contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true forward_users:flags.4?true forward_chats:flags.5?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers;
 messages.getMessages#63c66506 id:Vector<InputMessage> = messages.Messages;
 messages.getMessages#63c66506 id:Vector<InputMessage> = messages.Messages;
 messages.getDialogs#a0ee3b73 flags:# exclude_pinned:flags.0?true folder_id:flags.1?int offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:int = messages.Dialogs;
 messages.getDialogs#a0ee3b73 flags:# exclude_pinned:flags.0?true folder_id:flags.1?int offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:int = messages.Dialogs;
 messages.getHistory#dcbb8260 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
 messages.getHistory#dcbb8260 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
 messages.search#8614ef68 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
 messages.search#8614ef68 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
 messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages;
 messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages;
+messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true revoke:flags.1?true peer:InputPeer max_id:int = messages.AffectedHistory;
 messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector<int> = messages.AffectedMessages;
 messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector<int> = messages.AffectedMessages;
 messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>;
 messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>;
 messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool;
 messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool;
 messages.sendMessage#520c3870 flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int = Updates;
 messages.sendMessage#520c3870 flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int = Updates;
 messages.sendMedia#3491eba9 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int = Updates;
 messages.sendMedia#3491eba9 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int = Updates;
+messages.forwardMessages#d9fee60e flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true grouped:flags.9?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer schedule_date:flags.10?int = Updates;
 messages.getChats#3c6aa187 id:Vector<int> = messages.Chats;
 messages.getChats#3c6aa187 id:Vector<int> = messages.Chats;
 messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull;
 messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull;
+messages.editChatPhoto#ca4c79d8 chat_id:int photo:InputChatPhoto = Updates;
 messages.createChat#9cb126e users:Vector<InputUser> title:string = Updates;
 messages.createChat#9cb126e users:Vector<InputUser> title:string = Updates;
 messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig;
 messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig;
+messages.readMessageContents#36a73f77 id:Vector<int> = messages.AffectedMessages;
+messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers;
 messages.getWebPagePreview#8b68b0cc flags:# message:string entities:flags.3?Vector<MessageEntity> = MessageMedia;
 messages.getWebPagePreview#8b68b0cc flags:# message:string entities:flags.3?Vector<MessageEntity> = MessageMedia;
+messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet;
+messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult;
+messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool;
 messages.searchGlobal#bf7225a4 flags:# folder_id:flags.0?int q:string offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
 messages.searchGlobal#bf7225a4 flags:# folder_id:flags.0?int q:string offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
 messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document;
 messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document;
+messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs;
+messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs;
+messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults;
 messages.editMessage#48f71778 flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.15?int = Updates;
 messages.editMessage#48f71778 flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.15?int = Updates;
 messages.getPeerDialogs#e470bcfd peers:Vector<InputDialogPeer> = messages.PeerDialogs;
 messages.getPeerDialogs#e470bcfd peers:Vector<InputDialogPeer> = messages.PeerDialogs;
+messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector<MessageEntity> = Bool;
+messages.getFeaturedStickers#2dacca4f hash:int = messages.FeaturedStickers;
+messages.readFeaturedStickers#5b118126 id:Vector<long> = Bool;
+messages.getRecentStickers#5ea192c9 flags:# attached:flags.0?true hash:int = messages.RecentStickers;
 messages.getWebPage#32ca8f91 url:string hash:int = WebPage;
 messages.getWebPage#32ca8f91 url:string hash:int = WebPage;
+messages.toggleDialogPin#a731e257 flags:# pinned:flags.0?true peer:InputDialogPeer = Bool;
+messages.getPinnedDialogs#d6b94df2 folder_id:int = messages.PeerDialogs;
 messages.uploadMedia#519bc2b1 peer:InputPeer media:InputMedia = MessageMedia;
 messages.uploadMedia#519bc2b1 peer:InputPeer media:InputMedia = MessageMedia;
+messages.getFavedStickers#21ce0b0e hash:int = messages.FavedStickers;
+messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool;
+messages.sendMultiMedia#cc0110cb flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int multi_media:Vector<InputSingleMedia> schedule_date:flags.10?int = Updates;
+messages.searchStickerSets#c2b7d08b flags:# exclude_featured:flags.0?true q:string hash:int = messages.FoundStickerSets;
+messages.markDialogUnread#c286d98f flags:# unread:flags.0?true peer:InputDialogPeer = Bool;
 messages.updatePinnedMessage#d2aaf7ec flags:# silent:flags.0?true peer:InputPeer id:int = Updates;
 messages.updatePinnedMessage#d2aaf7ec flags:# silent:flags.0?true peer:InputPeer id:int = Updates;
+messages.sendVote#10ea6184 peer:InputPeer msg_id:int options:Vector<bytes> = Updates;
 messages.getOnlines#6e2be050 peer:InputPeer = ChatOnlines;
 messages.getOnlines#6e2be050 peer:InputPeer = ChatOnlines;
+messages.getPollVotes#b86e380e flags:# peer:InputPeer id:int option:flags.0?bytes offset:flags.1?string limit:int = messages.VotesList;
+messages.getDialogFilters#f19ed96d = Vector<DialogFilter>;
+messages.getSuggestedDialogFilters#a29cd42c = Vector<DialogFilterSuggested>;
+messages.updateDialogFilter#1ad4a04a flags:# id:int filter:flags.0?DialogFilter = Bool;
 updates.getState#edd4882a = updates.State;
 updates.getState#edd4882a = updates.State;
 updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
 updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
 updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference;
 updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference;
+photos.uploadProfilePhoto#4f32c098 file:InputFile = photos.Photo;
 upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool;
 upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool;
 upload.getFile#b15a9afc flags:# precise:flags.0?true cdn_supported:flags.1?true location:InputFileLocation offset:int limit:int = upload.File;
 upload.getFile#b15a9afc flags:# precise:flags.0?true cdn_supported:flags.1?true location:InputFileLocation offset:int limit:int = upload.File;
 upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool;
 upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool;
 help.getConfig#c4f9186b = Config;
 help.getConfig#c4f9186b = Config;
 help.getNearestDc#1fb33026 = NearestDc;
 help.getNearestDc#1fb33026 = NearestDc;
+help.getSupport#9cdf08cd = help.Support;
 help.acceptTermsOfService#ee72f79a id:DataJSON = Bool;
 help.acceptTermsOfService#ee72f79a id:DataJSON = Bool;
 channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool;
 channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool;
 channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector<int> = messages.AffectedMessages;
 channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector<int> = messages.AffectedMessages;
@@ -871,4 +918,11 @@ channels.getParticipants#123e05e9 channel:InputChannel filter:ChannelParticipant
 channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant;
 channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant;
 channels.getChannels#a7f6bbb id:Vector<InputChannel> = messages.Chats;
 channels.getChannels#a7f6bbb id:Vector<InputChannel> = messages.Chats;
 channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull;
 channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull;
-// LAYER 109
+channels.createChannel#3d5fb10f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string geo_point:flags.2?InputGeoPoint address:flags.2?string = Updates;
+channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates;
+channels.joinChannel#24b524c5 channel:InputChannel = Updates;
+channels.leaveChannel#f836aa95 channel:InputChannel = Updates;
+channels.deleteChannel#c0111fe3 channel:InputChannel = Updates;
+channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector<int> = Bool;
+folders.editPeerFolders#6847d0ab folder_peers:Vector<InputFolderPeer> = Updates;
+// LAYER 112

+ 1500 - 0
gramjs/tl/static/api.tl

@@ -0,0 +1,1500 @@
+///////////////////////////////
+/////////////////// Layer cons
+///////////////////////////////
+
+//invokeAfterMsg#cb9f372d msg_id:long query:!X = X;
+//invokeAfterMsgs#3dc4b4f0 msg_ids:Vector<long> query:!X = X;
+//invokeWithLayer1#53835315 query:!X = X;
+//invokeWithLayer2#289dd1f6 query:!X = X;
+//invokeWithLayer3#b7475268 query:!X = X;
+//invokeWithLayer4#dea0d430 query:!X = X;
+//invokeWithLayer5#417a57ae query:!X = X;
+//invokeWithLayer6#3a64d54d query:!X = X;
+//invokeWithLayer7#a5be56d3 query:!X = X;
+//invokeWithLayer8#e9abd9fd query:!X = X;
+//invokeWithLayer9#76715a63 query:!X = X;
+//invokeWithLayer10#39620c41 query:!X = X;
+//invokeWithLayer11#a6b88fdf query:!X = X;
+//invokeWithLayer12#dda60d3c query:!X = X;
+//invokeWithLayer13#427c8ea2 query:!X = X;
+//invokeWithLayer14#2b9b08fa query:!X = X;
+//invokeWithLayer15#b4418b64 query:!X = X;
+//invokeWithLayer16#cf5f0987 query:!X = X;
+//invokeWithLayer17#50858a19 query:!X = X;
+//invokeWithLayer18#1c900537 query:!X = X;
+//invokeWithLayer#da9b0d0d layer:int query:!X = X; // after 18 layer
+
+///////////////////////////////
+///////// Main application API
+///////////////////////////////
+
+boolFalse#bc799737 = Bool;
+boolTrue#997275b5 = Bool;
+
+true#3fedd339 = True;
+
+vector#1cb5c415 {t:Type} # [ t ] = Vector t;
+
+error#c4b9f9bb code:int text:string = Error;
+
+null#56730bcc = Null;
+
+inputPeerEmpty#7f3b18ea = InputPeer;
+inputPeerSelf#7da07ec9 = InputPeer;
+inputPeerChat#179be863 chat_id:int = InputPeer;
+inputPeerUser#7b8e7de6 user_id:int access_hash:long = InputPeer;
+inputPeerChannel#20adaef8 channel_id:int access_hash:long = InputPeer;
+inputPeerUserFromMessage#17bae2e6 peer:InputPeer msg_id:int user_id:int = InputPeer;
+inputPeerChannelFromMessage#9c95f7bb peer:InputPeer msg_id:int channel_id:int = InputPeer;
+
+inputUserEmpty#b98886cf = InputUser;
+inputUserSelf#f7c1b13f = InputUser;
+inputUser#d8292816 user_id:int access_hash:long = InputUser;
+inputUserFromMessage#2d117597 peer:InputPeer msg_id:int user_id:int = InputUser;
+
+inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact;
+
+inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile;
+inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile;
+
+inputMediaEmpty#9664f57f = InputMedia;
+inputMediaUploadedPhoto#1e287d04 flags:# file:InputFile stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int = InputMedia;
+inputMediaPhoto#b3ba0635 flags:# id:InputPhoto ttl_seconds:flags.0?int = InputMedia;
+inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia;
+inputMediaContact#f8ab7dfb phone_number:string first_name:string last_name:string vcard:string = InputMedia;
+inputMediaUploadedDocument#5b38c6c1 flags:# nosound_video:flags.3?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector<DocumentAttribute> stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int = InputMedia;
+inputMediaDocument#23ab23d2 flags:# id:InputDocument ttl_seconds:flags.0?int = InputMedia;
+inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia;
+inputMediaGifExternal#4843b0fd url:string q:string = InputMedia;
+inputMediaPhotoExternal#e5bbfe1a flags:# url:string ttl_seconds:flags.0?int = InputMedia;
+inputMediaDocumentExternal#fb52dc99 flags:# url:string ttl_seconds:flags.0?int = InputMedia;
+inputMediaGame#d33f43f3 id:InputGame = InputMedia;
+inputMediaInvoice#f4e096c3 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:string = InputMedia;
+inputMediaGeoLive#ce4e82fd flags:# stopped:flags.0?true geo_point:InputGeoPoint period:flags.1?int = InputMedia;
+inputMediaPoll#f94e5f1 flags:# poll:Poll correct_answers:flags.0?Vector<bytes> solution:flags.1?string solution_entities:flags.1?Vector<MessageEntity> = InputMedia;
+inputMediaDice#e66fbf7b emoticon:string = InputMedia;
+
+inputChatPhotoEmpty#1ca48f57 = InputChatPhoto;
+inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto;
+inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto;
+
+inputGeoPointEmpty#e4c123d6 = InputGeoPoint;
+inputGeoPoint#f3b7acc9 lat:double long:double = InputGeoPoint;
+
+inputPhotoEmpty#1cd7bf0d = InputPhoto;
+inputPhoto#3bb3b94a id:long access_hash:long file_reference:bytes = InputPhoto;
+
+inputFileLocation#dfdaabe1 volume_id:long local_id:int secret:long file_reference:bytes = InputFileLocation;
+inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation;
+inputDocumentFileLocation#bad07584 id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation;
+inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation;
+inputTakeoutFileLocation#29be5899 = InputFileLocation;
+inputPhotoFileLocation#40181ffe id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation;
+inputPhotoLegacyFileLocation#d83466f3 id:long access_hash:long file_reference:bytes volume_id:long local_id:int secret:long = InputFileLocation;
+inputPeerPhotoFileLocation#27d69997 flags:# big:flags.0?true peer:InputPeer volume_id:long local_id:int = InputFileLocation;
+inputStickerSetThumb#dbaeae9 stickerset:InputStickerSet volume_id:long local_id:int = InputFileLocation;
+
+peerUser#9db1bc6d user_id:int = Peer;
+peerChat#bad0e5bb chat_id:int = Peer;
+peerChannel#bddde532 channel_id:int = Peer;
+
+storage.fileUnknown#aa963b05 = storage.FileType;
+storage.filePartial#40bc6f52 = storage.FileType;
+storage.fileJpeg#7efe0e = storage.FileType;
+storage.fileGif#cae1aadf = storage.FileType;
+storage.filePng#a4f63c0 = storage.FileType;
+storage.filePdf#ae1e508d = storage.FileType;
+storage.fileMp3#528a0677 = storage.FileType;
+storage.fileMov#4b09ebbc = storage.FileType;
+storage.fileMp4#b3cea0e4 = storage.FileType;
+storage.fileWebp#1081464c = storage.FileType;
+
+userEmpty#200250ba id:int = User;
+user#938458c1 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector<RestrictionReason> bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User;
+
+userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto;
+userProfilePhoto#ecd75d8c photo_id:long photo_small:FileLocation photo_big:FileLocation dc_id:int = UserProfilePhoto;
+
+userStatusEmpty#9d05049 = UserStatus;
+userStatusOnline#edb93949 expires:int = UserStatus;
+userStatusOffline#8c703f was_online:int = UserStatus;
+userStatusRecently#e26f42f1 = UserStatus;
+userStatusLastWeek#7bf09fc = UserStatus;
+userStatusLastMonth#77ebc742 = UserStatus;
+
+chatEmpty#9ba2d800 id:int = Chat;
+chat#3bda1bde flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat;
+chatForbidden#7328bdb id:int title:string = Chat;
+channel#d31a961e flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?Vector<RestrictionReason> admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = Chat;
+channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat;
+
+chatFull#1b7c9db3 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true id:int about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int folder_id:flags.11?int = ChatFull;
+channelFull#f0e6672a flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_view_stats:flags.12?true can_set_location:flags.16?true has_scheduled:flags.19?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?int location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int = ChatFull;
+
+chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant;
+chatParticipantCreator#da13538a user_id:int = ChatParticipant;
+chatParticipantAdmin#e2d6e436 user_id:int inviter_id:int date:int = ChatParticipant;
+
+chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0?ChatParticipant = ChatParticipants;
+chatParticipants#3f460fed chat_id:int participants:Vector<ChatParticipant> version:int = ChatParticipants;
+
+chatPhotoEmpty#37c1011c = ChatPhoto;
+chatPhoto#475cdbd5 photo_small:FileLocation photo_big:FileLocation dc_id:int = ChatPhoto;
+
+messageEmpty#83e5de54 id:int = Message;
+message#452c0e65 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long restriction_reason:flags.22?Vector<RestrictionReason> = Message;
+messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message;
+
+messageMediaEmpty#3ded6320 = MessageMedia;
+messageMediaPhoto#695150d7 flags:# photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia;
+messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia;
+messageMediaContact#cbf24940 phone_number:string first_name:string last_name:string vcard:string user_id:int = MessageMedia;
+messageMediaUnsupported#9f84f49e = MessageMedia;
+messageMediaDocument#9cb070d7 flags:# document:flags.0?Document ttl_seconds:flags.2?int = MessageMedia;
+messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia;
+messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia;
+messageMediaGame#fdb19008 game:Game = MessageMedia;
+messageMediaInvoice#84551347 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string = MessageMedia;
+messageMediaGeoLive#7c3c2609 geo:GeoPoint period:int = MessageMedia;
+messageMediaPoll#4bd6e798 poll:Poll results:PollResults = MessageMedia;
+messageMediaDice#3f7ee58b value:int emoticon:string = MessageMedia;
+
+messageActionEmpty#b6aef7b0 = MessageAction;
+messageActionChatCreate#a6638b9a title:string users:Vector<int> = MessageAction;
+messageActionChatEditTitle#b5a1ce5a title:string = MessageAction;
+messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction;
+messageActionChatDeletePhoto#95e3fbef = MessageAction;
+messageActionChatAddUser#488a7337 users:Vector<int> = MessageAction;
+messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction;
+messageActionChatJoinedByLink#f89cf5e8 inviter_id:int = MessageAction;
+messageActionChannelCreate#95d2ac92 title:string = MessageAction;
+messageActionChatMigrateTo#51bdb021 channel_id:int = MessageAction;
+messageActionChannelMigrateFrom#b055eaee title:string chat_id:int = MessageAction;
+messageActionPinMessage#94bd38ed = MessageAction;
+messageActionHistoryClear#9fbab604 = MessageAction;
+messageActionGameScore#92a72876 game_id:long score:int = MessageAction;
+messageActionPaymentSentMe#8f31b327 flags:# currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge = MessageAction;
+messageActionPaymentSent#40699cd0 currency:string total_amount:long = MessageAction;
+messageActionPhoneCall#80e11a7f flags:# video:flags.2?true call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction;
+messageActionScreenshotTaken#4792929b = MessageAction;
+messageActionCustomAction#fae69f56 message:string = MessageAction;
+messageActionBotAllowed#abe9affe domain:string = MessageAction;
+messageActionSecureValuesSentMe#1b287353 values:Vector<SecureValue> credentials:SecureCredentialsEncrypted = MessageAction;
+messageActionSecureValuesSent#d95c6154 types:Vector<SecureValueType> = MessageAction;
+messageActionContactSignUp#f3f25f76 = MessageAction;
+
+dialog#2c171f72 flags:# pinned:flags.2?true unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int = Dialog;
+dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog;
+
+photoEmpty#2331b22d id:long = Photo;
+photo#d07504a5 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector<PhotoSize> dc_id:int = Photo;
+
+photoSizeEmpty#e17e23c type:string = PhotoSize;
+photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize;
+photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize;
+photoStrippedSize#e0b0bc2e type:string bytes:bytes = PhotoSize;
+
+geoPointEmpty#1117dd5f = GeoPoint;
+geoPoint#296f104 long:double lat:double access_hash:long = GeoPoint;
+
+auth.sentCode#5e002502 flags:# type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode;
+
+auth.authorization#cd050916 flags:# tmp_sessions:flags.0?int user:User = auth.Authorization;
+auth.authorizationSignUpRequired#44747e9a flags:# terms_of_service:flags.0?help.TermsOfService = auth.Authorization;
+
+auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization;
+
+inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer;
+inputNotifyUsers#193b4417 = InputNotifyPeer;
+inputNotifyChats#4a95e84e = InputNotifyPeer;
+inputNotifyBroadcasts#b1db7c7e = InputNotifyPeer;
+
+inputPeerNotifySettings#9c3d198e flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = InputPeerNotifySettings;
+
+peerNotifySettings#af509d20 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = PeerNotifySettings;
+
+peerSettings#818426cd flags:# report_spam:flags.0?true add_contact:flags.1?true block_contact:flags.2?true share_contact:flags.3?true need_contacts_exception:flags.4?true report_geo:flags.5?true = PeerSettings;
+
+wallPaper#a437c3ed id:long flags:# creator:flags.0?true default:flags.1?true pattern:flags.3?true dark:flags.4?true access_hash:long slug:string document:Document settings:flags.2?WallPaperSettings = WallPaper;
+wallPaperNoFile#8af40b25 flags:# default:flags.1?true dark:flags.4?true settings:flags.2?WallPaperSettings = WallPaper;
+
+inputReportReasonSpam#58dbcab8 = ReportReason;
+inputReportReasonViolence#1e22c78d = ReportReason;
+inputReportReasonPornography#2e59d922 = ReportReason;
+inputReportReasonChildAbuse#adf44ee3 = ReportReason;
+inputReportReasonOther#e1746d0a text:string = ReportReason;
+inputReportReasonCopyright#9b89f93a = ReportReason;
+inputReportReasonGeoIrrelevant#dbd4feed = ReportReason;
+
+userFull#edf17c12 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true user:User about:flags.1?string settings:PeerSettings profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int = UserFull;
+
+contact#f911c994 user_id:int mutual:Bool = Contact;
+
+importedContact#d0028438 user_id:int client_id:long = ImportedContact;
+
+contactBlocked#561bc879 user_id:int date:int = ContactBlocked;
+
+contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus;
+
+contacts.contactsNotModified#b74ba9d2 = contacts.Contacts;
+contacts.contacts#eae87e42 contacts:Vector<Contact> saved_count:int users:Vector<User> = contacts.Contacts;
+
+contacts.importedContacts#77d01c3b imported:Vector<ImportedContact> popular_invites:Vector<PopularContact> retry_contacts:Vector<long> users:Vector<User> = contacts.ImportedContacts;
+
+contacts.blocked#1c138d15 blocked:Vector<ContactBlocked> users:Vector<User> = contacts.Blocked;
+contacts.blockedSlice#900802a1 count:int blocked:Vector<ContactBlocked> users:Vector<User> = contacts.Blocked;
+
+messages.dialogs#15ba6c40 dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs;
+messages.dialogsSlice#71e094f3 count:int dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs;
+messages.dialogsNotModified#f0e3e596 count:int = messages.Dialogs;
+
+messages.messages#8c718e87 messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
+messages.messagesSlice#c8edce1e flags:# inexact:flags.1?true count:int next_rate:flags.0?int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
+messages.channelMessages#99262e37 flags:# inexact:flags.1?true pts:int count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
+messages.messagesNotModified#74535f21 count:int = messages.Messages;
+
+messages.chats#64ff9fd5 chats:Vector<Chat> = messages.Chats;
+messages.chatsSlice#9cd81144 count:int chats:Vector<Chat> = messages.Chats;
+
+messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector<Chat> users:Vector<User> = messages.ChatFull;
+
+messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory;
+
+inputMessagesFilterEmpty#57e2f66c = MessagesFilter;
+inputMessagesFilterPhotos#9609a51c = MessagesFilter;
+inputMessagesFilterVideo#9fc00e65 = MessagesFilter;
+inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter;
+inputMessagesFilterDocument#9eddf188 = MessagesFilter;
+inputMessagesFilterUrl#7ef0dd87 = MessagesFilter;
+inputMessagesFilterGif#ffc86587 = MessagesFilter;
+inputMessagesFilterVoice#50f5c392 = MessagesFilter;
+inputMessagesFilterMusic#3751b49e = MessagesFilter;
+inputMessagesFilterChatPhotos#3a20ecb8 = MessagesFilter;
+inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFilter;
+inputMessagesFilterRoundVoice#7a7c17a4 = MessagesFilter;
+inputMessagesFilterRoundVideo#b549da53 = MessagesFilter;
+inputMessagesFilterMyMentions#c1f8e69a = MessagesFilter;
+inputMessagesFilterGeo#e7026d0d = MessagesFilter;
+inputMessagesFilterContacts#e062db83 = MessagesFilter;
+
+updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update;
+updateMessageID#4e90bfd6 id:int random_id:long = Update;
+updateDeleteMessages#a20db0e5 messages:Vector<int> pts:int pts_count:int = Update;
+updateUserTyping#5c486927 user_id:int action:SendMessageAction = Update;
+updateChatUserTyping#9a65ea1f chat_id:int user_id:int action:SendMessageAction = Update;
+updateChatParticipants#7761198 participants:ChatParticipants = Update;
+updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update;
+updateUserName#a7332b73 user_id:int first_name:string last_name:string username:string = Update;
+updateUserPhoto#95313b0c user_id:int date:int photo:UserProfilePhoto previous:Bool = Update;
+updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update;
+updateEncryptedChatTyping#1710f156 chat_id:int = Update;
+updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update;
+updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update;
+updateChatParticipantAdd#ea4b0e5c chat_id:int user_id:int inviter_id:int date:int version:int = Update;
+updateChatParticipantDelete#6e5f8c22 chat_id:int user_id:int version:int = Update;
+updateDcOptions#8e5e9873 dc_options:Vector<DcOption> = Update;
+updateUserBlocked#80ece81a user_id:int blocked:Bool = Update;
+updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update;
+updateServiceNotification#ebe46819 flags:# popup:flags.0?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector<MessageEntity> = Update;
+updatePrivacy#ee3b272a key:PrivacyKey rules:Vector<PrivacyRule> = Update;
+updateUserPhone#12b9417b user_id:int phone:string = Update;
+updateReadHistoryInbox#9c974fdf flags:# folder_id:flags.0?int peer:Peer max_id:int still_unread_count:int pts:int pts_count:int = Update;
+updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update;
+updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update;
+updateReadMessagesContents#68c13933 messages:Vector<int> pts:int pts_count:int = Update;
+updateChannelTooLong#eb0467fb flags:# channel_id:int pts:flags.0?int = Update;
+updateChannel#b6d45656 channel_id:int = Update;
+updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update;
+updateReadChannelInbox#330b5424 flags:# folder_id:flags.0?int channel_id:int max_id:int still_unread_count:int pts:int = Update;
+updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector<int> pts:int pts_count:int = Update;
+updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update;
+updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update;
+updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update;
+updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true order:Vector<long> = Update;
+updateStickerSets#43ae3dec = Update;
+updateSavedGifs#9375341e = Update;
+updateBotInlineQuery#54826690 flags:# query_id:long user_id:int query:string geo:flags.0?GeoPoint offset:string = Update;
+updateBotInlineSend#e48f964 flags:# user_id:int query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update;
+updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update;
+updateChannelPinnedMessage#98592475 channel_id:int id:int = Update;
+updateBotCallbackQuery#e73547e1 flags:# query_id:long user_id:int peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update;
+updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update;
+updateInlineBotCallbackQuery#f9d27a5a flags:# query_id:long user_id:int msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update;
+updateReadChannelOutbox#25d6c9c7 channel_id:int max_id:int = Update;
+updateDraftMessage#ee2bb969 peer:Peer draft:DraftMessage = Update;
+updateReadFeaturedStickers#571d2742 = Update;
+updateRecentStickers#9a422c20 = Update;
+updateConfig#a229dd06 = Update;
+updatePtsChanged#3354678f = Update;
+updateChannelWebPage#40771900 channel_id:int webpage:WebPage pts:int pts_count:int = Update;
+updateDialogPinned#6e6fe51c flags:# pinned:flags.0?true folder_id:flags.1?int peer:DialogPeer = Update;
+updatePinnedDialogs#fa0f3ca2 flags:# folder_id:flags.1?int order:flags.0?Vector<DialogPeer> = Update;
+updateBotWebhookJSON#8317c0c3 data:DataJSON = Update;
+updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update;
+updateBotShippingQuery#e0cdc940 query_id:long user_id:int payload:bytes shipping_address:PostAddress = Update;
+updateBotPrecheckoutQuery#5d2f3aa9 flags:# query_id:long user_id:int payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string currency:string total_amount:long = Update;
+updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update;
+updateLangPackTooLong#46560264 lang_code:string = Update;
+updateLangPack#56022f4d difference:LangPackDifference = Update;
+updateFavedStickers#e511996d = Update;
+updateChannelReadMessagesContents#89893b45 channel_id:int messages:Vector<int> = Update;
+updateContactsReset#7084a7be = Update;
+updateChannelAvailableMessages#70db6837 channel_id:int available_min_id:int = Update;
+updateDialogUnreadMark#e16459c3 flags:# unread:flags.0?true peer:DialogPeer = Update;
+updateUserPinnedMessage#4c43da18 user_id:int id:int = Update;
+updateChatPinnedMessage#e10db349 chat_id:int id:int version:int = Update;
+updateMessagePoll#aca1657b flags:# poll_id:long poll:flags.0?Poll results:PollResults = Update;
+updateChatDefaultBannedRights#54c01850 peer:Peer default_banned_rights:ChatBannedRights version:int = Update;
+updateFolderPeers#19360dc0 folder_peers:Vector<FolderPeer> pts:int pts_count:int = Update;
+updatePeerSettings#6a7e7366 peer:Peer settings:PeerSettings = Update;
+updatePeerLocated#b4afcfb0 peers:Vector<PeerLocated> = Update;
+updateNewScheduledMessage#39a51dfb message:Message = Update;
+updateDeleteScheduledMessages#90866cee peer:Peer messages:Vector<int> = Update;
+updateTheme#8216fba3 theme:Theme = Update;
+updateGeoLiveViewed#871fb939 peer:Peer msg_id:int = Update;
+updateLoginToken#564fe691 = Update;
+updateMessagePollVote#42f88f2c poll_id:long user_id:int options:Vector<bytes> = Update;
+updateDialogFilter#26ffde7d flags:# id:int filter:flags.0?DialogFilter = Update;
+updateDialogFilterOrder#a5d72105 order:Vector<int> = Update;
+updateDialogFilters#3504914f = Update;
+
+updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
+
+updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference;
+updates.difference#f49ca0 new_messages:Vector<Message> new_encrypted_messages:Vector<EncryptedMessage> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> state:updates.State = updates.Difference;
+updates.differenceSlice#a8fb1981 new_messages:Vector<Message> new_encrypted_messages:Vector<EncryptedMessage> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> intermediate_state:updates.State = updates.Difference;
+updates.differenceTooLong#4afe8f6d pts:int = updates.Difference;
+
+updatesTooLong#e317af7e = Updates;
+updateShortMessage#914fbf11 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector<MessageEntity> = Updates;
+updateShortChatMessage#16812688 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector<MessageEntity> = Updates;
+updateShort#78d4dec1 update:Update date:int = Updates;
+updatesCombined#725b04c3 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq_start:int seq:int = Updates;
+updates#74ae4240 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq:int = Updates;
+updateShortSentMessage#11f1331c flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector<MessageEntity> = Updates;
+
+photos.photos#8dca6aa5 photos:Vector<Photo> users:Vector<User> = photos.Photos;
+photos.photosSlice#15051f54 count:int photos:Vector<Photo> users:Vector<User> = photos.Photos;
+
+photos.photo#20212ca8 photo:Photo users:Vector<User> = photos.Photo;
+
+upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File;
+upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes file_hashes:Vector<FileHash> = upload.File;
+
+dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption;
+
+config#330b4067 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true pfs_enabled:flags.13?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int pinned_infolder_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int = Config;
+
+nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc;
+
+help.appUpdate#1da7158f flags:# can_not_skip:flags.0?true id:int version:string text:string entities:Vector<MessageEntity> document:flags.1?Document url:flags.2?string = help.AppUpdate;
+help.noAppUpdate#c45a6536 = help.AppUpdate;
+
+help.inviteText#18cb9f78 message:string = help.InviteText;
+
+encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat;
+encryptedChatWaiting#3bf703dc id:int access_hash:long date:int admin_id:int participant_id:int = EncryptedChat;
+encryptedChatRequested#c878527e id:int access_hash:long date:int admin_id:int participant_id:int g_a:bytes = EncryptedChat;
+encryptedChat#fa56ce36 id:int access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long = EncryptedChat;
+encryptedChatDiscarded#13d6dd27 id:int = EncryptedChat;
+
+inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat;
+
+encryptedFileEmpty#c21f497e = EncryptedFile;
+encryptedFile#4a70994c id:long access_hash:long size:int dc_id:int key_fingerprint:int = EncryptedFile;
+
+inputEncryptedFileEmpty#1837c364 = InputEncryptedFile;
+inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile;
+inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile;
+inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile;
+
+encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage;
+encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage;
+
+messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig;
+messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig;
+
+messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage;
+messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage;
+
+inputDocumentEmpty#72f0eaae = InputDocument;
+inputDocument#1abfb575 id:long access_hash:long file_reference:bytes = InputDocument;
+
+documentEmpty#36f8c871 id:long = Document;
+document#9ba29cc1 flags:# id:long access_hash:long file_reference:bytes date:int mime_type:string size:int thumbs:flags.0?Vector<PhotoSize> dc_id:int attributes:Vector<DocumentAttribute> = Document;
+
+help.support#17c6b5f6 phone_number:string user:User = help.Support;
+
+notifyPeer#9fd40bd8 peer:Peer = NotifyPeer;
+notifyUsers#b4c83b4c = NotifyPeer;
+notifyChats#c007cec3 = NotifyPeer;
+notifyBroadcasts#d612e8ef = NotifyPeer;
+
+sendMessageTypingAction#16bf744e = SendMessageAction;
+sendMessageCancelAction#fd5ec8f5 = SendMessageAction;
+sendMessageRecordVideoAction#a187d66f = SendMessageAction;
+sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction;
+sendMessageRecordAudioAction#d52f73f7 = SendMessageAction;
+sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction;
+sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction;
+sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction;
+sendMessageGeoLocationAction#176f8ba1 = SendMessageAction;
+sendMessageChooseContactAction#628cbc6f = SendMessageAction;
+sendMessageGamePlayAction#dd6a8f48 = SendMessageAction;
+sendMessageRecordRoundAction#88f27fbc = SendMessageAction;
+sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction;
+
+contacts.found#b3134d9d my_results:Vector<Peer> results:Vector<Peer> chats:Vector<Chat> users:Vector<User> = contacts.Found;
+
+inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey;
+inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey;
+inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey;
+inputPrivacyKeyPhoneP2P#db9e70d2 = InputPrivacyKey;
+inputPrivacyKeyForwards#a4dd4c08 = InputPrivacyKey;
+inputPrivacyKeyProfilePhoto#5719bacc = InputPrivacyKey;
+inputPrivacyKeyPhoneNumber#352dafa = InputPrivacyKey;
+inputPrivacyKeyAddedByPhone#d1219bdd = InputPrivacyKey;
+
+privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey;
+privacyKeyChatInvite#500e6dfa = PrivacyKey;
+privacyKeyPhoneCall#3d662b7b = PrivacyKey;
+privacyKeyPhoneP2P#39491cc8 = PrivacyKey;
+privacyKeyForwards#69ec56a3 = PrivacyKey;
+privacyKeyProfilePhoto#96151fed = PrivacyKey;
+privacyKeyPhoneNumber#d19ae46d = PrivacyKey;
+privacyKeyAddedByPhone#42ffd42b = PrivacyKey;
+
+inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule;
+inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule;
+inputPrivacyValueAllowUsers#131cc67f users:Vector<InputUser> = InputPrivacyRule;
+inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule;
+inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule;
+inputPrivacyValueDisallowUsers#90110467 users:Vector<InputUser> = InputPrivacyRule;
+inputPrivacyValueAllowChatParticipants#4c81c1ba chats:Vector<int> = InputPrivacyRule;
+inputPrivacyValueDisallowChatParticipants#d82363af chats:Vector<int> = InputPrivacyRule;
+
+privacyValueAllowContacts#fffe1bac = PrivacyRule;
+privacyValueAllowAll#65427b82 = PrivacyRule;
+privacyValueAllowUsers#4d5bbe0c users:Vector<int> = PrivacyRule;
+privacyValueDisallowContacts#f888fa1a = PrivacyRule;
+privacyValueDisallowAll#8b73e763 = PrivacyRule;
+privacyValueDisallowUsers#c7f49b7 users:Vector<int> = PrivacyRule;
+privacyValueAllowChatParticipants#18be796b chats:Vector<int> = PrivacyRule;
+privacyValueDisallowChatParticipants#acae0690 chats:Vector<int> = PrivacyRule;
+
+account.privacyRules#50a04e45 rules:Vector<PrivacyRule> chats:Vector<Chat> users:Vector<User> = account.PrivacyRules;
+
+accountDaysTTL#b8d0afdf days:int = AccountDaysTTL;
+
+documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute;
+documentAttributeAnimated#11b58939 = DocumentAttribute;
+documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute;
+documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true supports_streaming:flags.1?true duration:int w:int h:int = DocumentAttribute;
+documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute;
+documentAttributeFilename#15590068 file_name:string = DocumentAttribute;
+documentAttributeHasStickers#9801d2f7 = DocumentAttribute;
+
+messages.stickersNotModified#f1749a22 = messages.Stickers;
+messages.stickers#e4599bbd hash:int stickers:Vector<Document> = messages.Stickers;
+
+stickerPack#12b299d4 emoticon:string documents:Vector<long> = StickerPack;
+
+messages.allStickersNotModified#e86602c3 = messages.AllStickers;
+messages.allStickers#edfd405f hash:int sets:Vector<StickerSet> = messages.AllStickers;
+
+messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages;
+
+webPageEmpty#eb1477e8 id:long = WebPage;
+webPagePending#c586da1c id:long date:int = WebPage;
+webPage#e89c45b2 flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page attributes:flags.12?Vector<WebPageAttribute> = WebPage;
+webPageNotModified#7311ca11 flags:# cached_page_views:flags.0?int = WebPage;
+
+authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true password_pending:flags.2?true hash:long device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization;
+
+account.authorizations#1250abde authorizations:Vector<Authorization> = account.Authorizations;
+
+account.password#ad2641f8 flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes = account.Password;
+
+account.passwordSettings#9a5c33e5 flags:# email:flags.0?string secure_settings:flags.1?SecureSecretSettings = account.PasswordSettings;
+
+account.passwordInputSettings#c23727c9 flags:# new_algo:flags.0?PasswordKdfAlgo new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string new_secure_settings:flags.2?SecureSecretSettings = account.PasswordInputSettings;
+
+auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery;
+
+receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage;
+
+chatInviteEmpty#69df3769 = ExportedChatInvite;
+chatInviteExported#fc2e05bc link:string = ExportedChatInvite;
+
+chatInviteAlready#5a686d7c chat:Chat = ChatInvite;
+chatInvite#dfc2f58e flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:Photo participants_count:int participants:flags.4?Vector<User> = ChatInvite;
+
+inputStickerSetEmpty#ffb62b95 = InputStickerSet;
+inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet;
+inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet;
+inputStickerSetAnimatedEmoji#28703c8 = InputStickerSet;
+inputStickerSetDice#e67f520e emoticon:string = InputStickerSet;
+
+stickerSet#eeb46f27 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumb:flags.4?PhotoSize thumb_dc_id:flags.4?int count:int hash:int = StickerSet;
+
+messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet;
+
+botCommand#c27ac8c7 command:string description:string = BotCommand;
+
+botInfo#98e81d3a user_id:int description:string commands:Vector<BotCommand> = BotInfo;
+
+keyboardButton#a2fa4880 text:string = KeyboardButton;
+keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton;
+keyboardButtonCallback#683a5e46 text:string data:bytes = KeyboardButton;
+keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton;
+keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton;
+keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton;
+keyboardButtonGame#50f41ccf text:string = KeyboardButton;
+keyboardButtonBuy#afd93fbb text:string = KeyboardButton;
+keyboardButtonUrlAuth#10b78d29 flags:# text:string fwd_text:flags.0?string url:string button_id:int = KeyboardButton;
+inputKeyboardButtonUrlAuth#d02e7fd4 flags:# request_write_access:flags.0?true text:string fwd_text:flags.1?string url:string bot:InputUser = KeyboardButton;
+keyboardButtonRequestPoll#bbc7515d flags:# quiz:flags.0?Bool text:string = KeyboardButton;
+
+keyboardButtonRow#77608b83 buttons:Vector<KeyboardButton> = KeyboardButtonRow;
+
+replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup;
+replyKeyboardForceReply#f4108aa0 flags:# single_use:flags.1?true selective:flags.2?true = ReplyMarkup;
+replyKeyboardMarkup#3502758c flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector<KeyboardButtonRow> = ReplyMarkup;
+replyInlineMarkup#48a30254 rows:Vector<KeyboardButtonRow> = ReplyMarkup;
+
+messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity;
+messageEntityMention#fa04579d offset:int length:int = MessageEntity;
+messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity;
+messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity;
+messageEntityUrl#6ed02538 offset:int length:int = MessageEntity;
+messageEntityEmail#64e475c2 offset:int length:int = MessageEntity;
+messageEntityBold#bd610bc9 offset:int length:int = MessageEntity;
+messageEntityItalic#826f8b60 offset:int length:int = MessageEntity;
+messageEntityCode#28a20571 offset:int length:int = MessageEntity;
+messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity;
+messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity;
+messageEntityMentionName#352dca58 offset:int length:int user_id:int = MessageEntity;
+inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity;
+messageEntityPhone#9b69e34b offset:int length:int = MessageEntity;
+messageEntityCashtag#4c4e743f offset:int length:int = MessageEntity;
+messageEntityUnderline#9c4e7e8b offset:int length:int = MessageEntity;
+messageEntityStrike#bf0693d4 offset:int length:int = MessageEntity;
+messageEntityBlockquote#20df5d0 offset:int length:int = MessageEntity;
+messageEntityBankCard#761e6af4 offset:int length:int = MessageEntity;
+
+inputChannelEmpty#ee8c1e86 = InputChannel;
+inputChannel#afeb712e channel_id:int access_hash:long = InputChannel;
+inputChannelFromMessage#2a286531 peer:InputPeer msg_id:int channel_id:int = InputChannel;
+
+contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector<Chat> users:Vector<User> = contacts.ResolvedPeer;
+
+messageRange#ae30253 min_id:int max_id:int = MessageRange;
+
+updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference;
+updates.channelDifferenceTooLong#a4bcc6fe flags:# final:flags.0?true timeout:flags.1?int dialog:Dialog messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = updates.ChannelDifference;
+updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector<Message> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> = updates.ChannelDifference;
+
+channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter;
+channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector<MessageRange> = ChannelMessagesFilter;
+
+channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant;
+channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant;
+channelParticipantCreator#808d15a4 flags:# user_id:int rank:flags.0?string = ChannelParticipant;
+channelParticipantAdmin#ccbebbaf flags:# can_edit:flags.0?true self:flags.1?true user_id:int inviter_id:flags.1?int promoted_by:int date:int admin_rights:ChatAdminRights rank:flags.2?string = ChannelParticipant;
+channelParticipantBanned#1c0facaf flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChatBannedRights = ChannelParticipant;
+
+channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter;
+channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter;
+channelParticipantsKicked#a3b54985 q:string = ChannelParticipantsFilter;
+channelParticipantsBots#b0d1865b = ChannelParticipantsFilter;
+channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter;
+channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter;
+channelParticipantsContacts#bb6ae88d q:string = ChannelParticipantsFilter;
+
+channels.channelParticipants#f56ee2a8 count:int participants:Vector<ChannelParticipant> users:Vector<User> = channels.ChannelParticipants;
+channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants;
+
+channels.channelParticipant#d0d9b163 participant:ChannelParticipant users:Vector<User> = channels.ChannelParticipant;
+
+help.termsOfService#780a0310 flags:# popup:flags.0?true id:DataJSON text:string entities:Vector<MessageEntity> min_age_confirm:flags.1?int = help.TermsOfService;
+
+foundGif#162ecc1f url:string thumb_url:string content_url:string content_type:string w:int h:int = FoundGif;
+foundGifCached#9c750409 url:string photo:Photo document:Document = FoundGif;
+
+messages.foundGifs#450a1c0a next_offset:int results:Vector<FoundGif> = messages.FoundGifs;
+
+messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs;
+messages.savedGifs#2e0709a5 hash:int gifs:Vector<Document> = messages.SavedGifs;
+
+inputBotInlineMessageMediaAuto#3380c786 flags:# message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
+inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
+inputBotInlineMessageMediaGeo#c1b15d65 flags:# geo_point:InputGeoPoint period:int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
+inputBotInlineMessageMediaVenue#417bbf11 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
+inputBotInlineMessageMediaContact#a6edbffd flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
+inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
+
+inputBotInlineResult#88bf9319 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?InputWebDocument content:flags.5?InputWebDocument send_message:InputBotInlineMessage = InputBotInlineResult;
+inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult;
+inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult;
+inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult;
+
+botInlineMessageMediaAuto#764cf810 flags:# message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
+botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
+botInlineMessageMediaGeo#b722de65 flags:# geo:GeoPoint period:int reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
+botInlineMessageMediaVenue#8a86659c flags:# geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
+botInlineMessageMediaContact#18d1cdc2 flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
+
+botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult;
+botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult;
+
+messages.botResults#947ca848 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM results:Vector<BotInlineResult> cache_time:int users:Vector<User> = messages.BotResults;
+
+exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink;
+
+messageFwdHeader#ec338270 flags:# from_id:flags.0?int from_name:flags.5?string date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int = MessageFwdHeader;
+
+auth.codeTypeSms#72a3158c = auth.CodeType;
+auth.codeTypeCall#741cd3e3 = auth.CodeType;
+auth.codeTypeFlashCall#226ccefb = auth.CodeType;
+
+auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType;
+auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType;
+auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType;
+auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType;
+
+messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true native_ui:flags.4?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer;
+
+messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData;
+
+inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID;
+
+inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM;
+
+messages.peerDialogs#3371c354 dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> state:updates.State = messages.PeerDialogs;
+
+topPeer#edcdc05b peer:Peer rating:double = TopPeer;
+
+topPeerCategoryBotsPM#ab661b5b = TopPeerCategory;
+topPeerCategoryBotsInline#148677e2 = TopPeerCategory;
+topPeerCategoryCorrespondents#637b7ed = TopPeerCategory;
+topPeerCategoryGroups#bd17a14a = TopPeerCategory;
+topPeerCategoryChannels#161d9628 = TopPeerCategory;
+topPeerCategoryPhoneCalls#1e76a78c = TopPeerCategory;
+topPeerCategoryForwardUsers#a8406ca9 = TopPeerCategory;
+topPeerCategoryForwardChats#fbeec0f0 = TopPeerCategory;
+
+topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector<TopPeer> = TopPeerCategoryPeers;
+
+contacts.topPeersNotModified#de266ef5 = contacts.TopPeers;
+contacts.topPeers#70b772a8 categories:Vector<TopPeerCategoryPeers> chats:Vector<Chat> users:Vector<User> = contacts.TopPeers;
+contacts.topPeersDisabled#b52c939d = contacts.TopPeers;
+
+draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage;
+draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector<MessageEntity> date:int = DraftMessage;
+
+messages.featuredStickersNotModified#c6dc0c66 count:int = messages.FeaturedStickers;
+messages.featuredStickers#b6abc341 hash:int count:int sets:Vector<StickerSetCovered> unread:Vector<long> = messages.FeaturedStickers;
+
+messages.recentStickersNotModified#b17f890 = messages.RecentStickers;
+messages.recentStickers#22f3afb3 hash:int packs:Vector<StickerPack> stickers:Vector<Document> dates:Vector<int> = messages.RecentStickers;
+
+messages.archivedStickers#4fcba9c8 count:int sets:Vector<StickerSetCovered> = messages.ArchivedStickers;
+
+messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult;
+messages.stickerSetInstallResultArchive#35e410a8 sets:Vector<StickerSetCovered> = messages.StickerSetInstallResult;
+
+stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered;
+stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector<Document> = StickerSetCovered;
+
+maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords;
+
+inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia;
+inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia;
+
+game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game;
+
+inputGameID#32c3e77 id:long access_hash:long = InputGame;
+inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame;
+
+highScore#58fffcd0 pos:int user_id:int score:int = HighScore;
+
+messages.highScores#9a3bfd99 scores:Vector<HighScore> users:Vector<User> = messages.HighScores;
+
+textEmpty#dc3d824f = RichText;
+textPlain#744694e0 text:string = RichText;
+textBold#6724abc4 text:RichText = RichText;
+textItalic#d912a59c text:RichText = RichText;
+textUnderline#c12622c4 text:RichText = RichText;
+textStrike#9bf8bb95 text:RichText = RichText;
+textFixed#6c3f19b9 text:RichText = RichText;
+textUrl#3c2884c1 text:RichText url:string webpage_id:long = RichText;
+textEmail#de5a0dd6 text:RichText email:string = RichText;
+textConcat#7e6260d7 texts:Vector<RichText> = RichText;
+textSubscript#ed6a8504 text:RichText = RichText;
+textSuperscript#c7fb5e01 text:RichText = RichText;
+textMarked#34b8621 text:RichText = RichText;
+textPhone#1ccb966a text:RichText phone:string = RichText;
+textImage#81ccf4f document_id:long w:int h:int = RichText;
+textAnchor#35553762 text:RichText name:string = RichText;
+
+pageBlockUnsupported#13567e8a = PageBlock;
+pageBlockTitle#70abc3fd text:RichText = PageBlock;
+pageBlockSubtitle#8ffa9a1f text:RichText = PageBlock;
+pageBlockAuthorDate#baafe5e0 author:RichText published_date:int = PageBlock;
+pageBlockHeader#bfd064ec text:RichText = PageBlock;
+pageBlockSubheader#f12bb6e1 text:RichText = PageBlock;
+pageBlockParagraph#467a0766 text:RichText = PageBlock;
+pageBlockPreformatted#c070d93e text:RichText language:string = PageBlock;
+pageBlockFooter#48870999 text:RichText = PageBlock;
+pageBlockDivider#db20b188 = PageBlock;
+pageBlockAnchor#ce0d37b0 name:string = PageBlock;
+pageBlockList#e4e88011 items:Vector<PageListItem> = PageBlock;
+pageBlockBlockquote#263d7c26 text:RichText caption:RichText = PageBlock;
+pageBlockPullquote#4f4456d3 text:RichText caption:RichText = PageBlock;
+pageBlockPhoto#1759c560 flags:# photo_id:long caption:PageCaption url:flags.0?string webpage_id:flags.0?long = PageBlock;
+pageBlockVideo#7c8fe7b6 flags:# autoplay:flags.0?true loop:flags.1?true video_id:long caption:PageCaption = PageBlock;
+pageBlockCover#39f23300 cover:PageBlock = PageBlock;
+pageBlockEmbed#a8718dc5 flags:# full_width:flags.0?true allow_scrolling:flags.3?true url:flags.1?string html:flags.2?string poster_photo_id:flags.4?long w:flags.5?int h:flags.5?int caption:PageCaption = PageBlock;
+pageBlockEmbedPost#f259a80b url:string webpage_id:long author_photo_id:long author:string date:int blocks:Vector<PageBlock> caption:PageCaption = PageBlock;
+pageBlockCollage#65a0fa4d items:Vector<PageBlock> caption:PageCaption = PageBlock;
+pageBlockSlideshow#31f9590 items:Vector<PageBlock> caption:PageCaption = PageBlock;
+pageBlockChannel#ef1751b5 channel:Chat = PageBlock;
+pageBlockAudio#804361ea audio_id:long caption:PageCaption = PageBlock;
+pageBlockKicker#1e148390 text:RichText = PageBlock;
+pageBlockTable#bf4dea82 flags:# bordered:flags.0?true striped:flags.1?true title:RichText rows:Vector<PageTableRow> = PageBlock;
+pageBlockOrderedList#9a8ae1e1 items:Vector<PageListOrderedItem> = PageBlock;
+pageBlockDetails#76768bed flags:# open:flags.0?true blocks:Vector<PageBlock> title:RichText = PageBlock;
+pageBlockRelatedArticles#16115a96 title:RichText articles:Vector<PageRelatedArticle> = PageBlock;
+pageBlockMap#a44f3ef6 geo:GeoPoint zoom:int w:int h:int caption:PageCaption = PageBlock;
+
+phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason;
+phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason;
+phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason;
+phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason;
+
+dataJSON#7d748d04 data:string = DataJSON;
+
+labeledPrice#cb296bf8 label:string amount:long = LabeledPrice;
+
+invoice#c30aa358 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true phone_to_provider:flags.6?true email_to_provider:flags.7?true currency:string prices:Vector<LabeledPrice> = Invoice;
+
+paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge;
+
+postAddress#1e8caaeb street_line1:string street_line2:string city:string state:string country_iso2:string post_code:string = PostAddress;
+
+paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string email:flags.2?string shipping_address:flags.3?PostAddress = PaymentRequestedInfo;
+
+paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials;
+
+webDocument#1c570ed1 url:string access_hash:long size:int mime_type:string attributes:Vector<DocumentAttribute> = WebDocument;
+webDocumentNoProxy#f9c8bcc6 url:string size:int mime_type:string attributes:Vector<DocumentAttribute> = WebDocument;
+
+inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector<DocumentAttribute> = InputWebDocument;
+
+inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation;
+inputWebFileGeoPointLocation#9f2221c9 geo_point:InputGeoPoint access_hash:long w:int h:int zoom:int scale:int = InputWebFileLocation;
+
+upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile;
+
+payments.paymentForm#3f56aea3 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true bot_id:int invoice:Invoice provider_id:int url:string native_provider:flags.4?string native_params:flags.4?DataJSON saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?PaymentSavedCredentials users:Vector<User> = payments.PaymentForm;
+
+payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector<ShippingOption> = payments.ValidatedRequestedInfo;
+
+payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult;
+payments.paymentVerificationNeeded#d8411139 url:string = payments.PaymentResult;
+
+payments.paymentReceipt#500911e1 flags:# date:int bot_id:int invoice:Invoice provider_id:int info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption currency:string total_amount:long credentials_title:string users:Vector<User> = payments.PaymentReceipt;
+
+payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo;
+
+inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials;
+inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials;
+inputPaymentCredentialsApplePay#aa1c39f payment_data:DataJSON = InputPaymentCredentials;
+inputPaymentCredentialsAndroidPay#ca05d50e payment_token:DataJSON google_transaction_id:string = InputPaymentCredentials;
+
+account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword;
+
+shippingOption#b6213cdf id:string title:string prices:Vector<LabeledPrice> = ShippingOption;
+
+inputStickerSetItem#ffa0a496 flags:# document:InputDocument emoji:string mask_coords:flags.0?MaskCoords = InputStickerSetItem;
+
+inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall;
+
+phoneCallEmpty#5366c915 id:long = PhoneCall;
+phoneCallWaiting#1b8f4ad1 flags:# video:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall;
+phoneCallRequested#87eabb53 flags:# video:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall;
+phoneCallAccepted#997c454a flags:# video:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_b:bytes protocol:PhoneCallProtocol = PhoneCall;
+phoneCall#8742ae7f flags:# p2p_allowed:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connections:Vector<PhoneConnection> start_date:int = PhoneCall;
+phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true video:flags.5?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall;
+
+phoneConnection#9d4c17c0 id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection;
+
+phoneCallProtocol#fc878fc8 flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int library_versions:Vector<string> = PhoneCallProtocol;
+
+phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector<User> = phone.PhoneCall;
+
+upload.cdnFileReuploadNeeded#eea8e46e request_token:bytes = upload.CdnFile;
+upload.cdnFile#a99fca4f bytes:bytes = upload.CdnFile;
+
+cdnPublicKey#c982eaba dc_id:int public_key:string = CdnPublicKey;
+
+cdnConfig#5725e40a public_keys:Vector<CdnPublicKey> = CdnConfig;
+
+langPackString#cad181f6 key:string value:string = LangPackString;
+langPackStringPluralized#6c47ac9f flags:# key:string zero_value:flags.0?string one_value:flags.1?string two_value:flags.2?string few_value:flags.3?string many_value:flags.4?string other_value:string = LangPackString;
+langPackStringDeleted#2979eeb2 key:string = LangPackString;
+
+langPackDifference#f385c1f6 lang_code:string from_version:int version:int strings:Vector<LangPackString> = LangPackDifference;
+
+langPackLanguage#eeca5ce3 flags:# official:flags.0?true rtl:flags.2?true beta:flags.3?true name:string native_name:string lang_code:string base_lang_code:flags.1?string plural_code:string strings_count:int translated_count:int translations_url:string = LangPackLanguage;
+
+channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction;
+channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction;
+channelAdminLogEventActionChangeUsername#6a4afc38 prev_value:string new_value:string = ChannelAdminLogEventAction;
+channelAdminLogEventActionChangePhoto#434bd2af prev_photo:Photo new_photo:Photo = ChannelAdminLogEventAction;
+channelAdminLogEventActionToggleInvites#1b7907ae new_value:Bool = ChannelAdminLogEventAction;
+channelAdminLogEventActionToggleSignatures#26ae0971 new_value:Bool = ChannelAdminLogEventAction;
+channelAdminLogEventActionUpdatePinned#e9e82c18 message:Message = ChannelAdminLogEventAction;
+channelAdminLogEventActionEditMessage#709b2405 prev_message:Message new_message:Message = ChannelAdminLogEventAction;
+channelAdminLogEventActionDeleteMessage#42e047bb message:Message = ChannelAdminLogEventAction;
+channelAdminLogEventActionParticipantJoin#183040d3 = ChannelAdminLogEventAction;
+channelAdminLogEventActionParticipantLeave#f89777f2 = ChannelAdminLogEventAction;
+channelAdminLogEventActionParticipantInvite#e31c34d8 participant:ChannelParticipant = ChannelAdminLogEventAction;
+channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction;
+channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction;
+channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction;
+channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction;
+channelAdminLogEventActionDefaultBannedRights#2df5fc0a prev_banned_rights:ChatBannedRights new_banned_rights:ChatBannedRights = ChannelAdminLogEventAction;
+channelAdminLogEventActionStopPoll#8f079643 message:Message = ChannelAdminLogEventAction;
+channelAdminLogEventActionChangeLinkedChat#a26f881b prev_value:int new_value:int = ChannelAdminLogEventAction;
+channelAdminLogEventActionChangeLocation#e6b76ae prev_value:ChannelLocation new_value:ChannelLocation = ChannelAdminLogEventAction;
+channelAdminLogEventActionToggleSlowMode#53909779 prev_value:int new_value:int = ChannelAdminLogEventAction;
+
+channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int action:ChannelAdminLogEventAction = ChannelAdminLogEvent;
+
+channels.adminLogResults#ed8af74d events:Vector<ChannelAdminLogEvent> chats:Vector<Chat> users:Vector<User> = channels.AdminLogResults;
+
+channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true = ChannelAdminLogEventsFilter;
+
+popularContact#5ce14175 client_id:long importers:int = PopularContact;
+
+messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers;
+messages.favedStickers#f37f2f16 hash:int packs:Vector<StickerPack> stickers:Vector<Document> = messages.FavedStickers;
+
+recentMeUrlUnknown#46e1d13d url:string = RecentMeUrl;
+recentMeUrlUser#8dbc3336 url:string user_id:int = RecentMeUrl;
+recentMeUrlChat#a01b22f9 url:string chat_id:int = RecentMeUrl;
+recentMeUrlChatInvite#eb49081d url:string chat_invite:ChatInvite = RecentMeUrl;
+recentMeUrlStickerSet#bc0a57dc url:string set:StickerSetCovered = RecentMeUrl;
+
+help.recentMeUrls#e0310d7 urls:Vector<RecentMeUrl> chats:Vector<Chat> users:Vector<User> = help.RecentMeUrls;
+
+inputSingleMedia#1cc6e91f flags:# media:InputMedia random_id:long message:string entities:flags.0?Vector<MessageEntity> = InputSingleMedia;
+
+webAuthorization#cac943f2 hash:long bot_id:int domain:string browser:string platform:string date_created:int date_active:int ip:string region:string = WebAuthorization;
+
+account.webAuthorizations#ed56c9fc authorizations:Vector<WebAuthorization> users:Vector<User> = account.WebAuthorizations;
+
+inputMessageID#a676a322 id:int = InputMessage;
+inputMessageReplyTo#bad88395 id:int = InputMessage;
+inputMessagePinned#86872538 = InputMessage;
+
+inputDialogPeer#fcaafeb7 peer:InputPeer = InputDialogPeer;
+inputDialogPeerFolder#64600527 folder_id:int = InputDialogPeer;
+
+dialogPeer#e56dbf05 peer:Peer = DialogPeer;
+dialogPeerFolder#514519e2 folder_id:int = DialogPeer;
+
+messages.foundStickerSetsNotModified#d54b65d = messages.FoundStickerSets;
+messages.foundStickerSets#5108d648 hash:int sets:Vector<StickerSetCovered> = messages.FoundStickerSets;
+
+fileHash#6242c773 offset:int limit:int hash:bytes = FileHash;
+
+inputClientProxy#75588b3f address:string port:int = InputClientProxy;
+
+help.proxyDataEmpty#e09e1fb8 expires:int = help.ProxyData;
+help.proxyDataPromo#2bf7ee23 expires:int peer:Peer chats:Vector<Chat> users:Vector<User> = help.ProxyData;
+
+help.termsOfServiceUpdateEmpty#e3309f7f expires:int = help.TermsOfServiceUpdate;
+help.termsOfServiceUpdate#28ecf961 expires:int terms_of_service:help.TermsOfService = help.TermsOfServiceUpdate;
+
+inputSecureFileUploaded#3334b0f0 id:long parts:int md5_checksum:string file_hash:bytes secret:bytes = InputSecureFile;
+inputSecureFile#5367e5be id:long access_hash:long = InputSecureFile;
+
+secureFileEmpty#64199744 = SecureFile;
+secureFile#e0277a62 id:long access_hash:long size:int dc_id:int date:int file_hash:bytes secret:bytes = SecureFile;
+
+secureData#8aeabec3 data:bytes data_hash:bytes secret:bytes = SecureData;
+
+securePlainPhone#7d6099dd phone:string = SecurePlainData;
+securePlainEmail#21ec5a5f email:string = SecurePlainData;
+
+secureValueTypePersonalDetails#9d2a81e3 = SecureValueType;
+secureValueTypePassport#3dac6a00 = SecureValueType;
+secureValueTypeDriverLicense#6e425c4 = SecureValueType;
+secureValueTypeIdentityCard#a0d0744b = SecureValueType;
+secureValueTypeInternalPassport#99a48f23 = SecureValueType;
+secureValueTypeAddress#cbe31e26 = SecureValueType;
+secureValueTypeUtilityBill#fc36954e = SecureValueType;
+secureValueTypeBankStatement#89137c0d = SecureValueType;
+secureValueTypeRentalAgreement#8b883488 = SecureValueType;
+secureValueTypePassportRegistration#99e3806a = SecureValueType;
+secureValueTypeTemporaryRegistration#ea02ec33 = SecureValueType;
+secureValueTypePhone#b320aadb = SecureValueType;
+secureValueTypeEmail#8e3ca7ee = SecureValueType;
+
+secureValue#187fa0ca flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?SecureFile reverse_side:flags.2?SecureFile selfie:flags.3?SecureFile translation:flags.6?Vector<SecureFile> files:flags.4?Vector<SecureFile> plain_data:flags.5?SecurePlainData hash:bytes = SecureValue;
+
+inputSecureValue#db21d0a7 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?InputSecureFile reverse_side:flags.2?InputSecureFile selfie:flags.3?InputSecureFile translation:flags.6?Vector<InputSecureFile> files:flags.4?Vector<InputSecureFile> plain_data:flags.5?SecurePlainData = InputSecureValue;
+
+secureValueHash#ed1ecdb0 type:SecureValueType hash:bytes = SecureValueHash;
+
+secureValueErrorData#e8a40bd9 type:SecureValueType data_hash:bytes field:string text:string = SecureValueError;
+secureValueErrorFrontSide#be3dfa type:SecureValueType file_hash:bytes text:string = SecureValueError;
+secureValueErrorReverseSide#868a2aa5 type:SecureValueType file_hash:bytes text:string = SecureValueError;
+secureValueErrorSelfie#e537ced6 type:SecureValueType file_hash:bytes text:string = SecureValueError;
+secureValueErrorFile#7a700873 type:SecureValueType file_hash:bytes text:string = SecureValueError;
+secureValueErrorFiles#666220e9 type:SecureValueType file_hash:Vector<bytes> text:string = SecureValueError;
+secureValueError#869d758f type:SecureValueType hash:bytes text:string = SecureValueError;
+secureValueErrorTranslationFile#a1144770 type:SecureValueType file_hash:bytes text:string = SecureValueError;
+secureValueErrorTranslationFiles#34636dd8 type:SecureValueType file_hash:Vector<bytes> text:string = SecureValueError;
+
+secureCredentialsEncrypted#33f0ea47 data:bytes hash:bytes secret:bytes = SecureCredentialsEncrypted;
+
+account.authorizationForm#ad2e1cd8 flags:# required_types:Vector<SecureRequiredType> values:Vector<SecureValue> errors:Vector<SecureValueError> users:Vector<User> privacy_policy_url:flags.0?string = account.AuthorizationForm;
+
+account.sentEmailCode#811f854f email_pattern:string length:int = account.SentEmailCode;
+
+help.deepLinkInfoEmpty#66afa166 = help.DeepLinkInfo;
+help.deepLinkInfo#6a4ee832 flags:# update_app:flags.0?true message:string entities:flags.1?Vector<MessageEntity> = help.DeepLinkInfo;
+
+savedPhoneContact#1142bd56 phone:string first_name:string last_name:string date:int = SavedContact;
+
+account.takeout#4dba4501 id:long = account.Takeout;
+
+passwordKdfAlgoUnknown#d45ab096 = PasswordKdfAlgo;
+passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow#3a912d4a salt1:bytes salt2:bytes g:int p:bytes = PasswordKdfAlgo;
+
+securePasswordKdfAlgoUnknown#4a8537 = SecurePasswordKdfAlgo;
+securePasswordKdfAlgoPBKDF2HMACSHA512iter100000#bbf2dda0 salt:bytes = SecurePasswordKdfAlgo;
+securePasswordKdfAlgoSHA512#86471d92 salt:bytes = SecurePasswordKdfAlgo;
+
+secureSecretSettings#1527bcac secure_algo:SecurePasswordKdfAlgo secure_secret:bytes secure_secret_id:long = SecureSecretSettings;
+
+inputCheckPasswordEmpty#9880f658 = InputCheckPasswordSRP;
+inputCheckPasswordSRP#d27ff082 srp_id:long A:bytes M1:bytes = InputCheckPasswordSRP;
+
+secureRequiredType#829d99da flags:# native_names:flags.0?true selfie_required:flags.1?true translation_required:flags.2?true type:SecureValueType = SecureRequiredType;
+secureRequiredTypeOneOf#27477b4 types:Vector<SecureRequiredType> = SecureRequiredType;
+
+help.passportConfigNotModified#bfb9f457 = help.PassportConfig;
+help.passportConfig#a098d6af hash:int countries_langs:DataJSON = help.PassportConfig;
+
+inputAppEvent#1d1b1245 time:double type:string peer:long data:JSONValue = InputAppEvent;
+
+jsonObjectValue#c0de1bd9 key:string value:JSONValue = JSONObjectValue;
+
+jsonNull#3f6d7b68 = JSONValue;
+jsonBool#c7345e6a value:Bool = JSONValue;
+jsonNumber#2be0dfa4 value:double = JSONValue;
+jsonString#b71e767a value:string = JSONValue;
+jsonArray#f7444763 value:Vector<JSONValue> = JSONValue;
+jsonObject#99c1d49d value:Vector<JSONObjectValue> = JSONValue;
+
+pageTableCell#34566b6a flags:# header:flags.0?true align_center:flags.3?true align_right:flags.4?true valign_middle:flags.5?true valign_bottom:flags.6?true text:flags.7?RichText colspan:flags.1?int rowspan:flags.2?int = PageTableCell;
+
+pageTableRow#e0c0c5e5 cells:Vector<PageTableCell> = PageTableRow;
+
+pageCaption#6f747657 text:RichText credit:RichText = PageCaption;
+
+pageListItemText#b92fb6cd text:RichText = PageListItem;
+pageListItemBlocks#25e073fc blocks:Vector<PageBlock> = PageListItem;
+
+pageListOrderedItemText#5e068047 num:string text:RichText = PageListOrderedItem;
+pageListOrderedItemBlocks#98dd8936 num:string blocks:Vector<PageBlock> = PageListOrderedItem;
+
+pageRelatedArticle#b390dc08 flags:# url:string webpage_id:long title:flags.0?string description:flags.1?string photo_id:flags.2?long author:flags.3?string published_date:flags.4?int = PageRelatedArticle;
+
+page#98657f0d flags:# part:flags.0?true rtl:flags.1?true v2:flags.2?true url:string blocks:Vector<PageBlock> photos:Vector<Photo> documents:Vector<Document> views:flags.3?int = Page;
+
+help.supportName#8c05f1c9 name:string = help.SupportName;
+
+help.userInfoEmpty#f3ae2eed = help.UserInfo;
+help.userInfo#1eb3758 message:string entities:Vector<MessageEntity> author:string date:int = help.UserInfo;
+
+pollAnswer#6ca9c2e9 text:string option:bytes = PollAnswer;
+
+poll#86e18161 id:long flags:# closed:flags.0?true public_voters:flags.1?true multiple_choice:flags.2?true quiz:flags.3?true question:string answers:Vector<PollAnswer> close_period:flags.4?int close_date:flags.5?int = Poll;
+
+pollAnswerVoters#3b6ddad2 flags:# chosen:flags.0?true correct:flags.1?true option:bytes voters:int = PollAnswerVoters;
+
+pollResults#badcc1a3 flags:# min:flags.0?true results:flags.1?Vector<PollAnswerVoters> total_voters:flags.2?int recent_voters:flags.3?Vector<int> solution:flags.4?string solution_entities:flags.4?Vector<MessageEntity> = PollResults;
+
+chatOnlines#f041e250 onlines:int = ChatOnlines;
+
+statsURL#47a971e0 url:string = StatsURL;
+
+chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true = ChatAdminRights;
+
+chatBannedRights#9f120418 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true send_polls:flags.8?true change_info:flags.10?true invite_users:flags.15?true pin_messages:flags.17?true until_date:int = ChatBannedRights;
+
+inputWallPaper#e630b979 id:long access_hash:long = InputWallPaper;
+inputWallPaperSlug#72091c80 slug:string = InputWallPaper;
+inputWallPaperNoFile#8427bbac = InputWallPaper;
+
+account.wallPapersNotModified#1c199183 = account.WallPapers;
+account.wallPapers#702b65a9 hash:int wallpapers:Vector<WallPaper> = account.WallPapers;
+
+codeSettings#debebe83 flags:# allow_flashcall:flags.0?true current_number:flags.1?true allow_app_hash:flags.4?true = CodeSettings;
+
+wallPaperSettings#5086cf8 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int second_background_color:flags.4?int intensity:flags.3?int rotation:flags.4?int = WallPaperSettings;
+
+autoDownloadSettings#e04232f3 flags:# disabled:flags.0?true video_preload_large:flags.1?true audio_preload_next:flags.2?true phonecalls_less_data:flags.3?true photo_size_max:int video_size_max:int file_size_max:int video_upload_maxbitrate:int = AutoDownloadSettings;
+
+account.autoDownloadSettings#63cacf26 low:AutoDownloadSettings medium:AutoDownloadSettings high:AutoDownloadSettings = account.AutoDownloadSettings;
+
+emojiKeyword#d5b3b9f9 keyword:string emoticons:Vector<string> = EmojiKeyword;
+emojiKeywordDeleted#236df622 keyword:string emoticons:Vector<string> = EmojiKeyword;
+
+emojiKeywordsDifference#5cc761bd lang_code:string from_version:int version:int keywords:Vector<EmojiKeyword> = EmojiKeywordsDifference;
+
+emojiURL#a575739d url:string = EmojiURL;
+
+emojiLanguage#b3fb5361 lang_code:string = EmojiLanguage;
+
+fileLocationToBeDeprecated#bc7fc6cd volume_id:long local_id:int = FileLocation;
+
+folder#ff544e65 flags:# autofill_new_broadcasts:flags.0?true autofill_public_groups:flags.1?true autofill_new_correspondents:flags.2?true id:int title:string photo:flags.3?ChatPhoto = Folder;
+
+inputFolderPeer#fbd2c296 peer:InputPeer folder_id:int = InputFolderPeer;
+
+folderPeer#e9baa668 peer:Peer folder_id:int = FolderPeer;
+
+messages.searchCounter#e844ebff flags:# inexact:flags.1?true filter:MessagesFilter count:int = messages.SearchCounter;
+
+urlAuthResultRequest#92d33a0e flags:# request_write_access:flags.0?true bot:User domain:string = UrlAuthResult;
+urlAuthResultAccepted#8f8c0e4e url:string = UrlAuthResult;
+urlAuthResultDefault#a9d6db1f = UrlAuthResult;
+
+channelLocationEmpty#bfb5ad8b = ChannelLocation;
+channelLocation#209b82db geo_point:GeoPoint address:string = ChannelLocation;
+
+peerLocated#ca461b5d peer:Peer expires:int distance:int = PeerLocated;
+peerSelfLocated#f8ec284b expires:int = PeerLocated;
+
+restrictionReason#d072acb4 platform:string reason:string text:string = RestrictionReason;
+
+inputTheme#3c5693e9 id:long access_hash:long = InputTheme;
+inputThemeSlug#f5890df1 slug:string = InputTheme;
+
+theme#28f1114 flags:# creator:flags.0?true default:flags.1?true id:long access_hash:long slug:string title:string document:flags.2?Document settings:flags.3?ThemeSettings installs_count:int = Theme;
+
+account.themesNotModified#f41eb622 = account.Themes;
+account.themes#7f676421 hash:int themes:Vector<Theme> = account.Themes;
+
+auth.loginToken#629f1980 expires:int token:bytes = auth.LoginToken;
+auth.loginTokenMigrateTo#68e9916 dc_id:int token:bytes = auth.LoginToken;
+auth.loginTokenSuccess#390d5c5e authorization:auth.Authorization = auth.LoginToken;
+
+account.contentSettings#57e28221 flags:# sensitive_enabled:flags.0?true sensitive_can_change:flags.1?true = account.ContentSettings;
+
+messages.inactiveChats#a927fec5 dates:Vector<int> chats:Vector<Chat> users:Vector<User> = messages.InactiveChats;
+
+baseThemeClassic#c3a12462 = BaseTheme;
+baseThemeDay#fbd81688 = BaseTheme;
+baseThemeNight#b7b31ea8 = BaseTheme;
+baseThemeTinted#6d5f77ee = BaseTheme;
+baseThemeArctic#5b11125a = BaseTheme;
+
+inputThemeSettings#bd507cd1 flags:# base_theme:BaseTheme accent_color:int message_top_color:flags.0?int message_bottom_color:flags.0?int wallpaper:flags.1?InputWallPaper wallpaper_settings:flags.1?WallPaperSettings = InputThemeSettings;
+
+themeSettings#9c14984a flags:# base_theme:BaseTheme accent_color:int message_top_color:flags.0?int message_bottom_color:flags.0?int wallpaper:flags.1?WallPaper = ThemeSettings;
+
+webPageAttributeTheme#54b56617 flags:# documents:flags.0?Vector<Document> settings:flags.1?ThemeSettings = WebPageAttribute;
+
+messageUserVote#a28e5559 user_id:int option:bytes date:int = MessageUserVote;
+messageUserVoteInputOption#36377430 user_id:int date:int = MessageUserVote;
+messageUserVoteMultiple#e8fe0de user_id:int options:Vector<bytes> date:int = MessageUserVote;
+
+messages.votesList#823f649 flags:# count:int votes:Vector<MessageUserVote> users:Vector<User> next_offset:flags.0?string = messages.VotesList;
+
+bankCardOpenUrl#f568028a url:string name:string = BankCardOpenUrl;
+
+payments.bankCardData#3e24e573 title:string open_urls:Vector<BankCardOpenUrl> = payments.BankCardData;
+
+dialogFilter#7438f7e8 flags:# contacts:flags.0?true non_contacts:flags.1?true groups:flags.2?true broadcasts:flags.3?true bots:flags.4?true exclude_muted:flags.11?true exclude_read:flags.12?true exclude_archived:flags.13?true id:int title:string emoticon:flags.25?string pinned_peers:Vector<InputPeer> include_peers:Vector<InputPeer> exclude_peers:Vector<InputPeer> = DialogFilter;
+
+dialogFilterSuggested#77744d4a filter:DialogFilter description:string = DialogFilterSuggested;
+
+statsDateRangeDays#b637edaf min_date:int max_date:int = StatsDateRangeDays;
+
+statsAbsValueAndPrev#cb43acde current:double previous:double = StatsAbsValueAndPrev;
+
+statsPercentValue#cbce2fe0 part:double total:double = StatsPercentValue;
+
+statsGraphAsync#4a27eb2d token:string = StatsGraph;
+statsGraphError#bedc9822 error:string = StatsGraph;
+statsGraph#8ea464b6 flags:# json:DataJSON zoom_token:flags.0?string = StatsGraph;
+
+messageInteractionCounters#ad4fc9bd msg_id:int views:int forwards:int = MessageInteractionCounters;
+
+stats.broadcastStats#bdf78394 period:StatsDateRangeDays followers:StatsAbsValueAndPrev views_per_post:StatsAbsValueAndPrev shares_per_post:StatsAbsValueAndPrev enabled_notifications:StatsPercentValue growth_graph:StatsGraph followers_graph:StatsGraph mute_graph:StatsGraph top_hours_graph:StatsGraph interactions_graph:StatsGraph iv_interactions_graph:StatsGraph views_by_source_graph:StatsGraph new_followers_by_source_graph:StatsGraph languages_graph:StatsGraph recent_message_interactions:Vector<MessageInteractionCounters> = stats.BroadcastStats;
+
+---functions---
+
+invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
+invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector<long> query:!X = X;
+initConnection#c1cd5ea9 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy params:flags.1?JSONValue query:!X = X;
+invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X;
+invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X;
+invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X;
+invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X;
+
+auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode;
+auth.signUp#80eee427 phone_number:string phone_code_hash:string first_name:string last_name:string = auth.Authorization;
+auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization;
+auth.logOut#5717da40 = Bool;
+auth.resetAuthorizations#9fab0d1a = Bool;
+auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization;
+auth.importAuthorization#e3ef9613 id:int bytes:bytes = auth.Authorization;
+auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool;
+auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization;
+auth.checkPassword#d18b4d16 password:InputCheckPasswordSRP = auth.Authorization;
+auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery;
+auth.recoverPassword#4ea56e92 code:string = auth.Authorization;
+auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode;
+auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool;
+auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector<long> = Bool;
+auth.exportLoginToken#b1b41517 api_id:int api_hash:string except_ids:Vector<int> = auth.LoginToken;
+auth.importLoginToken#95ac5ce4 token:bytes = auth.LoginToken;
+auth.acceptLoginToken#e894ad4d token:bytes = Authorization;
+
+account.registerDevice#68976c6f flags:# no_muted:flags.0?true token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector<int> = Bool;
+account.unregisterDevice#3076c4bf token_type:int token:string other_uids:Vector<int> = Bool;
+account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool;
+account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings;
+account.resetNotifySettings#db7e1747 = Bool;
+account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User;
+account.updateStatus#6628562c offline:Bool = Bool;
+account.getWallPapers#aabb1763 hash:int = account.WallPapers;
+account.reportPeer#ae189d5f peer:InputPeer reason:ReportReason = Bool;
+account.checkUsername#2714d86c username:string = Bool;
+account.updateUsername#3e0bdd7c username:string = User;
+account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules;
+account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector<InputPrivacyRule> = account.PrivacyRules;
+account.deleteAccount#418d4e0b reason:string = Bool;
+account.getAccountTTL#8fc711d = AccountDaysTTL;
+account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool;
+account.sendChangePhoneCode#82574ae5 phone_number:string settings:CodeSettings = auth.SentCode;
+account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User;
+account.updateDeviceLocked#38df3532 period:int = Bool;
+account.getAuthorizations#e320c158 = account.Authorizations;
+account.resetAuthorization#df77f3bc hash:long = Bool;
+account.getPassword#548a30f5 = account.Password;
+account.getPasswordSettings#9cd4eaf9 password:InputCheckPasswordSRP = account.PasswordSettings;
+account.updatePasswordSettings#a59b102f password:InputCheckPasswordSRP new_settings:account.PasswordInputSettings = Bool;
+account.sendConfirmPhoneCode#1b3faa88 hash:string settings:CodeSettings = auth.SentCode;
+account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool;
+account.getTmpPassword#449e0b51 password:InputCheckPasswordSRP period:int = account.TmpPassword;
+account.getWebAuthorizations#182e6d6f = account.WebAuthorizations;
+account.resetWebAuthorization#2d01b9ef hash:long = Bool;
+account.resetWebAuthorizations#682d2594 = Bool;
+account.getAllSecureValues#b288bc7d = Vector<SecureValue>;
+account.getSecureValue#73665bc2 types:Vector<SecureValueType> = Vector<SecureValue>;
+account.saveSecureValue#899fe31d value:InputSecureValue secure_secret_id:long = SecureValue;
+account.deleteSecureValue#b880bc4b types:Vector<SecureValueType> = Bool;
+account.getAuthorizationForm#b86ba8e1 bot_id:int scope:string public_key:string = account.AuthorizationForm;
+account.acceptAuthorization#e7027c94 bot_id:int scope:string public_key:string value_hashes:Vector<SecureValueHash> credentials:SecureCredentialsEncrypted = Bool;
+account.sendVerifyPhoneCode#a5a356f9 phone_number:string settings:CodeSettings = auth.SentCode;
+account.verifyPhone#4dd3a7f6 phone_number:string phone_code_hash:string phone_code:string = Bool;
+account.sendVerifyEmailCode#7011509f email:string = account.SentEmailCode;
+account.verifyEmail#ecba39db email:string code:string = Bool;
+account.initTakeoutSession#f05b4804 flags:# contacts:flags.0?true message_users:flags.1?true message_chats:flags.2?true message_megagroups:flags.3?true message_channels:flags.4?true files:flags.5?true file_max_size:flags.5?int = account.Takeout;
+account.finishTakeoutSession#1d2652ee flags:# success:flags.0?true = Bool;
+account.confirmPasswordEmail#8fdf1920 code:string = Bool;
+account.resendPasswordEmail#7a7f2a15 = Bool;
+account.cancelPasswordEmail#c1cbd5b6 = Bool;
+account.getContactSignUpNotification#9f07c728 = Bool;
+account.setContactSignUpNotification#cff43f61 silent:Bool = Bool;
+account.getNotifyExceptions#53577479 flags:# compare_sound:flags.1?true peer:flags.0?InputNotifyPeer = Updates;
+account.getWallPaper#fc8ddbea wallpaper:InputWallPaper = WallPaper;
+account.uploadWallPaper#dd853661 file:InputFile mime_type:string settings:WallPaperSettings = WallPaper;
+account.saveWallPaper#6c5a5b37 wallpaper:InputWallPaper unsave:Bool settings:WallPaperSettings = Bool;
+account.installWallPaper#feed5769 wallpaper:InputWallPaper settings:WallPaperSettings = Bool;
+account.resetWallPapers#bb3b9804 = Bool;
+account.getAutoDownloadSettings#56da0b3f = account.AutoDownloadSettings;
+account.saveAutoDownloadSettings#76f36233 flags:# low:flags.0?true high:flags.1?true settings:AutoDownloadSettings = Bool;
+account.uploadTheme#1c3db333 flags:# file:InputFile thumb:flags.0?InputFile file_name:string mime_type:string = Document;
+account.createTheme#8432c21f flags:# slug:string title:string document:flags.2?InputDocument settings:flags.3?InputThemeSettings = Theme;
+account.updateTheme#5cb367d5 flags:# format:string theme:InputTheme slug:flags.0?string title:flags.1?string document:flags.2?InputDocument settings:flags.3?InputThemeSettings = Theme;
+account.saveTheme#f257106c theme:InputTheme unsave:Bool = Bool;
+account.installTheme#7ae43737 flags:# dark:flags.0?true format:flags.1?string theme:flags.1?InputTheme = Bool;
+account.getTheme#8d9d742b format:string theme:InputTheme document_id:long = Theme;
+account.getThemes#285946f8 format:string hash:int = account.Themes;
+account.setContentSettings#b574b16b flags:# sensitive_enabled:flags.0?true = Bool;
+account.getContentSettings#8b9b4dae = account.ContentSettings;
+account.getMultiWallPapers#65ad71dc wallpapers:Vector<InputWallPaper> = Vector<WallPaper>;
+
+users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
+users.getFullUser#ca30a5b1 id:InputUser = UserFull;
+users.setSecureValueErrors#90c894b5 id:InputUser errors:Vector<SecureValueError> = Bool;
+
+contacts.getContactIDs#2caa4a42 hash:int = Vector<int>;
+contacts.getStatuses#c4a353ee = Vector<ContactStatus>;
+contacts.getContacts#c023849f hash:int = contacts.Contacts;
+contacts.importContacts#2c800be5 contacts:Vector<InputContact> = contacts.ImportedContacts;
+contacts.deleteContacts#96a0e00 id:Vector<InputUser> = Updates;
+contacts.deleteByPhones#1013fd9e phones:Vector<string> = Bool;
+contacts.block#332b49fc id:InputUser = Bool;
+contacts.unblock#e54100bd id:InputUser = Bool;
+contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked;
+contacts.search#11f812d8 q:string limit:int = contacts.Found;
+contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer;
+contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true forward_users:flags.4?true forward_chats:flags.5?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers;
+contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool;
+contacts.resetSaved#879537f1 = Bool;
+contacts.getSaved#82f1e39f = Vector<SavedContact>;
+contacts.toggleTopPeers#8514bdda enabled:Bool = Bool;
+contacts.addContact#e8f463d0 flags:# add_phone_privacy_exception:flags.0?true id:InputUser first_name:string last_name:string phone:string = Updates;
+contacts.acceptContact#f831a20f id:InputUser = Updates;
+contacts.getLocated#d348bc44 flags:# background:flags.1?true geo_point:InputGeoPoint self_expires:flags.0?int = Updates;
+
+messages.getMessages#63c66506 id:Vector<InputMessage> = messages.Messages;
+messages.getDialogs#a0ee3b73 flags:# exclude_pinned:flags.0?true folder_id:flags.1?int offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:int = messages.Dialogs;
+messages.getHistory#dcbb8260 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
+messages.search#8614ef68 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
+messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages;
+messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true revoke:flags.1?true peer:InputPeer max_id:int = messages.AffectedHistory;
+messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector<int> = messages.AffectedMessages;
+messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>;
+messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool;
+messages.sendMessage#520c3870 flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int = Updates;
+messages.sendMedia#3491eba9 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int = Updates;
+messages.forwardMessages#d9fee60e flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true grouped:flags.9?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer schedule_date:flags.10?int = Updates;
+messages.reportSpam#cf1592db peer:InputPeer = Bool;
+messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings;
+messages.report#bd82b658 peer:InputPeer id:Vector<int> reason:ReportReason = Bool;
+messages.getChats#3c6aa187 id:Vector<int> = messages.Chats;
+messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull;
+messages.editChatTitle#dc452855 chat_id:int title:string = Updates;
+messages.editChatPhoto#ca4c79d8 chat_id:int photo:InputChatPhoto = Updates;
+messages.addChatUser#f9a0aa09 chat_id:int user_id:InputUser fwd_limit:int = Updates;
+messages.deleteChatUser#e0611f16 chat_id:int user_id:InputUser = Updates;
+messages.createChat#9cb126e users:Vector<InputUser> title:string = Updates;
+messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig;
+messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat;
+messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat;
+messages.discardEncryption#edd923c5 chat_id:int = Bool;
+messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool;
+messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool;
+messages.sendEncrypted#a9776773 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage;
+messages.sendEncryptedFile#9a901b66 peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage;
+messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage;
+messages.receivedQueue#55a5bb66 max_qts:int = Vector<long>;
+messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool;
+messages.readMessageContents#36a73f77 id:Vector<int> = messages.AffectedMessages;
+messages.getStickers#43d4f2c emoticon:string hash:int = messages.Stickers;
+messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers;
+messages.getWebPagePreview#8b68b0cc flags:# message:string entities:flags.3?Vector<MessageEntity> = MessageMedia;
+messages.exportChatInvite#df7534c peer:InputPeer = ExportedChatInvite;
+messages.checkChatInvite#3eadb1bb hash:string = ChatInvite;
+messages.importChatInvite#6c50051c hash:string = Updates;
+messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet;
+messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult;
+messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool;
+messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates;
+messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector<int> increment:Bool = Vector<int>;
+messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool;
+messages.migrateChat#15a3b8e3 chat_id:int = Updates;
+messages.searchGlobal#bf7225a4 flags:# folder_id:flags.0?int q:string offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
+messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector<long> = Bool;
+messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document;
+messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs;
+messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs;
+messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool;
+messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults;
+messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector<InputBotInlineResult> cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool;
+messages.sendInlineBotResult#220815b0 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string schedule_date:flags.10?int = Updates;
+messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData;
+messages.editMessage#48f71778 flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.15?int = Updates;
+messages.editInlineBotMessage#83557dba flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Bool;
+messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer;
+messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool;
+messages.getPeerDialogs#e470bcfd peers:Vector<InputDialogPeer> = messages.PeerDialogs;
+messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector<MessageEntity> = Bool;
+messages.getAllDrafts#6a3f8d65 = Updates;
+messages.getFeaturedStickers#2dacca4f hash:int = messages.FeaturedStickers;
+messages.readFeaturedStickers#5b118126 id:Vector<long> = Bool;
+messages.getRecentStickers#5ea192c9 flags:# attached:flags.0?true hash:int = messages.RecentStickers;
+messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool;
+messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool;
+messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true offset_id:long limit:int = messages.ArchivedStickers;
+messages.getMaskStickers#65b8c79f hash:int = messages.AllStickers;
+messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector<StickerSetCovered>;
+messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates;
+messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool;
+messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores;
+messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores;
+messages.getCommonChats#d0a48c4 user_id:InputUser max_id:int limit:int = messages.Chats;
+messages.getAllChats#eba80ff0 except_ids:Vector<int> = messages.Chats;
+messages.getWebPage#32ca8f91 url:string hash:int = WebPage;
+messages.toggleDialogPin#a731e257 flags:# pinned:flags.0?true peer:InputDialogPeer = Bool;
+messages.reorderPinnedDialogs#3b1adf37 flags:# force:flags.0?true folder_id:int order:Vector<InputDialogPeer> = Bool;
+messages.getPinnedDialogs#d6b94df2 folder_id:int = messages.PeerDialogs;
+messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector<ShippingOption> = Bool;
+messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool;
+messages.uploadMedia#519bc2b1 peer:InputPeer media:InputMedia = MessageMedia;
+messages.sendScreenshotNotification#c97df020 peer:InputPeer reply_to_msg_id:int random_id:long = Updates;
+messages.getFavedStickers#21ce0b0e hash:int = messages.FavedStickers;
+messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool;
+messages.getUnreadMentions#46578472 peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages;
+messages.readMentions#f0189d3 peer:InputPeer = messages.AffectedHistory;
+messages.getRecentLocations#bbc45b09 peer:InputPeer limit:int hash:int = messages.Messages;
+messages.sendMultiMedia#cc0110cb flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int multi_media:Vector<InputSingleMedia> schedule_date:flags.10?int = Updates;
+messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile;
+messages.searchStickerSets#c2b7d08b flags:# exclude_featured:flags.0?true q:string hash:int = messages.FoundStickerSets;
+messages.getSplitRanges#1cff7e08 = Vector<MessageRange>;
+messages.markDialogUnread#c286d98f flags:# unread:flags.0?true peer:InputDialogPeer = Bool;
+messages.getDialogUnreadMarks#22e24e22 = Vector<DialogPeer>;
+messages.clearAllDrafts#7e58ee9c = Bool;
+messages.updatePinnedMessage#d2aaf7ec flags:# silent:flags.0?true peer:InputPeer id:int = Updates;
+messages.sendVote#10ea6184 peer:InputPeer msg_id:int options:Vector<bytes> = Updates;
+messages.getPollResults#73bb643b peer:InputPeer msg_id:int = Updates;
+messages.getOnlines#6e2be050 peer:InputPeer = ChatOnlines;
+messages.getStatsURL#812c2ae6 flags:# dark:flags.0?true peer:InputPeer params:string = StatsURL;
+messages.editChatAbout#def60797 peer:InputPeer about:string = Bool;
+messages.editChatDefaultBannedRights#a5866b41 peer:InputPeer banned_rights:ChatBannedRights = Updates;
+messages.getEmojiKeywords#35a0e062 lang_code:string = EmojiKeywordsDifference;
+messages.getEmojiKeywordsDifference#1508b6af lang_code:string from_version:int = EmojiKeywordsDifference;
+messages.getEmojiKeywordsLanguages#4e9963b2 lang_codes:Vector<string> = Vector<EmojiLanguage>;
+messages.getEmojiURL#d5b10c26 lang_code:string = EmojiURL;
+messages.getSearchCounters#732eef00 peer:InputPeer filters:Vector<MessagesFilter> = Vector<messages.SearchCounter>;
+messages.requestUrlAuth#e33f5613 peer:InputPeer msg_id:int button_id:int = UrlAuthResult;
+messages.acceptUrlAuth#f729ea98 flags:# write_allowed:flags.0?true peer:InputPeer msg_id:int button_id:int = UrlAuthResult;
+messages.hidePeerSettingsBar#4facb138 peer:InputPeer = Bool;
+messages.getScheduledHistory#e2c2685b peer:InputPeer hash:int = messages.Messages;
+messages.getScheduledMessages#bdbb0464 peer:InputPeer id:Vector<int> = messages.Messages;
+messages.sendScheduledMessages#bd38850a peer:InputPeer id:Vector<int> = Updates;
+messages.deleteScheduledMessages#59ae2b16 peer:InputPeer id:Vector<int> = Updates;
+messages.getPollVotes#b86e380e flags:# peer:InputPeer id:int option:flags.0?bytes offset:flags.1?string limit:int = messages.VotesList;
+messages.toggleStickerSets#b5052fea flags:# uninstall:flags.0?true archive:flags.1?true unarchive:flags.2?true stickersets:Vector<InputStickerSet> = Bool;
+messages.getDialogFilters#f19ed96d = Vector<DialogFilter>;
+messages.getSuggestedDialogFilters#a29cd42c = Vector<DialogFilterSuggested>;
+messages.updateDialogFilter#1ad4a04a flags:# id:int filter:flags.0?DialogFilter = Bool;
+messages.updateDialogFiltersOrder#c563c1e4 order:Vector<int> = Bool;
+messages.getOldFeaturedStickers#5fe7025b offset:int limit:int hash:int = messages.FeaturedStickers;
+
+updates.getState#edd4882a = updates.State;
+updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
+updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference;
+
+photos.updateProfilePhoto#f0bb5152 id:InputPhoto = UserProfilePhoto;
+photos.uploadProfilePhoto#4f32c098 file:InputFile = photos.Photo;
+photos.deletePhotos#87cf7f2f id:Vector<InputPhoto> = Vector<long>;
+photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos;
+
+upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool;
+upload.getFile#b15a9afc flags:# precise:flags.0?true cdn_supported:flags.1?true location:InputFileLocation offset:int limit:int = upload.File;
+upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool;
+upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile;
+upload.getCdnFile#2000bcc3 file_token:bytes offset:int limit:int = upload.CdnFile;
+upload.reuploadCdnFile#9b2754a8 file_token:bytes request_token:bytes = Vector<FileHash>;
+upload.getCdnFileHashes#4da54231 file_token:bytes offset:int = Vector<FileHash>;
+upload.getFileHashes#c7025931 location:InputFileLocation offset:int = Vector<FileHash>;
+
+help.getConfig#c4f9186b = Config;
+help.getNearestDc#1fb33026 = NearestDc;
+help.getAppUpdate#522d5a7d source:string = help.AppUpdate;
+help.getInviteText#4d392343 = help.InviteText;
+help.getSupport#9cdf08cd = help.Support;
+help.getAppChangelog#9010ef6f prev_app_version:string = Updates;
+help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool;
+help.getCdnConfig#52029342 = CdnConfig;
+help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls;
+help.getProxyData#3d7758e1 = help.ProxyData;
+help.getTermsOfServiceUpdate#2ca51fd1 = help.TermsOfServiceUpdate;
+help.acceptTermsOfService#ee72f79a id:DataJSON = Bool;
+help.getDeepLinkInfo#3fedc75f path:string = help.DeepLinkInfo;
+help.getAppConfig#98914110 = JSONValue;
+help.saveAppLog#6f02f748 events:Vector<InputAppEvent> = Bool;
+help.getPassportConfig#c661ad08 hash:int = help.PassportConfig;
+help.getSupportName#d360e72c = help.SupportName;
+help.getUserInfo#38a08d3 user_id:InputUser = help.UserInfo;
+help.editUserInfo#66b91b70 user_id:InputUser message:string entities:Vector<MessageEntity> = help.UserInfo;
+
+channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool;
+channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector<int> = messages.AffectedMessages;
+channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory;
+channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector<int> = Bool;
+channels.getMessages#ad8c9a23 channel:InputChannel id:Vector<InputMessage> = messages.Messages;
+channels.getParticipants#123e05e9 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:int = channels.ChannelParticipants;
+channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant;
+channels.getChannels#a7f6bbb id:Vector<InputChannel> = messages.Chats;
+channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull;
+channels.createChannel#3d5fb10f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string geo_point:flags.2?InputGeoPoint address:flags.2?string = Updates;
+channels.editAdmin#d33c8902 channel:InputChannel user_id:InputUser admin_rights:ChatAdminRights rank:string = Updates;
+channels.editTitle#566decd0 channel:InputChannel title:string = Updates;
+channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates;
+channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool;
+channels.updateUsername#3514b3de channel:InputChannel username:string = Bool;
+channels.joinChannel#24b524c5 channel:InputChannel = Updates;
+channels.leaveChannel#f836aa95 channel:InputChannel = Updates;
+channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector<InputUser> = Updates;
+channels.deleteChannel#c0111fe3 channel:InputChannel = Updates;
+channels.exportMessageLink#ceb77163 channel:InputChannel id:int grouped:Bool = ExportedMessageLink;
+channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates;
+channels.getAdminedPublicChannels#f8b036af flags:# by_location:flags.0?true check_limit:flags.1?true = messages.Chats;
+channels.editBanned#72796912 channel:InputChannel user_id:InputUser banned_rights:ChatBannedRights = Updates;
+channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector<InputUser> max_id:long min_id:long limit:int = channels.AdminLogResults;
+channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool;
+channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector<int> = Bool;
+channels.deleteHistory#af369d42 channel:InputChannel max_id:int = Bool;
+channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates;
+channels.getLeftChannels#8341ecc0 offset:int = messages.Chats;
+channels.getGroupsForDiscussion#f5dad378 = messages.Chats;
+channels.setDiscussionGroup#40582bb2 broadcast:InputChannel group:InputChannel = Bool;
+channels.editCreator#8f38cd1f channel:InputChannel user_id:InputUser password:InputCheckPasswordSRP = Updates;
+channels.editLocation#58e63f6d channel:InputChannel geo_point:InputGeoPoint address:string = Bool;
+channels.toggleSlowMode#edd49ef0 channel:InputChannel seconds:int = Updates;
+channels.getInactiveChannels#11e831ee = messages.InactiveChats;
+
+bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON;
+bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool;
+bots.setBotCommands#805d46f6 commands:Vector<BotCommand> = Bool;
+
+payments.getPaymentForm#99f09745 msg_id:int = payments.PaymentForm;
+payments.getPaymentReceipt#a092a980 msg_id:int = payments.PaymentReceipt;
+payments.validateRequestedInfo#770a8e74 flags:# save:flags.0?true msg_id:int info:PaymentRequestedInfo = payments.ValidatedRequestedInfo;
+payments.sendPaymentForm#2b8879b3 flags:# msg_id:int requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials = payments.PaymentResult;
+payments.getSavedInfo#227d824b = payments.SavedInfo;
+payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool;
+payments.getBankCardData#2e79d779 number:string = payments.BankCardData;
+
+stickers.createStickerSet#f1036780 flags:# masks:flags.0?true animated:flags.1?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector<InputStickerSetItem> = messages.StickerSet;
+stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet;
+stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet;
+stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet;
+stickers.setStickerSetThumb#9a364e30 stickerset:InputStickerSet thumb:InputDocument = messages.StickerSet;
+
+phone.getCallConfig#55451fa9 = DataJSON;
+phone.requestCall#42ff96ed flags:# video:flags.0?true user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall;
+phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall;
+phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall;
+phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool;
+phone.discardCall#b2cbc1c0 flags:# video:flags.0?true peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates;
+phone.setCallRating#59ead627 flags:# user_initiative:flags.0?true peer:InputPhoneCall rating:int comment:string = Updates;
+phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool;
+
+langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference;
+langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector<string> = Vector<LangPackString>;
+langpack.getDifference#cd984aa5 lang_pack:string lang_code:string from_version:int = LangPackDifference;
+langpack.getLanguages#42c6978f lang_pack:string = Vector<LangPackLanguage>;
+langpack.getLanguage#6a596502 lang_pack:string lang_code:string = LangPackLanguage;
+
+folders.editPeerFolders#6847d0ab folder_peers:Vector<InputFolderPeer> = Updates;
+folders.deleteFolder#1c295881 folder_id:int = Updates;
+
+stats.getBroadcastStats#e6300dba flags:# dark:flags.0?true channel:InputChannel tz_offset:int = stats.BroadcastStats;
+stats.loadAsyncGraph#621d5fa0 flags:# token:string x:flags.0?long = StatsGraph;
+
+// LAYER 112

+ 37 - 0
gramjs/tl/static/schema.reduced.tl

@@ -0,0 +1,37 @@
+resPQ#05162463 nonce:int128 server_nonce:int128 pq:string server_public_key_fingerprints:Vector<long> = ResPQ;
+p_q_inner_data#83c95aec pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 = P_Q_inner_data;
+server_DH_params_fail#79cb045d nonce:int128 server_nonce:int128 new_nonce_hash:int128 = Server_DH_Params;
+server_DH_params_ok#d0e8075c nonce:int128 server_nonce:int128 encrypted_answer:string = Server_DH_Params;
+server_DH_inner_data#b5890dba nonce:int128 server_nonce:int128 g:int dh_prime:string g_a:string server_time:int = Server_DH_inner_data;
+client_DH_inner_data#6643b654 nonce:int128 server_nonce:int128 retry_id:long g_b:string = Client_DH_Inner_Data;
+dh_gen_ok#3bcbf734 nonce:int128 server_nonce:int128 new_nonce_hash1:int128 = Set_client_DH_params_answer;
+dh_gen_retry#46dc1fb9 nonce:int128 server_nonce:int128 new_nonce_hash2:int128 = Set_client_DH_params_answer;
+dh_gen_fail#a69dae02 nonce:int128 server_nonce:int128 new_nonce_hash3:int128 = Set_client_DH_params_answer;
+destroy_auth_key_ok#f660e1d4 = DestroyAuthKeyRes;
+destroy_auth_key_none#0a9f2259 = DestroyAuthKeyRes;
+destroy_auth_key_fail#ea109b13 = DestroyAuthKeyRes;
+---functions---
+req_pq#60469778 nonce:int128 = ResPQ;
+req_pq_multi#be7e8ef1 nonce:int128 = ResPQ;
+req_DH_params#d712e4be nonce:int128 server_nonce:int128 p:string q:string public_key_fingerprint:long encrypted_data:string = Server_DH_Params;
+set_client_DH_params#f5045f1f nonce:int128 server_nonce:int128 encrypted_data:string = Set_client_DH_params_answer;
+destroy_auth_key#d1435160 = DestroyAuthKeyRes;
+---types---
+msgs_ack#62d6b459 msg_ids:Vector<long> = MsgsAck;
+bad_msg_notification#a7eff811 bad_msg_id:long bad_msg_seqno:int error_code:int = BadMsgNotification;
+bad_server_salt#edab447b bad_msg_id:long bad_msg_seqno:int error_code:int new_server_salt:long = BadMsgNotification;
+msgs_state_req#da69fb52 msg_ids:Vector<long> = MsgsStateReq;
+msgs_state_info#04deb57d req_msg_id:long info:string = MsgsStateInfo;
+msgs_all_info#8cc0d131 msg_ids:Vector<long> info:string = MsgsAllInfo;
+msg_detailed_info#276d3ec6 msg_id:long answer_msg_id:long bytes:int status:int = MsgDetailedInfo;
+msg_new_detailed_info#809db6df answer_msg_id:long bytes:int status:int = MsgDetailedInfo;
+msg_resend_req#7d861a08 msg_ids:Vector<long> = MsgResendReq;
+rpc_error#2144ca19 error_code:int error_message:string = RpcError;
+future_salt#0949d9dc valid_since:int valid_until:int salt:long = FutureSalt;
+future_salts#ae500895 req_msg_id:long now:int salts:vector<future_salt> = FutureSalts;
+pong#347773c5 msg_id:long ping_id:long = Pong;
+destroy_session_ok#e22045fc session_id:long = DestroySessionRes;
+destroy_session_none#62d350c9 session_id:long = DestroySessionRes;
+new_session_created#9ec20908 first_msg_id:long unique_id:long server_salt:long = NewSession;
+---functions---
+ping#7abe77ec ping_id:long = Pong;

+ 0 - 0
src/lib/gramjs/tl/static/schema.tl → gramjs/tl/static/schema.tl


+ 57 - 0
gramjs/tl/types-generator/generate.js

@@ -0,0 +1,57 @@
+const path = require('path')
+const fs = require('fs')
+
+const { parseTl } = require('../generationHelpers')
+const templateFn = require('./template')
+
+const INPUT_FILE = path.resolve(__dirname, '../static/api.tl')
+const SCHEMA_FILE = path.resolve(__dirname, '../static/schema.tl')
+
+const OUTPUT_FILE = path.resolve(__dirname, '../api.d.ts')
+
+function main() {
+    const tlContent = fs.readFileSync(INPUT_FILE, 'utf-8')
+    const apiConfig = extractParams(tlContent)
+    const schemeContent = fs.readFileSync(SCHEMA_FILE, 'utf-8')
+    const schemeConfig = extractParams(schemeContent)
+    const types = [...apiConfig.types, ...schemeConfig.types]
+    const functions = [...apiConfig.functions, ...schemeConfig.functions]
+    const constructors = [...apiConfig.constructors, ...schemeConfig.constructors]
+    const generated = templateFn({ types: types, functions: functions, constructors: constructors })
+
+    fs.writeFileSync(OUTPUT_FILE, generated)
+}
+
+function extractParams(fileContent) {
+    const defInterator = parseTl(fileContent, 109)
+    const types = {}
+    const constructors = []
+    const functions = []
+
+    for (const def of defInterator) {
+        if (def.isFunction) {
+            functions.push(def)
+        } else {
+            if (!types[def.result]) {
+                let [namespace, name] = def.result.includes('.') ? def.result.split('.') : [undefined, def.result]
+
+                types[def.result] = {
+                    namespace,
+                    name,
+                    constructors: []
+                }
+            }
+
+            types[def.result].constructors.push(def.namespace ? `${def.namespace}.${def.name}` : def.name)
+            constructors.push(def)
+        }
+    }
+
+    return {
+        types: Object.values(types),
+        constructors,
+        functions
+    }
+}
+
+main()

+ 219 - 0
gramjs/tl/types-generator/template.js

@@ -0,0 +1,219 @@
+// Not sure what they are for.
+const WEIRD_TYPES = new Set(['Bool', 'X', 'Type'])
+
+module.exports = ({ types, constructors, functions }) => {
+    function groupByKey(collection, key) {
+        return collection.reduce((byKey, member) => {
+            const keyValue = member[key] || '_'
+
+            if (!byKey[keyValue]) {
+                byKey[keyValue] = [member]
+            } else {
+                byKey[keyValue].push(member)
+            }
+
+            return byKey
+        }, {})
+    }
+
+    function renderTypes(types, indent) {
+        return types.map(({ name, constructors }) => `
+      ${!constructors.length ? '// ' : ''}export type Type${upperFirst(name)} = ${constructors.map((name) => name)
+            .join(' | ')};
+    `.trim())
+            .join(`\n${indent}`)
+    }
+
+    function renderConstructors(constructors, indent) {
+        return constructors.map(({ name, argsConfig }) => {
+            const argKeys = Object.keys(argsConfig)
+
+            if (!argKeys.length) {
+                return `export class ${upperFirst(name)} extends VirtualClass<void> {};`
+            }
+
+            let hasRequiredArgs = argKeys.some((argName) => argName !== 'flags' && !argsConfig[argName].isFlag)
+
+            return `
+      export class ${upperFirst(name)} extends VirtualClass<{
+${indent}  ${Object.keys(argsConfig)
+            .map((argName) => `
+        ${renderArg(argName, argsConfig[argName])};
+      `.trim())
+            .join(`\n${indent}  `)}
+${indent}}${!hasRequiredArgs ? ` | void` : ''}> {
+${indent}  ${Object.keys(argsConfig)
+            .map((argName) => `
+        ${renderArg(argName, argsConfig[argName])};
+      `.trim())
+            .join(`\n${indent}  `)}
+${indent}};`.trim()
+        })
+        .join(`\n${indent}`)
+    }
+
+    function renderRequests(requests, indent) {
+        return requests.map(({ name, argsConfig, result }) => {
+            const argKeys = Object.keys(argsConfig)
+
+            if (!argKeys.length) {
+                return `export class ${upperFirst(name)} extends Request<void, ${renderResult(result)}> {};`
+            }
+
+            let hasRequiredArgs = argKeys.some((argName) => argName !== 'flags' && !argsConfig[argName].isFlag)
+
+            return `
+      export class ${upperFirst(name)} extends Request<Partial<{
+${indent}  ${argKeys.map((argName) => `
+        ${renderArg(argName, argsConfig[argName])};
+      `.trim())
+            .join(`\n${indent}  `)}
+${indent}}${!hasRequiredArgs ? ` | void` : ''}>, ${renderResult(result)}> {
+${indent}  ${argKeys.map((argName) => `
+        ${renderArg(argName, argsConfig[argName])};
+      `.trim())
+            .join(`\n${indent}  `)}
+${indent}};`.trim()
+        })
+        .join(`\n${indent}`)
+    }
+
+    function renderResult(result) {
+        const vectorMatch = result.match(/[Vv]ector<([\w\d.]+)>/)
+        const isVector = Boolean(vectorMatch)
+        const scalarValue = isVector ? vectorMatch[1] : result
+        const isTlType = Boolean(scalarValue.match(/^[A-Z]/)) || scalarValue.includes('.')
+
+        return renderValueType(scalarValue, isVector, isTlType)
+    }
+
+    function renderArg(argName, argConfig) {
+        const {
+            isVector, isFlag, skipConstructorId, type
+        } = argConfig
+
+        const valueType = renderValueType(type, isVector, !skipConstructorId)
+
+        return `${argName === 'flags' ? '// ' : ''}${argName}${isFlag ? '?' : ''}: ${valueType}`
+    }
+
+    function renderValueType(type, isVector, isTlType) {
+        if (WEIRD_TYPES.has(type)) {
+            return type
+        }
+
+        let resType
+
+        if (typeof type === 'string' && isTlType) {
+            resType = renderTypeName(type)
+        } else {
+            resType = type
+        }
+
+        if (isVector) {
+            resType = `${resType}[]`
+        }
+
+        return resType
+    }
+
+    function renderTypeName(typeName) {
+        return typeName.includes('.') ? typeName.replace('.', '.Type') : `Api.Type${typeName}`
+    }
+
+    function upperFirst(str) {
+        return `${str[0].toUpperCase()}${str.slice(1)}`
+    }
+
+    const typesByNs = groupByKey(types, 'namespace')
+    const constructorsByNs = groupByKey(constructors, 'namespace')
+    const requestsByNs = groupByKey(functions, 'namespace')
+
+    // language=TypeScript
+    return `
+// This file is autogenerated. All changes will be overwritten.
+
+import { BigInteger } from 'big-integer';
+
+export default Api;
+
+namespace Api {
+
+  type AnyClass = new (...args: any[]) => any;
+  type I<T extends AnyClass> = InstanceType<T>;
+  type ValuesOf<T> = T[keyof T];
+  type AnyLiteral = Record<string, any>;
+
+  type Reader = any; // To be defined.
+  type Client = any; // To be defined.
+  type Utils = any; // To be defined.
+
+  type X = unknown;
+  type Type = unknown;
+  type Bool = boolean;
+  type int = number;
+  type int128 = number;
+  type int256 = number;
+  type long = BigInteger;
+  type bytes = Buffer;
+
+  class VirtualClass<Args extends AnyLiteral> {
+    static CONSTRUCTOR_ID: number;
+    static SUBCLASS_OF_ID: number;
+    static className: string;
+    static classType: 'constructor' | 'request';
+
+    static serializeBytes(data: Buffer | string): Buffer;
+    static serializeDate(date: Date | number): Buffer;
+    static fromReader(reader: Reader): VirtualClass<Args>;
+
+    CONSTRUCTOR_ID: number;
+    SUBCLASS_OF_ID: number;
+    className: string;
+    classType: 'constructor' | 'request';
+
+    constructor(args: Args);
+  }
+
+  class Request<Args, Response> extends VirtualClass<Partial<Args>> {
+    static readResult(reader: Reader): Buffer;
+    static resolve(client: Client, utils: Utils): Promise<void>;
+
+    __response: Response;
+  }
+
+  ${renderTypes(typesByNs._, '  ')}
+  ${Object.keys(typesByNs)
+        .map(namespace => namespace !== '_' ? `
+  export namespace ${namespace} {
+    ${renderTypes(typesByNs[namespace], '    ')}
+  }` : '')
+        .join('\n')}
+
+  ${renderConstructors(constructorsByNs._, '  ')}
+  ${Object.keys(constructorsByNs)
+        .map(namespace => namespace !== '_' ? `
+  export namespace ${namespace} {
+    ${renderConstructors(constructorsByNs[namespace], '    ')}
+  }` : '')
+        .join('\n')}
+
+  ${renderRequests(requestsByNs._, '  ')}
+  ${Object.keys(requestsByNs)
+        .map(namespace => namespace !== '_' ? `
+  export namespace ${namespace} {
+    ${renderRequests(requestsByNs[namespace], '    ')}
+  }` : '')
+        .join('\n')}
+
+  export type AnyRequest = ${requestsByNs._.map(({ name }) => upperFirst(name))
+        .join(' | ')}
+    | ${Object.keys(requestsByNs)
+        .filter(ns => ns !== '_')
+        .map(ns => requestsByNs[ns].map(({ name }) => `${ns}.${upperFirst(name)}`)
+            .join(' | '))
+        .join('\n    | ')};
+
+}
+`
+}

+ 186 - 0
index.js

@@ -0,0 +1,186 @@
+const fs = require('fs')
+const path = require('path')
+const glob = require('glob')
+
+class TempWorkDir {
+    /**
+     * Switches the working directory to be the one on which this file lives.
+     */
+    constructor(dir) {
+        this.original = null
+        this.dir = dir || path.join(__filename, '..')
+    }
+
+    open() {
+        this.original = __dirname
+        fs.mkdirSync(this.dir, { recursive: true })
+        process.chdir(this.dir)
+        return this
+    }
+
+    close() {
+        process.chdir(this.original)
+    }
+}
+
+const GENERATOR_DIR = './gramjs_generator'
+const LIBRARY_DIR = './gramjs'
+
+const ERRORS_IN = `${GENERATOR_DIR}/data/errors.csv`
+const ERRORS_OUT = `${LIBRARY_DIR}/errors/RPCErrorList.js`
+
+const METHODS_IN = `${GENERATOR_DIR}/data/methods.csv`
+
+// Which raw API methods are covered by *friendly* methods in the client?
+const FRIENDLY_IN = `${GENERATOR_DIR}/data/friendly.csv`
+
+const TLOBJECT_IN_TLS = glob.sync(`${GENERATOR_DIR}/data/*.tl`)
+const TLOBJECT_OUT = `${LIBRARY_DIR}/tl`
+const IMPORT_DEPTH = 2
+
+const DOCS_IN_RES = `../${GENERATOR_DIR}/data/html`
+const DOCS_OUT = `./docs`
+
+const generate = (which, action = 'gen') => {
+    const {
+        parseErrors,
+        parseMethods,
+        parseTl,
+        findLayer,
+    } = require('./gramjs_generator/parsers')
+
+    const {
+        generateErrors,
+        generateTLObjects,
+        generateDocs,
+        cleanTLObjects,
+    } = require('./gramjs_generator/generators')
+
+    const [layer] = TLOBJECT_IN_TLS.map(findLayer).filter(Boolean)
+    const errors = [...parseErrors(ERRORS_IN)]
+    const methods = [
+        ...parseMethods(
+            METHODS_IN,
+            FRIENDLY_IN,
+            errors.reduce((errors, error) => {
+                errors[error.stringCode] = error
+                return errors
+            }, {})
+        ),
+    ]
+
+    const tlobjects = TLOBJECT_IN_TLS.reduce(
+        (files, file) => [...files, ...parseTl(file, layer, methods)],
+        []
+    )
+
+    if (!which || which.length === 0) {
+        which.push('tl', 'errors')
+    }
+
+    const clean = action === 'clean'
+    action = clean ? 'Cleaning' : 'Generating'
+
+    if (which.includes('all')) {
+        which.splice(which.indexOf('all'), 1)
+
+        for (const x of ['tl', 'errors', 'docs']) {
+            if (!which.includes(x)) {
+                which.push(x)
+            }
+        }
+    }
+
+    if (which.includes('tl')) {
+        which.splice(which.indexOf('tl'), 1)
+        console.log(action, 'TLObjects...')
+
+        if (clean) {
+            cleanTLObjects(TLOBJECT_OUT)
+        } else {
+            generateTLObjects(tlobjects, layer, IMPORT_DEPTH, TLOBJECT_OUT)
+        }
+    }
+
+    if (which.includes('errors')) {
+        which.splice(which.indexOf('errors'), 1)
+        console.log(action, 'RPCErrors...')
+
+        if (clean) {
+            if (fs.statSync(ERRORS_OUT).isFile()) {
+                fs.unlinkSync(ERRORS_OUT)
+            }
+        } else {
+            const file = fs.createWriteStream(ERRORS_OUT)
+            generateErrors(errors, file)
+        }
+    }
+
+    if (which.includes('docs')) {
+        which.splice(which.indexOf('docs'), 1)
+        console.log(action, 'documentation...')
+
+        if (clean) {
+            if (fs.statSync(DOCS_OUT)) {
+                fs.rmdirSync(DOCS_OUT)
+            }
+        } else {
+            const tmp = new TempWorkDir(DOCS_OUT).open()
+            generateDocs(tlobjects, methods, layer, DOCS_IN_RES)
+            tmp.close()
+        }
+    }
+
+    if (which.includes('json')) {
+        which.splice(which.indexOf('json'), 1)
+        console.log(action, 'JSON schema...')
+
+        const jsonFiles = TLOBJECT_IN_TLS.map(
+            (x) => x.slice(0, x.lastIndexOf('.')) + '.json'
+        )
+
+        if (clean) {
+            for (const file of jsonFiles) {
+                if (fs.statSync(file).isFile()) {
+                    fs.unlinkSync(file)
+                }
+            }
+        } else {
+            const genJson = (fin, fout) => {
+                const meths = []
+                const constructors = []
+
+                for (const tl of parseTl(fin, layer)) {
+                    if (tl.isFunction) {
+                        meths.push(tl.toJson())
+                    } else {
+                        constructors.push(tl.toJson())
+                    }
+                }
+
+                const what = { constructors, methods }
+                fs.writeFileSync(fout, JSON.stringify(what, null, 2))
+            }
+
+            for (let i = 0; i < TLOBJECT_IN_TLS.length; i++) {
+                const fin = TLOBJECT_IN_TLS[i]
+                const fout = jsonFiles[i]
+                genJson(fin, fout)
+            }
+        }
+    }
+
+    if (which.length) {
+        console.log('The following items were not understood:', which)
+        console.log('  Consider using only "tl", "errors" and/or "docs".')
+        console.log(
+            '  Using only "clean" will clean them. "all" to act on all.'
+        )
+        console.log('  For instance "gen tl errors".')
+    }
+}
+
+const { argv } = process
+if (argv.length > 2 && argv[2] === 'gen') {
+    generate(argv.slice(3))
+}

+ 188 - 0
jest.config.js

@@ -0,0 +1,188 @@
+// For a detailed explanation regarding each configuration property, visit:
+// https://jestjs.io/docs/en/configuration.html
+
+module.exports = {
+    // All imported modules in your tests should be mocked automatically
+    // automock: false,
+
+    // Stop running tests after `n` failures
+    // bail: 0,
+
+    // Respect "browser" field in package.json when resolving modules
+    // browser: false,
+
+    // The directory where Jest should store its cached dependency information
+    // cacheDirectory: "C:\\Users\\painor\\AppData\\Local\\Temp\\jest",
+
+    // Automatically clear mock calls and instances between every test
+    clearMocks: true,
+
+    // Indicates whether the coverage information should be collected while executing the test
+    // collectCoverage: false,
+
+    // An array of glob patterns indicating a set of files for which coverage information should be collected
+    // collectCoverageFrom: null,
+
+    // The directory where Jest should output its coverage files
+    coverageDirectory: 'coverage',
+
+    // An array of regexp pattern strings used to skip coverage collection
+    // coveragePathIgnorePatterns: [
+    //   "\\\\node_modules\\\\"
+    // ],
+
+    // A list of reporter names that Jest uses when writing coverage reports
+    // coverageReporters: [
+    //   "json",
+    //   "text",
+    //   "lcov",
+    //   "clover"
+    // ],
+
+    // An object that configures minimum threshold enforcement for coverage results
+    // coverageThreshold: null,
+
+    // A path to a custom dependency extractor
+    // dependencyExtractor: null,
+
+    // Make calling deprecated APIs throw helpful error messages
+    // errorOnDeprecated: false,
+
+    // Force coverage collection from ignored files using an array of glob patterns
+    // forceCoverageMatch: [],
+
+    // A path to a module which exports an async function that is triggered once before all test suites
+    // globalSetup: null,
+
+    // A path to a module which exports an async function that is triggered once after all test suites
+    // globalTeardown: null,
+
+    // A set of global variables that need to be available in all test environments
+    // globals: {},
+
+    // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers.
+    // maxWorkers: "50%",
+
+    // An array of directory names to be searched recursively up from the requiring module's location
+    // moduleDirectories: [
+    //   "node_modules"
+    // ],
+
+    // An array of file extensions your modules use
+    // moduleFileExtensions: [
+    //   "js",
+    //   "json",
+    //   "jsx",
+    //   "ts",
+    //   "tsx",
+    //   "node"
+    // ],
+
+    // A map from regular expressions to module names that allow to stub out resources with a single module
+    // moduleNameMapper: {},
+
+    // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
+    // modulePathIgnorePatterns: [],
+
+    // Activates notifications for test results
+    // notify: false,
+
+    // An enum that specifies notification mode. Requires { notify: true }
+    // notifyMode: "failure-change",
+
+    // A preset that is used as a base for Jest's configuration
+    // preset: null,
+
+    // Run tests from one or more projects
+    // projects: null,
+
+    // Use this configuration option to add custom reporters to Jest
+    // reporters: undefined,
+
+    // Automatically reset mock state between every test
+    // resetMocks: false,
+
+    // Reset the module registry before running each individual test
+    // resetModules: false,
+
+    // A path to a custom resolver
+    // resolver: null,
+
+    // Automatically restore mock state between every test
+    // restoreMocks: false,
+
+    // The root directory that Jest should scan for tests and modules within
+    // rootDir: null,
+
+    // A list of paths to directories that Jest should use to search for files in
+    // roots: [
+    //   "<rootDir>"
+    // ],
+
+    // Allows you to use a custom runner instead of Jest's default test runner
+    // runner: "jest-runner",
+
+    // The paths to modules that run some code to configure or set up the testing environment before each test
+    // setupFiles: [],
+
+    // A list of paths to modules that run some code to configure or set up the testing framework before each test
+    // setupFilesAfterEnv: [],
+
+    // A list of paths to snapshot serializer modules Jest should use for snapshot testing
+    // snapshotSerializers: [],
+
+    // The test environment that will be used for testing
+    testEnvironment: 'node',
+
+    // Options that will be passed to the testEnvironment
+    // testEnvironmentOptions: {},
+
+    // Adds a location field to test results
+    // testLocationInResults: false,
+
+    // The glob patterns Jest uses to detect test files
+    // testMatch: [
+    //   "**/__tests__/**/*.[jt]s?(x)",
+    //   "**/?(*.)+(spec|test).[tj]s?(x)"
+    // ],
+
+    // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
+    // testPathIgnorePatterns: [
+    //   "\\\\node_modules\\\\"
+    // ],
+
+    // The regexp pattern or array of patterns that Jest uses to detect test files
+    // testRegex: [],
+
+    // This option allows the use of a custom results processor
+    // testResultsProcessor: null,
+
+    // This option allows use of a custom test runner
+    // testRunner: "jasmine2",
+
+    // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href
+    // testURL: "http://localhost",
+
+    // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout"
+    // timers: "real",
+
+    // A map from regular expressions to paths to transformers
+    // transform: null,
+
+    // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
+    // transformIgnorePatterns: [
+    //   "\\\\node_modules\\\\"
+    // ],
+
+    // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
+    // unmockedModulePathPatterns: undefined,
+
+    // Indicates whether each individual test should be reported during the run
+    // verbose: null,
+
+    // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
+    // watchPathIgnorePatterns: [],
+
+    // Whether to use watchman for file crawling
+    // watchman: true,
+}

Diferenças do arquivo suprimidas por serem muito extensas
+ 462 - 362
package-lock.json


+ 41 - 79
package.json

@@ -1,95 +1,57 @@
 {
 {
-  "name": "telegram-t",
-  "version": "1.0.0-0",
-  "description": "",
+  "name": "telegram",
+  "version": "1.0.0-alpha.2",
+  "description": "NodeJS MTProto API Telegram client library,",
   "main": "index.js",
   "main": "index.js",
   "scripts": {
   "scripts": {
-    "dev": "shx mkdir -p dist/ && shx cp node_modules/tdweb/dist/* dist/ && parcel src/index.html",
-    "build:staging:gramjs": "parcel build src/index.html --public-url ./",
-    "build:contest:tdlib": "./deploy/contest-tdlib.sh",
-    "build:contest:gramjs": "./deploy/contest-gramjs.sh",
-    "build:github:all": "./deploy/github.sh",
-    "test": "echo \"Error: no test specified\" && exit 1",
-    "lint": "eslint . --ext .ts,.tsx",
-    "lint:fix": "eslint . --ext .ts,.tsx --fix",
-    "gramjs:types": "node ./src/lib/gramjs/tl/types-generator/generate.js"
+    "test": "jest",
+    "lint": "eslint .",
+    "postinstall": "node index.js gen tl errors"
   },
   },
-  "husky": {
-    "hooks": {
-      "pre-commit": "lint-staged -- --fix"
-    }
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/gram-js/gramjs.git"
   },
   },
-  "lint-staged": {
-    "*.{ts,tsx}": "eslint"
+  "browser": {
+    "fs": false
   },
   },
-  "author": "Alexander Zinchuk (alexander@zinchuk.com)",
-  "license": "GPL-3.0-or-later",
-  "devDependencies": {
-    "@babel/core": "^7.7.2",
-    "@babel/plugin-proposal-class-properties": "^7.7.0",
-    "@babel/plugin-transform-runtime": "^7.6.2",
-    "@types/react": "^16.9.11",
-    "@types/react-dom": "^16.9.3",
-    "@typescript-eslint/eslint-plugin": "^2.6.1",
-    "@typescript-eslint/parser": "^2.6.1",
-    "babel-eslint": "^10.0.3",
-    "babel-preset-env": "^1.7.0",
-    "eslint": "^6.6.0",
-    "eslint-config-airbnb-typescript": "^6.0.0",
-    "eslint-config-react-app": "^5.0.2",
-    "eslint-plugin-flowtype": "^3.13.0",
-    "eslint-plugin-import": "^2.18.2",
-    "eslint-plugin-jsx-a11y": "^6.2.3",
-    "eslint-plugin-no-async-without-await": "^1.2.0",
-    "eslint-plugin-react": "^7.16.0",
-    "eslint-plugin-react-hooks": "^1.7.0",
-    "husky": "^3.0.9",
-    "lint-staged": "^9.4.2",
-    "parcel": "^1.12.4",
-    "react": "^16.11.0",
-    "sass": "^1.23.3",
-    "shx": "^0.3.2",
-    "terser": "^4.3.9",
-    "typescript": "^3.6.4"
+  "license": "MIT",
+  "bugs": {
+    "url": "https://github.com/gram-js/gramjs/issues"
   },
   },
+  "homepage": "https://github.com/gram-js/gramjs#readme",
   "dependencies": {
   "dependencies": {
-<<<<<<< HEAD
-<<<<<<< HEAD
+    "@babel/core": "^7.7.7",
+    "@babel/plugin-proposal-class-properties": "^7.7.0",
+    "@babel/preset-env": "^7.7.7",
     "aes-js": "^3.1.2",
     "aes-js": "^3.1.2",
+    "babel-loader": "^8.0.6",
+    "babel-register": "^6.26.0",
+    "better-sqlite3": "^5.4.3",
+    "chalk": "^2.4.2",
     "crc": "^3.8.0",
     "crc": "^3.8.0",
-    "crypto": "^1.0.1",
-    "emoji-regex": "^8.0.0",
-    "events": "^3.0.0",
+    "csv-parse": "^4.4.6",
+    "fast-csv": "^3.4.0",
+    "glob": "^7.1.4",
+    "mime-types": "^2.1.25",
+    "net": "^1.0.2",
     "node-gzip": "^1.1.2",
     "node-gzip": "^1.1.2",
     "node-rsa": "^1.0.6",
     "node-rsa": "^1.0.6",
-    "python-struct": "^1.1.2",
+    "python-struct": "^1.1.1",
+    "regenerator-runtime": "^0.13.3",
+    "sqlite3": "^4.1.1",
+    "stack-trace": "0.0.10",
     "string-format": "^2.0.0",
     "string-format": "^2.0.0",
-    "td": "^0.3.2",
-=======
-=======
-    "async-mutex": "^0.1.4",
-<<<<<<< HEAD
->>>>>>> 1a0b5c54... GramJS: Fix images loading: add `async-mutex`; Fix signed LE ints; Bring back `readExactly`
-    "big-integer": "latest",
-=======
-    "big-integer": "painor/BigInteger.js",
->>>>>>> ddb2a0ed... GramJS: Fix downloading images of uncommon (small) size
-    "croppie": "^2.6.4",
-    "emoji-regex": "^8.0.0",
-    "events": "^3.0.0",
-<<<<<<< HEAD
->>>>>>> 1ab480fe... Gram JS: Remove deps; Fix Factorizator and remove leemon lib
-    "tdweb": "^1.5.0",
-    "websocket": "^1.0.30",
-<<<<<<< HEAD
-    "big-integer": "latest"
-=======
-    "pako": "latest"
->>>>>>> f8f1a405... GramJS : Remove zlib and other small fixes.
-=======
-    "pako": "latest",
-    "tdweb": "^1.5.0",
     "websocket": "^1.0.30"
     "websocket": "^1.0.30"
->>>>>>> 1a0b5c54... GramJS: Fix images loading: add `async-mutex`; Fix signed LE ints; Bring back `readExactly`
+  },
+  "devDependencies": {
+    "@babel/plugin-transform-async-to-generator": "^7.7.0",
+    "babel-eslint": "^10.0.3",
+    "babel-jest": "^24.9.0",
+    "eslint": "^6.5.1",
+    "jest": "^24.9.0",
+    "webpack": "^4.41.2",
+    "webpack-cli": "^3.3.10",
+    "websocket-as-promised": "^0.10.1"
   }
   }
 }
 }

+ 0 - 13
src/@types/global.d.ts

@@ -1,13 +0,0 @@
-declare const process: { env: Record<string, string> };
-
-type AnyLiteral = Record<string, any>;
-type AnyClass = new (...args: any[]) => any;
-
-type Country = {
-  id: string;
-  name: string;
-  flag: string;
-  code: string;
-};
-
-declare module '*.png';

+ 0 - 64
src/api/gramjs/builders/chats.ts

@@ -1,64 +0,0 @@
-import { MTProto } from '../../../lib/gramjs';
-import { ApiChat } from '../../types';
-import { isPeerChat, isPeerUser } from './peers';
-import { buildApiPhotoLocations } from './common';
-
-export function buildApiChatFromDialog(dialog: MTProto.dialog, peerEntity: MTProto.user | MTProto.chat): ApiChat {
-  return {
-    id: getApiChatIdFromMtpPeer(dialog.peer),
-    type: {
-      '@type': getApiChatTypeFromMtpPeer(dialog.peer),
-      ...(isPeerUser(dialog.peer) && { user_id: dialog.peer.userId }),
-    },
-    title: getApiChatTitleFromMtpPeer(dialog.peer, peerEntity),
-    photo_locations: buildApiPhotoLocations(peerEntity),
-    last_read_outbox_message_id: dialog.readOutboxMaxId,
-    last_read_inbox_message_id: dialog.readInboxMaxId,
-    unread_count: dialog.unreadCount,
-    unread_mention_count: 0, // TODO
-    is_pinned: dialog.pinned || false,
-  };
-}
-
-export function getApiChatIdFromMtpPeer(peer: MTProto.Peer) {
-  if (isPeerUser(peer)) {
-    return peer.userId;
-  } else if (isPeerChat(peer)) {
-    return -peer.chatId;
-  } else {
-    return -peer.channelId;
-  }
-}
-
-export function getApiChatTypeFromMtpPeer(peer: MTProto.Peer) {
-  if (isPeerUser(peer)) {
-    return 'chatTypePrivate';
-  } else if (isPeerChat(peer)) {
-    return 'chatTypeBasicGroup';
-  } else {
-    // TODO Support channels, supergroups, etc.
-    return 'chatTypeBasicGroup';
-  }
-}
-
-export function getPeerKey(peer: MTProto.Peer) {
-  if (isPeerUser(peer)) {
-    return `user${peer.userId}`;
-  } else if (isPeerChat(peer)) {
-    return `chat${peer.chatId}`;
-  } else {
-    return `chat${peer.channelId}`;
-  }
-}
-
-export function getApiChatTitleFromMtpPeer(peer: MTProto.Peer, peerEntity: MTProto.user | MTProto.chat) {
-  if (isPeerUser(peer)) {
-    return getUserName(peerEntity as MTProto.user);
-  } else {
-    return (peerEntity as MTProto.chat).title;
-  }
-}
-
-function getUserName(user: MTProto.user) {
-  return user.firstName ? `${user.firstName}${user.lastName ? ` ${user.lastName}` : ''}` : undefined;
-}

+ 0 - 34
src/api/gramjs/builders/common.ts

@@ -1,34 +0,0 @@
-import { MTProto } from '../../../lib/gramjs';
-import { ApiFileLocation } from '../../types';
-
-export function buildApiPhotoLocations(entity: MTProto.user | MTProto.chat): {
-  small: ApiFileLocation;
-  big: ApiFileLocation;
-} | undefined {
-  if (!entity.photo) {
-    return undefined;
-  }
-
-  const { photoSmall, photoBig, dcId } = entity.photo as (MTProto.userProfilePhoto | MTProto.chatPhoto);
-
-  return {
-    small: {
-      ...photoSmall,
-      dcId,
-    },
-    big: {
-      ...photoBig,
-      dcId,
-    },
-  };
-}
-
-export function bytesToDataUri(bytes: Uint8Array, shouldOmitPrefix = false, mimeType: string = 'image/jpg') {
-  const prefix = shouldOmitPrefix ? '' : `data:${mimeType};base64,`;
-
-  return `${prefix}${btoa(
-    bytes.reduce((data, byte) => {
-      return data + String.fromCharCode(byte);
-    }, ''),
-  )}`;
-}

+ 0 - 208
src/api/gramjs/builders/messages.ts

@@ -1,208 +0,0 @@
-import { gramJsApi, MTProto } from '../../../lib/gramjs';
-import { strippedPhotoToJpg } from '../../../lib/gramjs/Utils';
-import {
-  ApiMessage, ApiMessageForwardInfo, ApiPhoto, ApiPhotoCachedSize, ApiPhotoSize, ApiSticker,
-} from '../../types';
-
-import { getApiChatIdFromMtpPeer } from './chats';
-import { isPeerUser } from './peers';
-import { bytesToDataUri } from './common';
-
-const ctors = gramJsApi.constructors;
-
-// TODO Maybe we do not need it.
-const DEFAULT_USER_ID = 0;
-
-export function buildApiMessage(mtpMessage: MTProto.Message): ApiMessage {
-  if (
-    !(mtpMessage instanceof ctors.Message)
-    && !(mtpMessage instanceof ctors.MessageService)) {
-    throw new Error('Not supported');
-  }
-
-  const isPrivateToMe = mtpMessage.out !== true && isPeerUser(mtpMessage.toId);
-  const chatId = isPrivateToMe
-    ? (mtpMessage.fromId || DEFAULT_USER_ID)
-    : getApiChatIdFromMtpPeer(mtpMessage.toId);
-
-  return buildApiMessageWithChatId(chatId, mtpMessage);
-}
-
-export function buildApiMessageFromShort(
-  mtpMessage: MTProto.updateShortMessage,
-): ApiMessage {
-  const chatId = getApiChatIdFromMtpPeer({ userId: mtpMessage.userId } as MTProto.Peer);
-
-  return buildApiMessageWithChatId(chatId, {
-    ...mtpMessage,
-    // TODO Current user ID needed here.
-    fromId: mtpMessage.out ? DEFAULT_USER_ID : mtpMessage.userId,
-  });
-}
-
-export function buildApiMessageFromShortChat(
-  mtpMessage: MTProto.updateShortChatMessage,
-): ApiMessage {
-  const chatId = getApiChatIdFromMtpPeer({ chatId: mtpMessage.chatId } as MTProto.Peer);
-
-  return buildApiMessageWithChatId(chatId, mtpMessage);
-}
-
-export function buildApiMessageWithChatId(
-  chatId: number,
-  mtpMessage: Pick<MTProto.message, (
-    'id' | 'out' | 'message' | 'date' | 'fromId' | 'fwdFrom' | 'replyToMsgId' | 'media'
-  )>,
-): ApiMessage {
-  const sticker = mtpMessage.media && buildSticker(mtpMessage.media);
-  const photo = mtpMessage.media && buildPhoto(mtpMessage.media);
-  const textContent = mtpMessage.message && {
-    '@type': 'formattedText' as 'formattedText',
-    text: mtpMessage.message,
-  };
-  const caption = textContent && photo ? textContent : null;
-  const text = textContent && !photo ? textContent : null;
-
-  return {
-    id: mtpMessage.id,
-    chat_id: chatId,
-    is_outgoing: Boolean(mtpMessage.out),
-    content: {
-      '@type': 'message',
-      ...(text && { text }),
-      ...(sticker && { sticker }),
-      ...(photo && { photo }),
-      ...(caption && { caption }),
-    },
-    date: mtpMessage.date,
-    sender_user_id: mtpMessage.fromId || DEFAULT_USER_ID,
-    reply_to_message_id: mtpMessage.replyToMsgId,
-    ...(mtpMessage.fwdFrom && { forward_info: buildApiMessageForwardInfo(mtpMessage.fwdFrom) }),
-  };
-}
-
-function buildApiMessageForwardInfo(fwdFrom: MTProto.messageFwdHeader): ApiMessageForwardInfo {
-  return {
-    '@type': 'messageForwardInfo',
-    from_chat_id: fwdFrom.fromId,
-    origin: {
-      '@type': 'messageForwardOriginUser',
-      // TODO Handle when empty `fromId`.
-      sender_user_id: fwdFrom.fromId,
-      // TODO @gramjs Not supported?
-      // sender_user_name: fwdFrom.fromName,
-    },
-  };
-}
-
-function buildSticker(media: MTProto.MessageMedia): ApiSticker | null {
-  if (
-    !(media instanceof ctors.MessageMediaDocument)
-    || !media.document
-    || !(media.document instanceof ctors.Document)
-  ) {
-    return null;
-  }
-
-  const stickerAttribute = media.document.attributes
-    .find((attr: any): attr is MTProto.documentAttributeSticker => (
-      attr instanceof ctors.DocumentAttributeSticker
-    ));
-
-  if (!stickerAttribute) {
-    return null;
-  }
-
-  const emoji = stickerAttribute.alt;
-  const isAnimated = media.document.mimeType === 'application/x-tgsticker';
-  const thumb = media.document.thumbs && media.document.thumbs.find((s: any) => s instanceof ctors.PhotoCachedSize);
-  const thumbnail = thumb && buildApiPhotoCachedSize(thumb as MTProto.photoCachedSize);
-  const { width, height } = thumbnail || {};
-
-  return {
-    '@type': 'sticker',
-    emoji,
-    is_animated: isAnimated,
-    width,
-    height,
-    thumbnail,
-  };
-}
-
-function buildPhoto(media: MTProto.MessageMedia): ApiPhoto | null {
-  if (!(media instanceof ctors.MessageMediaPhoto) || !media.photo || !(media.photo instanceof ctors.Photo)) {
-    return null;
-  }
-
-  const hasStickers = Boolean(media.photo.hasStickers);
-  const thumb = media.photo.sizes.find((s: any) => s instanceof ctors.PhotoStrippedSize);
-  const sizes = media.photo.sizes
-    .filter((s: any): s is MTProto.photoSize => s instanceof ctors.PhotoSize)
-    .map(buildApiPhotoSize);
-  const mSize = sizes.find((s: any) => s.type === 'm');
-  const { width, height } = mSize as ApiPhotoSize;
-  const minithumbnail: ApiPhoto['minithumbnail'] = thumb && {
-    '@type': 'minithumbnail',
-    data: bytesToDataUri(strippedPhotoToJpg((thumb as MTProto.photoStrippedSize).bytes as Buffer), true),
-    width,
-    height,
-  };
-
-  return {
-    '@type': 'photo',
-    has_stickers: hasStickers,
-    minithumbnail,
-    sizes,
-  };
-}
-
-function buildApiPhotoCachedSize(photoSize: MTProto.photoCachedSize): ApiPhotoCachedSize {
-  const {
-    w, h, type, bytes,
-  } = photoSize;
-  const dataUri = bytesToDataUri(strippedPhotoToJpg(bytes as Buffer));
-
-  return {
-    '@type': 'photoCachedSize',
-    width: w,
-    height: h,
-    type: type as ('m' | 'x' | 'y'),
-    dataUri,
-  };
-}
-
-function buildApiPhotoSize(photoSize: MTProto.photoSize): ApiPhotoSize {
-  const { w, h, type } = photoSize;
-
-  return {
-    '@type': 'photoSize',
-    width: w,
-    height: h,
-    type: type as ('m' | 'x' | 'y'),
-  };
-}
-
-// We only support 100000 local pending messages here and expect it will not interfere with real IDs.
-let localMessageCounter = -1;
-
-export function buildLocalMessage(chatId: number, text: string): ApiMessage {
-  const localId = localMessageCounter--;
-
-  return {
-    id: localId,
-    chat_id: chatId,
-    content: {
-      '@type': 'message',
-      text: {
-        '@type': 'formattedText',
-        text,
-      },
-    },
-    date: Math.round(Date.now() / 1000),
-    is_outgoing: true,
-    sender_user_id: DEFAULT_USER_ID, // TODO
-    sending_state: {
-      '@type': 'messageSendingStatePending',
-    },
-  };
-}

+ 0 - 13
src/api/gramjs/builders/peers.ts

@@ -1,13 +0,0 @@
-import { MTProto } from '../../../lib/gramjs';
-
-export function isPeerUser(peer: MTProto.Peer): peer is MTProto.peerUser {
-  return peer.hasOwnProperty('userId');
-}
-
-export function isPeerChat(peer: MTProto.Peer): peer is MTProto.peerChat {
-  return peer.hasOwnProperty('chatId');
-}
-
-export function isPeerChannel(peer: MTProto.Peer): peer is MTProto.peerChannel {
-  return peer.hasOwnProperty('channelId');
-}

+ 0 - 39
src/api/gramjs/builders/users.ts

@@ -1,39 +0,0 @@
-import { gramJsApi, MTProto } from '../../../lib/gramjs';
-import { ApiUser, ApiUserStatus } from '../../types';
-import { buildApiPhotoLocations } from './common';
-
-const ctors = gramJsApi.constructors;
-
-export function buildApiUser(mtpUser: MTProto.user): ApiUser {
-  return {
-    id: mtpUser.id,
-    type: {
-      // TODO Support other user types.
-      '@type': 'userTypeRegular',
-    },
-    first_name: mtpUser.firstName,
-    last_name: mtpUser.lastName,
-    username: mtpUser.username || '',
-    phone_number: mtpUser.phone || '',
-    profile_photo_locations: buildApiPhotoLocations(mtpUser),
-    status: buildApiUserStatus(mtpUser.status),
-  };
-}
-
-export function buildApiUserStatus(mtpStatus?: MTProto.UserStatus): ApiUserStatus | undefined {
-  if (!mtpStatus || mtpStatus instanceof ctors.UserStatusEmpty) {
-    return { '@type': 'userStatusEmpty' };
-  } else if (mtpStatus instanceof ctors.UserStatusOnline) {
-    return { '@type': 'userStatusOnline' };
-  } else if (mtpStatus instanceof ctors.UserStatusOffline) {
-    return { '@type': 'userStatusOffline', was_online: mtpStatus.wasOnline };
-  } else if (mtpStatus instanceof ctors.UserStatusRecently) {
-    return { '@type': 'userStatusRecently' };
-  } else if (mtpStatus instanceof ctors.UserStatusLastWeek) {
-    return { '@type': 'userStatusLastWeek' };
-  } else if (mtpStatus instanceof ctors.UserStatusLastMonth) {
-    return { '@type': 'userStatusLastMonth' };
-  }
-
-  return undefined;
-}

+ 0 - 212
src/api/gramjs/client.ts

@@ -1,212 +0,0 @@
-<<<<<<< HEAD
-<<<<<<< HEAD
-import {
-  TelegramClient, session, GramJsApi, MTProto,
-} from '../../lib/gramjs';
-=======
-import { TelegramClient, sessions, Api as GramJs } from '../../lib/gramjs';
->>>>>>> 42589b8b... GramJS: Add `LocalStorageSession` with keys and hashes for all DCs
-=======
-import {
-  TelegramClient, sessions, Api as GramJs, connection,
-} from '../../lib/gramjs';
->>>>>>> 48d2d818... Support reconnect and re-sync
-import { Logger as GramJsLogger } from '../../lib/gramjs/extensions';
-
-import { DEBUG } from '../../config';
-import {
-  onAuthReady, onRequestCode, onRequestPassword, onRequestPhoneNumber, onRequestRegistration,
-} from './connectors/auth';
-import { onGramJsUpdate } from './onGramJsUpdate';
-<<<<<<< HEAD
-<<<<<<< HEAD
-import localDb from './localDb';
-import { buildInputPeerPhotoFileLocation } from './inputHelpers';
-import { ApiFileLocation } from '../types';
-<<<<<<< HEAD
-=======
-=======
->>>>>>> f70d85dd... Gram JS: Replace generated `tl/*` contents with runtime logic; TypeScript typings
-
-GramJsLogger.getLogger().level = 'debug';
->>>>>>> dda7e47e... Fix images loading; Various Gram JS fixes; Refactor Gram JS Logger
-=======
-import queuedDownloadMedia from './connectors/media';
-
-GramJsLogger.setLevel(DEBUG ? 'debug' : 'warn');
-<<<<<<< HEAD
->>>>>>> ddb2a0ed... GramJS: Fix downloading images of uncommon (small) size
-=======
->>>>>>> 073c3e12... GramJS: Implement signup
-
-const gramJsUpdateEventBuilder = { build: (update: object) => update };
-
-let client: TelegramClient;
-let isConnected = false;
-
-export async function init(sessionId: string) {
-  const session = new sessions.LocalStorageSession(sessionId);
-  client = new TelegramClient(
-    session,
-    process.env.TELEGRAM_T_API_ID,
-    process.env.TELEGRAM_T_API_HASH,
-    { useWSS: true } as any,
-  );
-
-  client.addEventHandler(onGramJsUpdate, gramJsUpdateEventBuilder);
-  client.addEventHandler(onUpdate, gramJsUpdateEventBuilder);
-
-  try {
-    if (DEBUG) {
-      // eslint-disable-next-line no-console
-      console.log('[GramJs/worker] CONNECTING');
-    }
-
-    await client.start({
-      phone: onRequestPhoneNumber,
-      code: onRequestCode,
-      password: onRequestPassword,
-      firstAndLastNames: onRequestRegistration,
-    } as any);
-
-    const newSessionId = session.save();
-
-    if (DEBUG) {
-      // eslint-disable-next-line no-console
-      console.log('[GramJs/worker] CONNECTED as ', newSessionId);
-    }
-
-    onAuthReady(newSessionId);
-  } catch (err) {
-    if (DEBUG) {
-      // eslint-disable-next-line no-console
-      console.log('[GramJs/worker] CONNECTING ERROR', err);
-    }
-
-    throw err;
-  }
-}
-
-<<<<<<< HEAD
-<<<<<<< HEAD
-export async function invokeRequest<T extends InstanceType<GramJsApi.AnyRequest>>(request: T) {
-=======
-=======
-export async function destroy() {
-  await client.destroy();
-}
-
->>>>>>> 5143ac4c... Fixes for Log Out
-function onUpdate(update: any) {
-  if (update instanceof connection.UpdateConnectionState) {
-    isConnected = update.state === connection.UpdateConnectionState.states.connected;
-  }
-}
-
-export async function invokeRequest<T extends GramJs.AnyRequest>(request: T, shouldHandleUpdates = false) {
->>>>>>> 48d2d818... Support reconnect and re-sync
-  if (DEBUG) {
-    if (!isConnected) {
-      // eslint-disable-next-line no-console
-      console.warn(`[GramJs/client] INVOKE ${request.className} ERROR: Client is not connected`);
-      return undefined;
-    }
-
-    // eslint-disable-next-line no-console
-    console.log(`[GramJs/client] INVOKE ${request.className}`);
-  }
-
-  const result = await client.invoke(request);
-
-  if (DEBUG) {
-    // eslint-disable-next-line no-console
-    console.log(`[GramJs/client] INVOKE RESPONSE ${request.className}`, result);
-  }
-
-  return result;
-}
-
-<<<<<<< HEAD
-<<<<<<< HEAD
-export function downloadFile(id: number, fileLocation: ApiFileLocation, dcId?: number) {
-  return client.downloadFile(
-    buildInputPeerPhotoFileLocation({ id, fileLocation }),
-    true,
-=======
-export function downloadFile(chatOrUserId: number, fileLocation: ApiFileLocation) {
-  const { dcId, volumeId, localId } = fileLocation;
-
-  return client.downloadFile(
-    buildInputPeerPhotoFileLocation(chatOrUserId, volumeId, localId),
->>>>>>> dda7e47e... Fix images loading; Various Gram JS fixes; Refactor Gram JS Logger
-    { dcId },
-  );
-}
-
-<<<<<<< HEAD
-=======
-export function downloadMessageImage(message: MTP.message) {
-  return client.downloadMedia(message, { sizeType: 'x' });
-}
-
->>>>>>> dda7e47e... Fix images loading; Various Gram JS fixes; Refactor Gram JS Logger
-function postProcess(name: string, anyResult: any, args: AnyLiteral) {
-  switch (name) {
-    case 'GetDialogsRequest': {
-      const result: MTP.messages$Dialogs = anyResult;
-
-      if (!result || !result.dialogs) {
-        return;
-      }
-
-      result.users.forEach((user) => {
-        localDb.users[user.id] = user as MTP.user;
-      });
-
-      result.chats.forEach((chat) => {
-        localDb.chats[chat.id] = chat as MTP.chat | MTP.channel;
-      });
-
-      break;
-    }
-
-    case 'SendMessageRequest': {
-      const result = anyResult;
-
-      if (!result) {
-        return;
-      }
-
-      // TODO Support this.
-      if (result instanceof gramJsApi.UpdatesTooLong) {
-        return;
-      }
-
-      const updates = result.hasOwnProperty('updates') ? result.updates as MTP.Updates[] : [result as MTP.Updates];
-
-      const originRequest = {
-        name,
-        args,
-      };
-      updates.forEach((update) => onGramJsUpdate(update, originRequest));
-    }
-  }
-}
-=======
-export function downloadAvatar(entity: MTProto.chat | MTProto.user, isBig = false) {
-  return client.downloadProfilePhoto(entity, isBig);
-}
-
-<<<<<<< HEAD
-export function downloadMessageImage(message: MTProto.message) {
-  return client.downloadMedia(message, { sizeType: 'x' });
-=======
-export function downloadMedia(url: string) {
-  if (!isConnected) {
-    throw new Error('ERROR: Client is not connected');
-  }
-
-  return queuedDownloadMedia(client, url);
->>>>>>> 48d2d818... Support reconnect and re-sync
-}
->>>>>>> f70d85dd... Gram JS: Replace generated `tl/*` contents with runtime logic; TypeScript typings

+ 0 - 122
src/api/gramjs/connectors/auth.ts

@@ -1,122 +0,0 @@
-import { ApiUpdateAuthorizationState, ApiUpdateAuthorizationStateType } from '../../types';
-import { OnApiUpdate } from '../types';
-
-const authPromiseResolvers: {
-  resolvePhoneNumber: null | Function;
-  resolveCode: null | Function;
-  resolvePassword: null | Function;
-  resolveRegistration: null | Function;
-} = {
-  resolvePhoneNumber: null,
-  resolveCode: null,
-  resolvePassword: null,
-  resolveRegistration: null,
-};
-
-let onUpdate: OnApiUpdate;
-
-export function init(_onUpdate: OnApiUpdate) {
-  onUpdate = _onUpdate;
-}
-
-export function onRequestPhoneNumber() {
-  if (!onUpdate) {
-    return null;
-  }
-
-  onUpdate(buildAuthState('authorizationStateWaitPhoneNumber'));
-
-  return new Promise((resolve) => {
-    authPromiseResolvers.resolvePhoneNumber = resolve;
-  });
-}
-
-export function onRequestCode() {
-  if (!onUpdate) {
-    return null;
-  }
-
-  onUpdate(buildAuthState('authorizationStateWaitCode'));
-
-  return new Promise((resolve) => {
-    authPromiseResolvers.resolveCode = resolve;
-  });
-}
-
-export function onRequestPassword() {
-  if (!onUpdate) {
-    return null;
-  }
-
-  onUpdate(buildAuthState('authorizationStateWaitPassword'));
-
-  return new Promise((resolve) => {
-    authPromiseResolvers.resolvePassword = resolve;
-  });
-}
-
-export function onRequestRegistration() {
-  if (!onUpdate) {
-    return null;
-  }
-
-  onUpdate(buildAuthState('authorizationStateWaitRegistration'));
-
-  return new Promise((resolve) => {
-    authPromiseResolvers.resolveRegistration = resolve;
-  });
-}
-
-export function onAuthReady(sessionId: string) {
-  if (!onUpdate) {
-    return;
-  }
-
-  onUpdate({
-    ...buildAuthState('authorizationStateReady'),
-    session_id: sessionId,
-  });
-}
-
-export function buildAuthState(authState: ApiUpdateAuthorizationStateType): ApiUpdateAuthorizationState {
-  return {
-    '@type': 'updateAuthorizationState',
-    authorization_state: {
-      '@type': authState,
-    },
-  };
-}
-
-export function provideAuthPhoneNumber(phoneNumber: string) {
-  if (!authPromiseResolvers.resolvePhoneNumber) {
-    return;
-  }
-
-  authPromiseResolvers.resolvePhoneNumber(phoneNumber);
-}
-
-export function provideAuthCode(code: string) {
-  if (!authPromiseResolvers.resolveCode) {
-    return;
-  }
-
-  authPromiseResolvers.resolveCode(code);
-}
-
-export function provideAuthPassword(password: string) {
-  if (!authPromiseResolvers.resolvePassword) {
-    return;
-  }
-
-  authPromiseResolvers.resolvePassword(password);
-}
-
-export function provideAuthRegistration(registration: { firstName: string; lastName: string }) {
-  const { firstName, lastName } = registration;
-
-  if (!authPromiseResolvers.resolveRegistration) {
-    return;
-  }
-
-  authPromiseResolvers.resolveRegistration([firstName, lastName]);
-}

+ 0 - 129
src/api/gramjs/connectors/chats.ts

@@ -1,129 +0,0 @@
-import { gramJsApi, MTProto } from '../../../lib/gramjs';
-
-import { OnApiUpdate } from '../types';
-import { invokeRequest } from '../client';
-import { buildApiChatFromDialog, getApiChatIdFromMtpPeer, getPeerKey } from '../builders/chats';
-import { buildApiMessage } from '../builders/messages';
-import { buildApiUser } from '../builders/users';
-import { buildCollectionByKey } from '../../../util/iteratees';
-import { loadAvatar } from './files';
-import localDb from '../localDb';
-import { UNSUPPORTED_RESPONSE } from '../utils';
-
-const { constructors: ctors, requests } = gramJsApi;
-
-let onUpdate: OnApiUpdate;
-
-export function init(_onUpdate: OnApiUpdate) {
-  onUpdate = _onUpdate;
-}
-
-export async function fetchChats(
-  {
-    limit,
-    offsetDate,
-  }: {
-    limit: number;
-    offsetDate?: number;
-  },
-): Promise<{ chat_ids: number[] } | null> {
-  const result = await invokeRequest(new requests.messages.GetDialogsRequest({
-    offsetPeer: new ctors.InputPeerEmpty({}),
-    limit,
-    offsetDate,
-  }));
-
-<<<<<<< HEAD
-  if (!result || !(result instanceof ctors.messages.DialogsSlice) || !result.dialogs.length) {
-=======
-  // I had to change it to Dialogs to work for me.
-  if (!result || !(result instanceof GramJs.messages.DialogsSlice
-      || result instanceof GramJs.messages.Dialogs) || !result.dialogs.length) {
->>>>>>> 42589b8b... GramJS: Add `LocalStorageSession` with keys and hashes for all DCs
-    throw new Error(UNSUPPORTED_RESPONSE);
-  }
-
-  updateLocalDb(result);
-
-  const lastMessagesByChatId = buildCollectionByKey(result.messages.map(buildApiMessage), 'chat_id');
-  const peersByKey = preparePeers(result);
-  const chats = result.dialogs.map((dialog) => {
-    const peerEntity = peersByKey[getPeerKey(dialog.peer)];
-    const chat = buildApiChatFromDialog(dialog as MTProto.dialog, peerEntity);
-    chat.last_message = lastMessagesByChatId[chat.id];
-    return chat;
-  });
-
-  onUpdate({
-    '@type': 'chats',
-    chats,
-  });
-
-  const users = (result.users as MTProto.user[]).map(buildApiUser);
-  onUpdate({
-    '@type': 'users',
-    users,
-  });
-
-  loadAvatars(result);
-
-  const chatIds = chats.map((chat) => chat.id);
-
-  return {
-    chat_ids: chatIds,
-  };
-}
-
-function preparePeers(result: MTProto.messages_dialogsSlice) {
-  const store: Record<string, MTProto.chat | MTProto.user> = {};
-
-  result.chats.forEach((chat) => {
-    store[`chat${chat.id}`] = chat as MTProto.chat;
-  });
-
-  result.users.forEach((user) => {
-    store[`user${user.id}`] = user as MTProto.user;
-  });
-
-  return store;
-}
-
-function updateLocalDb(result: MTProto.messages_dialogsSlice) {
-  result.users.forEach((user) => {
-    localDb.users[user.id] = user as MTProto.user;
-  });
-
-  result.chats.forEach((chat) => {
-    localDb.chats[chat.id] = chat as MTProto.chat | MTProto.channel;
-  });
-}
-
-function loadAvatars(result: MTProto.messages_dialogsSlice) {
-  result.users.forEach((user) => {
-    loadAvatar(user as MTProto.user).then((dataUri) => {
-      if (!dataUri) {
-        return;
-      }
-
-      onUpdate({
-        '@type': 'updateAvatar',
-        chat_id: getApiChatIdFromMtpPeer({ userId: user.id } as MTProto.Peer),
-        data_uri: dataUri,
-      });
-    });
-  });
-
-  result.chats.forEach((chat) => {
-    loadAvatar(chat as MTProto.chat).then((dataUri) => {
-      if (!dataUri) {
-        return;
-      }
-
-      onUpdate({
-        '@type': 'updateAvatar',
-        chat_id: getApiChatIdFromMtpPeer({ chatId: chat.id } as MTProto.Peer),
-        data_uri: dataUri,
-      });
-    });
-  });
-}

+ 0 - 84
src/api/gramjs/connectors/files.ts

@@ -1,84 +0,0 @@
-<<<<<<< HEAD
-import { ApiFileLocation } from '../../types';
-
-<<<<<<< HEAD
-import { downloadFile } from '../client';
-=======
-import { downloadFile, downloadMessageImage } from '../client';
-=======
-import { MTProto } from '../../../lib/gramjs';
-import { downloadAvatar, downloadMessageImage } from '../client';
->>>>>>> f70d85dd... Gram JS: Replace generated `tl/*` contents with runtime logic; TypeScript typings
-import localDb from '../localDb';
-import { bytesToDataUri } from '../builders/common';
->>>>>>> dda7e47e... Fix images loading; Various Gram JS fixes; Refactor Gram JS Logger
-
-export function init() {
-}
-
-<<<<<<< HEAD
-export async function loadFile(id: any, fileLocation: ApiFileLocation): Promise<string | null> {
-  const fileBuffer = await downloadFile(id, fileLocation);
-=======
-export function loadAvatar(entity: MTProto.user | MTProto.chat): Promise<string | null> {
-  const entityId = entity.id;
-
-  if (!localDb.avatarRequests[entityId]) {
-    localDb.avatarRequests[entityId] = downloadAvatar(entity)
-      .then(
-        (fileBuffer: Buffer) => {
-          if (fileBuffer) {
-            return bytesToDataUri(fileBuffer);
-          } else {
-            delete localDb.avatarRequests[entityId];
-            return null;
-          }
-        },
-        () => {
-          delete localDb.avatarRequests[entityId];
-          return null;
-        },
-      );
-  }
->>>>>>> f70d85dd... Gram JS: Replace generated `tl/*` contents with runtime logic; TypeScript typings
-
-  return fileBuffer ? bytesToUrl(fileBuffer) : null;
-}
-
-<<<<<<< HEAD
-<<<<<<< HEAD
-function bytesToUrl(bytes: Uint8Array, mimeType?: string) {
-  if (!mimeType) {
-    mimeType = 'image/jpg';
-=======
-export function loadMessageMedia(message: MTP.message): Promise<string | null> {
-=======
-export function loadMessageMedia(message: MTProto.message): Promise<string | null> {
->>>>>>> f70d85dd... Gram JS: Replace generated `tl/*` contents with runtime logic; TypeScript typings
-  const messageId = message.id;
-
-  if (!localDb.mediaRequests[messageId]) {
-    localDb.mediaRequests[messageId] = downloadMessageImage(message)
-      .then(
-        (fileBuffer: Buffer) => {
-          if (fileBuffer) {
-            return bytesToDataUri(fileBuffer);
-          } else {
-            delete localDb.mediaRequests[messageId];
-            return null;
-          }
-        },
-        () => {
-          delete localDb.mediaRequests[messageId];
-          return null;
-        },
-      );
->>>>>>> dda7e47e... Fix images loading; Various Gram JS fixes; Refactor Gram JS Logger
-  }
-
-  return `data:${mimeType};base64,${btoa(
-    bytes.reduce((data, byte) => {
-      return data + String.fromCharCode(byte);
-    }, ''),
-  )}`;
-}

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff