import * as codec from './codec.js' ; import { getProtocol , names } from './protocols-table.js' ; import varint from 'varint' ; import { CID } from 'multiformats/cid' ; import { base58btc } from 'multiformats/bases/base58' ; import errCode from 'err-code' ; import { toString as uint8ArrayToString } from 'uint8arrays/to-string' ; import { equals as uint8ArrayEquals } from 'uint8arrays/equals' ; const inspect = Symbol . for ( 'nodejs.util.inspect.custom' ) ; export interface Protocol { code : number ; size : number ; name : string ; resolvable ? : boolean | undefined ; path ? : boolean | undefined ; } export interface MultiaddrObject { family : 4 | 6 ; host : string ; transport : string ; port : number ; } export interface NodeAddress { family : 4 | 6 ; address : string ; port : number ; } export type MultiaddrInput = string | Multiaddr | Uint8Array | null ; export interface Resolver { ( addr ) : Promise < string [ ] > ; } const resolvers = new Map < string , Resolver > ( ) ; const symbol = Symbol . for ( '@multiformats/js-multiaddr/multiaddr' ) ; /**
 * Creates a [multiaddr](https://github.com/multiformats/multiaddr) from
 * a Uint8Array, String or another Multiaddr instance
 * public key.
 *
 */ export class Multiaddr { static resolvers = resolvers ; public bytes : Uint8Array ; example param { MultiaddrInput } addr constructor ( addr ? ) { if ( addr == null ) { addr = '' ; } Object . defineProperty ( this , symbol , { value : true } ) ; if ( addr instanceof Uint8Array ) { type { Uint8Array } this . bytes = codec . fromBytes ( addr ) ; } else if ( typeof addr === 'string' ) { if ( addr . length > 0 && addr . charAt ( 0 ) !== '/' ) { throw new Error ( `multiaddr "${ addr }" must start with a "/"` ) ; } this . bytes = codec . fromString ( addr ) ; } else if ( Multiaddr . isMultiaddr ( addr ) ) { this . bytes = codec . fromBytes ( addr . bytes ) ; } else { throw new Error ( 'addr must be a string, Buffer, or another Multiaddr' ) ; } } example toString ( ) { return codec . bytesToString ( this . bytes ) ; } example toJSON ( ) { return this . toString ( ) ; } example toOptions ( ) { const parsed = this . toString ( ) . split ( '/' ) ; const opts = { family : parsed [ 1 ] === 'ip4' ? 4 : 6 , host : parsed [ 2 ] , transport : parsed [ 3 ] , port : parseInt ( parsed [ 4 ] ) } ; return opts ; } example protos ( ) { return this . protoCodes ( ) . map ( code => Object . assign ( { } , getProtocol ( code ) ) ) ; } example protoCodes ( ) { const codes = [ ] ; const buf = this . bytes ; let i = 0 ; while ( i < buf . length ) { const code = varint . decode ( buf , i ) ; const n = varint . decode . bytes ; const p = getProtocol ( code ) ; const size = codec . sizeForAddr ( p , buf . slice ( i + n ) ) ; i += ( size + n ) ; codes . push ( code ) ; } return codes ; } example protoNames ( ) { return this . protos ( ) . map ( proto => proto . name ) ; } example tuples ( ) { return codec . bytesToTuples ( this . bytes ) ; } example stringTuples ( ) { const t = codec . bytesToTuples ( this . bytes ) ; return codec . tuplesToStringTuples ( t ) ; } example param { MultiaddrInput } addr encapsulate ( addr ) { addr = new Multiaddr ( addr ) ; return new Multiaddr ( this . toString ( ) + addr . toString ( ) ) ; } example param { Multiaddr | string } addr decapsulate ( addr ) { const addrString = addr . toString ( ) ; const s = this . toString ( ) ; const i = s . lastIndexOf ( addrString ) ; if ( i < 0 ) { throw new Error ( `Address ${ this . toString ( ) } does not contain subaddress: ${ addr . toString ( ) }` ) ; } return new Multiaddr ( s . slice ( 0 , i ) ) ; } example decapsulateCode ( code ) { const tuples = this . tuples ( ) ; for ( let i = tuples . length - 1 ; i >= 0 ; i -- ) { if ( tuples [ i ] [ 0 ] === code ) { return new Multiaddr ( codec . tuplesToBytes ( tuples . slice ( 0 , i ) ) ) ; } } return this ; } example getPeerId ( ) { try { const tuples = this . stringTuples ( ) . filter ( ( tuple ) => { if ( tuple [ 0 ] === names . ipfs . code ) { return true ; } return false ; } ) ; const tuple = tuples . pop ( ) ; if ( tuple ?. [ 1 ] != null ) { const peerIdStr = tuple [ 1 ] ; if ( peerIdStr [ 0 ] === 'Q' || peerIdStr [ 0 ] === '1' ) { return uint8ArrayToString ( base58btc . decode ( `z${ peerIdStr }` ) , 'base58btc' ) ; } return uint8ArrayToString ( CID . parse ( peerIdStr ) . multihash . bytes , 'base58btc' ) ; } return null ; } catch ( e ) { return null ; } } example getPath ( ) { let path = null ; try { path = this . stringTuples ( ) . filter ( ( tuple ) => { const proto = getProtocol ( tuple [ 0 ] ) ; if ( proto . path === true ) { return true ; } return false ; } ) [ 0 ] [ 1 ] ; if ( path == null ) { path = null ; } } catch { path = null ; } return path ; } example equals ( addr ) { return uint8ArrayEquals ( this . bytes , addr . bytes ) ; } example async resolve ( ) { const resolvableProto = this . protos ( ) . find ( ( p ) => p . resolvable ) ; if ( resolvableProto == null ) { return [ this ] ; } const resolver = resolvers . get ( resolvableProto . name ) ; if ( resolver == null ) { throw errCode ( new Error ( `no available resolver for ${ resolvableProto . name }` ) , 'ERR_NO_AVAILABLE_RESOLVER' ) ; } const addresses = await resolver ( this ) ; return addresses . map ( ( a ) => new Multiaddr ( a ) ) ; } example nodeAddress ( ) { const codes = this . protoCodes ( ) ; const names = this . protoNames ( ) ; const parts = this . toString ( ) . split ( '/' ) . slice ( 1 ) ; if ( parts . length < 4 ) { throw new Error ( 'multiaddr must have a valid format: "/{ip4, ip6, dns4, dns6}/{address}/{tcp, udp}/{port}".' ) ; } else if ( codes [ 0 ] !== 4 && codes [ 0 ] !== 41 && codes [ 0 ] !== 54 && codes [ 0 ] !== 55 ) { throw new Error ( `no protocol with name: "'${ names [ 0 ] }'". Must have a valid family name: "{ip4, ip6, dns4, dns6}".` ) ; } else if ( parts [ 2 ] !== 'tcp' && parts [ 2 ] !== 'udp' ) { throw new Error ( `no protocol with name: "'${ names [ 1 ] }'". Must have a valid transport protocol: "{tcp, udp}".` ) ; } return { family : ( codes [ 0 ] === 41 || codes [ 0 ] === 55 ) ? 6 : 4 , address : parts [ 1 ] , port : parseInt ( parts [ 3 ] ) } ; } example isThinWaistAddress ( addr ? ) { const protos = ( addr ?? this ) . protos ( ) ; if ( protos . length !== 2 ) { return false ; } if ( protos [ 0 ] . code !== 4 && protos [ 0 ] . code !== 41 ) { return false ; } if ( protos [ 1 ] . code !== 6 && protos [ 1 ] . code !== 273 ) { return false ; } return true ; } example param { { family : 4 | 6 , address : string , port : number } } addr param { string } transport static fromNodeAddress ( addr , transport ) { if ( addr == null ) { throw new Error ( 'requires node address object' ) ; } if ( transport == null ) { throw new Error ( 'requires transport protocol' ) ; } let ip ; switch ( addr . family ) { case 4 : ip = 'ip4' ; break ; case 6 : ip = 'ip6' ; break ; default : throw Error ( 'Invalid addr family, should be 4 or 6.' ) ; } return new Multiaddr ( '/' + [ ip , addr . address , transport , addr . port ] . join ( '/' ) ) ; } /**
     * Returns if something is a Multiaddr that is a name
     */ static isName ( addr ) { if ( ! Multiaddr . isMultiaddr ( addr ) ) { return false ; } return addr . protos ( ) . some ( ( proto ) => proto . resolvable ) ; } /**
     * Check if object is a CID instance
     */ static isMultiaddr ( value ) { return value instanceof Multiaddr ?? Boolean ( value ?. [ symbol ] ) ; } example [ inspect ] ( ) { return '<Multiaddr ' + uint8ArrayToString ( this . bytes , 'base16' ) + ' - ' + codec . bytesToString ( this . bytes ) + '>' ; } example inspect ( ) { return '<Multiaddr ' + uint8ArrayToString ( this . bytes , 'base16' ) + ' - ' + codec . bytesToString ( this . bytes ) + '>' ; } } /**
 * Static factory
 */ export function multiaddr ( addr ) { return new Multiaddr ( addr ) ; } export { getProtocol as protocols } ; export { resolvers } ;