@multiformats/multiaddr
Version:
multiaddr implementation (binary + string representation of network addresses)
328 lines • 9.06 kB
JavaScript
/**
* @packageDocumentation
*
* A standard way to represent addresses that
*
* - support any standard network protocol
* - are self-describing
* - have a binary packed format
* - have a nice string representation
* - encapsulate well
*
* @example
*
* ```TypeScript
* import { multiaddr } from '@multiformats/multiaddr'
*
* const addr = multiaddr('/ip4/127.0.0.1/udp/1234')
* // Multiaddr(/ip4/127.0.0.1/udp/1234)
*
* addr.bytes
* // <Uint8Array 04 7f 00 00 01 11 04 d2>
*
* addr.toString()
* // '/ip4/127.0.0.1/udp/1234'
*
* addr.protos()
* // [
* // {code: 4, name: 'ip4', size: 32},
* // {code: 273, name: 'udp', size: 16}
* // ]
*
* // gives you an object that is friendly with what Node.js core modules expect for addresses
* addr.nodeAddress()
* // {
* // family: 4,
* // port: 1234,
* // address: "127.0.0.1"
* // }
*
* addr.encapsulate('/sctp/5678')
* // Multiaddr(/ip4/127.0.0.1/udp/1234/sctp/5678)
* ```
*
* ## Resolving DNSADDR addresses
*
* [DNSADDR](https://github.com/multiformats/multiaddr/blob/master/protocols/DNSADDR.md) is a spec that allows storing a TXT DNS record that contains a Multiaddr.
*
* To resolve DNSADDR addresses, call the `.resolve()` function the multiaddr, optionally passing a `DNS` resolver.
*
* DNSADDR addresses can resolve to multiple multiaddrs, since there is no limit to the number of TXT records that can be stored.
*
* @example Resolving DNSADDR Multiaddrs
*
* ```TypeScript
* import { multiaddr, resolvers } from '@multiformats/multiaddr'
* import { dnsaddrResolver } from '@multiformats/multiaddr/resolvers'
*
* resolvers.set('dnsaddr', dnsaddrResolver)
*
* const ma = multiaddr('/dnsaddr/bootstrap.libp2p.io')
*
* // resolve with a 5s timeout
* const resolved = await ma.resolve({
* signal: AbortSignal.timeout(5000)
* })
*
* console.info(resolved)
* // [Multiaddr('/ip4/147.75...'), Multiaddr('/ip4/147.75...'), Multiaddr('/ip4/147.75...')...]
* ```
*
* @example Using a custom DNS resolver to resolve DNSADDR Multiaddrs
*
* See the docs for [@multiformats/dns](https://www.npmjs.com/package/@multiformats/dns) for a full breakdown of how to specify multiple resolvers or resolvers that can be used for specific TLDs.
*
* ```TypeScript
* import { multiaddr } from '@multiformats/multiaddr'
* import { dns } from '@multiformats/dns'
* import { dnsJsonOverHttps } from '@multiformats/dns/resolvers'
*
* const resolver = dns({
* resolvers: {
* '.': dnsJsonOverHttps('https://cloudflare-dns.com/dns-query')
* }
* })
*
* const ma = multiaddr('/dnsaddr/bootstrap.libp2p.io')
* const resolved = await ma.resolve({
* dns: resolver
* })
*
* console.info(resolved)
* // [Multiaddr('/ip4/147.75...'), Multiaddr('/ip4/147.75...'), Multiaddr('/ip4/147.75...')...]
* ```
*
* @example Adding custom protocols
*
* To add application-specific or experimental protocols, add a protocol codec
* to the protocol registry:
*
* ```ts
* import { registry, V, multiaddr } from '@multiformats/multiaddr'
* import type { ProtocolCodec } from '@multiformats/multiaddr'
*
* const maWithCustomTuple = '/custom-protocol/hello'
*
* // throws UnknownProtocolError
* multiaddr(maWithCustomTuple)
*
* const protocol: ProtocolCodec = {
* code: 2059,
* name: 'custom-protocol',
* size: V
* // V means variable length, can also be 0, a positive integer (e.g. a fixed
* // length or omitted
* }
*
* registry.addProtocol(protocol)
*
* // does not throw UnknownProtocolError
* multiaddr(maWithCustomTuple)
*
* // protocols can also be removed
* registry.removeProtocol(protocol.code)
* ```
*/
import { toString as uint8ArrayToString } from 'uint8arrays/to-string';
import { InvalidParametersError } from "./errors.js";
import { Multiaddr as MultiaddrClass, symbol } from './multiaddr.js';
import { registry, V } from "./registry.js";
/**
* All configured {@link Resolver}s
*
* @deprecated DNS resolving will be removed in a future release
*/
export const resolvers = new Map();
export { MultiaddrFilter } from './filter/multiaddr-filter.js';
/**
* Creates a Multiaddr from a node-friendly address object
*
* @example
* ```js
* import { fromNodeAddress } from '@multiformats/multiaddr'
*
* fromNodeAddress({address: '127.0.0.1', port: '4001'}, 'tcp')
* // Multiaddr(/ip4/127.0.0.1/tcp/4001)
* ```
*/
export function fromNodeAddress(addr, transport) {
if (addr == null) {
throw new InvalidParametersError('requires node address object');
}
if (transport == null) {
throw new InvalidParametersError('requires transport protocol');
}
let ip;
let host = addr.address;
switch (addr.family) {
case 4:
ip = 'ip4';
break;
case 6:
ip = 'ip6';
if (host.includes('%')) {
const parts = host.split('%');
if (parts.length !== 2) {
throw Error('Multiple ip6 zones in multiaddr');
}
host = parts[0];
const zone = parts[1];
ip = `ip6zone/${zone}/ip6`;
}
break;
default:
throw Error('Invalid addr family, should be 4 or 6.');
}
return new MultiaddrClass('/' + [ip, host, transport, addr.port].join('/'));
}
/**
* Create a {@link Multiaddr} from an array of {@link Tuple}s
*
* @example
*
* ```ts
* import { fromTuples, multiaddr } from '@multiformats/multiaddr'
*
* const ma = multiaddr('/ip4/127.0.0.1')
* const tuples = ma.tuples()
*
* const ma2 = fromTuples(tuples)
*
* console.info(ma2)
* // '/ip4/127.0.0.1'
* ```
*
* @deprecated Will be removed in a future release
*/
export function fromTuples(tuples) {
return multiaddr(tuples.map(([code, value]) => {
const codec = registry.getProtocol(code);
const component = {
code,
name: codec.name
};
if (value != null) {
component.value = codec.bytesToValue?.(value) ?? uint8ArrayToString(value);
}
return component;
}));
}
/**
* Create a {@link Multiaddr} from an array of {@link StringTuple}s
*
* @example
*
* ```ts
* import { fromStringTuples, multiaddr } from '@multiformats/multiaddr'
*
* const ma = multiaddr('/ip4/127.0.0.1')
* const tuples = ma.stringTuples()
*
* const ma2 = fromStringTuples(tuples)
*
* console.info(ma2)
* // '/ip4/127.0.0.1'
* ```
*
* @deprecated Will be removed in a future release
*/
export function fromStringTuples(tuples) {
return multiaddr(tuples.map(([code, value]) => {
const codec = registry.getProtocol(code);
const component = {
code,
name: codec.name
};
if (value != null) {
component.value = value;
}
return component;
}));
}
/**
* Returns if something is a {@link Multiaddr} that is a resolvable name
*
* @example
*
* ```js
* import { isName, multiaddr } from '@multiformats/multiaddr'
*
* isName(multiaddr('/ip4/127.0.0.1'))
* // false
* isName(multiaddr('/dns/ipfs.io'))
* // true
* ```
*
* @deprecated DNS resolving will be removed in a future release
*/
export function isName(addr) {
if (!isMultiaddr(addr)) {
return false;
}
// if a part of the multiaddr is resolvable, then return true
return addr.protos().some((proto) => proto.resolvable);
}
/**
* Check if object is a {@link Multiaddr} instance
*
* @example
*
* ```js
* import { isMultiaddr, multiaddr } from '@multiformats/multiaddr'
*
* isMultiaddr(5)
* // false
* isMultiaddr(multiaddr('/ip4/127.0.0.1'))
* // true
* ```
*/
export function isMultiaddr(value) {
return Boolean(value?.[symbol]);
}
/**
* A function that takes a {@link MultiaddrInput} and returns a {@link Multiaddr}
*
* @example
* ```js
* import { multiaddr } from '@libp2p/multiaddr'
*
* multiaddr('/ip4/127.0.0.1/tcp/4001')
* // Multiaddr(/ip4/127.0.0.1/tcp/4001)
* ```
*
* @param {MultiaddrInput} [addr] - If String or Uint8Array, needs to adhere to the address format of a [multiaddr](https://github.com/multiformats/multiaddr#string-format)
*/
export function multiaddr(addr) {
return new MultiaddrClass(addr);
}
/**
* For the passed proto string or number, return a {@link Protocol}
*
* @example
*
* ```js
* import { protocol } from '@multiformats/multiaddr'
*
* console.info(protocol(4))
* // { code: 4, size: 32, name: 'ip4', resolvable: false, path: false }
* ```
*
* @deprecated This will be removed in a future version
*/
export function protocols(proto) {
const codec = registry.getProtocol(proto);
return {
code: codec.code,
size: codec.size ?? 0,
name: codec.name,
resolvable: Boolean(codec.resolvable),
path: Boolean(codec.path)
};
}
/**
* Export all table.csv codes. These are all named exports so can be tree-shaken
* out by bundlers.
*/
export * from "./constants.js";
export { registry, V };
//# sourceMappingURL=index.js.map