const { inspect } = require ( "util" ) ; const bigInt = require ( "big-integer" ) ; const { generateRandomBytes , readBigIntFromBuffer , isArrayLike , betterConsoleLog , } = require ( "../Helpers" ) ; const tlContent = require ( "./apiTl.js" ) ; const schemeContent = require ( "./schemaTl.js" ) ; function generateRandomBigInt ( ) { return readBigIntFromBuffer ( generateRandomBytes ( 8 ) , false , true ) ; } const { parseTl , serializeBytes , serializeDate , } = require ( "./generationHelpers" ) ; const { toSignedLittleBuffer } = require ( "../Helpers" ) ; const NAMED_AUTO_CASTS = new Set ( [ "chatId,int" ] ) ; const NAMED_BLACKLIST = new Set ( [ "discardEncryption" ] ) ; const AUTO_CASTS = new Set ( [ "InputPeer" , "InputChannel" , "InputUser" , "InputDialogPeer" , "InputNotifyPeer" , "InputMedia" , "InputPhoto" , "InputMessage" , "InputDocument" , "InputChatPhoto" , ] ) ; class CastError extends Error { constructor ( objectName , expected , actual , ... params ) { const message = "Found wrong type for " + objectName + ". expected " + expected + " but received " + actual + ".If you think this is a mistake please report it." ; super ( message , ... params ) ; if ( Error . captureStackTrace ) { Error . captureStackTrace ( this , CastError ) ; } this . name = "CastError" ; } } const CACHING_SUPPORTED = typeof self !== "undefined" && self . localStorage !== undefined ; const CACHE_KEY = "GramJs:apiCache" ; function buildApiFromTlSchema ( ) { let definitions ; const fromCache = CACHING_SUPPORTED && loadFromCache ( ) ; if ( fromCache ) { definitions = fromCache ; } else { definitions = loadFromTlSchemas ( ) ; if ( CACHING_SUPPORTED ) { localStorage . setItem ( CACHE_KEY , JSON . stringify ( definitions ) ) ; } } return createClasses ( "all" , definitions ) ; } function loadFromCache ( ) { const jsonCache = localStorage . getItem ( CACHE_KEY ) ; return jsonCache && JSON . parse ( jsonCache ) ; } function loadFromTlSchemas ( ) { const [ constructorParamsApi , functionParamsApi ] = extractParams ( tlContent ) ; const [ constructorParamsSchema , functionParamsSchema ] = extractParams ( schemeContent ) ; const constructors = [ ] . concat ( constructorParamsApi , constructorParamsSchema ) ; const requests = [ ] . concat ( functionParamsApi , functionParamsSchema ) ; return [ ] . concat ( constructors , requests ) ; } function extractParams ( fileContent ) { const f = parseTl ( fileContent , 109 ) ; const constructors = [ ] ; const functions = [ ] ; for ( const d of f ) { d . isFunction ? functions . push ( d ) : constructors . push ( d ) ; } return [ constructors , functions ] ; } function argToBytes ( x , type , argName , requestName ) { switch ( type ) { case "int" : const i = Buffer . alloc ( 4 ) ; i . writeInt32LE ( x , 0 ) ; return i ; case "long" : return toSignedLittleBuffer ( x , 8 ) ; case "int128" : return toSignedLittleBuffer ( x , 16 ) ; case "int256" : return toSignedLittleBuffer ( x , 32 ) ; case "double" : const d = Buffer . alloc ( 8 ) ; d . writeDoubleLE ( x , 0 ) ; return d ; case "string" : return serializeBytes ( x ) ; case "Bool" : return x ? Buffer . from ( "b5757299" , "hex" ) : Buffer . from ( "379779bc" , "hex" ) ; case "true" : return Buffer . alloc ( 0 ) ; case "bytes" : return serializeBytes ( x ) ; case "date" : return serializeDate ( x ) ; default : if ( x === undefined || typeof x . getBytes !== "function" ) { throw new Error ( `Required object ${ argName } of ${ requestName } is undefined` ) ; } return x . getBytes ( ) ; } } async function getInputFromResolve ( utils , client , peer , peerType ) { switch ( peerType ) { case "InputPeer" : return utils . getInputPeer ( await client . getInputEntity ( peer ) ) ; case "InputChannel" : return utils . getInputChannel ( await client . getInputEntity ( peer ) ) ; case "InputUser" : return utils . getInputUser ( await client . getInputEntity ( peer ) ) ; case "InputDialogPeer" : return await client . _getInputDialog ( peer ) ; case "InputNotifyPeer" : return await client . _getInputNotify ( peer ) ; case "InputMedia" : return utils . getInputMedia ( peer ) ; case "InputPhoto" : return utils . getInputPhoto ( peer ) ; case "InputMessage" : return utils . getInputMessage ( peer ) ; case "InputDocument" : return utils . getInputDocument ( peer ) ; case "InputChatPhoto" : return utils . getInputChatPhoto ( peer ) ; case "chatId,int" : return await client . getPeerId ( peer , false ) ; default : throw new Error ( "unsupported peer type : " + peerType ) ; } } function getArgFromReader ( reader , arg ) { if ( arg . isVector ) { if ( arg . useVectorId ) { reader . readInt ( ) ; } const temp = [ ] ; const len = reader . readInt ( ) ; arg . isVector = false ; for ( let i = 0 ; i < len ; i ++ ) { temp . push ( getArgFromReader ( reader , arg ) ) ; } arg . isVector = true ; return temp ; } else if ( arg . flagIndicator ) { return reader . readInt ( ) ; } else { switch ( arg . type ) { case "int" : return reader . readInt ( ) ; case "long" : return reader . readLong ( ) ; case "int128" : return reader . readLargeInt ( 128 ) ; case "int256" : return reader . readLargeInt ( 256 ) ; case "double" : return reader . readDouble ( ) ; case "string" : return reader . tgReadString ( ) ; case "Bool" : return reader . tgReadBool ( ) ; case "true" : return true ; case "bytes" : return reader . tgReadBytes ( ) ; case "date" : return reader . tgReadDate ( ) ; default : if ( ! arg . skipConstructorId ) { return reader . tgReadObject ( ) ; } else { return api . constructors [ arg . type ] . fromReader ( reader ) ; } } } } function compareType ( value , type ) { let correct = true ; switch ( type ) { case "number" : correct = typeof value === "number" || value === undefined ; break ; case "string" : case "boolean" : correct = typeof value === type ; break ; case "bigInt" : correct = bigInt . isInstance ( value ) || typeof value === "bigint" || typeof value === "number" || typeof value === "string" || value === undefined ; break ; case "true" : break ; case "buffer" : correct = Buffer . isBuffer ( value ) ; break ; case "date" : correct = ( value && Object . prototype . toString . call ( value ) === "[object Date]" && ! isNaN ( value ) ) || typeof value === "number" ; break ; default : console . error ( new Error ( "Unknown type." + type ) ) ; } return correct ; } function createClasses ( classesType , params ) { const classes = { } ; for ( const classParams of params ) { const { name , constructorId , subclassOfId , argsConfig , namespace , isFunction , result , } = classParams ; const fullName = [ namespace , name ] . join ( "." ) . replace ( /^\./ , "" ) ; class VirtualClass { static CONSTRUCTOR_ID = constructorId ; static SUBCLASS_OF_ID = subclassOfId ; static className = fullName ; static classType = isFunction ? "request" : "constructor" ; CONSTRUCTOR_ID = constructorId ; SUBCLASS_OF_ID = subclassOfId ; className = fullName ; classType = isFunction ? "request" : "constructor" ; constructor ( args ) { args = args || { } ; this . originalArgs = args ; this . init ( args ) ; for ( const argName in argsConfig ) { if ( argName === "randomId" && ! args [ argName ] ) { if ( argsConfig [ argName ] . isVector ) { const rands = [ ] ; for ( let i = 0 ; i < args [ "id" ] . length ; i ++ ) { rands . push ( generateRandomBigInt ( ) ) ; } this [ argName ] = rands ; } else { this [ argName ] = generateRandomBigInt ( ) ; } } else { this [ argName ] = args [ argName ] ; } } } init ( args ) { } static fromReader ( reader ) { const args = { } ; for ( const argName in argsConfig ) { if ( argsConfig . hasOwnProperty ( argName ) ) { const arg = argsConfig [ argName ] ; if ( arg . isFlag ) { if ( arg . type === "true" ) { args [ argName ] = Boolean ( args [ "flags" ] & ( 1 << arg . flagIndex ) ) ; continue ; } if ( args [ "flags" ] & ( 1 << arg . flagIndex ) ) { args [ argName ] = getArgFromReader ( reader , arg ) ; } else { args [ argName ] = null ; } } else { if ( arg . flagIndicator ) { arg . name = "flags" ; } args [ argName ] = getArgFromReader ( reader , arg ) ; } } } return new this ( args ) ; } validate ( ) { for ( const arg in argsConfig ) { if ( argsConfig . hasOwnProperty ( arg ) ) { if ( arg === "flags" || argsConfig [ arg ] . isFlag ) { continue ; } const currentValue = this [ arg ] ; this . assertType ( arg , argsConfig [ arg ] , currentValue ) ; } } } assertType ( objectName , object , value ) { let expected ; if ( object [ "isVector" ] ) { if ( ! isArrayLike ( value ) ) { console . error ( new CastError ( objectName , "array" , value ) ) ; } if ( value == undefined ) { value = [ ] ; } for ( const o of value ) { this . assertType ( objectName , { ... object , isVector : false } , o ) ; } } else { switch ( object [ "type" ] ) { case "int" : expected = "number" ; break ; case "long" : case "int128" : case "int256" : expected = "bigInt" ; break ; case "double" : expected = "number" ; break ; case "string" : expected = "string" ; break ; case "Bool" : expected = "boolean" ; break ; case "true" : expected = "true" ; break ; case "bytes" : expected = "buffer" ; break ; case "date" : expected = "date" ; break ; default : expected = "object" ; } if ( expected === "object" ) { } else { const isCorrectType = compareType ( value , expected ) ; if ( isCorrectType !== true ) { console . error ( new CastError ( objectName , expected , value ) ) ; } } } } getBytes ( ) { try { this . validate ( ) ; } catch ( e ) { } const idForBytes = this . CONSTRUCTOR_ID ; const c = Buffer . alloc ( 4 ) ; c . writeUInt32LE ( idForBytes , 0 ) ; const buffers = [ c ] ; for ( const arg in argsConfig ) { if ( argsConfig . hasOwnProperty ( arg ) ) { if ( argsConfig [ arg ] . isFlag ) { if ( this [ arg ] === false || this [ arg ] === null || this [ arg ] === undefined || argsConfig [ arg ] . type === "true" ) { continue ; } } if ( argsConfig [ arg ] . isVector ) { if ( argsConfig [ arg ] . useVectorId ) { buffers . push ( Buffer . from ( "15c4b51c" , "hex" ) ) ; } const l = Buffer . alloc ( 4 ) ; l . writeInt32LE ( this [ arg ] . length , 0 ) ; buffers . push ( l , Buffer . concat ( this [ arg ] . map ( ( x ) => argToBytes ( x , argsConfig [ arg ] . type , fullName ) ) ) ) ; } else if ( argsConfig [ arg ] . flagIndicator ) { if ( ! Object . values ( argsConfig ) . some ( ( f ) => f . isFlag ) ) { buffers . push ( Buffer . alloc ( 4 ) ) ; } else { let flagCalculate = 0 ; for ( const f in argsConfig ) { if ( argsConfig [ f ] . isFlag ) { if ( this [ f ] === false || this [ f ] === undefined || this [ f ] === null ) { flagCalculate |= 0 ; } else { flagCalculate |= 1 << argsConfig [ f ] . flagIndex ; } } } const f = Buffer . alloc ( 4 ) ; f . writeUInt32LE ( flagCalculate , 0 ) ; buffers . push ( f ) ; } } else { buffers . push ( argToBytes ( this [ arg ] , argsConfig [ arg ] . type , arg , fullName ) ) ; 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 ( ) ; } } } } } return Buffer . concat ( buffers ) ; } readResult ( reader ) { if ( ! isFunction ) { throw new Error ( "`readResult()` called for non-request instance" ) ; } const m = result . match ( /Vector<(int|long)>/ ) ; if ( m ) { reader . readInt ( ) ; const temp = [ ] ; const len = reader . readInt ( ) ; if ( m [ 1 ] === "int" ) { for ( let i = 0 ; i < len ; i ++ ) { temp . push ( reader . readInt ( ) ) ; } } else { for ( let i = 0 ; i < len ; i ++ ) { temp . push ( reader . readLong ( ) ) ; } } return temp ; } else { return reader . tgReadObject ( ) ; } } async resolve ( client , utils ) { if ( ! isFunction ) { throw new Error ( "`resolve()` called for non-request instance" ) ; } for ( const arg in argsConfig ) { if ( argsConfig . hasOwnProperty ( arg ) ) { if ( ! AUTO_CASTS . has ( argsConfig [ arg ] . type ) ) { if ( ! NAMED_AUTO_CASTS . has ( `${ argsConfig [ arg ] . name },${ argsConfig [ arg ] . type }` ) ) { continue ; } } if ( argsConfig [ arg ] . isFlag ) { if ( ! this [ arg ] ) { continue ; } } if ( argsConfig [ arg ] . isVector ) { const temp = [ ] ; for ( const x of this [ arg ] ) { temp . push ( await getInputFromResolve ( utils , client , x , argsConfig [ arg ] . type ) ) ; } this [ arg ] = temp ; } else { this [ arg ] = await getInputFromResolve ( utils , client , this [ arg ] , argsConfig [ arg ] . type ) ; } } } } [ inspect . custom ] ( ) { return betterConsoleLog ( this ) ; } toJSON ( ) { return this . originalArgs ; } } if ( namespace ) { if ( ! classes [ namespace ] ) { classes [ namespace ] = { } ; } classes [ namespace ] [ name ] = VirtualClass ; } else { classes [ name ] = VirtualClass ; } } return classes ; } const api = buildApiFromTlSchema ( ) ; module . exports = { Api : api } ;